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