home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / z / zsh220.zip / zsh2.2 / src / exec.c < prev    next >
C/C++ Source or Header  |  1992-05-07  |  36KB  |  1,830 lines

  1. /*
  2.  *
  3.  * exec.c - command execution
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made. 
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk. 
  18.  *
  19.  */
  20.  
  21. #include "zsh.h"
  22. #include <sys/errno.h>
  23. #ifdef __hpux
  24. #include <ndir.h>
  25. #else
  26. #include <sys/dir.h>
  27. #endif
  28.  
  29. #define execerr() { if (forked) exit(1); \
  30.     closemnodes(mfds); errflag = 1; return; }
  31.  
  32. static Lklist args;
  33. static Cmdnam cn;
  34.  
  35. /* parse list in a string */
  36.  
  37. List parselstring(s) /**/
  38. char *s;
  39. {
  40. List l;
  41.  
  42.     hungets(s);
  43.     strinbeg();
  44.     pushheap();
  45.     if (!(l = parse_list())) {
  46.         strinend();
  47.         hflush();
  48.         popheap();
  49.         return NULL;
  50.     }
  51.     strinend();
  52.     return l;
  53. }
  54.  
  55. /* execute a string */
  56.  
  57. void execstring(s) /**/
  58. char *s;
  59. {
  60. List l;
  61.  
  62.     if (l = parselstring(s)) {
  63.         execlist(l);
  64.         popheap();
  65.     }
  66. }
  67.  
  68. /* fork and set limits */
  69.  
  70. int phork() /**/
  71. {
  72. int pid,t0;
  73.  
  74.     if (thisjob >= MAXJOB-1) {
  75.         zerr("job table full",NULL,0);
  76.         return -1;
  77.     }
  78.     pid = fork();
  79.     if (pid == -1) {
  80.         zerr("fork failed: %e",NULL,errno);
  81.         return -1;
  82.     }
  83. #ifdef RLIM_INFINITY
  84.     if (!pid)
  85.         for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  86.             setrlimit(t0,limits+t0);
  87. #endif
  88.     return pid;
  89. }
  90.  
  91. /* execute a current shell command */
  92.  
  93. int execcursh(cmd) /**/
  94. Cmd cmd;
  95. {
  96.     runlist(cmd->u.list);
  97.     cmd->u.list = NULL;
  98.     return lastval;
  99. }
  100.  
  101. /* execve after handling $_ and #! */
  102.  
  103. #define POUNDBANGLIMIT 64
  104.  
  105. int zexecve(pth,argv) /**/
  106. char *pth;char **argv;
  107. {
  108. int eno;
  109. static char buf[MAXPATHLEN*2];
  110. char **eep;
  111.  
  112.     for (eep = environ; *eep; eep++)
  113.         if (**eep == '_' && (*eep)[1] == '=') break;
  114.     buf[0] = '_';
  115.     buf[1] = '=';
  116.     if (*pth == '/') strcpy(buf+2,pth);
  117.     else sprintf(buf+2,"%s/%s",pwd,pth);
  118.     if (!*eep) eep[1] = NULL;
  119.     *eep = buf;
  120.     execve(pth,argv,environ);
  121.     if ((eno = errno) == ENOEXEC) {
  122.         char buf[POUNDBANGLIMIT+1],*ptr,*ptr2,*argv0;
  123.         int fd,ct,t0;
  124.  
  125.         if ((fd = open(pth,O_RDONLY)) >= 0) {
  126.             argv0 = *argv;
  127.             *argv = pth;
  128.             ct = read(fd,buf,POUNDBANGLIMIT);
  129.             close(fd);
  130.             if (ct > 0) {
  131.                 if (buf[0] == '#')
  132.                     if (buf[1] == '!') {
  133.                         for (t0 = 0; t0 != ct; t0++)
  134.                             if (buf[t0] == '\n')
  135.                                 buf[t0] = '\0';
  136.                         buf[POUNDBANGLIMIT] = '\0';
  137.                         for (ptr = buf+2; *ptr && *ptr == ' '; ptr++);
  138.                         for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
  139.                         if (*ptr) {
  140.                             *ptr = '\0';
  141.                             argv[-2] = ptr2;
  142.                             argv[-1] = ptr+1;
  143.                             execve(ptr2,argv-2,environ);
  144.                         } else {
  145.                             argv[-1] = ptr2;
  146.                             execve(ptr2,argv-1,environ);
  147.                         }
  148.                     } else {
  149.                         argv[-1] = "sh";
  150.                         execve("/bin/sh",argv-1,environ);
  151.                     }
  152.                 else {
  153.                     for (t0 = 0; t0 != ct; t0++)
  154.                         if (!buf[t0]) break;
  155.                     if (t0 == ct) {
  156.                         argv[-1] = "sh";
  157.                         execve("/bin/sh",argv-1,environ);
  158.                     }
  159.                 }
  160.             } else eno = errno;
  161.             *argv = argv0;
  162.         } else eno = errno;
  163.     }
  164.     return eno;
  165. }
  166.  
  167. #define MAXCMDLEN (MAXPATHLEN*4)
  168.  
  169. /* execute an external command */
  170.  
  171. void execute(dash) /**/
  172. int dash;
  173. {
  174. char **argv,*arg0,**pp;
  175. char *z,*s,buf[MAXCMDLEN],buf2[MAXCMDLEN];
  176. int ee = 0,eno = 0;
  177.  
  178.     if (!full(args)) {
  179.         zerr("no command",NULL,0);
  180.         _exit(1);
  181.     }
  182.     cn = (Cmdnam) gethnode(peekfirst(args),cmdnamtab);
  183.     if (cn && cn->type == DISABLED)
  184.         cn = NULL;
  185.     if (s = zgetenv("STTY"))
  186.         zyztem("stty",s);
  187.     arg0 = peekfirst(args);
  188.     if (z = zgetenv("ARGV0")) {
  189.         setdata(firstnode(args),ztrdup(z));
  190.         delenv(z-6);
  191.     } else if (dash) {
  192.         sprintf(buf2,"-%s",arg0);
  193.         setdata(firstnode(args),ztrdup(buf2));
  194.     }
  195.     argv = makecline(args);
  196.     fixsigs();
  197.     if (strlen(arg0) > MAXPATHLEN) {
  198.         zerr("command too long: %s",arg0,0);
  199.         _exit(1);
  200.     }
  201.     for (s = arg0; *s; s++)
  202.         if (*s == '/') {
  203.             errno = zexecve(arg0,argv);
  204.             if (arg0 == s || unset(PATHDIRS)) {
  205.                 zerr("%e: %s",arg0,errno);
  206.                 _exit(1);
  207.             }
  208.             break;
  209.         }
  210.     if (cn && ISEXCMD(cn->type)) {
  211.         for (pp = path; pp < cn->pcomp; pp++)
  212.             if (**pp == '.' && (*pp)[1] == '\0') {
  213.                 ee = zexecve(arg0,argv);
  214.                 if (ee != ENOENT) eno = ee;
  215.             } else if (**pp != '/') {
  216.                 z = buf;
  217.                 strucpy(&z,*pp);
  218.                 *z++ = '/';
  219.                 strcpy(z,arg0);
  220.                 ee = zexecve(buf,argv);
  221.                 if (ee != ENOENT) eno = ee;
  222.             }
  223.         ee = zexecve(cn->u.nam,argv);
  224.         if (ee != ENOENT) eno = ee;
  225.     }
  226.     for (pp = path; *pp; pp++)
  227.         if ((*pp)[0] == '.' && !(*pp)[1]) {
  228.             ee = zexecve(arg0,argv);
  229.             if (ee != ENOENT) eno = ee;
  230.         } else {
  231.             z = buf;
  232.             strucpy(&z,*pp);
  233.             *z++ = '/';
  234.             strcpy(z,arg0);
  235.             ee = zexecve(buf,argv);
  236.             if (ee != ENOENT) eno = ee;
  237.         }
  238.     if (eno) zerr("%e: %s",arg0,eno);
  239.     else zerr("command not found: %s",arg0,0);
  240.     _exit(1);
  241. }
  242.  
  243. #define try(X) { if (iscom(X)) return ztrdup(X); }
  244.  
  245. /* get the full pathname of an external command */
  246.  
  247. char *findcmd(arg0) /**/
  248. char *arg0;
  249. {
  250. char **pp;
  251. char *z,*s,buf[MAXCMDLEN];
  252.  
  253.     cn = (Cmdnam) gethnode(arg0,cmdnamtab);
  254.     if (!cn && isset(HASHCMDS)) hashcmd(arg0,path);
  255.     if (cn && cn->type == DISABLED) cn = NULL;
  256.     if (strlen(arg0) > MAXPATHLEN) return NULL;
  257.     for (s = arg0; *s; s++)
  258.         if (*s == '/') {
  259.             try(arg0);
  260.             if (arg0 == s || unset(PATHDIRS)) {
  261.                 return NULL;
  262.             }
  263.             break;
  264.         }
  265.     if (cn && ISEXCMD(cn->type)) {
  266.         for (pp = path; pp < cn->pcomp; pp++)
  267.             if (**pp != '/') {
  268.                 z = buf;
  269.                 strucpy(&z,*pp);
  270.                 *z++ = '/';
  271.                 strcpy(z,arg0);
  272.                 try(buf);
  273.             }
  274.         try(cn->u.nam);
  275.     }
  276.     for (pp = path; *pp; pp++) {
  277.         z = buf;
  278.         strucpy(&z,*pp);
  279.         *z++ = '/';
  280.         strcpy(z,arg0);
  281.         try(buf);
  282.     }
  283.     return NULL;
  284. }
  285.  
  286. int iscom(s) /**/
  287. char *s;
  288. {
  289. struct stat statbuf;
  290.  
  291.     return (access(s,X_OK) == 0 && stat(s,&statbuf) >= 0 &&
  292.             S_ISREG(statbuf.st_mode));
  293. }
  294.  
  295. int isrelative(s) /**/
  296. char *s;
  297. {
  298.     if (*s != '/') return 1;
  299.     for (; *s; s++)
  300.         if (*s == '.' && s[-1] == '/' &&
  301.             (s[1] == '/' || s[1] == '\0' ||
  302.                 (s[1] == '.' && (s[2] == '/' || s[2] == '\0')))) return 1;
  303.     return 0;
  304. }
  305.  
  306. int hashcmd(arg0,pp) /**/
  307. char *arg0;char **pp;
  308. {
  309. char *s,buf[MAXPATHLEN];
  310. char **pq;
  311. DIR *dir;
  312. struct direct *de;
  313.  
  314.     for (; *pp; pp++)
  315.         if (**pp == '/') {
  316.             s = buf;
  317.             strucpy(&s,*pp);
  318.             *s++ = '/';
  319.             strcpy(s,arg0);
  320.             if (iscom(buf)) break;
  321.         }
  322.     if (!*pp || isrelative(*pp)) return 0;
  323.     cn = (Cmdnam) zcalloc(sizeof *cn);
  324.     cn->type = EXCMD;
  325.     cn->pcomp = pp;
  326.     cn->u.nam = ztrdup(buf);
  327.     addhnode(ztrdup(arg0),cn,cmdnamtab,freecmdnam);
  328.     if (unset(HASHDIRS)) return 1;
  329.     for (pq = pathchecked; pq <= pp; pq++) {
  330.         if (isrelative(*pq) || !(dir = opendir(*pq))) continue;
  331.         readdir(dir); readdir(dir);
  332.         while (de = readdir(dir)) addhcmdnode(de->d_name,pq);
  333.         closedir(dir);
  334.     }
  335.     pathchecked = pp+1;
  336.     return 1;
  337. }
  338.  
  339. void fullhash() /**/
  340. {
  341. char **pq;
  342. DIR *dir;
  343. struct direct *de;
  344.  
  345.     for (pq = pathchecked; *pq; pq++) {
  346.         if (isrelative(*pq) || !(dir = opendir(*pq))) continue;
  347.         readdir(dir); readdir(dir);
  348.         while (de = readdir(dir)) addhcmdnode(de->d_name,pq);
  349.         closedir(dir);
  350.     }
  351.     pathchecked = pq;
  352. }
  353.  
  354. void execlist(list) /**/
  355. List list;
  356. {
  357.     if (breaks) return;
  358.     if (!list) return;
  359.     simplifyright(list);
  360.     switch(list->type) {
  361.         case SYNC:
  362.         case ASYNC:
  363.             execlist2(list->left,list->type,!list->right);
  364.             if (sigtrapped[SIGDEBUG])
  365.                 dotrap(SIGDEBUG);
  366.             if (sigtrapped[SIGERR] && lastval)
  367.                 dotrap(SIGERR);
  368.             if (list->right && !retflag)
  369.                 execlist(list->right);
  370.             break;
  371.     }
  372. }
  373.  
  374. void execlist2(list,type,last1) /**/
  375. Sublist list;int type;int last1;
  376. {
  377.     if (!list) return;
  378.     switch(list->type) {
  379.         case END:
  380.             execpline(list,type,last1);
  381.             break;
  382.         case ORNEXT:
  383.             if (!execpline(list,SYNC,0)) execlist2(list->right,type,last1);
  384.             else while (list = list->right)
  385.                 if (list->type == ANDNEXT) {
  386.                     execlist2(list->right,type,last1);
  387.                     return;
  388.                 }
  389.             break;
  390.         case ANDNEXT:
  391.             if (execpline(list,SYNC,0)) execlist2(list->right,type,last1);
  392.             else while (list = list->right)
  393.                 if (list->type == ORNEXT) {
  394.                     execlist2(list->right,type,last1);
  395.                     return;
  396.                 }
  397.             break;
  398.     }
  399. }
  400.  
  401. int execpline(l,how,last1) /**/
  402. Sublist l;int how;int last1;
  403. {
  404. int ipipe[2],opipe[2];
  405.  
  406.     if (!l) return 0;
  407.     ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
  408.     blockchld();
  409.     if ((thisjob = getfreejob()) == -1)
  410.         return 1;
  411.     initjob();
  412.     if (how == TIMED) {
  413.         jobtab[thisjob].stat |= STAT_TIMED;
  414.         how = SYNC;
  415.     }
  416.     if (l->flags & PFLAG_COPROC) {
  417.         how = ASYNC;
  418.         if (coprocin >= 0) {
  419.             close(coprocin);
  420.             close(coprocout);
  421.         }
  422.         mpipe(ipipe);
  423.         mpipe(opipe);
  424.         coprocin = ipipe[0];
  425.         coprocout = opipe[1];
  426.     }
  427.     execpline2(l->left,how,opipe[0],ipipe[1],last1);
  428.     if (how == ASYNC) {
  429.         if (l->flags & PFLAG_COPROC) close(ipipe[1]);
  430.         spawnjob();
  431.         unblockchld();
  432.         return 1;
  433.     } else {
  434.         waitjobs();
  435.         unblockchld();
  436.         if (l->flags & PFLAG_NOT) lastval = !lastval;
  437.         return !lastval;
  438.     }
  439. }
  440.  
  441. void execpline2(pline,how,input,output,last1) /**/
  442. Pline pline;int how;int input;int output;int last1;
  443. {
  444. int pid;
  445. int pipes[2];
  446.  
  447.     if (breaks)
  448.         return;
  449.     if (!pline)
  450.         return;
  451.     if (pline->type == END) {
  452.         execcmd(pline->left,input,output,how==ASYNC,last1);
  453.         pline->left = NULL;
  454.     } else {
  455.         mpipe(pipes);
  456.         if (pline->left->type >= CURSH && how == SYNC) {
  457.  
  458.             /* if we are doing "foo | bar" where foo is a current
  459.                 shell command, do foo in a subshell and do
  460.                 the rest of the pipeline in the current shell. */
  461.  
  462.             if (!(pid = fork())) {
  463.                 close(pipes[0]);
  464.                 entersubsh(how==ASYNC);
  465.                 exiting = 1;
  466.                 execcmd(pline->left,input,pipes[1],how==ASYNC,0);
  467.                 _exit(lastval);
  468.             } else if (pid == -1)
  469.                 zerr("fork failed: %e",NULL,errno);
  470.             else {
  471.                 char *text = getjobtext((vptr) pline->left);
  472.                 addproc(pid,text);
  473.             }
  474.         } else {
  475.             /* otherwise just do the pipeline normally. */
  476.             execcmd(pline->left,input,pipes[1],how==ASYNC,0);
  477.         }
  478.         pline->left = NULL;
  479.         close(pipes[1]);
  480.         if (pline->right) {
  481.             execpline2(pline->right,how,pipes[0],output,last1);
  482.             close(pipes[0]);
  483.         }
  484.     }
  485. }
  486.  
  487. /* make the argv array */
  488.  
  489. char **makecline(list) /**/
  490. struct lklist *list;
  491. {
  492. int ct = 0;
  493. Lknode node;
  494. char **argv,**ptr;
  495.  
  496.     if (isset(XTRACE)) {
  497.         fprintf(stderr,"%s",(prompt4) ? prompt4 : "");
  498.         for (node = firstnode(list); node; incnode(node),ct++);
  499.         ptr = argv = 2+(char **) ncalloc((ct+4)*sizeof(char *));
  500.         for (node = firstnode(list); node; incnode(node))
  501.             if (*(char *) getdata(node)) {
  502.                 *ptr++ = getdata(node);
  503.                 untokenize(getdata(node));
  504.                 fputs(getdata(node),stderr);
  505.                 if (nextnode(node))
  506.                     fputc(' ',stderr);
  507.             }
  508.         *ptr = NULL;
  509.         fputc('\n',stderr);
  510.         fflush(stderr);
  511.         return(argv);
  512.     } else {
  513.         for (node = firstnode(list); node; incnode(node),ct++);
  514.         ptr = argv = 2+(char **) ncalloc((ct+4)*sizeof(char *));
  515.         for (node = firstnode(list); node; incnode(node))
  516.             if (*(char *) getdata(node)) {
  517.                 *ptr++ = getdata(node);
  518.                 untokenize(getdata(node));
  519.             }
  520.         *ptr = NULL;
  521.         return(argv);
  522.     }
  523. }
  524.  
  525. /* untokenize the command line and remove null arguments */
  526.  
  527. void fixcline(l) /**/
  528. Lklist l;
  529. {
  530. Lknode node,next;
  531.  
  532.     for (node = firstnode(l); node; node = next) {
  533.         next = nextnode(node);
  534.         if (!*(char *) getdata(node)) uremnode(l,node);
  535.         else untokenize(getdata(node));
  536.     }
  537. }
  538.  
  539. void untokenize(s) /**/
  540. char *s;
  541. {
  542.     for (; *s; s++)
  543.         if (itok(*s))
  544.             if (*s == Nularg) chuck(s--);
  545.             else *s = ztokens[*s-Pound];
  546. }
  547.  
  548. /* nonzero if we shouldn't clobber a file */
  549.  
  550. int dontclob(f) /**/
  551. struct redir *f;
  552. {
  553. struct stat buf;
  554.  
  555.     if (unset(NOCLOBBER) || f->type & 1) return 0;
  556.     if (stat(f->name,&buf) == -1) return 1;
  557.     return S_ISREG(buf.st_mode);
  558. }
  559.  
  560. /* close an multio (success) */
  561.  
  562. void closemn(mfds,fd) /**/
  563. struct multio **mfds;int fd;
  564. {
  565.     if (mfds[fd]) {
  566.         if (mfds[fd]->ct > 1)
  567.             if (mfds[fd]->rflag == 0)
  568.                 catproc(mfds[fd]);
  569.             else
  570.                 teeproc(mfds[fd]);
  571.         mfds[fd] = NULL;
  572.     }
  573. }
  574.  
  575. /* close all the mnodes (failure) */
  576.  
  577. void closemnodes(mfds) /**/
  578. struct multio **mfds;
  579. {
  580. int t0,t1;
  581.  
  582.     for (t0 = 0; t0 != 10; t0++)
  583.         if (mfds[t0]) {
  584.             for (t1 = 0; t1 != mfds[t0]->ct; t1++)
  585.                 close(mfds[t0]->fds[t1]);
  586.             mfds[t0] = NULL;
  587.         }
  588. }
  589.  
  590. /* add a fd to an multio */
  591. /* an multio is a list of fds associated with a certain fd.
  592.     thus if you do "foo >bar >ble", the multio for fd 1 will have
  593.     two fds, the result of open("bar",...), and the result of
  594.     open("ble",....). */
  595.  
  596. void addfd(forked,save,mfds,fd1,fd2,rflag) /**/
  597. int forked;int *save;struct multio **mfds;int fd1;int fd2;int rflag;
  598. {
  599. int pipes[2];
  600.  
  601.     if (!mfds[fd1]) {    /* starting a new multio */
  602.         mfds[fd1] = (struct multio *) alloc(sizeof(struct multio));
  603.         if (!forked && fd1 != fd2 && fd1 < 10)
  604.             save[fd1] = movefd(fd1);
  605.         redup(fd2,fd1);
  606.         mfds[fd1]->ct = 1;
  607.         mfds[fd1]->fds[0] = fd1;
  608.         mfds[fd1]->rflag = rflag;
  609.     } else {
  610.         if (mfds[fd1]->rflag != rflag) {
  611.             zerr("file mode mismatch on fd %d",NULL,fd1);
  612.             return;
  613.         }
  614.         if (mfds[fd1]->ct == 1) {        /* split the stream */
  615.             mfds[fd1]->fds[0] = movefd(fd1);
  616.             mfds[fd1]->fds[1] = movefd(fd2);
  617.             mpipe(pipes);
  618.             mfds[fd1]->pipe = pipes[1-rflag];
  619.             redup(pipes[rflag],fd1);
  620.             mfds[fd1]->ct = 2;
  621.         } else        /* add another fd to an already split stream */
  622.             mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2);
  623.     }
  624. }
  625.  
  626. void addvars(l,export) /**/
  627. Lklist l;int export;
  628. {
  629. struct varasg *v;
  630. Lklist vl;
  631.  
  632.     while (full(l)) {
  633.         char **arr,**ptr;
  634.  
  635.         v = (struct varasg *) ugetnode(l);
  636.         singsub(&v->name);
  637.         if (errflag)
  638.             return;
  639.         untokenize(v->name);
  640.         if (v->type == PMFLAG_s) {
  641.             vl = newlist();
  642.             addnode(vl,v->str);
  643.         } else
  644.             vl = v->arr;
  645.         prefork(vl);
  646.         if (errflag)
  647.             return;
  648.         postfork(vl,1);
  649.         if (errflag)
  650.             return;
  651.         if (v->type == PMFLAG_s && (!full(vl) || !nextnode(firstnode(vl)))) {
  652.             Param pm;
  653.             char *val;
  654.  
  655.             if (!full(vl))
  656.                 pm = setsparam(v->name,val = ztrdup(""));
  657.             else {
  658.                 untokenize(peekfirst(vl));
  659.                 pm = setsparam(v->name,val = ztrdup(ugetnode(vl)));
  660.             }
  661.             if (export && !(pm->flags & PMFLAG_x))
  662.                 addenv(v->name,val);
  663.             continue;
  664.         }
  665.         ptr = arr = (char **) zalloc(sizeof(char **)*(countnodes(vl)+1));
  666.         while (full(vl)) {
  667.             char *pp;
  668.             pp = ugetnode(vl);
  669.             if (*pp) {
  670.                 *ptr = ztrdup(pp);
  671.                 untokenize(*ptr++);
  672.             }
  673.         }
  674.         *ptr = NULL;
  675.         setaparam(v->name,arr);
  676.     }
  677. }
  678.  
  679. void execcmd(cmd,input,output,bkg,last1) /**/
  680. Cmd cmd;int input;int output;int bkg;int last1;
  681. {
  682. int type;
  683. long pid = 0;
  684. int save[10],t0;
  685. struct redir *fn;
  686. struct multio *mfds[10];
  687. int fil,forked = 0,iscursh = 0,nullexec = 0;
  688. char *text;
  689.  
  690.     args = cmd->args;
  691.     cn = NULL;
  692.     for (t0 = 0; t0 != 10; t0++) {
  693.         save[t0] = 0;
  694.         mfds[t0] = NULL;
  695.     }
  696.     if ((type = cmd->type) == SIMPLE && !full(args))
  697.         if (full(cmd->redir))
  698.             if (cmd->flags & CFLAG_EXEC) {
  699.                 nullexec = 1;
  700.             } else if (!*nullcmd) {
  701.                 zerr("redirection with no command",NULL,0);
  702.                 errflag = lastval = 1;
  703.                 return;
  704.             } else if (*readnullcmd &&
  705.                     ((Redir)peekfirst(cmd->redir))->type == READ &&
  706.                     !nextnode(firstnode(cmd->redir))) {
  707.                 addnode(args,strdup(readnullcmd));
  708.             } else
  709.                 addnode(args,strdup(nullcmd));
  710.         else {
  711.             addvars(cmd->vars,0);
  712.             return;
  713.         }
  714.     if (full(args) && *(char *) peekfirst(args) == '%') {
  715.         insnode(args,(Lknode) args,strdup((bkg) ? "bg" : "fg"));
  716.         bkg = 0;
  717.     }
  718.     if (isset(AUTORESUME) && !bkg && !full(cmd->redir) && full(args) &&
  719.             !input && type == SIMPLE && !nextnode(firstnode(args))) {
  720.         if (unset(NOTIFY)) scanjobs();
  721.         if (findjobnam(peekfirst(args)) != -1)
  722.             pushnode(args,strdup("fg"));
  723.     }
  724.     if (unset(RMSTARSILENT) && interact && isset(SHINSTDIN) &&
  725.                 type == SIMPLE && full(args) && nextnode(firstnode(args)) &&
  726.                 !strcmp(peekfirst(args),"rm")) {
  727.             char *s = getdata(nextnode(firstnode(args)));
  728.             int l = strlen(s);
  729.  
  730.             if (s[0] == Star && !s[1])
  731.                 checkrmall(pwd);
  732.             else if (l > 2 && s[l-2] == '/' && s[l-1] == Star) {
  733.                 char t = s[l-2];
  734.                 s[l-2] = 0;
  735.                 checkrmall(s);
  736.                 s[l-2] = t;
  737.             }
  738.     }
  739.     if (jobbing) {    /* get the text associated with this command */
  740.         char *s;
  741.         s = text = getjobtext((vptr) cmd);
  742.     } else text = NULL;
  743.     prefork(args);    /* do prefork substitutions */
  744.     if (errflag) {
  745.         lastval = 1;
  746.         return;
  747.     }
  748.     if (full(args) && ((char*)peekfirst(args))[0] == Inbrack &&
  749.             ((char*)peekfirst(args))[1] == '\0')
  750.         ((char*)peekfirst(args))[0] = '[';
  751.     if (type == SIMPLE && full(args) && !(cmd->flags & CFLAG_COMMAND)) {
  752.         char *s,*t;
  753.         cn = (Cmdnam) gethnode(t = s = peekfirst(args),cmdnamtab);
  754.         if (!cn && isset(HASHCMDS) && strcmp(t,"..")) {
  755.             while (*t && *t != '/') t++;
  756.             if (!*t) hashcmd(s,pathchecked);
  757.         }
  758.     }
  759.     if (type == SIMPLE && !cn && isset(AUTOCD) && isset(SHINSTDIN) &&
  760.             full(args) && !full(cmd->redir) &&
  761.             !nextnode(firstnode(args)) && cancd(peekfirst(args))) {
  762.         pushnode(args,strdup("cd"));
  763.         cn = (Cmdnam) gethnode("cd",cmdnamtab);
  764.     }
  765.  
  766.     /* this is nonzero if cmd is a current shell procedure */
  767.  
  768.     iscursh = (type >= CURSH) || (type == SIMPLE && cn &&
  769.         (cn->type == BUILTIN || cn->type == SHFUNC));
  770.  
  771.     /* if this command is backgrounded or (this is an external
  772.         command and we are not exec'ing it) or this is a builtin
  773.         with output piped somewhere, then fork.  If this is the
  774.         last stage in a subshell pipeline, don't fork, but make
  775.         the rest of the function think we forked. */
  776.  
  777.     if (bkg || !(iscursh || (cmd->flags & CFLAG_EXEC)) ||
  778.             (cn && (cn->type == BUILTIN || cn->type == SHFUNC) && output)) {
  779.         int synch[2];
  780.  
  781.         pipe(synch);
  782.         pid = (last1 && execok()) ? 0 : phork();
  783.         if (pid == -1) {
  784.             close(synch[0]);
  785.             close(synch[1]);
  786.             return;
  787.         }
  788.         if (pid) {
  789.             close(synch[1]);
  790.             read(synch[0],"foo",1);
  791.             close(synch[0]);
  792.             if (pid == -1)
  793.                 zerr("%e",NULL,errno);
  794.             else {
  795.                 if (bkg) lastpid = pid;
  796.                 ( void ) addproc(pid,text);
  797.             }
  798.             return;
  799.         }
  800.         close(synch[0]);
  801.         entersubsh(bkg);
  802.         close(synch[1]);
  803.         forked = 1;
  804.     }
  805.     if (bkg && isset(BGNICE))
  806.         nice(5);
  807.  
  808.     /* perform postfork substitutions */
  809.     postfork(args,!(cmd->flags & CFLAG_NOGLOB));
  810.     if (errflag) {
  811.         lastval = 1;
  812.         goto err;
  813.     } else {
  814.         char *s;
  815.         while (full(args) && (s = peekfirst(args)) && !*s) ugetnode(args);
  816.     }
  817.  
  818.     if (input)        /* add pipeline input/output to mnodes */
  819.         addfd(forked,save,mfds,0,input,0);
  820.     if (output)
  821.         addfd(forked,save,mfds,1,output,1);
  822.     spawnpipes(cmd->redir);        /* do process substitutions */
  823.     while (full(cmd->redir))
  824.         if ((fn = (struct redir*) ugetnode(cmd->redir))->type == INPIPE) {
  825.             if (fn->fd2 == -1)
  826.                 execerr();
  827.             addfd(forked,save,mfds,fn->fd1,fn->fd2,0);
  828.         } else if (fn->type == OUTPIPE) {
  829.             if (fn->fd2 == -1)
  830.                 execerr();
  831.             addfd(forked,save,mfds,fn->fd1,fn->fd2,1);
  832.         } else {
  833.             if (!(fn->type == HERESTR || fn->type == CLOSE || fn->type ==
  834.                     MERGE || fn->type == MERGEOUT))
  835.                 if (xpandredir(fn,cmd->redir))
  836.                     continue;
  837.             if (errflag) execerr();
  838.             if (fn->type == HERESTR) {
  839.                 fil = getherestr(fn);
  840.                 if (fil == -1) {
  841.                     if (errno != EINTR)
  842.                         zerr("%e",NULL,errno);
  843.                     execerr();
  844.                 }
  845.                 addfd(forked,save,mfds,fn->fd1,fil,0);
  846.             } else if (fn->type == READ) {
  847.                 fil = open(fn->name,O_RDONLY);
  848.                 if (fil == -1) {
  849.                     if (errno != EINTR)
  850.                         zerr("%e: %s",fn->name,errno);
  851.                     execerr();
  852.                 }
  853.                 addfd(forked,save,mfds,fn->fd1,fil,0);
  854.             } else if (fn->type == CLOSE) {
  855.                 if (!forked && fn->fd1 < 10)
  856.                     save[fn->fd1] = movefd(fn->fd1);
  857.                 closemn(mfds,fn->fd1);
  858.                 close(fn->fd1);
  859.             } else if (fn->type == MERGE || fn->type == MERGEOUT) {
  860.                 if (fn->fd2 == FD_COPROC)
  861.                     fn->fd2 = (fn->type == MERGEOUT) ? coprocout : coprocin;
  862.                 if (!forked && fn->fd1 < 10)
  863.                     save[fn->fd1] = movefd(fn->fd1);
  864.                 closemn(mfds,fn->fd1);
  865.                 fil = dup(fn->fd2);
  866.                 addfd(forked,save,mfds,fn->fd1,fil,fn->type == MERGEOUT);
  867.             } else {
  868.                 if (fn->type >= APP)
  869.                     fil = open(fn->name,
  870.                         (isset(NOCLOBBER) && !(fn->type & 1)) ?
  871.                         O_WRONLY|O_APPEND : O_WRONLY|O_APPEND|O_CREAT,0666);
  872.                 else
  873.                     fil = open(fn->name,dontclob(fn) ? 
  874.                         O_WRONLY|O_CREAT|O_EXCL : O_WRONLY|O_CREAT|O_TRUNC,0666);
  875.                 if (fil == -1) {
  876.                     if (errno != EINTR)
  877.                         zerr("%e: %s",fn->name,errno);
  878.                     execerr();
  879.                 }
  880.                 addfd(forked,save,mfds,fn->fd1,fil,1);
  881.             }
  882.         }
  883.     
  884.     /* we are done with redirection.  close the mnodes, spawning
  885.         tee/cat processes as necessary. */
  886.     for (t0 = 0; t0 != 10; t0++)
  887.         closemn(mfds,t0);
  888.  
  889.     if (nullexec)
  890.         return;
  891.     if (unset(NOEXEC))
  892.         if (type >= CURSH)
  893.             {
  894.             static int (*func[]) DCLPROTO((Cmd)) = {
  895.                 execcursh,exectime,execfuncdef,execfor,execwhile,
  896.                 execrepeat,execif,execcase,execselect,execcond };
  897.     
  898.             fixcline(args);
  899.             lastval = (func[type-CURSH])(cmd);
  900.             }
  901.         else if (iscursh)        /* builtin or shell function */
  902.             {
  903.             if (cmd->vars)
  904.                 addvars(cmd->vars,0);
  905.             fixcline(args);
  906.             if (cn && cn->type == SHFUNC)
  907.                 execshfunc(cmd,cn);
  908.             else
  909.                 {
  910.                 if (forked) closem();
  911.                 lastval = execbin(args,cn);
  912.                 if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
  913.                         lastval && !subsh) {
  914.                     fprintf(stderr,"zsh: exit %d\n",lastval);
  915.                 }
  916.                 fflush(stdout);
  917.                 if (ferror(stdout))
  918.                     {
  919.                     zerr("write error: %e",NULL,errno);
  920.                     clearerr(stdout);
  921.                     }
  922.                 }
  923.             }
  924.         else
  925.             {
  926.             if (cmd->vars)
  927.                 addvars(cmd->vars,1);
  928.             if (type == SIMPLE)
  929.                 {
  930.                 closem();
  931.                 execute(cmd->flags & CFLAG_DASH);
  932.                 }
  933.             else    /* ( ... ) */
  934.                 execlist(cmd->u.list);
  935.             }
  936. err:
  937.     if (forked)
  938.         _exit(lastval);
  939.     fixfds(save);
  940. }
  941.  
  942. /* restore fds after redirecting a builtin */
  943.  
  944. void fixfds(save) /**/
  945. int *save;
  946. {
  947. int t0;
  948.  
  949.     for (t0 = 0; t0 != 10; t0++)
  950.         if (save[t0])
  951.             redup(save[t0],t0);
  952. }
  953.  
  954. void entersubsh(bkg) /**/
  955. int bkg;
  956. {
  957.     if (!jobbing)
  958.         {
  959.         if (bkg && isatty(0))
  960.             {
  961.             close(0);
  962.             if (open("/dev/null",O_RDWR))
  963.                 {
  964.                 zerr("can't open /dev/null: %e",NULL,errno);
  965.                 _exit(1);
  966.                 }
  967.             }
  968.         }
  969.     else if (!jobtab[thisjob].gleader)
  970.         {
  971.         jobtab[thisjob].gleader = getpid();
  972.         setpgrp(0L,jobtab[thisjob].gleader);
  973.         if (!bkg)
  974.             attachtty(jobtab[thisjob].gleader);
  975.         }
  976.     else
  977.         setpgrp(0L,jobtab[thisjob].gleader);
  978.     subsh = 1;
  979.     if (SHTTY != -1)
  980.         {
  981.         close(SHTTY);
  982.         SHTTY = -1;
  983.         }
  984.     if (jobbing)
  985.         {
  986.         signal(SIGTTOU,SIG_DFL);
  987.         signal(SIGTTIN,SIG_DFL);
  988.         signal(SIGTSTP,SIG_DFL);
  989.         signal(SIGPIPE,SIG_DFL);
  990.         }
  991.     if (interact)
  992.         {
  993.         signal(SIGTERM,SIG_DFL);
  994.         if (sigtrapped[SIGINT])
  995.             signal(SIGINT,SIG_IGN);
  996.         }
  997.     if (!sigtrapped[SIGQUIT])
  998.         signal(SIGQUIT,SIG_DFL);
  999.     opts[MONITOR] = OPT_UNSET;
  1000.     clearjobtab();
  1001. }
  1002.  
  1003. /* close all internal shell fds */
  1004.  
  1005. void closem() /**/
  1006. {
  1007. int t0;
  1008.  
  1009.     for (t0 = 10; t0 != NOFILE; t0++)
  1010.         close(t0);
  1011. }
  1012.  
  1013. /* convert here document into a here string */
  1014.  
  1015. char *gethere(str,typ) /**/
  1016. char *str;int typ;
  1017. {
  1018. char pbuf[256];
  1019. int qt = 0,siz = 0,l,strip = 0;
  1020. char *s,*t,*bptr;
  1021.  
  1022.     for (s = str; *s; s++)
  1023.         if (*s == Nularg)
  1024.             qt = 1;
  1025.     untokenize(str);
  1026.     if (typ == HEREDOCDASH)
  1027.         {
  1028.         strip = 1;
  1029.         while (*str == '\t')
  1030.             str++;
  1031.         }
  1032.     t = ztrdup("");
  1033.     for(;;)
  1034.         {
  1035.         char *u,*v;
  1036.  
  1037.         if (!hgets(pbuf,256))
  1038.             break;
  1039.         bptr = pbuf;
  1040.         if (strip)
  1041.             while (*bptr == '\t')
  1042.                 bptr++;
  1043.         for (u = bptr, v = str; *u != '\n' && *v; u++,v++)
  1044.             if (*u != *v)
  1045.                 break;
  1046.         if (!(*u == '\n' && !*v))
  1047.             {
  1048.             l = strlen(bptr);
  1049.             if (!qt && l > 1 && bptr[l-1] == '\n' && bptr[l-2] == '\\')
  1050.                 bptr[l -= 2] = '\0';
  1051.             t = realloc(t,siz+l+1);
  1052.             strncpy(t+siz,bptr,l);
  1053.             siz += l;
  1054.             }
  1055.         else
  1056.             break;
  1057.         }
  1058.     t[siz] = '\0';
  1059.     if (siz && t[siz-1] == '\n')
  1060.         t[siz-1] = '\0';
  1061.     if (!qt)
  1062.         for (s = t; *s; s++)
  1063.             if (*s == '$') {
  1064.                 *s = Qstring;
  1065.             } else if (*s == '`') {
  1066.                 *s = Qtick;
  1067.             } else if (*s == '(') {
  1068.                 *s = Inpar;
  1069.             } else if (*s == ')') {
  1070.                 *s = Outpar;
  1071.             } else if (*s == '\\' &&
  1072.                 (s[1] == '$' || s[1] == '`')) chuck(s);
  1073.     s = strdup(t);
  1074.     free(t);
  1075.     return s;
  1076. }
  1077.  
  1078. /* open here string fd */
  1079.  
  1080. int getherestr(fn) /**/
  1081. struct redir *fn;
  1082. {
  1083. Lklist fake;
  1084. char *s = gettemp(),*t;
  1085. int fd;
  1086.  
  1087.     fake = newlist();
  1088.     addnode(fake,fn->name);
  1089.     prefork(fake);
  1090.     if (!errflag)
  1091.         postfork(fake,1);
  1092.     if (errflag)
  1093.         return -1;
  1094.     if ((fd = open(s,O_CREAT|O_WRONLY,0600)) == -1)
  1095.         return -1;
  1096.     while (t = ugetnode(fake))
  1097.         {
  1098.         untokenize(t);
  1099.         write(fd,t,strlen(t));
  1100.         if (full(fake))
  1101.             write(fd," ",1);
  1102.         }
  1103.     write(fd,"\n",1);
  1104.     close(fd);
  1105.     fd = open(s,O_RDONLY);
  1106.     unlink(s);
  1107.     return fd;
  1108. }
  1109.  
  1110. void catproc(mn) /**/
  1111. struct multio *mn;
  1112. {
  1113. int len,t0;
  1114. char *buf;
  1115.  
  1116.     if (phork())
  1117.         {
  1118.         for (t0 = 0; t0 != mn->ct; t0++)
  1119.             close(mn->fds[t0]);
  1120.         close(mn->pipe);
  1121.         return;
  1122.         }
  1123.     closeallelse(mn);
  1124.     buf = zalloc(4096);
  1125.     for (t0 = 0; t0 != mn->ct; t0++)
  1126.         while (len = read(mn->fds[t0],buf,4096))
  1127.             write(mn->pipe,buf,len);
  1128.     _exit(0);
  1129. }
  1130.  
  1131. void teeproc(mn) /**/
  1132. struct multio *mn;
  1133. {
  1134. int len,t0;
  1135. char *buf;
  1136.  
  1137.     if (phork())
  1138.         {
  1139.         for (t0 = 0; t0 != mn->ct; t0++)
  1140.             close(mn->fds[t0]);
  1141.         close(mn->pipe);
  1142.         return;
  1143.         }
  1144.     buf = zalloc(4096);
  1145.     closeallelse(mn);
  1146.     while ((len = read(mn->pipe,buf,4096)) > 0)
  1147.         for (t0 = 0; t0 != mn->ct; t0++)
  1148.             write(mn->fds[t0],buf,len);
  1149.     _exit(0);
  1150. }
  1151.  
  1152. void closeallelse(mn) /**/
  1153. struct multio *mn;
  1154. {
  1155. int t0,t1;
  1156.  
  1157.     for (t0 = 0; t0 != NOFILE; t0++)
  1158.         if (mn->pipe != t0)
  1159.             {
  1160.             for (t1 = 0; t1 != mn->ct; t1++)
  1161.                 if (mn->fds[t1] == t0)
  1162.                     break;
  1163.             if (t1 == mn->ct)
  1164.                 close(t0);
  1165.             }
  1166. }
  1167.  
  1168. long int zstrtol(s,t,base) /**/
  1169. char *s;char **t;int base;
  1170. {
  1171. int ret = 0;
  1172.  
  1173.     if (base <= 10)
  1174.         for (; *s >= '0' && *s < ('0'+base); s++)
  1175.             ret = ret*base+*s-'0';
  1176.     else
  1177.         for (; idigit(*s) || (*s >= 'a' && *s < ('a'+base-10))
  1178.                                 || (*s >= 'A' && *s < ('A'+base-10)); s++)
  1179.             ret = ret*base+(idigit(*s) ? (*s-'0') : (*s & 0x1f)+9);
  1180.     if (t)
  1181.         *t = (char *) s;
  1182.     return ret;
  1183. }
  1184.  
  1185. /* $(...) */
  1186.  
  1187. Lklist getoutput(cmd,qt) /**/
  1188. char *cmd;int qt;
  1189. {
  1190. List list;
  1191. int pipes[2];
  1192.  
  1193.     if (*cmd == '<') {
  1194.         int stream;
  1195.         char *fi,*s,x;
  1196.  
  1197.         for (cmd++; *cmd == ' '; cmd++);
  1198.         for (s = cmd; *s && *s != ' '; s++)
  1199.             if (*s == '\\') s++;
  1200.             else if (*s == '$') *s = String;
  1201.         x = *s;
  1202.         *s = '\0';
  1203.         fi = strdup(cmd);
  1204.         *s = x;
  1205.         if (*fi == '~')
  1206.             *fi = Tilde;
  1207.         else if (*fi == '=')
  1208.             *fi = Equals;
  1209.         singsub(&fi);
  1210.         if (errflag)
  1211.             return NULL;
  1212.         stream = open(fi,O_RDONLY);
  1213.         if (stream == -1) {
  1214.             zerr("%e: %s",fi,errno);
  1215.             return NULL;
  1216.         }
  1217.         return readoutput(stream,qt);
  1218.     }
  1219.     if (!(list = parselstring(cmd)))
  1220.         return NULL;
  1221.     mpipe(pipes);
  1222.     if (phork())
  1223.         {
  1224.         popheap();
  1225.         close(pipes[1]);
  1226.         /* chldsuspend(); */
  1227.         return readoutput(pipes[0],qt);
  1228.         }
  1229.     subsh = 1;
  1230.     close(pipes[0]);
  1231.     redup(pipes[1],1);
  1232.     entersubsh(0);
  1233.     signal(SIGTSTP,SIG_IGN);
  1234.     exiting = 1;
  1235.     execlist(list);
  1236.     close(1);
  1237.     exit(0);  return NULL;
  1238. }
  1239.  
  1240. /* read output of command substitution */
  1241.  
  1242. Lklist readoutput(in,qt) /**/
  1243. int in;int qt;
  1244. {
  1245. Lklist ret;
  1246. char *buf,*ptr;
  1247. int bsiz,c,cnt = 0;
  1248. FILE *fin;
  1249.  
  1250.     fin = fdopen(in,"r");
  1251.     ret = newlist();
  1252.     ptr = buf = ncalloc(bsiz = 64);
  1253.     while ((c = fgetc(fin)) != EOF)
  1254.         if (!qt && isep(c)) {
  1255.             if (cnt) {
  1256.                 *ptr = '\0';
  1257.                 addnode(ret,buf);
  1258.                 ptr = buf = ncalloc(bsiz = 64);
  1259.                 cnt = 0;
  1260.                 ptr = buf;
  1261.             }
  1262.         } else {
  1263.             *ptr++ = c;
  1264.             if (++cnt == bsiz) {
  1265.                 char *pp = ncalloc(bsiz *= 2);
  1266.                 
  1267.                 memcpy(pp,buf,cnt);
  1268.                 ptr = (buf = pp)+cnt;
  1269.             }
  1270.         }
  1271.     if (ptr != buf && ptr[-1] == '\n')
  1272.         ptr[-1] = '\0';
  1273.     else
  1274.         *ptr = '\0';
  1275.     if (cnt) addnode(ret,buf);
  1276.     fclose(fin);
  1277.     return ret;
  1278. }
  1279.  
  1280. /* =(...) */
  1281.  
  1282. char *getoutputfile(cmd) /**/
  1283. char *cmd;
  1284. {
  1285. #ifdef WAITPID
  1286. int pid;
  1287. #endif
  1288. char *nam = gettemp(),*str;
  1289. int tfil;
  1290. List list;
  1291.  
  1292.     if (thisjob == -1)
  1293.         return NULL;
  1294.     for (str = cmd; *str && *str != Outpar; str++);
  1295.     if (!*str)
  1296.         zerr("oops.",NULL,0);
  1297.     *str = '\0';
  1298.     if (!(list = parselstring(cmd)))
  1299.         return NULL;
  1300.     permalloc();
  1301.     if (!jobtab[thisjob].filelist)
  1302.         jobtab[thisjob].filelist = newlist();
  1303.     addnode(jobtab[thisjob].filelist,ztrdup(nam));
  1304.     heapalloc();
  1305. #ifdef WAITPID
  1306.     if (pid = phork())
  1307.         {
  1308.         popheap();
  1309.         waitpid(pid,NULL,WUNTRACED);
  1310.         return nam;
  1311.         }
  1312. #else
  1313.     if (waitfork()) {
  1314.         popheap();
  1315.         return nam;
  1316.     }
  1317. #endif
  1318.     subsh = 1;
  1319.     close(1);
  1320.     entersubsh(0);
  1321.     tfil = creat(nam,0666);
  1322.     exiting = 1;
  1323.     execlist(list);
  1324.     close(1);
  1325.     exit(0); return NULL;
  1326. }
  1327.  
  1328. /* get a temporary named pipe */
  1329.  
  1330. char *namedpipe() /**/
  1331. {
  1332. #ifndef NO_FIFOS
  1333. char *tnam = gettemp();
  1334.  
  1335.     if (mknod(tnam,0010666,0) < 0) return NULL;
  1336.     return tnam;
  1337. #else
  1338.     return NULL;
  1339. #endif
  1340. }
  1341.  
  1342. /* <(...) */
  1343.  
  1344. char *getoutproc(cmd) /**/
  1345. char *cmd;
  1346. {
  1347. #ifdef NO_FIFOS
  1348.     zerr("doesn't look like your system supports FIFOs.",NULL,0);
  1349.     return NULL;
  1350. #else
  1351. List list;
  1352. int fd;
  1353. char *pnam,*str;
  1354.  
  1355.     if (thisjob == -1)
  1356.         return NULL;
  1357.     for (str = cmd; *str && *str != Outpar; str++);
  1358.     if (!*str)
  1359.         zerr("oops.",NULL,0);
  1360.     *str = '\0';
  1361.     pnam = namedpipe();
  1362.     if (!pnam) return NULL;
  1363.     permalloc();
  1364.     if (!jobtab[thisjob].filelist)
  1365.         jobtab[thisjob].filelist = newlist();
  1366.     addnode(jobtab[thisjob].filelist,ztrdup(pnam));
  1367.     heapalloc();
  1368.     if (!(list = parselstring(cmd)))
  1369.         return NULL;
  1370.     if (phork())
  1371.         {
  1372.         popheap();
  1373.         return pnam;
  1374.         }
  1375.     entersubsh(1);
  1376.     closem();
  1377.     fd = open(pnam,O_WRONLY);
  1378.     if (fd == -1)
  1379.         {
  1380.         zerr("can't open %s: %e",pnam,errno);
  1381.         _exit(0);
  1382.         }
  1383.     redup(fd,1);
  1384.     fd = open("/dev/null",O_RDONLY);
  1385.     redup(fd,0);
  1386.     exiting = 1;
  1387.     execlist(list);
  1388.     close(1);
  1389.     _exit(0);  return NULL;
  1390. #endif
  1391. }
  1392.  
  1393. /* >(...) */
  1394.  
  1395. char *getinproc(cmd) /**/
  1396. char *cmd;
  1397. {
  1398. #ifdef NO_FIFOS
  1399.     zerr("doesn't look like your system supports FIFOs.",NULL,0);
  1400.     return NULL;
  1401. #else
  1402. List list;
  1403. int pid,fd;
  1404. char *pnam,*str;
  1405.  
  1406.     if (thisjob == -1)
  1407.         return NULL;
  1408.     for (str = cmd; *str && *str != Outpar; str++);
  1409.     if (!*str)
  1410.         zerr("oops.",NULL,0);
  1411.     *str = '\0';
  1412.     pnam = namedpipe();
  1413.     if (!pnam) return NULL;
  1414.     permalloc();
  1415.     if (!jobtab[thisjob].filelist)
  1416.         jobtab[thisjob].filelist = newlist();
  1417.     addnode(jobtab[thisjob].filelist,ztrdup(pnam));
  1418.     heapalloc();
  1419.     if (!(list = parselstring(cmd)))
  1420.         return NULL;
  1421.     if (pid = phork())
  1422.         {
  1423.         popheap();
  1424.         return pnam;
  1425.         }
  1426.     entersubsh(1);
  1427.     closem();
  1428.     fd = open(pnam,O_RDONLY);
  1429.     redup(fd,0);
  1430.     exiting = 1;
  1431.     execlist(list);
  1432.     _exit(0);  return NULL;
  1433. #endif
  1434. }
  1435.  
  1436. /* > >(...) (does not use named pipes) */
  1437.  
  1438. int getinpipe(cmd) /**/
  1439. char *cmd;
  1440. {
  1441. List list;
  1442. int pipes[2];
  1443. char *str = cmd;
  1444.  
  1445.     for (str = cmd; *str && *str != Outpar; str++);
  1446.     if (!*str)
  1447.         zerr("oops.",NULL,0);
  1448.     *str = '\0';
  1449.     if (!(list = parselstring(cmd+2)))
  1450.         return -1;
  1451.     mpipe(pipes);
  1452.     if (phork())
  1453.         {
  1454.         popheap();
  1455.         close(pipes[1]);
  1456.         return pipes[0];
  1457.         }
  1458.     close(pipes[0]);
  1459.     closem();
  1460.     entersubsh(1);
  1461.     redup(pipes[1],1);
  1462.     exiting = 1;
  1463.     execlist(list);
  1464.     _exit(0);  return 0;
  1465. }
  1466.  
  1467. /* < <(...) */
  1468.  
  1469. int getoutpipe(cmd) /**/
  1470. char *cmd;
  1471. {
  1472. List list;
  1473. int pipes[2];
  1474. char *str;
  1475.  
  1476.     for (str = cmd; *str && *str != Outpar; str++);
  1477.     if (!*str)
  1478.         zerr("oops.",NULL,0);
  1479.     *str = '\0';
  1480.     if (!(list = parselstring(cmd+2)))
  1481.         return -1;
  1482.     strinend();
  1483.     mpipe(pipes);
  1484.     if (phork())
  1485.         {
  1486.         popheap();
  1487.         close(pipes[0]);
  1488.         return pipes[1];
  1489.         }
  1490.     close(pipes[1]);
  1491.     closem();
  1492.     entersubsh(1);
  1493.     redup(pipes[0],0);
  1494.     exiting = 1;
  1495.     execlist(list);
  1496.     _exit(0);  return 0;
  1497. }
  1498.  
  1499. /* run a list, saving the current job num */
  1500.  
  1501. void runlist(l) /**/
  1502. List l;
  1503. {
  1504. int cj = thisjob;
  1505.  
  1506.     execlist(l);
  1507.     thisjob = cj;
  1508. }
  1509.  
  1510. char *gettemp() /**/
  1511. {
  1512.     return mktemp(dyncat(tmpprefix,"XXXXXX"));
  1513. }
  1514.  
  1515. /* my getwd; all the other ones I tried confused the SIGCHLD handler */
  1516.  
  1517. char *zgetwd() /**/
  1518. {
  1519. static char buf0[MAXPATHLEN];
  1520. char buf3[MAXPATHLEN],*buf2 = buf0+1;
  1521. struct stat sbuf;
  1522. struct direct *de;
  1523. DIR *dir;
  1524. ino_t ino = -1;
  1525. dev_t dev = -1;
  1526.  
  1527.     holdintr();
  1528.     buf2[0] = '\0';
  1529.     buf0[0] = '/';
  1530.     for(;;)
  1531.         {
  1532.         if (stat(".",&sbuf) < 0)
  1533.             {
  1534.             chdir(buf0);
  1535.             noholdintr();
  1536.             return ztrdup(".");
  1537.             }
  1538.         ino = sbuf.st_ino;
  1539.         dev = sbuf.st_dev;
  1540.         if (stat("..",&sbuf) < 0)
  1541.             {
  1542.             chdir(buf0);
  1543.             noholdintr();
  1544.             return ztrdup(".");
  1545.             }
  1546.         if (sbuf.st_ino == ino && sbuf.st_dev == dev)
  1547.             {
  1548.             chdir(buf0);
  1549.             noholdintr();
  1550.             return ztrdup(buf0);
  1551.             }
  1552.         dir = opendir("..");
  1553.         if (!dir)
  1554.             {
  1555.             chdir(buf0);
  1556.             noholdintr();
  1557.             return ztrdup(".");
  1558.             }
  1559.         chdir("..");
  1560.         readdir(dir); readdir(dir);
  1561.         while (de = readdir(dir))
  1562.             if (de->d_ino == ino)
  1563.                 {
  1564.                 lstat(de->d_name,&sbuf);
  1565.                 if (sbuf.st_dev == dev)
  1566.                     goto match;
  1567.                 }
  1568.         rewinddir(dir);
  1569.         readdir(dir); readdir(dir);
  1570.         while (de = readdir(dir))
  1571.             {
  1572.             lstat(de->d_name,&sbuf);
  1573.             if (sbuf.st_dev == dev)
  1574.                 goto match;
  1575.             }
  1576.         noholdintr();
  1577.         closedir(dir);
  1578.         return ztrdup(".");
  1579. match:
  1580.         strcpy(buf3,de->d_name);
  1581.         if (*buf2)
  1582.             strcat(buf3,"/");
  1583.         strcat(buf3,buf2);
  1584.         strcpy(buf2,buf3);
  1585.         closedir(dir);
  1586.         }
  1587. }
  1588.  
  1589. /* open pipes with fds >= 10 */
  1590.  
  1591. void mpipe(pp) /**/
  1592. int *pp;
  1593. {
  1594.     pipe(pp);
  1595.     pp[0] = movefd(pp[0]);
  1596.     pp[1] = movefd(pp[1]);
  1597. }
  1598.  
  1599. /* do process substitution with redirection */
  1600.  
  1601. void spawnpipes(l) /**/
  1602. Lklist l;
  1603. {
  1604. Lknode n = firstnode(l);
  1605. Redir f;
  1606.  
  1607.     for (; n; incnode(n))
  1608.         {
  1609.         f = (Redir) getdata(n);
  1610.         if (f->type == OUTPIPE)
  1611.             {
  1612.             char *str = f->name;
  1613.             f->fd2 = getoutpipe(str);
  1614.             }
  1615.         if (f->type == INPIPE)
  1616.             {
  1617.             char *str = f->name;
  1618.             f->fd2 = getinpipe(str);
  1619.             }
  1620.         }
  1621. }
  1622.  
  1623. /* perform time ... command */
  1624.  
  1625. int exectime(cmd) /**/
  1626. Cmd cmd;
  1627. {
  1628. int jb = thisjob;
  1629.  
  1630.     if (!cmd->u.pline) { shelltime(); return 0; }
  1631.     execpline(cmd->u.pline,TIMED,0);
  1632.     thisjob = jb;
  1633.     return lastval;
  1634. }
  1635.  
  1636. /* define a function */
  1637.  
  1638. int execfuncdef(cmd) /**/
  1639. Cmd cmd;
  1640. {
  1641. Cmdnam cc;
  1642. char *s;
  1643.  
  1644.     permalloc();
  1645.     while (s = ugetnode(cmd->args))
  1646.         {
  1647.         cc = (Cmdnam) zalloc(sizeof *cc);
  1648.         cc->type = SHFUNC;
  1649.         cc->flags = 0;
  1650.         if (!cmd->u.list)
  1651.             cc->u.list = NULL;
  1652.         else
  1653.             cc->u.list = (List) dupstruct(cmd->u.list);
  1654.         addhnode(ztrdup(s),cc,cmdnamtab,freecmdnam);
  1655.         if (!strncmp(s,"TRAP",4))
  1656.             {
  1657.             int t0 = getsignum(s+4);
  1658.  
  1659.             if (t0 != -1)
  1660.                 settrap(t0,cmd->u.list);
  1661.             }
  1662.         }
  1663.     heapalloc();
  1664.     return 0;
  1665. }
  1666.  
  1667. /* evaluate a [[ ... ]] */
  1668.  
  1669. int execcond(cmd) /**/
  1670. Cmd cmd;
  1671. {
  1672.     return !evalcond(cmd->u.cond);
  1673. }
  1674.  
  1675. void execshfunc(cmd,cn) /**/
  1676. Cmd cmd;Cmdnam cn;
  1677. {
  1678. List l;
  1679.  
  1680.     if (errflag) return;
  1681.     l = cn->u.list;
  1682.     if (!l) {
  1683.         char *nam;
  1684.  
  1685.         if (!(cn->flags & PMFLAG_u)) return;
  1686.         if (!(l = getfpfunc(nam = peekfirst(cmd->args)))) {
  1687.             zerr("function not found: %s",nam,0);
  1688.             lastval = 1;
  1689.             return;
  1690.         }
  1691.         cn->flags &= ~PMFLAG_u;
  1692.         permalloc();
  1693.         cn->u.list = (List) dupstruct(l);
  1694.         heapalloc();
  1695.     }
  1696.     doshfunc(l,cmd->args,cn->flags);
  1697. }
  1698.  
  1699. void doshfuncnoval(list,args,flags) /**/
  1700. List list; Lklist args; int flags;
  1701. {
  1702. int val = lastval;
  1703.  
  1704.     doshfunc(list,args,flags);
  1705.     lastval = val;
  1706. }
  1707.  
  1708. void doshfunc(list,args,flags) /**/
  1709. List list; Lklist args; int flags;
  1710. {
  1711. char **tab,**x,*oargv0;
  1712. int oxtr = opts[XTRACE],opev = opts[PRINTEXITVALUE],xexittr;
  1713. Lklist olist;
  1714. char *s;
  1715. List xexitfn;
  1716.  
  1717.     xexittr = sigtrapped[SIGEXIT];
  1718.     xexitfn = sigfuncs[SIGEXIT];
  1719.     tab = pparams;
  1720.     oargv0 = argzero;
  1721.     zoptind = 1;
  1722.     if (flags & PMFLAG_t) opts[XTRACE] = OPT_SET;
  1723.     opts[PRINTEXITVALUE] = OPT_UNSET;
  1724.     if (args) {
  1725.         pparams = x = (char **) zcalloc(((sizeof *x)*(1+countnodes(args))));
  1726.         argzero = ztrdup(ugetnode(args));
  1727.         while (*x = ugetnode(args))
  1728.             *x = ztrdup(*x), x++;
  1729.     } else {
  1730.         pparams = zcalloc(sizeof *pparams);
  1731.         argzero = ztrdup(argzero);
  1732.     }
  1733.     permalloc();
  1734.     olist = locallist;
  1735.     locallist = newlist();
  1736.     heapalloc();
  1737.     runlist(dupstruct(list));
  1738.     while (s = getnode(locallist)) unsetparam(s);
  1739.     free(locallist);
  1740.     locallist = olist;
  1741.     retflag = 0;
  1742.     freearray(pparams);
  1743.     free(argzero);
  1744.     argzero = oargv0;
  1745.     pparams = tab;
  1746.     if (sigfuncs[SIGEXIT] && sigfuncs[SIGEXIT] != xexitfn) {
  1747.         dotrap(SIGEXIT);
  1748.         freestruct(sigfuncs[SIGEXIT]);
  1749.     }
  1750.     sigtrapped[SIGEXIT] = xexittr;
  1751.     sigfuncs[SIGEXIT] = xexitfn;
  1752.     opts[XTRACE] = oxtr;
  1753.     opts[PRINTEXITVALUE] = opev;
  1754. }
  1755.  
  1756. /* search fpath for an undefined function */
  1757.  
  1758. List getfpfunc(s) /**/
  1759. char *s;
  1760. {
  1761. char **pp = fpath,buf[MAXPATHLEN];
  1762. int fd;
  1763.  
  1764.     for (; *pp; pp++)
  1765.         {
  1766.         sprintf(buf,"%s/%s",*pp,s);
  1767.         if (!access(buf,R_OK) && (fd = open(buf,O_RDONLY)) != -1)
  1768.             {
  1769.             int len = lseek(fd,0,2);
  1770.  
  1771.             if (len == -1)
  1772.                 close(fd);
  1773.             else
  1774.                 {
  1775.                 char *d;
  1776.  
  1777.                 lseek(fd,0,0);
  1778.                 d = zcalloc(len+1);
  1779.                 if (read(fd,d,len) != len)
  1780.                     {
  1781.                     free(d);
  1782.                     close(fd);
  1783.                     }
  1784.                 else
  1785.                     {
  1786.                     close(fd);
  1787.                     return parselstring(d);
  1788.                     }
  1789.                 }
  1790.             }
  1791.         }
  1792.     return NULL;
  1793. }
  1794.  
  1795. /* check to see if AUTOCD applies here */
  1796.  
  1797. int cancd(s)
  1798. char *s;
  1799. {
  1800. char *t;
  1801.  
  1802.     if ((t = getsparam(s)) && *t == '/') return 1;
  1803.     if (*s != '/')
  1804.         {
  1805.         char sbuf[MAXPATHLEN],**cp;
  1806.  
  1807.         if (cancd2(s))
  1808.             return 1;
  1809.         if (access(s,X_OK) == 0)
  1810.             return 0;
  1811.         for (cp = cdpath; *cp; cp++)
  1812.             {
  1813.             sprintf(sbuf,"%s/%s",*cp,s);
  1814.             if (cancd2(sbuf))
  1815.                 return 1;
  1816.             }
  1817.         return 0;
  1818.         }
  1819.     return cancd2(s);
  1820. }
  1821.  
  1822. int cancd2(s)
  1823. char *s;
  1824. {
  1825. struct stat buf;
  1826.  
  1827.     return !(access(s,X_OK) || stat(s,&buf) || !S_ISDIR(buf.st_mode));
  1828. }
  1829.  
  1830.