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