home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume25 / tcsh-6.01 / part15 / sh.c < prev   
C/C++ Source or Header  |  1991-12-19  |  45KB  |  1,843 lines

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