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