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