redir.c revision 66612
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.
351556Srgrimes */
361556Srgrimes
371556Srgrimes#ifndef lint
3836150Scharnier#if 0
3936150Scharnierstatic char sccsid[] = "@(#)redir.c	8.2 (Berkeley) 5/4/95";
4036150Scharnier#endif
4136150Scharnierstatic const char rcsid[] =
4250471Speter  "$FreeBSD: head/bin/sh/redir.c 66612 2000-10-03 23:13:14Z brian $";
431556Srgrimes#endif /* not lint */
441556Srgrimes
4517987Speter#include <sys/types.h>
4617987Speter#include <signal.h>
4717987Speter#include <string.h>
4817987Speter#include <fcntl.h>
4917987Speter#include <errno.h>
5017987Speter#include <unistd.h>
5117987Speter#include <stdlib.h>
5217987Speter
531556Srgrimes/*
541556Srgrimes * Code for dealing with input/output redirection.
551556Srgrimes */
561556Srgrimes
571556Srgrimes#include "shell.h"
581556Srgrimes#include "nodes.h"
591556Srgrimes#include "jobs.h"
601556Srgrimes#include "expand.h"
611556Srgrimes#include "redir.h"
621556Srgrimes#include "output.h"
631556Srgrimes#include "memalloc.h"
641556Srgrimes#include "error.h"
651556Srgrimes
661556Srgrimes
671556Srgrimes#define EMPTY -2		/* marks an unused slot in redirtab */
681556Srgrimes#define PIPESIZE 4096		/* amount of buffering in a pipe */
691556Srgrimes
701556Srgrimes
711556SrgrimesMKINIT
721556Srgrimesstruct redirtab {
731556Srgrimes	struct redirtab *next;
741556Srgrimes	short renamed[10];
751556Srgrimes};
761556Srgrimes
771556Srgrimes
781556SrgrimesMKINIT struct redirtab *redirlist;
791556Srgrimes
808855Srgrimes/*
811556Srgrimes * We keep track of whether or not fd0 has been redirected.  This is for
821556Srgrimes * background commands, where we want to redirect fd0 to /dev/null only
838855Srgrimes * if it hasn't already been redirected.
841556Srgrimes*/
851556Srgrimesint fd0_redirected = 0;
861556Srgrimes
8717987SpeterSTATIC void openredirect __P((union node *, char[10 ]));
8817987SpeterSTATIC int openhere __P((union node *));
891556Srgrimes
901556Srgrimes
911556Srgrimes/*
921556Srgrimes * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
931556Srgrimes * old file descriptors are stashed away so that the redirection can be
941556Srgrimes * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
951556Srgrimes * standard output, and the standard error if it becomes a duplicate of
961556Srgrimes * stdout, is saved in memory.
971556Srgrimes */
981556Srgrimes
991556Srgrimesvoid
1001556Srgrimesredirect(redir, flags)
1011556Srgrimes	union node *redir;
1021556Srgrimes	int flags;
1031556Srgrimes	{
1041556Srgrimes	union node *n;
10517987Speter	struct redirtab *sv = NULL;
1061556Srgrimes	int i;
1071556Srgrimes	int fd;
10825231Ssteve	int try;
10920425Ssteve	char memory[10];	/* file descriptors to write to memory */
1101556Srgrimes
1111556Srgrimes	for (i = 10 ; --i >= 0 ; )
1121556Srgrimes		memory[i] = 0;
1131556Srgrimes	memory[1] = flags & REDIR_BACKQ;
1141556Srgrimes	if (flags & REDIR_PUSH) {
1151556Srgrimes		sv = ckmalloc(sizeof (struct redirtab));
1161556Srgrimes		for (i = 0 ; i < 10 ; i++)
1171556Srgrimes			sv->renamed[i] = EMPTY;
1181556Srgrimes		sv->next = redirlist;
1191556Srgrimes		redirlist = sv;
1201556Srgrimes	}
1211556Srgrimes	for (n = redir ; n ; n = n->nfile.next) {
1221556Srgrimes		fd = n->nfile.fd;
12325231Ssteve		try = 0;
12411601Sjoerg		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
12511601Sjoerg		    n->ndup.dupfd == fd)
12620425Ssteve			continue; /* redirect from/to same file descriptor */
12725231Ssteve
1281556Srgrimes		if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
1291556Srgrimes			INTOFF;
13025231Ssteveagain:
13125231Ssteve			if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
13225231Ssteve				switch (errno) {
13325231Ssteve				case EBADF:
13425231Ssteve					if (!try) {
13525231Ssteve						openredirect(n, memory);
13625231Ssteve						try++;
13725231Ssteve						goto again;
13825231Ssteve					}
13925231Ssteve					/* FALLTHROUGH*/
14025231Ssteve				default:
14125231Ssteve					INTON;
14225231Ssteve					error("%d: %s", fd, strerror(errno));
14325231Ssteve					break;
14425231Ssteve				}
14525231Ssteve			}
14625231Ssteve			if (!try) {
1471556Srgrimes				sv->renamed[fd] = i;
1481556Srgrimes				close(fd);
1491556Srgrimes			}
1501556Srgrimes			INTON;
1511556Srgrimes		} else {
1521556Srgrimes			close(fd);
1531556Srgrimes		}
15425231Ssteve		if (fd == 0)
15525231Ssteve			fd0_redirected++;
15625231Ssteve		if (!try)
15725231Ssteve			openredirect(n, memory);
1581556Srgrimes	}
1591556Srgrimes	if (memory[1])
1601556Srgrimes		out1 = &memout;
1611556Srgrimes	if (memory[2])
1621556Srgrimes		out2 = &memout;
1631556Srgrimes}
1641556Srgrimes
1651556Srgrimes
1661556SrgrimesSTATIC void
1671556Srgrimesopenredirect(redir, memory)
1681556Srgrimes	union node *redir;
1691556Srgrimes	char memory[10];
1701556Srgrimes	{
1711556Srgrimes	int fd = redir->nfile.fd;
1721556Srgrimes	char *fname;
1731556Srgrimes	int f;
1741556Srgrimes
1751556Srgrimes	/*
1761556Srgrimes	 * We suppress interrupts so that we won't leave open file
1771556Srgrimes	 * descriptors around.  This may not be such a good idea because
1781556Srgrimes	 * an open of a device or a fifo can block indefinitely.
1791556Srgrimes	 */
1801556Srgrimes	INTOFF;
1811556Srgrimes	memory[fd] = 0;
1821556Srgrimes	switch (redir->nfile.type) {
1831556Srgrimes	case NFROM:
1841556Srgrimes		fname = redir->nfile.expfname;
1851556Srgrimes		if ((f = open(fname, O_RDONLY)) < 0)
1861556Srgrimes			error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
1871556Srgrimesmovefd:
1881556Srgrimes		if (f != fd) {
1891556Srgrimes			copyfd(f, fd);
1901556Srgrimes			close(f);
1911556Srgrimes		}
1921556Srgrimes		break;
19366612Sbrian	case NFROMTO:
19466612Sbrian		fname = redir->nfile.expfname;
19566612Sbrian#ifdef O_CREAT
19666612Sbrian		if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
19766612Sbrian			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
19866612Sbrian#else
19966612Sbrian		if ((f = open(fname, O_RDWR, 0666)) < 0) {
20066612Sbrian			if (errno != ENOENT)
20166612Sbrian				error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
20266612Sbrian			else if ((f = creat(fname, 0666)) < 0)
20366612Sbrian				error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
20466612Sbrian			else {
20566612Sbrian				close(f);
20666612Sbrian				if ((f = open(fname, O_RDWR)) < 0) {
20766612Sbrian					error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
20866612Sbrian					remove(fname);
20966612Sbrian				}
21066612Sbrian			}
21166612Sbrian		}
21266612Sbrian#endif
21366612Sbrian		goto movefd;
2141556Srgrimes	case NTO:
2151556Srgrimes		fname = redir->nfile.expfname;
2161556Srgrimes#ifdef O_CREAT
2171556Srgrimes		if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
2181556Srgrimes			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
2191556Srgrimes#else
2201556Srgrimes		if ((f = creat(fname, 0666)) < 0)
2211556Srgrimes			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
2221556Srgrimes#endif
2231556Srgrimes		goto movefd;
2241556Srgrimes	case NAPPEND:
2251556Srgrimes		fname = redir->nfile.expfname;
2261556Srgrimes#ifdef O_APPEND
2271556Srgrimes		if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
2281556Srgrimes			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
2291556Srgrimes#else
2301556Srgrimes		if ((f = open(fname, O_WRONLY)) < 0
2311556Srgrimes		 && (f = creat(fname, 0666)) < 0)
2321556Srgrimes			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
2331556Srgrimes		lseek(f, (off_t)0, 2);
2341556Srgrimes#endif
2351556Srgrimes		goto movefd;
2361556Srgrimes	case NTOFD:
2371556Srgrimes	case NFROMFD:
2381556Srgrimes		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
2391556Srgrimes			if (memory[redir->ndup.dupfd])
2401556Srgrimes				memory[fd] = 1;
2411556Srgrimes			else
2421556Srgrimes				copyfd(redir->ndup.dupfd, fd);
2431556Srgrimes		}
2441556Srgrimes		break;
2451556Srgrimes	case NHERE:
2461556Srgrimes	case NXHERE:
2471556Srgrimes		f = openhere(redir);
2481556Srgrimes		goto movefd;
2491556Srgrimes	default:
2501556Srgrimes		abort();
2511556Srgrimes	}
2521556Srgrimes	INTON;
2531556Srgrimes}
2541556Srgrimes
2551556Srgrimes
2561556Srgrimes/*
2571556Srgrimes * Handle here documents.  Normally we fork off a process to write the
2581556Srgrimes * data to a pipe.  If the document is short, we can stuff the data in
2591556Srgrimes * the pipe without forking.
2601556Srgrimes */
2611556Srgrimes
2621556SrgrimesSTATIC int
2631556Srgrimesopenhere(redir)
2641556Srgrimes	union node *redir;
2651556Srgrimes	{
2661556Srgrimes	int pip[2];
26717987Speter	int len = 0;
2681556Srgrimes
2691556Srgrimes	if (pipe(pip) < 0)
27053891Scracauer		error("Pipe call failed: %s", strerror(errno));
2711556Srgrimes	if (redir->type == NHERE) {
2721556Srgrimes		len = strlen(redir->nhere.doc->narg.text);
2731556Srgrimes		if (len <= PIPESIZE) {
2741556Srgrimes			xwrite(pip[1], redir->nhere.doc->narg.text, len);
2751556Srgrimes			goto out;
2761556Srgrimes		}
2771556Srgrimes	}
2781556Srgrimes	if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
2791556Srgrimes		close(pip[0]);
2801556Srgrimes		signal(SIGINT, SIG_IGN);
2811556Srgrimes		signal(SIGQUIT, SIG_IGN);
2821556Srgrimes		signal(SIGHUP, SIG_IGN);
2831556Srgrimes#ifdef SIGTSTP
2841556Srgrimes		signal(SIGTSTP, SIG_IGN);
2851556Srgrimes#endif
2861556Srgrimes		signal(SIGPIPE, SIG_DFL);
2871556Srgrimes		if (redir->type == NHERE)
2881556Srgrimes			xwrite(pip[1], redir->nhere.doc->narg.text, len);
2891556Srgrimes		else
2901556Srgrimes			expandhere(redir->nhere.doc, pip[1]);
2911556Srgrimes		_exit(0);
2921556Srgrimes	}
2931556Srgrimesout:
2941556Srgrimes	close(pip[1]);
2951556Srgrimes	return pip[0];
2961556Srgrimes}
2971556Srgrimes
2981556Srgrimes
2991556Srgrimes
3001556Srgrimes/*
3011556Srgrimes * Undo the effects of the last redirection.
3021556Srgrimes */
3031556Srgrimes
3041556Srgrimesvoid
3051556Srgrimespopredir() {
30625231Ssteve	struct redirtab *rp = redirlist;
3071556Srgrimes	int i;
3081556Srgrimes
3091556Srgrimes	for (i = 0 ; i < 10 ; i++) {
3101556Srgrimes		if (rp->renamed[i] != EMPTY) {
3111556Srgrimes                        if (i == 0)
3121556Srgrimes                                fd0_redirected--;
3131556Srgrimes			close(i);
3141556Srgrimes			if (rp->renamed[i] >= 0) {
3151556Srgrimes				copyfd(rp->renamed[i], i);
3161556Srgrimes				close(rp->renamed[i]);
3171556Srgrimes			}
3181556Srgrimes		}
3191556Srgrimes	}
3201556Srgrimes	INTOFF;
3211556Srgrimes	redirlist = rp->next;
3221556Srgrimes	ckfree(rp);
3231556Srgrimes	INTON;
3241556Srgrimes}
3251556Srgrimes
3261556Srgrimes/*
3271556Srgrimes * Undo all redirections.  Called on error or interrupt.
3281556Srgrimes */
3291556Srgrimes
3301556Srgrimes#ifdef mkinit
3311556Srgrimes
3321556SrgrimesINCLUDE "redir.h"
3331556Srgrimes
3341556SrgrimesRESET {
3351556Srgrimes	while (redirlist)
3361556Srgrimes		popredir();
3371556Srgrimes}
3381556Srgrimes
3391556SrgrimesSHELLPROC {
3401556Srgrimes	clearredir();
3411556Srgrimes}
3421556Srgrimes
3431556Srgrimes#endif
3441556Srgrimes
3451556Srgrimes/* Return true if fd 0 has already been redirected at least once.  */
3461556Srgrimesint
3471556Srgrimesfd0_redirected_p () {
3481556Srgrimes        return fd0_redirected != 0;
3491556Srgrimes}
3501556Srgrimes
3511556Srgrimes/*
3521556Srgrimes * Discard all saved file descriptors.
3531556Srgrimes */
3541556Srgrimes
3551556Srgrimesvoid
3561556Srgrimesclearredir() {
35725231Ssteve	struct redirtab *rp;
3581556Srgrimes	int i;
3591556Srgrimes
3601556Srgrimes	for (rp = redirlist ; rp ; rp = rp->next) {
3611556Srgrimes		for (i = 0 ; i < 10 ; i++) {
3621556Srgrimes			if (rp->renamed[i] >= 0) {
3631556Srgrimes				close(rp->renamed[i]);
3641556Srgrimes			}
3651556Srgrimes			rp->renamed[i] = EMPTY;
3661556Srgrimes		}
3671556Srgrimes	}
3681556Srgrimes}
3691556Srgrimes
3701556Srgrimes
3711556Srgrimes
3721556Srgrimes/*
3731556Srgrimes * Copy a file descriptor to be >= to.  Returns -1
3741556Srgrimes * if the source file descriptor is closed, EMPTY if there are no unused
3751556Srgrimes * file descriptors left.
3761556Srgrimes */
3771556Srgrimes
3781556Srgrimesint
37920425Sstevecopyfd(from, to)
38017987Speter	int from;
38117987Speter	int to;
38217987Speter{
3831556Srgrimes	int newfd;
3841556Srgrimes
3851556Srgrimes	newfd = fcntl(from, F_DUPFD, to);
38620425Ssteve	if (newfd < 0) {
38720425Ssteve		if (errno == EMFILE)
38820425Ssteve			return EMPTY;
38920425Ssteve		else
39020425Ssteve			error("%d: %s", from, strerror(errno));
39120425Ssteve	}
3921556Srgrimes	return newfd;
3931556Srgrimes}
394