main.c revision 966dd55b233982d9657c50b971cfa754d0315c19
1/*	$OpenBSD: main.c,v 1.57 2015/09/10 22:48:58 nicm Exp $	*/
2/*	$OpenBSD: tty.c,v 1.10 2014/08/10 02:44:26 guenther Exp $	*/
3/*	$OpenBSD: io.c,v 1.26 2015/09/11 08:00:27 guenther Exp $	*/
4/*	$OpenBSD: table.c,v 1.16 2015/09/01 13:12:31 tedu Exp $	*/
5
6/*-
7 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
8 *		 2011, 2012, 2013, 2014, 2015, 2016
9 *	mirabilos <m@mirbsd.org>
10 *
11 * Provided that these terms and disclaimer and all copyright notices
12 * are retained or reproduced in an accompanying document, permission
13 * is granted to deal in this work without restriction, including un-
14 * limited rights to use, publicly perform, distribute, sell, modify,
15 * merge, give away, or sublicence.
16 *
17 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
18 * the utmost extent permitted by applicable law, neither express nor
19 * implied; without malicious intent or gross negligence. In no event
20 * may a licensor, author or contributor be held liable for indirect,
21 * direct, other damage, loss, or other issues arising in any way out
22 * of dealing in the work, even if advised of the possibility of such
23 * damage or existence of a defect, except proven that it results out
24 * of said person's immediate fault when using the work as intended.
25 */
26
27#define EXTERN
28#include "sh.h"
29
30#if HAVE_LANGINFO_CODESET
31#include <langinfo.h>
32#endif
33#if HAVE_SETLOCALE_CTYPE
34#include <locale.h>
35#endif
36
37__RCSID("$MirOS: src/bin/mksh/main.c,v 1.322 2016/11/11 23:48:30 tg Exp $");
38
39extern char **environ;
40
41#ifndef MKSHRC_PATH
42#define MKSHRC_PATH	"~/.mkshrc"
43#endif
44
45#ifndef MKSH_DEFAULT_TMPDIR
46#define MKSH_DEFAULT_TMPDIR	MKSH_UNIXROOT "/tmp"
47#endif
48
49static uint8_t isuc(const char *);
50static int main_init(int, const char *[], Source **, struct block **);
51void chvt_reinit(void);
52static void reclaim(void);
53static void remove_temps(struct temp *);
54static mksh_uari_t rndsetup(void);
55#ifdef SIGWINCH
56static void x_sigwinch(int);
57#endif
58
59static const char initifs[] = "IFS= \t\n";
60
61static const char initsubs[] =
62    "${PS2=> }"
63    "${PS3=#? }"
64    "${PS4=+ }"
65    "${SECONDS=0}"
66    "${TMOUT=0}"
67    "${EPOCHREALTIME=}";
68
69static const char *initcoms[] = {
70	Ttypeset, "-r", initvsn, NULL,
71	Ttypeset, "-x", "HOME", TPATH, TSHELL, NULL,
72	Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL,
73	Talias,
74	"integer=\\typeset -i",
75	"local=\\typeset",
76	/* not "alias -t --": hash -r needs to work */
77	"hash=\\builtin alias -t",
78	"type=\\builtin whence -v",
79	"autoload=\\typeset -fu",
80	"functions=\\typeset -f",
81	"history=\\builtin fc -l",
82	"nameref=\\typeset -n",
83	"nohup=nohup ",
84	"r=\\builtin fc -e -",
85	"login=\\exec login",
86	NULL,
87	 /* this is what AT&T ksh seems to track, with the addition of emacs */
88	Talias, "-tU",
89	Tcat, "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
90	"make", "mv", "pr", "rm", "sed", Tsh, "vi", "who", NULL,
91	NULL
92};
93
94static const char *restr_com[] = {
95	Ttypeset, "-r", TPATH, "ENV", TSHELL, NULL
96};
97
98static bool initio_done;
99
100/* top-level parsing and execution environment */
101static struct env env;
102struct env *e = &env;
103
104static mksh_uari_t
105rndsetup(void)
106{
107	register uint32_t h;
108	struct {
109		ALLOC_ITEM alloc_INT;
110		void *dataptr, *stkptr, *mallocptr;
111#if defined(__GLIBC__) && (__GLIBC__ >= 2)
112		sigjmp_buf jbuf;
113#endif
114		struct timeval tv;
115	} *bufptr;
116	char *cp;
117
118	cp = alloc(sizeof(*bufptr) - sizeof(ALLOC_ITEM), APERM);
119	/* clear the allocated space, for valgrind and to avoid UB */
120	memset(cp, 0, sizeof(*bufptr) - sizeof(ALLOC_ITEM));
121	/* undo what alloc() did to the malloc result address */
122	bufptr = (void *)(cp - sizeof(ALLOC_ITEM));
123	/* PIE or something similar provides us with deltas here */
124	bufptr->dataptr = &rndsetupstate;
125	/* ASLR in at least Windows, Linux, some BSDs */
126	bufptr->stkptr = &bufptr;
127	/* randomised malloc in BSD (and possibly others) */
128	bufptr->mallocptr = bufptr;
129#if defined(__GLIBC__) && (__GLIBC__ >= 2)
130	/* glibc pointer guard */
131	sigsetjmp(bufptr->jbuf, 1);
132#endif
133	/* introduce variation (and yes, second arg MBZ for portability) */
134	mksh_TIME(bufptr->tv);
135
136#ifdef MKSH_ALLOC_CATCH_UNDERRUNS
137	mprotect(((char *)bufptr) + 4096, 4096, PROT_READ | PROT_WRITE);
138#endif
139	h = chvt_rndsetup(bufptr, sizeof(*bufptr));
140
141	afree(cp, APERM);
142	return ((mksh_uari_t)h);
143}
144
145void
146chvt_reinit(void)
147{
148	kshpid = procpid = getpid();
149	ksheuid = geteuid();
150	kshpgrp = getpgrp();
151	kshppid = getppid();
152}
153
154static const char *empty_argv[] = {
155	Tmksh, NULL
156};
157
158static uint8_t
159isuc(const char *cx) {
160	char *cp, *x;
161	uint8_t rv = 0;
162
163	if (!cx || !*cx)
164		return (0);
165
166	/* uppercase a string duplicate */
167	strdupx(x, cx, ATEMP);
168	cp = x;
169	while ((*cp = ksh_toupper(*cp)))
170		++cp;
171
172	/* check for UTF-8 */
173	if (strstr(x, "UTF-8") || strstr(x, "UTF8"))
174		rv = 1;
175
176	/* free copy and out */
177	afree(x, ATEMP);
178	return (rv);
179}
180
181static int
182main_init(int argc, const char *argv[], Source **sp, struct block **lp)
183{
184	int argi, i;
185	Source *s = NULL;
186	struct block *l;
187	unsigned char restricted_shell, errexit, utf_flag;
188	char *cp;
189	const char *ccp, **wp;
190	struct tbl *vp;
191	struct stat s_stdin;
192#if !defined(_PATH_DEFPATH) && defined(_CS_PATH)
193	ssize_t k;
194#endif
195
196#ifdef __OS2__
197	for (i = 0; i < 3; ++i)
198		if (!isatty(i))
199			setmode(i, O_BINARY);
200#endif
201
202	/* do things like getpgrp() et al. */
203	chvt_reinit();
204
205	/* make sure argv[] is sane, for weird OSes */
206	if (!*argv) {
207		argv = empty_argv;
208		argc = 1;
209	}
210	kshname = argv[0];
211
212	/* initialise permanent Area */
213	ainit(&aperm);
214	/* max. name length: -2147483648 = 11 (+ NUL) */
215	vtemp = alloc(offsetof(struct tbl, name[0]) + 12, APERM);
216
217	/* set up base environment */
218	env.type = E_NONE;
219	ainit(&env.area);
220	/* set up global l->vars and l->funs */
221	newblock();
222
223	/* Do this first so output routines (eg, errorf, shellf) can work */
224	initio();
225
226	/* determine the basename (without '-' or path) of the executable */
227	ccp = kshname;
228	goto begin_parsing_kshname;
229	while ((i = ccp[argi++])) {
230		if (mksh_cdirsep(i)) {
231			ccp += argi;
232 begin_parsing_kshname:
233			argi = 0;
234			if (*ccp == '-')
235				++ccp;
236		}
237	}
238	if (!*ccp)
239		ccp = empty_argv[0];
240
241	/*
242	 * Turn on nohup by default. (AT&T ksh does not have a nohup
243	 * option - it always sends the hup).
244	 */
245	Flag(FNOHUP) = 1;
246
247	/*
248	 * Turn on brace expansion by default. AT&T kshs that have
249	 * alternation always have it on.
250	 */
251	Flag(FBRACEEXPAND) = 1;
252
253	/*
254	 * Turn on "set -x" inheritance by default.
255	 */
256	Flag(FXTRACEREC) = 1;
257
258	/* define built-in commands and see if we were called as one */
259	ktinit(APERM, &builtins,
260	    /* currently up to 54 builtins: 75% of 128 = 2^7 */
261	    7);
262	for (i = 0; mkshbuiltins[i].name != NULL; i++)
263		if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
264		    mkshbuiltins[i].func)))
265			Flag(FAS_BUILTIN) = 1;
266
267	if (!Flag(FAS_BUILTIN)) {
268		/* check for -T option early */
269		argi = parse_args(argv, OF_FIRSTTIME, NULL);
270		if (argi < 0)
271			return (1);
272
273#if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)
274		/* are we called as -sh or /bin/sh or so? */
275		if (!strcmp(ccp, "sh" MKSH_EXE_EXT)) {
276			/* either also turns off braceexpand */
277#ifdef MKSH_BINSHPOSIX
278			/* enable better POSIX conformance */
279			change_flag(FPOSIX, OF_FIRSTTIME, true);
280#endif
281#ifdef MKSH_BINSHREDUCED
282			/* enable kludge/compat mode */
283			change_flag(FSH, OF_FIRSTTIME, true);
284#endif
285		}
286#endif
287	}
288
289	initvar();
290
291	initctypes();
292
293	inittraps();
294
295	coproc_init();
296
297	/* set up variable and command dictionaries */
298	ktinit(APERM, &taliases, 0);
299	ktinit(APERM, &aliases, 0);
300#ifndef MKSH_NOPWNAM
301	ktinit(APERM, &homedirs, 0);
302#endif
303
304	/* define shell keywords */
305	initkeywords();
306
307	init_histvec();
308
309	/* initialise tty size before importing environment */
310	change_winsz();
311
312#ifdef _PATH_DEFPATH
313	def_path = _PATH_DEFPATH;
314#else
315#ifdef _CS_PATH
316	if ((k = confstr(_CS_PATH, NULL, 0)) > 0 &&
317	    confstr(_CS_PATH, cp = alloc(k + 1, APERM), k + 1) == k + 1)
318		def_path = cp;
319	else
320#endif
321		/*
322		 * this is uniform across all OSes unless it
323		 * breaks somewhere hard; don't try to optimise,
324		 * e.g. add stuff for Interix or remove /usr
325		 * for HURD, because e.g. Debian GNU/HURD is
326		 * "keeping a regular /usr"; this is supposed
327		 * to be a sane 'basic' default PATH
328		 */
329		def_path = MKSH_UNIXROOT "/bin" MKSH_PATHSEPS
330		    MKSH_UNIXROOT "/usr/bin" MKSH_PATHSEPS
331		    MKSH_UNIXROOT "/sbin" MKSH_PATHSEPS
332		    MKSH_UNIXROOT "/usr/sbin";
333#endif
334
335	/*
336	 * Set PATH to def_path (will set the path global variable).
337	 * (import of environment below will probably change this setting).
338	 */
339	vp = global(TPATH);
340	/* setstr can't fail here */
341	setstr(vp, def_path, KSH_RETURN_ERROR);
342
343#ifndef MKSH_NO_CMDLINE_EDITING
344	/*
345	 * Set edit mode to emacs by default, may be overridden
346	 * by the environment or the user. Also, we want tab completion
347	 * on in vi by default.
348	 */
349	change_flag(FEMACS, OF_SPECIAL, true);
350#if !MKSH_S_NOVI
351	Flag(FVITABCOMPLETE) = 1;
352#endif
353#endif
354
355	/* import environment */
356	if (environ != NULL) {
357		wp = (const char **)environ;
358		while (*wp != NULL) {
359			rndpush(*wp);
360			typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
361			++wp;
362		}
363	}
364
365	/* for security */
366	typeset(initifs, 0, 0, 0, 0);
367
368	/* assign default shell variable values */
369	substitute(initsubs, 0);
370
371	/* Figure out the current working directory and set $PWD */
372	vp = global(TPWD);
373	cp = str_val(vp);
374	/* Try to use existing $PWD if it is valid */
375	set_current_wd((mksh_abspath(cp) && test_eval(NULL, TO_FILEQ, cp,
376	    Tdot, true)) ? cp : NULL);
377	if (current_wd[0])
378		simplify_path(current_wd);
379	/* Only set pwd if we know where we are or if it had a bogus value */
380	if (current_wd[0] || *cp)
381		/* setstr can't fail here */
382		setstr(vp, current_wd, KSH_RETURN_ERROR);
383
384	for (wp = initcoms; *wp != NULL; wp++) {
385		shcomexec(wp);
386		while (*wp != NULL)
387			wp++;
388	}
389	setint_n(global("OPTIND"), 1, 10);
390
391	kshuid = getuid();
392	kshgid = getgid();
393	kshegid = getegid();
394
395	safe_prompt = ksheuid ? "$ " : "# ";
396	vp = global("PS1");
397	/* Set PS1 if unset or we are root and prompt doesn't contain a # */
398	if (!(vp->flag & ISSET) ||
399	    (!ksheuid && !strchr(str_val(vp), '#')))
400		/* setstr can't fail here */
401		setstr(vp, safe_prompt, KSH_RETURN_ERROR);
402	setint_n((vp = global("BASHPID")), 0, 10);
403	vp->flag |= INT_U;
404	setint_n((vp = global("PGRP")), (mksh_uari_t)kshpgrp, 10);
405	vp->flag |= INT_U;
406	setint_n((vp = global("PPID")), (mksh_uari_t)kshppid, 10);
407	vp->flag |= INT_U;
408	setint_n((vp = global("USER_ID")), (mksh_uari_t)ksheuid, 10);
409	vp->flag |= INT_U;
410	setint_n((vp = global("KSHUID")), (mksh_uari_t)kshuid, 10);
411	vp->flag |= INT_U;
412	setint_n((vp = global("KSHEGID")), (mksh_uari_t)kshegid, 10);
413	vp->flag |= INT_U;
414	setint_n((vp = global("KSHGID")), (mksh_uari_t)kshgid, 10);
415	vp->flag |= INT_U;
416	setint_n((vp = global("RANDOM")), rndsetup(), 10);
417	vp->flag |= INT_U;
418	setint_n((vp_pipest = global("PIPESTATUS")), 0, 10);
419
420	/* Set this before parsing arguments */
421	Flag(FPRIVILEGED) = (kshuid != ksheuid || kshgid != kshegid) ? 2 : 0;
422
423	/* this to note if monitor is set on command line (see below) */
424#ifndef MKSH_UNEMPLOYED
425	Flag(FMONITOR) = 127;
426#endif
427	/* this to note if utf-8 mode is set on command line (see below) */
428	UTFMODE = 2;
429
430	if (!Flag(FAS_BUILTIN)) {
431		argi = parse_args(argv, OF_CMDLINE, NULL);
432		if (argi < 0)
433			return (1);
434	}
435
436	/* process this later only, default to off (hysterical raisins) */
437	utf_flag = UTFMODE;
438	UTFMODE = 0;
439
440	if (Flag(FAS_BUILTIN)) {
441		/* auto-detect from environment variables, always */
442		utf_flag = 3;
443	} else if (Flag(FCOMMAND)) {
444		s = pushs(SSTRINGCMDLINE, ATEMP);
445		if (!(s->start = s->str = argv[argi++]))
446			errorf(Tf_optfoo, "", "", 'c', Treq_arg);
447		while (*s->str) {
448			if (*s->str != ' ' && ctype(*s->str, C_QUOTE))
449				break;
450			s->str++;
451		}
452		if (!*s->str)
453			s->flags |= SF_MAYEXEC;
454		s->str = s->start;
455#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
456		/* compatibility to MidnightBSD 0.1 /bin/sh (kludge) */
457		if (Flag(FSH) && argv[argi] && !strcmp(argv[argi], "--"))
458			++argi;
459#endif
460		if (argv[argi])
461			kshname = argv[argi++];
462	} else if (argi < argc && !Flag(FSTDIN)) {
463		s = pushs(SFILE, ATEMP);
464#ifdef __OS2__
465		/*
466		 * A bug in OS/2 extproc (like shebang) handling makes
467		 * it not pass the full pathname of a script, so we need
468		 * to search for it. This changes the behaviour of a
469		 * simple "mksh foo", but can't be helped.
470		 */
471		s->file = search_path(argv[argi++], path, X_OK, NULL);
472		if (!s->file || !*s->file)
473			s->file = argv[argi - 1];
474#else
475		s->file = argv[argi++];
476#endif
477		s->u.shf = shf_open(s->file, O_RDONLY, 0,
478		    SHF_MAPHI | SHF_CLEXEC);
479		if (s->u.shf == NULL) {
480			shl_stdout_ok = false;
481			warningf(true, Tf_sD_s, s->file, cstrerror(errno));
482			/* mandated by SUSv4 */
483			exstat = 127;
484			unwind(LERROR);
485		}
486		kshname = s->file;
487	} else {
488		Flag(FSTDIN) = 1;
489		s = pushs(SSTDIN, ATEMP);
490		s->file = "<stdin>";
491		s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
492		    NULL);
493		if (isatty(0) && isatty(2)) {
494			Flag(FTALKING) = Flag(FTALKING_I) = 1;
495			/* The following only if isatty(0) */
496			s->flags |= SF_TTY;
497			s->u.shf->flags |= SHF_INTERRUPT;
498			s->file = NULL;
499		}
500	}
501
502	/* this bizarreness is mandated by POSIX */
503	if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
504	    Flag(FTALKING))
505		reset_nonblock(0);
506
507	/* initialise job control */
508	j_init();
509	/* do this after j_init() which calls tty_init_state() */
510	if (Flag(FTALKING)) {
511		if (utf_flag == 2) {
512#ifndef MKSH_ASSUME_UTF8
513			/* auto-detect from locale or environment */
514			utf_flag = 4;
515#else /* this may not be an #elif */
516#if MKSH_ASSUME_UTF8
517			utf_flag = 1;
518#else
519			/* always disable UTF-8 (for interactive) */
520			utf_flag = 0;
521#endif
522#endif
523		}
524#ifndef MKSH_NO_CMDLINE_EDITING
525		x_init();
526#endif
527	}
528
529#ifdef SIGWINCH
530	sigtraps[SIGWINCH].flags |= TF_SHELL_USES;
531	setsig(&sigtraps[SIGWINCH], x_sigwinch,
532	    SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
533#endif
534
535	l = e->loc;
536	if (Flag(FAS_BUILTIN)) {
537		l->argc = argc;
538		l->argv = argv;
539		l->argv[0] = ccp;
540	} else {
541		l->argc = argc - argi;
542		/*
543		 * allocate a new array because otherwise, when we modify
544		 * it in-place, ps(1) output changes; the meaning of argc
545		 * here is slightly different as it excludes kshname, and
546		 * we add a trailing NULL sentinel as well
547		 */
548		l->argv = alloc2(l->argc + 2, sizeof(void *), APERM);
549		l->argv[0] = kshname;
550		memcpy(&l->argv[1], &argv[argi], l->argc * sizeof(void *));
551		l->argv[l->argc + 1] = NULL;
552		getopts_reset(1);
553	}
554
555	/* divine the initial state of the utf8-mode Flag */
556	ccp = null;
557	switch (utf_flag) {
558
559	/* auto-detect from locale or environment */
560	case 4:
561#if HAVE_SETLOCALE_CTYPE
562		ccp = setlocale(LC_CTYPE, "");
563#if HAVE_LANGINFO_CODESET
564		if (!isuc(ccp))
565			ccp = nl_langinfo(CODESET);
566#endif
567		if (!isuc(ccp))
568			ccp = null;
569#endif
570		/* FALLTHROUGH */
571
572	/* auto-detect from environment */
573	case 3:
574		/* these were imported from environ earlier */
575		if (ccp == null)
576			ccp = str_val(global("LC_ALL"));
577		if (ccp == null)
578			ccp = str_val(global("LC_CTYPE"));
579		if (ccp == null)
580			ccp = str_val(global("LANG"));
581		UTFMODE = isuc(ccp);
582		break;
583
584	/* not set on command line, not FTALKING */
585	case 2:
586	/* unknown values */
587	default:
588		utf_flag = 0;
589		/* FALLTHROUGH */
590
591	/* known values */
592	case 1:
593	case 0:
594		UTFMODE = utf_flag;
595		break;
596	}
597
598	/* Disable during .profile/ENV reading */
599	restricted_shell = Flag(FRESTRICTED);
600	Flag(FRESTRICTED) = 0;
601	errexit = Flag(FERREXIT);
602	Flag(FERREXIT) = 0;
603
604	/*
605	 * Do this before profile/$ENV so that if it causes problems in them,
606	 * user will know why things broke.
607	 */
608	if (!current_wd[0] && Flag(FTALKING))
609		warningf(false, "can't determine current directory");
610
611	if (Flag(FLOGIN))
612		include(MKSH_SYSTEM_PROFILE, 0, NULL, true);
613	if (!Flag(FPRIVILEGED)) {
614		if (Flag(FLOGIN))
615			include(substitute("$HOME/.profile", 0), 0, NULL, true);
616		if (Flag(FTALKING)) {
617			cp = substitute(substitute("${ENV:-" MKSHRC_PATH "}",
618			    0), DOTILDE);
619			if (cp[0] != '\0')
620				include(cp, 0, NULL, true);
621		}
622	} else {
623		include(MKSH_SUID_PROFILE, 0, NULL, true);
624		/* turn off -p if not set explicitly */
625		if (Flag(FPRIVILEGED) != 1)
626			change_flag(FPRIVILEGED, OF_INTERNAL, false);
627	}
628
629	if (restricted_shell) {
630		shcomexec(restr_com);
631		/* After typeset command... */
632		Flag(FRESTRICTED) = 1;
633	}
634	Flag(FERREXIT) = errexit;
635
636	if (Flag(FTALKING) && s)
637		hist_init(s);
638	else
639		/* set after ENV */
640		Flag(FTRACKALL) = 1;
641
642	alarm_init();
643
644	*sp = s;
645	*lp = l;
646	return (0);
647}
648
649/* this indirection barrier reduces stack usage during normal operation */
650
651int
652main(int argc, const char *argv[])
653{
654	int rv;
655	Source *s;
656	struct block *l;
657
658	if ((rv = main_init(argc, argv, &s, &l)) == 0) {
659		if (Flag(FAS_BUILTIN)) {
660			rv = shcomexec(l->argv);
661		} else {
662			shell(s, true);
663			/* NOTREACHED */
664		}
665	}
666	return (rv);
667}
668
669int
670include(const char *name, int argc, const char **argv, bool intr_ok)
671{
672	Source *volatile s = NULL;
673	struct shf *shf;
674	const char **volatile old_argv;
675	volatile int old_argc;
676	int i;
677
678	shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
679	if (shf == NULL)
680		return (-1);
681
682	if (argv) {
683		old_argv = e->loc->argv;
684		old_argc = e->loc->argc;
685	} else {
686		old_argv = NULL;
687		old_argc = 0;
688	}
689	newenv(E_INCL);
690	if ((i = kshsetjmp(e->jbuf))) {
691		quitenv(s ? s->u.shf : NULL);
692		if (old_argv) {
693			e->loc->argv = old_argv;
694			e->loc->argc = old_argc;
695		}
696		switch (i) {
697		case LRETURN:
698		case LERROR:
699			/* see below */
700			return (exstat & 0xFF);
701		case LINTR:
702			/*
703			 * intr_ok is set if we are including .profile or $ENV.
704			 * If user ^Cs out, we don't want to kill the shell...
705			 */
706			if (intr_ok && ((exstat & 0xFF) - 128) != SIGTERM)
707				return (1);
708			/* FALLTHROUGH */
709		case LEXIT:
710		case LLEAVE:
711		case LSHELL:
712			unwind(i);
713			/* NOTREACHED */
714		default:
715			internal_errorf("include %d", i);
716			/* NOTREACHED */
717		}
718	}
719	if (argv) {
720		e->loc->argv = argv;
721		e->loc->argc = argc;
722	}
723	s = pushs(SFILE, ATEMP);
724	s->u.shf = shf;
725	strdupx(s->file, name, ATEMP);
726	i = shell(s, false);
727	quitenv(s->u.shf);
728	if (old_argv) {
729		e->loc->argv = old_argv;
730		e->loc->argc = old_argc;
731	}
732	/* & 0xff to ensure value not -1 */
733	return (i & 0xFF);
734}
735
736/* spawn a command into a shell optionally keeping track of the line number */
737int
738command(const char *comm, int line)
739{
740	Source *s, *sold = source;
741	int rv;
742
743	s = pushs(SSTRING, ATEMP);
744	s->start = s->str = comm;
745	s->line = line;
746	rv = shell(s, false);
747	source = sold;
748	return (rv);
749}
750
751/*
752 * run the commands from the input source, returning status.
753 */
754int
755shell(Source * volatile s, volatile bool toplevel)
756{
757	struct op *t;
758	volatile bool wastty = tobool(s->flags & SF_TTY);
759	volatile uint8_t attempts = 13;
760	volatile bool interactive = Flag(FTALKING) && toplevel;
761	volatile bool sfirst = true;
762	Source *volatile old_source = source;
763	int i;
764
765	newenv(E_PARSE);
766	if (interactive)
767		really_exit = false;
768	switch ((i = kshsetjmp(e->jbuf))) {
769	case 0:
770		break;
771	case LINTR:
772		/* we get here if SIGINT not caught or ignored */
773	case LERROR:
774	case LSHELL:
775		if (interactive) {
776			if (i == LINTR)
777				shellf("\n");
778			/*
779			 * Reset any eof that was read as part of a
780			 * multiline command.
781			 */
782			if (Flag(FIGNOREEOF) && s->type == SEOF && wastty)
783				s->type = SSTDIN;
784			/*
785			 * Used by exit command to get back to
786			 * top level shell. Kind of strange since
787			 * interactive is set if we are reading from
788			 * a tty, but to have stopped jobs, one only
789			 * needs FMONITOR set (not FTALKING/SF_TTY)...
790			 */
791			/* toss any input we have so far */
792			yyrecursive_pop(true);
793			s->start = s->str = null;
794			retrace_info = NULL;
795			herep = heres;
796			break;
797		}
798		/* FALLTHROUGH */
799	case LEXIT:
800	case LLEAVE:
801	case LRETURN:
802		source = old_source;
803		quitenv(NULL);
804		/* keep on going */
805		unwind(i);
806		/* NOTREACHED */
807	default:
808		source = old_source;
809		quitenv(NULL);
810		internal_errorf("shell %d", i);
811		/* NOTREACHED */
812	}
813	while (/* CONSTCOND */ 1) {
814		if (trap)
815			runtraps(0);
816
817		if (s->next == NULL) {
818			if (Flag(FVERBOSE))
819				s->flags |= SF_ECHO;
820			else
821				s->flags &= ~SF_ECHO;
822		}
823		if (interactive) {
824			j_notify();
825			set_prompt(PS1, s);
826		}
827		t = compile(s, sfirst);
828		if (interactive)
829			histsave(&s->line, NULL, HIST_FLUSH, true);
830		sfirst = false;
831		if (!t)
832			goto source_no_tree;
833		if (t->type == TEOF) {
834			if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
835				shellf("Use 'exit' to leave mksh\n");
836				s->type = SSTDIN;
837			} else if (wastty && !really_exit &&
838			    j_stopped_running()) {
839				really_exit = true;
840				s->type = SSTDIN;
841			} else {
842				/*
843				 * this for POSIX which says EXIT traps
844				 * shall be taken in the environment
845				 * immediately after the last command
846				 * executed.
847				 */
848				if (toplevel)
849					unwind(LEXIT);
850				break;
851			}
852		} else if ((s->flags & SF_MAYEXEC) && t->type == TCOM)
853			t->u.evalflags |= DOTCOMEXEC;
854		if (!Flag(FNOEXEC) || (s->flags & SF_TTY))
855			exstat = execute(t, 0, NULL) & 0xFF;
856
857		if (t->type != TEOF && interactive && really_exit)
858			really_exit = false;
859
860 source_no_tree:
861		reclaim();
862	}
863	quitenv(NULL);
864	source = old_source;
865	return (exstat & 0xFF);
866}
867
868/* return to closest error handler or shell(), exit if none found */
869/* note: i MUST NOT be 0 */
870void
871unwind(int i)
872{
873	/*
874	 * This is a kludge. We need to restore everything that was
875	 * changed in the new environment, see cid 1005090337C7A669439
876	 * and 10050903386452ACBF1, but fail to even save things most of
877	 * the time. funcs.c:c_eval() changes FERREXIT temporarily to 0,
878	 * which needs to be restored thus (related to Debian #696823).
879	 * We did not save the shell flags, so we use a special or'd
880	 * value here... this is mostly to clean up behind *other*
881	 * callers of unwind(LERROR) here; exec.c has the regular case.
882	 */
883	if (Flag(FERREXIT) & 0x80) {
884		/* GNU bash does not run this trapsig */
885		trapsig(ksh_SIGERR);
886		Flag(FERREXIT) &= ~0x80;
887	}
888
889	/* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */
890	if (i == LEXIT || ((i == LERROR || i == LINTR) &&
891	    sigtraps[ksh_SIGEXIT].trap &&
892	    (!Flag(FTALKING) || Flag(FERREXIT)))) {
893		++trap_nested;
894		runtrap(&sigtraps[ksh_SIGEXIT], trap_nested == 1);
895		--trap_nested;
896		i = LLEAVE;
897	} else if (Flag(FERREXIT) == 1 && (i == LERROR || i == LINTR)) {
898		++trap_nested;
899		runtrap(&sigtraps[ksh_SIGERR], trap_nested == 1);
900		--trap_nested;
901		i = LLEAVE;
902	}
903
904	while (/* CONSTCOND */ 1) {
905		switch (e->type) {
906		case E_PARSE:
907		case E_FUNC:
908		case E_INCL:
909		case E_LOOP:
910		case E_ERRH:
911			kshlongjmp(e->jbuf, i);
912			/* NOTREACHED */
913		case E_NONE:
914			if (i == LINTR)
915				e->flags |= EF_FAKE_SIGDIE;
916			/* FALLTHROUGH */
917		default:
918			quitenv(NULL);
919		}
920	}
921}
922
923void
924newenv(int type)
925{
926	struct env *ep;
927	char *cp;
928
929	/*
930	 * struct env includes ALLOC_ITEM for alignment constraints
931	 * so first get the actually used memory, then assign it
932	 */
933	cp = alloc(sizeof(struct env) - sizeof(ALLOC_ITEM), ATEMP);
934	/* undo what alloc() did to the malloc result address */
935	ep = (void *)(cp - sizeof(ALLOC_ITEM));
936	/* initialise public members of struct env (not the ALLOC_ITEM) */
937	ainit(&ep->area);
938	ep->oenv = e;
939	ep->loc = e->loc;
940	ep->savefd = NULL;
941	ep->temps = NULL;
942	ep->yyrecursive_statep = NULL;
943	ep->type = type;
944	ep->flags = 0;
945	/* jump buffer is invalid because flags == 0 */
946	e = ep;
947}
948
949void
950quitenv(struct shf *shf)
951{
952	struct env *ep = e;
953	char *cp;
954	int fd;
955
956	yyrecursive_pop(true);
957	while (ep->oenv && ep->oenv->loc != ep->loc)
958		popblock();
959	if (ep->savefd != NULL) {
960		for (fd = 0; fd < NUFILE; fd++)
961			/* if ep->savefd[fd] < 0, means fd was closed */
962			if (ep->savefd[fd])
963				restfd(fd, ep->savefd[fd]);
964		if (ep->savefd[2])
965			/* Clear any write errors */
966			shf_reopen(2, SHF_WR, shl_out);
967	}
968	/*
969	 * Bottom of the stack.
970	 * Either main shell is exiting or cleanup_parents_env() was called.
971	 */
972	if (ep->oenv == NULL) {
973#ifdef DEBUG_LEAKS
974		int i;
975#endif
976
977		if (ep->type == E_NONE) {
978			/* Main shell exiting? */
979#if HAVE_PERSISTENT_HISTORY
980			if (Flag(FTALKING))
981				hist_finish();
982#endif
983			j_exit();
984			if (ep->flags & EF_FAKE_SIGDIE) {
985				int sig = (exstat & 0xFF) - 128;
986
987				/*
988				 * ham up our death a bit (AT&T ksh
989				 * only seems to do this for SIGTERM)
990				 * Don't do it for SIGQUIT, since we'd
991				 * dump a core..
992				 */
993				if ((sig == SIGINT || sig == SIGTERM) &&
994				    (kshpgrp == kshpid)) {
995					setsig(&sigtraps[sig], SIG_DFL,
996					    SS_RESTORE_CURR | SS_FORCE);
997					kill(0, sig);
998				}
999			}
1000		}
1001		if (shf)
1002			shf_close(shf);
1003		reclaim();
1004#ifdef DEBUG_LEAKS
1005#ifndef MKSH_NO_CMDLINE_EDITING
1006		x_done();
1007#endif
1008#ifndef MKSH_NOPROSPECTOFWORK
1009		/* block at least SIGCHLD during/after afreeall */
1010		sigprocmask(SIG_BLOCK, &sm_sigchld, NULL);
1011#endif
1012		afreeall(APERM);
1013		for (fd = 3; fd < NUFILE; fd++)
1014			if ((i = fcntl(fd, F_GETFD, 0)) != -1 &&
1015			    (i & FD_CLOEXEC))
1016				close(fd);
1017		close(2);
1018		close(1);
1019		close(0);
1020#endif
1021		exit(exstat & 0xFF);
1022	}
1023	if (shf)
1024		shf_close(shf);
1025	reclaim();
1026
1027	e = e->oenv;
1028
1029	/* free the struct env - tricky due to the ALLOC_ITEM inside */
1030	cp = (void *)ep;
1031	afree(cp + sizeof(ALLOC_ITEM), ATEMP);
1032}
1033
1034/* Called after a fork to cleanup stuff left over from parents environment */
1035void
1036cleanup_parents_env(void)
1037{
1038	struct env *ep;
1039	int fd;
1040
1041	/*
1042	 * Don't clean up temporary files - parent will probably need them.
1043	 * Also, can't easily reclaim memory since variables, etc. could be
1044	 * anywhere.
1045	 */
1046
1047	/* close all file descriptors hiding in savefd */
1048	for (ep = e; ep; ep = ep->oenv) {
1049		if (ep->savefd) {
1050			for (fd = 0; fd < NUFILE; fd++)
1051				if (ep->savefd[fd] > 0)
1052					close(ep->savefd[fd]);
1053			afree(ep->savefd, &ep->area);
1054			ep->savefd = NULL;
1055		}
1056#ifdef DEBUG_LEAKS
1057		if (ep->type != E_NONE)
1058			ep->type = E_GONE;
1059#endif
1060	}
1061#ifndef DEBUG_LEAKS
1062	e->oenv = NULL;
1063#endif
1064}
1065
1066/* Called just before an execve cleanup stuff temporary files */
1067void
1068cleanup_proc_env(void)
1069{
1070	struct env *ep;
1071
1072	for (ep = e; ep; ep = ep->oenv)
1073		remove_temps(ep->temps);
1074}
1075
1076/* remove temp files and free ATEMP Area */
1077static void
1078reclaim(void)
1079{
1080	struct block *l;
1081
1082	while ((l = e->loc) && (!e->oenv || e->oenv->loc != l)) {
1083		e->loc = l->next;
1084		afreeall(&l->area);
1085	}
1086
1087	remove_temps(e->temps);
1088	e->temps = NULL;
1089
1090	/*
1091	 * if the memory backing source is reclaimed, things
1092	 * will end up badly when a function expecting it to
1093	 * be valid is run; a NULL pointer is easily debugged
1094	 */
1095	if (source && source->areap == &e->area)
1096		source = NULL;
1097	afreeall(&e->area);
1098}
1099
1100static void
1101remove_temps(struct temp *tp)
1102{
1103	while (tp) {
1104		if (tp->pid == procpid)
1105			unlink(tp->tffn);
1106		tp = tp->next;
1107	}
1108}
1109
1110/*
1111 * Initialise tty_fd. Used for tracking the size of the terminal,
1112 * saving/resetting tty modes upon forground job completion, and
1113 * for setting up the tty process group. Return values:
1114 *	0 = got controlling tty
1115 *	1 = got terminal but no controlling tty
1116 *	2 = cannot find a terminal
1117 *	3 = cannot dup fd
1118 *	4 = cannot make fd close-on-exec
1119 * An existing tty_fd is cached if no "better" one could be found,
1120 * i.e. if tty_devtty was already set or the new would not set it.
1121 */
1122int
1123tty_init_fd(void)
1124{
1125	int fd, rv, eno = 0;
1126	bool do_close = false, is_devtty = true;
1127
1128	if (tty_devtty) {
1129		/* already got a tty which is /dev/tty */
1130		return (0);
1131	}
1132
1133#ifdef _UWIN
1134	/*XXX imake style */
1135	if (isatty(3)) {
1136		/* fd 3 on UWIN _is_ /dev/tty (or our controlling tty) */
1137		fd = 3;
1138		goto got_fd;
1139	}
1140#endif
1141	if ((fd = open(T_devtty, O_RDWR, 0)) >= 0) {
1142		do_close = true;
1143		goto got_fd;
1144	}
1145	eno = errno;
1146
1147	if (tty_fd >= 0) {
1148		/* already got a non-devtty one */
1149		rv = 1;
1150		goto out;
1151	}
1152	is_devtty = false;
1153
1154	if (isatty((fd = 0)) || isatty((fd = 2)))
1155		goto got_fd;
1156	/* cannot find one */
1157	rv = 2;
1158	/* assert: do_close == false */
1159	goto out;
1160
1161 got_fd:
1162	if ((rv = fcntl(fd, F_DUPFD, FDBASE)) < 0) {
1163		eno = errno;
1164		rv = 3;
1165		goto out;
1166	}
1167	if (fcntl(rv, F_SETFD, FD_CLOEXEC) < 0) {
1168		eno = errno;
1169		close(rv);
1170		rv = 4;
1171		goto out;
1172	}
1173	tty_fd = rv;
1174	tty_devtty = is_devtty;
1175	rv = eno = 0;
1176 out:
1177	if (do_close)
1178		close(fd);
1179	errno = eno;
1180	return (rv);
1181}
1182
1183/* A shell error occurred (eg, syntax error, etc.) */
1184
1185#define VWARNINGF_ERRORPREFIX	1
1186#define VWARNINGF_FILELINE	2
1187#define VWARNINGF_BUILTIN	4
1188#define VWARNINGF_INTERNAL	8
1189
1190static void vwarningf(unsigned int, const char *, va_list)
1191    MKSH_A_FORMAT(__printf__, 2, 0);
1192
1193static void
1194vwarningf(unsigned int flags, const char *fmt, va_list ap)
1195{
1196	if (fmt) {
1197		if (flags & VWARNINGF_INTERNAL)
1198			shf_fprintf(shl_out, Tf_sD_, "internal error");
1199		if (flags & VWARNINGF_ERRORPREFIX)
1200			error_prefix(tobool(flags & VWARNINGF_FILELINE));
1201		if ((flags & VWARNINGF_BUILTIN) &&
1202		    /* not set when main() calls parse_args() */
1203		    builtin_argv0 && builtin_argv0 != kshname)
1204			shf_fprintf(shl_out, Tf_sD_, builtin_argv0);
1205		shf_vfprintf(shl_out, fmt, ap);
1206		shf_putchar('\n', shl_out);
1207	}
1208	shf_flush(shl_out);
1209}
1210
1211void
1212errorfx(int rc, const char *fmt, ...)
1213{
1214	va_list va;
1215
1216	exstat = rc;
1217
1218	/* debugging: note that stdout not valid */
1219	shl_stdout_ok = false;
1220
1221	va_start(va, fmt);
1222	vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va);
1223	va_end(va);
1224	unwind(LERROR);
1225}
1226
1227void
1228errorf(const char *fmt, ...)
1229{
1230	va_list va;
1231
1232	exstat = 1;
1233
1234	/* debugging: note that stdout not valid */
1235	shl_stdout_ok = false;
1236
1237	va_start(va, fmt);
1238	vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va);
1239	va_end(va);
1240	unwind(LERROR);
1241}
1242
1243/* like errorf(), but no unwind is done */
1244void
1245warningf(bool fileline, const char *fmt, ...)
1246{
1247	va_list va;
1248
1249	va_start(va, fmt);
1250	vwarningf(VWARNINGF_ERRORPREFIX | (fileline ? VWARNINGF_FILELINE : 0),
1251	    fmt, va);
1252	va_end(va);
1253}
1254
1255/*
1256 * Used by built-in utilities to prefix shell and utility name to message
1257 * (also unwinds environments for special builtins).
1258 */
1259void
1260bi_errorf(const char *fmt, ...)
1261{
1262	va_list va;
1263
1264	/* debugging: note that stdout not valid */
1265	shl_stdout_ok = false;
1266
1267	exstat = 1;
1268
1269	va_start(va, fmt);
1270	vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE |
1271	    VWARNINGF_BUILTIN, fmt, va);
1272	va_end(va);
1273
1274	/*
1275	 * POSIX special builtins and ksh special builtins cause
1276	 * non-interactive shells to exit. XXX may not want LERROR here
1277	 */
1278	if (builtin_spec) {
1279		builtin_argv0 = NULL;
1280		unwind(LERROR);
1281	}
1282}
1283
1284/* Called when something that shouldn't happen does */
1285void
1286internal_errorf(const char *fmt, ...)
1287{
1288	va_list va;
1289
1290	va_start(va, fmt);
1291	vwarningf(VWARNINGF_INTERNAL, fmt, va);
1292	va_end(va);
1293	unwind(LERROR);
1294}
1295
1296void
1297internal_warningf(const char *fmt, ...)
1298{
1299	va_list va;
1300
1301	va_start(va, fmt);
1302	vwarningf(VWARNINGF_INTERNAL, fmt, va);
1303	va_end(va);
1304}
1305
1306/* used by error reporting functions to print "ksh: .kshrc[25]: " */
1307void
1308error_prefix(bool fileline)
1309{
1310	/* Avoid foo: foo[2]: ... */
1311	if (!fileline || !source || !source->file ||
1312	    strcmp(source->file, kshname) != 0)
1313		shf_fprintf(shl_out, Tf_sD_, kshname + (*kshname == '-'));
1314	if (fileline && source && source->file != NULL) {
1315		shf_fprintf(shl_out, "%s[%lu]: ", source->file,
1316		    (unsigned long)(source->errline ?
1317		    source->errline : source->line));
1318		source->errline = 0;
1319	}
1320}
1321
1322/* printf to shl_out (stderr) with flush */
1323void
1324shellf(const char *fmt, ...)
1325{
1326	va_list va;
1327
1328	if (!initio_done)
1329		/* shl_out may not be set up yet... */
1330		return;
1331	va_start(va, fmt);
1332	shf_vfprintf(shl_out, fmt, va);
1333	va_end(va);
1334	shf_flush(shl_out);
1335}
1336
1337/* printf to shl_stdout (stdout) */
1338void
1339shprintf(const char *fmt, ...)
1340{
1341	va_list va;
1342
1343	if (!shl_stdout_ok)
1344		internal_errorf("shl_stdout not valid");
1345	va_start(va, fmt);
1346	shf_vfprintf(shl_stdout, fmt, va);
1347	va_end(va);
1348}
1349
1350/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
1351int
1352can_seek(int fd)
1353{
1354	struct stat statb;
1355
1356	return (fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
1357	    SHF_UNBUF : 0);
1358}
1359
1360#ifdef DF
1361int shl_dbg_fd;
1362#define NSHF_IOB 4
1363#else
1364#define NSHF_IOB 3
1365#endif
1366struct shf shf_iob[NSHF_IOB];
1367
1368void
1369initio(void)
1370{
1371#ifdef DF
1372	const char *lfp;
1373#endif
1374
1375	/* force buffer allocation */
1376	shf_fdopen(1, SHF_WR, shl_stdout);
1377	shf_fdopen(2, SHF_WR, shl_out);
1378	shf_fdopen(2, SHF_WR, shl_xtrace);
1379#ifdef DF
1380	if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
1381		if ((lfp = getenv("HOME")) == NULL || !mksh_abspath(lfp))
1382			errorf("cannot get home directory");
1383		lfp = shf_smprintf(Tf_sSs, lfp, "mksh-dbg.txt");
1384	}
1385
1386	if ((shl_dbg_fd = open(lfp, O_WRONLY | O_APPEND | O_CREAT, 0600)) < 0)
1387		errorf("cannot open debug output file %s", lfp);
1388	if (shl_dbg_fd < FDBASE) {
1389		int nfd;
1390
1391		nfd = fcntl(shl_dbg_fd, F_DUPFD, FDBASE);
1392		close(shl_dbg_fd);
1393		if ((shl_dbg_fd = nfd) == -1)
1394			errorf("cannot dup debug output file");
1395	}
1396	fcntl(shl_dbg_fd, F_SETFD, FD_CLOEXEC);
1397	shf_fdopen(shl_dbg_fd, SHF_WR, shl_dbg);
1398	DF("=== open ===");
1399#endif
1400	initio_done = true;
1401}
1402
1403/* A dup2() with error checking */
1404int
1405ksh_dup2(int ofd, int nfd, bool errok)
1406{
1407	int rv;
1408
1409	if (((rv = dup2(ofd, nfd)) < 0) && !errok && (errno != EBADF))
1410		errorf("too many files open in shell");
1411
1412#ifdef __ultrix
1413	/*XXX imake style */
1414	if (rv >= 0)
1415		fcntl(nfd, F_SETFD, 0);
1416#endif
1417
1418	return (rv);
1419}
1420
1421/*
1422 * Move fd from user space (0 <= fd < 10) to shell space (fd >= 10),
1423 * set close-on-exec flag. See FDBASE in sh.h, maybe 24 not 10 here.
1424 */
1425short
1426savefd(int fd)
1427{
1428	int nfd = fd;
1429
1430	if (fd < FDBASE && (nfd = fcntl(fd, F_DUPFD, FDBASE)) < 0 &&
1431	    (errno == EBADF || errno == EPERM))
1432		return (-1);
1433	if (nfd < 0 || nfd > SHRT_MAX)
1434		errorf("too many files open in shell");
1435	fcntl(nfd, F_SETFD, FD_CLOEXEC);
1436	return ((short)nfd);
1437}
1438
1439void
1440restfd(int fd, int ofd)
1441{
1442	if (fd == 2)
1443		shf_flush(&shf_iob[/* fd */ 2]);
1444	if (ofd < 0)
1445		/* original fd closed */
1446		close(fd);
1447	else if (fd != ofd) {
1448		/*XXX: what to do if this dup fails? */
1449		ksh_dup2(ofd, fd, true);
1450		close(ofd);
1451	}
1452}
1453
1454void
1455openpipe(int *pv)
1456{
1457	int lpv[2];
1458
1459	if (pipe(lpv) < 0)
1460		errorf("can't create pipe - try again");
1461	pv[0] = savefd(lpv[0]);
1462	if (pv[0] != lpv[0])
1463		close(lpv[0]);
1464	pv[1] = savefd(lpv[1]);
1465	if (pv[1] != lpv[1])
1466		close(lpv[1]);
1467}
1468
1469void
1470closepipe(int *pv)
1471{
1472	close(pv[0]);
1473	close(pv[1]);
1474}
1475
1476/*
1477 * Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
1478 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
1479 */
1480int
1481check_fd(const char *name, int mode, const char **emsgp)
1482{
1483	int fd, fl;
1484
1485	if (!name[0] || name[1])
1486		goto illegal_fd_name;
1487	if (name[0] == 'p')
1488		return (coproc_getfd(mode, emsgp));
1489	if (!ksh_isdigit(name[0])) {
1490 illegal_fd_name:
1491		if (emsgp)
1492			*emsgp = "illegal file descriptor name";
1493		return (-1);
1494	}
1495
1496	if ((fl = fcntl((fd = ksh_numdig(name[0])), F_GETFL, 0)) < 0) {
1497		if (emsgp)
1498			*emsgp = "bad file descriptor";
1499		return (-1);
1500	}
1501	fl &= O_ACCMODE;
1502	/*
1503	 * X_OK is a kludge to disable this check for dups (x<&1):
1504	 * historical shells never did this check (XXX don't know what
1505	 * POSIX has to say).
1506	 */
1507	if (!(mode & X_OK) && fl != O_RDWR && (
1508	    ((mode & R_OK) && fl != O_RDONLY) ||
1509	    ((mode & W_OK) && fl != O_WRONLY))) {
1510		if (emsgp)
1511			*emsgp = (fl == O_WRONLY) ?
1512			    "fd not open for reading" :
1513			    "fd not open for writing";
1514		return (-1);
1515	}
1516	return (fd);
1517}
1518
1519/* Called once from main */
1520void
1521coproc_init(void)
1522{
1523	coproc.read = coproc.readw = coproc.write = -1;
1524	coproc.njobs = 0;
1525	coproc.id = 0;
1526}
1527
1528/* Called by c_read() when eof is read - close fd if it is the co-process fd */
1529void
1530coproc_read_close(int fd)
1531{
1532	if (coproc.read >= 0 && fd == coproc.read) {
1533		coproc_readw_close(fd);
1534		close(coproc.read);
1535		coproc.read = -1;
1536	}
1537}
1538
1539/*
1540 * Called by c_read() and by iosetup() to close the other side of the
1541 * read pipe, so reads will actually terminate.
1542 */
1543void
1544coproc_readw_close(int fd)
1545{
1546	if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
1547		close(coproc.readw);
1548		coproc.readw = -1;
1549	}
1550}
1551
1552/*
1553 * Called by c_print when a write to a fd fails with EPIPE and by iosetup
1554 * when co-process input is dup'd
1555 */
1556void
1557coproc_write_close(int fd)
1558{
1559	if (coproc.write >= 0 && fd == coproc.write) {
1560		close(coproc.write);
1561		coproc.write = -1;
1562	}
1563}
1564
1565/*
1566 * Called to check for existence of/value of the co-process file descriptor.
1567 * (Used by check_fd() and by c_read/c_print to deal with -p option).
1568 */
1569int
1570coproc_getfd(int mode, const char **emsgp)
1571{
1572	int fd = (mode & R_OK) ? coproc.read : coproc.write;
1573
1574	if (fd >= 0)
1575		return (fd);
1576	if (emsgp)
1577		*emsgp = "no coprocess";
1578	return (-1);
1579}
1580
1581/*
1582 * called to close file descriptors related to the coprocess (if any)
1583 * Should be called with SIGCHLD blocked.
1584 */
1585void
1586coproc_cleanup(int reuse)
1587{
1588	/* This to allow co-processes to share output pipe */
1589	if (!reuse || coproc.readw < 0 || coproc.read < 0) {
1590		if (coproc.read >= 0) {
1591			close(coproc.read);
1592			coproc.read = -1;
1593		}
1594		if (coproc.readw >= 0) {
1595			close(coproc.readw);
1596			coproc.readw = -1;
1597		}
1598	}
1599	if (coproc.write >= 0) {
1600		close(coproc.write);
1601		coproc.write = -1;
1602	}
1603}
1604
1605struct temp *
1606maketemp(Area *ap, Temp_type type, struct temp **tlist)
1607{
1608	char *cp;
1609	size_t len;
1610	int i, j;
1611	struct temp *tp;
1612	const char *dir;
1613	struct stat sb;
1614
1615	dir = tmpdir ? tmpdir : MKSH_DEFAULT_TMPDIR;
1616	/* add "/shXXXXXX.tmp" plus NUL */
1617	len = strlen(dir);
1618	checkoktoadd(len, offsetof(struct temp, tffn[0]) + 14);
1619	tp = alloc(offsetof(struct temp, tffn[0]) + 14 + len, ap);
1620
1621	tp->shf = NULL;
1622	tp->pid = procpid;
1623	tp->type = type;
1624
1625	if (stat(dir, &sb) || !S_ISDIR(sb.st_mode)) {
1626		tp->tffn[0] = '\0';
1627		goto maketemp_out;
1628	}
1629
1630	cp = (void *)tp;
1631	cp += offsetof(struct temp, tffn[0]);
1632	memcpy(cp, dir, len);
1633	cp += len;
1634	memcpy(cp, "/shXXXXXX.tmp", 14);
1635	/* point to the first of six Xes */
1636	cp += 3;
1637
1638	/* cyclically attempt to open a temporary file */
1639	do {
1640		/* generate random part of filename */
1641		len = 0;
1642		do {
1643			cp[len++] = digits_lc[rndget() % 36];
1644		} while (len < 6);
1645
1646		/* check if this one works */
1647		if ((i = binopen3(tp->tffn, O_CREAT | O_EXCL | O_RDWR,
1648		    0600)) < 0 && errno != EEXIST)
1649			goto maketemp_out;
1650	} while (i < 0);
1651
1652	if (type == TT_FUNSUB) {
1653		/* map us high and mark as close-on-exec */
1654		if ((j = savefd(i)) != i) {
1655			close(i);
1656			i = j;
1657		}
1658
1659		/* operation mode for the shf */
1660		j = SHF_RD;
1661	} else
1662		j = SHF_WR;
1663
1664	/* shf_fdopen cannot fail, so no fd leak */
1665	tp->shf = shf_fdopen(i, j, NULL);
1666
1667 maketemp_out:
1668	tp->next = *tlist;
1669	*tlist = tp;
1670	return (tp);
1671}
1672
1673/*
1674 * We use a similar collision resolution algorithm as Python 2.5.4
1675 * but with a slightly tweaked implementation written from scratch.
1676 */
1677
1678#define	INIT_TBLSHIFT	3	/* initial table shift (2^3 = 8) */
1679#define PERTURB_SHIFT	5	/* see Python 2.5.4 Objects/dictobject.c */
1680
1681static void tgrow(struct table *);
1682static int tnamecmp(const void *, const void *);
1683
1684static void
1685tgrow(struct table *tp)
1686{
1687	size_t i, j, osize, mask, perturb;
1688	struct tbl *tblp, **pp;
1689	struct tbl **ntblp, **otblp = tp->tbls;
1690
1691	if (tp->tshift > 29)
1692		internal_errorf("hash table size limit reached");
1693
1694	/* calculate old size, new shift and new size */
1695	osize = (size_t)1 << (tp->tshift++);
1696	i = osize << 1;
1697
1698	ntblp = alloc2(i, sizeof(struct tbl *), tp->areap);
1699	/* multiplication cannot overflow: alloc2 checked that */
1700	memset(ntblp, 0, i * sizeof(struct tbl *));
1701
1702	/* table can get very full when reaching its size limit */
1703	tp->nfree = (tp->tshift == 30) ? 0x3FFF0000UL :
1704	    /* but otherwise, only 75% */
1705	    ((i * 3) / 4);
1706	tp->tbls = ntblp;
1707	if (otblp == NULL)
1708		return;
1709
1710	mask = i - 1;
1711	for (i = 0; i < osize; i++)
1712		if ((tblp = otblp[i]) != NULL) {
1713			if ((tblp->flag & DEFINED)) {
1714				/* search for free hash table slot */
1715				j = perturb = tblp->ua.hval;
1716				goto find_first_empty_slot;
1717 find_next_empty_slot:
1718				j = (j << 2) + j + perturb + 1;
1719				perturb >>= PERTURB_SHIFT;
1720 find_first_empty_slot:
1721				pp = &ntblp[j & mask];
1722				if (*pp != NULL)
1723					goto find_next_empty_slot;
1724				/* found an empty hash table slot */
1725				*pp = tblp;
1726				tp->nfree--;
1727			} else if (!(tblp->flag & FINUSE)) {
1728				afree(tblp, tp->areap);
1729			}
1730		}
1731	afree(otblp, tp->areap);
1732}
1733
1734void
1735ktinit(Area *ap, struct table *tp, uint8_t initshift)
1736{
1737	tp->areap = ap;
1738	tp->tbls = NULL;
1739	tp->tshift = ((initshift > INIT_TBLSHIFT) ?
1740	    initshift : INIT_TBLSHIFT) - 1;
1741	tgrow(tp);
1742}
1743
1744/* table, name (key) to search for, hash(name), rv pointer to tbl ptr */
1745struct tbl *
1746ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
1747{
1748	size_t j, perturb, mask;
1749	struct tbl **pp, *p;
1750
1751	mask = ((size_t)1 << (tp->tshift)) - 1;
1752	/* search for hash table slot matching name */
1753	j = perturb = h;
1754	goto find_first_slot;
1755 find_next_slot:
1756	j = (j << 2) + j + perturb + 1;
1757	perturb >>= PERTURB_SHIFT;
1758 find_first_slot:
1759	pp = &tp->tbls[j & mask];
1760	if ((p = *pp) != NULL && (p->ua.hval != h || !(p->flag & DEFINED) ||
1761	    strcmp(p->name, name)))
1762		goto find_next_slot;
1763	/* p == NULL if not found, correct found entry otherwise */
1764	if (ppp)
1765		*ppp = pp;
1766	return (p);
1767}
1768
1769/* table, name (key) to enter, hash(n) */
1770struct tbl *
1771ktenter(struct table *tp, const char *n, uint32_t h)
1772{
1773	struct tbl **pp, *p;
1774	size_t len;
1775
1776 Search:
1777	if ((p = ktscan(tp, n, h, &pp)))
1778		return (p);
1779
1780	if (tp->nfree == 0) {
1781		/* too full */
1782		tgrow(tp);
1783		goto Search;
1784	}
1785
1786	/* create new tbl entry */
1787	len = strlen(n);
1788	checkoktoadd(len, offsetof(struct tbl, name[0]) + 1);
1789	p = alloc(offsetof(struct tbl, name[0]) + ++len, tp->areap);
1790	p->flag = 0;
1791	p->type = 0;
1792	p->areap = tp->areap;
1793	p->ua.hval = h;
1794	p->u2.field = 0;
1795	p->u.array = NULL;
1796	memcpy(p->name, n, len);
1797
1798	/* enter in tp->tbls */
1799	tp->nfree--;
1800	*pp = p;
1801	return (p);
1802}
1803
1804void
1805ktwalk(struct tstate *ts, struct table *tp)
1806{
1807	ts->left = (size_t)1 << (tp->tshift);
1808	ts->next = tp->tbls;
1809}
1810
1811struct tbl *
1812ktnext(struct tstate *ts)
1813{
1814	while (--ts->left >= 0) {
1815		struct tbl *p = *ts->next++;
1816		if (p != NULL && (p->flag & DEFINED))
1817			return (p);
1818	}
1819	return (NULL);
1820}
1821
1822static int
1823tnamecmp(const void *p1, const void *p2)
1824{
1825	const struct tbl *a = *((const struct tbl * const *)p1);
1826	const struct tbl *b = *((const struct tbl * const *)p2);
1827
1828	return (strcmp(a->name, b->name));
1829}
1830
1831struct tbl **
1832ktsort(struct table *tp)
1833{
1834	size_t i;
1835	struct tbl **p, **sp, **dp;
1836
1837	/*
1838	 * since the table is never entirely full, no need to reserve
1839	 * additional space for the trailing NULL appended below
1840	 */
1841	i = (size_t)1 << (tp->tshift);
1842	p = alloc2(i, sizeof(struct tbl *), ATEMP);
1843	sp = tp->tbls;		/* source */
1844	dp = p;			/* dest */
1845	while (i--)
1846		if ((*dp = *sp++) != NULL && (((*dp)->flag & DEFINED) ||
1847		    ((*dp)->flag & ARRAY)))
1848			dp++;
1849	qsort(p, (i = dp - p), sizeof(struct tbl *), tnamecmp);
1850	p[i] = NULL;
1851	return (p);
1852}
1853
1854#ifdef SIGWINCH
1855static void
1856x_sigwinch(int sig MKSH_A_UNUSED)
1857{
1858	/* this runs inside interrupt context, with errno saved */
1859
1860	got_winch = 1;
1861}
1862#endif
1863
1864#ifdef DF
1865void
1866DF(const char *fmt, ...)
1867{
1868	va_list args;
1869	struct timeval tv;
1870	mirtime_mjd mjd;
1871
1872	mksh_lockfd(shl_dbg_fd);
1873	mksh_TIME(tv);
1874	timet2mjd(&mjd, tv.tv_sec);
1875	shf_fprintf(shl_dbg, "[%02u:%02u:%02u (%u) %u.%06u] ",
1876	    (unsigned)mjd.sec / 3600, ((unsigned)mjd.sec / 60) % 60,
1877	    (unsigned)mjd.sec % 60, (unsigned)getpid(),
1878	    (unsigned)tv.tv_sec, (unsigned)tv.tv_usec);
1879	va_start(args, fmt);
1880	shf_vfprintf(shl_dbg, fmt, args);
1881	va_end(args);
1882	shf_putc('\n', shl_dbg);
1883	shf_flush(shl_dbg);
1884	mksh_unlkfd(shl_dbg_fd);
1885}
1886#endif
1887
1888void
1889x_mkraw(int fd, mksh_ttyst *ocb, bool forread)
1890{
1891	mksh_ttyst cb;
1892
1893	if (ocb)
1894		mksh_tcget(fd, ocb);
1895	else
1896		ocb = &tty_state;
1897
1898	cb = *ocb;
1899	if (forread) {
1900		cb.c_iflag &= ~(ISTRIP);
1901		cb.c_lflag &= ~(ICANON) | ECHO;
1902	} else {
1903		cb.c_iflag &= ~(INLCR | ICRNL | ISTRIP);
1904		cb.c_lflag &= ~(ISIG | ICANON | ECHO);
1905	}
1906#if defined(VLNEXT) && defined(_POSIX_VDISABLE)
1907	/* OSF/1 processes lnext when ~icanon */
1908	cb.c_cc[VLNEXT] = _POSIX_VDISABLE;
1909#endif
1910	/* SunOS 4.1.x & OSF/1 processes discard(flush) when ~icanon */
1911#if defined(VDISCARD) && defined(_POSIX_VDISABLE)
1912	cb.c_cc[VDISCARD] = _POSIX_VDISABLE;
1913#endif
1914	cb.c_cc[VTIME] = 0;
1915	cb.c_cc[VMIN] = 1;
1916
1917	mksh_tcset(fd, &cb);
1918}
1919