1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 05/04/95"; 13 #endif /* not lint */ 14 15 #include <sys/types.h> 16 #include <signal.h> 17 #include <string.h> 18 #include <fcntl.h> 19 #include <errno.h> 20 #include <unistd.h> 21 #include <stdlib.h> 22 23 /* 24 * Code for dealing with input/output redirection. 25 */ 26 27 #include "shell.h" 28 #include "nodes.h" 29 #include "jobs.h" 30 #include "expand.h" 31 #include "redir.h" 32 #include "output.h" 33 #include "memalloc.h" 34 #include "error.h" 35 36 37 #define EMPTY -2 /* marks an unused slot in redirtab */ 38 #define PIPESIZE 4096 /* amount of buffering in a pipe */ 39 40 41 MKINIT 42 struct redirtab { 43 struct redirtab *next; 44 short renamed[10]; 45 }; 46 47 48 MKINIT struct redirtab *redirlist; 49 50 /* 51 * We keep track of whether or not fd0 has been redirected. This is for 52 * background commands, where we want to redirect fd0 to /dev/null only 53 * if it hasn't already been redirected. 54 */ 55 int fd0_redirected = 0; 56 57 STATIC void openredirect __P((union node *, char[10 ])); 58 STATIC int openhere __P((union node *)); 59 60 61 /* 62 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 63 * old file descriptors are stashed away so that the redirection can be 64 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 65 * standard output, and the standard error if it becomes a duplicate of 66 * stdout, is saved in memory. 67 */ 68 69 void 70 redirect(redir, flags) 71 union node *redir; 72 int flags; 73 { 74 union node *n; 75 struct redirtab *sv; 76 int i; 77 int fd; 78 char memory[10]; /* file descriptors to write to memory */ 79 80 for (i = 10 ; --i >= 0 ; ) 81 memory[i] = 0; 82 memory[1] = flags & REDIR_BACKQ; 83 if (flags & REDIR_PUSH) { 84 sv = ckmalloc(sizeof (struct redirtab)); 85 for (i = 0 ; i < 10 ; i++) 86 sv->renamed[i] = EMPTY; 87 sv->next = redirlist; 88 redirlist = sv; 89 } 90 for (n = redir ; n ; n = n->nfile.next) { 91 fd = n->nfile.fd; 92 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { 93 INTOFF; 94 if ((i = copyfd(fd, 10)) != EMPTY) { 95 sv->renamed[fd] = i; 96 close(fd); 97 } 98 INTON; 99 if (i == EMPTY) 100 error("Out of file descriptors"); 101 } else { 102 close(fd); 103 } 104 if (fd == 0) 105 fd0_redirected++; 106 openredirect(n, memory); 107 } 108 if (memory[1]) 109 out1 = &memout; 110 if (memory[2]) 111 out2 = &memout; 112 } 113 114 115 STATIC void 116 openredirect(redir, memory) 117 union node *redir; 118 char memory[10]; 119 { 120 int fd = redir->nfile.fd; 121 char *fname; 122 int f; 123 124 /* 125 * We suppress interrupts so that we won't leave open file 126 * descriptors around. This may not be such a good idea because 127 * an open of a device or a fifo can block indefinitely. 128 */ 129 INTOFF; 130 memory[fd] = 0; 131 switch (redir->nfile.type) { 132 case NFROM: 133 fname = redir->nfile.expfname; 134 if ((f = open(fname, O_RDONLY)) < 0) 135 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 136 movefd: 137 if (f != fd) { 138 copyfd(f, fd); 139 close(f); 140 } 141 break; 142 case NTO: 143 fname = redir->nfile.expfname; 144 #ifdef O_CREAT 145 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 146 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 147 #else 148 if ((f = creat(fname, 0666)) < 0) 149 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 150 #endif 151 goto movefd; 152 case NAPPEND: 153 fname = redir->nfile.expfname; 154 #ifdef O_APPEND 155 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) 156 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 157 #else 158 if ((f = open(fname, O_WRONLY)) < 0 159 && (f = creat(fname, 0666)) < 0) 160 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 161 lseek(f, (off_t)0, 2); 162 #endif 163 goto movefd; 164 case NTOFD: 165 case NFROMFD: 166 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 167 if (memory[redir->ndup.dupfd]) 168 memory[fd] = 1; 169 else 170 copyfd(redir->ndup.dupfd, fd); 171 } 172 break; 173 case NHERE: 174 case NXHERE: 175 f = openhere(redir); 176 goto movefd; 177 default: 178 abort(); 179 } 180 INTON; 181 } 182 183 184 /* 185 * Handle here documents. Normally we fork off a process to write the 186 * data to a pipe. If the document is short, we can stuff the data in 187 * the pipe without forking. 188 */ 189 190 STATIC int 191 openhere(redir) 192 union node *redir; 193 { 194 int pip[2]; 195 int len = 0; 196 197 if (pipe(pip) < 0) 198 error("Pipe call failed"); 199 if (redir->type == NHERE) { 200 len = strlen(redir->nhere.doc->narg.text); 201 if (len <= PIPESIZE) { 202 xwrite(pip[1], redir->nhere.doc->narg.text, len); 203 goto out; 204 } 205 } 206 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 207 close(pip[0]); 208 signal(SIGINT, SIG_IGN); 209 signal(SIGQUIT, SIG_IGN); 210 signal(SIGHUP, SIG_IGN); 211 #ifdef SIGTSTP 212 signal(SIGTSTP, SIG_IGN); 213 #endif 214 signal(SIGPIPE, SIG_DFL); 215 if (redir->type == NHERE) 216 xwrite(pip[1], redir->nhere.doc->narg.text, len); 217 else 218 expandhere(redir->nhere.doc, pip[1]); 219 _exit(0); 220 } 221 out: 222 close(pip[1]); 223 return pip[0]; 224 } 225 226 227 228 /* 229 * Undo the effects of the last redirection. 230 */ 231 232 void 233 popredir() { 234 register struct redirtab *rp = redirlist; 235 int i; 236 237 for (i = 0 ; i < 10 ; i++) { 238 if (rp->renamed[i] != EMPTY) { 239 if (i == 0) 240 fd0_redirected--; 241 close(i); 242 if (rp->renamed[i] >= 0) { 243 copyfd(rp->renamed[i], i); 244 close(rp->renamed[i]); 245 } 246 } 247 } 248 INTOFF; 249 redirlist = rp->next; 250 ckfree(rp); 251 INTON; 252 } 253 254 /* 255 * Undo all redirections. Called on error or interrupt. 256 */ 257 258 #ifdef mkinit 259 260 INCLUDE "redir.h" 261 262 RESET { 263 while (redirlist) 264 popredir(); 265 } 266 267 SHELLPROC { 268 clearredir(); 269 } 270 271 #endif 272 273 /* Return true if fd 0 has already been redirected at least once. */ 274 int 275 fd0_redirected_p () { 276 return fd0_redirected != 0; 277 } 278 279 /* 280 * Discard all saved file descriptors. 281 */ 282 283 void 284 clearredir() { 285 register struct redirtab *rp; 286 int i; 287 288 for (rp = redirlist ; rp ; rp = rp->next) { 289 for (i = 0 ; i < 10 ; i++) { 290 if (rp->renamed[i] >= 0) { 291 close(rp->renamed[i]); 292 } 293 rp->renamed[i] = EMPTY; 294 } 295 } 296 } 297 298 299 300 /* 301 * Copy a file descriptor to be >= to. Returns -1 302 * if the source file descriptor is closed, EMPTY if there are no unused 303 * file descriptors left. 304 */ 305 306 int 307 copyfd(from, to) 308 int from; 309 int to; 310 { 311 int newfd; 312 313 newfd = fcntl(from, F_DUPFD, to); 314 if (newfd < 0 && errno == EMFILE) 315 return EMPTY; 316 return newfd; 317 } 318