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