1*da2e3ebdSchin /*********************************************************************** 2*da2e3ebdSchin * * 3*da2e3ebdSchin * This software is part of the ast package * 4*da2e3ebdSchin * Copyright (c) 1992-2007 AT&T Knowledge Ventures * 5*da2e3ebdSchin * and is licensed under the * 6*da2e3ebdSchin * Common Public License, Version 1.0 * 7*da2e3ebdSchin * by AT&T Knowledge Ventures * 8*da2e3ebdSchin * * 9*da2e3ebdSchin * A copy of the License is available at * 10*da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt * 11*da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*da2e3ebdSchin * * 13*da2e3ebdSchin * Information and Software Systems Research * 14*da2e3ebdSchin * AT&T Research * 15*da2e3ebdSchin * Florham Park NJ * 16*da2e3ebdSchin * * 17*da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> * 18*da2e3ebdSchin * David Korn <dgk@research.att.com> * 19*da2e3ebdSchin * * 20*da2e3ebdSchin ***********************************************************************/ 21*da2e3ebdSchin #pragma prototyped 22*da2e3ebdSchin /* 23*da2e3ebdSchin * David Korn 24*da2e3ebdSchin * AT&T Bell Laboratories 25*da2e3ebdSchin * 26*da2e3ebdSchin * tee 27*da2e3ebdSchin */ 28*da2e3ebdSchin 29*da2e3ebdSchin static const char usage[] = 30*da2e3ebdSchin "[-?\n@(#)$Id: tee (AT&T Research) 2006-10-10 $\n]" 31*da2e3ebdSchin USAGE_LICENSE 32*da2e3ebdSchin "[+NAME?tee - duplicate standard input]" 33*da2e3ebdSchin "[+DESCRIPTION?\btee\b copies standard input to standard output " 34*da2e3ebdSchin "and to zero or more files. The options determine whether " 35*da2e3ebdSchin "the specified files are overwritten or appended to. The " 36*da2e3ebdSchin "\btee\b utility does not buffer output. If writes to any " 37*da2e3ebdSchin "\afile\a fail, writes to other files continue although \btee\b " 38*da2e3ebdSchin "will exit with a non-zero exit status.]" 39*da2e3ebdSchin "[+?The number of \afile\a operands that can be specified is limited " 40*da2e3ebdSchin "by the underlying operating system.]" 41*da2e3ebdSchin "[a:append?Append the standard input to the given files rather " 42*da2e3ebdSchin "than overwriting them.]" 43*da2e3ebdSchin "[i:ignore-interrupts?Ignore SIGINT signal.]" 44*da2e3ebdSchin "[l:linebuffer?Set the standard output to be line buffered.]" 45*da2e3ebdSchin "\n" 46*da2e3ebdSchin "\n[file ...]\n" 47*da2e3ebdSchin "\n" 48*da2e3ebdSchin "[+EXIT STATUS?]{" 49*da2e3ebdSchin "[+0?All files copies successfully.]" 50*da2e3ebdSchin "[+>0?An error occurred.]" 51*da2e3ebdSchin "}" 52*da2e3ebdSchin "[+SEE ALSO?\bcat\b(1), \bsignal\b(3)]" 53*da2e3ebdSchin ; 54*da2e3ebdSchin 55*da2e3ebdSchin 56*da2e3ebdSchin #include <cmd.h> 57*da2e3ebdSchin #include <ls.h> 58*da2e3ebdSchin #include <sig.h> 59*da2e3ebdSchin 60*da2e3ebdSchin typedef struct Tee_s 61*da2e3ebdSchin { 62*da2e3ebdSchin Sfdisc_t disc; 63*da2e3ebdSchin int fd[1]; 64*da2e3ebdSchin } Tee_t; 65*da2e3ebdSchin 66*da2e3ebdSchin /* 67*da2e3ebdSchin * This discipline writes to each file in the list given in handle 68*da2e3ebdSchin */ 69*da2e3ebdSchin 70*da2e3ebdSchin static ssize_t tee_write(Sfio_t* fp, const void* buf, size_t n, Sfdisc_t* handle) 71*da2e3ebdSchin { 72*da2e3ebdSchin register const char* bp; 73*da2e3ebdSchin register const char* ep; 74*da2e3ebdSchin register int* hp = ((Tee_t*)handle)->fd; 75*da2e3ebdSchin register int fd = sffileno(fp); 76*da2e3ebdSchin register ssize_t r; 77*da2e3ebdSchin 78*da2e3ebdSchin do 79*da2e3ebdSchin { 80*da2e3ebdSchin bp = (const char*)buf; 81*da2e3ebdSchin ep = bp + n; 82*da2e3ebdSchin while (bp < ep) 83*da2e3ebdSchin { 84*da2e3ebdSchin if ((r = write(fd, bp, ep - bp)) <= 0) 85*da2e3ebdSchin return(-1); 86*da2e3ebdSchin bp += r; 87*da2e3ebdSchin } 88*da2e3ebdSchin } while ((fd = *hp++) >= 0); 89*da2e3ebdSchin return(n); 90*da2e3ebdSchin } 91*da2e3ebdSchin 92*da2e3ebdSchin int 93*da2e3ebdSchin b_tee(int argc, register char** argv, void* context) 94*da2e3ebdSchin { 95*da2e3ebdSchin register Tee_t* tp = 0; 96*da2e3ebdSchin register int oflag = O_WRONLY|O_TRUNC|O_CREAT|O_BINARY; 97*da2e3ebdSchin register int n; 98*da2e3ebdSchin register int* hp; 99*da2e3ebdSchin register char* cp; 100*da2e3ebdSchin int line; 101*da2e3ebdSchin Sfdisc_t tee_disc; 102*da2e3ebdSchin 103*da2e3ebdSchin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 104*da2e3ebdSchin line = -1; 105*da2e3ebdSchin while (n = optget(argv, usage)) switch (n) 106*da2e3ebdSchin { 107*da2e3ebdSchin case 'a': 108*da2e3ebdSchin oflag &= ~O_TRUNC; 109*da2e3ebdSchin oflag |= O_APPEND; 110*da2e3ebdSchin break; 111*da2e3ebdSchin case 'i': 112*da2e3ebdSchin signal(SIGINT, SIG_IGN); 113*da2e3ebdSchin break; 114*da2e3ebdSchin case 'l': 115*da2e3ebdSchin line = sfset(sfstdout, 0, 0) & SF_LINE; 116*da2e3ebdSchin if ((line == 0) == (opt_info.num == 0)) 117*da2e3ebdSchin line = -1; 118*da2e3ebdSchin else 119*da2e3ebdSchin sfset(sfstdout, SF_LINE, !!opt_info.num); 120*da2e3ebdSchin break; 121*da2e3ebdSchin case ':': 122*da2e3ebdSchin error(2, "%s", opt_info.arg); 123*da2e3ebdSchin break; 124*da2e3ebdSchin case '?': 125*da2e3ebdSchin error(ERROR_usage(2), "%s", opt_info.arg); 126*da2e3ebdSchin break; 127*da2e3ebdSchin } 128*da2e3ebdSchin if(error_info.errors) 129*da2e3ebdSchin error(ERROR_usage(2), "%s", optusage(NiL)); 130*da2e3ebdSchin argv += opt_info.index; 131*da2e3ebdSchin argc -= opt_info.index; 132*da2e3ebdSchin 133*da2e3ebdSchin /* 134*da2e3ebdSchin * for backward compatibility 135*da2e3ebdSchin */ 136*da2e3ebdSchin 137*da2e3ebdSchin if (*argv && streq(*argv, "-")) 138*da2e3ebdSchin { 139*da2e3ebdSchin signal(SIGINT, SIG_IGN); 140*da2e3ebdSchin argv++; 141*da2e3ebdSchin argc--; 142*da2e3ebdSchin } 143*da2e3ebdSchin if (argc > 0) 144*da2e3ebdSchin { 145*da2e3ebdSchin if (!(tp = (Tee_t*)stakalloc(sizeof(Tee_t) + argc * sizeof(int)))) 146*da2e3ebdSchin error(ERROR_exit(1), "no space"); 147*da2e3ebdSchin memset(&tee_disc, 0, sizeof(tee_disc)); 148*da2e3ebdSchin tee_disc.writef = tee_write; 149*da2e3ebdSchin tp->disc = tee_disc; 150*da2e3ebdSchin hp = tp->fd; 151*da2e3ebdSchin while (cp = *argv++) 152*da2e3ebdSchin { 153*da2e3ebdSchin if ((*hp = open(cp, oflag, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) 154*da2e3ebdSchin error(ERROR_system(0), "%s: cannot create", cp); 155*da2e3ebdSchin else hp++; 156*da2e3ebdSchin } 157*da2e3ebdSchin if (hp == tp->fd) 158*da2e3ebdSchin tp = 0; 159*da2e3ebdSchin else 160*da2e3ebdSchin { 161*da2e3ebdSchin *hp = -1; 162*da2e3ebdSchin sfdisc(sfstdout, &tp->disc); 163*da2e3ebdSchin } 164*da2e3ebdSchin } 165*da2e3ebdSchin if (sfmove(sfstdin, sfstdout, SF_UNBOUND, -1) < 0 || !sfeof(sfstdin) || sfsync(sfstdout)) 166*da2e3ebdSchin error(ERROR_system(1), "cannot copy"); 167*da2e3ebdSchin 168*da2e3ebdSchin /* 169*da2e3ebdSchin * close files and free resources 170*da2e3ebdSchin */ 171*da2e3ebdSchin 172*da2e3ebdSchin if (tp) 173*da2e3ebdSchin { 174*da2e3ebdSchin sfdisc(sfstdout, NiL); 175*da2e3ebdSchin if (line >= 0) 176*da2e3ebdSchin sfset(sfstdout, SF_LINE, line); 177*da2e3ebdSchin for(hp = tp->fd; (n = *hp) >= 0; hp++) 178*da2e3ebdSchin close(n); 179*da2e3ebdSchin } 180*da2e3ebdSchin return(error_info.errors); 181*da2e3ebdSchin } 182