1/* $NetBSD: redir.c,v 1.32 2011/08/31 16:24:55 plunky 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 38static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; 39#else 40__RCSID("$NetBSD: redir.c,v 1.32 2011/08/31 16:24:55 plunky 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 77MKINIT 78struct redirtab { 79 struct redirtab *next; 80 short renamed[10]; 81}; 82 83 84MKINIT 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*/ 91int fd0_redirected = 0; 92 93STATIC void openredirect(union node *, char[10], int); 94STATIC 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 105void 106redirect(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; 137again: 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 173STATIC void 174openredirect(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, 1); 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, 1); 239 close(f); 240 } 241 INTON; 242 return; 243ecreate: 244 exerrno = 1; 245 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 246eopen: 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 258STATIC int 259openhere(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(NULL, 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 } 288out: 289 close(pip[1]); 290 return pip[0]; 291} 292 293 294 295/* 296 * Undo the effects of the last redirection. 297 */ 298 299void 300popredir(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, 1); 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 328INCLUDE "redir.h" 329 330RESET { 331 while (redirlist) 332 popredir(); 333} 334 335SHELLPROC { 336 clearredir(0); 337} 338 339#endif 340 341/* Return true if fd 0 has already been redirected at least once. */ 342int 343fd0_redirected_p () { 344 return fd0_redirected != 0; 345} 346 347/* 348 * Discard all saved file descriptors. 349 */ 350 351void 352clearredir(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 377int 378copyfd(int from, int to, int equal) 379{ 380 int newfd; 381 382 if (equal) 383 newfd = dup2(from, to); 384 else 385 newfd = fcntl(from, F_DUPFD, to); 386 if (newfd < 0) { 387 if (errno == EMFILE) 388 return EMPTY; 389 else 390 error("%d: %s", from, strerror(errno)); 391 } 392 return newfd; 393} 394