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