redir.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 static char sccsid[] = "@(#)redir.c     5.1 (Berkeley) 3/7/91";
00039 #endif /* not lint */
00040 
00041 /*
00042  * Code for dealing with input/output redirection.
00043  */
00044 
00045 #include "shell.h"
00046 #include "nodes.h"
00047 #include "jobs.h"
00048 #include "expand.h"
00049 #include "redir.h"
00050 #include "eval.h"
00051 #include "output.h"
00052 #include "memalloc.h"
00053 #include "error.h"
00054 #include <sys/types.h>
00055 #include <signal.h>
00056 #include <fcntl.h>
00057 #include <errno.h>
00058 #include <limits.h>
00059 
00060 
00061 #define EMPTY -2                /* marks an unused slot in redirtab */
00062 #define PIPESIZE 4096           /* amount of buffering in a pipe */
00063 
00064 
00065 MKINIT
00066 struct redirtab {
00067         struct redirtab *next;
00068         short renamed[10];
00069 };
00070 
00071 
00072 MKINIT struct redirtab *redirlist;
00073 
00074 /* We keep track of whether or not fd0 has been redirected.  This is for
00075    background commands, where we want to redirect fd0 to /dev/null only
00076    if it hasn't already been redirected.  */
00077 int fd0_redirected = 0;
00078 
00079 #ifdef __STDC__
00080 STATIC void openredirect(union node *, char *);
00081 STATIC int openhere(union node *);
00082 #else
00083 STATIC void openredirect();
00084 STATIC int openhere();
00085 #endif
00086 
00087 
00088 
00089 /*
00090  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
00091  * old file descriptors are stashed away so that the redirection can be
00092  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
00093  * standard output, and the standard error if it becomes a duplicate of
00094  * stdout, is saved in memory.
00095  */
00096 
00097 void
00098 redirect(redir, flags)
00099         union node *redir;
00100         int flags;
00101         {
00102         union node *n;
00103         struct redirtab *sv;
00104         int i;
00105         int fd;
00106         char memory[10];                /* file descriptors to write to memory */
00107 
00108         for (i = 10 ; --i >= 0 ; )
00109                 memory[i] = 0;
00110         memory[1] = flags & REDIR_BACKQ;
00111         if (flags & REDIR_PUSH) {
00112                 sv = ckmalloc(sizeof (struct redirtab));
00113                 for (i = 0 ; i < 10 ; i++)
00114                         sv->renamed[i] = EMPTY;
00115                 sv->next = redirlist;
00116                 redirlist = sv;
00117         }
00118         for (n = redir ; n ; n = n->nfile.next) {
00119                 fd = n->nfile.fd;
00120                 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
00121                         INTOFF;
00122                         if ((i = copyfd(fd, 10)) != EMPTY) {
00123                                 sv->renamed[fd] = i;
00124                                 close(fd);
00125                         }
00126                         INTON;
00127                         if (i == EMPTY)
00128                                 error("Out of file descriptors");
00129                 } else {
00130                         close(fd);
00131                 }
00132                 if (fd == 0)
00133                         fd0_redirected++;
00134                 openredirect(n, memory);
00135         }
00136         if (memory[1])
00137                 out1 = &memout;
00138         if (memory[2])
00139                 out2 = &memout;
00140 }
00141 
00142 
00143 STATIC void
00144 openredirect(redir, memory)
00145         union node *redir;
00146         char memory[10];
00147         {
00148         int fd = redir->nfile.fd;
00149         char *fname;
00150         int f;
00151 
00152         /* Assume redirection succeeds. */
00153         exitstatus = 0;
00154 
00155         /*
00156          * We suppress interrupts so that we won't leave open file
00157          * descriptors around.  This may not be such a good idea because
00158          * an open of a device or a fifo can block indefinitely.
00159          */
00160         INTOFF;
00161         memory[fd] = 0;
00162         switch (redir->nfile.type) {
00163         case NFROM:
00164                 fname = redir->nfile.expfname;
00165                 if ((f = open(fname, O_RDONLY)) < 0)
00166                         error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
00167 movefd:
00168                 if (f != fd) {
00169                         copyfd(f, fd);
00170                         close(f);
00171                 }
00172                 break;
00173         case NTO:
00174                 fname = redir->nfile.expfname;
00175 #ifdef O_CREAT
00176                 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
00177                         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
00178 #else
00179                 if ((f = creat(fname, 0666)) < 0)
00180                         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
00181 #endif
00182                 goto movefd;
00183         case NAPPEND:
00184                 fname = redir->nfile.expfname;
00185 #ifdef O_APPEND
00186                 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
00187                         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
00188 #else
00189                 if ((f = open(fname, O_WRONLY)) < 0
00190                  && (f = creat(fname, 0666)) < 0)
00191                         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
00192                 lseek(f, 0L, 2);
00193 #endif
00194                 goto movefd;
00195         case NTOFD:
00196         case NFROMFD:
00197                 if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
00198                         if (memory[redir->ndup.dupfd])
00199                                 memory[fd] = 1;
00200                         else
00201                                 copyfd(redir->ndup.dupfd, fd);
00202                 }
00203                 break;
00204         case NHERE:
00205         case NXHERE:
00206                 f = openhere(redir);
00207                 goto movefd;
00208         default:
00209                 abort();
00210         }
00211         INTON;
00212 }
00213 
00214 
00215 /*
00216  * Handle here documents.  Normally we fork off a process to write the
00217  * data to a pipe.  If the document is short, we can stuff the data in
00218  * the pipe without forking.
00219  */
00220 
00221 STATIC int
00222 openhere(redir)
00223         union node *redir;
00224         {
00225         int pip[2];
00226         int len;
00227 
00228         if (pipe(pip) < 0)
00229                 error("Pipe call failed");
00230         if (redir->type == NHERE) {
00231                 len = strlen(redir->nhere.doc->narg.text);
00232                 if (len <= PIPESIZE) {
00233                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
00234                         goto out;
00235                 }
00236         }
00237         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
00238                 close(pip[0]);
00239                 signal(SIGINT, SIG_IGN);
00240                 signal(SIGQUIT, SIG_IGN);
00241                 signal(SIGHUP, SIG_IGN);
00242 #ifdef SIGTSTP
00243                 signal(SIGTSTP, SIG_IGN);
00244 #endif
00245                 signal(SIGPIPE, SIG_DFL);
00246                 if (redir->type == NHERE)
00247                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
00248                 else
00249                         expandhere(redir->nhere.doc, pip[1]);
00250                 _exit(0);
00251         }
00252 out:
00253         close(pip[1]);
00254         return pip[0];
00255 }
00256 
00257 
00258 
00259 /*
00260  * Undo the effects of the last redirection.
00261  */
00262 
00263 void
00264 popredir() {
00265         register struct redirtab *rp = redirlist;
00266         int i;
00267 
00268         for (i = 0 ; i < 10 ; i++) {
00269                 if (rp->renamed[i] != EMPTY) {
00270                         if (i == 0)
00271                                 fd0_redirected--;
00272                         close(i);
00273                         if (rp->renamed[i] >= 0) {
00274                                 copyfd(rp->renamed[i], i);
00275                                 close(rp->renamed[i]);
00276                         }
00277                 }
00278         }
00279         INTOFF;
00280         redirlist = rp->next;
00281         ckfree(rp);
00282         INTON;
00283 }
00284 
00285 
00286 
00287 /*
00288  * Undo all redirections.  Called on error or interrupt.
00289  */
00290 
00291 #ifdef mkinit
00292 
00293 INCLUDE "redir.h"
00294 
00295 RESET {
00296         while (redirlist)
00297                 popredir();
00298 }
00299 
00300 SHELLPROC {
00301         clearredir();
00302 }
00303 
00304 #endif
00305 
00306 
00307 /*
00308  * Discard all saved file descriptors.
00309  */
00310 
00311 void
00312 clearredir() {
00313         register struct redirtab *rp;
00314         int i;
00315 
00316         for (rp = redirlist ; rp ; rp = rp->next) {
00317                 for (i = 0 ; i < 10 ; i++) {
00318                         if (rp->renamed[i] >= 0) {
00319                                 close(rp->renamed[i]);
00320                         }
00321                         rp->renamed[i] = EMPTY;
00322                 }
00323         }
00324 }
00325 
00326 
00327 
00328 /*
00329  * Copy a file descriptor, like the F_DUPFD option of fcntl.  Returns -1
00330  * if the source file descriptor is closed, EMPTY if there are no unused
00331  * file descriptors left.
00332  */
00333 
00334 int
00335 copyfd(from, to) {
00336 #ifdef F_DUPFD
00337         int newfd;
00338 
00339         newfd = fcntl(from, F_DUPFD, to);
00340         if (newfd < 0 && errno == EMFILE)
00341                 return EMPTY;
00342         return newfd;
00343 #else
00344         char toclose[32];
00345         int i;
00346         int newfd;
00347         int e;
00348 
00349         for (i = 0 ; i < to ; i++)
00350                 toclose[i] = 0;
00351         INTOFF;
00352         while ((newfd = dup(from)) >= 0 && newfd < to)
00353                 toclose[newfd] = 1;
00354         e = errno;
00355         for (i = 0 ; i < to ; i++) {
00356                 if (toclose[i])
00357                         close(i);
00358         }
00359         INTON;
00360         if (newfd < 0 && e == EMFILE)
00361                 return EMPTY;
00362         return newfd;
00363 #endif
00364 }
00365 
00366 /* Return true if fd 0 has already been redirected at least once.  */
00367 int
00368 fd0_redirected_p () {
00369         return fd0_redirected != 0;
00370 }

Generated on Fri Apr 14 22:56:41 2006 for minix by  doxygen 1.4.6