1*0f2b5450Skamil /* $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>
7fac4b394Skamil #include <sys/stat.h>
81dacfa0dSkamil #include <sys/time.h>
957bbaf57Schristos #include <locale.h>
101dacfa0dSkamil #include <time.h>
116377cac7Sagc
126377cac7Sagc #ifndef lint
13*0f2b5450Skamil __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*0f2b5450Skamil 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))
354dd8a75d5Skamil 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, "");
413dd8a75d5Skamil 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*0f2b5450Skamil 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);
479dd8a75d5Skamil 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*0f2b5450Skamil Source *s;
49416464dcdSchristos int r;
495e1b2664cSjtc
496e1b2664cSjtc s = pushs(SSTRING, ATEMP);
497e1b2664cSjtc s->start = s->str = comm;
498dd8a75d5Skamil 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)
529a2567f3bSjoerg 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*0f2b5450Skamil 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*0f2b5450Skamil struct env *ep = e;
673*0f2b5450Skamil 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);
790a2567f3bSjoerg errorf("%s", null); /* this is never executed - keeps gcc quiet */
791e1b2664cSjtc /*NOTREACHED*/
792e1b2664cSjtc }
793