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[] = "$Id: 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 4096 /* 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