home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / sh / redir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-15  |  7.7 KB  |  351 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)redir.c    5.1 (Berkeley) 3/7/91";
  39. #endif /* not lint */
  40.  
  41. /*
  42.  * Code for dealing with input/output redirection.
  43.  */
  44.  
  45. #include "shell.h"
  46. #include "nodes.h"
  47. #include "jobs.h"
  48. #include "expand.h"
  49. #include "redir.h"
  50. #include "output.h"
  51. #include "memalloc.h"
  52. #include "error.h"
  53. #include <signal.h>
  54. #include <fcntl.h>
  55. #include <errno.h>
  56.  
  57.  
  58. #define EMPTY -2        /* marks an unused slot in redirtab */
  59. #define PIPESIZE 4096        /* amount of buffering in a pipe */
  60.  
  61.  
  62. MKINIT
  63. struct redirtab {
  64.     struct redirtab *next;
  65.     short renamed[10];
  66. };
  67.  
  68.  
  69. MKINIT struct redirtab *redirlist;
  70.  
  71.  
  72. #ifdef __STDC__
  73. STATIC void openredirect(union node *, char *);
  74. STATIC int openhere(union node *);
  75. #else
  76. STATIC void openredirect();
  77. STATIC int openhere();
  78. #endif
  79.  
  80.  
  81.  
  82. /*
  83.  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
  84.  * old file descriptors are stashed away so that the redirection can be
  85.  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
  86.  * standard output, and the standard error if it becomes a duplicate of
  87.  * stdout, is saved in memory.
  88.  */
  89.  
  90. void
  91. redirect(redir, flags)
  92.     union node *redir;
  93.     int flags;
  94.     {
  95.     union node *n;
  96.     struct redirtab *sv;
  97.     int i;
  98.     int fd;
  99.     char memory[10];        /* file descriptors to write to memory */
  100.  
  101.     for (i = 10 ; --i >= 0 ; )
  102.         memory[i] = 0;
  103.     memory[1] = flags & REDIR_BACKQ;
  104.     if (flags & REDIR_PUSH) {
  105.         sv = ckmalloc(sizeof (struct redirtab));
  106.         for (i = 0 ; i < 10 ; i++)
  107.             sv->renamed[i] = EMPTY;
  108.         sv->next = redirlist;
  109.         redirlist = sv;
  110.     }
  111.     for (n = redir ; n ; n = n->nfile.next) {
  112.         fd = n->nfile.fd;
  113.         if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
  114.             INTOFF;
  115.             if ((i = copyfd(fd, 10)) != EMPTY) {
  116.                 sv->renamed[fd] = i;
  117.                 close(fd);
  118.             }
  119.             INTON;
  120.             if (i == EMPTY)
  121.                 error("Out of file descriptors");
  122.         } else {
  123.             close(fd);
  124.         }
  125.         openredirect(n, memory);
  126.     }
  127.     if (memory[1])
  128.         out1 = &memout;
  129.     if (memory[2])
  130.         out2 = &memout;
  131. }
  132.  
  133.  
  134. STATIC void
  135. openredirect(redir, memory)
  136.     union node *redir;
  137.     char memory[10];
  138.     {
  139.     int fd = redir->nfile.fd;
  140.     char *fname;
  141.     int f;
  142.  
  143.     /*
  144.      * We suppress interrupts so that we won't leave open file
  145.      * descriptors around.  This may not be such a good idea because
  146.      * an open of a device or a fifo can block indefinitely.
  147.      */
  148.     INTOFF;
  149.     memory[fd] = 0;
  150.     switch (redir->nfile.type) {
  151.     case NFROM:
  152.         fname = redir->nfile.expfname;
  153.         if ((f = open(fname, O_RDONLY)) < 0)
  154.             error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
  155. movefd:
  156.         if (f != fd) {
  157.             copyfd(f, fd);
  158.             close(f);
  159.         }
  160.         break;
  161.     case NTO:
  162.         fname = redir->nfile.expfname;
  163. #ifdef O_CREAT
  164.         if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
  165.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  166. #else
  167.         if ((f = creat(fname, 0666)) < 0)
  168.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  169. #endif
  170.         goto movefd;
  171.     case NAPPEND:
  172.         fname = redir->nfile.expfname;
  173. #ifdef O_APPEND
  174.         if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
  175.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  176. #else
  177.         if ((f = open(fname, O_WRONLY)) < 0
  178.          && (f = creat(fname, 0666)) < 0)
  179.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  180.         lseek(f, 0L, 2);
  181. #endif
  182.         goto movefd;
  183.     case NTOFD:
  184.     case NFROMFD:
  185.         if (redir->ndup.dupfd >= 0) {    /* if not ">&-" */
  186.             if (memory[redir->ndup.dupfd])
  187.                 memory[fd] = 1;
  188.             else
  189.                 copyfd(redir->ndup.dupfd, fd);
  190.         }
  191.         break;
  192.     case NHERE:
  193.     case NXHERE:
  194.         f = openhere(redir);
  195.         goto movefd;
  196.     default:
  197.         abort();
  198.     }
  199.     INTON;
  200. }
  201.  
  202.  
  203. /*
  204.  * Handle here documents.  Normally we fork off a process to write the
  205.  * data to a pipe.  If the document is short, we can stuff the data in
  206.  * the pipe without forking.
  207.  */
  208.  
  209. STATIC int
  210. openhere(redir)
  211.     union node *redir;
  212.     {
  213.     int pip[2];
  214.     int len;
  215.  
  216.     if (pipe(pip) < 0)
  217.         error("Pipe call failed");
  218.     if (redir->type == NHERE) {
  219.         len = strlen(redir->nhere.doc->narg.text);
  220.         if (len <= PIPESIZE) {
  221.             xwrite(pip[1], redir->nhere.doc->narg.text, len);
  222.             goto out;
  223.         }
  224.     }
  225.     if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
  226.         close(pip[0]);
  227.         signal(SIGINT, SIG_IGN);
  228.         signal(SIGQUIT, SIG_IGN);
  229.         signal(SIGHUP, SIG_IGN);
  230. #ifdef SIGTSTP
  231.         signal(SIGTSTP, SIG_IGN);
  232. #endif
  233.         signal(SIGPIPE, SIG_DFL);
  234.         if (redir->type == NHERE)
  235.             xwrite(pip[1], redir->nhere.doc->narg.text, len);
  236.         else
  237.             expandhere(redir->nhere.doc, pip[1]);
  238.         _exit(0);
  239.     }
  240. out:
  241.     close(pip[1]);
  242.     return pip[0];
  243. }
  244.  
  245.  
  246.  
  247. /*
  248.  * Undo the effects of the last redirection.
  249.  */
  250.  
  251. void
  252. popredir() {
  253.     register struct redirtab *rp = redirlist;
  254.     int i;
  255.  
  256.     for (i = 0 ; i < 10 ; i++) {
  257.         if (rp->renamed[i] != EMPTY) {
  258.             close(i);
  259.             if (rp->renamed[i] >= 0) {
  260.                 copyfd(rp->renamed[i], i);
  261.                 close(rp->renamed[i]);
  262.             }
  263.         }
  264.     }
  265.     INTOFF;
  266.     redirlist = rp->next;
  267.     ckfree(rp);
  268.     INTON;
  269. }
  270.  
  271.  
  272.  
  273. /*
  274.  * Undo all redirections.  Called on error or interrupt.
  275.  */
  276.  
  277. #ifdef mkinit
  278.  
  279. INCLUDE "redir.h"
  280.  
  281. RESET {
  282.     while (redirlist)
  283.         popredir();
  284. }
  285.  
  286. SHELLPROC {
  287.     clearredir();
  288. }
  289.  
  290. #endif
  291.  
  292.  
  293. /*
  294.  * Discard all saved file descriptors.
  295.  */
  296.  
  297. void
  298. clearredir() {
  299.     register struct redirtab *rp;
  300.     int i;
  301.  
  302.     for (rp = redirlist ; rp ; rp = rp->next) {
  303.         for (i = 0 ; i < 10 ; i++) {
  304.             if (rp->renamed[i] >= 0) {
  305.                 close(rp->renamed[i]);
  306.             }
  307.             rp->renamed[i] = EMPTY;
  308.         }
  309.     }
  310. }
  311.  
  312.  
  313.  
  314. /*
  315.  * Copy a file descriptor, like the F_DUPFD option of fcntl.  Returns -1
  316.  * if the source file descriptor is closed, EMPTY if there are no unused
  317.  * file descriptors left.
  318.  */
  319.  
  320. int
  321. copyfd(from, to) {
  322. #ifdef F_DUPFD
  323.     int newfd;
  324.  
  325.     newfd = fcntl(from, F_DUPFD, to);
  326.     if (newfd < 0 && errno == EMFILE)
  327.         return EMPTY;
  328.     return newfd;
  329. #else
  330.     char toclose[32];
  331.     int i;
  332.     int newfd;
  333.     int e;
  334.  
  335.     for (i = 0 ; i < to ; i++)
  336.         toclose[i] = 0;
  337.     INTOFF;
  338.     while ((newfd = dup(from)) >= 0 && newfd < to)
  339.         toclose[newfd] = 1;
  340.     e = errno;
  341.     for (i = 0 ; i < to ; i++) {
  342.         if (toclose[i])
  343.             close(i);
  344.     }
  345.     INTON;
  346.     if (newfd < 0 && e == EMFILE)
  347.         return EMPTY;
  348.     return newfd;
  349. #endif
  350. }
  351.