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