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