redir.c revision 213760
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3436150Scharnier#if 0
3536150Scharnierstatic char sccsid[] = "@(#)redir.c	8.2 (Berkeley) 5/4/95";
3636150Scharnier#endif
371556Srgrimes#endif /* not lint */
3899110Sobrien#include <sys/cdefs.h>
3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/redir.c 213760 2010-10-13 04:01:01Z obrien $");
401556Srgrimes
4117987Speter#include <sys/types.h>
4296922Stjr#include <sys/stat.h>
4317987Speter#include <signal.h>
4417987Speter#include <string.h>
4517987Speter#include <fcntl.h>
4617987Speter#include <errno.h>
4717987Speter#include <unistd.h>
4817987Speter#include <stdlib.h>
4917987Speter
501556Srgrimes/*
511556Srgrimes * Code for dealing with input/output redirection.
521556Srgrimes */
531556Srgrimes
541556Srgrimes#include "shell.h"
551556Srgrimes#include "nodes.h"
561556Srgrimes#include "jobs.h"
571556Srgrimes#include "expand.h"
581556Srgrimes#include "redir.h"
591556Srgrimes#include "output.h"
601556Srgrimes#include "memalloc.h"
611556Srgrimes#include "error.h"
6296922Stjr#include "options.h"
631556Srgrimes
641556Srgrimes
651556Srgrimes#define EMPTY -2		/* marks an unused slot in redirtab */
66199953Sjilles#define CLOSED -1		/* fd was not open before redir */
671556Srgrimes#define PIPESIZE 4096		/* amount of buffering in a pipe */
681556Srgrimes
691556Srgrimes
701556SrgrimesMKINIT
711556Srgrimesstruct redirtab {
721556Srgrimes	struct redirtab *next;
73100315Stjr	int renamed[10];
741556Srgrimes};
751556Srgrimes
761556Srgrimes
771556SrgrimesMKINIT struct redirtab *redirlist;
781556Srgrimes
798855Srgrimes/*
801556Srgrimes * We keep track of whether or not fd0 has been redirected.  This is for
811556Srgrimes * background commands, where we want to redirect fd0 to /dev/null only
828855Srgrimes * if it hasn't already been redirected.
831556Srgrimes*/
84213760Sobrienstatic int fd0_redirected = 0;
851556Srgrimes
8690111SimpSTATIC void openredirect(union node *, char[10 ]);
8790111SimpSTATIC int openhere(union node *);
881556Srgrimes
891556Srgrimes
901556Srgrimes/*
911556Srgrimes * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
921556Srgrimes * old file descriptors are stashed away so that the redirection can be
931556Srgrimes * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
941556Srgrimes * standard output, and the standard error if it becomes a duplicate of
951556Srgrimes * stdout, is saved in memory.
961556Srgrimes */
971556Srgrimes
981556Srgrimesvoid
9990111Simpredirect(union node *redir, int flags)
10090111Simp{
1011556Srgrimes	union node *n;
10217987Speter	struct redirtab *sv = NULL;
1031556Srgrimes	int i;
1041556Srgrimes	int fd;
10520425Ssteve	char memory[10];	/* file descriptors to write to memory */
1061556Srgrimes
1071556Srgrimes	for (i = 10 ; --i >= 0 ; )
1081556Srgrimes		memory[i] = 0;
1091556Srgrimes	memory[1] = flags & REDIR_BACKQ;
1101556Srgrimes	if (flags & REDIR_PUSH) {
1111556Srgrimes		sv = ckmalloc(sizeof (struct redirtab));
1121556Srgrimes		for (i = 0 ; i < 10 ; i++)
1131556Srgrimes			sv->renamed[i] = EMPTY;
1141556Srgrimes		sv->next = redirlist;
1151556Srgrimes		redirlist = sv;
1161556Srgrimes	}
1171556Srgrimes	for (n = redir ; n ; n = n->nfile.next) {
1181556Srgrimes		fd = n->nfile.fd;
11911601Sjoerg		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
12011601Sjoerg		    n->ndup.dupfd == fd)
12120425Ssteve			continue; /* redirect from/to same file descriptor */
12225231Ssteve
1231556Srgrimes		if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
1241556Srgrimes			INTOFF;
12525231Ssteve			if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
12625231Ssteve				switch (errno) {
12725231Ssteve				case EBADF:
128199953Sjilles					i = CLOSED;
129199953Sjilles					break;
13025231Ssteve				default:
13125231Ssteve					INTON;
13225231Ssteve					error("%d: %s", fd, strerror(errno));
13325231Ssteve					break;
13425231Ssteve				}
135199953Sjilles			} else
136199953Sjilles				(void)fcntl(i, F_SETFD, FD_CLOEXEC);
137199953Sjilles			sv->renamed[fd] = i;
1381556Srgrimes			INTON;
1391556Srgrimes		}
14025231Ssteve		if (fd == 0)
14125231Ssteve			fd0_redirected++;
142199953Sjilles		openredirect(n, memory);
1431556Srgrimes	}
1441556Srgrimes	if (memory[1])
1451556Srgrimes		out1 = &memout;
1461556Srgrimes	if (memory[2])
1471556Srgrimes		out2 = &memout;
1481556Srgrimes}
1491556Srgrimes
1501556Srgrimes
1511556SrgrimesSTATIC void
15290111Simpopenredirect(union node *redir, char memory[10])
15390111Simp{
15496922Stjr	struct stat sb;
1551556Srgrimes	int fd = redir->nfile.fd;
1561556Srgrimes	char *fname;
1571556Srgrimes	int f;
1581556Srgrimes
1591556Srgrimes	/*
1601556Srgrimes	 * We suppress interrupts so that we won't leave open file
161199660Sjilles	 * descriptors around.  Because the signal handler remains
162199660Sjilles	 * installed and we do not use system call restart, interrupts
163199660Sjilles	 * will still abort blocking opens such as fifos (they will fail
164199660Sjilles	 * with EINTR). There is, however, a race condition if an interrupt
165199660Sjilles	 * arrives after INTOFF and before open blocks.
1661556Srgrimes	 */
1671556Srgrimes	INTOFF;
1681556Srgrimes	memory[fd] = 0;
1691556Srgrimes	switch (redir->nfile.type) {
1701556Srgrimes	case NFROM:
1711556Srgrimes		fname = redir->nfile.expfname;
1721556Srgrimes		if ((f = open(fname, O_RDONLY)) < 0)
173104132Stjr			error("cannot open %s: %s", fname, strerror(errno));
1741556Srgrimesmovefd:
1751556Srgrimes		if (f != fd) {
176124780Sdes			dup2(f, fd);
1771556Srgrimes			close(f);
1781556Srgrimes		}
1791556Srgrimes		break;
18066612Sbrian	case NFROMTO:
18166612Sbrian		fname = redir->nfile.expfname;
18266612Sbrian		if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
183104132Stjr			error("cannot create %s: %s", fname, strerror(errno));
18466612Sbrian		goto movefd;
1851556Srgrimes	case NTO:
186194560Sjilles		if (Cflag) {
187194560Sjilles			fname = redir->nfile.expfname;
188194560Sjilles			if (stat(fname, &sb) == -1) {
189194560Sjilles				if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
190194560Sjilles					error("cannot create %s: %s", fname, strerror(errno));
191194560Sjilles			} else if (!S_ISREG(sb.st_mode)) {
192194560Sjilles				if ((f = open(fname, O_WRONLY, 0666)) < 0)
193194560Sjilles					error("cannot create %s: %s", fname, strerror(errno));
194194560Sjilles				if (fstat(f, &sb) != -1 && S_ISREG(sb.st_mode)) {
195194560Sjilles					close(f);
196194560Sjilles					error("cannot create %s: %s", fname,
197194560Sjilles					    strerror(EEXIST));
198194560Sjilles				}
199194560Sjilles			} else
200194560Sjilles				error("cannot create %s: %s", fname,
201194560Sjilles				    strerror(EEXIST));
202194560Sjilles			goto movefd;
203194560Sjilles		}
204194560Sjilles		/* FALLTHROUGH */
20596922Stjr	case NCLOBBER:
20696922Stjr		fname = redir->nfile.expfname;
20796922Stjr		if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
208104132Stjr			error("cannot create %s: %s", fname, strerror(errno));
20996922Stjr		goto movefd;
2101556Srgrimes	case NAPPEND:
2111556Srgrimes		fname = redir->nfile.expfname;
2121556Srgrimes		if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
213104132Stjr			error("cannot create %s: %s", fname, strerror(errno));
2141556Srgrimes		goto movefd;
2151556Srgrimes	case NTOFD:
2161556Srgrimes	case NFROMFD:
2171556Srgrimes		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
2181556Srgrimes			if (memory[redir->ndup.dupfd])
2191556Srgrimes				memory[fd] = 1;
220124780Sdes			else
221124780Sdes				dup2(redir->ndup.dupfd, fd);
222124780Sdes		} else {
22399645Stjr			close(fd);
224124780Sdes		}
2251556Srgrimes		break;
2261556Srgrimes	case NHERE:
2271556Srgrimes	case NXHERE:
2281556Srgrimes		f = openhere(redir);
2291556Srgrimes		goto movefd;
2301556Srgrimes	default:
2311556Srgrimes		abort();
2321556Srgrimes	}
2331556Srgrimes	INTON;
2341556Srgrimes}
2351556Srgrimes
2361556Srgrimes
2371556Srgrimes/*
2381556Srgrimes * Handle here documents.  Normally we fork off a process to write the
2391556Srgrimes * data to a pipe.  If the document is short, we can stuff the data in
2401556Srgrimes * the pipe without forking.
2411556Srgrimes */
2421556Srgrimes
2431556SrgrimesSTATIC int
24490111Simpopenhere(union node *redir)
24590111Simp{
2461556Srgrimes	int pip[2];
24717987Speter	int len = 0;
2481556Srgrimes
2491556Srgrimes	if (pipe(pip) < 0)
25053891Scracauer		error("Pipe call failed: %s", strerror(errno));
2511556Srgrimes	if (redir->type == NHERE) {
2521556Srgrimes		len = strlen(redir->nhere.doc->narg.text);
2531556Srgrimes		if (len <= PIPESIZE) {
2541556Srgrimes			xwrite(pip[1], redir->nhere.doc->narg.text, len);
2551556Srgrimes			goto out;
2561556Srgrimes		}
2571556Srgrimes	}
2581556Srgrimes	if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
2591556Srgrimes		close(pip[0]);
2601556Srgrimes		signal(SIGINT, SIG_IGN);
2611556Srgrimes		signal(SIGQUIT, SIG_IGN);
2621556Srgrimes		signal(SIGHUP, SIG_IGN);
2631556Srgrimes		signal(SIGTSTP, SIG_IGN);
2641556Srgrimes		signal(SIGPIPE, SIG_DFL);
2651556Srgrimes		if (redir->type == NHERE)
2661556Srgrimes			xwrite(pip[1], redir->nhere.doc->narg.text, len);
2671556Srgrimes		else
2681556Srgrimes			expandhere(redir->nhere.doc, pip[1]);
2691556Srgrimes		_exit(0);
2701556Srgrimes	}
2711556Srgrimesout:
2721556Srgrimes	close(pip[1]);
2731556Srgrimes	return pip[0];
2741556Srgrimes}
2751556Srgrimes
2761556Srgrimes
2771556Srgrimes
2781556Srgrimes/*
2791556Srgrimes * Undo the effects of the last redirection.
2801556Srgrimes */
2811556Srgrimes
2821556Srgrimesvoid
28390111Simppopredir(void)
28490111Simp{
28525231Ssteve	struct redirtab *rp = redirlist;
2861556Srgrimes	int i;
2871556Srgrimes
2881556Srgrimes	for (i = 0 ; i < 10 ; i++) {
2891556Srgrimes		if (rp->renamed[i] != EMPTY) {
2901556Srgrimes                        if (i == 0)
2911556Srgrimes                                fd0_redirected--;
2921556Srgrimes			if (rp->renamed[i] >= 0) {
293124780Sdes				dup2(rp->renamed[i], i);
2941556Srgrimes				close(rp->renamed[i]);
295124780Sdes			} else {
296124780Sdes				close(i);
2971556Srgrimes			}
2981556Srgrimes		}
2991556Srgrimes	}
3001556Srgrimes	INTOFF;
3011556Srgrimes	redirlist = rp->next;
3021556Srgrimes	ckfree(rp);
3031556Srgrimes	INTON;
3041556Srgrimes}
3051556Srgrimes
3061556Srgrimes/*
3071556Srgrimes * Undo all redirections.  Called on error or interrupt.
3081556Srgrimes */
3091556Srgrimes
3101556Srgrimes#ifdef mkinit
3111556Srgrimes
3121556SrgrimesINCLUDE "redir.h"
3131556Srgrimes
3141556SrgrimesRESET {
3151556Srgrimes	while (redirlist)
3161556Srgrimes		popredir();
3171556Srgrimes}
3181556Srgrimes
3191556SrgrimesSHELLPROC {
3201556Srgrimes	clearredir();
3211556Srgrimes}
3221556Srgrimes
3231556Srgrimes#endif
3241556Srgrimes
3251556Srgrimes/* Return true if fd 0 has already been redirected at least once.  */
3261556Srgrimesint
32790111Simpfd0_redirected_p(void)
32890111Simp{
3291556Srgrimes        return fd0_redirected != 0;
3301556Srgrimes}
3311556Srgrimes
3321556Srgrimes/*
3331556Srgrimes * Discard all saved file descriptors.
3341556Srgrimes */
3351556Srgrimes
3361556Srgrimesvoid
33790111Simpclearredir(void)
33890111Simp{
33925231Ssteve	struct redirtab *rp;
3401556Srgrimes	int i;
3411556Srgrimes
3421556Srgrimes	for (rp = redirlist ; rp ; rp = rp->next) {
3431556Srgrimes		for (i = 0 ; i < 10 ; i++) {
3441556Srgrimes			if (rp->renamed[i] >= 0) {
3451556Srgrimes				close(rp->renamed[i]);
3461556Srgrimes			}
3471556Srgrimes			rp->renamed[i] = EMPTY;
3481556Srgrimes		}
3491556Srgrimes	}
3501556Srgrimes}
351