# 2.11BSD#431 - /usr/src/bin/tcsh/sh.c

##### Functions

    done              X
    dosource          X
    exitstat          X
    gethdir           X
    goodbye           X
    importpath        X
    initdesc          X
    main              X
    pintr             X
    pintr1            X
    process           X
    rechist           X
    untty             X
    xexit             X

##### Variables

    batch             X
    copyright         X
    dflag             X
    dumphist          X
    enterhist         X
    fast              X
    insource          X
    jobargv           X
    just_signaled     X
    loaddirs          X
    loadhist          X
    mflag             X
    nexececho         X
    nofile            X
    nverbose          X
    prompt            X
    quitit            X
    reenter           X
    savet             X
    t_period          X
    tellwhat          X
    use_fork          X

##### Macros

    DIRAPPEND         X

       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 = &paraml;
    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(&paraml);
    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(&paraml) && !seterr && intty && !tellwhat && !Expand ||
    1428:         adrof(STRverbose)) {
    1429:         haderr = 1;
    1430:         prlex(&paraml);
    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(&paraml);
    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(&paraml);
    1476:         reset();
    1477:     }
    1478:
    1479:     alias(&paraml);
    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(&paraml);
    1487: #endif				/* BSDJOBS */
    1488:
    1489:     /*
    1490: 	 * Check to see if the user typed "rm * .o" or something
    1491: 	 */
    1492:     if (prompt)
    1493:         rmstar(&paraml);
    1494:     /*
    1495: 	 * Parse the words of the input into a parse tree.
    1496: 	 */
    1497:     savet = syntax(paraml.next, &paraml, 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(&paraml);
    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: }

#### Defined functions

d_path defined in line 1685; used 1 times

- in line 401

done defined in line 1656; used 9 times

- in /usr/src/bin/tcsh/sh.dol.c line 218-221(3), 239, 291, 298, 304, 311
- in /usr/src/bin/tcsh/sh.h line 101

dosource defined in line 1521; used 3 times

- in line 825, 846
- in /usr/src/bin/tcsh/sh.init.c line 142

exitstat defined in line 1196; used 8 times

- in line 899, 1193
- in /usr/src/bin/tcsh/sh.exp.c line 481
- in /usr/src/bin/tcsh/sh.glob.c line 708
- in /usr/src/bin/tcsh/sh.lex.c line 1321
- in /usr/src/bin/tcsh/sh.proc.c line 618
- in /usr/src/bin/tcsh/sh.sem.c line 511, 535

gethdir defined in line 1600; used 2 times

- in /usr/src/bin/tcsh/sh.glob.c line 107
- in /usr/src/bin/tcsh/tw.parse.c line 1220

goodbye defined in line 1168; used 4 times

- in line 886
- in /usr/src/bin/tcsh/sh.func.c line 250
- in /usr/src/bin/tcsh/sh.init.c line 62
- in /usr/src/bin/tcsh/tc.func.c line 486

importpath defined in line 915; used 3 times

- in line 403
- in /usr/src/bin/tcsh/sh.func.c line 1039
- in /usr/src/bin/tcsh/tc.os.c line 178

initdesc defined in line 1633; used 2 times

- in line 222
- in /usr/src/bin/tcsh/sh.glob.c line 678

mailchk defined in line 1552; used 1 times

- in line 1398

main defined in line 124; never used
phup defined in line 1215; used 3 times

- in line 430-435(3)

pintr defined in line 1243; used 1 times

- in line 665

pintr1 defined in line 1254; used 2 times

- in line 1248
- in /usr/src/bin/tcsh/sh.proc.c line 604

process defined in line 1333; used 3 times

- in line 873, 1101
- in /usr/src/bin/tcsh/sh.func.c line 1709

rcsid defined in line 45; never used
rechist defined in line 1141; used 5 times

- in line 898, 1171, 1219
- in /usr/src/bin/tcsh/sh.exec.c line 419
- in /usr/src/bin/tcsh/sh.func.c line 258

srccat defined in line 955; used 5 times

- in line 814-818(3), 828, 1188

srcfile defined in line 973; used 6 times

- in line 797, 803, 960, 966, 1185, 1539

srcunit defined in line 996; used 1 times

- in line 987

untty defined in line 903; used 4 times

- in line 1681
- in /usr/src/bin/tcsh/sh.func.c line 261, 276, 1596

xexit defined in line 1656; never used

#### Defined variables

batch defined in line 108; used 3 times

- in line 456, 467, 621

copyright defined in line 39; never used
dflag defined in line 95; used 2 times

- in line 498, 844

do_logout defined in line 87; used 4 times

- in line 140, 884, 1190, 1665

dumphist defined in line 90; used 2 times

- in line 1160-1161(2)

enterhist defined in line 111; used 8 times

- in line 1021, 1082-1083(2), 1126-1128(2), 1350, 1452, 1461

fast defined in line 107; used 7 times

- in line 314, 508, 785, 799, 820, 844, 1147

insource defined in line 995; used 3 times

- in line 1016, 1058, 1138

jobargv defined in line 1232; used 1 times

- in line 1275

just_signaled defined in line 1241; used 3 times

- in line 1247
- in /usr/src/bin/tcsh/tc.sched.c line 257, 263

loaddirs defined in line 94; used 1 times

- in line 846

loadhist defined in line 91; used 1 times

- in line 825

mflag defined in line 109; used 3 times

- in line 517, 960, 966

nexececho defined in line 105; used 2 times

- in line 543, 865

nofile defined in line 102; used 10 times

- in line 463, 493, 513, 529, 535, 576-578(3), 589-590(2)

nverbose defined in line 104; used 2 times

- in line 539, 863

prompt defined in line 110; used 8 times

- in line 461, 492, 534, 607, 648, 1397, 1485, 1492

quitit defined in line 106; used 5 times

- in line 168, 525, 568, 663-668(2)

reenter defined in line 103; used 2 times

- in line 783-785(2)

savet defined in line 1332; used 11 times

- in line 1340-1342(2), 1367-1368(3), 1374, 1497, 1505, 1511(2), 1517

t_period defined in line 113; used 1 times

- in line 214

tellwhat defined in line 112; used 4 times

- in line 1427, 1452, 1474, 1513

use_fork defined in line 99; used 1 times

- in line 560

#### Defined macros

DIRAPPEND defined in line 1698; used 6 times

- in line 1703-1722(6)

Last modified: 1994-01-03 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3672 |