1 /*- 2 * Copyright (c) 1980, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)csh.c 5.25 (Berkeley) 06/08/91"; 16 #endif /* not lint */ 17 18 #include <sys/types.h> 19 #include <sys/ioctl.h> 20 #include <sys/stat.h> 21 #include <fcntl.h> 22 #include <errno.h> 23 #include <pwd.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <locale.h> 27 #include <unistd.h> 28 #include "csh.h" 29 #include "extern.h" 30 #include "pathnames.h" 31 32 extern bool MapsAreInited; 33 extern bool NLSMapsAreInited; 34 35 /* 36 * C Shell 37 * 38 * Bill Joy, UC Berkeley, California, USA 39 * October 1978, May 1980 40 * 41 * Jim Kulp, IIASA, Laxenburg, Austria 42 * April 1980 43 * 44 * Christos Zoulas, Cornell University 45 * June, 1991 46 */ 47 48 Char *dumphist[] = {STRhistory, STRmh, 0, 0}; 49 Char *loadhist[] = {STRsource, STRmh, STRhistfile, 0}; 50 51 int nofile = 0; 52 bool reenter = 0; 53 bool nverbose = 0; 54 bool nexececho = 0; 55 bool quitit = 0; 56 bool fast = 0; 57 bool batch = 0; 58 bool mflag = 0; 59 bool prompt = 1; 60 bool enterhist = 0; 61 bool tellwhat = 0; 62 63 extern char **environ; 64 65 static int srccat __P((Char *, Char *)); 66 static int srcfile __P((char *, bool, bool)); 67 static void phup __P((int)); 68 static void srcunit __P((int, bool, bool)); 69 static void mailchk __P((void)); 70 static Char **defaultpath __P((void)); 71 72 int 73 main(argc, argv) 74 int argc; 75 char **argv; 76 { 77 register Char *cp; 78 register char *tcp; 79 register int f; 80 register char **tempv; 81 struct sigvec osv; 82 83 84 settimes(); /* Immed. estab. timing base */ 85 86 /* 87 * Initialize non constant strings 88 */ 89 #ifdef _PATH_BSHELL 90 STR_BSHELL = SAVE(_PATH_BSHELL); 91 #endif 92 #ifdef _PATH_CSHELL 93 STR_SHELLPATH = SAVE(_PATH_CSHELL); 94 #endif 95 STR_environ = blk2short(environ); 96 environ = short2blk(STR_environ); /* So that we can free it */ 97 STR_WORD_CHARS = SAVE(WORD_CHARS); 98 99 HIST = '!'; 100 HISTSUB = '^'; 101 word_chars = STR_WORD_CHARS; 102 103 tempv = argv; 104 if (eq(str2short(tempv[0]), STRaout)) /* A.out's are quittable */ 105 quitit = 1; 106 uid = getuid(); 107 gid = getgid(); 108 /* 109 * We are a login shell if: 1. we were invoked as -<something> and we had 110 * no arguments 2. or we were invoked only with the -l flag 111 */ 112 loginsh = (**tempv == '-' && argc == 1) || 113 (argc == 2 && tempv[1][0] == '-' && tempv[1][1] == 'l' && 114 tempv[1][2] == '\0'); 115 116 if (loginsh && **tempv != '-') { 117 /* 118 * Mangle the argv space 119 */ 120 tempv[1][0] = '\0'; 121 tempv[1][1] = '\0'; 122 tempv[1] = NULL; 123 for (tcp = *tempv; *tcp++;); 124 for (tcp--; tcp >= *tempv; tcp--) 125 tcp[1] = tcp[0]; 126 *++tcp = '-'; 127 argc--; 128 } 129 if (loginsh) 130 (void) time(&chktim); 131 132 AsciiOnly = 1; 133 #ifdef NLS 134 (void) setlocale(LC_ALL, ""); 135 { 136 int k; 137 138 for (k = 0200; k <= 0377 && !Isprint(k); k++); 139 AsciiOnly = k > 0377; 140 } 141 #else 142 AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL; 143 #endif /* NLS */ 144 145 /* 146 * Move the descriptors to safe places. The variable didfds is 0 while we 147 * have only FSH* to work with. When didfds is true, we have 0,1,2 and 148 * prefer to use these. 149 */ 150 initdesc(); 151 152 /* 153 * Initialize the shell variables. ARGV and PROMPT are initialized later. 154 * STATUS is also munged in several places. CHILD is munged when 155 * forking/waiting 156 */ 157 set(STRstatus, Strsave(STR0)); 158 159 if ((tcp = getenv("HOME")) != NULL) 160 cp = SAVE(tcp); 161 else 162 cp = NULL; 163 164 if (cp == NULL) 165 fast = 1; /* No home -> can't read scripts */ 166 else 167 set(STRhome, cp); 168 dinit(cp); /* dinit thinks that HOME == cwd in a login 169 * shell */ 170 /* 171 * Grab other useful things from the environment. Should we grab 172 * everything?? 173 */ 174 if ((tcp = getenv("LOGNAME")) != NULL || 175 (tcp = getenv("USER")) != NULL) 176 set(STRuser, SAVE(tcp)); 177 if ((tcp = getenv("TERM")) != NULL) 178 set(STRterm, SAVE(tcp)); 179 180 /* 181 * Re-initialize path if set in environment 182 */ 183 if ((tcp = getenv("PATH")) == NULL) 184 set1(STRpath, defaultpath(), &shvhed); 185 else 186 importpath(SAVE(tcp)); 187 188 set(STRshell, Strsave(STR_SHELLPATH)); 189 190 doldol = putn((int) getpid()); /* For $$ */ 191 shtemp = Strspl(STRtmpsh, doldol); /* For << */ 192 193 /* 194 * Record the interrupt states from the parent process. If the parent is 195 * non-interruptible our hand must be forced or we (and our children) won't 196 * be either. Our children inherit termination from our parent. We catch it 197 * only if we are the login shell. 198 */ 199 /* parents interruptibility */ 200 (void) sigvec(SIGINT, NULL, &osv); 201 parintr = (void (*) ()) osv.sv_handler; 202 (void) sigvec(SIGTERM, NULL, &osv); 203 parterm = (void (*) ()) osv.sv_handler; 204 205 if (loginsh) { 206 (void) signal(SIGHUP, phup); /* exit processing on HUP */ 207 (void) signal(SIGXCPU, phup); /* ...and on XCPU */ 208 (void) signal(SIGXFSZ, phup); /* ...and on XFSZ */ 209 } 210 211 /* 212 * Process the arguments. 213 * 214 * Note that processing of -v/-x is actually delayed till after script 215 * processing. 216 * 217 * We set the first character of our name to be '-' if we are a shell running 218 * interruptible commands. Many programs which examine ps'es use this to 219 * filter such shells out. 220 */ 221 argc--, tempv++; 222 while (argc > 0 && (tcp = tempv[0])[0] == '-' && *++tcp != '\0' && !batch) { 223 do 224 switch (*tcp++) { 225 226 case 0: /* - Interruptible, no prompt */ 227 prompt = 0; 228 setintr = 1; 229 nofile = 1; 230 break; 231 232 case 'b': /* -b Next arg is input file */ 233 batch = 1; 234 break; 235 236 case 'c': /* -c Command input from arg */ 237 if (argc == 1) 238 xexit(0); 239 argc--, tempv++; 240 arginp = SAVE(tempv[0]); 241 prompt = 0; 242 nofile = 1; 243 break; 244 245 case 'e': /* -e Exit on any error */ 246 exiterr = 1; 247 break; 248 249 case 'f': /* -f Fast start */ 250 fast = 1; 251 break; 252 253 case 'i': /* -i Interactive, even if !intty */ 254 intact = 1; 255 nofile = 1; 256 break; 257 258 case 'm': /* -m read .cshrc (from su) */ 259 mflag = 1; 260 break; 261 262 case 'n': /* -n Don't execute */ 263 noexec = 1; 264 break; 265 266 case 'q': /* -q (Undoc'd) ... die on quit */ 267 quitit = 1; 268 break; 269 270 case 's': /* -s Read from std input */ 271 nofile = 1; 272 break; 273 274 case 't': /* -t Read one line from input */ 275 onelflg = 2; 276 prompt = 0; 277 nofile = 1; 278 break; 279 280 case 'v': /* -v Echo hist expanded input */ 281 nverbose = 1; /* ... later */ 282 break; 283 284 case 'x': /* -x Echo just before execution */ 285 nexececho = 1; /* ... later */ 286 break; 287 288 case 'V': /* -V Echo hist expanded input */ 289 setNS(STRverbose); /* NOW! */ 290 break; 291 292 case 'X': /* -X Echo just before execution */ 293 setNS(STRecho); /* NOW! */ 294 break; 295 296 } while (*tcp); 297 tempv++, argc--; 298 } 299 300 if (quitit) /* With all due haste, for debugging */ 301 (void) signal(SIGQUIT, SIG_DFL); 302 303 /* 304 * Unless prevented by -, -c, -i, -s, or -t, if there are remaining 305 * arguments the first of them is the name of a shell file from which to 306 * read commands. 307 */ 308 if (nofile == 0 && argc > 0) { 309 nofile = open(tempv[0], O_RDONLY); 310 if (nofile < 0) { 311 child = 1; /* So this doesn't return */ 312 stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 313 } 314 ffile = SAVE(tempv[0]); 315 /* 316 * Replace FSHIN. Handle /dev/std{in,out,err} specially 317 * since once they are closed we cannot open them again. 318 * In that case we use our own saved descriptors 319 */ 320 if ((SHIN = dmove(nofile, FSHIN)) < 0) 321 switch(nofile) { 322 case 0: 323 SHIN = FSHIN; 324 break; 325 case 1: 326 SHIN = FSHOUT; 327 break; 328 case 2: 329 SHIN = FSHDIAG; 330 break; 331 default: 332 stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 333 break; 334 } 335 (void) ioctl(SHIN, FIOCLEX, NULL); 336 prompt = 0; 337 /* argc not used any more */ tempv++; 338 } 339 intty = isatty(SHIN); 340 intty |= intact; 341 if (intty || (intact && isatty(SHOUT))) { 342 if (!batch && (uid != geteuid() || gid != getegid())) { 343 errno = EACCES; 344 child = 1; /* So this doesn't return */ 345 stderror(ERR_SYSTEM, "csh", strerror(errno)); 346 } 347 } 348 /* 349 * Decide whether we should play with signals or not. If we are explicitly 350 * told (via -i, or -) or we are a login shell (arg0 starts with -) or the 351 * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 352 * Note that in only the login shell is it likely that parent may have set 353 * signals to be ignored 354 */ 355 if (loginsh || intact || intty && isatty(SHOUT)) 356 setintr = 1; 357 settell(); 358 /* 359 * Save the remaining arguments in argv. 360 */ 361 setq(STRargv, blk2short(tempv), &shvhed); 362 363 /* 364 * Set up the prompt. 365 */ 366 if (prompt) { 367 set(STRprompt, Strsave(uid == 0 ? STRsymhash : STRsymcent)); 368 /* that's a meta-questionmark */ 369 set(STRprompt2, Strsave(STRmquestion)); 370 } 371 372 /* 373 * If we are an interactive shell, then start fiddling with the signals; 374 * this is a tricky game. 375 */ 376 shpgrp = getpgrp(); 377 opgrp = tpgrp = -1; 378 if (setintr) { 379 **argv = '-'; 380 if (!quitit) /* Wary! */ 381 (void) signal(SIGQUIT, SIG_IGN); 382 (void) signal(SIGINT, pintr); 383 (void) sigblock(sigmask(SIGINT)); 384 (void) signal(SIGTERM, SIG_IGN); 385 if (quitit == 0 && arginp == 0) { 386 (void) signal(SIGTSTP, SIG_IGN); 387 (void) signal(SIGTTIN, SIG_IGN); 388 (void) signal(SIGTTOU, SIG_IGN); 389 /* 390 * Wait till in foreground, in case someone stupidly runs csh & 391 * dont want to try to grab away the tty. 392 */ 393 if (isatty(FSHDIAG)) 394 f = FSHDIAG; 395 else if (isatty(FSHOUT)) 396 f = FSHOUT; 397 else if (isatty(OLDSTD)) 398 f = OLDSTD; 399 else 400 f = -1; 401 retry: 402 if ((tpgrp = tcgetpgrp(f)) != -1) { 403 if (tpgrp != shpgrp) { 404 sig_t old = signal(SIGTTIN, SIG_DFL); 405 (void) kill(0, SIGTTIN); 406 (void) signal(SIGTTIN, old); 407 goto retry; 408 } 409 opgrp = shpgrp; 410 shpgrp = getpid(); 411 tpgrp = shpgrp; 412 /* 413 * Setpgid will fail if we are a session leader and 414 * mypid == mypgrp (POSIX 4.3.3) 415 */ 416 if (opgrp != shpgrp) 417 if (setpgid(0, shpgrp) == -1) 418 goto notty; 419 /* 420 * We do that after we set our process group, to make sure 421 * that the process group belongs to a process in the same 422 * session as the tty (our process and our group) (POSIX 7.2.4) 423 */ 424 if (tcsetpgrp(f, shpgrp) == -1) 425 goto notty; 426 (void) ioctl(dcopy(f, FSHTTY), FIOCLEX, NULL); 427 } 428 if (tpgrp == -1) { 429 notty: 430 xprintf("Warning: no access to tty (%s).\n", strerror(errno)); 431 xprintf("Thus no job control in this shell.\n"); 432 } 433 } 434 } 435 if ((setintr == 0) && (parintr == SIG_DFL)) 436 setintr = 1; 437 (void) signal(SIGCHLD, pchild); /* while signals not ready */ 438 439 /* 440 * Set an exit here in case of an interrupt or error reading the shell 441 * start-up scripts. 442 */ 443 reenter = setexit(); /* PWP */ 444 haderr = 0; /* In case second time through */ 445 if (!fast && reenter == 0) { 446 /* Will have value(STRhome) here because set fast if don't */ 447 { 448 int osetintr = setintr; 449 sigset_t omask = sigblock(sigmask(SIGINT)); 450 451 setintr = 0; 452 #ifdef _PATH_DOTCSHRC 453 (void) srcfile(_PATH_DOTCSHRC, 0, 0); 454 #endif 455 if (!fast && !arginp && !onelflg) 456 dohash(); 457 #ifdef _PATH_DOTLOGIN 458 if (loginsh) 459 (void) srcfile(_PATH_DOTLOGIN, 0, 0); 460 #endif 461 (void) sigsetmask(omask); 462 setintr = osetintr; 463 } 464 (void) srccat(value(STRhome), STRsldotcshrc); 465 466 if (!fast && !arginp && !onelflg && !havhash) 467 dohash(); 468 if (loginsh) 469 (void) srccat(value(STRhome), STRsldotlogin); 470 dosource(loadhist); 471 } 472 473 /* 474 * Now are ready for the -v and -x flags 475 */ 476 if (nverbose) 477 setNS(STRverbose); 478 if (nexececho) 479 setNS(STRecho); 480 481 /* 482 * All the rest of the world is inside this call. The argument to process 483 * indicates whether it should catch "error unwinds". Thus if we are a 484 * interactive shell our call here will never return by being blown past on 485 * an error. 486 */ 487 process(setintr); 488 489 /* 490 * Mop-up. 491 */ 492 if (intty) { 493 if (loginsh) { 494 xprintf("logout\n"); 495 (void) close(SHIN); 496 child = 1; 497 goodbye(); 498 } 499 else { 500 xprintf("exit\n"); 501 } 502 } 503 rechist(); 504 exitstat(); 505 return (0); 506 } 507 508 void 509 untty() 510 { 511 if (tpgrp > 0) { 512 (void) setpgid(0, opgrp); 513 (void) tcsetpgrp(FSHTTY, opgrp); 514 } 515 } 516 517 void 518 importpath(cp) 519 Char *cp; 520 { 521 register int i = 0; 522 register Char *dp; 523 register Char **pv; 524 int c; 525 526 for (dp = cp; *dp; dp++) 527 if (*dp == ':') 528 i++; 529 /* 530 * i+2 where i is the number of colons in the path. There are i+1 531 * directories in the path plus we need room for a zero terminator. 532 */ 533 pv = (Char **) xcalloc((size_t) (i + 2), sizeof(Char **)); 534 dp = cp; 535 i = 0; 536 if (*dp) 537 for (;;) { 538 if ((c = *dp) == ':' || c == 0) { 539 *dp = 0; 540 pv[i++] = Strsave(*cp ? cp : STRdot); 541 if (c) { 542 cp = dp + 1; 543 *dp = ':'; 544 } 545 else 546 break; 547 } 548 dp++; 549 } 550 pv[i] = 0; 551 set1(STRpath, pv, &shvhed); 552 } 553 554 /* 555 * Source to the file which is the catenation of the argument names. 556 */ 557 static int 558 srccat(cp, dp) 559 Char *cp, *dp; 560 { 561 register Char *ep = Strspl(cp, dp); 562 char *ptr = short2str(ep); 563 564 xfree((ptr_t) ep); 565 return srcfile(ptr, mflag ? 0 : 1, 0); 566 } 567 568 /* 569 * Source to a file putting the file descriptor in a safe place (> 2). 570 */ 571 static int 572 srcfile(f, onlyown, flag) 573 char *f; 574 bool onlyown, flag; 575 { 576 register int unit; 577 578 if ((unit = open(f, O_RDONLY)) == -1) 579 return 0; 580 unit = dmove(unit, -1); 581 582 (void) ioctl(unit, FIOCLEX, NULL); 583 srcunit(unit, onlyown, flag); 584 return 1; 585 } 586 587 /* 588 * Source to a unit. If onlyown it must be our file or our group or 589 * we don't chance it. This occurs on ".cshrc"s and the like. 590 */ 591 int insource; 592 static void 593 srcunit(unit, onlyown, hflg) 594 register int unit; 595 bool onlyown, hflg; 596 { 597 /* We have to push down a lot of state here */ 598 /* All this could go into a structure */ 599 int oSHIN = -1, oldintty = intty, oinsource = insource; 600 struct whyle *oldwhyl = whyles; 601 Char *ogointr = gointr, *oarginp = arginp; 602 Char *oevalp = evalp, **oevalvec = evalvec; 603 int oonelflg = onelflg; 604 bool oenterhist = enterhist; 605 char OHIST = HIST; 606 bool otell = cantell; 607 608 struct Bin saveB; 609 sigset_t omask; 610 jmp_buf oldexit; 611 612 /* The (few) real local variables */ 613 int my_reenter; 614 615 if (unit < 0) 616 return; 617 if (didfds) 618 donefds(); 619 if (onlyown) { 620 struct stat stb; 621 622 if (fstat(unit, &stb) < 0) { 623 (void) close(unit); 624 return; 625 } 626 } 627 628 /* 629 * There is a critical section here while we are pushing down the input 630 * stream since we have stuff in different structures. If we weren't 631 * careful an interrupt could corrupt SHIN's Bin structure and kill the 632 * shell. 633 * 634 * We could avoid the critical region by grouping all the stuff in a single 635 * structure and pointing at it to move it all at once. This is less 636 * efficient globally on many variable references however. 637 */ 638 insource = 1; 639 getexit(oldexit); 640 omask = 0; 641 642 if (setintr) 643 omask = sigblock(sigmask(SIGINT)); 644 /* Setup the new values of the state stuff saved above */ 645 bcopy((char *) &B, (char *) &(saveB), sizeof(B)); 646 fbuf = NULL; 647 fseekp = feobp = fblocks = 0; 648 oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; 649 intty = isatty(SHIN), whyles = 0, gointr = 0; 650 evalvec = 0; 651 evalp = 0; 652 enterhist = hflg; 653 if (enterhist) 654 HIST = '\0'; 655 656 /* 657 * Now if we are allowing commands to be interrupted, we let ourselves be 658 * interrupted. 659 */ 660 if (setintr) 661 (void) sigsetmask(omask); 662 settell(); 663 664 if ((my_reenter = setexit()) == 0) 665 process(0); /* 0 -> blow away on errors */ 666 667 if (setintr) 668 (void) sigsetmask(omask); 669 if (oSHIN >= 0) { 670 register int i; 671 672 /* We made it to the new state... free up its storage */ 673 /* This code could get run twice but xfree doesn't care */ 674 for (i = 0; i < fblocks; i++) 675 xfree((ptr_t) fbuf[i]); 676 xfree((ptr_t) fbuf); 677 678 /* Reset input arena */ 679 bcopy((char *) &(saveB), (char *) &B, sizeof(B)); 680 681 (void) close(SHIN), SHIN = oSHIN; 682 arginp = oarginp, onelflg = oonelflg; 683 evalp = oevalp, evalvec = oevalvec; 684 intty = oldintty, whyles = oldwhyl, gointr = ogointr; 685 if (enterhist) 686 HIST = OHIST; 687 enterhist = oenterhist; 688 cantell = otell; 689 } 690 691 resexit(oldexit); 692 /* 693 * If process reset() (effectively an unwind) then we must also unwind. 694 */ 695 if (my_reenter) 696 stderror(ERR_SILENT); 697 insource = oinsource; 698 } 699 700 void 701 rechist() 702 { 703 Char buf[BUFSIZ]; 704 int fp, ftmp, oldidfds; 705 706 if (!fast) { 707 if (value(STRsavehist)[0] == '\0') 708 return; 709 (void) Strcpy(buf, value(STRhome)); 710 (void) Strcat(buf, STRsldthist); 711 fp = creat(short2str(buf), 0600); 712 if (fp == -1) 713 return; 714 oldidfds = didfds; 715 didfds = 0; 716 ftmp = SHOUT; 717 SHOUT = fp; 718 (void) Strcpy(buf, value(STRsavehist)); 719 dumphist[2] = buf; 720 dohist(dumphist); 721 (void) close(fp); 722 SHOUT = ftmp; 723 didfds = oldidfds; 724 } 725 } 726 727 void 728 goodbye() 729 { 730 rechist(); 731 732 if (loginsh) { 733 (void) signal(SIGQUIT, SIG_IGN); 734 (void) signal(SIGINT, SIG_IGN); 735 (void) signal(SIGTERM, SIG_IGN); 736 setintr = 0; /* No interrupts after "logout" */ 737 if (!(adrof(STRlogout))) 738 set(STRlogout, STRnormal); 739 #ifdef _PATH_DOTLOGOUT 740 (void) srcfile(_PATH_DOTLOGOUT, 0, 0); 741 #endif 742 if (adrof(STRhome)) 743 (void) srccat(value(STRhome), STRsldtlogout); 744 } 745 exitstat(); 746 } 747 748 void 749 exitstat() 750 { 751 752 #ifdef PROF 753 monitor(0); 754 #endif 755 /* 756 * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit 757 * directly because we poke child here. Otherwise we might continue 758 * unwarrantedly (sic). 759 */ 760 child = 1; 761 xexit(getn(value(STRstatus))); 762 } 763 764 /* 765 * in the event of a HUP we want to save the history 766 */ 767 static void 768 phup(sig) 769 int sig; 770 { 771 rechist(); 772 xexit(sig); 773 } 774 775 Char *jobargv[2] = {STRjobs, 0}; 776 777 /* 778 * Catch an interrupt, e.g. during lexical input. 779 * If we are an interactive shell, we reset the interrupt catch 780 * immediately. In any case we drain the shell output, 781 * and finally go through the normal error mechanism, which 782 * gets a chance to make the shell go away. 783 */ 784 /* ARGSUSED */ 785 void 786 pintr(notused) 787 int notused; 788 { 789 pintr1(1); 790 } 791 792 void 793 pintr1(wantnl) 794 bool wantnl; 795 { 796 register Char **v; 797 sigset_t omask; 798 799 omask = sigblock((sigset_t) 0); 800 if (setintr) { 801 (void) sigsetmask(omask & ~sigmask(SIGINT)); 802 if (pjobs) { 803 pjobs = 0; 804 xprintf("\n"); 805 dojobs(jobargv); 806 stderror(ERR_NAME | ERR_INTR); 807 } 808 } 809 (void) sigsetmask(omask & ~sigmask(SIGCHLD)); 810 draino(); 811 (void) endpwent(); 812 813 /* 814 * If we have an active "onintr" then we search for the label. Note that if 815 * one does "onintr -" then we shan't be interruptible so we needn't worry 816 * about that here. 817 */ 818 if (gointr) { 819 search(T_GOTO, 0, gointr); 820 timflg = 0; 821 if (v = pargv) 822 pargv = 0, blkfree(v); 823 if (v = gargv) 824 gargv = 0, blkfree(v); 825 reset(); 826 } 827 else if (intty && wantnl) { 828 (void) putraw('\r'); 829 (void) putraw('\n'); 830 } 831 stderror(ERR_SILENT); 832 } 833 834 /* 835 * Process is the main driving routine for the shell. 836 * It runs all command processing, except for those within { ... } 837 * in expressions (which is run by a routine evalav in sh.exp.c which 838 * is a stripped down process), and `...` evaluation which is run 839 * also by a subset of this code in sh.glob.c in the routine backeval. 840 * 841 * The code here is a little strange because part of it is interruptible 842 * and hence freeing of structures appears to occur when none is necessary 843 * if this is ignored. 844 * 845 * Note that if catch is not set then we will unwind on any error. 846 * If an end-of-file occurs, we return. 847 */ 848 void 849 process(catch) 850 bool catch; 851 { 852 jmp_buf osetexit; 853 struct command *t; 854 855 getexit(osetexit); 856 for (;;) { 857 pendjob(); 858 paraml.next = paraml.prev = ¶ml; 859 paraml.word = STRNULL; 860 t = 0; 861 (void) setexit(); 862 justpr = enterhist; /* execute if not entering history */ 863 864 /* 865 * Interruptible during interactive reads 866 */ 867 if (setintr) 868 (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); 869 870 /* 871 * For the sake of reset() 872 */ 873 freelex(¶ml); 874 freesyn(t); 875 t = 0; 876 877 if (haderr) { 878 if (!catch) { 879 /* unwind */ 880 doneinp = 0; 881 resexit(osetexit); 882 reset(); 883 } 884 haderr = 0; 885 /* 886 * Every error is eventually caught here or the shell dies. It is 887 * at this point that we clean up any left-over open files, by 888 * closing all but a fixed number of pre-defined files. Thus 889 * routines don't have to worry about leaving files open due to 890 * deeper errors... they will get closed here. 891 */ 892 closem(); 893 continue; 894 } 895 if (doneinp) { 896 doneinp = 0; 897 break; 898 } 899 if (chkstop) 900 chkstop--; 901 if (neednote) 902 pnote(); 903 if (intty && prompt && evalvec == 0) { 904 mailchk(); 905 /* 906 * If we are at the end of the input buffer then we are going to 907 * read fresh stuff. Otherwise, we are rereading input and don't 908 * need or want to prompt. 909 */ 910 if (fseekp == feobp) 911 printprompt(); 912 flush(); 913 } 914 if (seterr) { 915 xfree((ptr_t) seterr); 916 seterr = NULL; 917 } 918 919 /* 920 * Echo not only on VERBOSE, but also with history expansion. If there 921 * is a lexical error then we forego history echo. 922 */ 923 if (lex(¶ml) && !seterr && intty || adrof(STRverbose)) { 924 haderr = 1; 925 prlex(¶ml); 926 haderr = 0; 927 } 928 929 /* 930 * The parser may lose space if interrupted. 931 */ 932 if (setintr) 933 (void) sigblock(sigmask(SIGINT)); 934 935 /* 936 * Save input text on the history list if reading in old history, or it 937 * is from the terminal at the top level and not in a loop. 938 * 939 * PWP: entry of items in the history list while in a while loop is done 940 * elsewhere... 941 */ 942 if (enterhist || catch && intty && !whyles) 943 savehist(¶ml); 944 945 /* 946 * Print lexical error messages, except when sourcing history lists. 947 */ 948 if (!enterhist && seterr) 949 stderror(ERR_OLD); 950 951 /* 952 * If had a history command :p modifier then this is as far as we 953 * should go 954 */ 955 if (justpr) 956 reset(); 957 958 alias(¶ml); 959 960 /* 961 * Parse the words of the input into a parse tree. 962 */ 963 t = syntax(paraml.next, ¶ml, 0); 964 if (seterr) 965 stderror(ERR_OLD); 966 967 execute(t, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); 968 969 /* 970 * Made it! 971 */ 972 freelex(¶ml); 973 freesyn(t); 974 } 975 resexit(osetexit); 976 } 977 978 void 979 dosource(t) 980 register Char **t; 981 { 982 register Char *f; 983 bool hflg = 0; 984 Char buf[BUFSIZ]; 985 986 t++; 987 if (*t && eq(*t, STRmh)) { 988 if (*++t == NULL) 989 stderror(ERR_NAME | ERR_HFLAG); 990 hflg++; 991 } 992 (void) Strcpy(buf, *t); 993 f = globone(buf, G_ERROR); 994 (void) strcpy((char *) buf, short2str(f)); 995 xfree((ptr_t) f); 996 if (!srcfile((char *) buf, 0, hflg) && !hflg) 997 stderror(ERR_SYSTEM, (char *) buf, strerror(errno)); 998 } 999 1000 /* 1001 * Check for mail. 1002 * If we are a login shell, then we don't want to tell 1003 * about any mail file unless its been modified 1004 * after the time we started. 1005 * This prevents us from telling the user things he already 1006 * knows, since the login program insists on saying 1007 * "You have mail." 1008 */ 1009 static void 1010 mailchk() 1011 { 1012 register struct varent *v; 1013 register Char **vp; 1014 time_t t; 1015 int intvl, cnt; 1016 struct stat stb; 1017 bool new; 1018 1019 v = adrof(STRmail); 1020 if (v == 0) 1021 return; 1022 (void) time(&t); 1023 vp = v->vec; 1024 cnt = blklen(vp); 1025 intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 1026 if (intvl < 1) 1027 intvl = 1; 1028 if (chktim + intvl > t) 1029 return; 1030 for (; *vp; vp++) { 1031 if (stat(short2str(*vp), &stb) < 0) 1032 continue; 1033 new = stb.st_mtime > time0.tv_sec; 1034 if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || 1035 (stb.st_atime < chktim && stb.st_mtime < chktim) || 1036 loginsh && !new) 1037 continue; 1038 if (cnt == 1) 1039 xprintf("You have %smail.\n", new ? "new " : ""); 1040 else 1041 xprintf("%s in %s.\n", new ? "New mail" : "Mail", short2str(*vp)); 1042 } 1043 chktim = t; 1044 } 1045 1046 /* 1047 * Extract a home directory from the password file 1048 * The argument points to a buffer where the name of the 1049 * user whose home directory is sought is currently. 1050 * We write the home directory of the user back there. 1051 */ 1052 int 1053 gethdir(home) 1054 Char *home; 1055 { 1056 Char *h; 1057 struct passwd *pw; 1058 1059 /* 1060 * Is it us? 1061 */ 1062 if (*home == '\0') { 1063 if (h = value(STRhome)) { 1064 (void) Strcpy(home, h); 1065 return 0; 1066 } 1067 else 1068 return 1; 1069 } 1070 1071 if (pw = getpwnam(short2str(home))) { 1072 (void) Strcpy(home, str2short(pw->pw_dir)); 1073 return 0; 1074 } 1075 else 1076 return 1; 1077 } 1078 1079 /* 1080 * Move the initial descriptors to their eventual 1081 * resting places, closin all other units. 1082 */ 1083 void 1084 initdesc() 1085 { 1086 1087 didfds = 0; /* 0, 1, 2 aren't set up */ 1088 (void) ioctl(SHIN = dcopy(0, FSHIN), FIOCLEX, NULL); 1089 (void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, NULL); 1090 (void) ioctl(SHDIAG = dcopy(2, FSHDIAG), FIOCLEX, NULL); 1091 (void) ioctl(OLDSTD = dcopy(SHIN, FOLDSTD), FIOCLEX, NULL); 1092 closem(); 1093 } 1094 1095 1096 void 1097 #ifdef PROF 1098 done(i) 1099 #else 1100 xexit(i) 1101 #endif 1102 int i; 1103 { 1104 untty(); 1105 _exit(i); 1106 } 1107 1108 static Char ** 1109 defaultpath() 1110 { 1111 char *ptr; 1112 Char **blk, **blkp; 1113 struct stat stb; 1114 1115 blkp = blk = (Char **) xmalloc((size_t) sizeof(Char *) * 10); 1116 1117 #define DIRAPPEND(a) \ 1118 if (stat(ptr = a, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) \ 1119 *blkp++ = SAVE(ptr) 1120 1121 DIRAPPEND(_PATH_BIN); 1122 DIRAPPEND(_PATH_USRBIN); 1123 1124 #undef DIRAPPEND 1125 1126 *blkp++ = Strsave(STRdot); 1127 *blkp = NULL; 1128 return (blk); 1129 } 1130 1131 void 1132 printprompt() 1133 { 1134 register Char *cp; 1135 1136 if (!whyles) { 1137 for (cp = value(STRprompt); *cp; cp++) 1138 if (*cp == HIST) 1139 xprintf("%d", eventno + 1); 1140 else { 1141 if (*cp == '\\' && cp[1] == HIST) 1142 cp++; 1143 xputchar(*cp | QUOTE); 1144 } 1145 } 1146 else 1147 /* 1148 * Prompt for forward reading loop body content. 1149 */ 1150 xprintf("? "); 1151 flush(); 1152 } 1153