xref: /netbsd/bin/ksh/main.c (revision ce8041bd)
1*ce8041bdSkamil /*	$NetBSD: main.c,v 1.23 2018/05/08 16:37:59 kamil Exp $	*/
22ab2e20cStls 
3e1b2664cSjtc /*
47b9b4ac6Swiz  * startup, main loop, environments and error handling
5e1b2664cSjtc  */
66377cac7Sagc #include <sys/cdefs.h>
71fe37413Skamil #include <sys/stat.h>
8f6a99c40Skamil #include <sys/time.h>
957bbaf57Schristos #include <locale.h>
10f6a99c40Skamil #include <time.h>
116377cac7Sagc 
126377cac7Sagc #ifndef lint
13*ce8041bdSkamil __RCSID("$NetBSD: main.c,v 1.23 2018/05/08 16:37:59 kamil Exp $");
146377cac7Sagc #endif
156377cac7Sagc 
16e1b2664cSjtc 
17e1b2664cSjtc #define	EXTERN				/* define EXTERNs in sh.h */
18e1b2664cSjtc 
19e1b2664cSjtc #include "sh.h"
20e1b2664cSjtc 
21e1b2664cSjtc extern char **environ;
22e1b2664cSjtc 
23e1b2664cSjtc /*
24e1b2664cSjtc  * global data
25e1b2664cSjtc  */
26e1b2664cSjtc 
27e1b2664cSjtc static void	reclaim ARGS((void));
28e1b2664cSjtc static void	remove_temps ARGS((struct temp *tp));
29e1b2664cSjtc static int	is_restricted ARGS((char *name));
30e1b2664cSjtc 
31e1b2664cSjtc /*
32e1b2664cSjtc  * shell initialization
33e1b2664cSjtc  */
34e1b2664cSjtc 
3548ee8d12Shubertf static const char initifs[] = "IFS= \t\n";
36e1b2664cSjtc 
3748ee8d12Shubertf static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
38e1b2664cSjtc 
39e1b2664cSjtc static const char version_param[] =
40e1b2664cSjtc #ifdef KSH
41e1b2664cSjtc 	"KSH_VERSION"
42e1b2664cSjtc #else /* KSH */
43e1b2664cSjtc 	"SH_VERSION"
44e1b2664cSjtc #endif /* KSH */
45e1b2664cSjtc 	;
46e1b2664cSjtc 
47e1b2664cSjtc static const char *const initcoms [] = {
48e1b2664cSjtc 	"typeset", "-x", "SHELL", "PATH", "HOME", NULL,
49e1b2664cSjtc 	"typeset", "-r", version_param, NULL,
5048ee8d12Shubertf 	"typeset", "-i", "PPID", NULL,
5148ee8d12Shubertf 	"typeset", "-i", "OPTIND=1", NULL,
52e1b2664cSjtc #ifdef KSH
5348ee8d12Shubertf 	"eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,
54e1b2664cSjtc #endif /* KSH */
55e1b2664cSjtc 	"alias",
56e1b2664cSjtc 	 /* Standard ksh aliases */
57e1b2664cSjtc 	  "hash=alias -t",	/* not "alias -t --": hash -r needs to work */
58e1b2664cSjtc 	  "type=whence -v",
59e1b2664cSjtc #ifdef JOBS
60e1b2664cSjtc 	  "stop=kill -STOP",
61e1b2664cSjtc 	  "suspend=kill -STOP $$",
62e1b2664cSjtc #endif
63e1b2664cSjtc #ifdef KSH
64e1b2664cSjtc 	  "autoload=typeset -fu",
65e1b2664cSjtc 	  "functions=typeset -f",
665a412486Sjtc # ifdef HISTORY
67e1b2664cSjtc 	  "history=fc -l",
685a412486Sjtc # endif /* HISTORY */
69e1b2664cSjtc 	  "integer=typeset -i",
70e1b2664cSjtc 	  "nohup=nohup ",
71e1b2664cSjtc 	  "local=typeset",
72e1b2664cSjtc 	  "r=fc -e -",
73e1b2664cSjtc #endif /* KSH */
74e1b2664cSjtc #ifdef KSH
75e1b2664cSjtc 	 /* Aliases that are builtin commands in at&t */
76e1b2664cSjtc 	  "login=exec login",
77b186175fSjschauma #ifndef __NetBSD__
78e1b2664cSjtc 	  "newgrp=exec newgrp",
79b186175fSjschauma #endif /* __NetBSD__ */
80e1b2664cSjtc #endif /* KSH */
81e1b2664cSjtc 	  NULL,
82e1b2664cSjtc 	/* this is what at&t ksh seems to track, with the addition of emacs */
83e1b2664cSjtc 	"alias", "-tU",
84e1b2664cSjtc 	  "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
85e1b2664cSjtc 	  "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who",
86e1b2664cSjtc 	  NULL,
87e1b2664cSjtc #ifdef EXTRA_INITCOMS
88e1b2664cSjtc 	EXTRA_INITCOMS, NULL,
89e1b2664cSjtc #endif /* EXTRA_INITCOMS */
90e1b2664cSjtc 	NULL
91e1b2664cSjtc };
92e1b2664cSjtc 
93e1b2664cSjtc int
main(int argc,char * argv[])94f662a744Smycroft main(int argc, char *argv[])
95e1b2664cSjtc {
96*ce8041bdSkamil 	int i;
97e1b2664cSjtc 	int argi;
98e1b2664cSjtc 	Source *s;
99e1b2664cSjtc 	struct block *l;
10048ee8d12Shubertf 	int restricted, errexit;
101e1b2664cSjtc 	char **wp;
102e1b2664cSjtc 	struct env env;
10348ee8d12Shubertf 	pid_t ppid;
104e1b2664cSjtc 
105e1b2664cSjtc 	/* make sure argv[] is sane */
106e1b2664cSjtc 	if (!*argv) {
107e1b2664cSjtc 		static const char	*empty_argv[] = {
108e1b2664cSjtc 					    "pdksh", (char *) 0
109e1b2664cSjtc 					};
110e1b2664cSjtc 
111a397ec1fSchristos 		argv = (char **)__UNCONST(empty_argv);
112e1b2664cSjtc 		argc = 1;
113e1b2664cSjtc 	}
114e1b2664cSjtc 	kshname = *argv;
115e1b2664cSjtc 
116e1b2664cSjtc 	ainit(&aperm);		/* initialize permanent Area */
117e1b2664cSjtc 
1187b9b4ac6Swiz 	/* set up base environment */
119614eee46Sjtc 	memset(&env, 0, sizeof(env));
120e1b2664cSjtc 	env.type = E_NONE;
121e1b2664cSjtc 	ainit(&env.area);
122e1b2664cSjtc 	e = &env;
123e1b2664cSjtc 	newblock();		/* set up global l->vars and l->funs */
124e1b2664cSjtc 
125e1b2664cSjtc 	/* Do this first so output routines (eg, errorf, shellf) can work */
126e1b2664cSjtc 	initio();
127e1b2664cSjtc 
128e1b2664cSjtc 	initvar();
129e1b2664cSjtc 
130e1b2664cSjtc 	initctypes();
131e1b2664cSjtc 
132e1b2664cSjtc 	inittraps();
133e1b2664cSjtc 
134e1b2664cSjtc #ifdef KSH
135e1b2664cSjtc 	coproc_init();
136e1b2664cSjtc #endif /* KSH */
137e1b2664cSjtc 
138e1b2664cSjtc 	/* set up variable and command dictionaries */
139e1b2664cSjtc 	tinit(&taliases, APERM, 0);
140e1b2664cSjtc 	tinit(&aliases, APERM, 0);
141e1b2664cSjtc 	tinit(&homedirs, APERM, 0);
142e1b2664cSjtc 
143e1b2664cSjtc 	/* define shell keywords */
144e1b2664cSjtc 	initkeywords();
145e1b2664cSjtc 
146e1b2664cSjtc 	/* define built-in commands */
147e1b2664cSjtc 	tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
148e1b2664cSjtc 	for (i = 0; shbuiltins[i].name != NULL; i++)
149e1b2664cSjtc 		builtin(shbuiltins[i].name, shbuiltins[i].func);
150e1b2664cSjtc 	for (i = 0; kshbuiltins[i].name != NULL; i++)
151e1b2664cSjtc 		builtin(kshbuiltins[i].name, kshbuiltins[i].func);
152e1b2664cSjtc 
153e1b2664cSjtc 	init_histvec();
154e1b2664cSjtc 
155e1b2664cSjtc 	def_path = DEFAULT__PATH;
156e1b2664cSjtc #if defined(HAVE_CONFSTR) && defined(_CS_PATH)
157e1b2664cSjtc 	{
158e1b2664cSjtc 		size_t len = confstr(_CS_PATH, (char *) 0, 0);
159e1b2664cSjtc 		char *new;
160e1b2664cSjtc 
161e1b2664cSjtc 		if (len > 0) {
162e1b2664cSjtc 			confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1);
163e1b2664cSjtc 			def_path = new;
164e1b2664cSjtc 		}
165e1b2664cSjtc 	}
166e1b2664cSjtc #endif /* HAVE_CONFSTR && _CS_PATH */
16748ee8d12Shubertf 
16848ee8d12Shubertf 	/* Set PATH to def_path (will set the path global variable).
16948ee8d12Shubertf 	 * (import of environment below will probably change this setting).
17048ee8d12Shubertf 	 */
17148ee8d12Shubertf 	{
17248ee8d12Shubertf 		struct tbl *vp = global("PATH");
17348ee8d12Shubertf 		/* setstr can't fail here */
17448ee8d12Shubertf 		setstr(vp, def_path, KSH_RETURN_ERROR);
17548ee8d12Shubertf 	}
176e1b2664cSjtc 
177e1b2664cSjtc 
178f662a744Smycroft 	/* Turn on nohup by default for now - will change to off
179f662a744Smycroft 	 * by default once people are aware of its existence
180e1b2664cSjtc 	 * (at&t ksh does not have a nohup option - it always sends
181e1b2664cSjtc 	 * the hup).
182e1b2664cSjtc 	 */
183e1b2664cSjtc 	Flag(FNOHUP) = 1;
184e1b2664cSjtc 
185e1b2664cSjtc 	/* Turn on brace expansion by default.  At&t ksh's that have
186e1b2664cSjtc 	 * alternation always have it on.  BUT, posix doesn't have
187e1b2664cSjtc 	 * brace expansion, so set this before setting up FPOSIX
188e1b2664cSjtc 	 * (change_flag() clears FBRACEEXPAND when FPOSIX is set).
189e1b2664cSjtc 	 */
190e1b2664cSjtc #ifdef BRACE_EXPAND
191e1b2664cSjtc 	Flag(FBRACEEXPAND) = 1;
192e1b2664cSjtc #endif /* BRACE_EXPAND */
193e1b2664cSjtc 
194e1b2664cSjtc 	/* set posix flag just before environment so that it will have
195e1b2664cSjtc 	 * exactly the same effect as the POSIXLY_CORRECT environment
196e1b2664cSjtc 	 * variable.  If this needs to be done sooner to ensure correct posix
197e1b2664cSjtc 	 * operation, an initial scan of the environment will also have
198e1b2664cSjtc 	 * done sooner.
199e1b2664cSjtc 	 */
200e1b2664cSjtc #ifdef POSIXLY_CORRECT
201e1b2664cSjtc 	change_flag(FPOSIX, OF_SPECIAL, 1);
202e1b2664cSjtc #endif /* POSIXLY_CORRECT */
203e1b2664cSjtc 
204a94ce5a7Sprovos 	/* Set edit mode to emacs by default, may be overridden
205a94ce5a7Sprovos 	 * by the environment or the user.  Also, we want tab completion
206a94ce5a7Sprovos 	 * on in vi by default. */
207a94ce5a7Sprovos #if defined(EDIT) && defined(EMACS)
208a94ce5a7Sprovos 	change_flag(FEMACS, OF_SPECIAL, 1);
209a94ce5a7Sprovos #endif /* EDIT && EMACS */
210a94ce5a7Sprovos #if defined(EDIT) && defined(VI)
211a94ce5a7Sprovos 	Flag(FVITABCOMPLETE) = 1;
212a94ce5a7Sprovos #endif /* EDIT && VI */
213a94ce5a7Sprovos 
2147b9b4ac6Swiz 	/* import environment */
215e1b2664cSjtc 	if (environ != NULL)
216e1b2664cSjtc 		for (wp = environ; *wp != NULL; wp++)
217e1b2664cSjtc 			typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
218e1b2664cSjtc 
219e1b2664cSjtc 	kshpid = procpid = getpid();
220e1b2664cSjtc 	typeset(initifs, 0, 0, 0, 0);	/* for security */
221e1b2664cSjtc 
222e1b2664cSjtc 	/* assign default shell variable values */
223e1b2664cSjtc 	substitute(initsubs, 0);
224e1b2664cSjtc 
225e1b2664cSjtc 	/* Figure out the current working directory and set $PWD */
226e1b2664cSjtc 	{
227e1b2664cSjtc 		struct stat s_pwd, s_dot;
228e1b2664cSjtc 		struct tbl *pwd_v = global("PWD");
229e1b2664cSjtc 		char *pwd = str_val(pwd_v);
230e1b2664cSjtc 		char *pwdx = pwd;
231e1b2664cSjtc 
232e1b2664cSjtc 		/* Try to use existing $PWD if it is valid */
233e1b2664cSjtc 		if (!ISABSPATH(pwd)
234e1b2664cSjtc 		    || stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0
235e1b2664cSjtc 		    || s_pwd.st_dev != s_dot.st_dev
236e1b2664cSjtc 		    || s_pwd.st_ino != s_dot.st_ino)
237e1b2664cSjtc 			pwdx = (char *) 0;
238e1b2664cSjtc 		set_current_wd(pwdx);
239e1b2664cSjtc 		if (current_wd[0])
240e1b2664cSjtc 			simplify_path(current_wd);
241e1b2664cSjtc 		/* Only set pwd if we know where we are or if it had a
242e1b2664cSjtc 		 * bogus value
243e1b2664cSjtc 		 */
244e1b2664cSjtc 		if (current_wd[0] || pwd != null)
24548ee8d12Shubertf 			/* setstr can't fail here */
24648ee8d12Shubertf 			setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
247e1b2664cSjtc 	}
24848ee8d12Shubertf 	ppid = getppid();
24948ee8d12Shubertf 	setint(global("PPID"), (long) ppid);
250e1b2664cSjtc #ifdef KSH
25148ee8d12Shubertf 	setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid));
252e1b2664cSjtc #endif /* KSH */
25348ee8d12Shubertf 	/* setstr can't fail here */
25448ee8d12Shubertf 	setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
255e1b2664cSjtc 
256e1b2664cSjtc 	/* execute initialization statements */
257a397ec1fSchristos 	for (wp = (char**)__UNCONST(initcoms); *wp != NULL; wp++) {
258e1b2664cSjtc 		shcomexec(wp);
259e1b2664cSjtc 		for (; *wp != NULL; wp++)
260e1b2664cSjtc 			;
261e1b2664cSjtc 	}
262e1b2664cSjtc 
26348ee8d12Shubertf 
26448ee8d12Shubertf 	ksheuid = geteuid();
26548ee8d12Shubertf 	safe_prompt = ksheuid ? "$ " : "# ";
266e1b2664cSjtc 	{
267e1b2664cSjtc 		struct tbl *vp = global("PS1");
268e1b2664cSjtc 
269e1b2664cSjtc 		/* Set PS1 if it isn't set, or we are root and prompt doesn't
270e1b2664cSjtc 		 * contain a #.
271e1b2664cSjtc 		 */
27248ee8d12Shubertf 		if (!(vp->flag & ISSET)
27348ee8d12Shubertf 		    || (!ksheuid && !strchr(str_val(vp), '#')))
27448ee8d12Shubertf 			/* setstr can't fail here */
27548ee8d12Shubertf 			setstr(vp, safe_prompt, KSH_RETURN_ERROR);
276e1b2664cSjtc 	}
277e1b2664cSjtc 
278e1b2664cSjtc 	/* Set this before parsing arguments */
27948ee8d12Shubertf 	Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
280e1b2664cSjtc 
281e1b2664cSjtc 	/* this to note if monitor is set on command line (see below) */
282e1b2664cSjtc 	Flag(FMONITOR) = 127;
283e1b2664cSjtc 	argi = parse_args(argv, OF_CMDLINE, (int *) 0);
2849dc385beSmycroft 	if (argi < 0) {
285e1b2664cSjtc 		exit(1);
2869dc385beSmycroft 		/* NOTREACHED */
2879dc385beSmycroft 	}
288e1b2664cSjtc 
289e1b2664cSjtc 	if (Flag(FCOMMAND)) {
290e1b2664cSjtc 		s = pushs(SSTRING, ATEMP);
291e1b2664cSjtc 		if (!(s->start = s->str = argv[argi++]))
292e1b2664cSjtc 			errorf("-c requires an argument");
293e1b2664cSjtc 		if (argv[argi])
294e1b2664cSjtc 			kshname = argv[argi++];
295e1b2664cSjtc 	} else if (argi < argc && !Flag(FSTDIN)) {
296e1b2664cSjtc 		s = pushs(SFILE, ATEMP);
297e1b2664cSjtc 		s->file = argv[argi++];
298e1b2664cSjtc 		s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
299e1b2664cSjtc 		if (s->u.shf == NULL) {
300e1b2664cSjtc 			exstat = 127; /* POSIX */
301e1b2664cSjtc 			errorf("%s: %s", s->file, strerror(errno));
302e1b2664cSjtc 		}
303e1b2664cSjtc 		kshname = s->file;
304e1b2664cSjtc 	} else {
305e1b2664cSjtc 		Flag(FSTDIN) = 1;
306e1b2664cSjtc 		s = pushs(SSTDIN, ATEMP);
307e1b2664cSjtc 		s->file = "<stdin>";
308e1b2664cSjtc 		s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
309e1b2664cSjtc 				      (struct shf *) 0);
310e1b2664cSjtc 		if (isatty(0) && isatty(2)) {
31148ee8d12Shubertf 			Flag(FTALKING) = Flag(FTALKING_I) = 1;
312e1b2664cSjtc 			/* The following only if isatty(0) */
313e1b2664cSjtc 			s->flags |= SF_TTY;
314e1b2664cSjtc 			s->u.shf->flags |= SHF_INTERRUPT;
315e1b2664cSjtc 			s->file = (char *) 0;
316e1b2664cSjtc 		}
317e1b2664cSjtc 	}
318e1b2664cSjtc 
319e1b2664cSjtc 	/* This bizarreness is mandated by POSIX */
320e1b2664cSjtc 	{
321e1b2664cSjtc 		struct stat s_stdin;
322e1b2664cSjtc 
323f662a744Smycroft 		if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
324f662a744Smycroft 		    Flag(FTALKING))
325e1b2664cSjtc 			reset_nonblock(0);
326e1b2664cSjtc 	}
327e1b2664cSjtc 
328e1b2664cSjtc 	/* initialize job control */
329e1b2664cSjtc 	i = Flag(FMONITOR) != 127;
330e1b2664cSjtc 	Flag(FMONITOR) = 0;
331e1b2664cSjtc 	j_init(i);
332e1b2664cSjtc #ifdef EDIT
333e1b2664cSjtc 	/* Do this after j_init(), as tty_fd is not initialized 'til then */
334e1b2664cSjtc 	if (Flag(FTALKING))
335e1b2664cSjtc 		x_init();
336e1b2664cSjtc #endif
337e1b2664cSjtc 
338e1b2664cSjtc 	l = e->loc;
339e1b2664cSjtc 	l->argv = &argv[argi - 1];
340e1b2664cSjtc 	l->argc = argc - argi;
341a397ec1fSchristos 	l->argv[0] = (char *)__UNCONST(kshname);
342e1b2664cSjtc 	getopts_reset(1);
343e1b2664cSjtc 
344e1b2664cSjtc 	/* Disable during .profile/ENV reading */
345e1b2664cSjtc 	restricted = Flag(FRESTRICTED);
346e1b2664cSjtc 	Flag(FRESTRICTED) = 0;
34748ee8d12Shubertf 	errexit = Flag(FERREXIT);
34848ee8d12Shubertf 	Flag(FERREXIT) = 0;
349e1b2664cSjtc 
350e1b2664cSjtc 	/* Do this before profile/$ENV so that if it causes problems in them,
351e1b2664cSjtc 	 * user will know why things broke.
352e1b2664cSjtc 	 */
353e1b2664cSjtc 	if (!current_wd[0] && Flag(FTALKING))
35413351aa1Skamil 		warningf(false, "Cannot determine current working directory");
355e1b2664cSjtc 
356e1b2664cSjtc 	if (Flag(FLOGIN)) {
3575a412486Sjtc 		include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1);
358e1b2664cSjtc 		if (!Flag(FPRIVILEGED))
359e1b2664cSjtc 			include(substitute("$HOME/.profile", 0), 0,
360e1b2664cSjtc 				(char **) 0, 1);
361e1b2664cSjtc 	}
362e1b2664cSjtc 
363e1b2664cSjtc 	if (Flag(FPRIVILEGED))
364e1b2664cSjtc 		include("/etc/suid_profile", 0, (char **) 0, 1);
365e1b2664cSjtc 	else {
366e1b2664cSjtc 		char *env_file;
367e1b2664cSjtc 
368e1b2664cSjtc #ifndef KSH
369e1b2664cSjtc 		if (!Flag(FPOSIX))
370e1b2664cSjtc 			env_file = null;
371e1b2664cSjtc 		else
372e1b2664cSjtc #endif /* !KSH */
373e1b2664cSjtc 			/* include $ENV */
374e1b2664cSjtc 			env_file = str_val(global("ENV"));
375e1b2664cSjtc 
376e1b2664cSjtc #ifdef DEFAULT_ENV
377e1b2664cSjtc 		/* If env isn't set, include default environment */
378e1b2664cSjtc 		if (env_file == null)
379a397ec1fSchristos 			env_file = __UNCONST(DEFAULT_ENV);
380e1b2664cSjtc #endif /* DEFAULT_ENV */
381e1b2664cSjtc 		env_file = substitute(env_file, DOTILDE);
382e1b2664cSjtc 		if (*env_file != '\0')
383e1b2664cSjtc 			include(env_file, 0, (char **) 0, 1);
384e1b2664cSjtc 		else if (Flag(FTALKING))
385e1b2664cSjtc 			include(substitute("$HOME/kshrc.ksh", 0), 0,
386e1b2664cSjtc 				(char **) 0, 1);
387e1b2664cSjtc 	}
388e1b2664cSjtc 
389e1b2664cSjtc 	if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL"))))
390e1b2664cSjtc 		restricted = 1;
391e1b2664cSjtc 	if (restricted) {
392e1b2664cSjtc 		static const char *const restr_com[] = {
393e1b2664cSjtc 						"typeset", "-r", "PATH",
394e1b2664cSjtc 						    "ENV", "SHELL",
395e1b2664cSjtc 						(char *) 0
396e1b2664cSjtc 					    };
397a397ec1fSchristos 		shcomexec((char **)__UNCONST(restr_com));
398e1b2664cSjtc 		/* After typeset command... */
399e1b2664cSjtc 		Flag(FRESTRICTED) = 1;
400e1b2664cSjtc 	}
40148ee8d12Shubertf 	if (errexit)
40248ee8d12Shubertf 		Flag(FERREXIT) = 1;
403e1b2664cSjtc 
404e1b2664cSjtc 	if (Flag(FTALKING)) {
405e1b2664cSjtc 		hist_init(s);
406e1b2664cSjtc #ifdef KSH
407e1b2664cSjtc 		alarm_init();
408e1b2664cSjtc #endif /* KSH */
409e1b2664cSjtc 	} else
410e1b2664cSjtc 		Flag(FTRACKALL) = 1;	/* set after ENV */
411e1b2664cSjtc 
41257bbaf57Schristos 	setlocale(LC_CTYPE, "");
41313351aa1Skamil 	shell(s, true);	/* doesn't return */
414e1b2664cSjtc 	return 0;
415e1b2664cSjtc }
416e1b2664cSjtc 
417e1b2664cSjtc int
include(name,argc,argv,intr_ok)418e1b2664cSjtc include(name, argc, argv, intr_ok)
419e1b2664cSjtc 	const char *name;
420e1b2664cSjtc 	int argc;
421e1b2664cSjtc 	char **argv;
422e1b2664cSjtc 	int intr_ok;
423e1b2664cSjtc {
424*ce8041bdSkamil 	Source *volatile s = NULL;
425e1b2664cSjtc 	struct shf *shf;
426e1b2664cSjtc 	char **volatile old_argv;
427e1b2664cSjtc 	volatile int old_argc;
428e1b2664cSjtc 	int i;
429e1b2664cSjtc 
430e1b2664cSjtc 	shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
431e1b2664cSjtc 	if (shf == NULL)
432e1b2664cSjtc 		return -1;
433e1b2664cSjtc 
434e1b2664cSjtc 	if (argv) {
435e1b2664cSjtc 		old_argv = e->loc->argv;
436e1b2664cSjtc 		old_argc = e->loc->argc;
437e1b2664cSjtc 	} else {
438e1b2664cSjtc 		old_argv = (char **) 0;
439e1b2664cSjtc 		old_argc = 0;
440e1b2664cSjtc 	}
441e1b2664cSjtc 	newenv(E_INCL);
442e1b2664cSjtc 	i = ksh_sigsetjmp(e->jbuf, 0);
443e1b2664cSjtc 	if (i) {
44448ee8d12Shubertf 		if (s) /* Do this before quitenv(), which frees the memory */
445e1b2664cSjtc 			shf_close(s->u.shf);
44648ee8d12Shubertf 		quitenv();
447e1b2664cSjtc 		if (old_argv) {
448e1b2664cSjtc 			e->loc->argv = old_argv;
449e1b2664cSjtc 			e->loc->argc = old_argc;
450e1b2664cSjtc 		}
451e1b2664cSjtc 		switch (i) {
452e1b2664cSjtc 		  case LRETURN:
453e1b2664cSjtc 		  case LERROR:
454e1b2664cSjtc 			return exstat & 0xff; /* see below */
455e1b2664cSjtc 		  case LINTR:
456e1b2664cSjtc 			/* intr_ok is set if we are including .profile or $ENV.
457e1b2664cSjtc 			 * If user ^C's out, we don't want to kill the shell...
458e1b2664cSjtc 			 */
459e1b2664cSjtc 			if (intr_ok && (exstat - 128) != SIGTERM)
460e1b2664cSjtc 				return 1;
461e1b2664cSjtc 			/* fall through... */
462e1b2664cSjtc 		  case LEXIT:
463e1b2664cSjtc 		  case LLEAVE:
464e1b2664cSjtc 		  case LSHELL:
465e1b2664cSjtc 			unwind(i);
466e1b2664cSjtc 			/*NOREACHED*/
467e1b2664cSjtc 		  default:
468e1b2664cSjtc 			internal_errorf(1, "include: %d", i);
469e1b2664cSjtc 			/*NOREACHED*/
470e1b2664cSjtc 		}
471e1b2664cSjtc 	}
472e1b2664cSjtc 	if (argv) {
473e1b2664cSjtc 		e->loc->argv = argv;
474e1b2664cSjtc 		e->loc->argc = argc;
475e1b2664cSjtc 	}
476e1b2664cSjtc 	s = pushs(SFILE, ATEMP);
477e1b2664cSjtc 	s->u.shf = shf;
478e1b2664cSjtc 	s->file = str_save(name, ATEMP);
47913351aa1Skamil 	i = shell(s, false);
480e1b2664cSjtc 	shf_close(s->u.shf);
48148ee8d12Shubertf 	quitenv();
482e1b2664cSjtc 	if (old_argv) {
483e1b2664cSjtc 		e->loc->argv = old_argv;
484e1b2664cSjtc 		e->loc->argc = old_argc;
485e1b2664cSjtc 	}
486e1b2664cSjtc 	return i & 0xff;	/* & 0xff to ensure value not -1 */
487e1b2664cSjtc }
488e1b2664cSjtc 
489e1b2664cSjtc int
command(comm)490e1b2664cSjtc command(comm)
491e1b2664cSjtc 	const char *comm;
492e1b2664cSjtc {
493*ce8041bdSkamil 	Source *s;
49416464dcdSchristos 	int r;
495e1b2664cSjtc 
496e1b2664cSjtc 	s = pushs(SSTRING, ATEMP);
497e1b2664cSjtc 	s->start = s->str = comm;
49813351aa1Skamil 	r = shell(s, false);
49916464dcdSchristos 	afree(s, ATEMP);
50016464dcdSchristos 	return r;
501e1b2664cSjtc }
502e1b2664cSjtc 
503e1b2664cSjtc /*
504e1b2664cSjtc  * run the commands from the input source, returning status.
505e1b2664cSjtc  */
506e1b2664cSjtc int
shell(s,toplevel)507e1b2664cSjtc shell(s, toplevel)
508e1b2664cSjtc 	Source *volatile s;		/* input source */
509e1b2664cSjtc 	int volatile toplevel;
510e1b2664cSjtc {
511e1b2664cSjtc 	struct op *t;
512e1b2664cSjtc 	volatile int wastty = s->flags & SF_TTY;
513e1b2664cSjtc 	volatile int attempts = 13;
514e1b2664cSjtc 	volatile int interactive = Flag(FTALKING) && toplevel;
515f662a744Smycroft 	Source *volatile old_source = source;
516e1b2664cSjtc 	int i;
517e1b2664cSjtc 
518e1b2664cSjtc 	newenv(E_PARSE);
519e1b2664cSjtc 	if (interactive)
520e1b2664cSjtc 		really_exit = 0;
521e1b2664cSjtc 	i = ksh_sigsetjmp(e->jbuf, 0);
522e1b2664cSjtc 	if (i) {
523e1b2664cSjtc 		switch (i) {
524e1b2664cSjtc 		  case LINTR: /* we get here if SIGINT not caught or ignored */
525e1b2664cSjtc 		  case LERROR:
526e1b2664cSjtc 		  case LSHELL:
527e1b2664cSjtc 			if (interactive) {
528e1b2664cSjtc 				if (i == LINTR)
5295d331600Sjoerg 					shellf("%s", newline);
530e1b2664cSjtc 				/* Reset any eof that was read as part of a
531e1b2664cSjtc 				 * multiline command.
532e1b2664cSjtc 				 */
533e1b2664cSjtc 				if (Flag(FIGNOREEOF) && s->type == SEOF
534e1b2664cSjtc 				    && wastty)
535e1b2664cSjtc 					s->type = SSTDIN;
536e1b2664cSjtc 				/* Used by exit command to get back to
537e1b2664cSjtc 				 * top level shell.  Kind of strange since
538e1b2664cSjtc 				 * interactive is set if we are reading from
539e1b2664cSjtc 				 * a tty, but to have stopped jobs, one only
540e1b2664cSjtc 				 * needs FMONITOR set (not FTALKING/SF_TTY)...
541e1b2664cSjtc 				 */
542f662a744Smycroft 				/* toss any input we have so far */
543f662a744Smycroft 				s->start = s->str = null;
544e1b2664cSjtc 				break;
545e1b2664cSjtc 			}
546e1b2664cSjtc 			/* fall through... */
547e1b2664cSjtc 		  case LEXIT:
548e1b2664cSjtc 		  case LLEAVE:
549e1b2664cSjtc 		  case LRETURN:
550f662a744Smycroft 			source = old_source;
551e1b2664cSjtc 			quitenv();
552e1b2664cSjtc 			unwind(i);	/* keep on going */
553e1b2664cSjtc 			/*NOREACHED*/
554e1b2664cSjtc 		  default:
555f662a744Smycroft 			source = old_source;
556e1b2664cSjtc 			quitenv();
557e1b2664cSjtc 			internal_errorf(1, "shell: %d", i);
558e1b2664cSjtc 			/*NOREACHED*/
559e1b2664cSjtc 		}
560e1b2664cSjtc 	}
561e1b2664cSjtc 
562e1b2664cSjtc 	while (1) {
563e1b2664cSjtc 		if (trap)
564e1b2664cSjtc 			runtraps(0);
565e1b2664cSjtc 
56645e5a869Sthorpej 		if (s->next == NULL) {
567e1b2664cSjtc 			if (Flag(FVERBOSE))
568e1b2664cSjtc 				s->flags |= SF_ECHO;
569e1b2664cSjtc 			else
570e1b2664cSjtc 				s->flags &= ~SF_ECHO;
57145e5a869Sthorpej 		}
572e1b2664cSjtc 
573e1b2664cSjtc 		if (interactive) {
574e1b2664cSjtc 			j_notify();
575e1b2664cSjtc #ifdef KSH
576e1b2664cSjtc 			mcheck();
577e1b2664cSjtc #endif /* KSH */
578e1b2664cSjtc 			set_prompt(PS1, s);
579e1b2664cSjtc 		}
580e1b2664cSjtc 
581e1b2664cSjtc 		t = compile(s);
582e1b2664cSjtc 		if (t != NULL && t->type == TEOF) {
583e1b2664cSjtc 			if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
584e1b2664cSjtc 				shellf("Use `exit' to leave ksh\n");
585e1b2664cSjtc 				s->type = SSTDIN;
586e1b2664cSjtc 			} else if (wastty && !really_exit
587e1b2664cSjtc 				   && j_stopped_running())
588e1b2664cSjtc 			{
589e1b2664cSjtc 				really_exit = 1;
590e1b2664cSjtc 				s->type = SSTDIN;
591e1b2664cSjtc 			} else {
592e1b2664cSjtc 				/* this for POSIX, which says EXIT traps
593e1b2664cSjtc 				 * shall be taken in the environment
594e1b2664cSjtc 				 * immediately after the last command
595e1b2664cSjtc 				 * executed.
596e1b2664cSjtc 				 */
597e1b2664cSjtc 				if (toplevel)
598e1b2664cSjtc 					unwind(LEXIT);
599e1b2664cSjtc 				break;
600e1b2664cSjtc 			}
601e1b2664cSjtc 		}
602e1b2664cSjtc 
603e1b2664cSjtc 		if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
604e1b2664cSjtc 			exstat = execute(t, 0);
605e1b2664cSjtc 
606e1b2664cSjtc 		if (t != NULL && t->type != TEOF && interactive && really_exit)
607e1b2664cSjtc 			really_exit = 0;
608e1b2664cSjtc 
609e1b2664cSjtc 		reclaim();
610e1b2664cSjtc 	}
611e1b2664cSjtc 	quitenv();
612f662a744Smycroft 	source = old_source;
613e1b2664cSjtc 	return exstat;
614e1b2664cSjtc }
615e1b2664cSjtc 
616e1b2664cSjtc /* return to closest error handler or shell(), exit if none found */
617e1b2664cSjtc void
unwind(i)618e1b2664cSjtc unwind(i)
619e1b2664cSjtc 	int i;
620e1b2664cSjtc {
621e1b2664cSjtc 	/* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
622e1b2664cSjtc 	if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR)
623e1b2664cSjtc 			   && sigtraps[SIGEXIT_].trap))
624e1b2664cSjtc 	{
625e1b2664cSjtc 		runtrap(&sigtraps[SIGEXIT_]);
626e1b2664cSjtc 		i = LLEAVE;
627e1b2664cSjtc 	} else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
628e1b2664cSjtc 		runtrap(&sigtraps[SIGERR_]);
629e1b2664cSjtc 		i = LLEAVE;
630e1b2664cSjtc 	}
631e1b2664cSjtc 	while (1) {
632e1b2664cSjtc 		switch (e->type) {
633e1b2664cSjtc 		  case E_PARSE:
634e1b2664cSjtc 		  case E_FUNC:
635e1b2664cSjtc 		  case E_INCL:
636e1b2664cSjtc 		  case E_LOOP:
637e1b2664cSjtc 		  case E_ERRH:
638e1b2664cSjtc 			ksh_siglongjmp(e->jbuf, i);
639e1b2664cSjtc 			/*NOTREACHED*/
640e1b2664cSjtc 
64148ee8d12Shubertf 		  case E_NONE:
64248ee8d12Shubertf 			if (i == LINTR)
64348ee8d12Shubertf 				e->flags |= EF_FAKE_SIGDIE;
64448ee8d12Shubertf 			/* Fall through... */
645e1b2664cSjtc 
646e1b2664cSjtc 		  default:
647e1b2664cSjtc 			quitenv();
648e1b2664cSjtc 		}
649e1b2664cSjtc 	}
650e1b2664cSjtc }
651e1b2664cSjtc 
652e1b2664cSjtc void
newenv(type)653e1b2664cSjtc newenv(type)
654e1b2664cSjtc 	int type;
655e1b2664cSjtc {
656*ce8041bdSkamil 	struct env *ep;
657e1b2664cSjtc 
658e1b2664cSjtc 	ep = (struct env *) alloc(sizeof(*ep), ATEMP);
659e1b2664cSjtc 	ep->type = type;
660e1b2664cSjtc 	ep->flags = 0;
661e1b2664cSjtc 	ainit(&ep->area);
662e1b2664cSjtc 	ep->loc = e->loc;
663e1b2664cSjtc 	ep->savefd = NULL;
664e1b2664cSjtc 	ep->oenv = e;
665e1b2664cSjtc 	ep->temps = NULL;
666e1b2664cSjtc 	e = ep;
667e1b2664cSjtc }
668e1b2664cSjtc 
669e1b2664cSjtc void
quitenv()670e1b2664cSjtc quitenv()
671e1b2664cSjtc {
672*ce8041bdSkamil 	struct env *ep = e;
673*ce8041bdSkamil 	int fd;
674e1b2664cSjtc 
67548ee8d12Shubertf 	if (ep->oenv && ep->oenv->loc != ep->loc)
676e1b2664cSjtc 		popblock();
677e1b2664cSjtc 	if (ep->savefd != NULL) {
678e1b2664cSjtc 		for (fd = 0; fd < NUFILE; fd++)
679e1b2664cSjtc 			/* if ep->savefd[fd] < 0, means fd was closed */
680e1b2664cSjtc 			if (ep->savefd[fd])
681e1b2664cSjtc 				restfd(fd, ep->savefd[fd]);
682e1b2664cSjtc 		if (ep->savefd[2]) /* Clear any write errors */
683e1b2664cSjtc 			shf_reopen(2, SHF_WR, shl_out);
684e1b2664cSjtc 	}
685e1b2664cSjtc 	reclaim();
68648ee8d12Shubertf 
68748ee8d12Shubertf 	/* Bottom of the stack.
68848ee8d12Shubertf 	 * Either main shell is exiting or cleanup_parents_env() was called.
68948ee8d12Shubertf 	 */
69048ee8d12Shubertf 	if (ep->oenv == NULL) {
69148ee8d12Shubertf 		if (ep->type == E_NONE) {	/* Main shell exiting? */
69248ee8d12Shubertf 			if (Flag(FTALKING))
69348ee8d12Shubertf 				hist_finish();
69448ee8d12Shubertf 			j_exit();
69548ee8d12Shubertf 			if (ep->flags & EF_FAKE_SIGDIE) {
69648ee8d12Shubertf 				int sig = exstat - 128;
69748ee8d12Shubertf 
69848ee8d12Shubertf 				/* ham up our death a bit (at&t ksh
69948ee8d12Shubertf 				 * only seems to do this for SIGTERM)
70048ee8d12Shubertf 				 * Don't do it for SIGQUIT, since we'd
70148ee8d12Shubertf 				 * dump a core..
70248ee8d12Shubertf 				 */
70348ee8d12Shubertf 				if (sig == SIGINT || sig == SIGTERM) {
70448ee8d12Shubertf 					setsig(&sigtraps[sig], SIG_DFL,
70548ee8d12Shubertf 						SS_RESTORE_CURR|SS_FORCE);
70648ee8d12Shubertf 					kill(0, sig);
70748ee8d12Shubertf 				}
70848ee8d12Shubertf 			}
70948ee8d12Shubertf 		}
71048ee8d12Shubertf 		exit(exstat);
71148ee8d12Shubertf 	}
71248ee8d12Shubertf 
713e1b2664cSjtc 	e = e->oenv;
714e1b2664cSjtc 	afree(ep, ATEMP);
715e1b2664cSjtc }
716e1b2664cSjtc 
717e1b2664cSjtc /* Called after a fork to cleanup stuff left over from parents environment */
718e1b2664cSjtc void
cleanup_parents_env()719e1b2664cSjtc cleanup_parents_env()
720e1b2664cSjtc {
721e1b2664cSjtc 	struct env *ep;
722e1b2664cSjtc 	int fd;
723e1b2664cSjtc 
724e1b2664cSjtc 	/* Don't clean up temporary files - parent will probably need them.
725e1b2664cSjtc 	 * Also, can't easily reclaim memory since variables, etc. could be
726f662a744Smycroft 	 * anywhere.
727e1b2664cSjtc 	 */
728e1b2664cSjtc 
729e1b2664cSjtc 	/* close all file descriptors hiding in savefd */
730e1b2664cSjtc 	for (ep = e; ep; ep = ep->oenv) {
73148ee8d12Shubertf 		if (ep->savefd) {
732e1b2664cSjtc 			for (fd = 0; fd < NUFILE; fd++)
733e1b2664cSjtc 				if (ep->savefd[fd] > 0)
734e1b2664cSjtc 					close(ep->savefd[fd]);
73548ee8d12Shubertf 			afree(ep->savefd, &ep->area);
73648ee8d12Shubertf 			ep->savefd = (short *) 0;
73748ee8d12Shubertf 		}
738e1b2664cSjtc 	}
739e1b2664cSjtc 	e->oenv = (struct env *) 0;
740e1b2664cSjtc }
741e1b2664cSjtc 
742614eee46Sjtc /* Called just before an execve cleanup stuff temporary files */
743614eee46Sjtc void
cleanup_proc_env()744614eee46Sjtc cleanup_proc_env()
745614eee46Sjtc {
746614eee46Sjtc 	struct env *ep;
747614eee46Sjtc 
748614eee46Sjtc 	for (ep = e; ep; ep = ep->oenv)
749614eee46Sjtc 		remove_temps(ep->temps);
750614eee46Sjtc }
751614eee46Sjtc 
752e1b2664cSjtc /* remove temp files and free ATEMP Area */
753e1b2664cSjtc static void
reclaim()754e1b2664cSjtc reclaim()
755e1b2664cSjtc {
756e1b2664cSjtc 	remove_temps(e->temps);
757e1b2664cSjtc 	e->temps = NULL;
758e1b2664cSjtc 	afreeall(&e->area);
759e1b2664cSjtc }
760e1b2664cSjtc 
761e1b2664cSjtc static void
remove_temps(tp)762e1b2664cSjtc remove_temps(tp)
763e1b2664cSjtc 	struct temp *tp;
764e1b2664cSjtc {
765e1b2664cSjtc 	for (; tp != NULL; tp = tp->next)
766614eee46Sjtc 		if (tp->pid == procpid) {
767e1b2664cSjtc 			unlink(tp->name);
768e1b2664cSjtc 		}
769614eee46Sjtc }
770e1b2664cSjtc 
771e1b2664cSjtc /* Returns true if name refers to a restricted shell */
772e1b2664cSjtc static int
is_restricted(name)773e1b2664cSjtc is_restricted(name)
774e1b2664cSjtc 	char *name;
775e1b2664cSjtc {
776e1b2664cSjtc 	char *p;
777e1b2664cSjtc 
778e1b2664cSjtc 	if ((p = ksh_strrchr_dirsep(name)))
779e1b2664cSjtc 		name = p;
780e1b2664cSjtc 	/* accepts rsh, rksh, rpdksh, pdrksh, etc. */
781e1b2664cSjtc 	return (p = strchr(name, 'r')) && strstr(p, "sh");
782e1b2664cSjtc }
783e1b2664cSjtc 
784e1b2664cSjtc void
aerror(ap,msg)785e1b2664cSjtc aerror(ap, msg)
786e1b2664cSjtc 	Area *ap;
787e1b2664cSjtc 	const char *msg;
788e1b2664cSjtc {
789e1b2664cSjtc 	internal_errorf(1, "alloc: %s", msg);
7905d331600Sjoerg 	errorf("%s", null); /* this is never executed - keeps gcc quiet */
791e1b2664cSjtc 	/*NOTREACHED*/
792e1b2664cSjtc }
793