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