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