da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1992-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* http://www.opensource.org/licenses/cpl1.0.txt *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Glenn Fowler <gsf@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#pragma prototyped
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * David Korn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * AT&T Bell Laboratories
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * tee
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const char usage[] =
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz"[-?\n@(#)$Id: tee (AT&T Research) 2009-06-19 $\n]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinUSAGE_LICENSE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"[+NAME?tee - duplicate standard input]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"[+DESCRIPTION?\btee\b copies standard input to standard output "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "and to zero or more files. The options determine whether "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "the specified files are overwritten or appended to. The "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "\btee\b utility does not buffer output. If writes to any "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "\afile\a fail, writes to other files continue although \btee\b "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "will exit with a non-zero exit status.]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"[+?The number of \afile\a operands that can be specified is limited "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "by the underlying operating system.]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"[a:append?Append the standard input to the given files rather "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "than overwriting them.]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"[i:ignore-interrupts?Ignore SIGINT signal.]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"[l:linebuffer?Set the standard output to be line buffered.]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"\n"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"\n[file ...]\n"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"\n"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"[+EXIT STATUS?]{"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "[+0?All files copies successfully.]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "[+>0?An error occurred.]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"}"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin"[+SEE ALSO?\bcat\b(1), \bsignal\b(3)]"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <cmd.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <ls.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sig.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chintypedef struct Tee_s
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Sfdisc_t disc;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz int line;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int fd[1];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin} Tee_t;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This discipline writes to each file in the list given in handle
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzstatic ssize_t
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainztee_write(Sfio_t* fp, const void* buf, size_t n, Sfdisc_t* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register const char* bp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register const char* ep;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int* hp = ((Tee_t*)handle)->fd;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int fd = sffileno(fp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register ssize_t r;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin do
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bp = (const char*)buf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ep = bp + n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (bp < ep)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((r = write(fd, bp, ep - bp)) <= 0)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bp += r;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } while ((fd = *hp++) >= 0);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz return n;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzstatic void
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainztee_cleanup(register Tee_t* tp)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz{
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz register int* hp;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz register int n;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (tp)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sfdisc(sfstdout, NiL);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (tp->line >= 0)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sfset(sfstdout, SF_LINE, tp->line);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz for (hp = tp->fd; (n = *hp) >= 0; hp++)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz close(n);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinb_tee(int argc, register char** argv, void* context)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register Tee_t* tp = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int oflag = O_WRONLY|O_TRUNC|O_CREAT|O_BINARY;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int* hp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int line;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (argc <= 0)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (context && (tp = (Tee_t*)sh_context(context)->data))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sh_context(context)->data = 0;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz tee_cleanup(tp);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz return 0;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_CALLBACK);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin line = -1;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz for (;;)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz switch (optget(argv, usage))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz case 'a':
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz oflag &= ~O_TRUNC;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz oflag |= O_APPEND;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz continue;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz case 'i':
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz signal(SIGINT, SIG_IGN);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz continue;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz case 'l':
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz line = sfset(sfstdout, 0, 0) & SF_LINE;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if ((line == 0) == (opt_info.num == 0))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz line = -1;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sfset(sfstdout, SF_LINE, !!opt_info.num);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz continue;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz case ':':
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz error(2, "%s", opt_info.arg);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz break;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz case '?':
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz error(ERROR_usage(2), "%s", opt_info.arg);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz break;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (error_info.errors)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(ERROR_usage(2), "%s", optusage(NiL));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin argv += opt_info.index;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin argc -= opt_info.index;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#if _ANCIENT_BSD_COMPATIBILITY
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*argv && streq(*argv, "-"))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin signal(SIGINT, SIG_IGN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin argv++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin argc--;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (argc > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (tp = (Tee_t*)stakalloc(sizeof(Tee_t) + argc * sizeof(int)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz memset(&tp->disc, 0, sizeof(tp->disc));
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz tp->disc.writef = tee_write;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (context)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sh_context(context)->data = (void*)tp;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz tp->line = line;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz hp = tp->fd;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz while (cp = *argv++)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if ((*hp = open(cp, oflag, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz error(ERROR_system(0), "%s: cannot create", cp);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz hp++;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (hp == tp->fd)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz tp = 0;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz {
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz *hp = -1;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sfdisc(sfstdout, &tp->disc);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz error(ERROR_exit(0), "out of space");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if ((sfmove(sfstdin, sfstdout, SF_UNBOUND, -1) < 0 || !sfeof(sfstdin)) && errno != EPIPE)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz error(ERROR_system(0), "read error");
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if (sfsync(sfstdout))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz error(ERROR_system(0), "write error");
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz tee_cleanup(tp);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz return error_info.errors;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}