1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1997-2005
5  *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/param.h>	/* PIPE_BUF */
38 #include <signal.h>
39 #include <string.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 
44 /*
45  * Code for dealing with input/output redirection.
46  */
47 
48 #include "main.h"
49 #include "shell.h"
50 #include "nodes.h"
51 #include "jobs.h"
52 #include "options.h"
53 #include "expand.h"
54 #include "redir.h"
55 #include "output.h"
56 #include "memalloc.h"
57 #include "error.h"
58 
59 
60 #define REALLY_CLOSED -3	/* fd that was closed and still is */
61 #define EMPTY -2		/* marks an unused slot in redirtab */
62 #define CLOSED -1		/* fd opened for redir needs to be closed */
63 
64 #ifndef PIPE_BUF
65 # define PIPESIZE 4096		/* amount of buffering in a pipe */
66 #else
67 # define PIPESIZE PIPE_BUF
68 #endif
69 
70 
71 MKINIT
72 struct redirtab {
73 	struct redirtab *next;
74 	int renamed[10];
75 };
76 
77 
78 MKINIT struct redirtab *redirlist;
79 
80 STATIC int openredirect(union node *);
81 #ifdef notyet
82 STATIC void dupredirect(union node *, int, char[10]);
83 #else
84 STATIC void dupredirect(union node *, int);
85 #endif
86 STATIC int openhere(union node *);
87 
88 
89 /*
90  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
91  * old file descriptors are stashed away so that the redirection can be
92  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
93  * standard output, and the standard error if it becomes a duplicate of
94  * stdout, is saved in memory.
95  */
96 
97 void
redirect(union node * redir,int flags)98 redirect(union node *redir, int flags)
99 {
100 	union node *n;
101 	struct redirtab *sv;
102 	int i;
103 	int fd;
104 	int newfd;
105 	int *p;
106 #if notyet
107 	char memory[10];	/* file descriptors to write to memory */
108 
109 	for (i = 10 ; --i >= 0 ; )
110 		memory[i] = 0;
111 	memory[1] = flags & REDIR_BACKQ;
112 #endif
113 	if (!redir)
114 		return;
115 	sv = NULL;
116 	INTOFF;
117 	if (likely(flags & REDIR_PUSH))
118 		sv = redirlist;
119 	n = redir;
120 	do {
121 		newfd = openredirect(n);
122 		if (newfd < -1)
123 			continue;
124 
125 		fd = n->nfile.fd;
126 
127 		if (sv) {
128 			p = &sv->renamed[fd];
129 			i = *p;
130 
131 			if (likely(i == EMPTY)) {
132 				i = CLOSED;
133 				if (fd != newfd) {
134 					i = savefd(fd, fd);
135 					fd = -1;
136 				}
137 			}
138 
139 			if (i == newfd)
140 				/* Can only happen if i == newfd == CLOSED */
141 				i = REALLY_CLOSED;
142 
143 			*p = i;
144 		}
145 
146 		if (fd == newfd)
147 			continue;
148 
149 #ifdef notyet
150 		dupredirect(n, newfd, memory);
151 #else
152 		dupredirect(n, newfd);
153 #endif
154 	} while ((n = n->nfile.next));
155 	INTON;
156 #ifdef notyet
157 	if (memory[1])
158 		out1 = &memout;
159 	if (memory[2])
160 		out2 = &memout;
161 #endif
162 	if (flags & REDIR_SAVEFD2 && sv->renamed[2] >= 0)
163 		preverrout.fd = sv->renamed[2];
164 }
165 
166 
167 STATIC int
openredirect(union node * redir)168 openredirect(union node *redir)
169 {
170 	struct stat sb;
171 	char *fname;
172 	int f;
173 
174 	switch (redir->nfile.type) {
175 	case NFROM:
176 		fname = redir->nfile.expfname;
177 		if ((f = open(fname, O_RDONLY)) < 0)
178 			goto eopen;
179 		break;
180 	case NFROMTO:
181 		fname = redir->nfile.expfname;
182 		if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
183 			goto ecreate;
184 		break;
185 	case NTO:
186 		/* Take care of noclobber mode. */
187 		if (Cflag) {
188 			fname = redir->nfile.expfname;
189 			if (stat(fname, &sb) < 0) {
190 				if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
191 					goto ecreate;
192 			} else if (!S_ISREG(sb.st_mode)) {
193 				if ((f = open(fname, O_WRONLY, 0666)) < 0)
194 					goto ecreate;
195 				if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
196 					close(f);
197 					errno = EEXIST;
198 					goto ecreate;
199 				}
200 			} else {
201 				errno = EEXIST;
202 				goto ecreate;
203 			}
204 			break;
205 		}
206 		/* FALLTHROUGH */
207 	case NCLOBBER:
208 		fname = redir->nfile.expfname;
209 		if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
210 			goto ecreate;
211 		break;
212 	case NAPPEND:
213 		fname = redir->nfile.expfname;
214 		if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
215 			goto ecreate;
216 		break;
217 	case NTOFD:
218 	case NFROMFD:
219 		f = redir->ndup.dupfd;
220 		if (f == redir->nfile.fd)
221 			f = -2;
222 		break;
223 	default:
224 #ifdef DEBUG
225 		abort();
226 #endif
227 		/* Fall through to eliminate warning. */
228 	case NHERE:
229 	case NXHERE:
230 		f = openhere(redir);
231 		break;
232 	}
233 
234 	return f;
235 ecreate:
236 	sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
237 eopen:
238 	sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
239 }
240 
241 
242 STATIC void
243 #ifdef notyet
dupredirect(redir,f,memory)244 dupredirect(redir, f, memory)
245 #else
246 dupredirect(redir, f)
247 #endif
248 	union node *redir;
249 	int f;
250 #ifdef notyet
251 	char memory[10];
252 #endif
253 	{
254 	int fd = redir->nfile.fd;
255 	int err = 0;
256 
257 #ifdef notyet
258 	memory[fd] = 0;
259 #endif
260 	if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
261 		/* if not ">&-" */
262 		if (f >= 0) {
263 #ifdef notyet
264 			if (memory[f])
265 				memory[fd] = 1;
266 			else
267 #endif
268 				if (dup2(f, fd) < 0) {
269 					err = errno;
270 					goto err;
271 				}
272 			return;
273 		}
274 		f = fd;
275 	} else if (dup2(f, fd) < 0)
276 		err = errno;
277 
278 	close(f);
279 	if (err < 0)
280 		goto err;
281 
282 	return;
283 
284 err:
285 	sh_error("%d: %s", f, strerror(err));
286 }
287 
288 
289 /*
290  * Handle here documents.  Normally we fork off a process to write the
291  * data to a pipe.  If the document is short, we can stuff the data in
292  * the pipe without forking.
293  */
294 
295 STATIC int
openhere(union node * redir)296 openhere(union node *redir)
297 {
298 	char *p;
299 	int pip[2];
300 	size_t len = 0;
301 
302 	if (pipe(pip) < 0)
303 		sh_error("Pipe call failed");
304 
305 	p = redir->nhere.doc->narg.text;
306 	if (redir->type == NXHERE) {
307 		expandarg(redir->nhere.doc, NULL, EXP_QUOTED);
308 		p = stackblock();
309 	}
310 
311 	len = strlen(p);
312 	if (len <= PIPESIZE) {
313 		xwrite(pip[1], p, len);
314 		goto out;
315 	}
316 
317 	if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
318 		close(pip[0]);
319 		signal(SIGINT, SIG_IGN);
320 		signal(SIGQUIT, SIG_IGN);
321 		signal(SIGHUP, SIG_IGN);
322 #ifdef SIGTSTP
323 		signal(SIGTSTP, SIG_IGN);
324 #endif
325 		signal(SIGPIPE, SIG_DFL);
326 		xwrite(pip[1], p, len);
327 		_exit(0);
328 	}
329 out:
330 	close(pip[1]);
331 	return pip[0];
332 }
333 
334 
335 
336 /*
337  * Undo the effects of the last redirection.
338  */
339 
340 void
popredir(int drop)341 popredir(int drop)
342 {
343 	struct redirtab *rp;
344 	int i;
345 
346 	INTOFF;
347 	rp = redirlist;
348 	for (i = 0 ; i < 10 ; i++) {
349 		switch (rp->renamed[i]) {
350 		case CLOSED:
351 			if (!drop)
352 				close(i);
353 			break;
354 		case EMPTY:
355 		case REALLY_CLOSED:
356 			break;
357 		default:
358 			if (!drop)
359 				dup2(rp->renamed[i], i);
360 			close(rp->renamed[i]);
361 			break;
362 		}
363 	}
364 	redirlist = rp->next;
365 	ckfree(rp);
366 	INTON;
367 }
368 
369 /*
370  * Undo all redirections.  Called on error or interrupt.
371  */
372 
373 #ifdef mkinit
374 
375 INCLUDE "redir.h"
376 
377 RESET {
378 	/*
379 	 * Discard all saved file descriptors.
380 	 */
381 	unwindredir(0);
382 }
383 
384 #endif
385 
386 
387 
388 /*
389  * Move a file descriptor to > 10.  Invokes sh_error on error unless
390  * the original file dscriptor is not open.
391  */
392 
393 int
savefd(int from,int ofd)394 savefd(int from, int ofd)
395 {
396 	int newfd;
397 	int err;
398 
399 	newfd = fcntl(from, F_DUPFD, 10);
400 	err = newfd < 0 ? errno : 0;
401 	if (err != EBADF) {
402 		close(ofd);
403 		if (err)
404 			sh_error("%d: %s", from, strerror(err));
405 		else
406 			fcntl(newfd, F_SETFD, FD_CLOEXEC);
407 	}
408 
409 	return newfd;
410 }
411 
412 
413 int
redirectsafe(union node * redir,int flags)414 redirectsafe(union node *redir, int flags)
415 {
416 	int err;
417 	volatile int saveint;
418 	struct jmploc *volatile savehandler = handler;
419 	struct jmploc jmploc;
420 
421 	SAVEINT(saveint);
422 	if (!(err = setjmp(jmploc.loc) * 2)) {
423 		handler = &jmploc;
424 		redirect(redir, flags);
425 	}
426 	handler = savehandler;
427 	if (err && exception != EXERROR)
428 		longjmp(handler->loc, 1);
429 	RESTOREINT(saveint);
430 	return err;
431 }
432 
433 
unwindredir(struct redirtab * stop)434 void unwindredir(struct redirtab *stop)
435 {
436 	while (redirlist != stop)
437 		popredir(0);
438 }
439 
440 
pushredir(union node * redir)441 struct redirtab *pushredir(union node *redir)
442 {
443 	struct redirtab *sv;
444 	struct redirtab *q;
445 	int i;
446 
447 	q = redirlist;
448 	if (!redir)
449 		goto out;
450 
451 	sv = ckmalloc(sizeof (struct redirtab));
452 	sv->next = q;
453 	redirlist = sv;
454 	for (i = 0; i < 10; i++)
455 		sv->renamed[i] = EMPTY;
456 
457 out:
458 	return q;
459 }
460