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