xref: /plan9/sys/src/ape/cmd/pdksh/main.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * startup, main loop, enviroments and error handling
37dd7cddfSDavid du Colombier  */
47dd7cddfSDavid du Colombier 
57dd7cddfSDavid du Colombier #define	EXTERN				/* define EXTERNs in sh.h */
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier #include "sh.h"
87dd7cddfSDavid du Colombier #include "ksh_stat.h"
97dd7cddfSDavid du Colombier #include "ksh_time.h"
107dd7cddfSDavid du Colombier 
117dd7cddfSDavid du Colombier extern char **environ;
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier /*
147dd7cddfSDavid du Colombier  * global data
157dd7cddfSDavid du Colombier  */
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier static void	reclaim ARGS((void));
187dd7cddfSDavid du Colombier static void	remove_temps ARGS((struct temp *tp));
197dd7cddfSDavid du Colombier static int	is_restricted ARGS((char *name));
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier /*
227dd7cddfSDavid du Colombier  * shell initialization
237dd7cddfSDavid du Colombier  */
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier static const char initifs[] = "IFS= \t\n";
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier static const char version_param[] =
307dd7cddfSDavid du Colombier #ifdef KSH
317dd7cddfSDavid du Colombier 	"KSH_VERSION"
327dd7cddfSDavid du Colombier #else /* KSH */
337dd7cddfSDavid du Colombier 	"SH_VERSION"
347dd7cddfSDavid du Colombier #endif /* KSH */
357dd7cddfSDavid du Colombier 	;
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier static const char *const initcoms [] = {
387dd7cddfSDavid du Colombier 	"typeset", "-x", "SHELL", "PATH", "HOME", NULL,
397dd7cddfSDavid du Colombier 	"typeset", "-r", version_param, NULL,
407dd7cddfSDavid du Colombier 	"typeset", "-i", "PPID", NULL,
417dd7cddfSDavid du Colombier 	"typeset", "-i", "OPTIND=1", NULL,
427dd7cddfSDavid du Colombier #ifdef KSH
437dd7cddfSDavid du Colombier 	"eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,
447dd7cddfSDavid du Colombier #endif /* KSH */
457dd7cddfSDavid du Colombier 	"alias",
467dd7cddfSDavid du Colombier 	 /* Standard ksh aliases */
477dd7cddfSDavid du Colombier 	  "hash=alias -t",	/* not "alias -t --": hash -r needs to work */
487dd7cddfSDavid du Colombier 	  "type=whence -v",
497dd7cddfSDavid du Colombier #ifdef JOBS
507dd7cddfSDavid du Colombier 	  "stop=kill -STOP",
517dd7cddfSDavid du Colombier 	  "suspend=kill -STOP $$",
527dd7cddfSDavid du Colombier #endif
537dd7cddfSDavid du Colombier #ifdef KSH
547dd7cddfSDavid du Colombier 	  "autoload=typeset -fu",
557dd7cddfSDavid du Colombier 	  "functions=typeset -f",
567dd7cddfSDavid du Colombier # ifdef HISTORY
577dd7cddfSDavid du Colombier 	  "history=fc -l",
587dd7cddfSDavid du Colombier # endif /* HISTORY */
597dd7cddfSDavid du Colombier 	  "integer=typeset -i",
607dd7cddfSDavid du Colombier 	  "nohup=nohup ",
617dd7cddfSDavid du Colombier 	  "local=typeset",
627dd7cddfSDavid du Colombier 	  "r=fc -e -",
637dd7cddfSDavid du Colombier #endif /* KSH */
647dd7cddfSDavid du Colombier #ifdef KSH
657dd7cddfSDavid du Colombier 	 /* Aliases that are builtin commands in at&t */
667dd7cddfSDavid du Colombier 	  "login=exec login",
677dd7cddfSDavid du Colombier 	  "newgrp=exec newgrp",
687dd7cddfSDavid du Colombier #endif /* KSH */
697dd7cddfSDavid du Colombier 	  NULL,
707dd7cddfSDavid du Colombier 	/* this is what at&t ksh seems to track, with the addition of emacs */
717dd7cddfSDavid du Colombier 	"alias", "-tU",
727dd7cddfSDavid du Colombier 	  "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
737dd7cddfSDavid du Colombier 	  "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who",
747dd7cddfSDavid du Colombier 	  NULL,
757dd7cddfSDavid du Colombier #ifdef EXTRA_INITCOMS
767dd7cddfSDavid du Colombier 	EXTRA_INITCOMS, NULL,
777dd7cddfSDavid du Colombier #endif /* EXTRA_INITCOMS */
787dd7cddfSDavid du Colombier 	NULL
797dd7cddfSDavid du Colombier };
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier int
main(argc,argv)827dd7cddfSDavid du Colombier main(argc, argv)
837dd7cddfSDavid du Colombier 	int argc;
847dd7cddfSDavid du Colombier 	register char **argv;
857dd7cddfSDavid du Colombier {
867dd7cddfSDavid du Colombier 	register int i;
877dd7cddfSDavid du Colombier 	int argi;
887dd7cddfSDavid du Colombier 	Source *s;
897dd7cddfSDavid du Colombier 	struct block *l;
907dd7cddfSDavid du Colombier 	int restricted, errexit;
917dd7cddfSDavid du Colombier 	char **wp;
927dd7cddfSDavid du Colombier 	struct env env;
937dd7cddfSDavid du Colombier 	pid_t ppid;
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier #ifdef MEM_DEBUG
967dd7cddfSDavid du Colombier 	chmem_set_defaults("ct", 1);
977dd7cddfSDavid du Colombier 	/* chmem_push("+c", 1); */
987dd7cddfSDavid du Colombier #endif /* MEM_DEBUG */
997dd7cddfSDavid du Colombier 
1007dd7cddfSDavid du Colombier #ifdef OS2
1017dd7cddfSDavid du Colombier 	setmode (0, O_BINARY);
1027dd7cddfSDavid du Colombier 	setmode (1, O_TEXT);
1037dd7cddfSDavid du Colombier #endif
1047dd7cddfSDavid du Colombier 
1057dd7cddfSDavid du Colombier 	/* make sure argv[] is sane */
1067dd7cddfSDavid du Colombier 	if (!*argv) {
1077dd7cddfSDavid du Colombier 		static const char	*empty_argv[] = {
1087dd7cddfSDavid du Colombier 					    "pdksh", (char *) 0
1097dd7cddfSDavid du Colombier 					};
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier 		argv = (char **) empty_argv;
1127dd7cddfSDavid du Colombier 		argc = 1;
1137dd7cddfSDavid du Colombier 	}
1147dd7cddfSDavid du Colombier 	kshname = *argv;
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 	ainit(&aperm);		/* initialize permanent Area */
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	/* set up base enviroment */
1197dd7cddfSDavid du Colombier 	memset(&env, 0, sizeof(env));
1207dd7cddfSDavid du Colombier 	env.type = E_NONE;
1217dd7cddfSDavid du Colombier 	ainit(&env.area);
1227dd7cddfSDavid du Colombier 	e = &env;
1237dd7cddfSDavid du Colombier 	newblock();		/* set up global l->vars and l->funs */
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier 	/* Do this first so output routines (eg, errorf, shellf) can work */
1267dd7cddfSDavid du Colombier 	initio();
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier 	initvar();
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	initctypes();
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier 	inittraps();
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier #ifdef KSH
1357dd7cddfSDavid du Colombier 	coproc_init();
1367dd7cddfSDavid du Colombier #endif /* KSH */
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier 	/* set up variable and command dictionaries */
1397dd7cddfSDavid du Colombier 	tinit(&taliases, APERM, 0);
1407dd7cddfSDavid du Colombier 	tinit(&aliases, APERM, 0);
1417dd7cddfSDavid du Colombier 	tinit(&homedirs, APERM, 0);
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier 	/* define shell keywords */
1447dd7cddfSDavid du Colombier 	initkeywords();
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier 	/* define built-in commands */
1477dd7cddfSDavid du Colombier 	tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
1487dd7cddfSDavid du Colombier 	for (i = 0; shbuiltins[i].name != NULL; i++)
1497dd7cddfSDavid du Colombier 		builtin(shbuiltins[i].name, shbuiltins[i].func);
1507dd7cddfSDavid du Colombier 	for (i = 0; kshbuiltins[i].name != NULL; i++)
1517dd7cddfSDavid du Colombier 		builtin(kshbuiltins[i].name, kshbuiltins[i].func);
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier 	init_histvec();
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 	def_path = DEFAULT__PATH;
1567dd7cddfSDavid du Colombier #if defined(HAVE_CONFSTR) && defined(_CS_PATH)
1577dd7cddfSDavid du Colombier 	{
1587dd7cddfSDavid du Colombier 		size_t len = confstr(_CS_PATH, (char *) 0, 0);
1597dd7cddfSDavid du Colombier 		char *new;
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier 		if (len > 0) {
1627dd7cddfSDavid du Colombier 			confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1);
1637dd7cddfSDavid du Colombier 			def_path = new;
1647dd7cddfSDavid du Colombier 		}
1657dd7cddfSDavid du Colombier 	}
1667dd7cddfSDavid du Colombier #endif /* HAVE_CONFSTR && _CS_PATH */
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier 	/* Set PATH to def_path (will set the path global variable).
1697dd7cddfSDavid du Colombier 	 * (import of environment below will probably change this setting).
1707dd7cddfSDavid du Colombier 	 */
1717dd7cddfSDavid du Colombier 	{
1727dd7cddfSDavid du Colombier 		struct tbl *vp = global("PATH");
1737dd7cddfSDavid du Colombier 		/* setstr can't fail here */
1747dd7cddfSDavid du Colombier 		setstr(vp, def_path, KSH_RETURN_ERROR);
1757dd7cddfSDavid du Colombier 	}
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier 	/* Turn on nohup by default for how - will change to off
1797dd7cddfSDavid du Colombier 	 * by default once people are aware of its existance
1807dd7cddfSDavid du Colombier 	 * (at&t ksh does not have a nohup option - it always sends
1817dd7cddfSDavid du Colombier 	 * the hup).
1827dd7cddfSDavid du Colombier 	 */
1837dd7cddfSDavid du Colombier 	Flag(FNOHUP) = 1;
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier 	/* Turn on brace expansion by default.  At&t ksh's that have
1867dd7cddfSDavid du Colombier 	 * alternation always have it on.  BUT, posix doesn't have
1877dd7cddfSDavid du Colombier 	 * brace expansion, so set this before setting up FPOSIX
1887dd7cddfSDavid du Colombier 	 * (change_flag() clears FBRACEEXPAND when FPOSIX is set).
1897dd7cddfSDavid du Colombier 	 */
1907dd7cddfSDavid du Colombier #ifdef BRACE_EXPAND
1917dd7cddfSDavid du Colombier 	Flag(FBRACEEXPAND) = 1;
1927dd7cddfSDavid du Colombier #endif /* BRACE_EXPAND */
1937dd7cddfSDavid du Colombier 
1947dd7cddfSDavid du Colombier 	/* set posix flag just before environment so that it will have
1957dd7cddfSDavid du Colombier 	 * exactly the same effect as the POSIXLY_CORRECT environment
1967dd7cddfSDavid du Colombier 	 * variable.  If this needs to be done sooner to ensure correct posix
1977dd7cddfSDavid du Colombier 	 * operation, an initial scan of the environment will also have
1987dd7cddfSDavid du Colombier 	 * done sooner.
1997dd7cddfSDavid du Colombier 	 */
2007dd7cddfSDavid du Colombier #ifdef POSIXLY_CORRECT
2017dd7cddfSDavid du Colombier 	change_flag(FPOSIX, OF_SPECIAL, 1);
2027dd7cddfSDavid du Colombier #endif /* POSIXLY_CORRECT */
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier 	/* import enviroment */
2057dd7cddfSDavid du Colombier 	if (environ != NULL)
2067dd7cddfSDavid du Colombier 		for (wp = environ; *wp != NULL; wp++)
2077dd7cddfSDavid du Colombier 			typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier 	kshpid = procpid = getpid();
2107dd7cddfSDavid du Colombier 	typeset(initifs, 0, 0, 0, 0);	/* for security */
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier 	/* assign default shell variable values */
2137dd7cddfSDavid du Colombier 	substitute(initsubs, 0);
2147dd7cddfSDavid du Colombier 
2157dd7cddfSDavid du Colombier 	/* Figure out the current working directory and set $PWD */
2167dd7cddfSDavid du Colombier 	{
2177dd7cddfSDavid du Colombier 		struct stat s_pwd, s_dot;
2187dd7cddfSDavid du Colombier 		struct tbl *pwd_v = global("PWD");
2197dd7cddfSDavid du Colombier 		char *pwd = str_val(pwd_v);
2207dd7cddfSDavid du Colombier 		char *pwdx = pwd;
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier 		/* Try to use existing $PWD if it is valid */
2237dd7cddfSDavid du Colombier 		if (!ISABSPATH(pwd)
2247dd7cddfSDavid du Colombier 		    || stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0
2257dd7cddfSDavid du Colombier 		    || s_pwd.st_dev != s_dot.st_dev
2267dd7cddfSDavid du Colombier 		    || s_pwd.st_ino != s_dot.st_ino)
2277dd7cddfSDavid du Colombier 			pwdx = (char *) 0;
2287dd7cddfSDavid du Colombier 		set_current_wd(pwdx);
2297dd7cddfSDavid du Colombier 		if (current_wd[0])
2307dd7cddfSDavid du Colombier 			simplify_path(current_wd);
2317dd7cddfSDavid du Colombier 		/* Only set pwd if we know where we are or if it had a
2327dd7cddfSDavid du Colombier 		 * bogus value
2337dd7cddfSDavid du Colombier 		 */
2347dd7cddfSDavid du Colombier 		if (current_wd[0] || pwd != null)
2357dd7cddfSDavid du Colombier 			/* setstr can't fail here */
2367dd7cddfSDavid du Colombier 			setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
2377dd7cddfSDavid du Colombier 	}
2387dd7cddfSDavid du Colombier 	ppid = getppid();
2397dd7cddfSDavid du Colombier 	setint(global("PPID"), (long) ppid);
2407dd7cddfSDavid du Colombier #ifdef KSH
2417dd7cddfSDavid du Colombier 	setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid));
2427dd7cddfSDavid du Colombier #endif /* KSH */
2437dd7cddfSDavid du Colombier 	/* setstr can't fail here */
2447dd7cddfSDavid du Colombier 	setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 	/* execute initialization statements */
2477dd7cddfSDavid du Colombier 	for (wp = (char**) initcoms; *wp != NULL; wp++) {
2487dd7cddfSDavid du Colombier 		shcomexec(wp);
2497dd7cddfSDavid du Colombier 		for (; *wp != NULL; wp++)
2507dd7cddfSDavid du Colombier 			;
2517dd7cddfSDavid du Colombier 	}
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier 	ksheuid = geteuid();
2557dd7cddfSDavid du Colombier 	safe_prompt = ksheuid ? "$ " : "# ";
2567dd7cddfSDavid du Colombier 	{
2577dd7cddfSDavid du Colombier 		struct tbl *vp = global("PS1");
2587dd7cddfSDavid du Colombier 
2597dd7cddfSDavid du Colombier 		/* Set PS1 if it isn't set, or we are root and prompt doesn't
2607dd7cddfSDavid du Colombier 		 * contain a #.
2617dd7cddfSDavid du Colombier 		 */
2627dd7cddfSDavid du Colombier 		if (!(vp->flag & ISSET)
2637dd7cddfSDavid du Colombier 		    || (!ksheuid && !strchr(str_val(vp), '#')))
2647dd7cddfSDavid du Colombier 			/* setstr can't fail here */
2657dd7cddfSDavid du Colombier 			setstr(vp, safe_prompt, KSH_RETURN_ERROR);
2667dd7cddfSDavid du Colombier 	}
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 	/* Set this before parsing arguments */
2697dd7cddfSDavid du Colombier 	Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	/* this to note if monitor is set on command line (see below) */
2727dd7cddfSDavid du Colombier 	Flag(FMONITOR) = 127;
2737dd7cddfSDavid du Colombier 	argi = parse_args(argv, OF_CMDLINE, (int *) 0);
2747dd7cddfSDavid du Colombier 	if (argi < 0)
2757dd7cddfSDavid du Colombier 		exit(1);
2767dd7cddfSDavid du Colombier 
2777dd7cddfSDavid du Colombier 	if (Flag(FCOMMAND)) {
2787dd7cddfSDavid du Colombier 		s = pushs(SSTRING, ATEMP);
2797dd7cddfSDavid du Colombier 		if (!(s->start = s->str = argv[argi++]))
2807dd7cddfSDavid du Colombier 			errorf("-c requires an argument");
2817dd7cddfSDavid du Colombier 		if (argv[argi])
2827dd7cddfSDavid du Colombier 			kshname = argv[argi++];
2837dd7cddfSDavid du Colombier 	} else if (argi < argc && !Flag(FSTDIN)) {
2847dd7cddfSDavid du Colombier 		s = pushs(SFILE, ATEMP);
2857dd7cddfSDavid du Colombier #ifdef OS2
2867dd7cddfSDavid du Colombier 		/* a bug in os2 extproc shell processing doesn't
2877dd7cddfSDavid du Colombier 		 * pass full pathnames so we have to search for it.
2887dd7cddfSDavid du Colombier 		 * This changes the behavior of 'ksh arg' to search
2897dd7cddfSDavid du Colombier 		 * the users search path but it can't be helped.
2907dd7cddfSDavid du Colombier 		 */
2917dd7cddfSDavid du Colombier 		s->file = search(argv[argi++], path, R_OK, (int *) 0);
2927dd7cddfSDavid du Colombier 		if (!s->file || !*s->file)
2937dd7cddfSDavid du Colombier 		        s->file = argv[argi - 1];
2947dd7cddfSDavid du Colombier #else
2957dd7cddfSDavid du Colombier 		s->file = argv[argi++];
2967dd7cddfSDavid du Colombier #endif /* OS2 */
2977dd7cddfSDavid du Colombier 		s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
2987dd7cddfSDavid du Colombier 		if (s->u.shf == NULL) {
2997dd7cddfSDavid du Colombier 			exstat = 127; /* POSIX */
3007dd7cddfSDavid du Colombier 			errorf("%s: %s", s->file, strerror(errno));
3017dd7cddfSDavid du Colombier 		}
3027dd7cddfSDavid du Colombier 		kshname = s->file;
3037dd7cddfSDavid du Colombier 	} else {
3047dd7cddfSDavid du Colombier 		Flag(FSTDIN) = 1;
3057dd7cddfSDavid du Colombier 		s = pushs(SSTDIN, ATEMP);
3067dd7cddfSDavid du Colombier 		s->file = "<stdin>";
3077dd7cddfSDavid du Colombier 		s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
3087dd7cddfSDavid du Colombier 				      (struct shf *) 0);
309223a736eSDavid du Colombier 		if (!Flag(FNOTTALKING) && isatty(0) && isatty(2)) {
3107dd7cddfSDavid du Colombier 			Flag(FTALKING) = Flag(FTALKING_I) = 1;
3117dd7cddfSDavid du Colombier 			/* The following only if isatty(0) */
3127dd7cddfSDavid du Colombier 			s->flags |= SF_TTY;
3137dd7cddfSDavid du Colombier 			s->u.shf->flags |= SHF_INTERRUPT;
3147dd7cddfSDavid du Colombier 			s->file = (char *) 0;
3157dd7cddfSDavid du Colombier 		}
3167dd7cddfSDavid du Colombier 	}
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier 	/* This bizarreness is mandated by POSIX */
3197dd7cddfSDavid du Colombier 	{
3207dd7cddfSDavid du Colombier 		struct stat s_stdin;
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier 		if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode))
3237dd7cddfSDavid du Colombier 			reset_nonblock(0);
3247dd7cddfSDavid du Colombier 	}
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 	/* initialize job control */
3277dd7cddfSDavid du Colombier 	i = Flag(FMONITOR) != 127;
3287dd7cddfSDavid du Colombier 	Flag(FMONITOR) = 0;
3297dd7cddfSDavid du Colombier 	j_init(i);
3307dd7cddfSDavid du Colombier #ifdef EDIT
3317dd7cddfSDavid du Colombier 	/* Do this after j_init(), as tty_fd is not initialized 'til then */
3327dd7cddfSDavid du Colombier 	if (Flag(FTALKING))
3337dd7cddfSDavid du Colombier 		x_init();
3347dd7cddfSDavid du Colombier #endif
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier 	l = e->loc;
3377dd7cddfSDavid du Colombier 	l->argv = &argv[argi - 1];
3387dd7cddfSDavid du Colombier 	l->argc = argc - argi;
3397dd7cddfSDavid du Colombier 	l->argv[0] = (char *) kshname;
3407dd7cddfSDavid du Colombier 	getopts_reset(1);
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 	/* Disable during .profile/ENV reading */
3437dd7cddfSDavid du Colombier 	restricted = Flag(FRESTRICTED);
3447dd7cddfSDavid du Colombier 	Flag(FRESTRICTED) = 0;
3457dd7cddfSDavid du Colombier 	errexit = Flag(FERREXIT);
3467dd7cddfSDavid du Colombier 	Flag(FERREXIT) = 0;
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier 	/* Do this before profile/$ENV so that if it causes problems in them,
3497dd7cddfSDavid du Colombier 	 * user will know why things broke.
3507dd7cddfSDavid du Colombier 	 */
3517dd7cddfSDavid du Colombier 	if (!current_wd[0] && Flag(FTALKING))
3527dd7cddfSDavid du Colombier 		warningf(FALSE, "Cannot determine current working directory");
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier 	if (Flag(FLOGIN)) {
3557dd7cddfSDavid du Colombier #ifdef OS2
3567dd7cddfSDavid du Colombier 		char *profile;
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier 		/* Try to find a profile - first see if $INIT has a value,
3597dd7cddfSDavid du Colombier 		 * then try /etc/profile.ksh, then c:/usr/etc/profile.ksh.
3607dd7cddfSDavid du Colombier 		 */
3617dd7cddfSDavid du Colombier 		if (!Flag(FPRIVILEGED)
3627dd7cddfSDavid du Colombier 		    && strcmp(profile = substitute("$INIT/profile.ksh", 0),
3637dd7cddfSDavid du Colombier 			      "/profile.ksh"))
3647dd7cddfSDavid du Colombier 			include(profile, 0, (char **) 0, 1);
3657dd7cddfSDavid du Colombier 		else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0)
3667dd7cddfSDavid du Colombier 			include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1);
3677dd7cddfSDavid du Colombier 		if (!Flag(FPRIVILEGED))
3687dd7cddfSDavid du Colombier 			include(substitute("$HOME/profile.ksh", 0), 0,
3697dd7cddfSDavid du Colombier 				(char **) 0, 1);
3707dd7cddfSDavid du Colombier #else /* OS2 */
3717dd7cddfSDavid du Colombier 		include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1);
3727dd7cddfSDavid du Colombier 		if (!Flag(FPRIVILEGED))
3737dd7cddfSDavid du Colombier 			include(substitute("$HOME/.profile", 0), 0,
3747dd7cddfSDavid du Colombier 				(char **) 0, 1);
3757dd7cddfSDavid du Colombier #endif /* OS2 */
3767dd7cddfSDavid du Colombier 	}
3777dd7cddfSDavid du Colombier 
3787dd7cddfSDavid du Colombier 	if (Flag(FPRIVILEGED))
3797dd7cddfSDavid du Colombier 		include("/etc/suid_profile", 0, (char **) 0, 1);
3807dd7cddfSDavid du Colombier 	else {
3817dd7cddfSDavid du Colombier 		char *env_file;
3827dd7cddfSDavid du Colombier 
3837dd7cddfSDavid du Colombier #ifndef KSH
3847dd7cddfSDavid du Colombier 		if (!Flag(FPOSIX))
3857dd7cddfSDavid du Colombier 			env_file = null;
3867dd7cddfSDavid du Colombier 		else
3877dd7cddfSDavid du Colombier #endif /* !KSH */
3887dd7cddfSDavid du Colombier 			/* include $ENV */
3897dd7cddfSDavid du Colombier 			env_file = str_val(global("ENV"));
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier #ifdef DEFAULT_ENV
3927dd7cddfSDavid du Colombier 		/* If env isn't set, include default environment */
3937dd7cddfSDavid du Colombier 		if (env_file == null)
3947dd7cddfSDavid du Colombier 			env_file = DEFAULT_ENV;
3957dd7cddfSDavid du Colombier #endif /* DEFAULT_ENV */
3967dd7cddfSDavid du Colombier 		env_file = substitute(env_file, DOTILDE);
3977dd7cddfSDavid du Colombier 		if (*env_file != '\0')
3987dd7cddfSDavid du Colombier 			include(env_file, 0, (char **) 0, 1);
3997dd7cddfSDavid du Colombier #ifdef OS2
4007dd7cddfSDavid du Colombier 		else if (Flag(FTALKING))
4017dd7cddfSDavid du Colombier 			include(substitute("$HOME/kshrc.ksh", 0), 0,
4027dd7cddfSDavid du Colombier 				(char **) 0, 1);
4037dd7cddfSDavid du Colombier #endif /* OS2 */
4047dd7cddfSDavid du Colombier 	}
4057dd7cddfSDavid du Colombier 
4067dd7cddfSDavid du Colombier 	if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL"))))
4077dd7cddfSDavid du Colombier 		restricted = 1;
4087dd7cddfSDavid du Colombier 	if (restricted) {
4097dd7cddfSDavid du Colombier 		static const char *const restr_com[] = {
4107dd7cddfSDavid du Colombier 						"typeset", "-r", "PATH",
4117dd7cddfSDavid du Colombier 						    "ENV", "SHELL",
4127dd7cddfSDavid du Colombier 						(char *) 0
4137dd7cddfSDavid du Colombier 					    };
4147dd7cddfSDavid du Colombier 		shcomexec((char **) restr_com);
4157dd7cddfSDavid du Colombier 		/* After typeset command... */
4167dd7cddfSDavid du Colombier 		Flag(FRESTRICTED) = 1;
4177dd7cddfSDavid du Colombier 	}
4187dd7cddfSDavid du Colombier 	if (errexit)
4197dd7cddfSDavid du Colombier 		Flag(FERREXIT) = 1;
4207dd7cddfSDavid du Colombier 
4217dd7cddfSDavid du Colombier 	if (Flag(FTALKING)) {
4227dd7cddfSDavid du Colombier 		hist_init(s);
4237dd7cddfSDavid du Colombier #ifdef KSH
4247dd7cddfSDavid du Colombier 		alarm_init();
4257dd7cddfSDavid du Colombier #endif /* KSH */
4267dd7cddfSDavid du Colombier 	} else
4277dd7cddfSDavid du Colombier 		Flag(FTRACKALL) = 1;	/* set after ENV */
4287dd7cddfSDavid du Colombier 
4297dd7cddfSDavid du Colombier 	shell(s, TRUE);	/* doesn't return */
4307dd7cddfSDavid du Colombier 	return 0;
4317dd7cddfSDavid du Colombier }
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier int
include(name,argc,argv,intr_ok)4347dd7cddfSDavid du Colombier include(name, argc, argv, intr_ok)
4357dd7cddfSDavid du Colombier 	const char *name;
4367dd7cddfSDavid du Colombier 	int argc;
4377dd7cddfSDavid du Colombier 	char **argv;
4387dd7cddfSDavid du Colombier 	int intr_ok;
4397dd7cddfSDavid du Colombier {
4407dd7cddfSDavid du Colombier 	register Source *volatile s = NULL;
4417dd7cddfSDavid du Colombier 	Source *volatile sold;
4427dd7cddfSDavid du Colombier 	struct shf *shf;
4437dd7cddfSDavid du Colombier 	char **volatile old_argv;
4447dd7cddfSDavid du Colombier 	volatile int old_argc;
4457dd7cddfSDavid du Colombier 	int i;
4467dd7cddfSDavid du Colombier 
4477dd7cddfSDavid du Colombier 	shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
4487dd7cddfSDavid du Colombier 	if (shf == NULL)
4497dd7cddfSDavid du Colombier 		return -1;
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 	if (argv) {
4527dd7cddfSDavid du Colombier 		old_argv = e->loc->argv;
4537dd7cddfSDavid du Colombier 		old_argc = e->loc->argc;
4547dd7cddfSDavid du Colombier 	} else {
4557dd7cddfSDavid du Colombier 		old_argv = (char **) 0;
4567dd7cddfSDavid du Colombier 		old_argc = 0;
4577dd7cddfSDavid du Colombier 	}
4587dd7cddfSDavid du Colombier 	sold = source;
4597dd7cddfSDavid du Colombier 	newenv(E_INCL);
4607dd7cddfSDavid du Colombier 	i = ksh_sigsetjmp(e->jbuf, 0);
4617dd7cddfSDavid du Colombier 	if (i) {
4627dd7cddfSDavid du Colombier 		source = sold;
4637dd7cddfSDavid du Colombier 		if (s) /* Do this before quitenv(), which frees the memory */
4647dd7cddfSDavid du Colombier 			shf_close(s->u.shf);
4657dd7cddfSDavid du Colombier 		quitenv();
4667dd7cddfSDavid du Colombier 		if (old_argv) {
4677dd7cddfSDavid du Colombier 			e->loc->argv = old_argv;
4687dd7cddfSDavid du Colombier 			e->loc->argc = old_argc;
4697dd7cddfSDavid du Colombier 		}
4707dd7cddfSDavid du Colombier 		switch (i) {
4717dd7cddfSDavid du Colombier 		  case LRETURN:
4727dd7cddfSDavid du Colombier 		  case LERROR:
4737dd7cddfSDavid du Colombier 			return exstat & 0xff; /* see below */
4747dd7cddfSDavid du Colombier 		  case LINTR:
4757dd7cddfSDavid du Colombier 			/* intr_ok is set if we are including .profile or $ENV.
4767dd7cddfSDavid du Colombier 			 * If user ^C's out, we don't want to kill the shell...
4777dd7cddfSDavid du Colombier 			 */
4787dd7cddfSDavid du Colombier 			if (intr_ok && (exstat - 128) != SIGTERM)
4797dd7cddfSDavid du Colombier 				return 1;
4807dd7cddfSDavid du Colombier 			/* fall through... */
4817dd7cddfSDavid du Colombier 		  case LEXIT:
4827dd7cddfSDavid du Colombier 		  case LLEAVE:
4837dd7cddfSDavid du Colombier 		  case LSHELL:
4847dd7cddfSDavid du Colombier 			unwind(i);
4857dd7cddfSDavid du Colombier 			/*NOREACHED*/
4867dd7cddfSDavid du Colombier 		  default:
4877dd7cddfSDavid du Colombier 			internal_errorf(1, "include: %d", i);
4887dd7cddfSDavid du Colombier 			/*NOREACHED*/
4897dd7cddfSDavid du Colombier 		}
4907dd7cddfSDavid du Colombier 	}
4917dd7cddfSDavid du Colombier 	if (argv) {
4927dd7cddfSDavid du Colombier 		e->loc->argv = argv;
4937dd7cddfSDavid du Colombier 		e->loc->argc = argc;
4947dd7cddfSDavid du Colombier 	}
4957dd7cddfSDavid du Colombier 	s = pushs(SFILE, ATEMP);
4967dd7cddfSDavid du Colombier 	s->u.shf = shf;
4977dd7cddfSDavid du Colombier 	s->file = str_save(name, ATEMP);
4987dd7cddfSDavid du Colombier 	i = shell(s, FALSE);
4997dd7cddfSDavid du Colombier 	source = sold;
5007dd7cddfSDavid du Colombier 	shf_close(s->u.shf);
5017dd7cddfSDavid du Colombier 	quitenv();
5027dd7cddfSDavid du Colombier 	if (old_argv) {
5037dd7cddfSDavid du Colombier 		e->loc->argv = old_argv;
5047dd7cddfSDavid du Colombier 		e->loc->argc = old_argc;
5057dd7cddfSDavid du Colombier 	}
5067dd7cddfSDavid du Colombier 	return i & 0xff;	/* & 0xff to ensure value not -1 */
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier int
command(comm)5107dd7cddfSDavid du Colombier command(comm)
5117dd7cddfSDavid du Colombier 	const char *comm;
5127dd7cddfSDavid du Colombier {
5137dd7cddfSDavid du Colombier 	register Source *s;
5147dd7cddfSDavid du Colombier 
5157dd7cddfSDavid du Colombier 	s = pushs(SSTRING, ATEMP);
5167dd7cddfSDavid du Colombier 	s->start = s->str = comm;
5177dd7cddfSDavid du Colombier 	return shell(s, FALSE);
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier 
5207dd7cddfSDavid du Colombier /*
5217dd7cddfSDavid du Colombier  * run the commands from the input source, returning status.
5227dd7cddfSDavid du Colombier  */
5237dd7cddfSDavid du Colombier int
shell(s,toplevel)5247dd7cddfSDavid du Colombier shell(s, toplevel)
5257dd7cddfSDavid du Colombier 	Source *volatile s;		/* input source */
5267dd7cddfSDavid du Colombier 	int volatile toplevel;
5277dd7cddfSDavid du Colombier {
5287dd7cddfSDavid du Colombier 	struct op *t;
5297dd7cddfSDavid du Colombier 	volatile int wastty = s->flags & SF_TTY;
5307dd7cddfSDavid du Colombier 	volatile int attempts = 13;
5317dd7cddfSDavid du Colombier 	volatile int interactive = Flag(FTALKING) && toplevel;
5327dd7cddfSDavid du Colombier 	int i;
5337dd7cddfSDavid du Colombier 
5347dd7cddfSDavid du Colombier 	newenv(E_PARSE);
5357dd7cddfSDavid du Colombier 	if (interactive)
5367dd7cddfSDavid du Colombier 		really_exit = 0;
5377dd7cddfSDavid du Colombier 	i = ksh_sigsetjmp(e->jbuf, 0);
5387dd7cddfSDavid du Colombier 	if (i) {
5397dd7cddfSDavid du Colombier 		s->start = s->str = null;
5407dd7cddfSDavid du Colombier 		switch (i) {
5417dd7cddfSDavid du Colombier 		  case LINTR: /* we get here if SIGINT not caught or ignored */
5427dd7cddfSDavid du Colombier 		  case LERROR:
5437dd7cddfSDavid du Colombier 		  case LSHELL:
5447dd7cddfSDavid du Colombier 			if (interactive) {
5457dd7cddfSDavid du Colombier 				if (i == LINTR)
5467dd7cddfSDavid du Colombier 					shellf(newline);
5477dd7cddfSDavid du Colombier 				/* Reset any eof that was read as part of a
5487dd7cddfSDavid du Colombier 				 * multiline command.
5497dd7cddfSDavid du Colombier 				 */
5507dd7cddfSDavid du Colombier 				if (Flag(FIGNOREEOF) && s->type == SEOF
5517dd7cddfSDavid du Colombier 				    && wastty)
5527dd7cddfSDavid du Colombier 					s->type = SSTDIN;
5537dd7cddfSDavid du Colombier 				/* Used by exit command to get back to
5547dd7cddfSDavid du Colombier 				 * top level shell.  Kind of strange since
5557dd7cddfSDavid du Colombier 				 * interactive is set if we are reading from
5567dd7cddfSDavid du Colombier 				 * a tty, but to have stopped jobs, one only
5577dd7cddfSDavid du Colombier 				 * needs FMONITOR set (not FTALKING/SF_TTY)...
5587dd7cddfSDavid du Colombier 				 */
5597dd7cddfSDavid du Colombier 				break;
5607dd7cddfSDavid du Colombier 			}
5617dd7cddfSDavid du Colombier 			/* fall through... */
5627dd7cddfSDavid du Colombier 		  case LEXIT:
5637dd7cddfSDavid du Colombier 		  case LLEAVE:
5647dd7cddfSDavid du Colombier 		  case LRETURN:
5657dd7cddfSDavid du Colombier 			quitenv();
5667dd7cddfSDavid du Colombier 			unwind(i);	/* keep on going */
5677dd7cddfSDavid du Colombier 			/*NOREACHED*/
5687dd7cddfSDavid du Colombier 		  default:
5697dd7cddfSDavid du Colombier 			quitenv();
5707dd7cddfSDavid du Colombier 			internal_errorf(1, "shell: %d", i);
5717dd7cddfSDavid du Colombier 			/*NOREACHED*/
5727dd7cddfSDavid du Colombier 		}
5737dd7cddfSDavid du Colombier 	}
5747dd7cddfSDavid du Colombier 
5757dd7cddfSDavid du Colombier 	while (1) {
5767dd7cddfSDavid du Colombier 		if (trap)
5777dd7cddfSDavid du Colombier 			runtraps(0);
5787dd7cddfSDavid du Colombier 
5797dd7cddfSDavid du Colombier 		if (s->next == NULL)
5807dd7cddfSDavid du Colombier 			if (Flag(FVERBOSE))
5817dd7cddfSDavid du Colombier 				s->flags |= SF_ECHO;
5827dd7cddfSDavid du Colombier 			else
5837dd7cddfSDavid du Colombier 				s->flags &= ~SF_ECHO;
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier 		if (interactive) {
5867dd7cddfSDavid du Colombier 			j_notify();
5877dd7cddfSDavid du Colombier #ifdef KSH
5887dd7cddfSDavid du Colombier 			mcheck();
5897dd7cddfSDavid du Colombier #endif /* KSH */
5907dd7cddfSDavid du Colombier 			set_prompt(PS1, s);
5917dd7cddfSDavid du Colombier 		}
5927dd7cddfSDavid du Colombier 
5937dd7cddfSDavid du Colombier 		t = compile(s);
5947dd7cddfSDavid du Colombier 		if (t != NULL && t->type == TEOF) {
5957dd7cddfSDavid du Colombier 			if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
5967dd7cddfSDavid du Colombier 				shellf("Use `exit' to leave ksh\n");
5977dd7cddfSDavid du Colombier 				s->type = SSTDIN;
5987dd7cddfSDavid du Colombier 			} else if (wastty && !really_exit
5997dd7cddfSDavid du Colombier 				   && j_stopped_running())
6007dd7cddfSDavid du Colombier 			{
6017dd7cddfSDavid du Colombier 				really_exit = 1;
6027dd7cddfSDavid du Colombier 				s->type = SSTDIN;
6037dd7cddfSDavid du Colombier 			} else {
6047dd7cddfSDavid du Colombier 				/* this for POSIX, which says EXIT traps
6057dd7cddfSDavid du Colombier 				 * shall be taken in the environment
6067dd7cddfSDavid du Colombier 				 * immediately after the last command
6077dd7cddfSDavid du Colombier 				 * executed.
6087dd7cddfSDavid du Colombier 				 */
6097dd7cddfSDavid du Colombier 				if (toplevel)
6107dd7cddfSDavid du Colombier 					unwind(LEXIT);
6117dd7cddfSDavid du Colombier 				break;
6127dd7cddfSDavid du Colombier 			}
6137dd7cddfSDavid du Colombier 		}
6147dd7cddfSDavid du Colombier 
6157dd7cddfSDavid du Colombier 		if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
6167dd7cddfSDavid du Colombier 			exstat = execute(t, 0);
6177dd7cddfSDavid du Colombier 
6187dd7cddfSDavid du Colombier 		if (t != NULL && t->type != TEOF && interactive && really_exit)
6197dd7cddfSDavid du Colombier 			really_exit = 0;
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier 		reclaim();
6227dd7cddfSDavid du Colombier 	}
6237dd7cddfSDavid du Colombier 	quitenv();
6247dd7cddfSDavid du Colombier 	return exstat;
6257dd7cddfSDavid du Colombier }
6267dd7cddfSDavid du Colombier 
6277dd7cddfSDavid du Colombier /* return to closest error handler or shell(), exit if none found */
6287dd7cddfSDavid du Colombier void
unwind(i)6297dd7cddfSDavid du Colombier unwind(i)
6307dd7cddfSDavid du Colombier 	int i;
6317dd7cddfSDavid du Colombier {
6327dd7cddfSDavid du Colombier 	/* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
6337dd7cddfSDavid du Colombier 	if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR)
6347dd7cddfSDavid du Colombier 			   && sigtraps[SIGEXIT_].trap))
6357dd7cddfSDavid du Colombier 	{
6367dd7cddfSDavid du Colombier 		runtrap(&sigtraps[SIGEXIT_]);
6377dd7cddfSDavid du Colombier 		i = LLEAVE;
6387dd7cddfSDavid du Colombier 	} else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
6397dd7cddfSDavid du Colombier 		runtrap(&sigtraps[SIGERR_]);
6407dd7cddfSDavid du Colombier 		i = LLEAVE;
6417dd7cddfSDavid du Colombier 	}
6427dd7cddfSDavid du Colombier 	while (1) {
6437dd7cddfSDavid du Colombier 		switch (e->type) {
6447dd7cddfSDavid du Colombier 		  case E_PARSE:
6457dd7cddfSDavid du Colombier 		  case E_FUNC:
6467dd7cddfSDavid du Colombier 		  case E_INCL:
6477dd7cddfSDavid du Colombier 		  case E_LOOP:
6487dd7cddfSDavid du Colombier 		  case E_ERRH:
6497dd7cddfSDavid du Colombier 			ksh_siglongjmp(e->jbuf, i);
6507dd7cddfSDavid du Colombier 			/*NOTREACHED*/
6517dd7cddfSDavid du Colombier 
6527dd7cddfSDavid du Colombier 		  case E_NONE:
6537dd7cddfSDavid du Colombier 			if (i == LINTR)
6547dd7cddfSDavid du Colombier 				e->flags |= EF_FAKE_SIGDIE;
6557dd7cddfSDavid du Colombier 			/* Fall through... */
6567dd7cddfSDavid du Colombier 
6577dd7cddfSDavid du Colombier 		  default:
6587dd7cddfSDavid du Colombier 			quitenv();
6597dd7cddfSDavid du Colombier 		}
6607dd7cddfSDavid du Colombier 	}
6617dd7cddfSDavid du Colombier }
6627dd7cddfSDavid du Colombier 
6637dd7cddfSDavid du Colombier void
newenv(type)6647dd7cddfSDavid du Colombier newenv(type)
6657dd7cddfSDavid du Colombier 	int type;
6667dd7cddfSDavid du Colombier {
6677dd7cddfSDavid du Colombier 	register struct env *ep;
6687dd7cddfSDavid du Colombier 
6697dd7cddfSDavid du Colombier 	ep = (struct env *) alloc(sizeof(*ep), ATEMP);
6707dd7cddfSDavid du Colombier 	ep->type = type;
6717dd7cddfSDavid du Colombier 	ep->flags = 0;
6727dd7cddfSDavid du Colombier 	ainit(&ep->area);
6737dd7cddfSDavid du Colombier 	ep->loc = e->loc;
6747dd7cddfSDavid du Colombier 	ep->savefd = NULL;
6757dd7cddfSDavid du Colombier 	ep->oenv = e;
6767dd7cddfSDavid du Colombier 	ep->temps = NULL;
6777dd7cddfSDavid du Colombier 	e = ep;
6787dd7cddfSDavid du Colombier }
6797dd7cddfSDavid du Colombier 
6807dd7cddfSDavid du Colombier void
quitenv()6817dd7cddfSDavid du Colombier quitenv()
6827dd7cddfSDavid du Colombier {
6837dd7cddfSDavid du Colombier 	register struct env *ep = e;
6847dd7cddfSDavid du Colombier 	register int fd;
6857dd7cddfSDavid du Colombier 
6867dd7cddfSDavid du Colombier 	if (ep->oenv && ep->oenv->loc != ep->loc)
6877dd7cddfSDavid du Colombier 		popblock();
6887dd7cddfSDavid du Colombier 	if (ep->savefd != NULL) {
6897dd7cddfSDavid du Colombier 		for (fd = 0; fd < NUFILE; fd++)
6907dd7cddfSDavid du Colombier 			/* if ep->savefd[fd] < 0, means fd was closed */
6917dd7cddfSDavid du Colombier 			if (ep->savefd[fd])
6927dd7cddfSDavid du Colombier 				restfd(fd, ep->savefd[fd]);
6937dd7cddfSDavid du Colombier 		if (ep->savefd[2]) /* Clear any write errors */
6947dd7cddfSDavid du Colombier 			shf_reopen(2, SHF_WR, shl_out);
6957dd7cddfSDavid du Colombier 	}
6967dd7cddfSDavid du Colombier 	reclaim();
6977dd7cddfSDavid du Colombier 
6987dd7cddfSDavid du Colombier 	/* Bottom of the stack.
6997dd7cddfSDavid du Colombier 	 * Either main shell is exiting or cleanup_parents_env() was called.
7007dd7cddfSDavid du Colombier 	 */
7017dd7cddfSDavid du Colombier 	if (ep->oenv == NULL) {
7027dd7cddfSDavid du Colombier 		if (ep->type == E_NONE) {	/* Main shell exiting? */
7037dd7cddfSDavid du Colombier 			if (Flag(FTALKING))
7047dd7cddfSDavid du Colombier 				hist_finish();
7057dd7cddfSDavid du Colombier 			j_exit();
7067dd7cddfSDavid du Colombier 			if (ep->flags & EF_FAKE_SIGDIE) {
7077dd7cddfSDavid du Colombier 				int sig = exstat - 128;
7087dd7cddfSDavid du Colombier 
7097dd7cddfSDavid du Colombier 				/* ham up our death a bit (at&t ksh
7107dd7cddfSDavid du Colombier 				 * only seems to do this for SIGTERM)
7117dd7cddfSDavid du Colombier 				 * Don't do it for SIGQUIT, since we'd
7127dd7cddfSDavid du Colombier 				 * dump a core..
7137dd7cddfSDavid du Colombier 				 */
7147dd7cddfSDavid du Colombier 				if (sig == SIGINT || sig == SIGTERM) {
7157dd7cddfSDavid du Colombier 					setsig(&sigtraps[sig], SIG_DFL,
7167dd7cddfSDavid du Colombier 						SS_RESTORE_CURR|SS_FORCE);
7177dd7cddfSDavid du Colombier 					kill(0, sig);
7187dd7cddfSDavid du Colombier 				}
7197dd7cddfSDavid du Colombier 			}
7207dd7cddfSDavid du Colombier #ifdef MEM_DEBUG
7217dd7cddfSDavid du Colombier 			chmem_allfree();
7227dd7cddfSDavid du Colombier #endif /* MEM_DEBUG */
7237dd7cddfSDavid du Colombier 		}
7247dd7cddfSDavid du Colombier 		exit(exstat);
7257dd7cddfSDavid du Colombier 	}
7267dd7cddfSDavid du Colombier 
7277dd7cddfSDavid du Colombier 	e = e->oenv;
7287dd7cddfSDavid du Colombier 	afree(ep, ATEMP);
7297dd7cddfSDavid du Colombier }
7307dd7cddfSDavid du Colombier 
7317dd7cddfSDavid du Colombier /* Called after a fork to cleanup stuff left over from parents environment */
7327dd7cddfSDavid du Colombier void
cleanup_parents_env()7337dd7cddfSDavid du Colombier cleanup_parents_env()
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier 	struct env *ep;
7367dd7cddfSDavid du Colombier 	int fd;
7377dd7cddfSDavid du Colombier 
7387dd7cddfSDavid du Colombier 	/* Don't clean up temporary files - parent will probably need them.
7397dd7cddfSDavid du Colombier 	 * Also, can't easily reclaim memory since variables, etc. could be
7407dd7cddfSDavid du Colombier 	 * anywyere.
7417dd7cddfSDavid du Colombier 	 */
7427dd7cddfSDavid du Colombier 
7437dd7cddfSDavid du Colombier 	/* close all file descriptors hiding in savefd */
7447dd7cddfSDavid du Colombier 	for (ep = e; ep; ep = ep->oenv) {
7457dd7cddfSDavid du Colombier 		if (ep->savefd) {
7467dd7cddfSDavid du Colombier 			for (fd = 0; fd < NUFILE; fd++)
7477dd7cddfSDavid du Colombier 				if (ep->savefd[fd] > 0)
7487dd7cddfSDavid du Colombier 					close(ep->savefd[fd]);
7497dd7cddfSDavid du Colombier 			afree(ep->savefd, &ep->area);
7507dd7cddfSDavid du Colombier 			ep->savefd = (short *) 0;
7517dd7cddfSDavid du Colombier 		}
7527dd7cddfSDavid du Colombier 	}
7537dd7cddfSDavid du Colombier 	e->oenv = (struct env *) 0;
7547dd7cddfSDavid du Colombier }
7557dd7cddfSDavid du Colombier 
7567dd7cddfSDavid du Colombier /* Called just before an execve cleanup stuff temporary files */
7577dd7cddfSDavid du Colombier void
cleanup_proc_env()7587dd7cddfSDavid du Colombier cleanup_proc_env()
7597dd7cddfSDavid du Colombier {
7607dd7cddfSDavid du Colombier 	struct env *ep;
7617dd7cddfSDavid du Colombier 
7627dd7cddfSDavid du Colombier 	for (ep = e; ep; ep = ep->oenv)
7637dd7cddfSDavid du Colombier 		remove_temps(ep->temps);
7647dd7cddfSDavid du Colombier }
7657dd7cddfSDavid du Colombier 
7667dd7cddfSDavid du Colombier /* remove temp files and free ATEMP Area */
7677dd7cddfSDavid du Colombier static void
reclaim()7687dd7cddfSDavid du Colombier reclaim()
7697dd7cddfSDavid du Colombier {
7707dd7cddfSDavid du Colombier 	remove_temps(e->temps);
7717dd7cddfSDavid du Colombier 	e->temps = NULL;
7727dd7cddfSDavid du Colombier 	afreeall(&e->area);
7737dd7cddfSDavid du Colombier }
7747dd7cddfSDavid du Colombier 
7757dd7cddfSDavid du Colombier static void
remove_temps(tp)7767dd7cddfSDavid du Colombier remove_temps(tp)
7777dd7cddfSDavid du Colombier 	struct temp *tp;
7787dd7cddfSDavid du Colombier {
7797dd7cddfSDavid du Colombier #ifdef OS2
7807dd7cddfSDavid du Colombier 	static struct temp *delayed_remove;
7817dd7cddfSDavid du Colombier 	struct temp *t, **tprev;
7827dd7cddfSDavid du Colombier 
7837dd7cddfSDavid du Colombier 	if (delayed_remove) {
7847dd7cddfSDavid du Colombier 		for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev)
7857dd7cddfSDavid du Colombier 			/* No need to check t->pid here... */
7867dd7cddfSDavid du Colombier 			if (unlink(t->name) >= 0 || errno == ENOENT) {
7877dd7cddfSDavid du Colombier 				*tprev = t->next;
7887dd7cddfSDavid du Colombier 				afree(t, APERM);
7897dd7cddfSDavid du Colombier 			} else
7907dd7cddfSDavid du Colombier 				tprev = &t->next;
7917dd7cddfSDavid du Colombier 	}
7927dd7cddfSDavid du Colombier #endif /* OS2 */
7937dd7cddfSDavid du Colombier 
7947dd7cddfSDavid du Colombier 	for (; tp != NULL; tp = tp->next)
7957dd7cddfSDavid du Colombier 		if (tp->pid == procpid) {
7967dd7cddfSDavid du Colombier #ifdef OS2
7977dd7cddfSDavid du Colombier 			/* OS/2 (and dos) do not allow files that are currently
7987dd7cddfSDavid du Colombier 			 * open to be removed, so we cache it away for future
7997dd7cddfSDavid du Colombier 			 * removal.
8007dd7cddfSDavid du Colombier 			 * XXX should only do this if errno
8017dd7cddfSDavid du Colombier 			 *     is Efile-still-open-can't-remove
8027dd7cddfSDavid du Colombier 			 *     (but I don't know what that is...)
8037dd7cddfSDavid du Colombier 			 */
8047dd7cddfSDavid du Colombier 			if (unlink(tp->name) < 0 && errno != ENOENT) {
8057dd7cddfSDavid du Colombier 				t = (struct temp *) alloc(
8067dd7cddfSDavid du Colombier 				    sizeof(struct temp) + strlen(tp->name) + 1,
8077dd7cddfSDavid du Colombier 				    APERM);
8087dd7cddfSDavid du Colombier 				memset(t, 0, sizeof(struct temp));
8097dd7cddfSDavid du Colombier 				t->name = (char *) &t[1];
8107dd7cddfSDavid du Colombier 				strcpy(t->name, tp->name);
8117dd7cddfSDavid du Colombier 				t->next = delayed_remove;
8127dd7cddfSDavid du Colombier 				delayed_remove = t;
8137dd7cddfSDavid du Colombier 			}
8147dd7cddfSDavid du Colombier #else /* OS2 */
8157dd7cddfSDavid du Colombier 			unlink(tp->name);
8167dd7cddfSDavid du Colombier #endif /* OS2 */
8177dd7cddfSDavid du Colombier 		}
8187dd7cddfSDavid du Colombier }
8197dd7cddfSDavid du Colombier 
8207dd7cddfSDavid du Colombier /* Returns true if name refers to a restricted shell */
8217dd7cddfSDavid du Colombier static int
is_restricted(name)8227dd7cddfSDavid du Colombier is_restricted(name)
8237dd7cddfSDavid du Colombier 	char *name;
8247dd7cddfSDavid du Colombier {
8257dd7cddfSDavid du Colombier 	char *p;
8267dd7cddfSDavid du Colombier 
827*59cc4ca5SDavid du Colombier 	/* this silly function prevents you running a command called runconf.sh. */
828*59cc4ca5SDavid du Colombier 	/* we don't care about restricted shells, which aren't very restricted anyway */
829*59cc4ca5SDavid du Colombier 	/* and introduce a false sense of security */
830*59cc4ca5SDavid du Colombier 	return 0;
831*59cc4ca5SDavid du Colombier #ifdef dumbidea
8327dd7cddfSDavid du Colombier 	if ((p = ksh_strrchr_dirsep(name)))
8337dd7cddfSDavid du Colombier 		name = p;
8347dd7cddfSDavid du Colombier 	/* accepts rsh, rksh, rpdksh, pdrksh, etc. */
8357dd7cddfSDavid du Colombier 	return (p = strchr(name, 'r')) && strstr(p, "sh");
836*59cc4ca5SDavid du Colombier #endif
8377dd7cddfSDavid du Colombier }
8387dd7cddfSDavid du Colombier 
8397dd7cddfSDavid du Colombier void
aerror(ap,msg)8407dd7cddfSDavid du Colombier aerror(ap, msg)
8417dd7cddfSDavid du Colombier 	Area *ap;
8427dd7cddfSDavid du Colombier 	const char *msg;
8437dd7cddfSDavid du Colombier {
8447dd7cddfSDavid du Colombier 	internal_errorf(1, "alloc: %s", msg);
8457dd7cddfSDavid du Colombier 	errorf(null); /* this is never executed - keeps gcc quiet */
8467dd7cddfSDavid du Colombier 	/*NOTREACHED*/
8477dd7cddfSDavid du Colombier }
848