1 /* $NetBSD: redir.c,v 1.30 2008/01/21 06:43:03 msaitoh 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.30 2008/01/21 06:43:03 msaitoh 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 exerrno = 1; 245 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 246 eopen: 247 exerrno = 1; 248 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 249 } 250 251 252 /* 253 * Handle here documents. Normally we fork off a process to write the 254 * data to a pipe. If the document is short, we can stuff the data in 255 * the pipe without forking. 256 */ 257 258 STATIC int 259 openhere(union node *redir) 260 { 261 int pip[2]; 262 int len = 0; 263 264 if (pipe(pip) < 0) 265 error("Pipe call failed"); 266 if (redir->type == NHERE) { 267 len = strlen(redir->nhere.doc->narg.text); 268 if (len <= PIPESIZE) { 269 xwrite(pip[1], redir->nhere.doc->narg.text, len); 270 goto out; 271 } 272 } 273 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 274 close(pip[0]); 275 signal(SIGINT, SIG_IGN); 276 signal(SIGQUIT, SIG_IGN); 277 signal(SIGHUP, SIG_IGN); 278 #ifdef SIGTSTP 279 signal(SIGTSTP, SIG_IGN); 280 #endif 281 signal(SIGPIPE, SIG_DFL); 282 if (redir->type == NHERE) 283 xwrite(pip[1], redir->nhere.doc->narg.text, len); 284 else 285 expandhere(redir->nhere.doc, pip[1]); 286 _exit(0); 287 } 288 out: 289 close(pip[1]); 290 return pip[0]; 291 } 292 293 294 295 /* 296 * Undo the effects of the last redirection. 297 */ 298 299 void 300 popredir(void) 301 { 302 struct redirtab *rp = redirlist; 303 int i; 304 305 for (i = 0 ; i < 10 ; i++) { 306 if (rp->renamed[i] != EMPTY) { 307 if (i == 0) 308 fd0_redirected--; 309 close(i); 310 if (rp->renamed[i] >= 0) { 311 copyfd(rp->renamed[i], i); 312 close(rp->renamed[i]); 313 } 314 } 315 } 316 INTOFF; 317 redirlist = rp->next; 318 ckfree(rp); 319 INTON; 320 } 321 322 /* 323 * Undo all redirections. Called on error or interrupt. 324 */ 325 326 #ifdef mkinit 327 328 INCLUDE "redir.h" 329 330 RESET { 331 while (redirlist) 332 popredir(); 333 } 334 335 SHELLPROC { 336 clearredir(0); 337 } 338 339 #endif 340 341 /* Return true if fd 0 has already been redirected at least once. */ 342 int 343 fd0_redirected_p () { 344 return fd0_redirected != 0; 345 } 346 347 /* 348 * Discard all saved file descriptors. 349 */ 350 351 void 352 clearredir(vforked) 353 int vforked; 354 { 355 struct redirtab *rp; 356 int i; 357 358 for (rp = redirlist ; rp ; rp = rp->next) { 359 for (i = 0 ; i < 10 ; i++) { 360 if (rp->renamed[i] >= 0) { 361 close(rp->renamed[i]); 362 } 363 if (!vforked) 364 rp->renamed[i] = EMPTY; 365 } 366 } 367 } 368 369 370 371 /* 372 * Copy a file descriptor to be >= to. Returns -1 373 * if the source file descriptor is closed, EMPTY if there are no unused 374 * file descriptors left. 375 */ 376 377 int 378 copyfd(int from, int to) 379 { 380 int newfd; 381 382 newfd = fcntl(from, F_DUPFD, to); 383 if (newfd < 0) { 384 if (errno == EMFILE) 385 return EMPTY; 386 else 387 error("%d: %s", from, strerror(errno)); 388 } 389 return newfd; 390 } 391