1 /* 2 * startup, main loop, enviroments and error handling 3 */ 4 5 #define EXTERN /* define EXTERNs in sh.h */ 6 7 #include "sh.h" 8 #include "ksh_stat.h" 9 #include "ksh_time.h" 10 11 extern char **environ; 12 13 /* 14 * global data 15 */ 16 17 static void reclaim ARGS((void)); 18 static void remove_temps ARGS((struct temp *tp)); 19 static int is_restricted ARGS((char *name)); 20 21 /* 22 * shell initialization 23 */ 24 25 static const char initifs [] = "IFS= \t\n"; /* must be R/W */ 26 27 static const char initsubs [] = 28 "${PS2=> } ${PS3=#? } ${PS4=+ }"; 29 30 static const char version_param[] = 31 #ifdef KSH 32 "KSH_VERSION" 33 #else /* KSH */ 34 "SH_VERSION" 35 #endif /* KSH */ 36 ; 37 38 static const char *const initcoms [] = { 39 "typeset", "-x", "SHELL", "PATH", "HOME", NULL, 40 "typeset", "-r", version_param, NULL, 41 "typeset", "-ri", "PPID", NULL, 42 "typeset", "-i", "OPTIND=1", 43 #ifdef KSH 44 "MAILCHECK=600", "RANDOM", "SECONDS=0", "TMOUT=0", 45 #endif /* KSH */ 46 NULL, 47 "alias", 48 /* Standard ksh aliases */ 49 "hash=alias -t", /* not "alias -t --": hash -r needs to work */ 50 "type=whence -v", 51 #ifdef JOBS 52 "stop=kill -STOP", 53 "suspend=kill -STOP $$", 54 #endif 55 #ifdef KSH 56 "autoload=typeset -fu", 57 "functions=typeset -f", 58 # ifdef HISTORY 59 "history=fc -l", 60 # endif /* HISTORY */ 61 "integer=typeset -i", 62 "nohup=nohup ", 63 "local=typeset", 64 "r=fc -e -", 65 #endif /* KSH */ 66 #ifdef KSH 67 /* Aliases that are builtin commands in at&t */ 68 "login=exec login", 69 "newgrp=exec newgrp", 70 #endif /* KSH */ 71 NULL, 72 /* this is what at&t ksh seems to track, with the addition of emacs */ 73 "alias", "-tU", 74 "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls", 75 "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who", 76 NULL, 77 #ifdef EXTRA_INITCOMS 78 EXTRA_INITCOMS, NULL, 79 #endif /* EXTRA_INITCOMS */ 80 NULL 81 }; 82 83 int 84 main(argc, argv) 85 int argc; 86 register char **argv; 87 { 88 register int i; 89 int argi; 90 Source *s; 91 struct block *l; 92 int restricted; 93 char **wp; 94 struct env env; 95 int euid; 96 97 #ifdef MEM_DEBUG 98 chmem_push("+c", 1); 99 /*chmem_push("+cd", 1);*/ 100 #endif 101 102 #ifdef OS2 103 setmode (0, O_BINARY); 104 setmode (1, O_TEXT); 105 #endif 106 107 /* make sure argv[] is sane */ 108 if (!*argv) { 109 static const char *empty_argv[] = { 110 "pdksh", (char *) 0 111 }; 112 113 argv = (char **) empty_argv; 114 argc = 1; 115 } 116 kshname = *argv; 117 118 ainit(&aperm); /* initialize permanent Area */ 119 120 /* set up base enviroment */ 121 env.type = E_NONE; 122 ainit(&env.area); 123 env.savefd = NULL; 124 env.oenv = NULL; 125 env.loc = (struct block *) 0; 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 /* remove temp files and free ATEMP Area */ 731 static void 732 reclaim() 733 { 734 remove_temps(e->temps); 735 e->temps = NULL; 736 afreeall(&e->area); 737 } 738 739 static void 740 remove_temps(tp) 741 struct temp *tp; 742 { 743 #ifdef OS2 744 static char tmpfile[30]; 745 int status; 746 747 if (strlen (tmpfile) > 0 ) { 748 unlink(tmpfile); 749 *tmpfile=0; 750 } 751 #endif /* OS2 */ 752 753 for (; tp != NULL; tp = tp->next) 754 if (tp->pid == procpid) 755 #ifdef OS2 756 { status=unlink(tp->name); 757 if (status < 0) 758 strcpy(tmpfile, tp->name); 759 } 760 #else /* OS2 */ 761 unlink(tp->name); 762 #endif /* OS2 */ 763 } 764 765 /* Returns true if name refers to a restricted shell */ 766 static int 767 is_restricted(name) 768 char *name; 769 { 770 char *p; 771 772 if ((p = ksh_strrchr_dirsep(name))) 773 name = p; 774 /* accepts rsh, rksh, rpdksh, pdrksh, etc. */ 775 return (p = strchr(name, 'r')) && strstr(p, "sh"); 776 } 777 778 void 779 aerror(ap, msg) 780 Area *ap; 781 const char *msg; 782 { 783 internal_errorf(1, "alloc: %s", msg); 784 errorf(null); /* this is never executed - keeps gcc quiet */ 785 /*NOTREACHED*/ 786 } 787