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