xref: /original-bsd/bin/sh/redir.c (revision b3c06cab)
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
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
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
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
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
275 fd0_redirected_p () {
276         return fd0_redirected != 0;
277 }
278 
279 /*
280  * Discard all saved file descriptors.
281  */
282 
283 void
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
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