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