xref: /csrg-svn/bin/sh/redir.c (revision 69272)
147141Sbostic /*-
260698Sbostic  * Copyright (c) 1991, 1993
360698Sbostic  *	The Regents of the University of California.  All rights reserved.
447141Sbostic  *
547141Sbostic  * This code is derived from software contributed to Berkeley by
647141Sbostic  * Kenneth Almquist.
747141Sbostic  *
847141Sbostic  * %sccs.include.redist.c%
947141Sbostic  */
1047141Sbostic 
1147141Sbostic #ifndef lint
12*69272Schristos static char sccsid[] = "@(#)redir.c	8.2 (Berkeley) 05/04/95";
1347141Sbostic #endif /* not lint */
1447141Sbostic 
15*69272Schristos #include <sys/types.h>
16*69272Schristos #include <signal.h>
17*69272Schristos #include <string.h>
18*69272Schristos #include <fcntl.h>
19*69272Schristos #include <errno.h>
20*69272Schristos #include <unistd.h>
21*69272Schristos #include <stdlib.h>
22*69272Schristos 
2347141Sbostic /*
2447141Sbostic  * Code for dealing with input/output redirection.
2547141Sbostic  */
2647141Sbostic 
2747141Sbostic #include "shell.h"
2847141Sbostic #include "nodes.h"
2947141Sbostic #include "jobs.h"
3047141Sbostic #include "expand.h"
3147141Sbostic #include "redir.h"
3247141Sbostic #include "output.h"
3347141Sbostic #include "memalloc.h"
3447141Sbostic #include "error.h"
3547141Sbostic 
3647141Sbostic 
3747141Sbostic #define EMPTY -2		/* marks an unused slot in redirtab */
3847141Sbostic #define PIPESIZE 4096		/* amount of buffering in a pipe */
3947141Sbostic 
4047141Sbostic 
4147141Sbostic MKINIT
4247141Sbostic struct redirtab {
4347141Sbostic 	struct redirtab *next;
4447141Sbostic 	short renamed[10];
4547141Sbostic };
4647141Sbostic 
4747141Sbostic 
4847141Sbostic MKINIT struct redirtab *redirlist;
4947141Sbostic 
5060296Smarc /*
5160296Smarc  * We keep track of whether or not fd0 has been redirected.  This is for
5260296Smarc  * background commands, where we want to redirect fd0 to /dev/null only
5360296Smarc  * if it hasn't already been redirected.
5460296Smarc */
5560296Smarc int fd0_redirected = 0;
5647141Sbostic 
57*69272Schristos STATIC void openredirect __P((union node *, char[10 ]));
58*69272Schristos STATIC int openhere __P((union node *));
5947141Sbostic 
6047141Sbostic 
6147141Sbostic /*
6247141Sbostic  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
6347141Sbostic  * old file descriptors are stashed away so that the redirection can be
6447141Sbostic  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
6547141Sbostic  * standard output, and the standard error if it becomes a duplicate of
6647141Sbostic  * stdout, is saved in memory.
6747141Sbostic  */
6847141Sbostic 
6947141Sbostic void
redirect(redir,flags)7047141Sbostic redirect(redir, flags)
7147141Sbostic 	union node *redir;
7247141Sbostic 	int flags;
7347141Sbostic 	{
7447141Sbostic 	union node *n;
7547141Sbostic 	struct redirtab *sv;
7647141Sbostic 	int i;
7747141Sbostic 	int fd;
7847141Sbostic 	char memory[10];		/* file descriptors to write to memory */
7947141Sbostic 
8047141Sbostic 	for (i = 10 ; --i >= 0 ; )
8147141Sbostic 		memory[i] = 0;
8247141Sbostic 	memory[1] = flags & REDIR_BACKQ;
8347141Sbostic 	if (flags & REDIR_PUSH) {
8447141Sbostic 		sv = ckmalloc(sizeof (struct redirtab));
8547141Sbostic 		for (i = 0 ; i < 10 ; i++)
8647141Sbostic 			sv->renamed[i] = EMPTY;
8747141Sbostic 		sv->next = redirlist;
8847141Sbostic 		redirlist = sv;
8947141Sbostic 	}
9047141Sbostic 	for (n = redir ; n ; n = n->nfile.next) {
9147141Sbostic 		fd = n->nfile.fd;
9247141Sbostic 		if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
9347141Sbostic 			INTOFF;
9447141Sbostic 			if ((i = copyfd(fd, 10)) != EMPTY) {
9547141Sbostic 				sv->renamed[fd] = i;
9647141Sbostic 				close(fd);
9747141Sbostic 			}
9847141Sbostic 			INTON;
9947141Sbostic 			if (i == EMPTY)
10047141Sbostic 				error("Out of file descriptors");
10147141Sbostic 		} else {
10247141Sbostic 			close(fd);
10347141Sbostic 		}
10460296Smarc                 if (fd == 0)
10560296Smarc                         fd0_redirected++;
10647141Sbostic 		openredirect(n, memory);
10747141Sbostic 	}
10847141Sbostic 	if (memory[1])
10947141Sbostic 		out1 = &memout;
11047141Sbostic 	if (memory[2])
11147141Sbostic 		out2 = &memout;
11247141Sbostic }
11347141Sbostic 
11447141Sbostic 
11547141Sbostic STATIC void
openredirect(redir,memory)11647141Sbostic openredirect(redir, memory)
11747141Sbostic 	union node *redir;
11847141Sbostic 	char memory[10];
11947141Sbostic 	{
12047141Sbostic 	int fd = redir->nfile.fd;
12147141Sbostic 	char *fname;
12247141Sbostic 	int f;
12347141Sbostic 
12447141Sbostic 	/*
12547141Sbostic 	 * We suppress interrupts so that we won't leave open file
12647141Sbostic 	 * descriptors around.  This may not be such a good idea because
12747141Sbostic 	 * an open of a device or a fifo can block indefinitely.
12847141Sbostic 	 */
12947141Sbostic 	INTOFF;
13047141Sbostic 	memory[fd] = 0;
13147141Sbostic 	switch (redir->nfile.type) {
13247141Sbostic 	case NFROM:
13347141Sbostic 		fname = redir->nfile.expfname;
13447141Sbostic 		if ((f = open(fname, O_RDONLY)) < 0)
13547141Sbostic 			error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
13647141Sbostic movefd:
13747141Sbostic 		if (f != fd) {
13847141Sbostic 			copyfd(f, fd);
13947141Sbostic 			close(f);
14047141Sbostic 		}
14147141Sbostic 		break;
14247141Sbostic 	case NTO:
14347141Sbostic 		fname = redir->nfile.expfname;
14447141Sbostic #ifdef O_CREAT
14547141Sbostic 		if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
14647141Sbostic 			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
14747141Sbostic #else
14847141Sbostic 		if ((f = creat(fname, 0666)) < 0)
14947141Sbostic 			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
15047141Sbostic #endif
15147141Sbostic 		goto movefd;
15247141Sbostic 	case NAPPEND:
15347141Sbostic 		fname = redir->nfile.expfname;
15447141Sbostic #ifdef O_APPEND
15547141Sbostic 		if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
15647141Sbostic 			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
15747141Sbostic #else
15847141Sbostic 		if ((f = open(fname, O_WRONLY)) < 0
15947141Sbostic 		 && (f = creat(fname, 0666)) < 0)
16047141Sbostic 			error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
16154327Smarc 		lseek(f, (off_t)0, 2);
16247141Sbostic #endif
16347141Sbostic 		goto movefd;
16447141Sbostic 	case NTOFD:
16547141Sbostic 	case NFROMFD:
16647141Sbostic 		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
16747141Sbostic 			if (memory[redir->ndup.dupfd])
16847141Sbostic 				memory[fd] = 1;
16947141Sbostic 			else
17047141Sbostic 				copyfd(redir->ndup.dupfd, fd);
17147141Sbostic 		}
17247141Sbostic 		break;
17347141Sbostic 	case NHERE:
17447141Sbostic 	case NXHERE:
17547141Sbostic 		f = openhere(redir);
17647141Sbostic 		goto movefd;
17747141Sbostic 	default:
17847141Sbostic 		abort();
17947141Sbostic 	}
18047141Sbostic 	INTON;
18147141Sbostic }
18247141Sbostic 
18347141Sbostic 
18447141Sbostic /*
18547141Sbostic  * Handle here documents.  Normally we fork off a process to write the
18647141Sbostic  * data to a pipe.  If the document is short, we can stuff the data in
18747141Sbostic  * the pipe without forking.
18847141Sbostic  */
18947141Sbostic 
19047141Sbostic STATIC int
openhere(redir)19147141Sbostic openhere(redir)
19247141Sbostic 	union node *redir;
19347141Sbostic 	{
19447141Sbostic 	int pip[2];
195*69272Schristos 	int len = 0;
19647141Sbostic 
19747141Sbostic 	if (pipe(pip) < 0)
19847141Sbostic 		error("Pipe call failed");
19947141Sbostic 	if (redir->type == NHERE) {
20047141Sbostic 		len = strlen(redir->nhere.doc->narg.text);
20147141Sbostic 		if (len <= PIPESIZE) {
20247141Sbostic 			xwrite(pip[1], redir->nhere.doc->narg.text, len);
20347141Sbostic 			goto out;
20447141Sbostic 		}
20547141Sbostic 	}
20647141Sbostic 	if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
20747141Sbostic 		close(pip[0]);
20847141Sbostic 		signal(SIGINT, SIG_IGN);
20947141Sbostic 		signal(SIGQUIT, SIG_IGN);
21047141Sbostic 		signal(SIGHUP, SIG_IGN);
21147141Sbostic #ifdef SIGTSTP
21247141Sbostic 		signal(SIGTSTP, SIG_IGN);
21347141Sbostic #endif
21447141Sbostic 		signal(SIGPIPE, SIG_DFL);
21547141Sbostic 		if (redir->type == NHERE)
21647141Sbostic 			xwrite(pip[1], redir->nhere.doc->narg.text, len);
21747141Sbostic 		else
21847141Sbostic 			expandhere(redir->nhere.doc, pip[1]);
21947141Sbostic 		_exit(0);
22047141Sbostic 	}
22147141Sbostic out:
22247141Sbostic 	close(pip[1]);
22347141Sbostic 	return pip[0];
22447141Sbostic }
22547141Sbostic 
22647141Sbostic 
22747141Sbostic 
22847141Sbostic /*
22947141Sbostic  * Undo the effects of the last redirection.
23047141Sbostic  */
23147141Sbostic 
23247141Sbostic void
popredir()23347141Sbostic popredir() {
23447141Sbostic 	register struct redirtab *rp = redirlist;
23547141Sbostic 	int i;
23647141Sbostic 
23747141Sbostic 	for (i = 0 ; i < 10 ; i++) {
23847141Sbostic 		if (rp->renamed[i] != EMPTY) {
23960296Smarc                         if (i == 0)
24060296Smarc                                 fd0_redirected--;
24147141Sbostic 			close(i);
24247141Sbostic 			if (rp->renamed[i] >= 0) {
24347141Sbostic 				copyfd(rp->renamed[i], i);
24447141Sbostic 				close(rp->renamed[i]);
24547141Sbostic 			}
24647141Sbostic 		}
24747141Sbostic 	}
24847141Sbostic 	INTOFF;
24947141Sbostic 	redirlist = rp->next;
25047141Sbostic 	ckfree(rp);
25147141Sbostic 	INTON;
25247141Sbostic }
25347141Sbostic 
25447141Sbostic /*
25547141Sbostic  * Undo all redirections.  Called on error or interrupt.
25647141Sbostic  */
25747141Sbostic 
25847141Sbostic #ifdef mkinit
25947141Sbostic 
26047141Sbostic INCLUDE "redir.h"
26147141Sbostic 
26247141Sbostic RESET {
26347141Sbostic 	while (redirlist)
26447141Sbostic 		popredir();
26547141Sbostic }
26647141Sbostic 
26747141Sbostic SHELLPROC {
26847141Sbostic 	clearredir();
26947141Sbostic }
27047141Sbostic 
27147141Sbostic #endif
27247141Sbostic 
27360296Smarc /* Return true if fd 0 has already been redirected at least once.  */
27460296Smarc int
fd0_redirected_p()27560296Smarc fd0_redirected_p () {
27660296Smarc         return fd0_redirected != 0;
27760296Smarc }
27847141Sbostic 
27947141Sbostic /*
28047141Sbostic  * Discard all saved file descriptors.
28147141Sbostic  */
28247141Sbostic 
28347141Sbostic void
clearredir()28447141Sbostic clearredir() {
28547141Sbostic 	register struct redirtab *rp;
28647141Sbostic 	int i;
28747141Sbostic 
28847141Sbostic 	for (rp = redirlist ; rp ; rp = rp->next) {
28947141Sbostic 		for (i = 0 ; i < 10 ; i++) {
29047141Sbostic 			if (rp->renamed[i] >= 0) {
29147141Sbostic 				close(rp->renamed[i]);
29247141Sbostic 			}
29347141Sbostic 			rp->renamed[i] = EMPTY;
29447141Sbostic 		}
29547141Sbostic 	}
29647141Sbostic }
29747141Sbostic 
29847141Sbostic 
29947141Sbostic 
30047141Sbostic /*
30153650Smarc  * Copy a file descriptor to be >= to.  Returns -1
30247141Sbostic  * if the source file descriptor is closed, EMPTY if there are no unused
30347141Sbostic  * file descriptors left.
30447141Sbostic  */
30547141Sbostic 
30647141Sbostic int
copyfd(from,to)307*69272Schristos copyfd(from, to)
308*69272Schristos 	int from;
309*69272Schristos 	int to;
310*69272Schristos {
31147141Sbostic 	int newfd;
31247141Sbostic 
31347141Sbostic 	newfd = fcntl(from, F_DUPFD, to);
31447141Sbostic 	if (newfd < 0 && errno == EMFILE)
31547141Sbostic 		return EMPTY;
31647141Sbostic 	return newfd;
31747141Sbostic }
318