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