1 /* $NetBSD: main.c,v 1.9 2002/09/25 02:55:03 provos Exp $ */ 2 3 /* 4 * startup, main loop, environments and error handling 5 */ 6 7 #define EXTERN /* define EXTERNs in sh.h */ 8 9 #include "sh.h" 10 #include "ksh_stat.h" 11 #include "ksh_time.h" 12 13 extern char **environ; 14 15 /* 16 * global data 17 */ 18 19 static void reclaim ARGS((void)); 20 static void remove_temps ARGS((struct temp *tp)); 21 static int is_restricted ARGS((char *name)); 22 23 /* 24 * shell initialization 25 */ 26 27 static const char initifs[] = "IFS= \t\n"; 28 29 static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }"; 30 31 static const char version_param[] = 32 #ifdef KSH 33 "KSH_VERSION" 34 #else /* KSH */ 35 "SH_VERSION" 36 #endif /* KSH */ 37 ; 38 39 static const char *const initcoms [] = { 40 "typeset", "-x", "SHELL", "PATH", "HOME", NULL, 41 "typeset", "-r", version_param, NULL, 42 "typeset", "-i", "PPID", NULL, 43 "typeset", "-i", "OPTIND=1", NULL, 44 #ifdef KSH 45 "eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL, 46 #endif /* KSH */ 47 "alias", 48 /* Standard ksh aliases */ 49 "hash=alias -t", /* not "alias -t --": hash -r needs to work */ 50 "type=whence -v", 51 #ifdef JOBS 52 "stop=kill -STOP", 53 "suspend=kill -STOP $$", 54 #endif 55 #ifdef KSH 56 "autoload=typeset -fu", 57 "functions=typeset -f", 58 # ifdef HISTORY 59 "history=fc -l", 60 # endif /* HISTORY */ 61 "integer=typeset -i", 62 "nohup=nohup ", 63 "local=typeset", 64 "r=fc -e -", 65 #endif /* KSH */ 66 #ifdef KSH 67 /* Aliases that are builtin commands in at&t */ 68 "login=exec login", 69 #ifndef __NetBSD__ 70 "newgrp=exec newgrp", 71 #endif /* __NetBSD__ */ 72 #endif /* KSH */ 73 NULL, 74 /* this is what at&t ksh seems to track, with the addition of emacs */ 75 "alias", "-tU", 76 "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls", 77 "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who", 78 NULL, 79 #ifdef EXTRA_INITCOMS 80 EXTRA_INITCOMS, NULL, 81 #endif /* EXTRA_INITCOMS */ 82 NULL 83 }; 84 85 int main __P((int, char **)); 86 87 int 88 main(argc, argv) 89 int argc; 90 register char **argv; 91 { 92 register int i; 93 int argi; 94 Source *s; 95 struct block *l; 96 int restricted, errexit; 97 char **wp; 98 struct env env; 99 pid_t ppid; 100 101 #ifdef MEM_DEBUG 102 chmem_set_defaults("ct", 1); 103 /* chmem_push("+c", 1); */ 104 #endif /* MEM_DEBUG */ 105 106 #ifdef OS2 107 setmode (0, O_BINARY); 108 setmode (1, O_TEXT); 109 #endif 110 111 /* make sure argv[] is sane */ 112 if (!*argv) { 113 static const char *empty_argv[] = { 114 "pdksh", (char *) 0 115 }; 116 117 argv = (char **) empty_argv; 118 argc = 1; 119 } 120 kshname = *argv; 121 122 ainit(&aperm); /* initialize permanent Area */ 123 124 /* set up base environment */ 125 memset(&env, 0, sizeof(env)); 126 env.type = E_NONE; 127 ainit(&env.area); 128 e = &env; 129 newblock(); /* set up global l->vars and l->funs */ 130 131 /* Do this first so output routines (eg, errorf, shellf) can work */ 132 initio(); 133 134 initvar(); 135 136 initctypes(); 137 138 inittraps(); 139 140 #ifdef KSH 141 coproc_init(); 142 #endif /* KSH */ 143 144 /* set up variable and command dictionaries */ 145 tinit(&taliases, APERM, 0); 146 tinit(&aliases, APERM, 0); 147 tinit(&homedirs, APERM, 0); 148 149 /* define shell keywords */ 150 initkeywords(); 151 152 /* define built-in commands */ 153 tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */ 154 for (i = 0; shbuiltins[i].name != NULL; i++) 155 builtin(shbuiltins[i].name, shbuiltins[i].func); 156 for (i = 0; kshbuiltins[i].name != NULL; i++) 157 builtin(kshbuiltins[i].name, kshbuiltins[i].func); 158 159 init_histvec(); 160 161 def_path = DEFAULT__PATH; 162 #if defined(HAVE_CONFSTR) && defined(_CS_PATH) 163 { 164 size_t len = confstr(_CS_PATH, (char *) 0, 0); 165 char *new; 166 167 if (len > 0) { 168 confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1); 169 def_path = new; 170 } 171 } 172 #endif /* HAVE_CONFSTR && _CS_PATH */ 173 174 /* Set PATH to def_path (will set the path global variable). 175 * (import of environment below will probably change this setting). 176 */ 177 { 178 struct tbl *vp = global("PATH"); 179 /* setstr can't fail here */ 180 setstr(vp, def_path, KSH_RETURN_ERROR); 181 } 182 183 184 /* Turn on nohup by default for how - will change to off 185 * by default once people are aware of its existance 186 * (at&t ksh does not have a nohup option - it always sends 187 * the hup). 188 */ 189 Flag(FNOHUP) = 1; 190 191 /* Turn on brace expansion by default. At&t ksh's that have 192 * alternation always have it on. BUT, posix doesn't have 193 * brace expansion, so set this before setting up FPOSIX 194 * (change_flag() clears FBRACEEXPAND when FPOSIX is set). 195 */ 196 #ifdef BRACE_EXPAND 197 Flag(FBRACEEXPAND) = 1; 198 #endif /* BRACE_EXPAND */ 199 200 /* set posix flag just before environment so that it will have 201 * exactly the same effect as the POSIXLY_CORRECT environment 202 * variable. If this needs to be done sooner to ensure correct posix 203 * operation, an initial scan of the environment will also have 204 * done sooner. 205 */ 206 #ifdef POSIXLY_CORRECT 207 change_flag(FPOSIX, OF_SPECIAL, 1); 208 #endif /* POSIXLY_CORRECT */ 209 210 /* Set edit mode to emacs by default, may be overridden 211 * by the environment or the user. Also, we want tab completion 212 * on in vi by default. */ 213 #if defined(EDIT) && defined(EMACS) 214 change_flag(FEMACS, OF_SPECIAL, 1); 215 #endif /* EDIT && EMACS */ 216 #if defined(EDIT) && defined(VI) 217 Flag(FVITABCOMPLETE) = 1; 218 #endif /* EDIT && VI */ 219 220 /* import environment */ 221 if (environ != NULL) 222 for (wp = environ; *wp != NULL; wp++) 223 typeset(*wp, IMPORT|EXPORT, 0, 0, 0); 224 225 kshpid = procpid = getpid(); 226 typeset(initifs, 0, 0, 0, 0); /* for security */ 227 228 /* assign default shell variable values */ 229 substitute(initsubs, 0); 230 231 /* Figure out the current working directory and set $PWD */ 232 { 233 struct stat s_pwd, s_dot; 234 struct tbl *pwd_v = global("PWD"); 235 char *pwd = str_val(pwd_v); 236 char *pwdx = pwd; 237 238 /* Try to use existing $PWD if it is valid */ 239 if (!ISABSPATH(pwd) 240 || stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0 241 || s_pwd.st_dev != s_dot.st_dev 242 || s_pwd.st_ino != s_dot.st_ino) 243 pwdx = (char *) 0; 244 set_current_wd(pwdx); 245 if (current_wd[0]) 246 simplify_path(current_wd); 247 /* Only set pwd if we know where we are or if it had a 248 * bogus value 249 */ 250 if (current_wd[0] || pwd != null) 251 /* setstr can't fail here */ 252 setstr(pwd_v, current_wd, KSH_RETURN_ERROR); 253 } 254 ppid = getppid(); 255 setint(global("PPID"), (long) ppid); 256 #ifdef KSH 257 setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid)); 258 #endif /* KSH */ 259 /* setstr can't fail here */ 260 setstr(global(version_param), ksh_version, KSH_RETURN_ERROR); 261 262 /* execute initialization statements */ 263 for (wp = (char**) initcoms; *wp != NULL; wp++) { 264 shcomexec(wp); 265 for (; *wp != NULL; wp++) 266 ; 267 } 268 269 270 ksheuid = geteuid(); 271 safe_prompt = ksheuid ? "$ " : "# "; 272 { 273 struct tbl *vp = global("PS1"); 274 275 /* Set PS1 if it isn't set, or we are root and prompt doesn't 276 * contain a #. 277 */ 278 if (!(vp->flag & ISSET) 279 || (!ksheuid && !strchr(str_val(vp), '#'))) 280 /* setstr can't fail here */ 281 setstr(vp, safe_prompt, KSH_RETURN_ERROR); 282 } 283 284 /* Set this before parsing arguments */ 285 Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid(); 286 287 /* this to note if monitor is set on command line (see below) */ 288 Flag(FMONITOR) = 127; 289 argi = parse_args(argv, OF_CMDLINE, (int *) 0); 290 if (argi < 0) { 291 exit(1); 292 /* NOTREACHED */ 293 } 294 295 if (Flag(FCOMMAND)) { 296 s = pushs(SSTRING, ATEMP); 297 if (!(s->start = s->str = argv[argi++])) 298 errorf("-c requires an argument"); 299 if (argv[argi]) 300 kshname = argv[argi++]; 301 } else if (argi < argc && !Flag(FSTDIN)) { 302 s = pushs(SFILE, ATEMP); 303 #ifdef OS2 304 /* a bug in os2 extproc shell processing doesn't 305 * pass full pathnames so we have to search for it. 306 * This changes the behavior of 'ksh arg' to search 307 * the users search path but it can't be helped. 308 */ 309 s->file = search(argv[argi++], path, R_OK, (int *) 0); 310 if (!s->file || !*s->file) 311 s->file = argv[argi - 1]; 312 #else 313 s->file = argv[argi++]; 314 #endif /* OS2 */ 315 s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); 316 if (s->u.shf == NULL) { 317 exstat = 127; /* POSIX */ 318 errorf("%s: %s", s->file, strerror(errno)); 319 } 320 kshname = s->file; 321 } else { 322 Flag(FSTDIN) = 1; 323 s = pushs(SSTDIN, ATEMP); 324 s->file = "<stdin>"; 325 s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0), 326 (struct shf *) 0); 327 if (isatty(0) && isatty(2)) { 328 Flag(FTALKING) = Flag(FTALKING_I) = 1; 329 /* The following only if isatty(0) */ 330 s->flags |= SF_TTY; 331 s->u.shf->flags |= SHF_INTERRUPT; 332 s->file = (char *) 0; 333 } 334 } 335 336 /* This bizarreness is mandated by POSIX */ 337 { 338 struct stat s_stdin; 339 340 if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode)) 341 reset_nonblock(0); 342 } 343 344 /* initialize job control */ 345 i = Flag(FMONITOR) != 127; 346 Flag(FMONITOR) = 0; 347 j_init(i); 348 #ifdef EDIT 349 /* Do this after j_init(), as tty_fd is not initialized 'til then */ 350 if (Flag(FTALKING)) 351 x_init(); 352 #endif 353 354 l = e->loc; 355 l->argv = &argv[argi - 1]; 356 l->argc = argc - argi; 357 l->argv[0] = (char *) kshname; 358 getopts_reset(1); 359 360 /* Disable during .profile/ENV reading */ 361 restricted = Flag(FRESTRICTED); 362 Flag(FRESTRICTED) = 0; 363 errexit = Flag(FERREXIT); 364 Flag(FERREXIT) = 0; 365 366 /* Do this before profile/$ENV so that if it causes problems in them, 367 * user will know why things broke. 368 */ 369 if (!current_wd[0] && Flag(FTALKING)) 370 warningf(FALSE, "Cannot determine current working directory"); 371 372 if (Flag(FLOGIN)) { 373 #ifdef OS2 374 char *profile; 375 376 /* Try to find a profile - first see if $INIT has a value, 377 * then try /etc/profile.ksh, then c:/usr/etc/profile.ksh. 378 */ 379 if (!Flag(FPRIVILEGED) 380 && strcmp(profile = substitute("$INIT/profile.ksh", 0), 381 "/profile.ksh")) 382 include(profile, 0, (char **) 0, 1); 383 else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0) 384 include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1); 385 if (!Flag(FPRIVILEGED)) 386 include(substitute("$HOME/profile.ksh", 0), 0, 387 (char **) 0, 1); 388 #else /* OS2 */ 389 include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1); 390 if (!Flag(FPRIVILEGED)) 391 include(substitute("$HOME/.profile", 0), 0, 392 (char **) 0, 1); 393 #endif /* OS2 */ 394 } 395 396 if (Flag(FPRIVILEGED)) 397 include("/etc/suid_profile", 0, (char **) 0, 1); 398 else { 399 char *env_file; 400 401 #ifndef KSH 402 if (!Flag(FPOSIX)) 403 env_file = null; 404 else 405 #endif /* !KSH */ 406 /* include $ENV */ 407 env_file = str_val(global("ENV")); 408 409 #ifdef DEFAULT_ENV 410 /* If env isn't set, include default environment */ 411 if (env_file == null) 412 env_file = DEFAULT_ENV; 413 #endif /* DEFAULT_ENV */ 414 env_file = substitute(env_file, DOTILDE); 415 if (*env_file != '\0') 416 include(env_file, 0, (char **) 0, 1); 417 #ifdef OS2 418 else if (Flag(FTALKING)) 419 include(substitute("$HOME/kshrc.ksh", 0), 0, 420 (char **) 0, 1); 421 #endif /* OS2 */ 422 } 423 424 if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL")))) 425 restricted = 1; 426 if (restricted) { 427 static const char *const restr_com[] = { 428 "typeset", "-r", "PATH", 429 "ENV", "SHELL", 430 (char *) 0 431 }; 432 shcomexec((char **) restr_com); 433 /* After typeset command... */ 434 Flag(FRESTRICTED) = 1; 435 } 436 if (errexit) 437 Flag(FERREXIT) = 1; 438 439 if (Flag(FTALKING)) { 440 hist_init(s); 441 #ifdef KSH 442 alarm_init(); 443 #endif /* KSH */ 444 } else 445 Flag(FTRACKALL) = 1; /* set after ENV */ 446 447 shell(s, TRUE); /* doesn't return */ 448 return 0; 449 } 450 451 int 452 include(name, argc, argv, intr_ok) 453 const char *name; 454 int argc; 455 char **argv; 456 int intr_ok; 457 { 458 register Source *volatile s = NULL; 459 Source *volatile sold; 460 struct shf *shf; 461 char **volatile old_argv; 462 volatile int old_argc; 463 int i; 464 465 shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); 466 if (shf == NULL) 467 return -1; 468 469 if (argv) { 470 old_argv = e->loc->argv; 471 old_argc = e->loc->argc; 472 } else { 473 old_argv = (char **) 0; 474 old_argc = 0; 475 } 476 sold = source; 477 newenv(E_INCL); 478 i = ksh_sigsetjmp(e->jbuf, 0); 479 if (i) { 480 source = sold; 481 if (s) /* Do this before quitenv(), which frees the memory */ 482 shf_close(s->u.shf); 483 quitenv(); 484 if (old_argv) { 485 e->loc->argv = old_argv; 486 e->loc->argc = old_argc; 487 } 488 switch (i) { 489 case LRETURN: 490 case LERROR: 491 return exstat & 0xff; /* see below */ 492 case LINTR: 493 /* intr_ok is set if we are including .profile or $ENV. 494 * If user ^C's out, we don't want to kill the shell... 495 */ 496 if (intr_ok && (exstat - 128) != SIGTERM) 497 return 1; 498 /* fall through... */ 499 case LEXIT: 500 case LLEAVE: 501 case LSHELL: 502 unwind(i); 503 /*NOREACHED*/ 504 default: 505 internal_errorf(1, "include: %d", i); 506 /*NOREACHED*/ 507 } 508 } 509 if (argv) { 510 e->loc->argv = argv; 511 e->loc->argc = argc; 512 } 513 s = pushs(SFILE, ATEMP); 514 s->u.shf = shf; 515 s->file = str_save(name, ATEMP); 516 i = shell(s, FALSE); 517 source = sold; 518 shf_close(s->u.shf); 519 quitenv(); 520 if (old_argv) { 521 e->loc->argv = old_argv; 522 e->loc->argc = old_argc; 523 } 524 return i & 0xff; /* & 0xff to ensure value not -1 */ 525 } 526 527 int 528 command(comm) 529 const char *comm; 530 { 531 register Source *s; 532 533 s = pushs(SSTRING, ATEMP); 534 s->start = s->str = comm; 535 return shell(s, FALSE); 536 } 537 538 /* 539 * run the commands from the input source, returning status. 540 */ 541 int 542 shell(s, toplevel) 543 Source *volatile s; /* input source */ 544 int volatile toplevel; 545 { 546 struct op *t; 547 volatile int wastty = s->flags & SF_TTY; 548 volatile int attempts = 13; 549 volatile int interactive = Flag(FTALKING) && toplevel; 550 int i; 551 552 newenv(E_PARSE); 553 if (interactive) 554 really_exit = 0; 555 i = ksh_sigsetjmp(e->jbuf, 0); 556 if (i) { 557 s->start = s->str = null; 558 switch (i) { 559 case LINTR: /* we get here if SIGINT not caught or ignored */ 560 case LERROR: 561 case LSHELL: 562 if (interactive) { 563 if (i == LINTR) 564 shellf(newline); 565 /* Reset any eof that was read as part of a 566 * multiline command. 567 */ 568 if (Flag(FIGNOREEOF) && s->type == SEOF 569 && wastty) 570 s->type = SSTDIN; 571 /* Used by exit command to get back to 572 * top level shell. Kind of strange since 573 * interactive is set if we are reading from 574 * a tty, but to have stopped jobs, one only 575 * needs FMONITOR set (not FTALKING/SF_TTY)... 576 */ 577 break; 578 } 579 /* fall through... */ 580 case LEXIT: 581 case LLEAVE: 582 case LRETURN: 583 quitenv(); 584 unwind(i); /* keep on going */ 585 /*NOREACHED*/ 586 default: 587 quitenv(); 588 internal_errorf(1, "shell: %d", i); 589 /*NOREACHED*/ 590 } 591 } 592 593 while (1) { 594 if (trap) 595 runtraps(0); 596 597 if (s->next == NULL) { 598 if (Flag(FVERBOSE)) 599 s->flags |= SF_ECHO; 600 else 601 s->flags &= ~SF_ECHO; 602 } 603 604 if (interactive) { 605 j_notify(); 606 #ifdef KSH 607 mcheck(); 608 #endif /* KSH */ 609 set_prompt(PS1, s); 610 } 611 612 t = compile(s); 613 if (t != NULL && t->type == TEOF) { 614 if (wastty && Flag(FIGNOREEOF) && --attempts > 0) { 615 shellf("Use `exit' to leave ksh\n"); 616 s->type = SSTDIN; 617 } else if (wastty && !really_exit 618 && j_stopped_running()) 619 { 620 really_exit = 1; 621 s->type = SSTDIN; 622 } else { 623 /* this for POSIX, which says EXIT traps 624 * shall be taken in the environment 625 * immediately after the last command 626 * executed. 627 */ 628 if (toplevel) 629 unwind(LEXIT); 630 break; 631 } 632 } 633 634 if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY))) 635 exstat = execute(t, 0); 636 637 if (t != NULL && t->type != TEOF && interactive && really_exit) 638 really_exit = 0; 639 640 reclaim(); 641 } 642 quitenv(); 643 return exstat; 644 } 645 646 /* return to closest error handler or shell(), exit if none found */ 647 void 648 unwind(i) 649 int i; 650 { 651 /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */ 652 if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) 653 && sigtraps[SIGEXIT_].trap)) 654 { 655 runtrap(&sigtraps[SIGEXIT_]); 656 i = LLEAVE; 657 } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) { 658 runtrap(&sigtraps[SIGERR_]); 659 i = LLEAVE; 660 } 661 while (1) { 662 switch (e->type) { 663 case E_PARSE: 664 case E_FUNC: 665 case E_INCL: 666 case E_LOOP: 667 case E_ERRH: 668 ksh_siglongjmp(e->jbuf, i); 669 /*NOTREACHED*/ 670 671 case E_NONE: 672 if (i == LINTR) 673 e->flags |= EF_FAKE_SIGDIE; 674 /* Fall through... */ 675 676 default: 677 quitenv(); 678 } 679 } 680 } 681 682 void 683 newenv(type) 684 int type; 685 { 686 register struct env *ep; 687 688 ep = (struct env *) alloc(sizeof(*ep), ATEMP); 689 ep->type = type; 690 ep->flags = 0; 691 ainit(&ep->area); 692 ep->loc = e->loc; 693 ep->savefd = NULL; 694 ep->oenv = e; 695 ep->temps = NULL; 696 e = ep; 697 } 698 699 void 700 quitenv() 701 { 702 register struct env *ep = e; 703 register int fd; 704 705 if (ep->oenv && ep->oenv->loc != ep->loc) 706 popblock(); 707 if (ep->savefd != NULL) { 708 for (fd = 0; fd < NUFILE; fd++) 709 /* if ep->savefd[fd] < 0, means fd was closed */ 710 if (ep->savefd[fd]) 711 restfd(fd, ep->savefd[fd]); 712 if (ep->savefd[2]) /* Clear any write errors */ 713 shf_reopen(2, SHF_WR, shl_out); 714 } 715 reclaim(); 716 717 /* Bottom of the stack. 718 * Either main shell is exiting or cleanup_parents_env() was called. 719 */ 720 if (ep->oenv == NULL) { 721 if (ep->type == E_NONE) { /* Main shell exiting? */ 722 if (Flag(FTALKING)) 723 hist_finish(); 724 j_exit(); 725 if (ep->flags & EF_FAKE_SIGDIE) { 726 int sig = exstat - 128; 727 728 /* ham up our death a bit (at&t ksh 729 * only seems to do this for SIGTERM) 730 * Don't do it for SIGQUIT, since we'd 731 * dump a core.. 732 */ 733 if (sig == SIGINT || sig == SIGTERM) { 734 setsig(&sigtraps[sig], SIG_DFL, 735 SS_RESTORE_CURR|SS_FORCE); 736 kill(0, sig); 737 } 738 } 739 #ifdef MEM_DEBUG 740 chmem_allfree(); 741 #endif /* MEM_DEBUG */ 742 } 743 exit(exstat); 744 } 745 746 e = e->oenv; 747 afree(ep, ATEMP); 748 } 749 750 /* Called after a fork to cleanup stuff left over from parents environment */ 751 void 752 cleanup_parents_env() 753 { 754 struct env *ep; 755 int fd; 756 757 /* Don't clean up temporary files - parent will probably need them. 758 * Also, can't easily reclaim memory since variables, etc. could be 759 * anywyere. 760 */ 761 762 /* close all file descriptors hiding in savefd */ 763 for (ep = e; ep; ep = ep->oenv) { 764 if (ep->savefd) { 765 for (fd = 0; fd < NUFILE; fd++) 766 if (ep->savefd[fd] > 0) 767 close(ep->savefd[fd]); 768 afree(ep->savefd, &ep->area); 769 ep->savefd = (short *) 0; 770 } 771 } 772 e->oenv = (struct env *) 0; 773 } 774 775 /* Called just before an execve cleanup stuff temporary files */ 776 void 777 cleanup_proc_env() 778 { 779 struct env *ep; 780 781 for (ep = e; ep; ep = ep->oenv) 782 remove_temps(ep->temps); 783 } 784 785 /* remove temp files and free ATEMP Area */ 786 static void 787 reclaim() 788 { 789 remove_temps(e->temps); 790 e->temps = NULL; 791 afreeall(&e->area); 792 } 793 794 static void 795 remove_temps(tp) 796 struct temp *tp; 797 { 798 #ifdef OS2 799 static struct temp *delayed_remove; 800 struct temp *t, **tprev; 801 802 if (delayed_remove) { 803 for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev) 804 /* No need to check t->pid here... */ 805 if (unlink(t->name) >= 0 || errno == ENOENT) { 806 *tprev = t->next; 807 afree(t, APERM); 808 } else 809 tprev = &t->next; 810 } 811 #endif /* OS2 */ 812 813 for (; tp != NULL; tp = tp->next) 814 if (tp->pid == procpid) { 815 #ifdef OS2 816 /* OS/2 (and dos) do not allow files that are currently 817 * open to be removed, so we cache it away for future 818 * removal. 819 * XXX should only do this if errno 820 * is Efile-still-open-can't-remove 821 * (but I don't know what that is...) 822 */ 823 if (unlink(tp->name) < 0 && errno != ENOENT) { 824 t = (struct temp *) alloc( 825 sizeof(struct temp) + strlen(tp->name) + 1, 826 APERM); 827 memset(t, 0, sizeof(struct temp)); 828 t->name = (char *) &t[1]; 829 strcpy(t->name, tp->name); 830 t->next = delayed_remove; 831 delayed_remove = t; 832 } 833 #else /* OS2 */ 834 unlink(tp->name); 835 #endif /* OS2 */ 836 } 837 } 838 839 /* Returns true if name refers to a restricted shell */ 840 static int 841 is_restricted(name) 842 char *name; 843 { 844 char *p; 845 846 if ((p = ksh_strrchr_dirsep(name))) 847 name = p; 848 /* accepts rsh, rksh, rpdksh, pdrksh, etc. */ 849 return (p = strchr(name, 'r')) && strstr(p, "sh"); 850 } 851 852 void 853 aerror(ap, msg) 854 Area *ap; 855 const char *msg; 856 { 857 internal_errorf(1, "alloc: %s", msg); 858 errorf(null); /* this is never executed - keeps gcc quiet */ 859 /*NOTREACHED*/ 860 } 861