1 /* $NetBSD: main.c,v 1.3 1997/07/20 17:42:08 christos 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 269 if (Flag(FCOMMAND)) { 270 s = pushs(SSTRING, ATEMP); 271 if (!(s->start = s->str = argv[argi++])) 272 errorf("-c requires an argument"); 273 if (argv[argi]) 274 kshname = argv[argi++]; 275 } else if (argi < argc && !Flag(FSTDIN)) { 276 s = pushs(SFILE, ATEMP); 277 #ifdef OS2 278 /* a bug in os2 extproc shell processing doesn't 279 * pass full pathnames so we have to search for it. 280 * This changes the behavior of 'ksh arg' to search 281 * the users search path but it can't be helped. 282 */ 283 s->file = search(argv[argi++], path, R_OK, (int *) 0); 284 if (!s->file || !*s->file) 285 s->file = argv[argi - 1]; 286 #else 287 s->file = argv[argi++]; 288 #endif /* OS2 */ 289 s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); 290 if (s->u.shf == NULL) { 291 exstat = 127; /* POSIX */ 292 errorf("%s: %s", s->file, strerror(errno)); 293 } 294 kshname = s->file; 295 } else { 296 Flag(FSTDIN) = 1; 297 s = pushs(SSTDIN, ATEMP); 298 s->file = "<stdin>"; 299 s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0), 300 (struct shf *) 0); 301 if (isatty(0) && isatty(2)) { 302 Flag(FTALKING) = 1; 303 /* The following only if isatty(0) */ 304 s->flags |= SF_TTY; 305 s->u.shf->flags |= SHF_INTERRUPT; 306 s->file = (char *) 0; 307 } 308 } 309 310 /* This bizarreness is mandated by POSIX */ 311 { 312 struct stat s_stdin; 313 314 if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode)) 315 reset_nonblock(0); 316 } 317 318 /* initialize job control */ 319 i = Flag(FMONITOR) != 127; 320 Flag(FMONITOR) = 0; 321 j_init(i); 322 #ifdef EDIT 323 /* Do this after j_init(), as tty_fd is not initialized 'til then */ 324 if (Flag(FTALKING)) 325 x_init(); 326 #endif 327 328 l = e->loc; 329 l->argv = &argv[argi - 1]; 330 l->argc = argc - argi; 331 l->argv[0] = (char *) kshname; 332 getopts_reset(1); 333 334 /* Disable during .profile/ENV reading */ 335 restricted = Flag(FRESTRICTED); 336 Flag(FRESTRICTED) = 0; 337 338 /* Do this before profile/$ENV so that if it causes problems in them, 339 * user will know why things broke. 340 */ 341 if (!current_wd[0] && Flag(FTALKING)) 342 warningf(FALSE, "Cannot determine current working directory"); 343 344 if (Flag(FLOGIN)) { 345 #ifdef OS2 346 char *profile; 347 348 /* Try to find a profile - first see if $INIT has a value, 349 * then try /etc/profile.ksh, then c:/usr/etc/profile.ksh. 350 */ 351 if (!Flag(FPRIVILEGED) 352 && strcmp(profile = substitute("$INIT/profile.ksh", 0), 353 "/profile.ksh")) 354 include(profile, 0, (char **) 0, 1); 355 else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0) 356 include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1); 357 if (!Flag(FPRIVILEGED)) 358 include(substitute("$HOME/profile.ksh", 0), 0, 359 (char **) 0, 1); 360 #else /* OS2 */ 361 include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1); 362 if (!Flag(FPRIVILEGED)) 363 include(substitute("$HOME/.profile", 0), 0, 364 (char **) 0, 1); 365 #endif /* OS2 */ 366 } 367 368 if (Flag(FPRIVILEGED)) 369 include("/etc/suid_profile", 0, (char **) 0, 1); 370 else { 371 char *env_file; 372 373 #ifndef KSH 374 if (!Flag(FPOSIX)) 375 env_file = null; 376 else 377 #endif /* !KSH */ 378 /* include $ENV */ 379 env_file = str_val(global("ENV")); 380 381 #ifdef DEFAULT_ENV 382 /* If env isn't set, include default environment */ 383 if (env_file == null) 384 env_file = DEFAULT_ENV; 385 #endif /* DEFAULT_ENV */ 386 env_file = substitute(env_file, DOTILDE); 387 if (*env_file != '\0') 388 include(env_file, 0, (char **) 0, 1); 389 #ifdef OS2 390 else if (Flag(FTALKING)) 391 include(substitute("$HOME/kshrc.ksh", 0), 0, 392 (char **) 0, 1); 393 #endif /* OS2 */ 394 } 395 396 if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL")))) 397 restricted = 1; 398 if (restricted) { 399 static const char *const restr_com[] = { 400 "typeset", "-r", "PATH", 401 "ENV", "SHELL", 402 (char *) 0 403 }; 404 shcomexec((char **) restr_com); 405 /* After typeset command... */ 406 Flag(FRESTRICTED) = 1; 407 } 408 409 if (Flag(FTALKING)) { 410 hist_init(s); 411 #ifdef KSH 412 alarm_init(); 413 #endif /* KSH */ 414 } else 415 Flag(FTRACKALL) = 1; /* set after ENV */ 416 417 shell(s, TRUE); /* doesn't return */ 418 return 0; 419 } 420 421 int 422 include(name, argc, argv, intr_ok) 423 const char *name; 424 int argc; 425 char **argv; 426 int intr_ok; 427 { 428 register Source *volatile s = NULL; 429 Source *volatile sold; 430 struct shf *shf; 431 char **volatile old_argv; 432 volatile int old_argc; 433 int i; 434 435 shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); 436 if (shf == NULL) 437 return -1; 438 439 if (argv) { 440 old_argv = e->loc->argv; 441 old_argc = e->loc->argc; 442 } else { 443 old_argv = (char **) 0; 444 old_argc = 0; 445 } 446 sold = source; 447 newenv(E_INCL); 448 i = ksh_sigsetjmp(e->jbuf, 0); 449 if (i) { 450 quitenv(); 451 source = sold; 452 if (s) 453 shf_close(s->u.shf); 454 if (old_argv) { 455 e->loc->argv = old_argv; 456 e->loc->argc = old_argc; 457 } 458 switch (i) { 459 case LRETURN: 460 case LERROR: 461 return exstat & 0xff; /* see below */ 462 case LINTR: 463 /* intr_ok is set if we are including .profile or $ENV. 464 * If user ^C's out, we don't want to kill the shell... 465 */ 466 if (intr_ok && (exstat - 128) != SIGTERM) 467 return 1; 468 /* fall through... */ 469 case LEXIT: 470 case LLEAVE: 471 case LSHELL: 472 unwind(i); 473 /*NOREACHED*/ 474 default: 475 internal_errorf(1, "include: %d", i); 476 /*NOREACHED*/ 477 } 478 } 479 if (argv) { 480 e->loc->argv = argv; 481 e->loc->argc = argc; 482 } 483 s = pushs(SFILE, ATEMP); 484 s->u.shf = shf; 485 s->file = str_save(name, ATEMP); 486 i = shell(s, FALSE); 487 quitenv(); 488 source = sold; 489 shf_close(s->u.shf); 490 if (old_argv) { 491 e->loc->argv = old_argv; 492 e->loc->argc = old_argc; 493 } 494 return i & 0xff; /* & 0xff to ensure value not -1 */ 495 } 496 497 int 498 command(comm) 499 const char *comm; 500 { 501 register Source *s; 502 503 s = pushs(SSTRING, ATEMP); 504 s->start = s->str = comm; 505 return shell(s, FALSE); 506 } 507 508 /* 509 * run the commands from the input source, returning status. 510 */ 511 int 512 shell(s, toplevel) 513 Source *volatile s; /* input source */ 514 int volatile toplevel; 515 { 516 struct op *t; 517 volatile int wastty = s->flags & SF_TTY; 518 volatile int attempts = 13; 519 volatile int interactive = Flag(FTALKING) && toplevel; 520 int i; 521 522 newenv(E_PARSE); 523 if (interactive) 524 really_exit = 0; 525 i = ksh_sigsetjmp(e->jbuf, 0); 526 if (i) { 527 s->start = s->str = null; 528 switch (i) { 529 case LINTR: /* we get here if SIGINT not caught or ignored */ 530 case LERROR: 531 case LSHELL: 532 if (interactive) { 533 if (i == LINTR) 534 shellf(newline); 535 /* Reset any eof that was read as part of a 536 * multiline command. 537 */ 538 if (Flag(FIGNOREEOF) && s->type == SEOF 539 && wastty) 540 s->type = SSTDIN; 541 /* Used by exit command to get back to 542 * top level shell. Kind of strange since 543 * interactive is set if we are reading from 544 * a tty, but to have stopped jobs, one only 545 * needs FMONITOR set (not FTALKING/SF_TTY)... 546 */ 547 break; 548 } 549 /* fall through... */ 550 case LEXIT: 551 case LLEAVE: 552 case LRETURN: 553 quitenv(); 554 unwind(i); /* keep on going */ 555 /*NOREACHED*/ 556 default: 557 quitenv(); 558 internal_errorf(1, "shell: %d", i); 559 /*NOREACHED*/ 560 } 561 } 562 563 while (1) { 564 if (trap) 565 runtraps(0); 566 567 if (s->next == NULL) 568 if (Flag(FVERBOSE)) 569 s->flags |= SF_ECHO; 570 else 571 s->flags &= ~SF_ECHO; 572 573 if (interactive) { 574 j_notify(); 575 #ifdef KSH 576 mcheck(); 577 #endif /* KSH */ 578 set_prompt(PS1, s); 579 } 580 581 t = compile(s); 582 if (t != NULL && t->type == TEOF) { 583 if (wastty && Flag(FIGNOREEOF) && --attempts > 0) { 584 shellf("Use `exit' to leave ksh\n"); 585 s->type = SSTDIN; 586 } else if (wastty && !really_exit 587 && j_stopped_running()) 588 { 589 really_exit = 1; 590 s->type = SSTDIN; 591 } else { 592 /* this for POSIX, which says EXIT traps 593 * shall be taken in the environment 594 * immediately after the last command 595 * executed. 596 */ 597 if (toplevel) 598 unwind(LEXIT); 599 break; 600 } 601 } 602 603 if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY))) 604 exstat = execute(t, 0); 605 606 if (t != NULL && t->type != TEOF && interactive && really_exit) 607 really_exit = 0; 608 609 reclaim(); 610 } 611 quitenv(); 612 return exstat; 613 } 614 615 /* return to closest error handler or shell(), exit if none found */ 616 void 617 unwind(i) 618 int i; 619 { 620 /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */ 621 if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) 622 && sigtraps[SIGEXIT_].trap)) 623 { 624 runtrap(&sigtraps[SIGEXIT_]); 625 i = LLEAVE; 626 } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) { 627 runtrap(&sigtraps[SIGERR_]); 628 i = LLEAVE; 629 } 630 while (1) { 631 switch (e->type) { 632 case E_PARSE: 633 case E_FUNC: 634 case E_INCL: 635 case E_LOOP: 636 case E_ERRH: 637 ksh_siglongjmp(e->jbuf, i); 638 /*NOTREACHED*/ 639 640 case E_NONE: /* bottom of the stack */ 641 { 642 if (Flag(FTALKING)) 643 hist_finish(); 644 j_exit(); 645 remove_temps(func_heredocs); 646 if (i == LINTR) { 647 int sig = exstat - 128; 648 649 /* ham up our death a bit (at&t ksh 650 * only seems to do this for SIGTERM) 651 * Don't do it for SIGQUIT, since we'd 652 * dump a core.. 653 */ 654 if (sig == SIGINT || sig == SIGTERM) { 655 setsig(&sigtraps[sig], SIG_DFL, 656 SS_RESTORE_CURR|SS_FORCE); 657 kill(0, sig); 658 } 659 } 660 exit(exstat); 661 /* NOTREACHED */ 662 } 663 664 default: 665 quitenv(); 666 } 667 } 668 } 669 670 void 671 newenv(type) 672 int type; 673 { 674 register struct env *ep; 675 676 ep = (struct env *) alloc(sizeof(*ep), ATEMP); 677 ep->type = type; 678 ep->flags = 0; 679 ainit(&ep->area); 680 ep->loc = e->loc; 681 ep->savefd = NULL; 682 ep->oenv = e; 683 ep->temps = NULL; 684 e = ep; 685 } 686 687 void 688 quitenv() 689 { 690 register struct env *ep = e; 691 register int fd; 692 693 if (ep->oenv == NULL) /* cleanup_parents_env() was called */ 694 exit(exstat); /* exit child */ 695 if (ep->oenv->loc != ep->loc) 696 popblock(); 697 if (ep->savefd != NULL) { 698 for (fd = 0; fd < NUFILE; fd++) 699 /* if ep->savefd[fd] < 0, means fd was closed */ 700 if (ep->savefd[fd]) 701 restfd(fd, ep->savefd[fd]); 702 if (ep->savefd[2]) /* Clear any write errors */ 703 shf_reopen(2, SHF_WR, shl_out); 704 } 705 reclaim(); 706 e = e->oenv; 707 afree(ep, ATEMP); 708 } 709 710 /* Called after a fork to cleanup stuff left over from parents environment */ 711 void 712 cleanup_parents_env() 713 { 714 struct env *ep; 715 int fd; 716 717 /* Don't clean up temporary files - parent will probably need them. 718 * Also, can't easily reclaim memory since variables, etc. could be 719 * anywyere. 720 */ 721 722 /* close all file descriptors hiding in savefd */ 723 for (ep = e; ep; ep = ep->oenv) { 724 if (ep->savefd) 725 for (fd = 0; fd < NUFILE; fd++) 726 if (ep->savefd[fd] > 0) 727 close(ep->savefd[fd]); 728 } 729 e->oenv = (struct env *) 0; 730 } 731 732 /* Called just before an execve cleanup stuff temporary files */ 733 void 734 cleanup_proc_env() 735 { 736 struct env *ep; 737 738 for (ep = e; ep; ep = ep->oenv) 739 remove_temps(ep->temps); 740 remove_temps(func_heredocs); 741 } 742 743 /* remove temp files and free ATEMP Area */ 744 static void 745 reclaim() 746 { 747 remove_temps(e->temps); 748 e->temps = NULL; 749 afreeall(&e->area); 750 } 751 752 static void 753 remove_temps(tp) 754 struct temp *tp; 755 { 756 #ifdef OS2 757 static struct temp *delayed_remove; 758 struct temp *t, **tprev; 759 760 if (delayed_remove) { 761 for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev) 762 /* No need to check t->pid here... */ 763 if (unlink(t->name) >= 0 || errno == ENOENT) { 764 *tprev = t->next; 765 afree(t, APERM); 766 } else 767 tprev = &t->next; 768 } 769 #endif /* OS2 */ 770 771 for (; tp != NULL; tp = tp->next) 772 if (tp->pid == procpid) { 773 #ifdef OS2 774 /* OS/2 (and dos) do not allow files that are currently 775 * open to be removed, so we cache it away for future 776 * removal. 777 * XXX should only do this if errno 778 * is Efile-still-open-can't-remove 779 * (but I don't know what that is...) 780 */ 781 if (unlink(tp->name) < 0 && errno != ENOENT) { 782 t = (struct temp *) alloc( 783 sizeof(struct temp) + strlen(tp->name) + 1, 784 APERM); 785 memset(t, 0, sizeof(struct temp)); 786 strcpy(t->name, tp->name); 787 t->next = delayed_remove; 788 delayed_remove = t; 789 } 790 #else /* OS2 */ 791 unlink(tp->name); 792 #endif /* OS2 */ 793 } 794 } 795 796 /* Returns true if name refers to a restricted shell */ 797 static int 798 is_restricted(name) 799 char *name; 800 { 801 char *p; 802 803 if ((p = ksh_strrchr_dirsep(name))) 804 name = p; 805 /* accepts rsh, rksh, rpdksh, pdrksh, etc. */ 806 return (p = strchr(name, 'r')) && strstr(p, "sh"); 807 } 808 809 void 810 aerror(ap, msg) 811 Area *ap; 812 const char *msg; 813 { 814 internal_errorf(1, "alloc: %s", msg); 815 errorf(null); /* this is never executed - keeps gcc quiet */ 816 /*NOTREACHED*/ 817 } 818