14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1992-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * *
204887Schin ***********************************************************************/
214887Schin #pragma prototyped
224887Schin /*
234887Schin * David Korn
244887Schin * AT&T Bell Laboratories
254887Schin *
264887Schin * tee
274887Schin */
284887Schin
294887Schin static const char usage[] =
3010898Sroland.mainz@nrubsig.org "[-?\n@(#)$Id: tee (AT&T Research) 2009-06-19 $\n]"
314887Schin USAGE_LICENSE
324887Schin "[+NAME?tee - duplicate standard input]"
334887Schin "[+DESCRIPTION?\btee\b copies standard input to standard output "
344887Schin "and to zero or more files. The options determine whether "
354887Schin "the specified files are overwritten or appended to. The "
364887Schin "\btee\b utility does not buffer output. If writes to any "
374887Schin "\afile\a fail, writes to other files continue although \btee\b "
384887Schin "will exit with a non-zero exit status.]"
394887Schin "[+?The number of \afile\a operands that can be specified is limited "
404887Schin "by the underlying operating system.]"
414887Schin "[a:append?Append the standard input to the given files rather "
424887Schin "than overwriting them.]"
434887Schin "[i:ignore-interrupts?Ignore SIGINT signal.]"
444887Schin "[l:linebuffer?Set the standard output to be line buffered.]"
454887Schin "\n"
464887Schin "\n[file ...]\n"
474887Schin "\n"
484887Schin "[+EXIT STATUS?]{"
494887Schin "[+0?All files copies successfully.]"
504887Schin "[+>0?An error occurred.]"
514887Schin "}"
524887Schin "[+SEE ALSO?\bcat\b(1), \bsignal\b(3)]"
534887Schin ;
544887Schin
554887Schin #include <cmd.h>
564887Schin #include <ls.h>
574887Schin #include <sig.h>
584887Schin
594887Schin typedef struct Tee_s
604887Schin {
614887Schin Sfdisc_t disc;
6210898Sroland.mainz@nrubsig.org int line;
634887Schin int fd[1];
644887Schin } Tee_t;
654887Schin
664887Schin /*
674887Schin * This discipline writes to each file in the list given in handle
684887Schin */
694887Schin
7010898Sroland.mainz@nrubsig.org static ssize_t
tee_write(Sfio_t * fp,const void * buf,size_t n,Sfdisc_t * handle)7110898Sroland.mainz@nrubsig.org tee_write(Sfio_t* fp, const void* buf, size_t n, Sfdisc_t* handle)
724887Schin {
734887Schin register const char* bp;
744887Schin register const char* ep;
754887Schin register int* hp = ((Tee_t*)handle)->fd;
764887Schin register int fd = sffileno(fp);
774887Schin register ssize_t r;
784887Schin
794887Schin do
804887Schin {
814887Schin bp = (const char*)buf;
824887Schin ep = bp + n;
834887Schin while (bp < ep)
844887Schin {
854887Schin if ((r = write(fd, bp, ep - bp)) <= 0)
8610898Sroland.mainz@nrubsig.org return -1;
874887Schin bp += r;
884887Schin }
894887Schin } while ((fd = *hp++) >= 0);
9010898Sroland.mainz@nrubsig.org return n;
9110898Sroland.mainz@nrubsig.org }
9210898Sroland.mainz@nrubsig.org
9310898Sroland.mainz@nrubsig.org static void
tee_cleanup(register Tee_t * tp)9410898Sroland.mainz@nrubsig.org tee_cleanup(register Tee_t* tp)
9510898Sroland.mainz@nrubsig.org {
9610898Sroland.mainz@nrubsig.org register int* hp;
9710898Sroland.mainz@nrubsig.org register int n;
9810898Sroland.mainz@nrubsig.org
9910898Sroland.mainz@nrubsig.org if (tp)
10010898Sroland.mainz@nrubsig.org {
10110898Sroland.mainz@nrubsig.org sfdisc(sfstdout, NiL);
10210898Sroland.mainz@nrubsig.org if (tp->line >= 0)
10310898Sroland.mainz@nrubsig.org sfset(sfstdout, SF_LINE, tp->line);
10410898Sroland.mainz@nrubsig.org for (hp = tp->fd; (n = *hp) >= 0; hp++)
10510898Sroland.mainz@nrubsig.org close(n);
10610898Sroland.mainz@nrubsig.org }
1074887Schin }
1084887Schin
1094887Schin int
b_tee(int argc,register char ** argv,void * context)1104887Schin b_tee(int argc, register char** argv, void* context)
1114887Schin {
1124887Schin register Tee_t* tp = 0;
1134887Schin register int oflag = O_WRONLY|O_TRUNC|O_CREAT|O_BINARY;
1144887Schin register int* hp;
1154887Schin register char* cp;
1164887Schin int line;
1174887Schin
11810898Sroland.mainz@nrubsig.org if (argc <= 0)
11910898Sroland.mainz@nrubsig.org {
12010898Sroland.mainz@nrubsig.org if (context && (tp = (Tee_t*)sh_context(context)->data))
12110898Sroland.mainz@nrubsig.org {
12210898Sroland.mainz@nrubsig.org sh_context(context)->data = 0;
12310898Sroland.mainz@nrubsig.org tee_cleanup(tp);
12410898Sroland.mainz@nrubsig.org }
12510898Sroland.mainz@nrubsig.org return 0;
12610898Sroland.mainz@nrubsig.org }
12710898Sroland.mainz@nrubsig.org cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_CALLBACK);
1284887Schin line = -1;
12910898Sroland.mainz@nrubsig.org for (;;)
1304887Schin {
13110898Sroland.mainz@nrubsig.org switch (optget(argv, usage))
13210898Sroland.mainz@nrubsig.org {
13310898Sroland.mainz@nrubsig.org case 'a':
13410898Sroland.mainz@nrubsig.org oflag &= ~O_TRUNC;
13510898Sroland.mainz@nrubsig.org oflag |= O_APPEND;
13610898Sroland.mainz@nrubsig.org continue;
13710898Sroland.mainz@nrubsig.org case 'i':
13810898Sroland.mainz@nrubsig.org signal(SIGINT, SIG_IGN);
13910898Sroland.mainz@nrubsig.org continue;
14010898Sroland.mainz@nrubsig.org case 'l':
14110898Sroland.mainz@nrubsig.org line = sfset(sfstdout, 0, 0) & SF_LINE;
14210898Sroland.mainz@nrubsig.org if ((line == 0) == (opt_info.num == 0))
14310898Sroland.mainz@nrubsig.org line = -1;
14410898Sroland.mainz@nrubsig.org else
14510898Sroland.mainz@nrubsig.org sfset(sfstdout, SF_LINE, !!opt_info.num);
14610898Sroland.mainz@nrubsig.org continue;
14710898Sroland.mainz@nrubsig.org case ':':
14810898Sroland.mainz@nrubsig.org error(2, "%s", opt_info.arg);
14910898Sroland.mainz@nrubsig.org break;
15010898Sroland.mainz@nrubsig.org case '?':
15110898Sroland.mainz@nrubsig.org error(ERROR_usage(2), "%s", opt_info.arg);
15210898Sroland.mainz@nrubsig.org break;
15310898Sroland.mainz@nrubsig.org }
1544887Schin break;
1554887Schin }
15610898Sroland.mainz@nrubsig.org if (error_info.errors)
1574887Schin error(ERROR_usage(2), "%s", optusage(NiL));
1584887Schin argv += opt_info.index;
1594887Schin argc -= opt_info.index;
1608462SApril.Chin@Sun.COM #if _ANCIENT_BSD_COMPATIBILITY
1614887Schin if (*argv && streq(*argv, "-"))
1624887Schin {
1634887Schin signal(SIGINT, SIG_IGN);
1644887Schin argv++;
1654887Schin argc--;
1664887Schin }
1678462SApril.Chin@Sun.COM #endif
1684887Schin if (argc > 0)
1694887Schin {
17010898Sroland.mainz@nrubsig.org if (tp = (Tee_t*)stakalloc(sizeof(Tee_t) + argc * sizeof(int)))
1714887Schin {
17210898Sroland.mainz@nrubsig.org memset(&tp->disc, 0, sizeof(tp->disc));
17310898Sroland.mainz@nrubsig.org tp->disc.writef = tee_write;
17410898Sroland.mainz@nrubsig.org if (context)
17510898Sroland.mainz@nrubsig.org sh_context(context)->data = (void*)tp;
17610898Sroland.mainz@nrubsig.org tp->line = line;
17710898Sroland.mainz@nrubsig.org hp = tp->fd;
17810898Sroland.mainz@nrubsig.org while (cp = *argv++)
17910898Sroland.mainz@nrubsig.org {
18010898Sroland.mainz@nrubsig.org if ((*hp = open(cp, oflag, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
18110898Sroland.mainz@nrubsig.org error(ERROR_system(0), "%s: cannot create", cp);
18210898Sroland.mainz@nrubsig.org else
18310898Sroland.mainz@nrubsig.org hp++;
18410898Sroland.mainz@nrubsig.org }
18510898Sroland.mainz@nrubsig.org if (hp == tp->fd)
18610898Sroland.mainz@nrubsig.org tp = 0;
18710898Sroland.mainz@nrubsig.org else
18810898Sroland.mainz@nrubsig.org {
18910898Sroland.mainz@nrubsig.org *hp = -1;
19010898Sroland.mainz@nrubsig.org sfdisc(sfstdout, &tp->disc);
19110898Sroland.mainz@nrubsig.org }
1924887Schin }
19310898Sroland.mainz@nrubsig.org else
19410898Sroland.mainz@nrubsig.org error(ERROR_exit(0), "out of space");
1954887Schin }
19610898Sroland.mainz@nrubsig.org if ((sfmove(sfstdin, sfstdout, SF_UNBOUND, -1) < 0 || !sfeof(sfstdin)) && errno != EPIPE)
19710898Sroland.mainz@nrubsig.org error(ERROR_system(0), "read error");
19810898Sroland.mainz@nrubsig.org if (sfsync(sfstdout))
19910898Sroland.mainz@nrubsig.org error(ERROR_system(0), "write error");
20010898Sroland.mainz@nrubsig.org tee_cleanup(tp);
20110898Sroland.mainz@nrubsig.org return error_info.errors;
2024887Schin }
203