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