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