home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / ASH / ASH-LINU.2 / ASH-LINU / ash-linux-0.2 / redir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-04  |  8.1 KB  |  366 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[] = "from: @(#)redir.c    5.1 (Berkeley) 3/7/91";*/
  39. static char rcsid[] = "redir.c,v 1.5 1993/08/01 18:58:01 mycroft Exp";
  40. #endif /* not lint */
  41.  
  42. /*
  43.  * Code for dealing with input/output redirection.
  44.  */
  45.  
  46. #include "shell.h"
  47. #include "nodes.h"
  48. #include "jobs.h"
  49. #include "expand.h"
  50. #include "redir.h"
  51. #include "output.h"
  52. #include "memalloc.h"
  53. #include "error.h"
  54. #include <signal.h>
  55. #include <fcntl.h>
  56. #include <errno.h>
  57.  
  58.  
  59. #define EMPTY -2        /* marks an unused slot in redirtab */
  60. #define PIPESIZE 4095        /* amount of buffering in a pipe */
  61.  
  62.  
  63. MKINIT
  64. struct redirtab {
  65.     struct redirtab *next;
  66.     short renamed[10];
  67. };
  68.  
  69.  
  70. MKINIT struct redirtab *redirlist;
  71.  
  72. /* We keep track of whether or not fd0 has been redirected.  This is for
  73.    background commands, where we want to redirect fd0 to /dev/null only
  74.    if it hasn't already been redirected.  */
  75. int fd0_redirected = 0;
  76.  
  77. #ifdef __STDC__
  78. STATIC void openredirect(union node *, char *);
  79. STATIC int openhere(union node *);
  80. #else
  81. STATIC void openredirect();
  82. STATIC int openhere();
  83. #endif
  84.  
  85.  
  86.  
  87. /*
  88.  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
  89.  * old file descriptors are stashed away so that the redirection can be
  90.  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
  91.  * standard output, and the standard error if it becomes a duplicate of
  92.  * stdout, is saved in memory.
  93.  */
  94.  
  95. void
  96. redirect(redir, flags)
  97.     union node *redir;
  98.     int flags;
  99.     {
  100.     union node *n;
  101.     struct redirtab *sv;
  102.     int i;
  103.     int fd;
  104.     char memory[10];        /* file descriptors to write to memory */
  105.  
  106.     for (i = 10 ; --i >= 0 ; )
  107.         memory[i] = 0;
  108.     memory[1] = flags & REDIR_BACKQ;
  109.     if (flags & REDIR_PUSH) {
  110.         sv = ckmalloc(sizeof (struct redirtab));
  111.         for (i = 0 ; i < 10 ; i++)
  112.             sv->renamed[i] = EMPTY;
  113.         sv->next = redirlist;
  114.         redirlist = sv;
  115.     }
  116.     for (n = redir ; n ; n = n->nfile.next) {
  117.         fd = n->nfile.fd;
  118.         if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
  119.             INTOFF;
  120.             if ((i = copyfd(fd, 10)) != EMPTY) {
  121.                 sv->renamed[fd] = i;
  122.                 close(fd);
  123.             }
  124.             INTON;
  125.             if (i == EMPTY)
  126.                 error("Out of file descriptors");
  127.         } else {
  128.             close(fd);
  129.         }
  130.         if (fd == 0)
  131.             fd0_redirected++;
  132.         openredirect(n, memory);
  133.     }
  134.     if (memory[1])
  135.         out1 = &memout;
  136.     if (memory[2])
  137.         out2 = &memout;
  138. }
  139.  
  140.  
  141. STATIC void
  142. openredirect(redir, memory)
  143.     union node *redir;
  144.     char memory[10];
  145.     {
  146.     int fd = redir->nfile.fd;
  147.     char *fname;
  148.     int f;
  149.  
  150.     /*
  151.      * We suppress interrupts so that we won't leave open file
  152.      * descriptors around.  This may not be such a good idea because
  153.      * an open of a device or a fifo can block indefinitely.
  154.      */
  155.     INTOFF;
  156.     memory[fd] = 0;
  157.     switch (redir->nfile.type) {
  158.     case NFROM:
  159.         fname = redir->nfile.expfname;
  160.         if ((f = open(fname, O_RDONLY)) < 0)
  161.             error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
  162. movefd:
  163.         if (f != fd) {
  164.             copyfd(f, fd);
  165.             close(f);
  166.         }
  167.         break;
  168.     case NTO:
  169.         fname = redir->nfile.expfname;
  170. #ifdef O_CREAT
  171.         if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
  172.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  173. #else
  174.         if ((f = creat(fname, 0666)) < 0)
  175.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  176. #endif
  177.         goto movefd;
  178.     case NAPPEND:
  179.         fname = redir->nfile.expfname;
  180. #ifdef O_APPEND
  181.         if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
  182.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  183. #else
  184.         if ((f = open(fname, O_WRONLY)) < 0
  185.          && (f = creat(fname, 0666)) < 0)
  186.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  187.         lseek(f, 0L, 2);
  188. #endif
  189.         goto movefd;
  190.     case NTOFD:
  191.     case NFROMFD:
  192.         if (redir->ndup.dupfd >= 0) {    /* if not ">&-" */
  193.             if (memory[redir->ndup.dupfd])
  194.                 memory[fd] = 1;
  195.             else
  196.                 copyfd(redir->ndup.dupfd, fd);
  197.         }
  198.         break;
  199.     case NHERE:
  200.     case NXHERE:
  201.         f = openhere(redir);
  202.         goto movefd;
  203.     default:
  204.         abort();
  205.     }
  206.     INTON;
  207. }
  208.  
  209.  
  210. /*
  211.  * Handle here documents.  Normally we fork off a process to write the
  212.  * data to a pipe.  If the document is short, we can stuff the data in
  213.  * the pipe without forking.
  214.  */
  215.  
  216. STATIC int
  217. openhere(redir)
  218.     union node *redir;
  219.     {
  220.     int pip[2];
  221.     int len;
  222.  
  223.     if (pipe(pip) < 0)
  224.         error("Pipe call failed");
  225.     if (redir->type == NHERE) {
  226.         len = strlen(redir->nhere.doc->narg.text);
  227.         if (len <= PIPESIZE) {
  228.             xwrite(pip[1], redir->nhere.doc->narg.text, len);
  229.             goto out;
  230.         }
  231.     }
  232.     if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
  233.         close(pip[0]);
  234.         signal(SIGINT, SIG_IGN);
  235.         signal(SIGQUIT, SIG_IGN);
  236.         signal(SIGHUP, SIG_IGN);
  237. #ifdef SIGTSTP
  238.         signal(SIGTSTP, SIG_IGN);
  239. #endif
  240.         signal(SIGPIPE, SIG_DFL);
  241.         if (redir->type == NHERE)
  242.             xwrite(pip[1], redir->nhere.doc->narg.text, len);
  243.         else
  244.             expandhere(redir->nhere.doc, pip[1]);
  245.         _exit(0);
  246.     }
  247. out:
  248.     close(pip[1]);
  249.     return pip[0];
  250. }
  251.  
  252.  
  253.  
  254. /*
  255.  * Undo the effects of the last redirection.
  256.  */
  257.  
  258. void
  259. popredir() {
  260.     register struct redirtab *rp = redirlist;
  261.     int i;
  262.  
  263.     for (i = 0 ; i < 10 ; i++) {
  264.         if (rp->renamed[i] != EMPTY) {
  265.             if (i == 0)
  266.                 fd0_redirected--;
  267.             close(i);
  268.             if (rp->renamed[i] >= 0) {
  269.                 copyfd(rp->renamed[i], i);
  270.                 close(rp->renamed[i]);
  271.             }
  272.         }
  273.     }
  274.     INTOFF;
  275.     redirlist = rp->next;
  276.     ckfree(rp);
  277.     INTON;
  278. }
  279.  
  280.  
  281.  
  282. /*
  283.  * Undo all redirections.  Called on error or interrupt.
  284.  */
  285.  
  286. #ifdef mkinit
  287.  
  288. INCLUDE "redir.h"
  289.  
  290. RESET {
  291.     while (redirlist)
  292.         popredir();
  293. }
  294.  
  295. SHELLPROC {
  296.     clearredir();
  297. }
  298.  
  299. #endif
  300.  
  301.  
  302. /*
  303.  * Discard all saved file descriptors.
  304.  */
  305.  
  306. void
  307. clearredir() {
  308.     register struct redirtab *rp;
  309.     int i;
  310.  
  311.     for (rp = redirlist ; rp ; rp = rp->next) {
  312.         for (i = 0 ; i < 10 ; i++) {
  313.             if (rp->renamed[i] >= 0) {
  314.                 close(rp->renamed[i]);
  315.             }
  316.             rp->renamed[i] = EMPTY;
  317.         }
  318.     }
  319. }
  320.  
  321.  
  322.  
  323. /*
  324.  * Copy a file descriptor, like the F_DUPFD option of fcntl.  Returns -1
  325.  * if the source file descriptor is closed, EMPTY if there are no unused
  326.  * file descriptors left.
  327.  */
  328.  
  329. int
  330. copyfd(from, to) {
  331. #ifdef F_DUPFD
  332.     int newfd;
  333.  
  334.     newfd = fcntl(from, F_DUPFD, to);
  335.     if (newfd < 0 && errno == EMFILE)
  336.         return EMPTY;
  337.     return newfd;
  338. #else
  339.     char toclose[32];
  340.     int i;
  341.     int newfd;
  342.     int e;
  343.  
  344.     for (i = 0 ; i < to ; i++)
  345.         toclose[i] = 0;
  346.     INTOFF;
  347.     while ((newfd = dup(from)) >= 0 && newfd < to)
  348.         toclose[newfd] = 1;
  349.     e = errno;
  350.     for (i = 0 ; i < to ; i++) {
  351.         if (toclose[i])
  352.             close(i);
  353.     }
  354.     INTON;
  355.     if (newfd < 0 && e == EMFILE)
  356.         return EMPTY;
  357.     return newfd;
  358. #endif
  359. }
  360.  
  361. /* Return true if fd 0 has already been redirected at least once.  */
  362. int
  363. fd0_redirected_p () {
  364.     return fd0_redirected != 0;
  365. }
  366.