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
rndsetup(void)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
chvt_rndsetup(const void * bp,size_t sz)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
chvt_reinit(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
isuc(const char * cx)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
main_init(int argc,const char * argv[],Source ** sp,struct block ** lp)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
main(int argc,const char * argv[])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
include(const char * name,int argc,const char ** argv,bool intr_ok)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
command(const char * comm,int line)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
shell(Source * volatile s,volatile bool toplevel)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
unwind(int i)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
newenv(int type)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
quitenv(struct shf * shf)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
cleanup_parents_env(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
cleanup_proc_env(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
reclaim(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
remove_temps(struct temp * tp)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
tty_init_fd(void)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
vwarningf(unsigned int flags,const char * fmt,va_list ap)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
errorfx(int rc,const char * fmt,...)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
errorf(const char * fmt,...)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
warningf(bool fileline,const char * fmt,...)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
bi_errorf(const char * fmt,...)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
internal_errorf(const char * fmt,...)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
internal_warningf(const char * fmt,...)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
error_prefix(bool fileline)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
shellf(const char * fmt,...)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
shprintf(const char * fmt,...)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
can_seek(int fd)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
initio(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
ksh_dup2(int ofd,int nfd,bool errok)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
savefd(int fd)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
restfd(int fd,int ofd)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
openpipe(int * pv)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
closepipe(int * pv)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
check_fd(const char * name,int mode,const char ** emsgp)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
coproc_init(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
coproc_read_close(int fd)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
coproc_readw_close(int fd)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
coproc_write_close(int fd)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
coproc_getfd(int mode,const char ** emsgp)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
coproc_cleanup(int reuse)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 *
maketemp(Area * ap,Temp_type type,struct temp ** tlist)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
tgrow(struct table * tp)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
ktinit(Area * ap,struct table * tp,uint8_t initshift)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 *
ktscan(struct table * tp,const char * name,uint32_t h,struct tbl *** ppp)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 *
ktenter(struct table * tp,const char * n,uint32_t h)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
ktwalk(struct tstate * ts,struct table * tp)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 *
ktnext(struct tstate * ts)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
tnamecmp(const void * p1,const void * p2)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 **
ktsort(struct table * tp)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
x_sigwinch(int sig MKSH_A_UNUSED)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
DF(const char * fmt,...)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
x_mkraw(int fd,mksh_ttyst * ocb,bool forread)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 }
1942