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