xref: /onnv-gate/usr/src/lib/libcmd/common/tee.c (revision 12068:08a39a083754)
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