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