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