1/* tee - duplicate standard input */ 2 3/* See Makefile for compilation details. */ 4 5#include "config.h" 6 7#include "bashtypes.h" 8#include "posixstat.h" 9#include "filecntl.h" 10 11#include <signal.h> 12 13#if defined (HAVE_UNISTD_H) 14# include <unistd.h> 15#endif 16 17#include "bashansi.h" 18 19#include <stdio.h> 20#include <errno.h> 21 22#include "builtins.h" 23#include "shell.h" 24#include "bashgetopt.h" 25 26#if !defined (errno) 27extern int errno; 28#endif 29 30typedef struct flist { 31 struct flist *next; 32 int fd; 33 char *fname; 34} FLIST; 35 36static FLIST *tee_flist; 37 38#define TEE_BUFSIZE 8192 39 40extern int interrupt_immediately; 41 42extern char *strerror (); 43 44tee_builtin (list) 45 WORD_LIST *list; 46{ 47 int opt, append, nointr, rval, fd, fflags; 48 int n, nr, nw; 49 FLIST *fl; 50 char *buf, *bp; 51 52 char *t; 53 54 reset_internal_getopt (); 55 append = nointr = 0; 56 tee_flist = (FLIST *)NULL; 57 while ((opt = internal_getopt (list, "ai")) != -1) 58 { 59 switch (opt) 60 { 61 case 'a': 62 append = 1; 63 break; 64 case 'i': 65 nointr = 1; 66 break; 67 default: 68 builtin_usage (); 69 return (EX_USAGE); 70 } 71 } 72 list = loptend; 73 74 if (nointr == 0) 75 interrupt_immediately++; 76 77 buf = xmalloc (TEE_BUFSIZE); 78 79 /* Initialize output file list. */ 80 fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST)); 81 tee_flist->fd = 1; 82 tee_flist->fname = "stdout"; 83 tee_flist->next = (FLIST *)NULL; 84 85 /* Add file arguments to list of output files. */ 86 fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC; 87 for (rval = EXECUTION_SUCCESS; list; list = list->next) 88 { 89 fd = open (list->word->word, fflags, 0666); 90 if (fd < 0) 91 { 92 builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno)); 93 rval = EXECUTION_FAILURE; 94 } 95 else 96 { 97 fl->next = (FLIST *)xmalloc (sizeof(FLIST)); 98 fl->next->fd = fd; 99 fl->next->fname = list->word->word; 100 fl = fl->next; 101 fl->next = (FLIST *)NULL; 102 } 103 } 104 105 while ((nr = read(0, buf, TEE_BUFSIZE)) > 0) 106 for (fl = tee_flist; fl; fl = fl->next) 107 { 108 n = nr; 109 bp = buf; 110 do 111 { 112 if ((nw = write (fl->fd, bp, n)) == -1) 113 { 114 builtin_error ("%s: write error: %s", fl->fname, strerror (errno)); 115 rval = EXECUTION_FAILURE; 116 break; 117 } 118 bp += nw; 119 } 120 while (n -= nw); 121 } 122 if (nr < 0) 123 builtin_error ("read error: %s", strerror (errno)); 124 125 /* Deallocate resources -- this is a builtin command. */ 126 tee_flist = tee_flist->next; /* skip bogus close of stdout */ 127 while (tee_flist) 128 { 129 fl = tee_flist; 130 if (close (fl->fd) < 0) 131 { 132 builtin_error ("%s: close_error: %s", fl->fname, strerror (errno)); 133 rval = EXECUTION_FAILURE; 134 } 135 tee_flist = tee_flist->next; 136 free (fl); 137 } 138 139 return (rval); 140} 141 142char *tee_doc[] = { 143 "Copy standard input to standard output, making a copy in each", 144 "filename argument. If the `-a' option is gived, the specified", 145 "files are appended to, otherwise they are overwritten. If the", 146 "`-i' option is supplied, tee ignores interrupts.", 147 (char *)NULL 148}; 149 150struct builtin tee_struct = { 151 "tee", /* builtin name */ 152 tee_builtin, /* function implementing the builtin */ 153 BUILTIN_ENABLED, /* initial flags for builtin */ 154 tee_doc, /* array of long documentation strings. */ 155 "tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */ 156 0 /* reserved for internal use */ 157}; 158