1 /* $NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos 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. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; 39 #else 40 __RCSID("$NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 #include <sys/types.h> 45 #include <sys/param.h> /* PIPE_BUF */ 46 #include <signal.h> 47 #include <string.h> 48 #include <fcntl.h> 49 #include <errno.h> 50 #include <unistd.h> 51 #include <stdlib.h> 52 53 /* 54 * Code for dealing with input/output redirection. 55 */ 56 57 #include "main.h" 58 #include "shell.h" 59 #include "nodes.h" 60 #include "jobs.h" 61 #include "options.h" 62 #include "expand.h" 63 #include "redir.h" 64 #include "output.h" 65 #include "memalloc.h" 66 #include "error.h" 67 68 69 #define EMPTY -2 /* marks an unused slot in redirtab */ 70 #ifndef PIPE_BUF 71 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 72 #else 73 # define PIPESIZE PIPE_BUF 74 #endif 75 76 77 MKINIT 78 struct redirtab { 79 struct redirtab *next; 80 short renamed[10]; 81 }; 82 83 84 MKINIT struct redirtab *redirlist; 85 86 /* 87 * We keep track of whether or not fd0 has been redirected. This is for 88 * background commands, where we want to redirect fd0 to /dev/null only 89 * if it hasn't already been redirected. 90 */ 91 int fd0_redirected = 0; 92 93 STATIC void openredirect(union node *, char[10], int); 94 STATIC int openhere(union node *); 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(union node *redir, int flags) 107 { 108 union node *n; 109 struct redirtab *sv = NULL; 110 int i; 111 int fd; 112 int try; 113 char memory[10]; /* file descriptors to write to memory */ 114 115 for (i = 10 ; --i >= 0 ; ) 116 memory[i] = 0; 117 memory[1] = flags & REDIR_BACKQ; 118 if (flags & REDIR_PUSH) { 119 /* We don't have to worry about REDIR_VFORK here, as 120 * flags & REDIR_PUSH is never true if REDIR_VFORK is set. 121 */ 122 sv = ckmalloc(sizeof (struct redirtab)); 123 for (i = 0 ; i < 10 ; i++) 124 sv->renamed[i] = EMPTY; 125 sv->next = redirlist; 126 redirlist = sv; 127 } 128 for (n = redir ; n ; n = n->nfile.next) { 129 fd = n->nfile.fd; 130 try = 0; 131 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && 132 n->ndup.dupfd == fd) 133 continue; /* redirect from/to same file descriptor */ 134 135 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { 136 INTOFF; 137 again: 138 if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { 139 switch (errno) { 140 case EBADF: 141 if (!try) { 142 openredirect(n, memory, flags); 143 try++; 144 goto again; 145 } 146 /* FALLTHROUGH*/ 147 default: 148 INTON; 149 error("%d: %s", fd, strerror(errno)); 150 /* NOTREACHED */ 151 } 152 } 153 if (!try) { 154 sv->renamed[fd] = i; 155 close(fd); 156 } 157 INTON; 158 } else { 159 close(fd); 160 } 161 if (fd == 0) 162 fd0_redirected++; 163 if (!try) 164 openredirect(n, memory, flags); 165 } 166 if (memory[1]) 167 out1 = &memout; 168 if (memory[2]) 169 out2 = &memout; 170 } 171 172 173 STATIC void 174 openredirect(union node *redir, char memory[10], int flags) 175 { 176 int fd = redir->nfile.fd; 177 char *fname; 178 int f; 179 int oflags = O_WRONLY|O_CREAT|O_TRUNC, eflags; 180 181 /* 182 * We suppress interrupts so that we won't leave open file 183 * descriptors around. This may not be such a good idea because 184 * an open of a device or a fifo can block indefinitely. 185 */ 186 INTOFF; 187 memory[fd] = 0; 188 switch (redir->nfile.type) { 189 case NFROM: 190 fname = redir->nfile.expfname; 191 if (flags & REDIR_VFORK) 192 eflags = O_NONBLOCK; 193 else 194 eflags = 0; 195 if ((f = open(fname, O_RDONLY|eflags)) < 0) 196 goto eopen; 197 if (eflags) 198 (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags); 199 break; 200 case NFROMTO: 201 fname = redir->nfile.expfname; 202 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) 203 goto ecreate; 204 break; 205 case NTO: 206 if (Cflag) 207 oflags |= O_EXCL; 208 /* FALLTHROUGH */ 209 case NCLOBBER: 210 fname = redir->nfile.expfname; 211 if ((f = open(fname, oflags, 0666)) < 0) 212 goto ecreate; 213 break; 214 case NAPPEND: 215 fname = redir->nfile.expfname; 216 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) 217 goto ecreate; 218 break; 219 case NTOFD: 220 case NFROMFD: 221 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 222 if (memory[redir->ndup.dupfd]) 223 memory[fd] = 1; 224 else 225 copyfd(redir->ndup.dupfd, fd); 226 } 227 INTON; 228 return; 229 case NHERE: 230 case NXHERE: 231 f = openhere(redir); 232 break; 233 default: 234 abort(); 235 } 236 237 if (f != fd) { 238 copyfd(f, fd); 239 close(f); 240 } 241 INTON; 242 return; 243 ecreate: 244 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 245 eopen: 246 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 247 } 248 249 250 /* 251 * Handle here documents. Normally we fork off a process to write the 252 * data to a pipe. If the document is short, we can stuff the data in 253 * the pipe without forking. 254 */ 255 256 STATIC int 257 openhere(union node *redir) 258 { 259 int pip[2]; 260 int len = 0; 261 262 if (pipe(pip) < 0) 263 error("Pipe call failed"); 264 if (redir->type == NHERE) { 265 len = strlen(redir->nhere.doc->narg.text); 266 if (len <= PIPESIZE) { 267 xwrite(pip[1], redir->nhere.doc->narg.text, len); 268 goto out; 269 } 270 } 271 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 272 close(pip[0]); 273 signal(SIGINT, SIG_IGN); 274 signal(SIGQUIT, SIG_IGN); 275 signal(SIGHUP, SIG_IGN); 276 #ifdef SIGTSTP 277 signal(SIGTSTP, SIG_IGN); 278 #endif 279 signal(SIGPIPE, SIG_DFL); 280 if (redir->type == NHERE) 281 xwrite(pip[1], redir->nhere.doc->narg.text, len); 282 else 283 expandhere(redir->nhere.doc, pip[1]); 284 _exit(0); 285 } 286 out: 287 close(pip[1]); 288 return pip[0]; 289 } 290 291 292 293 /* 294 * Undo the effects of the last redirection. 295 */ 296 297 void 298 popredir(void) 299 { 300 struct redirtab *rp = redirlist; 301 int i; 302 303 for (i = 0 ; i < 10 ; i++) { 304 if (rp->renamed[i] != EMPTY) { 305 if (i == 0) 306 fd0_redirected--; 307 close(i); 308 if (rp->renamed[i] >= 0) { 309 copyfd(rp->renamed[i], i); 310 close(rp->renamed[i]); 311 } 312 } 313 } 314 INTOFF; 315 redirlist = rp->next; 316 ckfree(rp); 317 INTON; 318 } 319 320 /* 321 * Undo all redirections. Called on error or interrupt. 322 */ 323 324 #ifdef mkinit 325 326 INCLUDE "redir.h" 327 328 RESET { 329 while (redirlist) 330 popredir(); 331 } 332 333 SHELLPROC { 334 clearredir(0); 335 } 336 337 #endif 338 339 /* Return true if fd 0 has already been redirected at least once. */ 340 int 341 fd0_redirected_p () { 342 return fd0_redirected != 0; 343 } 344 345 /* 346 * Discard all saved file descriptors. 347 */ 348 349 void 350 clearredir(vforked) 351 int vforked; 352 { 353 struct redirtab *rp; 354 int i; 355 356 for (rp = redirlist ; rp ; rp = rp->next) { 357 for (i = 0 ; i < 10 ; i++) { 358 if (rp->renamed[i] >= 0) { 359 close(rp->renamed[i]); 360 } 361 if (!vforked) 362 rp->renamed[i] = EMPTY; 363 } 364 } 365 } 366 367 368 369 /* 370 * Copy a file descriptor to be >= to. Returns -1 371 * if the source file descriptor is closed, EMPTY if there are no unused 372 * file descriptors left. 373 */ 374 375 int 376 copyfd(int from, int to) 377 { 378 int newfd; 379 380 newfd = fcntl(from, F_DUPFD, to); 381 if (newfd < 0) { 382 if (errno == EMFILE) 383 return EMPTY; 384 else 385 error("%d: %s", from, strerror(errno)); 386 } 387 return newfd; 388 } 389