home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / csh / sem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-06  |  15.9 KB  |  642 lines

  1. /*-
  2.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)sem.c    5.22 (Berkeley) 11/6/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/ioctl.h>
  40. #include <sys/stat.h>
  41. #include <errno.h>
  42. #include <fcntl.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include <unistd.h>
  46. #if __STDC__
  47. # include <stdarg.h>
  48. #else
  49. # include <varargs.h>
  50. #endif
  51.  
  52. #include "csh.h"
  53. #include "proc.h"
  54. #include "extern.h"
  55.  
  56. static void     vffree __P((int));
  57. static Char    *splicepipe __P((struct command *t, Char *));
  58. static void     doio __P((struct command *t, int *, int *));
  59. static void     chkclob __P((char *));
  60.  
  61. void
  62. execute(t, wanttty, pipein, pipeout)
  63.     register struct command *t;
  64.     int     wanttty, *pipein, *pipeout;
  65. {
  66.     bool    forked = 0;
  67.     struct biltins *bifunc;
  68.     int     pid = 0;
  69.     int     pv[2];
  70.  
  71.     static sigset_t csigmask;
  72.  
  73.     static sigset_t ocsigmask;
  74.     static int onosigchld = 0;
  75.     static int nosigchld = 0;
  76.  
  77.     if (t == 0)
  78.     return;
  79.  
  80.     if (t->t_dflg & F_AMPERSAND)
  81.     wanttty = 0;
  82.     switch (t->t_dtyp) {
  83.  
  84.     case NODE_COMMAND:
  85.     if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
  86.         (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
  87.     if ((t->t_dflg & F_REPEAT) == 0)
  88.         Dfix(t);        /* $ " ' \ */
  89.     if (t->t_dcom[0] == 0)
  90.         return;
  91.     /* fall into... */
  92.  
  93.     case NODE_PAREN:
  94.     if (t->t_dflg & F_PIPEOUT)
  95.         mypipe(pipeout);
  96.     /*
  97.      * Must do << early so parent will know where input pointer should be.
  98.      * If noexec then this is all we do.
  99.      */
  100.     if (t->t_dflg & F_READ) {
  101.         (void) close(0);
  102.         heredoc(t->t_dlef);
  103.         if (noexec)
  104.         (void) close(0);
  105.     }
  106.  
  107.     set(STRstatus, Strsave(STR0));
  108.  
  109.     /*
  110.      * This mess is the necessary kludge to handle the prefix builtins:
  111.      * nice, nohup, time.  These commands can also be used by themselves,
  112.      * and this is not handled here. This will also work when loops are
  113.      * parsed.
  114.      */
  115.     while (t->t_dtyp == NODE_COMMAND)
  116.         if (eq(t->t_dcom[0], STRnice))
  117.         if (t->t_dcom[1])
  118.             if (strchr("+-", t->t_dcom[1][0]))
  119.             if (t->t_dcom[2]) {
  120.                 setname("nice");
  121.                 t->t_nice =
  122.                 getn(t->t_dcom[1]);
  123.                 lshift(t->t_dcom, 2);
  124.                 t->t_dflg |= F_NICE;
  125.             }
  126.             else
  127.                 break;
  128.             else {
  129.             t->t_nice = 4;
  130.             lshift(t->t_dcom, 1);
  131.             t->t_dflg |= F_NICE;
  132.             }
  133.         else
  134.             break;
  135.         else if (eq(t->t_dcom[0], STRnohup))
  136.         if (t->t_dcom[1]) {
  137.             t->t_dflg |= F_NOHUP;
  138.             lshift(t->t_dcom, 1);
  139.         }
  140.         else
  141.             break;
  142.         else if (eq(t->t_dcom[0], STRtime))
  143.         if (t->t_dcom[1]) {
  144.             t->t_dflg |= F_TIME;
  145.             lshift(t->t_dcom, 1);
  146.         }
  147.         else
  148.             break;
  149.         else
  150.         break;
  151.  
  152.     /* is it a command */
  153.     if (t->t_dtyp == NODE_COMMAND) {
  154.         /*
  155.          * Check if we have a builtin function and remember which one.
  156.          */
  157.         bifunc = isbfunc(t);
  158.          if (noexec) {
  159.         /*
  160.          * Continue for builtins that are part of the scripting language
  161.          */
  162.         if (bifunc->bfunct != dobreak   && bifunc->bfunct != docontin &&
  163.             bifunc->bfunct != doelse    && bifunc->bfunct != doend    &&
  164.             bifunc->bfunct != doforeach && bifunc->bfunct != dogoto   &&
  165.             bifunc->bfunct != doif      && bifunc->bfunct != dorepeat &&
  166.             bifunc->bfunct != doswbrk   && bifunc->bfunct != doswitch &&
  167.             bifunc->bfunct != dowhile   && bifunc->bfunct != dozip)
  168.             break;
  169.         }
  170.     }
  171.     else {            /* not a command */
  172.         bifunc = NULL;
  173.         if (noexec)
  174.         break;
  175.     }
  176.  
  177.     /*
  178.      * We fork only if we are timed, or are not the end of a parenthesized
  179.      * list and not a simple builtin function. Simple meaning one that is
  180.      * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
  181.      * fork in some of these cases.
  182.      */
  183.     /*
  184.      * Prevent forking cd, pushd, popd, chdir cause this will cause the
  185.      * shell not to change dir!
  186.      */
  187.     if (bifunc && (bifunc->bfunct == dochngd ||
  188.                bifunc->bfunct == dopushd ||
  189.                bifunc->bfunct == dopopd))
  190.         t->t_dflg &= ~(F_NICE);
  191.     if (((t->t_dflg & F_TIME) || (t->t_dflg & F_NOFORK) == 0 &&
  192.          (!bifunc || t->t_dflg &
  193.           (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP))) ||
  194.     /*
  195.      * We have to fork for eval too.
  196.      */
  197.         (bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 &&
  198.          bifunc->bfunct == doeval))
  199.         if (t->t_dtyp == NODE_PAREN ||
  200.         t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) {
  201.         forked++;
  202.         /*
  203.          * We need to block SIGCHLD here, so that if the process does
  204.          * not die before we can set the process group
  205.          */
  206.         if (wanttty >= 0 && !nosigchld) {
  207.             csigmask = sigblock(sigmask(SIGCHLD));
  208.             nosigchld = 1;
  209.         }
  210.  
  211.         pid = pfork(t, wanttty);
  212.         if (pid == 0 && nosigchld) {
  213.             (void) sigsetmask(csigmask);
  214.             nosigchld = 0;
  215.         }
  216.         else if (pid != 0 && (t->t_dflg & F_AMPERSAND))
  217.             backpid = pid;
  218.  
  219.         }
  220.         else {
  221.         int     ochild, osetintr, ohaderr, odidfds;
  222.         int     oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp;
  223.         sigset_t omask;
  224.  
  225.         /*
  226.          * Prepare for the vfork by saving everything that the child
  227.          * corrupts before it exec's. Note that in some signal
  228.          * implementations which keep the signal info in user space
  229.          * (e.g. Sun's) it will also be necessary to save and restore
  230.          * the current sigvec's for the signals the child touches
  231.          * before it exec's.
  232.          */
  233.         if (wanttty >= 0 && !nosigchld && !noexec) {
  234.             csigmask = sigblock(sigmask(SIGCHLD));
  235.             nosigchld = 1;
  236.         }
  237.         omask = sigblock(sigmask(SIGCHLD) | sigmask(SIGINT));
  238.         ochild = child;
  239.         osetintr = setintr;
  240.         ohaderr = haderr;
  241.         odidfds = didfds;
  242.         oSHIN = SHIN;
  243.         oSHOUT = SHOUT;
  244.         oSHERR = SHERR;
  245.         oOLDSTD = OLDSTD;
  246.         otpgrp = tpgrp;
  247.         ocsigmask = csigmask;
  248.         onosigchld = nosigchld;
  249.         Vsav = Vdp = 0;
  250.         Vexpath = 0;
  251.         Vt = 0;
  252.         pid = vfork();
  253.  
  254.         if (pid < 0) {
  255.             (void) sigsetmask(omask);
  256.             stderror(ERR_NOPROC);
  257.         }
  258.         forked++;
  259.         if (pid) {    /* parent */
  260.             child = ochild;
  261.             setintr = osetintr;
  262.             haderr = ohaderr;
  263.             didfds = odidfds;
  264.             SHIN = oSHIN;
  265.             SHOUT = oSHOUT;
  266.             SHERR = oSHERR;
  267.             OLDSTD = oOLDSTD;
  268.             tpgrp = otpgrp;
  269.             csigmask = ocsigmask;
  270.             nosigchld = onosigchld;
  271.  
  272.             xfree((ptr_t) Vsav);
  273.             Vsav = 0;
  274.             xfree((ptr_t) Vdp);
  275.             Vdp = 0;
  276.             xfree((ptr_t) Vexpath);
  277.             Vexpath = 0;
  278.             blkfree((Char **) Vt);
  279.             Vt = 0;
  280.             /* this is from pfork() */
  281.             palloc(pid, t);
  282.             (void) sigsetmask(omask);
  283.         }
  284.         else {        /* child */
  285.             /* this is from pfork() */
  286.             int     pgrp;
  287.             bool    ignint = 0;
  288.  
  289.             if (nosigchld) {
  290.             (void) sigsetmask(csigmask);
  291.             nosigchld = 0;
  292.             }
  293.  
  294.             if (setintr)
  295.             ignint =
  296.                 (tpgrp == -1 &&
  297.                  (t->t_dflg & F_NOINTERRUPT))
  298.                 || gointr && eq(gointr, STRminus);
  299.             pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
  300.             child++;
  301.             if (setintr) {
  302.             setintr = 0;
  303.             if (ignint) {
  304.                 (void) signal(SIGINT, SIG_IGN);
  305.                 (void) signal(SIGQUIT, SIG_IGN);
  306.             }
  307.             else {
  308.                 (void) signal(SIGINT, vffree);
  309.                 (void) signal(SIGQUIT, SIG_DFL);
  310.             }
  311.  
  312.             if (wanttty >= 0) {
  313.                 (void) signal(SIGTSTP, SIG_DFL);
  314.                 (void) signal(SIGTTIN, SIG_DFL);
  315.                 (void) signal(SIGTTOU, SIG_DFL);
  316.             }
  317.  
  318.             (void) signal(SIGTERM, parterm);
  319.             }
  320.             else if (tpgrp == -1 &&
  321.                  (t->t_dflg & F_NOINTERRUPT)) {
  322.             (void) signal(SIGINT, SIG_IGN);
  323.             (void) signal(SIGQUIT, SIG_IGN);
  324.             }
  325.  
  326.             pgetty(wanttty, pgrp);
  327.             if (t->t_dflg & F_NOHUP)
  328.             (void) signal(SIGHUP, SIG_IGN);
  329.             if (t->t_dflg & F_NICE)
  330.             (void) setpriority(PRIO_PROCESS, 0, t->t_nice);
  331.         }
  332.  
  333.         }
  334.     if (pid != 0) {
  335.         /*
  336.          * It would be better if we could wait for the whole job when we
  337.          * knew the last process had been started.  Pwait, in fact, does
  338.          * wait for the whole job anyway, but this test doesn't really
  339.          * express our intentions.
  340.          */
  341.         if (didfds == 0 && t->t_dflg & F_PIPEIN) {
  342.         (void) close(pipein[0]);
  343.         (void) close(pipein[1]);
  344.         }
  345.         if ((t->t_dflg & F_PIPEOUT) == 0) {
  346.         if (nosigchld) {
  347.             (void) sigsetmask(csigmask);
  348.             nosigchld = 0;
  349.         }
  350.         if ((t->t_dflg & F_AMPERSAND) == 0)
  351.             pwait();
  352.         }
  353.         break;
  354.     }
  355.     doio(t, pipein, pipeout);
  356.     if (t->t_dflg & F_PIPEOUT) {
  357.         (void) close(pipeout[0]);
  358.         (void) close(pipeout[1]);
  359.     }
  360.     /*
  361.      * Perform a builtin function. If we are not forked, arrange for
  362.      * possible stopping
  363.      */
  364.     if (bifunc) {
  365.         func(t, bifunc);
  366.         if (forked)
  367.         exitstat();
  368.         break;
  369.     }
  370.     if (t->t_dtyp != NODE_PAREN) {
  371.         doexec(NULL, t);
  372.         /* NOTREACHED */
  373.     }
  374.     /*
  375.      * For () commands must put new 0,1,2 in FSH* and recurse
  376.      */
  377.     OLDSTD = dcopy(0, FOLDSTD);
  378.     SHOUT = dcopy(1, FSHOUT);
  379.     SHERR = dcopy(2, FSHERR);
  380.     (void) close(SHIN);
  381.     SHIN = -1;
  382.     didfds = 0;
  383.     wanttty = -1;
  384.     t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT;
  385.     execute(t->t_dspr, wanttty, NULL, NULL);
  386.     exitstat();
  387.  
  388.     case NODE_PIPE:
  389.     t->t_dcar->t_dflg |= F_PIPEOUT |
  390.         (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT));
  391.     execute(t->t_dcar, wanttty, pipein, pv);
  392.     t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
  393.             (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT));
  394.     if (wanttty > 0)
  395.         wanttty = 0;    /* got tty already */
  396.     execute(t->t_dcdr, wanttty, pv, pipeout);
  397.     break;
  398.  
  399.     case NODE_LIST:
  400.     if (t->t_dcar) {
  401.         t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
  402.         execute(t->t_dcar, wanttty, NULL, NULL);
  403.         /*
  404.          * In strange case of A&B make a new job after A
  405.          */
  406.         if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
  407.         (t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
  408.         pendjob();
  409.     }
  410.     if (t->t_dcdr) {
  411.         t->t_dcdr->t_dflg |= t->t_dflg &
  412.         (F_NOFORK | F_NOINTERRUPT);
  413.         execute(t->t_dcdr, wanttty, NULL, NULL);
  414.     }
  415.     break;
  416.  
  417.     case NODE_OR:
  418.     case NODE_AND:
  419.     if (t->t_dcar) {
  420.         t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
  421.         execute(t->t_dcar, wanttty, NULL, NULL);
  422.         if ((getn(value(STRstatus)) == 0) !=
  423.         (t->t_dtyp == NODE_AND))
  424.         return;
  425.     }
  426.     if (t->t_dcdr) {
  427.         t->t_dcdr->t_dflg |= t->t_dflg &
  428.         (F_NOFORK | F_NOINTERRUPT);
  429.         execute(t->t_dcdr, wanttty, NULL, NULL);
  430.     }
  431.     break;
  432.     }
  433.     /*
  434.      * Fall through for all breaks from switch
  435.      * 
  436.      * If there will be no more executions of this command, flush all file
  437.      * descriptors. Places that turn on the F_REPEAT bit are responsible for
  438.      * doing donefds after the last re-execution
  439.      */
  440.     if (didfds && !(t->t_dflg & F_REPEAT))
  441.     donefds();
  442. }
  443.  
  444. static void
  445. vffree(i)
  446. int i;
  447. {
  448.     register Char **v;
  449.  
  450.     if (v = gargv) {
  451.     gargv = 0;
  452.     xfree((ptr_t) v);
  453.     }
  454.     if (v = pargv) {
  455.     pargv = 0;
  456.     xfree((ptr_t) v);
  457.     }
  458.     _exit(i);
  459. }
  460.  
  461. /*
  462.  * Expand and glob the words after an i/o redirection.
  463.  * If more than one word is generated, then update the command vector.
  464.  *
  465.  * This is done differently in all the shells:
  466.  * 1. in the bourne shell and ksh globbing is not performed
  467.  * 2. Bash/csh say ambiguous
  468.  * 3. zsh does i/o to/from all the files
  469.  * 4. itcsh concatenates the words.
  470.  *
  471.  * I don't know what is best to do. I think that Ambiguous is better
  472.  * than restructuring the command vector, because the user can get
  473.  * unexpected results. In any case, the command vector restructuring 
  474.  * code is present and the user can choose it by setting noambiguous
  475.  */
  476. static Char *
  477. splicepipe(t, cp)
  478.     register struct command *t;
  479.     Char *cp;    /* word after < or > */
  480. {
  481.     Char *blk[2];
  482.  
  483.     if (adrof(STRnoambiguous)) {
  484.     Char **pv;
  485.  
  486.     blk[0] = Dfix1(cp); /* expand $ */
  487.     blk[1] = NULL;
  488.  
  489.     gflag = 0, tglob(blk);
  490.     if (gflag) {
  491.         pv = globall(blk);
  492.         if (pv == NULL) {
  493.         setname(vis_str(blk[0]));
  494.         xfree((ptr_t) blk[0]);
  495.         stderror(ERR_NAME | ERR_NOMATCH);
  496.         }
  497.         gargv = NULL;
  498.         if (pv[1] != NULL) { /* we need to fix the command vector */
  499.         Char **av = blkspl(t->t_dcom, &pv[1]);
  500.         xfree((ptr_t) t->t_dcom);
  501.         t->t_dcom = av;
  502.         }
  503.         xfree((ptr_t) blk[0]);
  504.         blk[0] = pv[0];
  505.         xfree((ptr_t) pv);
  506.     }
  507.     }
  508.     else {
  509.     blk[0] = globone(blk[1] = Dfix1(cp), G_ERROR);
  510.     xfree((ptr_t) blk[1]);
  511.     }
  512.     return(blk[0]);
  513. }
  514.  
  515. /*
  516.  * Perform io redirection.
  517.  * We may or maynot be forked here.
  518.  */
  519. static void
  520. doio(t, pipein, pipeout)
  521.     register struct command *t;
  522.     int    *pipein, *pipeout;
  523. {
  524.     register int fd;
  525.     register Char *cp;
  526.     register int flags = t->t_dflg;
  527.  
  528.     if (didfds || (flags & F_REPEAT))
  529.     return;
  530.     if ((flags & F_READ) == 0) {/* F_READ already done */
  531.     if (t->t_dlef) {
  532.         char    tmp[MAXPATHLEN+1];
  533.  
  534.         /*
  535.          * so < /dev/std{in,out,err} work
  536.          */
  537.         (void) dcopy(SHIN, 0);
  538.         (void) dcopy(SHOUT, 1);
  539.         (void) dcopy(SHERR, 2);
  540.         cp = splicepipe(t, t->t_dlef);
  541.         (void) strncpy(tmp, short2str(cp), MAXPATHLEN);
  542.         tmp[MAXPATHLEN] = '\0';
  543.         xfree((ptr_t) cp);
  544.         if ((fd = open(tmp, O_RDONLY)) < 0)
  545.         stderror(ERR_SYSTEM, tmp, strerror(errno));
  546.         (void) dmove(fd, 0);
  547.     }
  548.     else if (flags & F_PIPEIN) {
  549.         (void) close(0);
  550.         (void) dup(pipein[0]);
  551.         (void) close(pipein[0]);
  552.         (void) close(pipein[1]);
  553.     }
  554.     else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
  555.         (void) close(0);
  556.         (void) open(_PATH_DEVNULL, O_RDONLY);
  557.     }
  558.     else {
  559.         (void) close(0);
  560.         (void) dup(OLDSTD);
  561.         (void) ioctl(0, FIONCLEX, NULL);
  562.     }
  563.     }
  564.     if (t->t_drit) {
  565.     char    tmp[MAXPATHLEN+1];
  566.  
  567.     cp = splicepipe(t, t->t_drit);
  568.     (void) strncpy(tmp, short2str(cp), MAXPATHLEN);
  569.     tmp[MAXPATHLEN] = '\0';
  570.     xfree((ptr_t) cp);
  571.     /*
  572.      * so > /dev/std{out,err} work
  573.      */
  574.     (void) dcopy(SHOUT, 1);
  575.     (void) dcopy(SHERR, 2);
  576.     if ((flags & F_APPEND) &&
  577. #ifdef O_APPEND
  578.         (fd = open(tmp, O_WRONLY | O_APPEND)) >= 0);
  579. #else
  580.         (fd = open(tmp, O_WRONLY)) >= 0)
  581.         (void) lseek(1, (off_t) 0, L_XTND);
  582. #endif
  583.     else {
  584.         if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) {
  585.         if (flags & F_APPEND)
  586.             stderror(ERR_SYSTEM, tmp, strerror(errno));
  587.         chkclob(tmp);
  588.         }
  589.         if ((fd = creat(tmp, 0666)) < 0)
  590.         stderror(ERR_SYSTEM, tmp, strerror(errno));
  591.     }
  592.     (void) dmove(fd, 1);
  593.     }
  594.     else if (flags & F_PIPEOUT) {
  595.     (void) close(1);
  596.     (void) dup(pipeout[1]);
  597.     }
  598.     else {
  599.     (void) close(1);
  600.     (void) dup(SHOUT);
  601.     (void) ioctl(1, FIONCLEX, NULL);
  602.     }
  603.  
  604.     (void) close(2);
  605.     if (flags & F_STDERR) {
  606.     (void) dup(1);
  607.     }
  608.     else {
  609.     (void) dup(SHERR);
  610.     (void) ioctl(2, FIONCLEX, NULL);
  611.     }
  612.     didfds = 1;
  613. }
  614.  
  615. void
  616. mypipe(pv)
  617.     register int *pv;
  618. {
  619.  
  620.     if (pipe(pv) < 0)
  621.     goto oops;
  622.     pv[0] = dmove(pv[0], -1);
  623.     pv[1] = dmove(pv[1], -1);
  624.     if (pv[0] >= 0 && pv[1] >= 0)
  625.     return;
  626. oops:
  627.     stderror(ERR_PIPE);
  628. }
  629.  
  630. static void
  631. chkclob(cp)
  632.     register char *cp;
  633. {
  634.     struct stat stb;
  635.  
  636.     if (stat(cp, &stb) < 0)
  637.     return;
  638.     if (S_ISCHR(stb.st_mode))
  639.     return;
  640.     stderror(ERR_EXISTS, cp);
  641. }
  642.