home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Shells / zsh-3.0.5-MIHS / src / Src / exec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-25  |  64.0 KB  |  2,770 lines

  1. /*
  2.  * $Id: exec.c,v 2.93 1996/10/15 20:16:35 hzoli Exp $
  3.  *
  4.  * exec.c - command execution
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and to distribute modified versions of this software for any
  14.  * purpose, provided that the above copyright notice and the following
  15.  * two paragraphs appear in all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #include "zsh.h"
  33.  
  34. #define execerr() if (!forked) { lastval = 1; return; } else _exit(1)
  35.     
  36.  
  37. static LinkList args;
  38. static int doneps4;
  39.  
  40. /* parse string into a list */
  41.  
  42. /**/
  43. List
  44. parse_string(char *s)
  45. {
  46.     List l;
  47.  
  48.     lexsave();
  49.     inpush(s, 0, NULL);
  50.     strinbeg();
  51.     stophist = 2;
  52.     l = parse_list();
  53.     strinend();
  54.     inpop();
  55.     lexrestore();
  56.     return l;
  57. }
  58.  
  59. #ifdef HAVE_GETRLIMIT
  60. /**/
  61. int
  62. zsetlimit(int limnum, char *nam)
  63. {
  64.     if (limits[limnum].rlim_max != current_limits[limnum].rlim_max ||
  65.     limits[limnum].rlim_cur != current_limits[limnum].rlim_cur) {
  66.     if (setrlimit(limnum, limits + limnum)) {
  67.         if (nam)
  68.         zwarnnam(nam, "setrlimit failed: %e", NULL, errno);
  69.         return -1;
  70.     }
  71.     current_limits[limnum] = limits[limnum];
  72.     }
  73.     return 0;
  74. }
  75.  
  76. /**/
  77. int
  78. setlimits(char *nam)
  79. {
  80.     int limnum;
  81.     int ret = 0;
  82.  
  83.     for (limnum = 0; limnum < RLIM_NLIMITS; limnum++)
  84.     if (zsetlimit(limnum, nam))
  85.         ret++;
  86.     return ret;
  87. }
  88. #endif
  89.  
  90. /* fork and set limits */
  91.  
  92. /**/
  93. pid_t
  94. zfork(void)
  95. {
  96.     pid_t pid;
  97.  
  98.     if (thisjob >= MAXJOB - 1) {
  99.     zerr("job table full", NULL, 0);
  100.     return -1;
  101.     }
  102.     pid = fork();
  103.     if (pid == -1) {
  104.     zerr("fork failed: %e", NULL, errno);
  105.     return -1;
  106.     }
  107. #ifdef HAVE_GETRLIMIT
  108.     if (!pid)
  109.     /* set resource limits for the child process */
  110.     setlimits(NULL);
  111. #endif
  112.     return pid;
  113. }
  114.  
  115.  
  116. int list_pipe = 0, simple_pline = 0;
  117.  
  118. static pid_t list_pipe_pid;
  119. static int nowait, pline_level = 0;
  120. static int list_pipe_child = 0, list_pipe_job;
  121. static char list_pipe_text[JOBTEXTSIZE];
  122.  
  123. /* execute a current shell command */
  124.  
  125. /**/
  126. int
  127. execcursh(Cmd cmd)
  128. {
  129.     if (!list_pipe)
  130.     deletejob(jobtab + thisjob);
  131.     execlist(cmd->u.list, 1, cmd->flags & CFLAG_EXEC);
  132.     cmd->u.list = NULL;
  133.     return lastval;
  134. }
  135.  
  136. /* execve after handling $_ and #! */
  137.  
  138. #define POUNDBANGLIMIT 64
  139.  
  140. /**/
  141. int
  142. zexecve(char *pth, char **argv)
  143. {
  144.     int eno;
  145.     static char buf[PATH_MAX * 2];
  146.     char **eep;
  147.  
  148.     unmetafy(pth, NULL);
  149.     for (eep = argv; *eep; eep++)
  150.     if (*eep != pth)
  151.         unmetafy(*eep, NULL);
  152.     for (eep = environ; *eep; eep++)
  153.     if (**eep == '_' && (*eep)[1] == '=')
  154.         break;
  155.     buf[0] = '_';
  156.     buf[1] = '=';
  157.     if (*pth == '/')
  158.     strcpy(buf + 2, pth);
  159.     else
  160.     sprintf(buf + 2, "%s/%s", pwd, pth);
  161.     if (!*eep)
  162.     eep[1] = NULL;
  163.     *eep = buf;
  164.     execve(pth, argv, environ);
  165.  
  166.     /* If the execve returns (which in general shouldn't happen),   *
  167.      * then check for an errno equal to ENOEXEC.  This errno is set *
  168.      * if the process file has the appropriate access permission,   *
  169.      * but has an invalid magic number in its header.               */
  170.     if ((eno = errno) == ENOEXEC) {
  171.     char execvebuf[POUNDBANGLIMIT + 1], *ptr, *ptr2, *argv0;
  172.     int fd, ct, t0;
  173.  
  174.     if ((fd = open(pth, O_RDONLY)) >= 0) {
  175.         argv0 = *argv;
  176.         *argv = pth;
  177.         ct = read(fd, execvebuf, POUNDBANGLIMIT);
  178.         close(fd);
  179.         if (ct > 0) {
  180.         if (execvebuf[0] == '#') {
  181.             if (execvebuf[1] == '!') {
  182.             for (t0 = 0; t0 != ct; t0++)
  183.                 if (execvebuf[t0] == '\n')
  184.                 execvebuf[t0] = '\0';
  185.             execvebuf[POUNDBANGLIMIT] = '\0';
  186.             for (ptr = execvebuf + 2; *ptr && *ptr == ' '; ptr++);
  187.             for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
  188.             if (*ptr) {
  189.                 *ptr = '\0';
  190.                 argv[-2] = ptr2;
  191.                 argv[-1] = ptr + 1;
  192.                 execve(ptr2, argv - 2, environ);
  193.             } else {
  194.                 argv[-1] = ptr2;
  195.                 execve(ptr2, argv - 1, environ);
  196.             }
  197.             } else {
  198.             argv[-1] = "sh";
  199.             execve("/bin/sh", argv - 1, environ);
  200.             }
  201.         } else {
  202.             for (t0 = 0; t0 != ct; t0++)
  203.             if (!execvebuf[t0])
  204.                 break;
  205.             if (t0 == ct) {
  206.             argv[-1] = "sh";
  207.             execve("/bin/sh", argv - 1, environ);
  208.             }
  209.         }
  210.         } else
  211.         eno = errno;
  212.         *argv = argv0;
  213.     } else
  214.         eno = errno;
  215.     }
  216.     /* restore the original arguments and path but do not bother with *
  217.      * null characters as these cannot be passed to external commands *
  218.      * anyway.  So the result is truncated at the first null char.    */
  219.     pth = metafy(pth, -1, META_NOALLOC);
  220.     for (eep = argv; *eep; eep++)
  221.     if (*eep != pth)
  222.         (void) metafy(*eep, -1, META_NOALLOC);
  223.     return eno;
  224. }
  225.  
  226. #define MAXCMDLEN (PATH_MAX*4)
  227.  
  228. /* test whether we really want to believe the error number */
  229.  
  230. /**/
  231. int
  232. isgooderr(int e, char *dir)
  233. {
  234.     /*
  235.      * Maybe the directory was unreadable, or maybe it wasn't
  236.      * even a directory. 
  237.      */
  238.     return ((e != EACCES || !access(dir, X_OK)) &&
  239.         e != ENOENT && e != ENOTDIR); 
  240. }
  241.  
  242. /* execute an external command */
  243.  
  244. /**/
  245. void
  246. execute(Cmdnam not_used_yet, int dash)
  247. {
  248.     Cmdnam cn;
  249.     static LinkList exargs;
  250.     char buf[MAXCMDLEN], buf2[MAXCMDLEN];
  251.     char *s, *z, *arg0;
  252.     char **argv, **pp;
  253.     int eno = 0, ee;
  254.  
  255.     /* If the parameter STTY is set in the command's environment, *
  256.      * we first run the stty command with the value of this       *
  257.      * parameter as it arguments.                                 */
  258.     if (!exargs && (s = zgetenv("STTY")) && isatty(0)) {
  259.     char *t;
  260.  
  261.     exargs = args;    /* this prevents infinite recursion */
  262.     args = NULL;
  263.     t = tricat("stty", " ", s);
  264.     execstring(t, 1, 0);
  265.     zsfree(t);
  266.     args = exargs;
  267.     exargs = NULL;
  268.     }
  269.  
  270.     arg0 = (char *) peekfirst(args);
  271.     cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0);
  272.  
  273.     /* If ARGV0 is in the commands environment, we use *
  274.      * that as argv[0] for this external command       */
  275.     if ((z = zgetenv("ARGV0"))) {
  276.     setdata(firstnode(args), (void *) ztrdup(z));
  277.     delenv(z - 6);
  278.     } else if (dash) {
  279.     /* Else if the pre-command `-' was given, we add `-' *
  280.      * to the front of argv[0] for this command.         */
  281.     sprintf(buf2, "-%s", arg0);
  282.     setdata(firstnode(args), (void *) ztrdup(buf2));
  283.     }
  284.  
  285.     argv = makecline(args);
  286.     child_unblock();
  287.     if ((int) strlen(arg0) >= PATH_MAX) {
  288.     zerr("command too long: %s", arg0, 0);
  289.     _exit(1);
  290.     }
  291.     for (s = arg0; *s; s++)
  292.     if (*s == '/') {
  293.         errno = zexecve(arg0, argv);
  294.         if (arg0 == s || unset(PATHDIRS) ||
  295.         (arg0[0] == '.' && (arg0 + 1 == s ||
  296.                     (arg0[1] == '.' && arg0 + 2 == s)))) {
  297.         zerr("%e: %s", arg0, errno);
  298.         _exit(1);
  299.         }
  300.         break;
  301.     }
  302.  
  303.     if (cn) {
  304.     char nn[PATH_MAX], *dptr;
  305.  
  306.     if (cn->flags & HASHED)
  307.         strcpy(nn, cn->u.cmd);
  308.     else {
  309.         for (pp = path; pp < cn->u.name; pp++)
  310.         if (!**pp || (**pp == '.' && (*pp)[1] == '\0')) {
  311.             ee = zexecve(arg0, argv);
  312.             if (isgooderr(ee, *pp))
  313.             eno = ee;
  314.         } else if (**pp != '/') {
  315.             z = buf;
  316.             strucpy(&z, *pp);
  317.             *z++ = '/';
  318.             strcpy(z, arg0);
  319.             ee = zexecve(buf, argv);
  320.             if (isgooderr(ee, *pp))
  321.             eno = ee;
  322.         }
  323.         strcpy(nn, cn->u.name ? *(cn->u.name) : "");
  324.         strcat(nn, "/");
  325.         strcat(nn, cn->nam);
  326.     }
  327.     ee = zexecve(nn, argv);
  328.  
  329.     if ((dptr = strrchr(nn, '/')))
  330.         *dptr = '\0';
  331.     if (isgooderr(ee, *nn ? nn : "/"))
  332.         eno = ee;
  333.     }
  334.     for (pp = path; *pp; pp++)
  335.     if (!(*pp)[0] || ((*pp)[0] == '.' && !(*pp)[1])) {
  336.         ee = zexecve(arg0, argv);
  337.         if (isgooderr(ee, *pp))
  338.         eno = ee;
  339.     } else {
  340.         z = buf;
  341.         strucpy(&z, *pp);
  342.         *z++ = '/';
  343.         strcpy(z, arg0);
  344.         ee = zexecve(buf, argv);
  345.         if (isgooderr(ee, *pp))
  346.         eno = ee;
  347.     }
  348.     if (eno)
  349.     zerr("%e: %s", arg0, eno);
  350.     else
  351.     zerr("command not found: %s", arg0, 0);
  352.     _exit(1);
  353. }
  354.  
  355. #define try(X) { if (iscom(X)) return ztrdup(X); }
  356.  
  357. /* get the full pathname of an external command */
  358.  
  359. /**/
  360. char *
  361. findcmd(char *arg0)
  362. {
  363.     char **pp;
  364.     char *z, *s, buf[MAXCMDLEN];
  365.     Cmdnam cn;
  366.  
  367.     cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0);
  368.     if (!cn && isset(HASHCMDS))
  369.     cn = hashcmd(arg0, path);
  370.     if ((int) strlen(arg0) > PATH_MAX)
  371.     return NULL;
  372.     for (s = arg0; *s; s++)
  373.     if (*s == '/') {
  374.         try(arg0);
  375.         if (arg0 == s || unset(PATHDIRS)) {
  376.         return NULL;
  377.         }
  378.         break;
  379.     }
  380.     if (cn) {
  381.     char nn[PATH_MAX];
  382.  
  383.     if (cn->flags & HASHED)
  384.         strcpy(nn, cn->u.cmd);
  385.     else {
  386.         for (pp = path; pp < cn->u.name; pp++)
  387.         if (**pp != '/') {
  388.             z = buf;
  389.             if (**pp) {
  390.             strucpy(&z, *pp);
  391.             *z++ = '/';
  392.             }
  393.             strcpy(z, arg0);
  394.             try(buf);
  395.         }
  396.         strcpy(nn, cn->u.name ? *(cn->u.name) : "");
  397.         strcat(nn, "/");
  398.         strcat(nn, cn->nam);
  399.     }
  400.     try(nn);
  401.     }
  402.     for (pp = path; *pp; pp++) {
  403.     z = buf;
  404.     if (**pp) {
  405.         strucpy(&z, *pp);
  406.         *z++ = '/';
  407.     }
  408.     strcpy(z, arg0);
  409.     try(buf);
  410.     }
  411.     return NULL;
  412. }
  413.  
  414. /**/
  415. int
  416. iscom(char *s)
  417. {
  418.     struct stat statbuf;
  419.     char *us = unmeta(s);
  420.  
  421.     return (access(us, X_OK) == 0 && stat(us, &statbuf) >= 0 &&
  422.         S_ISREG(statbuf.st_mode));
  423. }
  424.  
  425. /**/
  426. int
  427. isrelative(char *s)
  428. {
  429.     if (*s != '/')
  430.     return 1;
  431.     for (; *s; s++)
  432.     if (*s == '.' && s[-1] == '/' &&
  433.         (s[1] == '/' || s[1] == '\0' ||
  434.          (s[1] == '.' && (s[2] == '/' || s[2] == '\0'))))
  435.         return 1;
  436.     return 0;
  437. }
  438.  
  439. /**/
  440. Cmdnam
  441. hashcmd(char *arg0, char **pp)
  442. {
  443.     Cmdnam cn;
  444.     char *s, buf[PATH_MAX];
  445.     char **pq;
  446.  
  447.     for (; *pp; pp++)
  448.     if (**pp == '/') {
  449.         s = buf;
  450.         strucpy(&s, *pp);
  451.         *s++ = '/';
  452.         if ((s - buf) + strlen(arg0) >= PATH_MAX)
  453.         continue;
  454.         strcpy(s, arg0);
  455.         if (iscom(buf))
  456.         break;
  457.     }
  458.  
  459.     if (!*pp)
  460.     return NULL;
  461.  
  462.     cn = (Cmdnam) zcalloc(sizeof *cn);
  463.     cn->flags = 0;
  464.     cn->u.name = pp;
  465.     cmdnamtab->addnode(cmdnamtab, ztrdup(arg0), cn);
  466.  
  467.     if (isset(HASHDIRS)) {
  468.     for (pq = pathchecked; pq <= pp; pq++)
  469.         hashdir(pq);
  470.     pathchecked = pp + 1;
  471.     }
  472.  
  473.     return cn;
  474. }
  475.  
  476. /* execute a string */
  477.  
  478. /**/
  479. void
  480. execstring(char *s, int dont_change_job, int exiting)
  481. {
  482.     List list;
  483.  
  484.     pushheap();
  485.     if ((list = parse_string(s)))
  486.     execlist(list, dont_change_job, exiting);
  487.     popheap();
  488. }
  489.  
  490. /* Main routine for executing a list.                                *
  491.  * exiting means that the (sub)shell we are in is a definite goner   *
  492.  * after the current list is finished, so we may be able to exec the *
  493.  * last command directly instead of forking.  If dont_change_job is  *
  494.  * nonzero, then restore the current job number after executing the  *
  495.  * list.                                                             */
  496.  
  497. /**/
  498. void
  499. execlist(List list, int dont_change_job, int exiting)
  500. {
  501.     Sublist slist;
  502.     static int donetrap;
  503.     int ret, cj;
  504.     int old_pline_level, old_list_pipe;
  505.  
  506.     cj = thisjob;
  507.     old_pline_level = pline_level;
  508.     old_list_pipe = list_pipe;
  509.  
  510.     if (sourcelevel && unset(SHINSTDIN))
  511.     pline_level = list_pipe = 0;
  512.  
  513.     /* Loop over all sets of comands separated by newline, *
  514.      * semi-colon or ampersand (`sublists').               */
  515.     while (list && list != &dummy_list && !breaks && !retflag) {
  516.     /* Reset donetrap:  this ensures that a trap is only *
  517.      * called once for each sublist that fails.          */
  518.     donetrap = 0;
  519.     simplifyright(list);
  520.     slist = list->left;
  521.  
  522.     /* Loop through code followed by &&, ||, or end of sublist. */
  523.     while (slist) {
  524.         switch (slist->type) {
  525.         case END:
  526.         /* End of sublist; just execute, ignoring status. */
  527.         execpline(slist, list->type, !list->right && exiting);
  528.         goto sublist_done;
  529.         break;
  530.         case ANDNEXT:
  531.         /* If the return code is non-zero, we skip pipelines until *
  532.          * we find a sublist followed by ORNEXT.                   */
  533.         if ((ret = execpline(slist, Z_SYNC, 0))) {
  534.             while ((slist = slist->right))
  535.             if (slist->type == ORNEXT)
  536.                 break;
  537.             if (!slist) {
  538.             /* We've skipped to the end of the list, not executing *
  539.              * the final pipeline, so don't perform error handling *
  540.              * for this sublist.                                   */
  541.             donetrap = 1;
  542.             goto sublist_done;
  543.             }
  544.         }
  545.         break;
  546.         case ORNEXT:
  547.         /* If the return code is zero, we skip pipelines until *
  548.          * we find a sublist followed by ANDNEXT.              */
  549.         if (!(ret = execpline(slist, Z_SYNC, 0))) {
  550.             while ((slist = slist->right))
  551.             if (slist->type == ANDNEXT)
  552.                 break;
  553.             if (!slist) {
  554.             /* We've skipped to the end of the list, not executing *
  555.              * the final pipeline, so don't perform error handling *
  556.              * for this sublist.                                   */
  557.             donetrap = 1;
  558.             goto sublist_done;
  559.              }
  560.         }
  561.         break;
  562.         }
  563.         slist = slist->right;
  564.     }
  565. sublist_done:
  566.  
  567.     if (sigtrapped[SIGDEBUG])
  568.         dotrap(SIGDEBUG);
  569.  
  570.     /* Check whether we are suppressing traps/errexit *
  571.      * (typically in init scripts) and if we haven't  *
  572.      * already performed them for this sublist.       */
  573.     if (!noerrexit && !donetrap) {
  574.         if (sigtrapped[SIGZERR] && lastval) {
  575.         dotrap(SIGZERR);
  576.         donetrap = 1;
  577.         }
  578.         if (lastval && isset(ERREXIT)) {
  579.         if (sigtrapped[SIGEXIT])
  580.             dotrap(SIGEXIT);
  581.         if (mypid != getpid())
  582.             _exit(lastval);
  583.         else
  584.             exit(lastval);
  585.         }
  586.     }
  587.  
  588.     list = list->right;
  589.     }
  590.  
  591.     pline_level = old_pline_level;
  592.     list_pipe = old_list_pipe;
  593.     if (dont_change_job)
  594.     thisjob = cj;
  595. }
  596.  
  597. /* Execute a pipeline.                                                *
  598.  * last1 is a flag that this command is the last command in a shell   *
  599.  * that is about to exit, so we can exec instead of forking.  It gets *
  600.  * passed all the way down to execcmd() which actually makes the      *
  601.  * decision.  A 0 is always passed if the command is not the last in  *
  602.  * the pipeline.  This function assumes that the sublist is not NULL. *
  603.  * If last1 is zero but the command is at the end of a pipeline, we   *
  604.  * pass 2 down to execcmd().                                          *
  605.  */
  606.  
  607. /**/
  608. int
  609. execpline(Sublist l, int how, int last1)
  610. {
  611.     int ipipe[2], opipe[2];
  612.     int pj, newjob;
  613.     static int lastwj;
  614.  
  615.     if (!l->left)
  616.     return lastval = (l->flags & PFLAG_NOT) != 0;
  617.  
  618.     pj = thisjob;
  619.     ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
  620.     child_block();
  621.  
  622.     /* get free entry in job table and initialize it */
  623.     if ((thisjob = newjob = initjob()) == -1)
  624.     return 1;
  625.     if (how & Z_TIMED)
  626.     jobtab[thisjob].stat |= STAT_TIMED;
  627.  
  628.     if (l->flags & PFLAG_COPROC) {
  629.     how = Z_ASYNC;
  630.     if (coprocin >= 0) {
  631.         zclose(coprocin);
  632.         zclose(coprocout);
  633.     }
  634.     mpipe(ipipe);
  635.     mpipe(opipe);
  636.     coprocin = ipipe[0];
  637.     coprocout = opipe[1];
  638.     fdtable[coprocin] = fdtable[coprocout] = 0;
  639.     }
  640.     if (!pline_level++) {
  641.     list_pipe_job = newjob;
  642.     nowait = 0;
  643.     }
  644.     list_pipe_pid = lastwj = 0;
  645.     if (pline_level == 1)
  646.     simple_pline = (l->left->type == END);
  647.     execpline2(l->left, how, opipe[0], ipipe[1], last1);
  648.     pline_level--;
  649.     if (how & Z_ASYNC) {
  650.     lastwj = newjob;
  651.     jobtab[thisjob].stat |= STAT_NOSTTY;
  652.     if (l->flags & PFLAG_COPROC)
  653.         zclose(ipipe[1]);
  654.     if (how & Z_DISOWN) {
  655.         deletejob(jobtab + thisjob);
  656.         thisjob = -1;
  657.     }
  658.     else
  659.         spawnjob();
  660.     child_unblock();
  661.     return 0;
  662.     } else {
  663.     if (newjob != lastwj) {
  664.         Job jn = jobtab + newjob;
  665.  
  666.         if (newjob == list_pipe_job && list_pipe_child)
  667.         _exit(0);
  668.  
  669.         lastwj = thisjob = newjob;
  670.  
  671.         if (list_pipe)
  672.         jn->stat |= STAT_NOPRINT;
  673.  
  674.         if (nowait) {
  675.         if(!pline_level) {
  676.             struct process *pn, *qn;
  677.  
  678.             curjob = newjob;
  679.             addproc(list_pipe_pid, list_pipe_text);
  680.  
  681.             for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
  682.             if (WIFSTOPPED(pn->status))
  683.                 break;
  684.  
  685.             if (pn) {
  686.             for (qn = jn->procs; qn->next; qn = qn->next);
  687.             qn->status = pn->status;
  688.             }
  689.  
  690.             jn->stat &= ~(STAT_DONE | STAT_NOPRINT);
  691.             jn->stat |= STAT_STOPPED | STAT_CHANGED;
  692.             printjob(jn, !!isset(LONGLISTJOBS), 1);
  693.         }
  694.         else
  695.             deletejob(jn);
  696.         }
  697.  
  698.         for (; !nowait;) {
  699.         if (list_pipe_child) {
  700.             jn->stat |= STAT_NOPRINT;
  701.             makerunning(jn);
  702.         }
  703.         if (!(jn->stat & STAT_LOCKED))
  704.             waitjobs();
  705.  
  706.         if (list_pipe_child &&
  707.             jn->stat & STAT_DONE &&
  708.             lastval2 & 0200)
  709.             killpg(mypgrp, lastval2 & ~0200);
  710.         if ((list_pipe || last1) && !list_pipe_child &&
  711.             jn->stat & STAT_STOPPED) {
  712.             pid_t pid;
  713.             int synch[2];
  714.  
  715.             pipe(synch);
  716.  
  717.             if ((pid = fork()) == -1) {
  718.             trashzle();
  719.             close(synch[0]);
  720.             close(synch[1]);
  721.             putc('\n', stderr);
  722.             fprintf(stderr, "zsh: job can't be suspended\n");
  723.             fflush(stderr);
  724.             makerunning(jn);
  725.             killjb(jn, SIGCONT);
  726.             thisjob = newjob;
  727.             }
  728.             else if (pid) {
  729.             char dummy;
  730.  
  731.             list_pipe_pid = pid;
  732.             nowait = errflag = 1;
  733.             breaks = loops;
  734.             close(synch[1]);
  735.             read(synch[0], &dummy, 1);
  736.             close(synch[0]);
  737.             jobtab[list_pipe_job].other = newjob;
  738.             jobtab[list_pipe_job].stat |= STAT_SUPERJOB;
  739.             jn->stat |= STAT_SUBJOB | STAT_NOPRINT;
  740.             jn->other = pid;
  741.             killpg(jobtab[list_pipe_job].gleader, SIGSTOP);
  742.             break;
  743.             }
  744.             else {
  745.             close(synch[0]);
  746.             entersubsh(Z_ASYNC, 0, 0);
  747.             setpgrp(0L, mypgrp = jobtab[list_pipe_job].gleader);
  748.             close(synch[1]);
  749.             kill(getpid(), SIGSTOP);
  750.             list_pipe = 0;
  751.             list_pipe_child = 1;
  752.             break;
  753.             }
  754.         }
  755.         else if (subsh && jn->stat & STAT_STOPPED)
  756.             thisjob = newjob;
  757.         else
  758.             break;
  759.         }
  760.         child_unblock();
  761.  
  762.         if (list_pipe && (lastval & 0200) && pj >= 0 &&
  763.         (!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) {
  764.         jn = jobtab + pj;
  765.         jn->stat |= STAT_NOPRINT;
  766.         killjb(jobtab + pj, lastval & ~0200);
  767.         }
  768.         if (list_pipe_child || (list_pipe && (jn->stat & STAT_DONE)))
  769.         deletejob(jn);
  770.         thisjob = pj;
  771.  
  772.     }
  773.     if (l->flags & PFLAG_NOT)
  774.         lastval = !lastval;
  775.     }
  776.     if (!pline_level)
  777.     simple_pline = 0;
  778.     return lastval;
  779. }
  780.  
  781. int subsh_close = -1;
  782.  
  783. /* execute pipeline.  This function assumes the `pline' is not NULL. */
  784.  
  785. /**/
  786. void
  787. execpline2(Pline pline, int how, int input, int output, int last1)
  788. {
  789.     pid_t pid;
  790.     int pipes[2];
  791.     int oldlineno;
  792.  
  793.     if (breaks || retflag)
  794.     return;
  795.  
  796.     oldlineno = lineno;
  797.     lineno = pline->left->lineno;
  798.  
  799.     if (pline_level == 1)
  800.     strcpy(list_pipe_text, getjobtext((void *) pline->left));
  801.     if (pline->type == END) {
  802.     execcmd(pline->left, input, output, how, last1 ? 1 : 2);
  803.     pline->left = NULL;
  804.     } else {
  805.     int old_list_pipe = list_pipe;
  806.  
  807.     mpipe(pipes);
  808.  
  809.     /* if we are doing "foo | bar" where foo is a current *
  810.      * shell command, do foo in a subshell and do the     *
  811.      * rest of the pipeline in the current shell.         */
  812.     if (pline->left->type >= CURSH && (how & Z_SYNC)) {
  813.         int synch[2];
  814.  
  815.         pipe(synch);
  816.         if ((pid = fork()) == -1) {
  817.         close(synch[0]);
  818.         close(synch[1]);
  819.         zerr("fork failed: %e", NULL, errno);
  820.         } else if (pid) {
  821.         char dummy, *text;
  822.  
  823.         text = getjobtext((void *) pline->left);
  824.         addproc(pid, text);
  825.         close(synch[1]);
  826.         read(synch[0], &dummy, 1);
  827.         close(synch[0]);
  828.         } else {
  829.         zclose(pipes[0]);
  830.         close(synch[0]);
  831.         entersubsh(how, 2, 0);
  832.         close(synch[1]);
  833.         execcmd(pline->left, input, pipes[1], how, 0);
  834.         _exit(lastval);
  835.         }
  836.     } else {
  837.     /* otherwise just do the pipeline normally. */
  838.         subsh_close = pipes[0];
  839.         execcmd(pline->left, input, pipes[1], how, 0);
  840.     }
  841.     pline->left = NULL;
  842.     zclose(pipes[1]);
  843.     if (pline->right) {
  844.         /* if another execpline() is invoked because the command is *
  845.          * a list it must know that we're already in a pipeline     */
  846.         list_pipe = 1;
  847.         execpline2(pline->right, how, pipes[0], output, last1);
  848.         list_pipe = old_list_pipe;
  849.         zclose(pipes[0]);
  850.         subsh_close = -1;
  851.     }
  852.     }
  853.  
  854.     lineno = oldlineno;
  855. }
  856.  
  857. /* make the argv array */
  858.  
  859. /**/
  860. char **
  861. makecline(LinkList list)
  862. {
  863.     LinkNode node;
  864.     char **argv, **ptr;
  865.  
  866.     /* A bigger argv is necessary for executing scripts */
  867.     ptr  =
  868.     argv = 2 + (char **) ncalloc((countlinknodes(list) + 4) * sizeof(char *));
  869.     if (isset(XTRACE)) {
  870.     if (!doneps4)
  871.         fprintf(stderr, "%s", (prompt4) ? prompt4 : "");
  872.  
  873.     for (node = firstnode(list); node; incnode(node)) {
  874.         *ptr++ = (char *)getdata(node);
  875.         zputs(getdata(node), stderr);
  876.         if (nextnode(node))
  877.         fputc(' ', stderr);
  878.     }
  879.     fputc('\n', stderr);
  880.     fflush(stderr);
  881.     } else {
  882.     for (node = firstnode(list); node; incnode(node))
  883.         *ptr++ = (char *)getdata(node);
  884.     }
  885.     *ptr = NULL;
  886.     return (argv);
  887. }
  888.  
  889. /**/
  890. void
  891. untokenize(char *s)
  892. {
  893.     for (; *s; s++)
  894.     if (itok(*s))
  895.         if (*s == Nularg)
  896.         chuck(s--);
  897.         else
  898.         *s = ztokens[*s - Pound];
  899. }
  900.  
  901. /* Open a file for writing redicection */
  902.  
  903. /**/
  904. int
  905. clobber_open(struct redir *f)
  906. {
  907.     struct stat buf;
  908.     int fd;
  909.  
  910.     if (isset(CLOBBER) || IS_CLOBBER_REDIR(f->type))
  911.     return open(unmeta(f->name), O_WRONLY | O_CREAT | O_TRUNC, 0666);
  912.     if (stat(unmeta(f->name), &buf) || S_ISREG(buf.st_mode))
  913.     return open(unmeta(f->name), O_WRONLY | O_CREAT | O_EXCL, 0666);
  914.     if ((fd = open(unmeta(f->name), O_WRONLY)) < 0)
  915.     return fd;
  916.     if (!fstat(fd, &buf) && !S_ISREG(buf.st_mode))
  917.     return fd;
  918.     /* someone replaced the file between stat and open */
  919.     close(fd);
  920.     errno = EEXIST;
  921.     return -1;
  922. }
  923.  
  924. /* size of buffer for tee and cat processes */
  925. #define TCBUFSIZE 4092
  926.  
  927. /* close an multio (success) */
  928.  
  929. /**/
  930. void
  931. closemn(struct multio **mfds, int fd)
  932. {
  933.     struct multio *mn = mfds[fd];
  934.     char buf[TCBUFSIZE];
  935.     int len, i;
  936.  
  937.     if (fd < 0 || !mfds[fd] || mfds[fd]->ct < 2)
  938.     return;
  939.     if (zfork()) {
  940.     for (i = 0; i < mn->ct; i++)
  941.         zclose(mn->fds[i]);
  942.     zclose(mn->pipe);
  943.     mn->ct = 1;
  944.     mn->fds[0] = fd;
  945.     return;
  946.     }
  947.     /* pid == 0 */
  948.     closeallelse(mn);
  949.     if (mn->rflag) {
  950.     /* tee process */
  951.     while ((len = read(mn->pipe, buf, TCBUFSIZE)) > 0)
  952.         for (i = 0; i < mn->ct; i++)
  953.         write(mn->fds[i], buf, len);
  954.     } else {
  955.     /* cat process */
  956.     for (i = 0; i < mn->ct; i++)
  957.         while ((len = read(mn->fds[i], buf, TCBUFSIZE)) > 0)
  958.         write(mn->pipe, buf, len);
  959.     }
  960.     _exit(0);
  961. }
  962.  
  963. /* close all the mnodes (failure) */
  964.  
  965. /**/
  966. void
  967. closemnodes(struct multio **mfds)
  968. {
  969.     int i, j;
  970.  
  971.     for (i = 0; i < 10; i++)
  972.     if (mfds[i]) {
  973.         for (j = 0; j < mfds[i]->ct; j++)
  974.         zclose(mfds[i]->fds[j]);
  975.         mfds[i] = NULL;
  976.     }
  977. }
  978.  
  979. /**/
  980. void
  981. closeallelse(struct multio *mn)
  982. {
  983.     int i, j;
  984.  
  985.     for (i = 0; i < OPEN_MAX; i++)
  986.     if (mn->pipe != i) {
  987.         for (j = 0; j < mn->ct; j++)
  988.         if (mn->fds[j] == i)
  989.             break;
  990.         if (j == mn->ct)
  991.         zclose(i);
  992.     }
  993. }
  994.  
  995. /* A multio is a list of fds associated with a certain fd.       *
  996.  * Thus if you do "foo >bar >ble", the multio for fd 1 will have *
  997.  * two fds, the result of open("bar",...), and the result of     *
  998.  * open("ble",....).                                             */
  999.  
  1000. /* Add a fd to an multio.  fd1 must be < 10, and may be in any state. *
  1001.  * fd2 must be open, and is `consumed' by this function.  Note that   *
  1002.  * fd1 == fd2 is possible, and indicates that fd1 was really closed.  *
  1003.  * We effectively do `fd2 = movefd(fd2)' at the beginning of this     *
  1004.  * function, but in most cases we can avoid an extra dup by delaying  *
  1005.  * the movefd: we only >need< to move it if we're actually doing a    *
  1006.  * multiple redirection.                                              */
  1007.  
  1008. /**/
  1009. void
  1010. addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag)
  1011. {
  1012.     int pipes[2];
  1013.  
  1014.     if (!mfds[fd1] || unset(MULTIOS)) {
  1015.     if(!mfds[fd1]) {        /* starting a new multio */
  1016.         mfds[fd1] = (struct multio *) alloc(sizeof(struct multio));
  1017.         if (!forked && save[fd1] == -2)
  1018.         save[fd1] = (fd1 == fd2) ? -1 : movefd(fd1);
  1019.     }
  1020.     redup(fd2, fd1);
  1021.     mfds[fd1]->ct = 1;
  1022.     mfds[fd1]->fds[0] = fd1;
  1023.     mfds[fd1]->rflag = rflag;
  1024.     } else {
  1025.     if (mfds[fd1]->rflag != rflag) {
  1026.         zerr("file mode mismatch on fd %d", NULL, fd1);
  1027.         return;
  1028.     }
  1029.     if (mfds[fd1]->ct == 1) {    /* split the stream */
  1030.         mfds[fd1]->fds[0] = movefd(fd1);
  1031.         mfds[fd1]->fds[1] = movefd(fd2);
  1032.         mpipe(pipes);
  1033.         mfds[fd1]->pipe = pipes[1 - rflag];
  1034.         redup(pipes[rflag], fd1);
  1035.         mfds[fd1]->ct = 2;
  1036.     } else {        /* add another fd to an already split stream */
  1037.         if(!(mfds[fd1]->ct % MULTIOUNIT)) {
  1038.         int new = sizeof(struct multio) + sizeof(int) * mfds[fd1]->ct;
  1039.         int old = new - sizeof(int) * MULTIOUNIT;
  1040.         mfds[fd1] = hrealloc((char *)mfds[fd1], old, new);
  1041.         }
  1042.         mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2);
  1043.     }
  1044.     }
  1045.     if (subsh_close >= 0 && !fdtable[subsh_close])
  1046.     subsh_close = -1;
  1047. }
  1048.  
  1049. /**/
  1050. void
  1051. addvars(LinkList l, int export)
  1052. {
  1053.     Varasg v;
  1054.     LinkList vl;
  1055.     int xtr;
  1056.     char **arr, **ptr;
  1057.  
  1058.     xtr = isset(XTRACE);
  1059.     if (xtr && nonempty(l)) {
  1060.     fprintf(stderr, "%s", prompt4 ? prompt4 : "");
  1061.     doneps4 = 1;
  1062.     }
  1063.  
  1064.     while (nonempty(l)) {
  1065.     v = (Varasg) ugetnode(l);
  1066.     singsub(&v->name);
  1067.     if (errflag)
  1068.         return;
  1069.     untokenize(v->name);
  1070.     if (xtr)
  1071.         fprintf(stderr, "%s=", v->name);
  1072.     if (v->type == PM_SCALAR) {
  1073.         vl = newlinklist();
  1074.         addlinknode(vl, v->str);
  1075.     } else
  1076.         vl = v->arr;
  1077.     prefork(vl, v->type == PM_SCALAR ? 7 : 3);
  1078.     if (errflag)
  1079.         return;
  1080.     if (isset(GLOBASSIGN) || v->type != PM_SCALAR)
  1081.         globlist(vl);
  1082.     if (errflag)
  1083.         return;
  1084.     if (v->type == PM_SCALAR && (empty(vl) || !nextnode(firstnode(vl)))) {
  1085.         Param pm;
  1086.         char *val;
  1087.         int allexp;
  1088.  
  1089.         if (empty(vl))
  1090.         val = ztrdup("");
  1091.         else {
  1092.         untokenize(peekfirst(vl));
  1093.         val = ztrdup(ugetnode(vl));
  1094.         }
  1095.         if (xtr)
  1096.         fprintf(stderr, "%s ", val);
  1097.         if (export) {
  1098.         if (export < 0)
  1099.             /* We are going to fork so do not bother freeing this */
  1100.             paramtab->removenode(paramtab, v->name);
  1101.         allexp = opts[ALLEXPORT];
  1102.         opts[ALLEXPORT] = 1;
  1103.         pm = setsparam(v->name, ztrdup(val));
  1104.         opts[ALLEXPORT] = allexp;
  1105.         } else
  1106.         pm = setsparam(v->name, ztrdup(val));
  1107.         if (errflag)
  1108.         return;
  1109.         zsfree(val);
  1110.         continue;
  1111.     }
  1112.     ptr = arr = (char **) zalloc(sizeof(char **) * (countlinknodes(vl) + 1));
  1113.  
  1114.     while (nonempty(vl))
  1115.         *ptr++ = ztrdup((char *) ugetnode(vl));
  1116.  
  1117.     *ptr = NULL;
  1118.     if (xtr) {
  1119.         fprintf(stderr, "( ");
  1120.         for (ptr = arr; *ptr; ptr++)
  1121.         fprintf(stderr, "%s ", *ptr);
  1122.         fprintf(stderr, ") ");
  1123.     }
  1124.     setaparam(v->name, arr);
  1125.     if (errflag)
  1126.         return;
  1127.     }
  1128. }
  1129.  
  1130. /**/
  1131. void
  1132. execcmd(Cmd cmd, int input, int output, int how, int last1)
  1133. {
  1134.     HashNode hn = NULL;
  1135.     LinkNode node;
  1136.     Redir fn;
  1137.     struct multio *mfds[10];
  1138.     char *text;
  1139.     int save[10];
  1140.     int fil, dfil, is_cursh, type, i;
  1141.     int nullexec = 0, assign = 0, forked = 0;
  1142.     int is_shfunc = 0, is_builtin = 0, is_exec = 0;
  1143.     /* Various flags to the command. */
  1144.     int cflags = 0, checked = 0;
  1145.  
  1146.     doneps4 = 0;
  1147.     args = cmd->args;
  1148.     type = cmd->type;
  1149.  
  1150.     for (i = 0; i < 10; i++) {
  1151.     save[i] = -2;
  1152.     mfds[i] = NULL;
  1153.     }
  1154.  
  1155.     /* If the command begins with `%', then assume it is a *
  1156.      * reference to a job in the job table.                */
  1157.     if (type == SIMPLE && nonempty(args) &&
  1158.     *(char *)peekfirst(args) == '%') {
  1159.     pushnode(args, dupstring((how & Z_DISOWN)
  1160.                  ? "disown" : (how & Z_ASYNC) ? "bg" : "fg"));
  1161.     how = Z_SYNC;
  1162.     }
  1163.  
  1164.     /* If AUTORESUME is set, the command is SIMPLE, and doesn't have *
  1165.      * any redirections, then check if it matches as a prefix of a   *
  1166.      * job currently in the job table.  If it does, then we treat it *
  1167.      * as a command to resume this job.                              */
  1168.     if (isset(AUTORESUME) && type == SIMPLE && (how & Z_SYNC) &&
  1169.     nonempty(args) && empty(cmd->redir) && !input &&
  1170.     !nextnode(firstnode(args))) {
  1171.     if (unset(NOTIFY))
  1172.         scanjobs();
  1173.     if (findjobnam(peekfirst(args)) != -1)
  1174.         pushnode(args, dupstring("fg"));
  1175.     }
  1176.  
  1177.     /* Check if it's a builtin needing automatic MAGIC_EQUALS_SUBST      *
  1178.      * handling.  Things like typeset need this.  We can't detect the    *
  1179.      * command if it contains some tokens (e.g. x=ex; ${x}port), so this *
  1180.      * only works in simple cases.  has_token() is called to make sure   *
  1181.      * this really is a simple case.                                     */
  1182.     if (type == SIMPLE) {
  1183.     while (nonempty(args)) {
  1184.         char *cmdarg = (char *) peekfirst(args);
  1185.         checked = !has_token(cmdarg);
  1186.         if (!checked)
  1187.         break;
  1188.         if (!(cflags & (BINF_BUILTIN | BINF_COMMAND)) &&
  1189.         (hn = shfunctab->getnode(shfunctab, cmdarg))) {
  1190.         is_shfunc = 1;
  1191.         break;
  1192.         }
  1193.         if (!(hn = builtintab->getnode(builtintab, cmdarg))) {
  1194.         checked = !(cflags & BINF_BUILTIN);
  1195.         break;
  1196.         }
  1197.         if (!(hn->flags & BINF_PREFIX)) {
  1198.         is_builtin = 1;
  1199.         assign = (hn->flags & BINF_MAGICEQUALS);
  1200.         break;
  1201.         }
  1202.         cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
  1203.         cflags |= hn->flags;
  1204.         uremnode(args, firstnode(args));
  1205.         hn = NULL;
  1206.         checked = 0;
  1207.         if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS))
  1208.         break;
  1209.     }
  1210.     }
  1211.  
  1212.     /* Do prefork substitutions */
  1213.     prefork(args, assign ? 2 : isset(MAGICEQUALSUBST));
  1214.  
  1215.     if (type == SIMPLE) {
  1216.     int unglobbed = 0;
  1217.  
  1218.     for (;;) {
  1219.         char *cmdarg;
  1220.  
  1221.         if (!(cflags & BINF_NOGLOB))
  1222.         while (!checked && !errflag && nonempty(args) &&
  1223.                has_token((char *) peekfirst(args)))
  1224.             glob(args, firstnode(args));
  1225.         else if (!unglobbed) {
  1226.         for (node = firstnode(args); node; incnode(node))
  1227.             untokenize((char *) getdata(node));
  1228.         unglobbed = 1;
  1229.         }
  1230.  
  1231.         /* Current shell should not fork unless the *
  1232.          * exec occurs at the end of a pipeline.    */
  1233.         if ((cflags & BINF_EXEC) && last1 == 2)
  1234.         cmd->flags |= CFLAG_EXEC;
  1235.  
  1236.         /* Empty command */
  1237.         if (empty(args)) {
  1238.         if (nonempty(cmd->redir)) {
  1239.             if (cmd->flags & CFLAG_EXEC) {
  1240.             /* Was this "exec < foobar"? */
  1241.             nullexec = 1;
  1242.             break;
  1243.             } else if (!nullcmd || !*nullcmd ||
  1244.                    (cflags & BINF_PREFIX)) {
  1245.             zerr("redirection with no command", NULL, 0);
  1246.             errflag = lastval = 1;
  1247.             return;
  1248.             } else if (readnullcmd && *readnullcmd &&
  1249.                    ((Redir) peekfirst(cmd->redir))->type == READ &&
  1250.                    !nextnode(firstnode(cmd->redir))) {
  1251.             addlinknode(args, dupstring(readnullcmd));
  1252.             } else
  1253.             addlinknode(args, dupstring(nullcmd));
  1254.         } else if ((cflags & BINF_PREFIX) && (cflags & BINF_COMMAND)) {
  1255.             lastval = 0;
  1256.             return;
  1257.         } else {
  1258.             cmdoutval = 0;
  1259.             addvars(cmd->vars, 0);
  1260.             if (errflag)
  1261.             lastval = errflag;
  1262.             else
  1263.             lastval = cmdoutval;
  1264.             if (isset(XTRACE)) {
  1265.             fputc('\n', stderr);
  1266.             fflush(stderr);
  1267.             }
  1268.             return;
  1269.         }
  1270.         }
  1271.  
  1272.         if (errflag || checked ||
  1273.         (unset(POSIXBUILTINS) && (cflags & BINF_COMMAND)))
  1274.         break;
  1275.  
  1276.         cmdarg = (char *) peekfirst(args);
  1277.         if (!(cflags & (BINF_BUILTIN | BINF_COMMAND)) &&
  1278.         (hn = shfunctab->getnode(shfunctab, cmdarg))) {
  1279.         is_shfunc = 1;
  1280.         break;
  1281.         }
  1282.         if (!(hn = builtintab->getnode(builtintab, cmdarg))) {
  1283.         if (cflags & BINF_BUILTIN) {
  1284.             zerr("no such builtin: %s", cmdarg, 0);
  1285.             errflag = lastval = 1;
  1286.             return;
  1287.         }
  1288.         break;
  1289.         }
  1290.         if (!(hn->flags & BINF_PREFIX)) {
  1291.         is_builtin = 1;
  1292.         break;
  1293.         }
  1294.         cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
  1295.         cflags |= hn->flags;
  1296.         uremnode(args, firstnode(args));
  1297.         hn = NULL;
  1298.     }
  1299.     }
  1300.  
  1301.     if (errflag) {
  1302.     lastval = 1;
  1303.     return;
  1304.     }
  1305.  
  1306.     /* Get the text associated with this command. */
  1307.     if (jobbing || (how & Z_TIMED))
  1308.     text = getjobtext((void *) cmd);
  1309.     else
  1310.     text = NULL;
  1311.  
  1312.     /* Set up special parameter $_ */
  1313.     zsfree(underscore);
  1314.     if (nonempty(args)
  1315.     && (underscore = ztrdup((char *) getdata(lastnode(args)))))
  1316.     untokenize(underscore); 
  1317.     else
  1318.       underscore = ztrdup("");
  1319.  
  1320.     /* Warn about "rm *" */
  1321.     if (type == SIMPLE && interact && unset(RMSTARSILENT)
  1322.     && isset(SHINSTDIN) && nonempty(args) && nextnode(firstnode(args))
  1323.     && !strcmp(peekfirst(args), "rm")) {
  1324.     LinkNode node, next;
  1325.  
  1326.     for (node = nextnode(firstnode(args)); node && !errflag; node = next) {
  1327.         char *s = (char *) getdata(node);
  1328.         int l = strlen(s);
  1329.  
  1330.         next = nextnode(node);
  1331.         if (s[0] == Star && !s[1]) {
  1332.         if (!checkrmall(pwd))
  1333.             uremnode(args, node);
  1334.         } else if (l > 2 && s[l - 2] == '/' && s[l - 1] == Star) {
  1335.         char t = s[l - 2];
  1336.  
  1337.         s[l - 2] = 0;
  1338.         if (!checkrmall(s))
  1339.             uremnode(args, node);
  1340.         s[l - 2] = t;
  1341.         }
  1342.     }
  1343.     if (!nextnode(firstnode(args)))
  1344.         errflag = 1;
  1345.     }
  1346.  
  1347.     if (errflag) {
  1348.     lastval = 1;
  1349.     return;
  1350.     }
  1351.  
  1352.     if (type == SIMPLE && !nullexec) {
  1353.     char *s;
  1354.  
  1355.     DPUTS(empty(args), "BUG: empty(args) in exec.c");
  1356.     if (!hn) {
  1357.         /* Resolve external commands */
  1358.         char *cmdarg = (char *) peekfirst(args);
  1359.  
  1360.         hn = cmdnamtab->getnode(cmdnamtab, cmdarg);
  1361.         if (!hn && isset(HASHCMDS) && strcmp(cmdarg, "..")) {
  1362.         for (s = cmdarg; *s && *s != '/'; s++);
  1363.         if (!*s)
  1364.             hn = (HashNode) hashcmd(cmdarg, pathchecked);
  1365.         }
  1366.     }
  1367.  
  1368.     /* If no command found yet, see if it  *
  1369.      * is a directory we should AUTOCD to. */
  1370.     if (!hn && isset(AUTOCD) && isset(SHINSTDIN) && empty(cmd->redir)
  1371.         && !nextnode(firstnode(args)) && *(char *)peekfirst(args)
  1372.         && (s = cancd(peekfirst(args)))) {
  1373.         peekfirst(args) = (void *) s;
  1374.         pushnode(args, dupstring("cd"));
  1375.         if ((hn = builtintab->getnode(builtintab, "cd")))
  1376.         is_builtin = 1;
  1377.     }
  1378.     }
  1379.  
  1380.     /* This is nonzero if the command is a current shell procedure? */
  1381.     is_cursh = (is_builtin || is_shfunc || (type >= CURSH) || nullexec);
  1382.  
  1383.     /**************************************************************************
  1384.      * Do we need to fork?  We need to fork if:                               *
  1385.      * 1) The command is supposed to run in the background. (or)              *
  1386.      * 2) There is no `exec' flag, and either:                                *
  1387.      *    a) This is a builtin or shell function with output piped somewhere. *
  1388.      *    b) This is an external command and we can't do a `fake exec'.       *
  1389.      *                                                                        *
  1390.      * A `fake exec' is possible if we have all the following conditions:     *
  1391.      * 1) last1 flag is 1.  This indicates that the current shell will not    *
  1392.      *    be needed after the current command.  This is typically the case    *
  1393.      *    when when the command is the last stage in a subshell, or is the    *
  1394.      *    last command after the option `-c'.                                 *
  1395.      * 2) We are not trapping EXIT or ZERR.                                   *
  1396.      * 3) We don't have any files to delete.                                  *
  1397.      *                                                                        *
  1398.      * The condition above for a `fake exec' will also work for a current     *
  1399.      * shell command such as a builtin, but doesn't really buy us anything    *
  1400.      * (doesn't save us a process), since it is already running in the        *
  1401.      * current shell.                                                         *
  1402.      **************************************************************************/
  1403.  
  1404.     if ((how & Z_ASYNC) || (!(cmd->flags & CFLAG_EXEC) &&
  1405.        (((is_builtin || is_shfunc) && output) ||
  1406.        (!is_cursh && (last1 != 1 || sigtrapped[SIGZERR] ||
  1407.         sigtrapped[SIGEXIT] || havefiles()))))) {
  1408.  
  1409.     pid_t pid;
  1410.     int synch[2];
  1411.     char dummy;
  1412.  
  1413.     child_block();
  1414.     pipe(synch);
  1415.  
  1416.     if ((pid = zfork()) == -1) {
  1417.         close(synch[0]);
  1418.         close(synch[1]);
  1419.         return;
  1420.     } if (pid) {
  1421.         close(synch[1]);
  1422.         read(synch[0], &dummy, 1);
  1423.         close(synch[0]);
  1424. #ifdef PATH_DEV_FD
  1425.         closem(2);
  1426. #endif
  1427.         if (how & Z_ASYNC) {
  1428.         lastpid = (long) pid;
  1429.         } else if (!jobtab[thisjob].stty_in_env && nonempty(cmd->vars)) {
  1430.         /* search for STTY=... */
  1431.         while (nonempty(cmd->vars))
  1432.             if (!strcmp(((Varasg) ugetnode(cmd->vars))->name, "STTY")) {
  1433.             jobtab[thisjob].stty_in_env = 1;
  1434.             break;
  1435.             }
  1436.         }
  1437.         addproc(pid, text);
  1438.         return;
  1439.     }
  1440.     /* pid == 0 */
  1441.     close(synch[0]);
  1442.     entersubsh(how, type != SUBSH && !(how & Z_ASYNC) ? 2 : 1, 0);
  1443.     close(synch[1]);
  1444.     forked = 1;
  1445.     if (sigtrapped[SIGINT] & ZSIG_IGNORED)
  1446.         holdintr();
  1447.     /* Check if we should run background jobs at a lower priority. */
  1448.     if ((how & Z_ASYNC) && isset(BGNICE))
  1449.         nice(5);
  1450.  
  1451.     } else if (is_cursh) {
  1452.     /* This is a current shell procedure that didn't need to fork.    *
  1453.      * This includes current shell procedures that are being exec'ed, *
  1454.      * as well as null execs.                                         */
  1455.     jobtab[thisjob].stat |= STAT_CURSH;
  1456.     } else {
  1457.     /* This is an exec (real or fake) for an external command.    *
  1458.      * Note that any form of exec means that the subshell is fake *
  1459.      * (but we may be in a subshell already).                     */
  1460.     is_exec = 1;
  1461.     }
  1462.  
  1463.     if (!(cflags & BINF_NOGLOB))
  1464.     globlist(args);
  1465.     if (errflag) {
  1466.     lastval = 1;
  1467.     goto err;
  1468.     }
  1469.  
  1470.     /* Add pipeline input/output to mnodes */
  1471.     if (input)
  1472.     addfd(forked, save, mfds, 0, input, 0);
  1473.     if (output)
  1474.     addfd(forked, save, mfds, 1, output, 1);
  1475.  
  1476.     /* Do process substitutions */
  1477.     spawnpipes(cmd->redir);
  1478.  
  1479.     /* Do io redirections */
  1480.     while (nonempty(cmd->redir)) {
  1481.     fn = (Redir) ugetnode(cmd->redir);
  1482.     DPUTS(fn->type == HEREDOC || fn->type == HEREDOCDASH,
  1483.           "BUG: unexpanded here document\n");
  1484.     if (fn->type == INPIPE) {
  1485.         if (fn->fd2 == -1) {
  1486.         closemnodes(mfds);
  1487.         fixfds(save);
  1488.         execerr();
  1489.         }
  1490.         addfd(forked, save, mfds, fn->fd1, fn->fd2, 0);
  1491.     } else if (fn->type == OUTPIPE) {
  1492.         if (fn->fd2 == -1) {
  1493.         closemnodes(mfds);
  1494.         fixfds(save);
  1495.         execerr();
  1496.         }
  1497.         addfd(forked, save, mfds, fn->fd1, fn->fd2, 1);
  1498.     } else {
  1499.         if (fn->type != HERESTR && xpandredir(fn, cmd->redir))
  1500.         continue;
  1501.         if (errflag) {
  1502.         closemnodes(mfds);
  1503.         fixfds(save);
  1504.         execerr();
  1505.         }
  1506.         if (unset(EXECOPT))
  1507.         continue;
  1508.         switch(fn->type) {
  1509.         case HERESTR:
  1510.         fil = getherestr(fn);
  1511.         if (fil == -1) {
  1512.             closemnodes(mfds);
  1513.             fixfds(save);
  1514.             if (errno != EINTR)
  1515.             zerr("%e", NULL, errno);
  1516.             execerr();
  1517.         }
  1518.         addfd(forked, save, mfds, fn->fd1, fil, 0);
  1519.         break;
  1520.         case READ:
  1521.         case READWRITE:
  1522.         if (fn->type == READ)
  1523.             fil = open(unmeta(fn->name), O_RDONLY);
  1524.         else
  1525.             fil = open(unmeta(fn->name), O_RDWR | O_CREAT, 0666);
  1526.         if (fil == -1) {
  1527.             closemnodes(mfds);
  1528.             fixfds(save);
  1529.             if (errno != EINTR)
  1530.             zerr("%e: %s", fn->name, errno);
  1531.             execerr();
  1532.         }
  1533.         addfd(forked, save, mfds, fn->fd1, fil, 0);
  1534.         /* If this is 'exec < file', read from stdin, *
  1535.          * not terminal, unless `file' is a terminal. */
  1536.         if (nullexec && fn->fd1 == 0 && isset(SHINSTDIN) && interact)
  1537.             init_io();
  1538.         break;
  1539.         case CLOSE:
  1540.         if (!forked && fn->fd1 < 10 && save[fn->fd1] == -2)
  1541.             save[fn->fd1] = movefd(fn->fd1);
  1542.         closemn(mfds, fn->fd1);
  1543.         zclose(fn->fd1);
  1544.         break;
  1545.         case MERGEIN:
  1546.         case MERGEOUT:
  1547.         if(fn->fd2 < 10)
  1548.             closemn(mfds, fn->fd2);
  1549.         fil = dup(fn->fd2);
  1550.         if (fil == -1) {
  1551.             char fdstr[4];
  1552.  
  1553.             closemnodes(mfds);
  1554.             fixfds(save);
  1555.             sprintf(fdstr, "%d", fn->fd2);
  1556.             zerr("%s: %e", fdstr, errno);
  1557.             execerr();
  1558.         }
  1559.         addfd(forked, save, mfds, fn->fd1, fil, fn->type == MERGEOUT);
  1560.         break;
  1561.         default:
  1562.         if (IS_APPEND_REDIR(fn->type))
  1563.             fil = open(unmeta(fn->name),
  1564.                    (unset(CLOBBER) && !IS_CLOBBER_REDIR(fn->type)) ?
  1565.                    O_WRONLY | O_APPEND : O_WRONLY | O_APPEND | O_CREAT, 0666);
  1566.         else
  1567.             fil = clobber_open(fn);
  1568.         if(fil != -1 && IS_ERROR_REDIR(fn->type))
  1569.             dfil = dup(fil);
  1570.         else
  1571.             dfil = 0;
  1572.         if (fil == -1 || dfil == -1) {
  1573.             if(fil != -1)
  1574.             close(fil);
  1575.             closemnodes(mfds);
  1576.             fixfds(save);
  1577.             if (errno != EINTR)
  1578.             zerr("%e: %s", fn->name, errno);
  1579.             execerr();
  1580.         }
  1581.         addfd(forked, save, mfds, fn->fd1, fil, 1);
  1582.         if(IS_ERROR_REDIR(fn->type))
  1583.             addfd(forked, save, mfds, 2, dfil, 1);
  1584.         break;
  1585.         }
  1586.     }
  1587.     }
  1588.  
  1589.     /* We are done with redirection.  close the mnodes, *
  1590.      * spawning tee/cat processes as necessary.         */
  1591.     for (i = 0; i < 10; i++)
  1592.     closemn(mfds, i);
  1593.  
  1594.     if (nullexec) {
  1595.     for (i = 0; i < 10; i++)
  1596.         if (save[i] != -2)
  1597.         zclose(save[i]);
  1598.     /*
  1599.      * Here we specifically *don't* restore the original fd's
  1600.      * before returning.
  1601.      */
  1602.     return;
  1603.     }
  1604.  
  1605.     if (isset(EXECOPT) && !errflag) {
  1606.     /*
  1607.      * We delay the entersubsh() to here when we are exec'ing
  1608.      * the current shell (including a fake exec to run a builtin then
  1609.      * exit) in case there is an error return.
  1610.      */
  1611.     if (is_exec)
  1612.         entersubsh(how, type != SUBSH ? 2 : 1, 1);
  1613.     if (type >= CURSH) {
  1614.         static int (*func[]) _((Cmd)) = {
  1615.         execcursh, exectime, execfuncdef, execfor, execwhile,
  1616.         execrepeat, execif, execcase, execselect, execcond,
  1617.         execarith
  1618.         };
  1619.  
  1620.         if (last1 == 1)
  1621.         cmd->flags |= CFLAG_EXEC;
  1622.         lastval = (func[type - CURSH]) (cmd);
  1623.     } else if (is_builtin || is_shfunc) {
  1624.         LinkList restorelist = 0, removelist = 0;
  1625.         /* builtin or shell function */
  1626.  
  1627.         if (!forked && ((cflags & BINF_COMMAND) ||
  1628.                 (unset(POSIXBUILTINS) && !assign) ||
  1629.                 (isset(POSIXBUILTINS) && !is_shfunc &&
  1630.                  !(hn->flags & BINF_PSPECIAL))))
  1631.         save_params(cmd, &restorelist, &removelist);
  1632.  
  1633.         if (cmd->vars) {
  1634.         /* Export this if the command is a shell function,
  1635.          * but not if it's a builtin.
  1636.          */
  1637.         addvars(cmd->vars, is_shfunc);
  1638.         if (errflag) {
  1639.             restore_params(restorelist, removelist);
  1640.             lastval = 1;
  1641.             fixfds(save);
  1642.             return;
  1643.         }
  1644.         }
  1645.  
  1646.         if (is_shfunc) {
  1647.         /* It's a shell function */
  1648. #ifdef PATH_DEV_FD
  1649.         int i;
  1650.  
  1651.         for (i = 10; i <= max_zsh_fd; i++)
  1652.             if (fdtable[i] > 1)
  1653.             fdtable[i]++;
  1654. #endif
  1655.         if (subsh_close >= 0)
  1656.             zclose(subsh_close);
  1657.         subsh_close = -1;
  1658.         execshfunc(cmd, (Shfunc) hn);
  1659. #ifdef PATH_DEV_FD
  1660.         for (i = 10; i <= max_zsh_fd; i++)
  1661.             if (fdtable[i] > 1)
  1662.             if (--(fdtable[i]) <= 2)
  1663.                 zclose(i);
  1664. #endif
  1665.         } else {
  1666.         /* It's a builtin */
  1667.         if (forked)
  1668.             closem(1);
  1669.         lastval = execbuiltin(args, (Builtin) hn);
  1670. #ifdef PATH_DEV_FD
  1671.         closem(2);
  1672. #endif
  1673.         if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) && lastval && !subsh) {
  1674.             fprintf(stderr, "zsh: exit %ld\n", (long)lastval);
  1675.         }
  1676.         fflush(stdout);
  1677.         if (save[1] == -2) {
  1678.             if (ferror(stdout)) {
  1679.             zerr("write error: %e", NULL, errno);
  1680.             clearerr(stdout);
  1681.             errflag = 0;
  1682.             }
  1683.         } else
  1684.             clearerr(stdout);
  1685.         }
  1686.  
  1687.         if (cmd->flags & CFLAG_EXEC) {
  1688.         if (subsh)
  1689.             _exit(lastval);
  1690.  
  1691.         /* If we are exec'ing a command, and we are not in a subshell, *
  1692.          * then check if we should save the history file.              */
  1693.         if (isset(RCS) && interact && !nohistsave)
  1694.             savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0);
  1695.         exit(lastval);
  1696.         }
  1697.  
  1698.         restore_params(restorelist, removelist);
  1699.  
  1700.     } else {
  1701.         if (cmd->flags & CFLAG_EXEC) {
  1702.         setiparam("SHLVL", --shlvl);
  1703.         /* If we are exec'ing a command, and we are not *
  1704.          * in a subshell, then save the history file.   */
  1705.         if (!subsh && isset(RCS) && interact && !nohistsave)
  1706.             savehistfile(getsparam("HISTFILE"), 1, isset(APPENDHISTORY) ? 3 : 0);
  1707.         }
  1708.         if (type == SIMPLE) {
  1709.         if (cmd->vars) {
  1710.             addvars(cmd->vars, -1);
  1711.             if (errflag)
  1712.             _exit(1);
  1713.         }
  1714.         closem(1);
  1715.         if (coprocin)
  1716.             zclose(coprocin);
  1717.         if (coprocout)
  1718.             zclose(coprocout);
  1719. #ifdef HAVE_GETRLIMIT
  1720.         if (!forked)
  1721.             setlimits(NULL);
  1722. #endif
  1723.         execute((Cmdnam) hn, cflags & BINF_DASH);
  1724.         } else {        /* ( ... ) */
  1725.         DPUTS(cmd->vars && nonempty(cmd->vars),
  1726.               "BUG: assigment before complex command.");
  1727.         list_pipe = 0;
  1728.         if (subsh_close >= 0)
  1729.             zclose(subsh_close);
  1730.                 subsh_close = -1;
  1731.         /* If we're forked (and we should be), no need to return */
  1732.         DPUTS(last1 != 1 && !forked, "BUG? not exiting?");
  1733.         execlist(cmd->u.list, 0, 1);
  1734.         }
  1735.     }
  1736.     }
  1737.  
  1738.   err:
  1739.     if (forked)
  1740.     _exit(lastval);
  1741.     fixfds(save);
  1742. }
  1743.  
  1744. /* Arrange to have variables restored. */
  1745.  
  1746. /**/
  1747. void
  1748. save_params(Cmd cmd, LinkList *restore_p, LinkList *remove_p)
  1749. {
  1750.     Param pm;
  1751.     LinkNode node;
  1752.     char *s;
  1753.  
  1754.     MUSTUSEHEAP("save_params()");
  1755.  
  1756.     *restore_p = newlinklist();
  1757.     *remove_p = newlinklist();
  1758.  
  1759.     for (node = firstnode(cmd->vars); node; incnode(node)) {
  1760.     s = ((Varasg) getdata(node))->name;
  1761.     if ((pm = (Param) paramtab->getnode(paramtab, s))) {
  1762.         if (!(pm->flags & PM_SPECIAL)) {
  1763.         paramtab->removenode(paramtab, s);
  1764.         } else if (!(pm->flags & PM_READONLY)) {
  1765.         Param tpm = (Param) alloc(sizeof *tpm);
  1766.  
  1767.         tpm->nam = s;
  1768.         tpm->flags = pm->flags;
  1769.         switch (PM_TYPE(pm->flags)) {
  1770.         case PM_SCALAR:
  1771.             tpm->u.str = ztrdup(pm->gets.cfn(pm));
  1772.             break;
  1773.         case PM_INTEGER:
  1774.             tpm->u.val = pm->gets.ifn(pm);
  1775.             break;
  1776.         case PM_ARRAY:
  1777.             PERMALLOC {
  1778.             tpm->u.arr = arrdup(pm->gets.afn(pm));
  1779.             } LASTALLOC;
  1780.             break;
  1781.         }
  1782.         pm = tpm;
  1783.         }
  1784.         addlinknode(*remove_p, s);
  1785.         addlinknode(*restore_p, pm);
  1786.     } else {
  1787.         addlinknode(*remove_p, s);
  1788.     }
  1789.     }
  1790. }
  1791.  
  1792. /* Restore saved parameters after executing a shfunc or builtin */
  1793.  
  1794. /**/
  1795. void
  1796. restore_params(LinkList restorelist, LinkList removelist)
  1797. {
  1798.     Param pm;
  1799.     char *s;
  1800.  
  1801.     if (removelist) {
  1802.     /* remove temporary parameters */
  1803.     while ((s = (char *) ugetnode(removelist))) {
  1804.         if ((pm = (Param) paramtab->getnode(paramtab, s)) &&
  1805.         !(pm->flags & PM_SPECIAL)) {
  1806.         pm->flags &= ~PM_READONLY;
  1807.         unsetparam_pm(pm, 0);
  1808.         }
  1809.     }
  1810.     }
  1811.  
  1812.     if (restorelist) {
  1813.     /* restore saved parameters */
  1814.     while ((pm = (Param) ugetnode(restorelist))) {
  1815.         if (pm->flags & PM_SPECIAL) {
  1816.         Param tpm = (Param) paramtab->getnode(paramtab, pm->nam);
  1817.  
  1818.         DPUTS(!tpm || PM_TYPE(pm->flags) != PM_TYPE(tpm->flags) ||
  1819.               !(pm->flags & PM_SPECIAL),
  1820.               "BUG in restoring special parameters.");
  1821.         tpm->flags = pm->flags;
  1822.         switch (PM_TYPE(pm->flags)) {
  1823.         case PM_SCALAR:
  1824.             tpm->sets.cfn(tpm, pm->u.str);
  1825.             break;
  1826.         case PM_INTEGER:
  1827.             tpm->sets.ifn(tpm, pm->u.val);
  1828.             break;
  1829.         case PM_ARRAY:
  1830.             tpm->sets.afn(tpm, pm->u.arr);
  1831.             break;
  1832.         }
  1833.         } else
  1834.         paramtab->addnode(paramtab, pm->nam, pm);
  1835.         if (pm->flags & PM_EXPORTED)
  1836.         pm->env = addenv(pm->nam, getsparam(pm->nam));
  1837.     }
  1838.     }
  1839. }
  1840.  
  1841. /* restore fds after redirecting a builtin */
  1842.  
  1843. /**/
  1844. void
  1845. fixfds(int *save)
  1846. {
  1847.     int old_errno = errno;
  1848.     int i;
  1849.  
  1850.     for (i = 0; i != 10; i++)
  1851.     if (save[i] != -2)
  1852.         redup(save[i], i);
  1853.     errno = old_errno;
  1854. }
  1855.  
  1856. /**/
  1857. void
  1858. entersubsh(int how, int cl, int fake)
  1859. {
  1860.     int sig;
  1861.  
  1862.     if (cl != 2)
  1863.     for (sig = 0; sig < VSIGCOUNT; sig++)
  1864.         if (!(sigtrapped[sig] & ZSIG_FUNC))
  1865.         unsettrap(sig);
  1866.     if (unset(MONITOR)) {
  1867.     if (how & Z_ASYNC) {
  1868.         settrap(SIGINT, NULL);
  1869.         settrap(SIGQUIT, NULL);
  1870.         if (isatty(0)) {
  1871.         close(0);
  1872.         if (open("/dev/null", O_RDWR)) {
  1873.             zerr("can't open /dev/null: %e", NULL, errno);
  1874.             _exit(1);
  1875.         }
  1876.         }
  1877.     }
  1878.     } else if (thisjob != -1 && cl) {
  1879.     if (jobtab[list_pipe_job].gleader && (list_pipe || list_pipe_child)) {
  1880.         if (kill(jobtab[list_pipe_job].gleader, 0) == -1 ||
  1881.         setpgrp(0L, jobtab[list_pipe_job].gleader) == -1) {
  1882.         jobtab[list_pipe_job].gleader =
  1883.             jobtab[thisjob].gleader = mypgrp;
  1884.         setpgrp(0L, mypgrp);
  1885.  
  1886.         if (how & Z_SYNC)
  1887.             attachtty(jobtab[thisjob].gleader);
  1888.         }
  1889.     }
  1890.     else if (!jobtab[thisjob].gleader ||
  1891.          (setpgrp(0L, jobtab[thisjob].gleader) == -1)) {
  1892.         jobtab[thisjob].gleader = getpid();
  1893.         if (list_pipe_job != thisjob &&
  1894.         !jobtab[list_pipe_job].gleader)
  1895.         jobtab[list_pipe_job].gleader = jobtab[thisjob].gleader;
  1896.         setpgrp(0L, jobtab[thisjob].gleader);
  1897.         if (how & Z_SYNC)
  1898.         attachtty(jobtab[thisjob].gleader);
  1899.     }
  1900.     }
  1901.     if (!fake)
  1902.     subsh = 1;
  1903.     if (SHTTY != -1) {
  1904.     zclose(SHTTY);
  1905.     SHTTY = -1;
  1906.     }
  1907.     if (isset(MONITOR)) {
  1908.     signal_default(SIGTTOU);
  1909.     signal_default(SIGTTIN);
  1910.     signal_default(SIGTSTP);
  1911.     }
  1912.     if (interact) {
  1913.     signal_default(SIGTERM);
  1914.     if (!(sigtrapped[SIGINT] & ZSIG_IGNORED))
  1915.         signal_default(SIGINT);
  1916.     }
  1917.     if (!(sigtrapped[SIGQUIT] & ZSIG_IGNORED))
  1918.     signal_default(SIGQUIT);
  1919.     opts[MONITOR] = opts[USEZLE] = 0;
  1920.     zleactive = 0;
  1921.     if (cl)
  1922.     clearjobtab();
  1923.     times(&shtms);
  1924. }
  1925.  
  1926. /* close internal shell fds */
  1927.  
  1928. /**/
  1929. void
  1930. closem(int how)
  1931. {
  1932.     int i;
  1933.  
  1934.     for (i = 10; i <= max_zsh_fd; i++)
  1935.     if (fdtable[i] && (!how || fdtable[i] == how))
  1936.         zclose(i);
  1937. }
  1938.  
  1939. /* convert here document into a here string */
  1940.  
  1941. /**/
  1942. char *
  1943. gethere(char *str, int typ)
  1944. {
  1945.     char *buf;
  1946.     int bsiz, qt = 0, strip = 0;
  1947.     char *s, *t, *bptr, c;
  1948.  
  1949.     for (s = str; *s; s++)
  1950.     if (INULL(*s)) {
  1951.         *s = Nularg;
  1952.         qt = 1;
  1953.     }
  1954.     untokenize(str);
  1955.     if (typ == HEREDOCDASH) {
  1956.     strip = 1;
  1957.     while (*str == '\t')
  1958.         str++;
  1959.     }
  1960.     bptr = buf = zalloc(bsiz = 256);
  1961.     for (;;) {
  1962.     t = bptr;
  1963.  
  1964.     while ((c = hgetc()) == '\t' && strip)
  1965.         ;
  1966.     for (;;) {
  1967.         if (bptr == buf + bsiz) {
  1968.         buf = realloc(buf, 2 * bsiz);
  1969.         t = buf + bsiz - (bptr - t);
  1970.         bptr = buf + bsiz;
  1971.         bsiz *= 2;
  1972.         }
  1973.         if (lexstop || c == '\n')
  1974.         break;
  1975.         *bptr++ = c;
  1976.         c = hgetc();
  1977.     }
  1978.     *bptr = '\0';
  1979.     if (!strcmp(t, str))
  1980.         break;
  1981.     if (lexstop) {
  1982.         t = bptr;
  1983.         break;
  1984.     }
  1985.     *bptr++ = '\n';
  1986.     }
  1987.     if (t > buf && t[-1] == '\n')
  1988.     t--;
  1989.     *t = '\0';
  1990.     if (!qt)
  1991.     parsestr(buf);
  1992.     s = dupstring(buf);
  1993.     zfree(buf, bsiz);
  1994.     return s;
  1995. }
  1996.  
  1997. /* open here string fd */
  1998.  
  1999. /**/
  2000. int
  2001. getherestr(struct redir *fn)
  2002. {
  2003.     char *s, *t;
  2004.     int fd, len;
  2005.  
  2006.     t = fn->name;
  2007.     singsub(&t);
  2008.     untokenize(t);
  2009.     unmetafy(t, &len);
  2010.     t[len++] = '\n';
  2011.     s = gettempname();
  2012.     if (!s || (fd = open(s, O_CREAT | O_WRONLY | O_EXCL, 0600)) == -1)
  2013.     return -1;
  2014.     write(fd, t, len);
  2015.     close(fd);
  2016.     fd = open(s, O_RDONLY);
  2017.     unlink(s);
  2018.     return fd;
  2019. }
  2020.  
  2021. /* $(...) */
  2022.  
  2023. /**/
  2024. LinkList
  2025. getoutput(char *cmd, int qt)
  2026. {
  2027.     List list;
  2028.     int pipes[2];
  2029.     pid_t pid;
  2030.     Cmd c;
  2031.     Redir r;
  2032.  
  2033.     if (!(list = parse_string(cmd)))
  2034.     return NULL;
  2035.     if (list != &dummy_list && !list->right && !list->left->flags &&
  2036.     list->left->type == END && list->left->left->type == END &&
  2037.     (c = list->left->left->left)->type == SIMPLE && empty(c->args) &&
  2038.     empty(c->vars) && nonempty(c->redir) &&
  2039.     !nextnode(firstnode(c->redir)) &&
  2040.     (r = (Redir) getdata(firstnode(c->redir)))->fd1 == 0 &&
  2041.     r->type == READ) {
  2042.     /* $(< word) */
  2043.     int stream;
  2044.     char *s = r->name;
  2045.  
  2046.     singsub(&s);
  2047.     if (errflag)
  2048.         return NULL;
  2049.     untokenize(s);
  2050.     if ((stream = open(unmeta(s), O_RDONLY)) == -1) {
  2051.         zerr("%e: %s", s, errno);
  2052.         return NULL;
  2053.     }
  2054.     return readoutput(stream, qt);
  2055.     }
  2056.  
  2057.     mpipe(pipes);
  2058.     child_block();
  2059.     cmdoutval = 0;
  2060.     if ((cmdoutpid = pid = zfork()) == -1) {
  2061.     /* fork error */
  2062.     zclose(pipes[0]);
  2063.     zclose(pipes[1]);
  2064.     errflag = 1;
  2065.     cmdoutpid = 0;
  2066.     child_unblock();
  2067.     return NULL;
  2068.     } else if (pid) {
  2069.     LinkList retval;
  2070.  
  2071.     zclose(pipes[1]);
  2072.     retval = readoutput(pipes[0], qt);
  2073.     fdtable[pipes[0]] = 0;
  2074.     child_suspend(0);        /* unblocks */
  2075.     lastval = cmdoutval;
  2076.     return retval;
  2077.     }
  2078.  
  2079.     /* pid == 0 */
  2080.     child_unblock();
  2081.     zclose(pipes[0]);
  2082.     redup(pipes[1], 1);
  2083.     opts[MONITOR] = 0;
  2084.     entersubsh(Z_SYNC, 1, 0);
  2085.     execlist(list, 0, 1);
  2086.     close(1);
  2087.     _exit(lastval);
  2088.     zerr("exit returned in child!!", NULL, 0);
  2089.     kill(getpid(), SIGKILL);
  2090.     return NULL;
  2091. }
  2092.  
  2093. /* read output of command substitution */
  2094.  
  2095. /**/
  2096. LinkList
  2097. readoutput(int in, int qt)
  2098. {
  2099.     LinkList ret;
  2100.     char *buf, *ptr;
  2101.     int bsiz, c, cnt = 0;
  2102.     FILE *fin;
  2103.  
  2104.     fin = fdopen(in, "r");
  2105.     ret = newlinklist();
  2106.     ptr = buf = (char *) ncalloc(bsiz = 64);
  2107.     while ((c = fgetc(fin)) != EOF) {
  2108.     if (imeta(c)) {
  2109.         *ptr++ = Meta;
  2110.         c ^= 32;
  2111.         cnt++;
  2112.     }
  2113.     if (++cnt >= bsiz) {
  2114.         char *pp = (char *) ncalloc(bsiz *= 2);
  2115.  
  2116.         memcpy(pp, buf, cnt - 1);
  2117.         ptr = (buf = pp) + cnt - 1;
  2118.     }
  2119.     *ptr++ = c;
  2120.     }
  2121.     fclose(fin);
  2122.     while (cnt && ptr[-1] == '\n')
  2123.     ptr--, cnt--;
  2124.     *ptr = '\0';
  2125.     if (qt) {
  2126.     if (!cnt) {
  2127.         *ptr++ = Nularg;
  2128.         *ptr = '\0';
  2129.     }
  2130.     addlinknode(ret, buf);
  2131.     } else {
  2132.     char **words = spacesplit(buf, 0);
  2133.  
  2134.     while (*words) {
  2135.         if (isset(GLOBSUBST))
  2136.         tokenize(*words);
  2137.         addlinknode(ret, *words++);
  2138.     }
  2139.     }
  2140.     return ret;
  2141. }
  2142.  
  2143. /**/
  2144. List
  2145. parsecmd(char *cmd)
  2146. {
  2147.     char *str;
  2148.     List list;
  2149.  
  2150.     for (str = cmd + 2; *str && *str != Outpar; str++);
  2151.     if (!*str || cmd[1] != Inpar) {
  2152.     zerr("oops.", NULL, 0);
  2153.     return NULL;
  2154.     }
  2155.     *str = '\0';
  2156.     if (str[1] || !(list = parse_string(cmd + 2))) {
  2157.     zerr("parse error in process substitution", NULL, 0);
  2158.     return NULL;
  2159.     }
  2160.     return list;
  2161. }
  2162.  
  2163. /* =(...) */
  2164.  
  2165. /**/
  2166. char *
  2167. getoutputfile(char *cmd)
  2168. {
  2169.     pid_t pid;
  2170.     char *nam;
  2171.     List list;
  2172.     int fd;
  2173.  
  2174.     if (thisjob == -1)
  2175.     return NULL;
  2176.     if (!(list = parsecmd(cmd)))
  2177.     return NULL;
  2178.     if (!(nam = gettempname()))
  2179.     return NULL;
  2180.  
  2181.     nam = ztrdup(nam);
  2182.     PERMALLOC {
  2183.     if (!jobtab[thisjob].filelist)
  2184.         jobtab[thisjob].filelist = newlinklist();
  2185.     addlinknode(jobtab[thisjob].filelist, nam);
  2186.     } LASTALLOC;
  2187.     child_block();
  2188.     fd = open(nam, O_WRONLY | O_CREAT | O_EXCL, 0600); /* create the file */
  2189.  
  2190.     if (fd < 0 || (cmdoutpid = pid = zfork()) == -1) {
  2191.     /* fork or open error */
  2192.     child_unblock();
  2193.     return nam;
  2194.     } else if (pid) {
  2195.     int os;
  2196.  
  2197.     close(fd);
  2198.     os = jobtab[thisjob].stat;
  2199.     waitforpid(pid);
  2200.     cmdoutval = 0;
  2201.     jobtab[thisjob].stat = os;
  2202.     return nam;
  2203.     }
  2204.  
  2205.     /* pid == 0 */
  2206.     redup(fd, 1);
  2207.     opts[MONITOR] = 0;
  2208.     entersubsh(Z_SYNC, 1, 0);
  2209.     execlist(list, 0, 1);
  2210.     close(1);
  2211.     _exit(lastval);
  2212.     zerr("exit returned in child!!", NULL, 0);
  2213.     kill(getpid(), SIGKILL);
  2214.     return NULL;
  2215. }
  2216.  
  2217. #if !defined(PATH_DEV_FD) && defined(HAVE_FIFOS)
  2218. /* get a temporary named pipe */
  2219.  
  2220. /**/
  2221. char *
  2222. namedpipe(void)
  2223. {
  2224.     char *tnam = gettempname();
  2225.  
  2226. # ifdef HAVE_MKFIFO
  2227.     if (mkfifo(tnam, 0600) < 0)
  2228. # else
  2229.     if (mknod(tnam, 0010600, 0) < 0)
  2230. # endif
  2231.     return NULL;
  2232.     return tnam;
  2233. }
  2234. #endif /* ! PATH_DEV_FD && HAVE_FIFOS */
  2235.  
  2236. /* <(...) or >(...) */
  2237.  
  2238. /**/
  2239. char *
  2240. getproc(char *cmd)
  2241. {
  2242. #if !defined(HAVE_FIFOS) && !defined(PATH_DEV_FD)
  2243.     zerr("doesn't look like your system supports FIFOs.", NULL, 0);
  2244.     return NULL;
  2245. #else
  2246.     List list;
  2247.     int out = *cmd == Inang;
  2248.     char *pnam;
  2249. #ifndef PATH_DEV_FD
  2250.     int fd;
  2251. #else
  2252.     int pipes[2];
  2253. #endif
  2254.  
  2255.     if (thisjob == -1)
  2256.     return NULL;
  2257. #ifndef PATH_DEV_FD
  2258.     if (!(pnam = namedpipe()))
  2259.     return NULL;
  2260. #else
  2261.     pnam = ncalloc(strlen(PATH_DEV_FD) + 6);
  2262. #endif
  2263.     if (!(list = parsecmd(cmd)))
  2264.     return NULL;
  2265. #ifndef PATH_DEV_FD
  2266.     PERMALLOC {
  2267.     if (!jobtab[thisjob].filelist)
  2268.         jobtab[thisjob].filelist = newlinklist();
  2269.     addlinknode(jobtab[thisjob].filelist, ztrdup(pnam));
  2270.     } LASTALLOC;
  2271.     if (zfork()) {
  2272. #else
  2273.     mpipe(pipes);
  2274.     if (zfork()) {
  2275.     sprintf(pnam, "%s/%d", PATH_DEV_FD, pipes[!out]);
  2276.     zclose(pipes[out]);
  2277.     fdtable[pipes[!out]] = 2;
  2278. #endif
  2279.     return pnam;
  2280.     }
  2281. #ifndef PATH_DEV_FD
  2282.     closem(0);
  2283.     fd = open(pnam, out ? O_WRONLY : O_RDONLY);
  2284.     if (fd == -1) {
  2285.     zerr("can't open %s: %e", pnam, errno);
  2286.     _exit(1);
  2287.     }
  2288.     entersubsh(Z_ASYNC, 1, 0);
  2289.     redup(fd, out);
  2290. #else
  2291.     entersubsh(Z_ASYNC, 1, 0);
  2292.     redup(pipes[out], out);
  2293.     closem(0);   /* this closes pipes[!out] as well */
  2294. #endif
  2295.     execlist(list, 0, 1);
  2296.     zclose(out);
  2297.     _exit(lastval);
  2298.     return NULL;
  2299. #endif   /* HAVE_FIFOS and PATH_DEV_FD not defined */
  2300. }
  2301.  
  2302. /* > >(...) or < <(...) (does not use named pipes) */
  2303.  
  2304. /**/
  2305. int
  2306. getpipe(char *cmd)
  2307. {
  2308.     List list;
  2309.     int pipes[2], out = *cmd == Inang;
  2310.  
  2311.     if (!(list = parsecmd(cmd)))
  2312.     return -1;
  2313.     mpipe(pipes);
  2314.     if (zfork()) {
  2315.     zclose(pipes[out]);
  2316.     return pipes[!out];
  2317.     }
  2318.     entersubsh(Z_ASYNC, 1, 0);
  2319.     redup(pipes[out], out);
  2320.     closem(0);    /* this closes pipes[!out] as well */
  2321.     execlist(list, 0, 1);
  2322.     _exit(lastval);
  2323.     return 0;
  2324. }
  2325.  
  2326. /* open pipes with fds >= 10 */
  2327.  
  2328. /**/
  2329. void
  2330. mpipe(int *pp)
  2331. {
  2332.     pipe(pp);
  2333.     pp[0] = movefd(pp[0]);
  2334.     pp[1] = movefd(pp[1]);
  2335. }
  2336.  
  2337. /* Do process substitution with redirection */
  2338.  
  2339. /**/
  2340. void
  2341. spawnpipes(LinkList l)
  2342. {
  2343.     LinkNode n;
  2344.     Redir f;
  2345.     char *str;
  2346.  
  2347.     n = firstnode(l);
  2348.     for (; n; incnode(n)) {
  2349.     f = (Redir) getdata(n);
  2350.     if (f->type == OUTPIPE || f->type == INPIPE) {
  2351.         str = f->name;
  2352.         f->fd2 = getpipe(str);
  2353.     }
  2354.     }
  2355. }
  2356.  
  2357. /* evaluate a [[ ... ]] */
  2358.  
  2359. /**/
  2360. int
  2361. execcond(Cmd cmd)
  2362. {
  2363.     return !evalcond(cmd->u.cond);
  2364. }
  2365.  
  2366. /* evaluate a ((...)) arithmetic command */
  2367.  
  2368. /**/
  2369. int
  2370. execarith(Cmd cmd)
  2371. {
  2372.     char *e;
  2373.     long val = 0;
  2374.  
  2375.     while ((e = (char *) ugetnode(cmd->args)))
  2376.     val = matheval(e);
  2377.     errflag = 0;
  2378.     return !val;
  2379. }
  2380.  
  2381. /* perform time ... command */
  2382.  
  2383. /**/
  2384. int
  2385. exectime(Cmd cmd)
  2386. {
  2387.     int jb;
  2388.  
  2389.     jb = thisjob;
  2390.     if (!cmd->u.pline) {
  2391.     shelltime();
  2392.     return 0;
  2393.     }
  2394.     execpline(cmd->u.pline, Z_TIMED|Z_SYNC, 0);
  2395.     thisjob = jb;
  2396.     return lastval;
  2397. }
  2398.  
  2399. /* Define a shell function */
  2400.  
  2401. /**/
  2402. int
  2403. execfuncdef(Cmd cmd)
  2404. {
  2405.     Shfunc shf;
  2406.     char *s;
  2407.     int signum;
  2408.  
  2409.     PERMALLOC {
  2410.     while ((s = (char *) ugetnode(cmd->args))) {
  2411.         shf = (Shfunc) zalloc(sizeof *shf);
  2412.         shf->funcdef = (List) dupstruct(cmd->u.list);
  2413.         shf->flags = 0;
  2414.  
  2415.         /* is this shell function a signal trap? */
  2416.         if (!strncmp(s, "TRAP", 4) && (signum = getsignum(s + 4)) != -1) {
  2417.         if (settrap(signum, shf->funcdef)) {
  2418.             freestruct(shf->funcdef);
  2419.             zfree(shf, sizeof *shf);
  2420.             LASTALLOC_RETURN 1;
  2421.         }
  2422.         sigtrapped[signum] |= ZSIG_FUNC;
  2423.         }
  2424.         shfunctab->addnode(shfunctab, ztrdup(s), shf);
  2425.     }
  2426.     } LASTALLOC;
  2427.     return 0;
  2428. }
  2429.  
  2430. /* Main entry point to execute a shell function.  It will retrieve *
  2431.  * an autoloaded shell function if it is currently undefined.      */
  2432.  
  2433. /**/
  2434. void
  2435. execshfunc(Cmd cmd, Shfunc shf)
  2436. {
  2437.     List funcdef;
  2438.     char *nam;
  2439.     LinkList last_file_list = NULL;
  2440.  
  2441.     if (errflag)
  2442.     return;
  2443.  
  2444.     if (!list_pipe) {
  2445.     /* Without this deletejob the process table *
  2446.      * would be filled by a recursive function. */
  2447.     last_file_list = jobtab[thisjob].filelist;
  2448.     jobtab[thisjob].filelist = NULL;
  2449.     deletejob(jobtab + thisjob);
  2450.     }
  2451.  
  2452.     /* Are we dealing with an autoloaded shell function? */
  2453.     if (shf->flags & PM_UNDEFINED) {
  2454.     nam = (char *) peekfirst(cmd->args);
  2455.     if (!(funcdef = getfpfunc(nam))) {
  2456.         zerr("function not found: %s", nam, 0);
  2457.         lastval = 1;
  2458.     } else {
  2459.         PERMALLOC {
  2460.         shf->flags &= ~PM_UNDEFINED;
  2461.         funcdef = shf->funcdef = (List) dupstruct(funcdef);
  2462.         } LASTALLOC;
  2463.  
  2464.         /* Execute the function definition, we just retrived */
  2465.         doshfunc(shf->funcdef, cmd->args, shf->flags, 0);
  2466.  
  2467.         /* See if this file defined the autoloaded function *
  2468.          * by name.  If so, we execute it again.            */
  2469.         if ((shf = (Shfunc) shfunctab->getnode(shfunctab, nam))
  2470.         && shf->funcdef && shf->funcdef != funcdef)
  2471.         doshfunc(shf->funcdef, cmd->args, shf->flags, 0);
  2472.     }
  2473.     } else
  2474.     /* Normal shell function execution */
  2475.     doshfunc(shf->funcdef, cmd->args, shf->flags, 0);
  2476.     if (!list_pipe)
  2477.     deletefilelist(last_file_list);
  2478. }
  2479.  
  2480. /* execute a shell function */
  2481.  
  2482. /**/
  2483. void
  2484. doshfunc(List list, LinkList doshargs, int flags, int noreturnval)
  2485. /* If noreturnval is nonzero, then reset the current return *
  2486.  * value (lastval) to its value before the shell function   *
  2487.  * was executed.                                            */
  2488. {
  2489.     Param pm;
  2490.     char **tab, **x, *oargv0 = NULL;
  2491.     int xexittr, newexittr, oldzoptind, oldlastval;
  2492.     LinkList olist;
  2493.     char *s, *ou;
  2494.     void *xexitfn, *newexitfn;
  2495.     char saveopts[OPT_SIZE];
  2496.     int obreaks = breaks;
  2497.  
  2498.     HEAPALLOC {
  2499.     pushheap();
  2500.     if (trapreturn < 0)
  2501.         trapreturn--;
  2502.     oldlastval = lastval;
  2503.     xexittr = sigtrapped[SIGEXIT];
  2504.     if (xexittr & ZSIG_FUNC)
  2505.         xexitfn = shfunctab->removenode(shfunctab, "TRAPEXIT");
  2506.     else
  2507.         xexitfn = sigfuncs[SIGEXIT];
  2508.     sigtrapped[SIGEXIT] = 0;
  2509.     sigfuncs[SIGEXIT] = NULL;
  2510.     tab = pparams;
  2511.     oldzoptind = zoptind;
  2512.     zoptind = 1;
  2513.  
  2514.     /* We need to save the current options even if LOCALOPTIONS is *
  2515.      * not currently set.  That's because if it gets set in the    *
  2516.      * function we need to restore the original options on exit.   */
  2517.     memcpy(saveopts, opts, sizeof(opts));
  2518.  
  2519.     if (flags & PM_TAGGED)
  2520.         opts[XTRACE] = 1;
  2521.     opts[PRINTEXITVALUE] = 0;
  2522.     if (doshargs) {
  2523.         LinkNode node;
  2524.  
  2525.         node = doshargs->first;
  2526.         pparams = x = (char **) zcalloc(((sizeof *x) * (1 + countlinknodes(doshargs))));
  2527.         if (isset(FUNCTIONARGZERO)) {
  2528.         oargv0 = argzero;
  2529.         argzero = ztrdup((char *) node->dat);
  2530.         }
  2531.         node = node->next;
  2532.         for (; node; node = node->next, x++)
  2533.         *x = ztrdup((char *) node->dat);
  2534.     } else {
  2535.         pparams = (char **) zcalloc(sizeof *pparams);
  2536.         if (isset(FUNCTIONARGZERO)) {
  2537.         oargv0 = argzero;
  2538.         argzero = ztrdup(argzero);
  2539.         }
  2540.     }
  2541.     PERMALLOC {
  2542.         olist = locallist;        /* save the old locallist since shell functions may be nested */
  2543.         locallist = newlinklist();    /* make a new list of local variables that we have to destroy */
  2544.     } LASTALLOC;
  2545.     locallevel++;
  2546.     ou = underscore;
  2547.     underscore = ztrdup(underscore);
  2548.     execlist(dupstruct(list), 1, 0);
  2549.     zsfree(underscore);
  2550.     underscore = ou;
  2551.     locallevel--;
  2552.  
  2553.     /* destroy the local variables we have created in the shell function */
  2554.     while ((s = (char *) getlinknode(locallist))) {
  2555.         if((pm = (Param) paramtab->getnode(paramtab, s)) && (pm->level > locallevel))
  2556.         unsetparam_pm(pm, 0);
  2557.         zsfree(s);
  2558.     }
  2559.     zfree(locallist, sizeof(struct linklist));
  2560.  
  2561.     locallist = olist;    /* restore the old list of local variables */
  2562.     if (retflag) {
  2563.         retflag = 0;
  2564.         breaks = obreaks;
  2565.     }
  2566.     freearray(pparams);
  2567.     if (oargv0) {
  2568.         zsfree(argzero);
  2569.         argzero = oargv0;
  2570.     }
  2571.     zoptind = oldzoptind;
  2572.     pparams = tab;
  2573.  
  2574.     if (isset(LOCALOPTIONS)) {
  2575.         /* restore all shell options except PRIVILEGED */
  2576.         saveopts[PRIVILEGED] = opts[PRIVILEGED];
  2577.         memcpy(opts, saveopts, sizeof(opts));
  2578.     } else {
  2579.         /* just restore a couple. */
  2580.         opts[XTRACE] = saveopts[XTRACE];
  2581.         opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
  2582.         opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
  2583.     }
  2584.  
  2585.     /*
  2586.      * The trap '...' EXIT runs in the environment of the caller,
  2587.      * so remember it here but run it after resetting the
  2588.      * traps for the parent.
  2589.      */
  2590.     newexittr = sigtrapped[SIGEXIT];
  2591.     newexitfn = sigfuncs[SIGEXIT];
  2592.     if (newexittr & ZSIG_FUNC)
  2593.         shfunctab->removenode(shfunctab, "TRAPEXIT");
  2594.  
  2595.     sigtrapped[SIGEXIT] = xexittr;
  2596.     if (xexittr & ZSIG_FUNC) {
  2597.         shfunctab->addnode(shfunctab, ztrdup("TRAPEXIT"), xexitfn);
  2598.         sigfuncs[SIGEXIT] = ((Shfunc) xexitfn)->funcdef;
  2599.     } else
  2600.         sigfuncs[SIGEXIT] = (List) xexitfn;
  2601.  
  2602.     if (newexitfn) {
  2603.         dotrapargs(SIGEXIT, &newexittr, newexitfn);
  2604.         freestruct(newexitfn);
  2605.     }
  2606.  
  2607.     if (trapreturn < -1)
  2608.         trapreturn++;
  2609.     if (noreturnval)
  2610.         lastval = oldlastval;
  2611.     popheap();
  2612.     } LASTALLOC;
  2613. }
  2614.  
  2615. /* Search fpath for an undefined function. */
  2616.  
  2617. /**/
  2618. List
  2619. getfpfunc(char *s)
  2620. {
  2621.     char **pp, buf[PATH_MAX];
  2622.     off_t len;
  2623.     char *d;
  2624.     List r;
  2625.     int fd;
  2626.  
  2627.     pp = fpath;
  2628.     for (; *pp; pp++) {
  2629.     if (strlen(*pp) + strlen(s) + 1 >= PATH_MAX)
  2630.         continue;
  2631.     if (**pp)
  2632.         sprintf(buf, "%s/%s", *pp, s);
  2633.     else
  2634.         strcpy(buf, s);
  2635.     unmetafy(buf, NULL);
  2636.     if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY)) != -1) {
  2637.         if ((len = lseek(fd, 0, 2)) != -1) {
  2638.         lseek(fd, 0, 0);
  2639.         d = (char *) zcalloc(len + 1);
  2640.         if (read(fd, d, len) == len) {
  2641.             close(fd);
  2642.             d = metafy(d, len, META_REALLOC);
  2643.             HEAPALLOC {
  2644.             r = parse_string(d);
  2645.             } LASTALLOC;
  2646.             zfree(d, len + 1);
  2647.             return r;
  2648.         } else {
  2649.             zfree(d, len + 1);
  2650.             close(fd);
  2651.         }
  2652.         } else {
  2653.         close(fd);
  2654.         }
  2655.     }
  2656.     }
  2657.     return NULL;
  2658. }
  2659.  
  2660. /* check to see if AUTOCD applies here */
  2661.  
  2662. extern int doprintdir;
  2663.  
  2664. /**/
  2665. char *
  2666. cancd(char *s)
  2667. {
  2668.     int nocdpath = s[0] == '.' &&
  2669.     (s[1] == '/' || !s[1] || (s[1] == '.' && (s[2] == '/' || !s[1])));
  2670.     char *t;
  2671.  
  2672.     if (*s != '/') {
  2673.     char sbuf[PATH_MAX], **cp;
  2674.  
  2675.     if (cancd2(s))
  2676.         return s;
  2677.     if (access(unmeta(s), X_OK) == 0)
  2678.         return NULL;
  2679.     if (!nocdpath)
  2680.         for (cp = cdpath; *cp; cp++) {
  2681.         if (strlen(*cp) + strlen(s) + 1 >= PATH_MAX)
  2682.             continue;
  2683.         if (**cp)
  2684.             sprintf(sbuf, "%s/%s", *cp, s);
  2685.         else
  2686.             strcpy(sbuf, s);
  2687.         if (cancd2(sbuf)) {
  2688.             doprintdir = -1;
  2689.             return dupstring(sbuf);
  2690.         }
  2691.         }
  2692.     if ((t = cd_able_vars(s))) {
  2693.         if (cancd2(t)) {
  2694.         doprintdir = -1;
  2695.         return t;
  2696.         }
  2697.     }
  2698.     return NULL;
  2699.     }
  2700.     return cancd2(s) ? s : NULL;
  2701. }
  2702.  
  2703. /**/
  2704. int
  2705. cancd2(char *s)
  2706. {
  2707.     struct stat buf;
  2708.     char *us = unmeta(s);
  2709.  
  2710.     return !(access(us, X_OK) || stat(us, &buf) || !S_ISDIR(buf.st_mode));
  2711. }
  2712.  
  2713. /**/
  2714. void
  2715. execsave(void)
  2716. {
  2717.     struct execstack *es;
  2718.  
  2719.     es = (struct execstack *) malloc(sizeof(struct execstack));
  2720.     es->args = args;
  2721.     es->list_pipe_pid = list_pipe_pid;
  2722.     es->nowait = nowait;
  2723.     es->pline_level = pline_level;
  2724.     es->list_pipe_child = list_pipe_child;
  2725.     es->list_pipe_job = list_pipe_job;
  2726.     strcpy(es->list_pipe_text, list_pipe_text);
  2727.     es->lastval = lastval;
  2728.     es->noeval = noeval;
  2729.     es->badcshglob = badcshglob;
  2730.     es->cmdoutpid = cmdoutpid;
  2731.     es->cmdoutval = cmdoutval;
  2732.     es->trapreturn = trapreturn;
  2733.     es->noerrs = noerrs;
  2734.     es->subsh_close = subsh_close;
  2735.     es->underscore = underscore;
  2736.     underscore = ztrdup(underscore);
  2737.     es->next = exstack;
  2738.     exstack = es;
  2739.     noerrs = cmdoutpid = 0;
  2740. }
  2741.  
  2742. /**/
  2743. void
  2744. execrestore(void)
  2745. {
  2746.     struct execstack *en;
  2747.  
  2748.     DPUTS(!exstack, "BUG: execrestore() without execsave()");
  2749.     args = exstack->args;
  2750.     list_pipe_pid = exstack->list_pipe_pid;
  2751.     nowait = exstack->nowait;
  2752.     pline_level = exstack->pline_level;
  2753.     list_pipe_child = exstack->list_pipe_child;
  2754.     list_pipe_job = exstack->list_pipe_job;
  2755.     strcpy(list_pipe_text, exstack->list_pipe_text);
  2756.     lastval = exstack->lastval;
  2757.     noeval = exstack->noeval;
  2758.     badcshglob = exstack->badcshglob;
  2759.     cmdoutpid = exstack->cmdoutpid;
  2760.     cmdoutval = exstack->cmdoutval;
  2761.     trapreturn = exstack->trapreturn;
  2762.     noerrs = exstack->noerrs;
  2763.     subsh_close = exstack->subsh_close;
  2764.     zsfree(underscore);
  2765.     underscore = exstack->underscore;
  2766.     en = exstack->next;
  2767.     free(exstack);
  2768.     exstack = en;
  2769. }
  2770.