OSDN Git Service

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