redir.c revision 17987
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 * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
353044Sdg *
3617987Speter *	$Id: redir.c,v 1.4 1995/10/21 00:47:31 joerg Exp $
371556Srgrimes */
381556Srgrimes
391556Srgrimes#ifndef lint
4017987Speterstatic char sccsid[] = "@(#)redir.c	8.2 (Berkeley) 5/4/95";
411556Srgrimes#endif /* not lint */
421556Srgrimes
4317987Speter#include <sys/types.h>
4417987Speter#include <signal.h>
4517987Speter#include <string.h>
4617987Speter#include <fcntl.h>
4717987Speter#include <errno.h>
4817987Speter#include <unistd.h>
4917987Speter#include <stdlib.h>
5017987Speter
511556Srgrimes/*
521556Srgrimes * Code for dealing with input/output redirection.
531556Srgrimes */
541556Srgrimes
551556Srgrimes#include "shell.h"
561556Srgrimes#include "nodes.h"
571556Srgrimes#include "jobs.h"
581556Srgrimes#include "expand.h"
591556Srgrimes#include "redir.h"
601556Srgrimes#include "output.h"
611556Srgrimes#include "memalloc.h"
621556Srgrimes#include "error.h"
631556Srgrimes
641556Srgrimes
651556Srgrimes#define EMPTY -2		/* marks an unused slot in redirtab */
661556Srgrimes#define PIPESIZE 4096		/* amount of buffering in a pipe */
671556Srgrimes
681556Srgrimes
691556SrgrimesMKINIT
701556Srgrimesstruct redirtab {
711556Srgrimes	struct redirtab *next;
721556Srgrimes	short renamed[10];
731556Srgrimes};
741556Srgrimes
751556Srgrimes
761556SrgrimesMKINIT struct redirtab *redirlist;
771556Srgrimes
788855Srgrimes/*
791556Srgrimes * We keep track of whether or not fd0 has been redirected.  This is for
801556Srgrimes * background commands, where we want to redirect fd0 to /dev/null only
818855Srgrimes * if it hasn't already been redirected.
821556Srgrimes*/
831556Srgrimesint fd0_redirected = 0;
841556Srgrimes
8517987SpeterSTATIC void openredirect __P((union node *, char[10 ]));
8617987SpeterSTATIC int openhere __P((union node *));
871556Srgrimes
881556Srgrimes
891556Srgrimes/*
901556Srgrimes * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
911556Srgrimes * old file descriptors are stashed away so that the redirection can be
921556Srgrimes * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
931556Srgrimes * standard output, and the standard error if it becomes a duplicate of
941556Srgrimes * stdout, is saved in memory.
951556Srgrimes */
961556Srgrimes
971556Srgrimesvoid
981556Srgrimesredirect(redir, flags)
991556Srgrimes	union node *redir;
1001556Srgrimes	int flags;
1011556Srgrimes	{
1021556Srgrimes	union node *n;
10317987Speter	struct redirtab *sv = NULL;
1041556Srgrimes	int i;
1051556Srgrimes	int fd;
1061556Srgrimes	char memory[10];		/* file descriptors to write to memory */
1071556Srgrimes
1081556Srgrimes	for (i = 10 ; --i >= 0 ; )
1091556Srgrimes		memory[i] = 0;
1101556Srgrimes	memory[1] = flags & REDIR_BACKQ;
1111556Srgrimes	if (flags & REDIR_PUSH) {
1121556Srgrimes		sv = ckmalloc(sizeof (struct redirtab));
1131556Srgrimes		for (i = 0 ; i < 10 ; i++)
1141556Srgrimes			sv->renamed[i] = EMPTY;
1151556Srgrimes		sv->next = redirlist;
1161556Srgrimes		redirlist = sv;
1171556Srgrimes	}
1181556Srgrimes	for (n = redir ; n ; n = n->nfile.next) {
1191556Srgrimes		fd = n->nfile.fd;
12011601Sjoerg		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
12111601Sjoerg		    n->ndup.dupfd == fd)
12211601Sjoerg			continue; /* redirect from/to myself */
1231556Srgrimes		if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
1241556Srgrimes			INTOFF;
1251556Srgrimes			if ((i = copyfd(fd, 10)) != EMPTY) {
1261556Srgrimes				sv->renamed[fd] = i;
1271556Srgrimes				close(fd);
1281556Srgrimes			}
1291556Srgrimes			INTON;
1301556Srgrimes			if (i == EMPTY)
1311556Srgrimes				error("Out of file descriptors");
1321556Srgrimes		} else {
1331556Srgrimes			close(fd);
1341556Srgrimes		}
1351556Srgrimes                if (fd == 0)
1361556Srgrimes                        fd0_redirected++;
1371556Srgrimes		openredirect(n, memory);
1381556Srgrimes	}
1391556Srgrimes	if (memory[1])
1401556Srgrimes		out1 = &memout;
1411556Srgrimes	if (memory[2])
1421556Srgrimes		out2 = &memout;
1431556Srgrimes}
1441556Srgrimes
1451556Srgrimes
1461556SrgrimesSTATIC void
1471556Srgrimesopenredirect(redir, memory)
1481556Srgrimes	union node *redir;
1491556Srgrimes	char memory[10];
1501556Srgrimes	{
1511556Srgrimes	int fd = redir->nfile.fd;
1521556Srgrimes	char *fname;
1531556Srgrimes	int f;
1541556Srgrimes
1551556Srgrimes	/*
1561556Srgrimes	 * We suppress interrupts so that we won't leave open file
1571556Srgrimes	 * descriptors around.  This may not be such a good idea because
1581556Srgrimes	 * an open of a device or a fifo can block indefinitely.
1591556Srgrimes	 */
1601556Srgrimes	INTOFF;
1611556Srgrimes	memory[fd] = 0;
1621556Srgrimes	switch (redir->nfile.type) {
1631556Srgrimes	case NFROM:
1641556Srgrimes		fname = redir->nfile.expfname;
1651556Srgrimes		if ((f = open(fname, O_RDONLY)) < 0)
1661556Srgrimes			error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
1671556Srgrimesmovefd:
1681556Srgrimes		if (f != fd) {
1691556Srgrimes			copyfd(f, fd);
1701556Srgrimes			close(f);
1711556Srgrimes		}
1721556Srgrimes		break;
1731556Srgrimes	case NTO:
1741556Srgrimes		fname = redir->nfile.expfname;
1751556Srgrimes#ifdef O_CREAT
1761556Srgrimes		if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
1771556Srgrimes			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
1781556Srgrimes#else
1791556Srgrimes		if ((f = creat(fname, 0666)) < 0)
1801556Srgrimes			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
1811556Srgrimes#endif
1821556Srgrimes		goto movefd;
1831556Srgrimes	case NAPPEND:
1841556Srgrimes		fname = redir->nfile.expfname;
1851556Srgrimes#ifdef O_APPEND
1861556Srgrimes		if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
1871556Srgrimes			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
1881556Srgrimes#else
1891556Srgrimes		if ((f = open(fname, O_WRONLY)) < 0
1901556Srgrimes		 && (f = creat(fname, 0666)) < 0)
1911556Srgrimes			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
1921556Srgrimes		lseek(f, (off_t)0, 2);
1931556Srgrimes#endif
1941556Srgrimes		goto movefd;
1951556Srgrimes	case NTOFD:
1961556Srgrimes	case NFROMFD:
1971556Srgrimes		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
1981556Srgrimes			if (memory[redir->ndup.dupfd])
1991556Srgrimes				memory[fd] = 1;
2001556Srgrimes			else
2011556Srgrimes				copyfd(redir->ndup.dupfd, fd);
2021556Srgrimes		}
2031556Srgrimes		break;
2041556Srgrimes	case NHERE:
2051556Srgrimes	case NXHERE:
2061556Srgrimes		f = openhere(redir);
2071556Srgrimes		goto movefd;
2081556Srgrimes	default:
2091556Srgrimes		abort();
2101556Srgrimes	}
2111556Srgrimes	INTON;
2121556Srgrimes}
2131556Srgrimes
2141556Srgrimes
2151556Srgrimes/*
2161556Srgrimes * Handle here documents.  Normally we fork off a process to write the
2171556Srgrimes * data to a pipe.  If the document is short, we can stuff the data in
2181556Srgrimes * the pipe without forking.
2191556Srgrimes */
2201556Srgrimes
2211556SrgrimesSTATIC int
2221556Srgrimesopenhere(redir)
2231556Srgrimes	union node *redir;
2241556Srgrimes	{
2251556Srgrimes	int pip[2];
22617987Speter	int len = 0;
2271556Srgrimes
2281556Srgrimes	if (pipe(pip) < 0)
2291556Srgrimes		error("Pipe call failed");
2301556Srgrimes	if (redir->type == NHERE) {
2311556Srgrimes		len = strlen(redir->nhere.doc->narg.text);
2321556Srgrimes		if (len <= PIPESIZE) {
2331556Srgrimes			xwrite(pip[1], redir->nhere.doc->narg.text, len);
2341556Srgrimes			goto out;
2351556Srgrimes		}
2361556Srgrimes	}
2371556Srgrimes	if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
2381556Srgrimes		close(pip[0]);
2391556Srgrimes		signal(SIGINT, SIG_IGN);
2401556Srgrimes		signal(SIGQUIT, SIG_IGN);
2411556Srgrimes		signal(SIGHUP, SIG_IGN);
2421556Srgrimes#ifdef SIGTSTP
2431556Srgrimes		signal(SIGTSTP, SIG_IGN);
2441556Srgrimes#endif
2451556Srgrimes		signal(SIGPIPE, SIG_DFL);
2461556Srgrimes		if (redir->type == NHERE)
2471556Srgrimes			xwrite(pip[1], redir->nhere.doc->narg.text, len);
2481556Srgrimes		else
2491556Srgrimes			expandhere(redir->nhere.doc, pip[1]);
2501556Srgrimes		_exit(0);
2511556Srgrimes	}
2521556Srgrimesout:
2531556Srgrimes	close(pip[1]);
2541556Srgrimes	return pip[0];
2551556Srgrimes}
2561556Srgrimes
2571556Srgrimes
2581556Srgrimes
2591556Srgrimes/*
2601556Srgrimes * Undo the effects of the last redirection.
2611556Srgrimes */
2621556Srgrimes
2631556Srgrimesvoid
2641556Srgrimespopredir() {
2651556Srgrimes	register struct redirtab *rp = redirlist;
2661556Srgrimes	int i;
2671556Srgrimes
2681556Srgrimes	for (i = 0 ; i < 10 ; i++) {
2691556Srgrimes		if (rp->renamed[i] != EMPTY) {
2701556Srgrimes                        if (i == 0)
2711556Srgrimes                                fd0_redirected--;
2721556Srgrimes			close(i);
2731556Srgrimes			if (rp->renamed[i] >= 0) {
2741556Srgrimes				copyfd(rp->renamed[i], i);
2751556Srgrimes				close(rp->renamed[i]);
2761556Srgrimes			}
2771556Srgrimes		}
2781556Srgrimes	}
2791556Srgrimes	INTOFF;
2801556Srgrimes	redirlist = rp->next;
2811556Srgrimes	ckfree(rp);
2821556Srgrimes	INTON;
2831556Srgrimes}
2841556Srgrimes
2851556Srgrimes/*
2861556Srgrimes * Undo all redirections.  Called on error or interrupt.
2871556Srgrimes */
2881556Srgrimes
2891556Srgrimes#ifdef mkinit
2901556Srgrimes
2911556SrgrimesINCLUDE "redir.h"
2921556Srgrimes
2931556SrgrimesRESET {
2941556Srgrimes	while (redirlist)
2951556Srgrimes		popredir();
2961556Srgrimes}
2971556Srgrimes
2981556SrgrimesSHELLPROC {
2991556Srgrimes	clearredir();
3001556Srgrimes}
3011556Srgrimes
3021556Srgrimes#endif
3031556Srgrimes
3041556Srgrimes/* Return true if fd 0 has already been redirected at least once.  */
3051556Srgrimesint
3061556Srgrimesfd0_redirected_p () {
3071556Srgrimes        return fd0_redirected != 0;
3081556Srgrimes}
3091556Srgrimes
3101556Srgrimes/*
3111556Srgrimes * Discard all saved file descriptors.
3121556Srgrimes */
3131556Srgrimes
3141556Srgrimesvoid
3151556Srgrimesclearredir() {
3161556Srgrimes	register struct redirtab *rp;
3171556Srgrimes	int i;
3181556Srgrimes
3191556Srgrimes	for (rp = redirlist ; rp ; rp = rp->next) {
3201556Srgrimes		for (i = 0 ; i < 10 ; i++) {
3211556Srgrimes			if (rp->renamed[i] >= 0) {
3221556Srgrimes				close(rp->renamed[i]);
3231556Srgrimes			}
3241556Srgrimes			rp->renamed[i] = EMPTY;
3251556Srgrimes		}
3261556Srgrimes	}
3271556Srgrimes}
3281556Srgrimes
3291556Srgrimes
3301556Srgrimes
3311556Srgrimes/*
3321556Srgrimes * Copy a file descriptor to be >= to.  Returns -1
3331556Srgrimes * if the source file descriptor is closed, EMPTY if there are no unused
3341556Srgrimes * file descriptors left.
3351556Srgrimes */
3361556Srgrimes
3371556Srgrimesint
33817987Spetercopyfd(from, to)
33917987Speter	int from;
34017987Speter	int to;
34117987Speter{
3421556Srgrimes	int newfd;
3431556Srgrimes
3441556Srgrimes	newfd = fcntl(from, F_DUPFD, to);
3451556Srgrimes	if (newfd < 0 && errno == EMFILE)
3461556Srgrimes		return EMPTY;
34711601Sjoerg	if (newfd < 0)
34811601Sjoerg		error("%d: %s", from, strerror(errno));
3491556Srgrimes	return newfd;
3501556Srgrimes}
351