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