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