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