xref: /netbsd-src/bin/sh/redir.c (revision a24efa7dea9f1f56c3bdb15a927d3516792ace1c)
1 /*	$NetBSD: redir.c,v 1.47 2016/05/12 13:31:37 kre Exp $	*/
2 
3 /*-
4  * Copyright (c) 1991, 1993
5  *	The Regents of the University of California.  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/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)redir.c	8.2 (Berkeley) 5/4/95";
39 #else
40 __RCSID("$NetBSD: redir.c,v 1.47 2016/05/12 13:31:37 kre Exp $");
41 #endif
42 #endif /* not lint */
43 
44 #include <sys/types.h>
45 #include <sys/param.h>	/* PIPE_BUF */
46 #include <signal.h>
47 #include <string.h>
48 #include <fcntl.h>
49 #include <errno.h>
50 #include <unistd.h>
51 #include <stdlib.h>
52 
53 /*
54  * Code for dealing with input/output redirection.
55  */
56 
57 #include "main.h"
58 #include "shell.h"
59 #include "nodes.h"
60 #include "jobs.h"
61 #include "options.h"
62 #include "expand.h"
63 #include "redir.h"
64 #include "output.h"
65 #include "memalloc.h"
66 #include "error.h"
67 
68 
69 #define EMPTY -2		/* marks an unused slot in redirtab */
70 #define CLOSED -1		/* fd was not open before redir */
71 #ifndef PIPE_BUF
72 # define PIPESIZE 4096		/* amount of buffering in a pipe */
73 #else
74 # define PIPESIZE PIPE_BUF
75 #endif
76 
77 
78 MKINIT
79 struct renamelist {
80 	struct renamelist *next;
81 	int orig;
82 	int into;
83 };
84 
85 MKINIT
86 struct redirtab {
87 	struct redirtab *next;
88 	struct renamelist *renamed;
89 };
90 
91 
92 MKINIT struct redirtab *redirlist;
93 
94 /*
95  * We keep track of whether or not fd0 has been redirected.  This is for
96  * background commands, where we want to redirect fd0 to /dev/null only
97  * if it hasn't already been redirected.
98  */
99 STATIC int fd0_redirected = 0;
100 
101 /*
102  * And also where to put internal use fds that should be out of the
103  * way of user defined fds (normally)
104  */
105 STATIC int big_sh_fd = 0;
106 
107 STATIC const struct renamelist *is_renamed(const struct renamelist *, int);
108 STATIC void fd_rename(struct redirtab *, int, int);
109 STATIC void free_rl(struct redirtab *, int);
110 STATIC void openredirect(union node *, char[10], int);
111 STATIC int openhere(const union node *);
112 STATIC int copyfd(int, int, int);
113 STATIC void find_big_fd(void);
114 
115 STATIC const struct renamelist *
116 is_renamed(const struct renamelist *rl, int fd)
117 {
118 	while (rl != NULL) {
119 		if (rl->orig == fd)
120 			return rl;
121 		rl = rl->next;
122 	}
123 	return NULL;
124 }
125 
126 STATIC void
127 free_rl(struct redirtab *rt, int reset)
128 {
129 	struct renamelist *rl, *rn = rt->renamed;
130 
131 	while ((rl = rn) != NULL) {
132 		rn = rl->next;
133 		if (rl->orig == 0)
134 			fd0_redirected--;
135 		if (reset) {
136 			if (rl->into < 0)
137 				close(rl->orig);
138 			else
139 				movefd(rl->into, rl->orig);
140 		}
141 		ckfree(rl);
142 	}
143 	rt->renamed = NULL;
144 }
145 
146 STATIC void
147 fd_rename(struct redirtab *rt, int from, int to)
148 {
149 	struct renamelist *rl = ckmalloc(sizeof(struct renamelist));
150 
151 	rl->next = rt->renamed;
152 	rt->renamed = rl;
153 
154 	rl->orig = from;
155 	rl->into = to;
156 }
157 
158 /*
159  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
160  * old file descriptors are stashed away so that the redirection can be
161  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
162  * standard output, and the standard error if it becomes a duplicate of
163  * stdout, is saved in memory.
164  */
165 
166 void
167 redirect(union node *redir, int flags)
168 {
169 	union node *n;
170 	struct redirtab *sv = NULL;
171 	int i;
172 	int fd;
173 	char memory[10];	/* file descriptors to write to memory */
174 
175 	for (i = 10 ; --i >= 0 ; )
176 		memory[i] = 0;
177 	memory[1] = flags & REDIR_BACKQ;
178 	if (flags & REDIR_PUSH) {
179 		/* We don't have to worry about REDIR_VFORK here, as
180 		 * flags & REDIR_PUSH is never true if REDIR_VFORK is set.
181 		 */
182 		sv = ckmalloc(sizeof (struct redirtab));
183 		sv->renamed = NULL;
184 		sv->next = redirlist;
185 		redirlist = sv;
186 	}
187 	for (n = redir ; n ; n = n->nfile.next) {
188 		fd = n->nfile.fd;
189 		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
190 		    n->ndup.dupfd == fd) {
191 			/* redirect from/to same file descriptor */
192 			/* make sure it stays open */
193 			if (fcntl(fd, F_SETFD, 0) < 0)
194 				error("fd %d: %s", fd, strerror(errno));
195 			continue;
196 		}
197 
198 		if ((flags & REDIR_PUSH) && !is_renamed(sv->renamed, fd)) {
199 			INTOFF;
200 			if (big_sh_fd < 10)
201 				find_big_fd();
202 			if ((i = fcntl(fd, F_DUPFD, big_sh_fd)) == -1) {
203 				switch (errno) {
204 				case EBADF:
205 					i = CLOSED;
206 					break;
207 				case EMFILE:
208 				case EINVAL:
209 					find_big_fd();
210 					i = fcntl(fd, F_DUPFD, big_sh_fd);
211 					if (i >= 0)
212 						break;
213 					/* FALLTHRU */
214 				default:
215 					i = errno;
216 					INTON;    /* XXX not needed here ? */
217 					error("%d: %s", fd, strerror(i));
218 					/* NOTREACHED */
219 				}
220 			}
221 			if (i >= 0)
222 				(void)fcntl(i, F_SETFD, FD_CLOEXEC);
223 			fd_rename(sv, fd, i);
224 			INTON;
225 		}
226 		if (fd == 0)
227 			fd0_redirected++;
228 		openredirect(n, memory, flags);
229 	}
230 	if (memory[1])
231 		out1 = &memout;
232 	if (memory[2])
233 		out2 = &memout;
234 }
235 
236 
237 STATIC void
238 openredirect(union node *redir, char memory[10], int flags)
239 {
240 	struct stat sb;
241 	int fd = redir->nfile.fd;
242 	char *fname;
243 	int f;
244 	int eflags, cloexec;
245 
246 	/*
247 	 * We suppress interrupts so that we won't leave open file
248 	 * descriptors around.  This may not be such a good idea because
249 	 * an open of a device or a fifo can block indefinitely.
250 	 */
251 	INTOFF;
252 	if (fd < 10)
253 		memory[fd] = 0;
254 	switch (redir->nfile.type) {
255 	case NFROM:
256 		fname = redir->nfile.expfname;
257 		if (flags & REDIR_VFORK)
258 			eflags = O_NONBLOCK;
259 		else
260 			eflags = 0;
261 		if ((f = open(fname, O_RDONLY|eflags)) < 0)
262 			goto eopen;
263 		if (eflags)
264 			(void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags);
265 		break;
266 	case NFROMTO:
267 		fname = redir->nfile.expfname;
268 		if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
269 			goto ecreate;
270 		break;
271 	case NTO:
272 		if (Cflag) {
273 			fname = redir->nfile.expfname;
274 			if ((f = open(fname, O_WRONLY)) == -1) {
275 				if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL,
276 				    0666)) < 0)
277 					goto ecreate;
278 			} else if (fstat(f, &sb) == -1) {
279 				int serrno = errno;
280 				close(f);
281 				errno = serrno;
282 				goto ecreate;
283 			} else if (S_ISREG(sb.st_mode)) {
284 				close(f);
285 				errno = EEXIST;
286 				goto ecreate;
287 			}
288 			break;
289 		}
290 		/* FALLTHROUGH */
291 	case NCLOBBER:
292 		fname = redir->nfile.expfname;
293 		if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
294 			goto ecreate;
295 		break;
296 	case NAPPEND:
297 		fname = redir->nfile.expfname;
298 		if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
299 			goto ecreate;
300 		break;
301 	case NTOFD:
302 	case NFROMFD:
303 		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
304 			if (fd < 10 && redir->ndup.dupfd < 10 &&
305 			    memory[redir->ndup.dupfd])
306 				memory[fd] = 1;
307 			else if (copyfd(redir->ndup.dupfd, fd,
308 			    (flags&(REDIR_PUSH|REDIR_KEEP)) == REDIR_PUSH) < 0)
309 				error("Redirect (from %d to %d) failed: %s",
310 				    redir->ndup.dupfd, fd, strerror(errno));
311 		} else
312 			(void) close(fd);
313 		INTON;
314 		return;
315 	case NHERE:
316 	case NXHERE:
317 		f = openhere(redir);
318 		break;
319 	default:
320 		abort();
321 	}
322 
323 	cloexec = fd > 2 && (flags & REDIR_KEEP) == 0;
324 	if (f != fd) {
325 		if (copyfd(f, fd, cloexec) < 0) {
326 			int e = errno;
327 
328 			close(f);
329 			error("redirect reassignment (fd %d) failed: %s", fd,
330 			    strerror(e));
331 		}
332 		close(f);
333 	} else if (cloexec)
334 		(void)fcntl(f, F_SETFD, FD_CLOEXEC);
335 
336 	INTON;
337 	return;
338 ecreate:
339 	exerrno = 1;
340 	error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
341 eopen:
342 	exerrno = 1;
343 	error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
344 }
345 
346 
347 /*
348  * Handle here documents.  Normally we fork off a process to write the
349  * data to a pipe.  If the document is short, we can stuff the data in
350  * the pipe without forking.
351  */
352 
353 STATIC int
354 openhere(const union node *redir)
355 {
356 	int pip[2];
357 	int len = 0;
358 
359 	if (pipe(pip) < 0)
360 		error("Pipe call failed");
361 	if (redir->type == NHERE) {
362 		len = strlen(redir->nhere.doc->narg.text);
363 		if (len <= PIPESIZE) {
364 			xwrite(pip[1], redir->nhere.doc->narg.text, len);
365 			goto out;
366 		}
367 	}
368 	if (forkshell(NULL, NULL, FORK_NOJOB) == 0) {
369 		close(pip[0]);
370 		signal(SIGINT, SIG_IGN);
371 		signal(SIGQUIT, SIG_IGN);
372 		signal(SIGHUP, SIG_IGN);
373 #ifdef SIGTSTP
374 		signal(SIGTSTP, SIG_IGN);
375 #endif
376 		signal(SIGPIPE, SIG_DFL);
377 		if (redir->type == NHERE)
378 			xwrite(pip[1], redir->nhere.doc->narg.text, len);
379 		else
380 			expandhere(redir->nhere.doc, pip[1]);
381 		_exit(0);
382 	}
383 out:
384 	close(pip[1]);
385 	return pip[0];
386 }
387 
388 
389 
390 /*
391  * Undo the effects of the last redirection.
392  */
393 
394 void
395 popredir(void)
396 {
397 	struct redirtab *rp = redirlist;
398 
399 	INTOFF;
400 	free_rl(rp, 1);
401 	redirlist = rp->next;
402 	ckfree(rp);
403 	INTON;
404 }
405 
406 /*
407  * Undo all redirections.  Called on error or interrupt.
408  */
409 
410 #ifdef mkinit
411 
412 INCLUDE "redir.h"
413 
414 RESET {
415 	while (redirlist)
416 		popredir();
417 }
418 
419 SHELLPROC {
420 	clearredir(0);
421 }
422 
423 #endif
424 
425 /* Return true if fd 0 has already been redirected at least once.  */
426 int
427 fd0_redirected_p(void)
428 {
429 	return fd0_redirected != 0;
430 }
431 
432 /*
433  * Discard all saved file descriptors.
434  */
435 
436 void
437 clearredir(int vforked)
438 {
439 	struct redirtab *rp;
440 	struct renamelist *rl;
441 
442 	for (rp = redirlist ; rp ; rp = rp->next) {
443 		if (!vforked)
444 			free_rl(rp, 0);
445 		else for (rl = rp->renamed; rl; rl = rl->next)
446 			if (rl->into >= 0)
447 				close(rl->into);
448 	}
449 }
450 
451 
452 
453 /*
454  * Copy a file descriptor to be == to.
455  * cloexec indicates if we want close-on-exec or not.
456  * Returns -1 if any error occurs.
457  */
458 
459 STATIC int
460 copyfd(int from, int to, int cloexec)
461 {
462 	int newfd;
463 
464 	if (cloexec && to > 2)
465 		newfd = dup3(from, to, O_CLOEXEC);
466 	else
467 		newfd = dup2(from, to);
468 
469 	return newfd;
470 }
471 
472 /*
473  * rename fd from to be fd to (closing from).
474  * close-on-exec is never set on 'to' (unless
475  * from==to and it was set on from) - ie: a no-op
476  * returns to (or errors() if an error occurs).
477  *
478  * This is mostly used for rearranging the
479  * results from pipe().
480  */
481 int
482 movefd(int from, int to)
483 {
484 	if (from == to)
485 		return to;
486 
487 	(void) close(to);
488 	if (copyfd(from, to, 0) != to) {
489 		int e = errno;
490 
491 		(void) close(from);
492 		error("Unable to make fd %d: %s", to, strerror(e));
493 	}
494 	(void) close(from);
495 
496 	return to;
497 }
498 
499 STATIC void
500 find_big_fd(void)
501 {
502 	int i, fd;
503 
504 	for (i = (1 << 10); i >= 10; i >>= 1) {
505 		if ((fd = fcntl(0, F_DUPFD, i - 1)) >= 0) {
506 			close(fd);
507 			break;
508 		}
509 	}
510 
511 	fd = (i / 5) * 4;
512 	if ((i - fd) > 100)
513 		fd = i - 100;
514 	else if (fd < 10)
515 		fd = 10;
516 
517 	big_sh_fd = fd;
518 }
519 
520 /*
521  * If possible, move file descriptor fd out of the way
522  * of expected user fd values.   Returns the new fd
523  * (which may be the input fd if things do not go well.)
524  * Always set close-on-exec on the result, and close
525  * the input fd unless it is to be our result.
526  */
527 int
528 to_upper_fd(int fd)
529 {
530 	int i;
531 
532 	if (big_sh_fd < 10)
533 		find_big_fd();
534 	do {
535 		i = fcntl(fd, F_DUPFD_CLOEXEC, big_sh_fd);
536 		if (i >= 0) {
537 			if (fd != i)
538 				close(fd);
539 			return i;
540 		}
541 		if (errno != EMFILE)
542 			break;
543 		find_big_fd();
544 	} while (big_sh_fd > 10);
545 
546 	/*
547 	 * If we wanted to move this fd to some random high number
548 	 * we certainly do not intend to pass it through exec, even
549 	 * if the reassignment failed.
550 	 */
551 	(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
552 	return fd;
553 }
554