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