redir.c revision 1.14 1 /* $NetBSD: redir.c,v 1.14 1997/01/11 02:04:46 tls 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. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 #if 0
41 static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
42 #else
43 static char rcsid[] = "$NetBSD: redir.c,v 1.14 1997/01/11 02:04:46 tls Exp $";
44 #endif
45 #endif /* not lint */
46
47 #include <sys/types.h>
48 #include <signal.h>
49 #include <string.h>
50 #include <fcntl.h>
51 #include <errno.h>
52 #include <unistd.h>
53 #include <stdlib.h>
54
55 /*
56 * Code for dealing with input/output redirection.
57 */
58
59 #include "shell.h"
60 #include "nodes.h"
61 #include "jobs.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 #define PIPESIZE 4096 /* amount of buffering in a pipe */
71
72
73 MKINIT
74 struct redirtab {
75 struct redirtab *next;
76 short renamed[10];
77 };
78
79
80 MKINIT struct redirtab *redirlist;
81
82 /*
83 * We keep track of whether or not fd0 has been redirected. This is for
84 * background commands, where we want to redirect fd0 to /dev/null only
85 * if it hasn't already been redirected.
86 */
87 int fd0_redirected = 0;
88
89 STATIC void openredirect __P((union node *, char[10 ]));
90 STATIC int openhere __P((union node *));
91
92
93 /*
94 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
95 * old file descriptors are stashed away so that the redirection can be
96 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
97 * standard output, and the standard error if it becomes a duplicate of
98 * stdout, is saved in memory.
99 */
100
101 void
102 redirect(redir, flags)
103 union node *redir;
104 int flags;
105 {
106 union node *n;
107 struct redirtab *sv;
108 int i;
109 int fd;
110 char memory[10]; /* file descriptors to write to memory */
111
112 for (i = 10 ; --i >= 0 ; )
113 memory[i] = 0;
114 memory[1] = flags & REDIR_BACKQ;
115 if (flags & REDIR_PUSH) {
116 sv = ckmalloc(sizeof (struct redirtab));
117 for (i = 0 ; i < 10 ; i++)
118 sv->renamed[i] = EMPTY;
119 sv->next = redirlist;
120 redirlist = sv;
121 }
122 for (n = redir ; n ; n = n->nfile.next) {
123 fd = n->nfile.fd;
124 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
125 n->ndup.dupfd == fd)
126 continue; /* redirect from/to same file descriptor */
127 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
128 INTOFF;
129 if ((i = copyfd(fd, 10)) != EMPTY) {
130 sv->renamed[fd] = i;
131 close(fd);
132 }
133 INTON;
134 if (i == EMPTY)
135 error("Out of file descriptors");
136 } else {
137 close(fd);
138 }
139 if (fd == 0)
140 fd0_redirected++;
141 openredirect(n, memory);
142 }
143 if (memory[1])
144 out1 = &memout;
145 if (memory[2])
146 out2 = &memout;
147 }
148
149
150 STATIC void
151 openredirect(redir, memory)
152 union node *redir;
153 char memory[10];
154 {
155 int fd = redir->nfile.fd;
156 char *fname;
157 int f;
158
159 /*
160 * We suppress interrupts so that we won't leave open file
161 * descriptors around. This may not be such a good idea because
162 * an open of a device or a fifo can block indefinitely.
163 */
164 INTOFF;
165 memory[fd] = 0;
166 switch (redir->nfile.type) {
167 case NFROM:
168 fname = redir->nfile.expfname;
169 if ((f = open(fname, O_RDONLY)) < 0)
170 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
171 movefd:
172 if (f != fd) {
173 copyfd(f, fd);
174 close(f);
175 }
176 break;
177 case NTO:
178 fname = redir->nfile.expfname;
179 #ifdef O_CREAT
180 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
181 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
182 #else
183 if ((f = creat(fname, 0666)) < 0)
184 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
185 #endif
186 goto movefd;
187 case NAPPEND:
188 fname = redir->nfile.expfname;
189 #ifdef O_APPEND
190 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
191 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
192 #else
193 if ((f = open(fname, O_WRONLY)) < 0
194 && (f = creat(fname, 0666)) < 0)
195 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
196 lseek(f, (off_t)0, 2);
197 #endif
198 goto movefd;
199 case NTOFD:
200 case NFROMFD:
201 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
202 if (memory[redir->ndup.dupfd])
203 memory[fd] = 1;
204 else
205 copyfd(redir->ndup.dupfd, fd);
206 }
207 break;
208 case NHERE:
209 case NXHERE:
210 f = openhere(redir);
211 goto movefd;
212 default:
213 abort();
214 }
215 INTON;
216 }
217
218
219 /*
220 * Handle here documents. Normally we fork off a process to write the
221 * data to a pipe. If the document is short, we can stuff the data in
222 * the pipe without forking.
223 */
224
225 STATIC int
226 openhere(redir)
227 union node *redir;
228 {
229 int pip[2];
230 int len = 0;
231
232 if (pipe(pip) < 0)
233 error("Pipe call failed");
234 if (redir->type == NHERE) {
235 len = strlen(redir->nhere.doc->narg.text);
236 if (len <= PIPESIZE) {
237 xwrite(pip[1], redir->nhere.doc->narg.text, len);
238 goto out;
239 }
240 }
241 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
242 close(pip[0]);
243 signal(SIGINT, SIG_IGN);
244 signal(SIGQUIT, SIG_IGN);
245 signal(SIGHUP, SIG_IGN);
246 #ifdef SIGTSTP
247 signal(SIGTSTP, SIG_IGN);
248 #endif
249 signal(SIGPIPE, SIG_DFL);
250 if (redir->type == NHERE)
251 xwrite(pip[1], redir->nhere.doc->narg.text, len);
252 else
253 expandhere(redir->nhere.doc, pip[1]);
254 _exit(0);
255 }
256 out:
257 close(pip[1]);
258 return pip[0];
259 }
260
261
262
263 /*
264 * Undo the effects of the last redirection.
265 */
266
267 void
268 popredir() {
269 struct redirtab *rp = redirlist;
270 int i;
271
272 for (i = 0 ; i < 10 ; i++) {
273 if (rp->renamed[i] != EMPTY) {
274 if (i == 0)
275 fd0_redirected--;
276 close(i);
277 if (rp->renamed[i] >= 0) {
278 copyfd(rp->renamed[i], i);
279 close(rp->renamed[i]);
280 }
281 }
282 }
283 INTOFF;
284 redirlist = rp->next;
285 ckfree(rp);
286 INTON;
287 }
288
289 /*
290 * Undo all redirections. Called on error or interrupt.
291 */
292
293 #ifdef mkinit
294
295 INCLUDE "redir.h"
296
297 RESET {
298 while (redirlist)
299 popredir();
300 }
301
302 SHELLPROC {
303 clearredir();
304 }
305
306 #endif
307
308 /* Return true if fd 0 has already been redirected at least once. */
309 int
310 fd0_redirected_p () {
311 return fd0_redirected != 0;
312 }
313
314 /*
315 * Discard all saved file descriptors.
316 */
317
318 void
319 clearredir() {
320 struct redirtab *rp;
321 int i;
322
323 for (rp = redirlist ; rp ; rp = rp->next) {
324 for (i = 0 ; i < 10 ; i++) {
325 if (rp->renamed[i] >= 0) {
326 close(rp->renamed[i]);
327 }
328 rp->renamed[i] = EMPTY;
329 }
330 }
331 }
332
333
334
335 /*
336 * Copy a file descriptor to be >= to. Returns -1
337 * if the source file descriptor is closed, EMPTY if there are no unused
338 * file descriptors left.
339 */
340
341 int
342 copyfd(from, to)
343 int from;
344 int to;
345 {
346 int newfd;
347
348 newfd = fcntl(from, F_DUPFD, to);
349 if (newfd < 0) {
350 if (errno == EMFILE)
351 return EMPTY;
352 else
353 error("%d: %s", from, strerror(errno));
354 }
355 return newfd;
356 }
357