xref: /original-bsd/bin/sh/redir.c (revision 3588a932)
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
12 static char sccsid[] = "@(#)redir.c	5.1 (Berkeley) 03/07/91";
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 
36 MKINIT
37 struct redirtab {
38 	struct redirtab *next;
39 	short renamed[10];
40 };
41 
42 
43 MKINIT struct redirtab *redirlist;
44 
45 
46 #ifdef __STDC__
47 STATIC void openredirect(union node *, char *);
48 STATIC int openhere(union node *);
49 #else
50 STATIC void openredirect();
51 STATIC 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 
64 void
65 redirect(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 
108 STATIC void
109 openredirect(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));
129 movefd:
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 
183 STATIC int
184 openhere(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 	}
214 out:
215 	close(pip[1]);
216 	return pip[0];
217 }
218 
219 
220 
221 /*
222  * Undo the effects of the last redirection.
223  */
224 
225 void
226 popredir() {
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 
253 INCLUDE "redir.h"
254 
255 RESET {
256 	while (redirlist)
257 		popredir();
258 }
259 
260 SHELLPROC {
261 	clearredir();
262 }
263 
264 #endif
265 
266 
267 /*
268  * Discard all saved file descriptors.
269  */
270 
271 void
272 clearredir() {
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 /*
289  * Copy a file descriptor, like the F_DUPFD option of fcntl.  Returns -1
290  * if the source file descriptor is closed, EMPTY if there are no unused
291  * file descriptors left.
292  */
293 
294 int
295 copyfd(from, to) {
296 #ifdef F_DUPFD
297 	int newfd;
298 
299 	newfd = fcntl(from, F_DUPFD, to);
300 	if (newfd < 0 && errno == EMFILE)
301 		return EMPTY;
302 	return newfd;
303 #else
304 	char toclose[32];
305 	int i;
306 	int newfd;
307 	int e;
308 
309 	for (i = 0 ; i < to ; i++)
310 		toclose[i] = 0;
311 	INTOFF;
312 	while ((newfd = dup(from)) >= 0 && newfd < to)
313 		toclose[newfd] = 1;
314 	e = errno;
315 	for (i = 0 ; i < to ; i++) {
316 		if (toclose[i])
317 			close(i);
318 	}
319 	INTON;
320 	if (newfd < 0 && e == EMFILE)
321 		return EMPTY;
322 	return newfd;
323 #endif
324 }
325