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