1 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 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.27 2002/11/24 22:35:42 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 "main.h" 62 #include "shell.h" 63 #include "nodes.h" 64 #include "jobs.h" 65 #include "options.h" 66 #include "expand.h" 67 #include "redir.h" 68 #include "output.h" 69 #include "memalloc.h" 70 #include "error.h" 71 72 73 #define EMPTY -2 /* marks an unused slot in redirtab */ 74 #ifndef PIPE_BUF 75 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 76 #else 77 # define PIPESIZE PIPE_BUF 78 #endif 79 80 81 MKINIT 82 struct redirtab { 83 struct redirtab *next; 84 short renamed[10]; 85 }; 86 87 88 MKINIT struct redirtab *redirlist; 89 90 /* 91 * We keep track of whether or not fd0 has been redirected. This is for 92 * background commands, where we want to redirect fd0 to /dev/null only 93 * if it hasn't already been redirected. 94 */ 95 int fd0_redirected = 0; 96 97 STATIC void openredirect(union node *, char[10 ]); 98 STATIC int openhere(union node *); 99 100 101 /* 102 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 103 * old file descriptors are stashed away so that the redirection can be 104 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 105 * standard output, and the standard error if it becomes a duplicate of 106 * stdout, is saved in memory. 107 */ 108 109 void 110 redirect(union node *redir, int flags) 111 { 112 union node *n; 113 struct redirtab *sv = NULL; 114 int i; 115 int fd; 116 int try; 117 char memory[10]; /* file descriptors to write to memory */ 118 119 for (i = 10 ; --i >= 0 ; ) 120 memory[i] = 0; 121 memory[1] = flags & REDIR_BACKQ; 122 if (flags & REDIR_PUSH) { 123 /* We don't have to worry about REDIR_VFORK here, as 124 * flags & REDIR_PUSH is never true if REDIR_VFORK is set. 125 */ 126 sv = ckmalloc(sizeof (struct redirtab)); 127 for (i = 0 ; i < 10 ; i++) 128 sv->renamed[i] = EMPTY; 129 sv->next = redirlist; 130 redirlist = sv; 131 } 132 for (n = redir ; n ; n = n->nfile.next) { 133 fd = n->nfile.fd; 134 try = 0; 135 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && 136 n->ndup.dupfd == fd) 137 continue; /* redirect from/to same file descriptor */ 138 139 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { 140 INTOFF; 141 again: 142 if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { 143 switch (errno) { 144 case EBADF: 145 if (!try) { 146 openredirect(n, memory); 147 try++; 148 goto again; 149 } 150 /* FALLTHROUGH*/ 151 default: 152 INTON; 153 error("%d: %s", fd, strerror(errno)); 154 /* NOTREACHED */ 155 } 156 } 157 if (!try) { 158 sv->renamed[fd] = i; 159 close(fd); 160 } 161 INTON; 162 } else { 163 close(fd); 164 } 165 if (fd == 0) 166 fd0_redirected++; 167 if (!try) 168 openredirect(n, memory); 169 } 170 if (memory[1]) 171 out1 = &memout; 172 if (memory[2]) 173 out2 = &memout; 174 } 175 176 177 STATIC void 178 openredirect(union node *redir, 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(union node *redir) 256 { 257 int pip[2]; 258 int len = 0; 259 260 if (pipe(pip) < 0) 261 error("Pipe call failed"); 262 if (redir->type == NHERE) { 263 len = strlen(redir->nhere.doc->narg.text); 264 if (len <= PIPESIZE) { 265 xwrite(pip[1], redir->nhere.doc->narg.text, len); 266 goto out; 267 } 268 } 269 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 270 close(pip[0]); 271 signal(SIGINT, SIG_IGN); 272 signal(SIGQUIT, SIG_IGN); 273 signal(SIGHUP, SIG_IGN); 274 #ifdef SIGTSTP 275 signal(SIGTSTP, SIG_IGN); 276 #endif 277 signal(SIGPIPE, SIG_DFL); 278 if (redir->type == NHERE) 279 xwrite(pip[1], redir->nhere.doc->narg.text, len); 280 else 281 expandhere(redir->nhere.doc, pip[1]); 282 _exit(0); 283 } 284 out: 285 close(pip[1]); 286 return pip[0]; 287 } 288 289 290 291 /* 292 * Undo the effects of the last redirection. 293 */ 294 295 void 296 popredir(void) 297 { 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(0); 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(vforked) 349 int vforked; 350 { 351 struct redirtab *rp; 352 int i; 353 354 for (rp = redirlist ; rp ; rp = rp->next) { 355 for (i = 0 ; i < 10 ; i++) { 356 if (rp->renamed[i] >= 0) { 357 close(rp->renamed[i]); 358 } 359 if (!vforked) 360 rp->renamed[i] = EMPTY; 361 } 362 } 363 } 364 365 366 367 /* 368 * Copy a file descriptor to be >= to. Returns -1 369 * if the source file descriptor is closed, EMPTY if there are no unused 370 * file descriptors left. 371 */ 372 373 int 374 copyfd(int from, int to) 375 { 376 int newfd; 377 378 newfd = fcntl(from, F_DUPFD, to); 379 if (newfd < 0) { 380 if (errno == EMFILE) 381 return EMPTY; 382 else 383 error("%d: %s", from, strerror(errno)); 384 } 385 return newfd; 386 } 387