Subversion Repositories HelenOS

Rev

Rev 2714 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*  $NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric Exp $ */
  2.  
  3. /*-
  4.  * Copyright (c) 1991, 1993
  5.  *  The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Kenneth Almquist.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *  This product includes software developed by the University of
  21.  *  California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #include <sys/cdefs.h>
  40. #ifndef lint
  41. #if 0
  42. static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
  43. #else
  44. __RCSID("$NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric Exp $");
  45. #endif
  46. #endif /* not lint */
  47.  
  48. #include <sys/stat.h>
  49. #include <sys/types.h>
  50. #include <sys/param.h>  /* PIPE_BUF */
  51. #include <signal.h>
  52. #include <string.h>
  53. #include <fcntl.h>
  54. #include <errno.h>
  55. #include <unistd.h>
  56. #include <stdlib.h>
  57.  
  58. /*
  59.  * Code for dealing with input/output redirection.
  60.  */
  61.  
  62. #include "shell.h"
  63. #include "nodes.h"
  64. #include "jobs.h"
  65. #include "expand.h"
  66. #include "redir.h"
  67. #include "output.h"
  68. #include "memalloc.h"
  69. #include "error.h"
  70. #include "options.h"
  71.  
  72.  
  73. #define EMPTY -2        /* marks an unused slot in redirtab */
  74. #ifndef PIPE_BUF
  75. # define PIPESIZE 4096      /* amount of buffering in a pipe */
  76. #else
  77. # define PIPESIZE PIPE_BUF
  78. #endif
  79.  
  80.  
  81. MKINIT
  82. struct redirtab {
  83.     struct redirtab *next;
  84.     short renamed[10];
  85. };
  86.  
  87.  
  88. MKINIT struct redirtab *redirlist;
  89.  
  90. /*
  91.  * We keep track of whether or not fd0 has been redirected.  This is for
  92.  * background commands, where we want to redirect fd0 to /dev/null only
  93.  * if it hasn't already been redirected.
  94. */
  95. int fd0_redirected = 0;
  96.  
  97. /*
  98.  * We also keep track of where fd2 goes.
  99.  */
  100. int fd2 = 2;
  101.  
  102. STATIC int openredirect (union node *);
  103. STATIC void dupredirect (union node *, int, char[10 ]);
  104. STATIC int openhere (union node *);
  105. STATIC int noclobberopen (const char *);
  106.  
  107.  
  108. /*
  109.  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
  110.  * old file descriptors are stashed away so that the redirection can be
  111.  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
  112.  * standard output, and the standard error if it becomes a duplicate of
  113.  * stdout, is saved in memory.
  114.  */
  115.  
  116. void
  117. redirect(redir, flags)
  118.     union node *redir;
  119.     int flags;
  120.     {
  121.     union node *n;
  122.     struct redirtab *sv = NULL;
  123.     int i;
  124.     int fd;
  125.     int newfd;
  126.     int try;
  127.     char memory[10];    /* file descriptors to write to memory */
  128.  
  129.     for (i = 10 ; --i >= 0 ; )
  130.         memory[i] = 0;
  131.     memory[1] = flags & REDIR_BACKQ;
  132.     if (flags & REDIR_PUSH) {
  133.         sv = ckmalloc(sizeof (struct redirtab));
  134.         for (i = 0 ; i < 10 ; i++)
  135.             sv->renamed[i] = EMPTY;
  136.         sv->next = redirlist;
  137.         redirlist = sv;
  138.     }
  139.     for (n = redir ; n ; n = n->nfile.next) {
  140.         fd = n->nfile.fd;
  141.         try = 0;
  142.         if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
  143.             n->ndup.dupfd == fd)
  144.             continue; /* redirect from/to same file descriptor */
  145.  
  146.         INTOFF;
  147.         newfd = openredirect(n);
  148.         if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
  149.             (fd == fd2)) {
  150.             if (newfd == fd) {
  151.                 try++;
  152.             } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
  153.                 switch (errno) {
  154.                 case EBADF:
  155.                     if (!try) {
  156.                         dupredirect(n, newfd, memory);
  157.                         try++;
  158.                         break;
  159.                     }
  160.                     /* FALLTHROUGH*/
  161.                 default:
  162.                     if (newfd >= 0) {
  163.                         close(newfd);
  164.                     }
  165.                     INTON;
  166.                     error("%d: %s", fd, strerror(errno));
  167.                     /* NOTREACHED */
  168.                 }
  169.             }
  170.             if (!try) {
  171.                 close(fd);
  172.                 if (flags & REDIR_PUSH) {
  173.                     sv->renamed[fd] = i;
  174.                 }
  175.                 if (fd == fd2) {
  176.                     fd2 = i;
  177.                 }
  178.             }
  179.         } else if (fd != newfd) {
  180.             close(fd);
  181.         }
  182.                 if (fd == 0)
  183.                         fd0_redirected++;
  184.         if (!try)
  185.             dupredirect(n, newfd, memory);
  186.         INTON;
  187.     }
  188.     if (memory[1])
  189.         out1 = &memout;
  190.     if (memory[2])
  191.         out2 = &memout;
  192. }
  193.  
  194.  
  195. STATIC int
  196. openredirect(redir)
  197.     union node *redir;
  198.     {
  199.     char *fname;
  200.     int f;
  201.  
  202.     switch (redir->nfile.type) {
  203.     case NFROM:
  204.         fname = redir->nfile.expfname;
  205.         if ((f = open(fname, O_RDONLY)) < 0)
  206.             goto eopen;
  207.         break;
  208.     case NFROMTO:
  209.         fname = redir->nfile.expfname;
  210.         if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
  211.             goto ecreate;
  212.         break;
  213.     case NTO:
  214.         /* Take care of noclobber mode. */
  215.         if (Cflag) {
  216.             fname = redir->nfile.expfname;
  217.             if ((f = noclobberopen(fname)) < 0)
  218.                 goto ecreate;
  219.             break;
  220.         }
  221.     case NTOOV:
  222.         fname = redir->nfile.expfname;
  223. #ifdef O_CREAT
  224.         if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
  225.             goto ecreate;
  226. #else
  227.         if ((f = creat(fname, 0666)) < 0)
  228.             goto ecreate;
  229. #endif
  230.         break;
  231.     case NAPPEND:
  232.         fname = redir->nfile.expfname;
  233. #ifdef O_APPEND
  234.         if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
  235.             goto ecreate;
  236. #else
  237.         if ((f = open(fname, O_WRONLY)) < 0
  238.          && (f = creat(fname, 0666)) < 0)
  239.             goto ecreate;
  240.         lseek(f, (off_t)0, 2);
  241. #endif
  242.         break;
  243.     case NTOFD:
  244.     case NFROMFD:
  245.         f = -1;
  246.         break;
  247.     case NHERE:
  248.     case NXHERE:
  249.         f = openhere(redir);
  250.         break;
  251.     default:
  252.         abort();
  253.     }
  254.  
  255.     return f;
  256. ecreate:
  257.     error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  258. eopen:
  259.     error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
  260. }
  261.  
  262.  
  263. STATIC void
  264. dupredirect(redir, f, memory)
  265.     union node *redir;
  266.     int f;
  267.     char memory[10];
  268.     {
  269.     int fd = redir->nfile.fd;
  270.  
  271.     memory[fd] = 0;
  272.     if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
  273.         if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
  274.             if (memory[redir->ndup.dupfd])
  275.                 memory[fd] = 1;
  276.             else
  277.                 copyfd(redir->ndup.dupfd, fd);
  278.         }
  279.         return;
  280.     }
  281.  
  282.     if (f != fd) {
  283.         copyfd(f, fd);
  284.         close(f);
  285.     }
  286.     return;
  287. }
  288.  
  289.  
  290. /*
  291.  * Handle here documents.  Normally we fork off a process to write the
  292.  * data to a pipe.  If the document is short, we can stuff the data in
  293.  * the pipe without forking.
  294.  */
  295.  
  296. STATIC int
  297. openhere(redir)
  298.     union node *redir;
  299.     {
  300.     int pip[2];
  301.     int len = 0;
  302.  
  303.     if (pipe(pip) < 0)
  304.         error("Pipe call failed");
  305.     if (redir->type == NHERE) {
  306.         len = strlen(redir->nhere.doc->narg.text);
  307.         if (len <= PIPESIZE) {
  308.             xwrite(pip[1], redir->nhere.doc->narg.text, len);
  309.             goto out;
  310.         }
  311.     }
  312.     if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
  313.         close(pip[0]);
  314.         signal(SIGINT, SIG_IGN);
  315.         signal(SIGQUIT, SIG_IGN);
  316.         signal(SIGHUP, SIG_IGN);
  317. #ifdef SIGTSTP
  318.         signal(SIGTSTP, SIG_IGN);
  319. #endif
  320.         signal(SIGPIPE, SIG_DFL);
  321.         if (redir->type == NHERE)
  322.             xwrite(pip[1], redir->nhere.doc->narg.text, len);
  323.         else
  324.             expandhere(redir->nhere.doc, pip[1]);
  325.         _exit(0);
  326.     }
  327. out:
  328.     close(pip[1]);
  329.     return pip[0];
  330. }
  331.  
  332.  
  333.  
  334. /*
  335.  * Undo the effects of the last redirection.
  336.  */
  337.  
  338. void
  339. popredir() {
  340.     struct redirtab *rp = redirlist;
  341.     int i;
  342.  
  343.     INTOFF;
  344.     for (i = 0 ; i < 10 ; i++) {
  345.         if (rp->renamed[i] != EMPTY) {
  346.                         if (i == 0)
  347.                                 fd0_redirected--;
  348.             close(i);
  349.             if (rp->renamed[i] >= 0) {
  350.                 copyfd(rp->renamed[i], i);
  351.                 close(rp->renamed[i]);
  352.             }
  353.             if (rp->renamed[i] == fd2) {
  354.                 fd2 = i;
  355.             }
  356.         }
  357.     }
  358.     redirlist = rp->next;
  359.     ckfree(rp);
  360.     INTON;
  361. }
  362.  
  363. /*
  364.  * Undo all redirections.  Called on error or interrupt.
  365.  */
  366.  
  367. #ifdef mkinit
  368.  
  369. INCLUDE "redir.h"
  370.  
  371. RESET {
  372.     while (redirlist)
  373.         popredir();
  374. }
  375.  
  376. SHELLPROC {
  377.     clearredir();
  378. }
  379.  
  380. #endif
  381.  
  382. /* Return true if fd 0 has already been redirected at least once.  */
  383. int
  384. fd0_redirected_p () {
  385.         return fd0_redirected != 0;
  386. }
  387.  
  388. /*
  389.  * Discard all saved file descriptors.
  390.  */
  391.  
  392. void
  393. clearredir() {
  394.     struct redirtab *rp;
  395.     int i;
  396.  
  397.     for (rp = redirlist ; rp ; rp = rp->next) {
  398.         for (i = 0 ; i < 10 ; i++) {
  399.             if (rp->renamed[i] >= 0) {
  400.                 close(rp->renamed[i]);
  401.                 if (rp->renamed[i] == fd2) {
  402.                     fd2 = -1;
  403.                 }
  404.             }
  405.             rp->renamed[i] = EMPTY;
  406.         }
  407.     }
  408. }
  409.  
  410.  
  411.  
  412. /*
  413.  * Copy a file descriptor to be >= to.  Returns -1
  414.  * if the source file descriptor is closed, EMPTY if there are no unused
  415.  * file descriptors left.
  416.  */
  417.  
  418. int
  419. copyfd(from, to)
  420.     int from;
  421.     int to;
  422. {
  423.     int newfd;
  424.  
  425.     newfd = fcntl(from, F_DUPFD, to);
  426.     if (newfd < 0) {
  427.         if (errno == EMFILE)
  428.             return EMPTY;
  429.         else
  430.             error("%d: %s", from, strerror(errno));
  431.     }
  432.     return newfd;
  433. }
  434.  
  435. /*
  436.  * Open a file in noclobber mode.
  437.  * The code was copied from bash.
  438.  */
  439. int
  440. noclobberopen(fname)
  441.     const char *fname;
  442. {
  443.     int r, fd;
  444.     struct stat finfo, finfo2;
  445.  
  446.     /*
  447.      * If the file exists and is a regular file, return an error
  448.      * immediately.
  449.      */
  450.     r = stat(fname, &finfo);
  451.     if (r == 0 && S_ISREG(finfo.st_mode)) {
  452.         errno = EEXIST;
  453.         return -1;
  454.     }
  455.  
  456.     /*
  457.      * If the file was not present (r != 0), make sure we open it
  458.      * exclusively so that if it is created before we open it, our open
  459.      * will fail.  Make sure that we do not truncate an existing file.
  460.      * Note that we don't turn on O_EXCL unless the stat failed -- if the
  461.      * file was not a regular file, we leave O_EXCL off.
  462.      */
  463.     if (r != 0)
  464.         return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
  465.     fd = open(fname, O_WRONLY|O_CREAT, 0666);
  466.  
  467.     /* If the open failed, return the file descriptor right away. */
  468.     if (fd < 0)
  469.         return fd;
  470.  
  471.     /*
  472.      * OK, the open succeeded, but the file may have been changed from a
  473.      * non-regular file to a regular file between the stat and the open.
  474.      * We are assuming that the O_EXCL open handles the case where FILENAME
  475.      * did not exist and is symlinked to an existing file between the stat
  476.      * and open.
  477.      */
  478.  
  479.     /*
  480.      * If we can open it and fstat the file descriptor, and neither check
  481.      * revealed that it was a regular file, and the file has not been
  482.      * replaced, return the file descriptor.
  483.      */
  484.      if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
  485.          finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
  486.         return fd;
  487.  
  488.     /* The file has been replaced.  badness. */
  489.     close(fd);
  490.     errno = EEXIST;
  491.     return -1;
  492. }
  493.