home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / tcshsrc.zoo / tcsh / sh.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-01  |  48.2 KB  |  1,976 lines

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