home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / tcsh / Source / sh.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  49.3 KB  |  2,021 lines

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