1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.c,v 3.0 1991/07/04 23:34:26 christos Exp $ */ 2: /* 3: * sh.c: Main shell routines 4: */ 5: /*- 6: * Copyright (c) 1980, 1991 The Regents of the University of California. 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: */ 37: #include "config.h" 38: #if !defined(lint) && !defined(pdp11) 39: char copyright[] = 40: "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 41: All rights reserved.\n"; 42: #endif /* not lint */ 43: 44: #if !defined(lint) && !defined(pdp11) 45: static char *rcsid() 46: { return "$Id: sh.c,v 3.0 1991/07/04 23:34:26 christos Exp $"; } 47: #endif 48: 49: #include "sh.h" 50: #include "ed.h" 51: 52: extern bool MapsAreInited; 53: extern bool NLSMapsAreInited; 54: extern bool NoNLSRebind; 55: 56: /* 57: * C Shell 58: * 59: * Bill Joy, UC Berkeley, California, USA 60: * October 1978, May 1980 61: * 62: * Jim Kulp, IIASA, Laxenburg, Austria 63: * April 1980 64: * 65: * Filename recognition added: 66: * Ken Greer, Ind. Consultant, Palo Alto CA 67: * October 1983. 68: * 69: * Karl Kleinpaste, Computer Consoles, Inc. 70: * Added precmd, periodic/tperiod, prompt changes, 71: * directory stack hack, and login watch. 72: * Sometime March 1983 - Feb 1984. 73: * 74: * Added scheduled commands, including the "sched" command, 75: * plus the call to sched_run near the precmd et al 76: * routines. 77: * Upgraded scheduled events for running events while 78: * sitting idle at command input. 79: * 80: * Paul Placeway, Ohio State 81: * added stuff for running with twenex/inputl 9 Oct 1984. 82: * 83: * ported to Apple Unix (TM) (OREO) 26 -- 29 Jun 1987 84: */ 85: 86: #ifdef TESLA 87: static int do_logout; 88: #endif /* TESLA */ 89: 90: Char *dumphist[] = {STRhsto, STRmh, 0, 0}; 91: Char *loadhist[] = {STRsource, STRmh, STRhstf, 0}; 92: 93: #ifdef CSHDIRS 94: Char *loaddirs[] = {STRsource, STRdirfile, 0}; 95: bool dflag = 0; 96: #endif 97: 98: #if defined(convex) || defined(__convex__) 99: bool use_fork = 0; /* use fork() instead of vfork()? */ 100: #endif 101: 102: int nofile = 0; 103: bool reenter = 0; 104: bool nverbose = 0; 105: bool nexececho = 0; 106: bool quitit = 0; 107: bool fast = 0; 108: bool batch = 0; 109: bool mflag = 0; 110: bool prompt = 1; 111: bool enterhist = 0; 112: bool tellwhat = 0; 113: time_t t_period; 114: 115: extern char **environ; 116: 117: static int srccat __P((Char *, Char *)); 118: static int srcfile __P((char *, bool, bool)); 119: static sigret_t phup __P((int)); 120: static void srcunit __P((int, bool, bool)); 121: static void mailchk __P((void)); 122: static Char **d_path __P((void)); 123: 124: int 125: main(argc, argv) 126: int argc; 127: char **argv; 128: { 129: register Char *cp, *cp2; 130: register char *tcp, *ttyn; 131: register int f; 132: register char **tempv; 133: 134: #ifdef BSDSIGS 135: sigvec_t osv; 136: #endif /* BSDSIGS */ 137: 138: settimes(); /* Immed. estab. timing base */ 139: #ifdef TESLA 140: do_logout = 0; 141: #endif /* TESLA */ 142: 143: osinit(); /* Os dependent initialization */ 144: 145: /* 146: * Initialize non constant strings 147: */ 148: #ifdef _PATH_BSHELL 149: STR_BSHELL = SAVE(_PATH_BSHELL); 150: #endif 151: #ifdef _PATH_CSHELL 152: STR_SHELLPATH = SAVE(_PATH_CSHELL); 153: #endif 154: #ifdef _PATH_TCSHELL 155: STR_SHELLPATH = SAVE(_PATH_TCSHELL); 156: #endif 157: STR_environ = blk2short(environ); 158: environ = short2blk(STR_environ); /* So that we can free it */ 159: STR_WORD_CHARS = SAVE(WORD_CHARS); 160: 161: HIST = '!'; 162: HISTSUB = '^'; 163: word_chars = STR_WORD_CHARS; 164: bslash_quote = 0; /* PWP: do tcsh-style backslash quoting? */ 165: 166: tempv = argv; 167: if (eq(str2short(tempv[0]), STRaout)) /* A.out's are quittable */ 168: quitit = 1; 169: uid = getuid(); 170: gid = getgid(); 171: /* 172: * We are a login shell if: 1. we were invoked as -<something> and we had 173: * no arguments 2. or we were invoked only with the -l flag 174: */ 175: loginsh = (**tempv == '-' && argc == 1) || (argc == 2 && 176: tempv[1][0] == '-' && tempv[1][1] == 'l' && 177: tempv[1][2] == '\0'); 178: if (loginsh && **tempv != '-') { 179: /* 180: * Mangle the argv space 181: */ 182: tempv[1][0] = '\0'; 183: tempv[1][1] = '\0'; 184: tempv[1] = NULL; 185: for (tcp = *tempv; *tcp++;); 186: for (tcp--; tcp >= *tempv; tcp--) 187: tcp[1] = tcp[0]; 188: *++tcp = '-'; 189: argc--; 190: } 191: if (loginsh) 192: (void) time(&chktim); 193: 194: AsciiOnly = 1; 195: NoNLSRebind = getenv("NOREBIND") != NULL; 196: #ifdef NLS 197: (void) setlocale(LC_ALL, ""); 198: { 199: int k; 200: 201: for (k = 0200; k <= 0377 && !Isprint(k); k++); 202: AsciiOnly = k > 0377; 203: } 204: #else 205: AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL; 206: #endif /* NLS */ 207: if (MapsAreInited && !NLSMapsAreInited) 208: ed_INLSMaps(); 209: 210: /* 211: * Initialize for periodic command intervals. Also, initialize the dummy 212: * tty list for login-watch. 213: */ 214: (void) time(&t_period); 215: initwatch(); 216: 217: /* 218: * Move the descriptors to safe places. The variable didfds is 0 while we 219: * have only FSH* to work with. When didfds is true, we have 0,1,2 and 220: * prefer to use these. 221: */ 222: initdesc(); 223: 224: /* 225: * Get and set the tty now 226: */ 227: if (ttyn = ttyname(SHIN)) { 228: /* 229: * Could use rindex to get rid of other possible path components, but 230: * hpux preserves the subdirectory /pty/ when storing the tty name in 231: * utmp, so we keep it too. 232: */ 233: if (strncmp(ttyn, "/dev/", 5) == 0) 234: set(STRtty, cp = SAVE(ttyn + 5)); 235: else 236: set(STRtty, cp = SAVE(ttyn)); 237: } 238: else 239: set(STRtty, cp = SAVE("")); 240: /* 241: * Initialize the shell variables. ARGV and PROMPT are initialized later. 242: * STATUS is also munged in several places. CHILD is munged when 243: * forking/waiting 244: */ 245: 246: /* 247: * 7-10-87 Paul Placeway autologout should be set ONLY on login shells and 248: * on shells running as root. Out of these, autologout should NOT be set 249: * for any psudo-terminals (this catches most window systems) and not for 250: * any terminal running X windows. 251: * 252: * At Ohio State, we have had problems with a user having his X session drop 253: * out from under him (on a Sun) because the shell in his master xterm 254: * timed out and exited. 255: * 256: * Really, this should be done with a program external to the shell, that 257: * watches for no activity (and NO running programs, such as dump) on a 258: * terminal for a long peroid of time, and then SIGHUPS the shell on that 259: * terminal. 260: * 261: * bugfix by Rich Salz <rsalz@PINEAPPLE.BBN.COM>: For root rsh things allways 262: * first check to see if loginsh or really root, then do things with 263: * ttyname() 264: * 265: * Also by Jean-Francois Lamy <lamy%ai.toronto.edu@RELAY.CS.NET>: check the 266: * value of cp before using it! ("root can rsh too") 267: * 268: * PWP: keep the nested ifs; the order of the tests matters and a good (smart) 269: * C comp_r might re-arange things wrong. 270: */ 271: #ifdef AUTOLOGOUT 272: if (loginsh || (uid == 0)) { 273: if (*cp) { 274: /* only for login shells or root and we must have a tty */ 275: if ((cp2 = Strrchr(cp, (Char) '/')) != NULL) { 276: cp = cp2 + 1; 277: } 278: if (!((Strncmp(cp, STRtty, 3) == 0) && 279: (cp[3] >= 'p' && cp[3] <= 'u'))) { 280: if (getenv("DISPLAY") == NULL) { 281: /* NOT on X window shells */ 282: set(STRa_logout, Strsave(STRdflt_auto_logout)); 283: } 284: } 285: } 286: } 287: #endif /* AUTOLOGOUT */ 288: 289: (void) sigset(SIGALRM, alrmcatch); 290: 291: set(STRstatus, Strsave(STR0)); 292: fix_version(); /* publish the shell version */ 293: 294: /* 295: * set the shell-level var to 1 or increment it. 296: */ 297: if ((tcp = getenv("SHLVL")) != NULL) { 298: Char buff[BUFSIZ]; 299: 300: Itoa(1 + atoi(tcp), buff); 301: set(STRshlvl, Strsave(buff)); 302: Setenv(STRSHLVL, buff); 303: } 304: else { 305: set(STRshlvl, SAVE("1")); 306: Setenv(STRSHLVL, str2short("1")); 307: } 308: 309: if ((tcp = getenv("HOME")) != NULL) 310: cp = SAVE(tcp); 311: else 312: cp = NOSTR; 313: if (cp == NOSTR) 314: fast = 1; /* No home -> can't read scripts */ 315: else 316: set(STRhome, cp); 317: dinit(cp); /* dinit thinks that HOME == cwd in a login 318: * shell */ 319: /* 320: * Grab other useful things from the environment. Should we grab 321: * everything?? 322: */ 323: if ((tcp = getenv("LOGNAME")) != NULL || (tcp = getenv("USER")) != NULL) 324: set(STRuser, SAVE(tcp)); 325: if ((tcp = getenv("TERM")) != NULL) 326: set(STRterm, SAVE(tcp)); 327: 328: /* 329: * set usefull environment things for the user 330: */ 331: { 332: 333: Char buff[BUFSIZ]; 334: 335: #ifdef apollo 336: int oid = getoid(); 337: 338: Itoa(oid, buff); 339: set(STRoid, Strsave(buff)); 340: #endif /* apollo */ 341: Itoa(uid, buff); 342: set(STRuid, Strsave(buff)); 343: 344: Itoa(gid, buff); 345: set(STRgid, Strsave(buff)); 346: } 347: 348: /* 349: * HOST may be wrong, since rexd transports the entire environment on sun 350: * 3.x Just set it again 351: */ 352: { 353: char cbuff[MAXHOSTNAMELEN]; 354: 355: if (gethostname(cbuff, sizeof(cbuff)) >= 0) { 356: cbuff[sizeof(cbuff) - 1] = '\0'; /* just in case */ 357: Setenv(STRHST, str2short(cbuff)); 358: } 359: else 360: Setenv(STRHST, str2short("unknown")); 361: } 362: 363: 364: /* 365: * HOSTTYPE, too. Just set it again. 366: */ 367: Setenv(STRHSTTYPE, GetHostType()); 368: #ifdef apollo 369: if ((tcp = getenv("SYSTYPE")) == NULL) 370: tcp = "bsd4.3"; 371: Setenv(STRSYSTYPE, str2short(tcp)); 372: #endif /* apollo */ 373: 374: /* 375: * set editing on by default, unless running under Emacs as an inferior 376: * shell. 377: */ 378: if ((tcp = getenv("EMACS")) == NULL || strcmp(tcp, "t") != 0) { 379: /* not running under Emacs */ 380: /* The 'edit' variable is either set or unset. It doesn't */ 381: /* need a value. Making it 'emacs' might be confusing. */ 382: set(STRedit, Strsave(STRNULL)); 383: editing = 1; 384: } 385: else { /* running under Emacs */ 386: /* we don't set edit to anything */ 387: editing = 0; 388: } 389: 390: 391: /* 392: * still more mutability: make the complete routine automatically add the 393: * suffix of file names... 394: */ 395: set(STRaddsuffix, Strsave(STRNULL)); 396: 397: /* 398: * Re-initialize path if set in environment 399: */ 400: if ((tcp = getenv("PATH")) == NULL) 401: set1(STRpath, d_path(), &shvhed); 402: else 403: importpath(SAVE(tcp)); 404: 405: set(STRshell, Strsave(STR_SHELLPATH)); 406: 407: doldol = putn((int) getpid()); /* For $$ */ 408: shtemp = Strspl(STRtmpsh, doldol); /* For << */ 409: 410: /* 411: * Record the interrupt states from the parent process. If the parent is 412: * non-interruptible our hand must be forced or we (and our children) won't 413: * be either. Our children inherit termination from our parent. We catch it 414: * only if we are the login shell. 415: */ 416: #ifdef BSDSIGS 417: /* parents interruptibility */ 418: (void) mysigvec(SIGINT, NULL, &osv); 419: parintr = (sigret_t(*) ()) osv.sv_handler; 420: (void) mysigvec(SIGTERM, NULL, &osv); 421: parterm = (sigret_t(*) ()) osv.sv_handler; 422: #else /* BSDSIGS */ 423: parintr = signal(SIGINT, SIG_IGN); /* parents interruptibility */ 424: (void) sigset(SIGINT, parintr); /* ... restore */ 425: parterm = signal(SIGTERM, SIG_IGN); /* parents terminability */ 426: (void) sigset(SIGTERM, parterm); /* ... restore */ 427: #endif /* BSDSIGS */ 428: 429: if (loginsh) { 430: (void) signal(SIGHUP, phup); /* exit processing on HUP */ 431: #ifdef SIGXCPU 432: (void) signal(SIGXCPU, phup); /* ...and on XCPU */ 433: #endif /* SIGXCPU */ 434: #ifdef SIGXFSZ 435: (void) signal(SIGXFSZ, phup); /* ...and on XFSZ */ 436: #endif /* SIGXFSZ */ 437: } 438: 439: #ifdef TCF 440: /* Enable process migration on ourselves and our progeny */ 441: (void) signal(SIGMIGRATE, SIG_DFL); 442: #endif /* TCF */ 443: 444: /* 445: * Process the arguments. 446: * 447: * Note that processing of -v/-x is actually delayed till after script 448: * processing. 449: * 450: * We set the first character of our name to be '-' if we are a shell running 451: * interruptible commands. Many programs which examine ps'es use this to 452: * filter such shells out. 453: */ 454: argc--, tempv++; 455: while (argc > 0 && (tcp = tempv[0])[0] == '-' && 456: *++tcp != '\0' && !batch) { 457: do 458: switch (*tcp++) { 459: 460: case 0: /* - Interruptible, no prompt */ 461: prompt = 0; 462: setintr = 1; 463: nofile = 1; 464: break; 465: 466: case 'b': /* -b Next arg is input file */ 467: batch = 1; 468: break; 469: 470: case 'c': /* -c Command input from arg */ 471: if (argc == 1) 472: xexit(0); 473: argc--, tempv++; 474: arginp = SAVE(tempv[0]); 475: /* 476: * * Give an error on -c arguments that end in * backslash to 477: * ensure that you don't make * nonportable csh scripts. 478: */ 479: { 480: register Char *cp; 481: register int count; 482: 483: cp = arginp + Strlen(arginp); 484: count = 0; 485: while (cp > arginp && *--cp == '\\') 486: ++count; 487: if ((count & 1) != 0) { 488: exiterr = 1; 489: stderror(ERR_ARGC); 490: } 491: } 492: prompt = 0; 493: nofile = 1; 494: break; 495: 496: #ifdef CSHDIRS 497: case 'd': /* -d Force load of ~/.cshdirs */ 498: dflag++; 499: break; 500: #endif 501: 502: 503: case 'e': /* -e Exit on any error */ 504: exiterr = 1; 505: break; 506: 507: case 'f': /* -f Fast start */ 508: fast = 1; 509: break; 510: 511: case 'i': /* -i Interactive, even if !intty */ 512: intact = 1; 513: nofile = 1; 514: break; 515: 516: case 'm': /* -m read .cshrc (from su) */ 517: mflag = 1; 518: break; 519: 520: case 'n': /* -n Don't execute */ 521: noexec = 1; 522: break; 523: 524: case 'q': /* -q (Undoc'd) ... die on quit */ 525: quitit = 1; 526: break; 527: 528: case 's': /* -s Read from std input */ 529: nofile = 1; 530: break; 531: 532: case 't': /* -t Read one line from input */ 533: onelflg = 2; 534: prompt = 0; 535: nofile = 1; 536: break; 537: 538: case 'v': /* -v Echo hist expanded input */ 539: nverbose = 1; /* ... later */ 540: break; 541: 542: case 'x': /* -x Echo just before execution */ 543: nexececho = 1; /* ... later */ 544: break; 545: 546: case 'V': /* -V Echo hist expanded input */ 547: setNS(STRverbose); /* NOW! */ 548: break; 549: 550: case 'X': /* -X Echo just before execution */ 551: setNS(STRecho); /* NOW! */ 552: break; 553: 554: #if defined(__convex__) || defined(convex) 555: case 'F': /* Undocumented flag */ 556: /* 557: * This will cause children to be created using fork instead of 558: * vfork. 559: */ 560: use_fork = 1; 561: break; 562: #endif 563: 564: } while (*tcp); 565: tempv++, argc--; 566: } 567: 568: if (quitit) /* With all due haste, for debugging */ 569: (void) signal(SIGQUIT, SIG_DFL); 570: 571: /* 572: * Unless prevented by -, -c, -i, -s, or -t, if there are remaining 573: * arguments the first of them is the name of a shell file from which to 574: * read commands. 575: */ 576: if (nofile == 0 && argc > 0) { 577: nofile = open(tempv[0], O_RDONLY); 578: if (nofile < 0) { 579: child = 1; /* So this ... */ 580: /* ... doesn't return */ 581: stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 582: } 583: ffile = SAVE(tempv[0]); 584: /* 585: * Replace FSHIN. Handle /dev/std{in,out,err} specially 586: * since once they are closed we cannot open them again. 587: * In that case we use our own saved descriptors 588: */ 589: if ((SHIN = dmove(nofile, FSHIN)) < 0) 590: switch(nofile) { 591: case 0: 592: SHIN = FSHIN; 593: break; 594: case 1: 595: SHIN = FSHOUT; 596: break; 597: case 2: 598: SHIN = FSHDIAG; 599: break; 600: default: 601: stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 602: break; 603: } 604: #ifdef FIOCLEX 605: (void) ioctl(SHIN, FIOCLEX, NULL); 606: #endif 607: prompt = 0; 608: /* argc not used any more */ tempv++; 609: } 610: /* 611: * Consider input a tty if it really is or we are interactive. but not for 612: * editing (christos) 613: */ 614: if (!(intty = isatty(SHIN))) { 615: if (adrof(STRedit)) 616: unsetv(STRedit); 617: editing = 0; 618: } 619: intty |= intact; 620: if (intty || (intact && isatty(SHOUT))) { 621: if (!batch && (uid != geteuid() || gid != getegid())) { 622: errno = EACCES; 623: child = 1; /* So this ... */ 624: /* ... doesn't return */ 625: stderror(ERR_SYSTEM, "tcsh", strerror(errno)); 626: } 627: } 628: isoutatty = isatty(SHOUT); 629: isdiagatty = isatty(SHDIAG); 630: /* 631: * Decide whether we should play with signals or not. If we are explicitly 632: * told (via -i, or -) or we are a login shell (arg0 starts with -) or the 633: * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 634: * Note that in only the login shell is it likely that parent may have set 635: * signals to be ignored 636: */ 637: if (loginsh || intact || intty && isatty(SHOUT)) 638: setintr = 1; 639: settell(); 640: /* 641: * Save the remaining arguments in argv. 642: */ 643: setq(STRargv, blk2short(tempv), &shvhed); 644: 645: /* 646: * Set up the prompt. 647: */ 648: if (prompt) { 649: set(STRprompt, Strsave(uid == 0 ? STRsymhash : STRsymarrow)); 650: /* that's a meta-questionmark */ 651: set(STRp_2, Strsave(STRmquestion)); 652: set(STRp_3, Strsave(STRCORRECT)); 653: } 654: 655: /* 656: * If we are an interactive shell, then start fiddling with the signals; 657: * this is a tricky game. 658: */ 659: shpgrp = mygetpgrp(); 660: opgrp = tpgrp = -1; 661: if (setintr) { 662: **argv = '-'; 663: if (!quitit) /* Wary! */ 664: (void) signal(SIGQUIT, SIG_IGN); 665: (void) sigset(SIGINT, pintr); 666: (void) sighold(SIGINT); 667: (void) signal(SIGTERM, SIG_IGN); 668: if (quitit == 0 && arginp == 0) { 669: #ifdef SIGTSTP 670: (void) signal(SIGTSTP, SIG_IGN); 671: #endif 672: #ifdef SIGTTIN 673: (void) signal(SIGTTIN, SIG_IGN); 674: #endif 675: #ifdef SIGTTOU 676: (void) signal(SIGTTOU, SIG_IGN); 677: #endif 678: /* 679: * Wait till in foreground, in case someone stupidly runs csh & 680: * dont want to try to grab away the tty. 681: */ 682: if (isatty(FSHDIAG)) 683: f = FSHDIAG; 684: else if (isatty(FSHOUT)) 685: f = FSHOUT; 686: else if (isatty(OLDSTD)) 687: f = OLDSTD; 688: else 689: f = -1; 690: 691: retry: 692: #ifdef BSDJOBS /* if we have tty job control */ 693: if ((tpgrp = tcgetpgrp(f)) != -1) { 694: if (tpgrp != shpgrp) { 695: sigret_t(*old) () = signal(SIGTTIN, SIG_DFL); 696: (void) kill(0, SIGTTIN); 697: (void) signal(SIGTTIN, old); 698: goto retry; 699: } 700: /* 701: * Thanks to Matt Day for the POSIX references, and to 702: * Paul Close for the SGI clarification. 703: */ 704: if (setdisc(f) != -1) { 705: opgrp = shpgrp; 706: shpgrp = getpid(); 707: tpgrp = shpgrp; 708: if (tcsetpgrp(f, shpgrp) == -1) { 709: /* 710: * On hpux 7.03 this fails with EPERM. This happens on 711: * the 800 when opgrp != shpgrp at this point. (we were 712: * forked from a non job control shell) 713: * POSIX 7.2.4, says we failed because the process 714: * group specified did not belong to a process 715: * in the same session with the tty. So we set our 716: * process group and try again. 717: */ 718: if (setpgid(0, shpgrp) == -1) { 719: xprintf("setpgid:"); 720: goto notty; 721: } 722: if (tcsetpgrp(f, shpgrp) == -1) { 723: xprintf("tcsetpgrp:"); 724: goto notty; 725: } 726: } 727: /* 728: * We check the process group now. If it is the same, then 729: * we don't need to set it again. On hpux 7.0 on the 300's 730: * if we set it again it fails with EPERM. This is the 731: * correct behavior according to POSIX 4.3.3 if the process 732: * was a session leader . 733: */ 734: else if (shpgrp != mygetpgrp()) { 735: if(setpgid(0, shpgrp) == -1) { 736: xprintf("setpgid:"); 737: goto notty; 738: } 739: } 740: #ifdef IRIS4D 741: /* 742: * But on irix 3.3 we need to set it again, even if it is 743: * the same. We do that to tell the system that we 744: * need BSD process group compatibility. 745: */ 746: else 747: (void) setpgid(0, shpgrp); 748: #endif 749: #ifdef FIOCLEX 750: (void) ioctl(dcopy(f, FSHTTY), FIOCLEX, NULL); 751: #else /* FIOCLEX */ 752: (void) dcopy(f, FSHTTY); 753: #endif /* FIOCLEX */ 754: } 755: else 756: tpgrp = -1; 757: } 758: if (tpgrp == -1) { 759: notty: 760: xprintf("Warning: no access to tty (%s).\n", strerror(errno)); 761: xprintf("Thus no job control in this shell.\n"); 762: /* 763: * Fix from:Sakari Jalovaara <sja@sirius.hut.fi> if we don't 764: * have access to tty, disable editing too 765: */ 766: if (adrof(STRedit)) 767: unsetv(STRedit); 768: editing = 0; 769: } 770: #else /* BSDJOBS */ /* don't have job control, so frotz it */ 771: tpgrp = -1; 772: #endif /* BSDJOBS */ 773: } 774: } 775: if ((setintr == 0) && (parintr == SIG_DFL)) 776: setintr = 1; 777: (void) sigset(SIGCHLD, pchild); /* while signals not ready */ 778: 779: /* 780: * Set an exit here in case of an interrupt or error reading the shell 781: * start-up scripts. 782: */ 783: reenter = setexit(); /* PWP */ 784: haderr = 0; /* In case second time through */ 785: if (!fast && reenter == 0) { 786: /* Will have value(STRhome) here because set fast if don't */ 787: { 788: int osetintr = setintr; 789: 790: #ifdef BSDSIGS 791: sigmask_t omask = sigblock(sigmask(SIGINT)); 792: #else 793: sighold(SIGINT); 794: #endif 795: setintr = 0; 796: #ifdef _PATH_DOTCSHRC 797: (void) srcfile(_PATH_DOTCSHRC, 0, 0); 798: #endif 799: if (!fast && !arginp && !onelflg) 800: dohash(); 801: #ifdef _PATH_DOTLOGIN 802: if (loginsh) 803: (void) srcfile(_PATH_DOTLOGIN, 0, 0); 804: #endif 805: #ifdef BSDSIGS 806: (void) sigsetmask(omask); 807: #else 808: (void) sigrelse(SIGINT); 809: #endif 810: setintr = osetintr; 811: } 812: #ifdef LOGINFIRST 813: if (loginsh) 814: (void) srccat(value(STRhome), STRd_login); 815: #endif 816: /* upward compat. */ 817: if (!srccat(value(STRhome), STRd_tcshrc)) 818: (void) srccat(value(STRhome), STRd_cshrc); 819: 820: if (!fast && !arginp && !onelflg && !havhash) 821: dohash(); 822: /* 823: * Source history before .login so that it is available in .login 824: */ 825: dosource(loadhist); 826: #ifndef LOGINFIRST 827: if (loginsh) 828: (void) srccat(value(STRhome), STRd_login); 829: #endif 830: #ifdef CSHDIRS 831: /* 832: * if dflag then source ~/.cshdirs, but if fast ALWAYS skip the dirs 833: * restoring. (dflag used to get non-login shells to source the save 834: * dirs file). Of course, ~/.cshdirs must exist. -strike 835: */ 836: { 837: extern int bequiet; /* make dirs shut up */ 838: Char cshd[BUFSIZ]; 839: struct stat st; 840: 841: (void) Strcpy(cshd, value(STRhome)); 842: (void) Strcat(cshd, STRs_dirs); 843: if (!stat(short2str(cshd), &st) && 844: (dflag || loginsh) && !fast) { 845: bequiet = 1; 846: dosource(loaddirs); 847: bequiet = 0; 848: } 849: } 850: #endif 851: } 852: /* Initing AFTER .cshrc is the Right Way */ 853: if (intty && !arginp) { /* PWP setup stuff */ 854: ed_I(); /* init the new line editor */ 855: #ifdef SIG_WINDOW 856: check_window_size(1); /* mung environment */ 857: #endif /* SIG_WINDOW */ 858: } 859: 860: /* 861: * Now are ready for the -v and -x flags 862: */ 863: if (nverbose) 864: setNS(STRverbose); 865: if (nexececho) 866: setNS(STRecho); 867: /* 868: * All the rest of the world is inside this call. The argument to process 869: * indicates whether it should catch "error unwinds". Thus if we are a 870: * interactive shell our call here will never return by being blown past on 871: * an error. 872: */ 873: process(setintr); 874: 875: /* 876: * Mop-up. 877: */ 878: if (intty) { 879: if (loginsh) { 880: xprintf("logout\n"); 881: (void) close(SHIN); 882: child = 1; 883: #ifdef TESLA 884: do_logout = 1; 885: #endif /* TESLA */ 886: goodbye(); 887: } 888: else { 889: xprintf("exit\n"); 890: } 891: } 892: #ifdef CSHDIRS 893: /* 894: * save the directory stack -strike 895: */ 896: recdirs(); 897: #endif 898: rechist(); 899: exitstat(); 900: return (0); 901: } 902: 903: void 904: untty() 905: { 906: #ifdef BSDJOBS 907: if (tpgrp > 0) { 908: (void) setpgid(0, opgrp); 909: (void) tcsetpgrp(FSHTTY, opgrp); 910: (void) resetdisc(FSHTTY); 911: } 912: #endif /* BSDJOBS */ 913: } 914: 915: void 916: importpath(cp) 917: Char *cp; 918: { 919: register int i = 0; 920: register Char *dp; 921: register Char **pv; 922: int c; 923: 924: for (dp = cp; *dp; dp++) 925: if (*dp == ':') 926: i++; 927: /* 928: * i+2 where i is the number of colons in the path. There are i+1 929: * directories in the path plus we need room for a zero terminator. 930: */ 931: pv = (Char **) xcalloc((size_t) (i + 2), sizeof(Char **)); 932: dp = cp; 933: i = 0; 934: if (*dp) 935: for (;;) { 936: if ((c = *dp) == ':' || c == 0) { 937: *dp = 0; 938: pv[i++] = Strsave(*cp ? cp : STRdot); 939: if (c) { 940: cp = dp + 1; 941: *dp = ':'; 942: } 943: else 944: break; 945: } 946: dp++; 947: } 948: pv[i] = 0; 949: set1(STRpath, pv, &shvhed); 950: } 951: 952: /* 953: * Source to the file which is the catenation of the argument names. 954: */ 955: static int 956: srccat(cp, dp) 957: Char *cp, *dp; 958: { 959: if (cp[0] == '/' && cp[1] == '\0') 960: return srcfile(short2str(dp), mflag ? 0 : 1, 0); 961: else { 962: register Char *ep = Strspl(cp, dp); 963: char *ptr = short2str(ep); 964: 965: xfree((ptr_t) ep); 966: return srcfile(ptr, mflag ? 0 : 1, 0); 967: } 968: } 969: 970: /* 971: * Source to a file putting the file descriptor in a safe place (> 2). 972: */ 973: static int 974: srcfile(f, onlyown, flag) 975: char *f; 976: bool onlyown, flag; 977: { 978: register int unit; 979: 980: if ((unit = open(f, O_RDONLY)) == -1) 981: return 0; 982: unit = dmove(unit, -1); 983: 984: #ifdef FIOCLEX 985: (void) ioctl(unit, FIOCLEX, NULL); 986: #endif 987: srcunit(unit, onlyown, flag); 988: return 1; 989: } 990: 991: /* 992: * Source to a unit. If onlyown it must be our file or our group or 993: * we don't chance it. This occurs on ".cshrc"s and the like. 994: */ 995: int insource; 996: static void 997: srcunit(unit, onlyown, hflg) 998: register int unit; 999: bool onlyown, hflg; 1000: { 1001: /* 1002: * PWP: this is arranged like this so that an optimizing comp_r won't go 1003: * and put things like oSHIN in a register that longjmp() restores. The 1004: * problem is that on my Sun 3/50, gcc will put oSHIN in a register. That 1005: * would be OK, but setjmp() saves ALL of the registers and longjmp() 1006: * restores ALL of them, thus if you do a setjmp(), set oSHIN to something 1007: * (like SHIN), then do a longjmp(), the value of oSHIN will magically 1008: * become -1 again. 1009: * 1010: * Perhaps setjmp() should only save the stack pointer, frame pointer, and 1011: * program counter... 1012: */ 1013: 1014: /* We have to push down a lot of state here */ 1015: /* All this could go into a structure */ 1016: int oSHIN = -1, oldintty = intty, oinsource = insource; 1017: struct whyle *oldwhyl = whyles; 1018: Char *ogointr = gointr, *oarginp = arginp; 1019: Char *oevalp = evalp, **oevalvec = evalvec; 1020: int oonelflg = onelflg; 1021: bool oenterhist = enterhist; 1022: char OHIST = HIST; 1023: bool otell = cantell; 1024: struct Bin saveB; 1025: #ifdef BSDSIGS 1026: volatile sigmask_t omask = (sigmask_t) 0; 1027: #endif 1028: jmp_buf oldexit; 1029: 1030: /* The (few) real local variables */ 1031: int my_reenter; 1032: 1033: if (unit < 0) 1034: return; 1035: if (didfds) 1036: donefds(); 1037: if (onlyown) { 1038: struct stat stb; 1039: 1040: if (fstat(unit, &stb) < 0 1041: /* || (stb.st_uid != uid && stb.st_gid != gid) */ 1042: ) { 1043: (void) close(unit); 1044: return; 1045: } 1046: } 1047: 1048: /* 1049: * There is a critical section here while we are pushing down the input 1050: * stream since we have stuff in different structures. If we weren't 1051: * careful an interrupt could corrupt SHIN's Bin structure and kill the 1052: * shell. 1053: * 1054: * We could avoid the critical region by grouping all the stuff in a single 1055: * structure and pointing at it to move it all at once. This is less 1056: * efficient globally on many variable references however. 1057: */ 1058: insource = 1; 1059: getexit(oldexit); 1060: 1061: if (setintr) 1062: #ifdef BSDSIGS 1063: omask = sigblock(sigmask(SIGINT)); 1064: #else 1065: (void) sighold(SIGINT); 1066: #endif 1067: /* 1068: * Bugfix for running out of memory by: Jak Kirman 1069: * <jak%cs.brown.edu@RELAY.CS.NET>. Solution: pay attention to what 1070: * setexit() is returning because my_reenter _may_ be in a register, and 1071: * thus restored to 0 on a longjump(). (PWP: insert flames about 1072: * comp_r-dependant code here) PWP: THANKS LOTS !!! 1073: */ 1074: /* Setup the new values of the state stuff saved above */ 1075: copy((char *) &(saveB), (char *) &B, sizeof(B)); 1076: fbuf = NULL; 1077: fseekp = feobp = fblocks = 0; 1078: oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; 1079: intty = isatty(SHIN), whyles = 0, gointr = 0; 1080: evalvec = 0; 1081: evalp = 0; 1082: enterhist = hflg; 1083: if (enterhist) 1084: HIST = '\0'; 1085: 1086: /* 1087: * Now if we are allowing commands to be interrupted, we let ourselves be 1088: * interrupted. 1089: */ 1090: if (setintr) 1091: #ifdef BSDSIGS 1092: (void) sigsetmask(omask); 1093: #else 1094: (void) sigrelse(SIGINT); 1095: #endif 1096: settell(); 1097: 1098: /* PWP: think of this as like a LISP (unwind-protect ...) */ 1099: /* thanks to Diana Smetters for pointing out how this _should_ be written */ 1100: if ((my_reenter = setexit()) == 0) { 1101: process(0); /* 0 -> blow away on errors */ 1102: } 1103: 1104: if (setintr) 1105: #ifdef BSDSIGS 1106: (void) sigsetmask(omask); 1107: #else 1108: (void) sigrelse(SIGINT); 1109: #endif 1110: if (oSHIN >= 0) { 1111: register int i; 1112: 1113: /* We made it to the new state... free up its storage */ 1114: /* This code could get run twice but xfree doesn't care */ 1115: for (i = 0; i < fblocks; i++) 1116: xfree((ptr_t) fbuf[i]); 1117: xfree((ptr_t) fbuf); 1118: 1119: /* Reset input arena */ 1120: copy((char *) &B, (char *) &(saveB), sizeof(B)); 1121: 1122: (void) close(SHIN), SHIN = oSHIN; 1123: arginp = oarginp, onelflg = oonelflg; 1124: evalp = oevalp, evalvec = oevalvec; 1125: intty = oldintty, whyles = oldwhyl, gointr = ogointr; 1126: if (enterhist) 1127: HIST = OHIST; 1128: enterhist = oenterhist; 1129: cantell = otell; 1130: } 1131: 1132: resexit(oldexit); 1133: /* 1134: * If process reset() (effectively an unwind) then we must also unwind. 1135: */ 1136: if (my_reenter) 1137: stderror(ERR_SILENT); 1138: insource = oinsource; 1139: } 1140: 1141: void 1142: rechist() 1143: { 1144: Char buf[BUFSIZ]; 1145: int fp, ftmp, oldidfds; 1146: 1147: if (!fast) { 1148: if (value(STRsvhist)[0] == '\0') 1149: return; 1150: (void) Strcpy(buf, value(STRhome)); 1151: (void) Strcat(buf, STRs_hist); 1152: fp = creat(short2str(buf), 0600); 1153: if (fp == -1) 1154: return; 1155: oldidfds = didfds; 1156: didfds = 0; 1157: ftmp = SHOUT; 1158: SHOUT = fp; 1159: (void) Strcpy(buf, value(STRsvhist)); 1160: dumphist[2] = buf; 1161: dohist(dumphist); 1162: (void) close(fp); 1163: SHOUT = ftmp; 1164: didfds = oldidfds; 1165: } 1166: } 1167: 1168: void 1169: goodbye() 1170: { 1171: rechist(); 1172: 1173: #ifdef CSHDIRS 1174: recdirs(); 1175: #endif 1176: 1177: if (loginsh) { 1178: (void) signal(SIGQUIT, SIG_IGN); 1179: (void) sigset(SIGINT, SIG_IGN); 1180: (void) signal(SIGTERM, SIG_IGN); 1181: setintr = 0; /* No interrupts after "logout" */ 1182: if (!(adrof(STRlogout))) 1183: set(STRlogout, STRnormal); 1184: #ifdef _PATH_DOTLOGOUT 1185: (void) srcfile(_PATH_DOTLOGOUT, 0, 0); 1186: #endif 1187: if (adrof(STRhome)) 1188: (void) srccat(value(STRhome), STRs_logout); 1189: #ifdef TESLA 1190: do_logout = 1; 1191: #endif /* TESLA */ 1192: } 1193: exitstat(); 1194: } 1195: 1196: void 1197: exitstat() 1198: { 1199: 1200: #ifdef PROF 1201: monitor(0); 1202: #endif 1203: /* 1204: * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit 1205: * directly because we poke child here. Otherwise we might continue 1206: * unwarrantedly (sic). 1207: */ 1208: child = 1; 1209: xexit(getn(value(STRstatus))); 1210: } 1211: 1212: /* 1213: * in the event of a HUP we want to save the history 1214: */ 1215: static sigret_t 1216: phup(i) 1217: int i; 1218: { 1219: rechist(); 1220: #ifdef CSHDIRS 1221: /* 1222: * save the directory stack on HUP - strike 1223: */ 1224: recdirs(); 1225: #endif 1226: xexit(i); 1227: #ifndef SIGVOID 1228: return (i); 1229: #endif 1230: } 1231: 1232: Char *jobargv[2] = {STRjobs, 0}; 1233: 1234: /* 1235: * Catch an interrupt, e.g. during lexical input. 1236: * If we are an interactive shell, we reset the interrupt catch 1237: * immediately. In any case we drain the shell output, 1238: * and finally go through the normal error mechanism, which 1239: * gets a chance to make the shell go away. 1240: */ 1241: int just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ 1242: 1243: sigret_t 1244: pintr(i) 1245: int i; 1246: { 1247: just_signaled = 1; 1248: pintr1(1); 1249: #ifndef SIGVOID 1250: return (i); 1251: #endif 1252: } 1253: 1254: void 1255: pintr1(wantnl) 1256: bool wantnl; 1257: { 1258: register Char **v; 1259: #ifdef BSDSIGS 1260: sigmask_t omask; 1261: #endif 1262: 1263: #ifdef BSDSIGS 1264: omask = sigblock((sigmask_t) 0); 1265: #endif 1266: if (setintr) { 1267: #ifdef BSDSIGS 1268: (void) sigsetmask(omask & ~sigmask(SIGINT)); 1269: #else 1270: (void) sigrelse(SIGINT); 1271: #endif 1272: if (pjobs) { 1273: pjobs = 0; 1274: xprintf("\n"); 1275: dojobs(jobargv); 1276: stderror(ERR_NAME | ERR_INTR); 1277: } 1278: } 1279: /* JV - Make sure we shut off inputl */ 1280: { 1281: extern Char GettingInput; 1282: 1283: (void) Cookedmode(); 1284: GettingInput = 0; 1285: } 1286: #ifdef BSDSIGS 1287: (void) sigsetmask(omask & ~sigmask(SIGCHLD)); 1288: #else 1289: if (setintr) 1290: (void) sighold(SIGINT); 1291: (void) sigrelse(SIGCHLD); 1292: #endif 1293: draino(); 1294: (void) endpwent(); 1295: 1296: /* 1297: * If we have an active "onintr" then we search for the label. Note that if 1298: * one does "onintr -" then we shan't be interruptible so we needn't worry 1299: * about that here. 1300: */ 1301: if (gointr) { 1302: search(T_GOTO, 0, gointr); 1303: timflg = 0; 1304: if (v = pargv) 1305: pargv = 0, blkfree(v); 1306: if (v = gargv) 1307: gargv = 0, blkfree(v); 1308: reset(); 1309: } 1310: else if (intty && wantnl) { 1311: /* xprintf("\n"); *//* Some like this, others don't */ 1312: (void) putraw('\r'); 1313: (void) putraw('\n'); 1314: } 1315: stderror(ERR_SILENT); 1316: } 1317: 1318: /* 1319: * Process is the main driving routine for the shell. 1320: * It runs all command processing, except for those within { ... } 1321: * in expressions (which is run by a routine evalav in sh.exp.c which 1322: * is a stripped down process), and `...` evaluation which is run 1323: * also by a subset of this code in sh.glob.c in the routine backeval. 1324: * 1325: * The code here is a little strange because part of it is interruptible 1326: * and hence freeing of structures appears to occur when none is necessary 1327: * if this is ignored. 1328: * 1329: * Note that if catch is not set then we will unwind on any error. 1330: * If an end-of-file occurs, we return. 1331: */ 1332: struct command *savet = NULL; 1333: void 1334: process(catch) 1335: bool catch; 1336: { 1337: extern char Expand; 1338: jmp_buf osetexit; 1339: /* PWP: This might get nuked my longjmp so don't make it a register var */ 1340: struct command *t = savet; 1341: 1342: savet = NULL; 1343: getexit(osetexit); 1344: for (;;) { 1345: 1346: pendjob(); 1347: paraml.next = paraml.prev = ¶ml; 1348: paraml.word = STRNULL; 1349: (void) setexit(); 1350: justpr = enterhist; /* execute if not entering history */ 1351: 1352: /* 1353: * Interruptible during interactive reads 1354: */ 1355: if (setintr) 1356: #ifdef BSDSIGS 1357: (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 1358: #else 1359: (void) sigrelse(SIGINT); 1360: #endif 1361: 1362: 1363: /* 1364: * For the sake of reset() 1365: */ 1366: freelex(¶ml); 1367: if (savet) 1368: freesyn(savet), savet = NULL; 1369: 1370: if (haderr) { 1371: if (!catch) { 1372: /* unwind */ 1373: doneinp = 0; 1374: savet = t; 1375: resexit(osetexit); 1376: reset(); 1377: } 1378: haderr = 0; 1379: /* 1380: * Every error is eventually caught here or the shell dies. It is 1381: * at this point that we clean up any left-over open files, by 1382: * closing all but a fixed number of pre-defined files. Thus 1383: * routines don't have to worry about leaving files open due to 1384: * deeper errors... they will get closed here. 1385: */ 1386: closem(); 1387: continue; 1388: } 1389: if (doneinp) { 1390: doneinp = 0; 1391: break; 1392: } 1393: if (chkstop) 1394: chkstop--; 1395: if (neednote) 1396: pnote(); 1397: if (intty && prompt && evalvec == 0) { 1398: mailchk(); 1399: /* 1400: * Watch for logins/logouts. Next is scheduled commands stored 1401: * previously using "sched." Then execute periodic commands. 1402: * Following that, the prompt precmd is run. 1403: */ 1404: watch_login(); 1405: sched_run(); 1406: period_cmd(); 1407: precmd(); 1408: /* 1409: * If we are at the end of the input buffer then we are going to 1410: * read fresh stuff. Otherwise, we are rereading input and don't 1411: * need or want to prompt. 1412: */ 1413: if (fseekp == feobp) 1414: printprompt(0, NULL); 1415: flush(); 1416: setalarm(); 1417: } 1418: if (seterr) { 1419: xfree((ptr_t) seterr); 1420: seterr = NULL; 1421: } 1422: 1423: /* 1424: * Echo not only on VERBOSE, but also with history expansion. If there 1425: * is a lexical error then we forego history echo. 1426: */ 1427: if (lex(¶ml) && !seterr && intty && !tellwhat && !Expand || 1428: adrof(STRverbose)) { 1429: haderr = 1; 1430: prlex(¶ml); 1431: haderr = 0; 1432: } 1433: (void) alarm(0); /* Autologout OFF */ 1434: 1435: /* 1436: * The parser may lose space if interrupted. 1437: */ 1438: if (setintr) 1439: #ifdef BSDSIGS 1440: (void) sigblock(sigmask(SIGINT)); 1441: #else 1442: (void) sighold(SIGINT); 1443: #endif 1444: 1445: /* 1446: * Save input text on the history list if reading in old history, or it 1447: * is from the terminal at the top level and not in a loop. 1448: * 1449: * PWP: entry of items in the history list while in a while loop is done 1450: * elsewhere... 1451: */ 1452: if (enterhist || catch && intty && !whyles && !tellwhat) 1453: savehist(¶ml); 1454: 1455: if (Expand && seterr) 1456: Expand = 0; 1457: 1458: /* 1459: * Print lexical error messages, except when sourcing history lists. 1460: */ 1461: if (!enterhist && seterr) 1462: stderror(ERR_OLD); 1463: 1464: /* 1465: * If had a history command :p modifier then this is as far as we 1466: * should go 1467: */ 1468: if (justpr) 1469: reset(); 1470: 1471: /* 1472: * If had a tellwhat from twenex() then do 1473: */ 1474: if (tellwhat) { 1475: tellmewhat(¶ml); 1476: reset(); 1477: } 1478: 1479: alias(¶ml); 1480: 1481: #ifdef BSDJOBS 1482: /* 1483: * If we are interactive, try to continue jobs that we have stopped 1484: */ 1485: if (prompt) 1486: con_jobs(¶ml); 1487: #endif /* BSDJOBS */ 1488: 1489: /* 1490: * Check to see if the user typed "rm * .o" or something 1491: */ 1492: if (prompt) 1493: rmstar(¶ml); 1494: /* 1495: * Parse the words of the input into a parse tree. 1496: */ 1497: savet = syntax(paraml.next, ¶ml, 0); 1498: if (seterr) 1499: stderror(ERR_OLD); 1500: 1501: /* 1502: * Execute the parse tree From: Michael Schroeder 1503: * <mlschroe@immd4.informatik.uni-erlangen.de> was execute(t, tpgrp); 1504: */ 1505: execute(savet, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); 1506: 1507: /* 1508: * Made it! 1509: */ 1510: freelex(¶ml); 1511: freesyn(savet), savet = NULL; 1512: #ifdef SIG_WINDOW 1513: if (catch && intty && !whyles && !tellwhat) 1514: window_change(0); /* for window systems */ 1515: #endif /* SIG_WINDOW */ 1516: } 1517: savet = t; 1518: resexit(osetexit); 1519: } 1520: 1521: void 1522: dosource(t) 1523: register Char **t; 1524: { 1525: register Char *f; 1526: bool hflg = 0; 1527: Char buf[BUFSIZ]; 1528: 1529: t++; 1530: if (*t && eq(*t, STRmh)) { 1531: if (*++t == NOSTR) 1532: stderror(ERR_NAME | ERR_HFLAG); 1533: hflg++; 1534: } 1535: (void) Strcpy(buf, *t); 1536: f = globone(buf, G_ERROR); 1537: (void) strcpy((char *) buf, short2str(f)); 1538: xfree((ptr_t) f); 1539: if (!srcfile((char *) buf, 0, hflg) && !hflg) 1540: stderror(ERR_SYSTEM, (char *) buf, strerror(errno)); 1541: } 1542: 1543: /* 1544: * Check for mail. 1545: * If we are a login shell, then we don't want to tell 1546: * about any mail file unless its been modified 1547: * after the time we started. 1548: * This prevents us from telling the user things he already 1549: * knows, since the login program insists on saying 1550: * "You have mail." 1551: */ 1552: static void 1553: mailchk() 1554: { 1555: register struct varent *v; 1556: register Char **vp; 1557: time_t t; 1558: int intvl, cnt; 1559: struct stat stb; 1560: bool new; 1561: 1562: v = adrof(STRmail); 1563: if (v == 0) 1564: return; 1565: (void) time(&t); 1566: vp = v->vec; 1567: cnt = blklen(vp); 1568: intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 1569: if (intvl < 1) 1570: intvl = 1; 1571: if (chktim + intvl > t) 1572: return; 1573: for (; *vp; vp++) { 1574: if (stat(short2str(*vp), &stb) < 0) 1575: continue; 1576: #if defined(BSDTIMES) || defined(_SEQUENT_) 1577: new = stb.st_mtime > time0.tv_sec; 1578: #else 1579: new = stb.st_mtime > time0; 1580: #endif 1581: if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || 1582: (stb.st_atime < chktim && stb.st_mtime < chktim) || 1583: loginsh && !new) 1584: continue; 1585: if (cnt == 1) 1586: xprintf("You have %smail.\n", new ? "new " : ""); 1587: else 1588: xprintf("%s in %s.\n", new ? "New mail" : "Mail", 1589: short2str(*vp)); 1590: } 1591: chktim = t; 1592: } 1593: 1594: /* 1595: * Extract a home directory from the password file 1596: * The argument points to a buffer where the name of the 1597: * user whose home directory is sought is currently. 1598: * We write the home directory of the user back there. 1599: */ 1600: int 1601: gethdir(home) 1602: Char *home; 1603: { 1604: Char *h; 1605: 1606: /* 1607: * Is it us? 1608: */ 1609: if (*home == '\0') { 1610: if (h = value(STRhome)) { 1611: (void) Strcpy(home, h); 1612: return 0; 1613: } 1614: else 1615: return 1; 1616: } 1617: 1618: /* 1619: * Look in the cache 1620: */ 1621: if ((h = gettilde(home)) == NULL) 1622: return 1; 1623: else { 1624: (void) Strcpy(home, h); 1625: return 0; 1626: } 1627: } 1628: 1629: /* 1630: * Move the initial descriptors to their eventual 1631: * resting places, closing all other units. 1632: */ 1633: void 1634: initdesc() 1635: { 1636: 1637: didfds = 0; /* 0, 1, 2 aren't set up */ 1638: #ifdef FIOCLEX 1639: (void) ioctl(SHIN = dcopy(0, FSHIN), FIOCLEX, NULL); 1640: (void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, NULL); 1641: (void) ioctl(SHDIAG = dcopy(2, FSHDIAG), FIOCLEX, NULL); 1642: (void) ioctl(OLDSTD = dcopy(SHIN, FOLDSTD), FIOCLEX, NULL); 1643: #else 1644: didcch = 0; /* Havent closed for child */ 1645: SHIN = dcopy(0, FSHIN); 1646: SHOUT = dcopy(1, FSHOUT); 1647: isoutatty = isatty(SHOUT); 1648: SHDIAG = dcopy(2, FSHDIAG); 1649: isdiagatty = isatty(SHDIAG); 1650: OLDSTD = dcopy(SHIN, FOLDSTD); 1651: #endif 1652: closem(); 1653: } 1654: 1655: 1656: void 1657: #ifdef PROF 1658: done(i) 1659: #else 1660: xexit(i) 1661: #endif 1662: int i; 1663: { 1664: #ifdef TESLA 1665: if (loginsh && do_logout) { 1666: /* this is to send hangup signal to the develcon */ 1667: /* we toggle DTR. clear dtr - sleep 1 - set dtr */ 1668: /* ioctl will return ENOTTY for pty's but we ignore it */ 1669: /* exitstat will run after disconnect */ 1670: /* we sleep for 2 seconds to let things happen in */ 1671: /* .logout and rechist() */ 1672: #ifdef TIOCCDTR 1673: (void) sleep(2); 1674: (void) ioctl(FSHTTY, TIOCCDTR, NULL); 1675: (void) sleep(1); 1676: (void) ioctl(FSHTTY, TIOCSDTR, NULL); 1677: #endif /* TIOCCDTR */ 1678: } 1679: #endif /* TESLA */ 1680: 1681: untty(); 1682: _exit(i); 1683: } 1684: 1685: static Char ** 1686: d_path() 1687: { 1688: char *ptr; 1689: Char **blk, **blkp; 1690: struct stat stb; 1691: 1692: blkp = blk = (Char **) xmalloc((size_t) sizeof(Char *) * 10); 1693: 1694: #ifndef DOTLAST 1695: *blkp++ = Strsave(STRdot); 1696: #endif 1697: 1698: #define DIRAPPEND(a) \ 1699: if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \ 1700: *blkp++ = SAVE(ptr) 1701: 1702: #ifdef _PATH_LOCAL 1703: DIRAPPEND(_PATH_LOCAL); 1704: #endif 1705: 1706: #ifdef _PATH_USRUCB 1707: DIRAPPEND(_PATH_USRUCB); 1708: #endif 1709: 1710: #ifdef _PATH_USRBSD 1711: DIRAPPEND(_PATH_USRBSD); 1712: #endif 1713: 1714: #ifdef _PATH_BIN 1715: DIRAPPEND(_PATH_BIN); 1716: #endif 1717: 1718: #ifdef _PATH_USRBIN 1719: DIRAPPEND(_PATH_USRBIN); 1720: #endif 1721: 1722: #undef DIRAPPEND 1723: 1724: #ifdef DOTLAST 1725: *blkp++ = Strsave(STRdot); 1726: #endif 1727: *blkp = NULL; 1728: return (blk); 1729: }