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