1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1992-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
20 ***********************************************************************/
24 * AT&T Bell Laboratories
29 static const char usage
[] =
30 "[-?\n@(#)$Id: tee (AT&T Research) 2009-06-19 $\n]"
32 "[+NAME?tee - duplicate standard input]"
33 "[+DESCRIPTION?\btee\b copies standard input to standard output "
34 "and to zero or more files. The options determine whether "
35 "the specified files are overwritten or appended to. The "
36 "\btee\b utility does not buffer output. If writes to any "
37 "\afile\a fail, writes to other files continue although \btee\b "
38 "will exit with a non-zero exit status.]"
39 "[+?The number of \afile\a operands that can be specified is limited "
40 "by the underlying operating system.]"
41 "[a:append?Append the standard input to the given files rather "
42 "than overwriting them.]"
43 "[i:ignore-interrupts?Ignore SIGINT signal.]"
44 "[l:linebuffer?Set the standard output to be line buffered.]"
49 "[+0?All files copies successfully.]"
50 "[+>0?An error occurred.]"
52 "[+SEE ALSO?\bcat\b(1), \bsignal\b(3)]"
67 * This discipline writes to each file in the list given in handle
71 tee_write(Sfio_t
* fp
, const void* buf
, size_t n
, Sfdisc_t
* handle
)
73 register const char* bp
;
74 register const char* ep
;
75 register int* hp
= ((Tee_t
*)handle
)->fd
;
76 register int fd
= sffileno(fp
);
81 bp
= (const char*)buf
;
85 if ((r
= write(fd
, bp
, ep
- bp
)) <= 0)
89 } while ((fd
= *hp
++) >= 0);
94 tee_cleanup(register Tee_t
* tp
)
101 sfdisc(sfstdout
, NiL
);
103 sfset(sfstdout
, SF_LINE
, tp
->line
);
104 for (hp
= tp
->fd
; (n
= *hp
) >= 0; hp
++)
110 b_tee(int argc
, register char** argv
, void* context
)
112 register Tee_t
* tp
= 0;
113 register int oflag
= O_WRONLY
|O_TRUNC
|O_CREAT
|O_BINARY
;
120 if (context
&& (tp
= (Tee_t
*)sh_context(context
)->data
))
122 sh_context(context
)->data
= 0;
127 cmdinit(argc
, argv
, context
, ERROR_CATALOG
, ERROR_CALLBACK
);
131 switch (optget(argv
, usage
))
138 signal(SIGINT
, SIG_IGN
);
141 line
= sfset(sfstdout
, 0, 0) & SF_LINE
;
142 if ((line
== 0) == (opt_info
.num
== 0))
145 sfset(sfstdout
, SF_LINE
, !!opt_info
.num
);
148 error(2, "%s", opt_info
.arg
);
151 error(ERROR_usage(2), "%s", opt_info
.arg
);
156 if (error_info
.errors
)
157 error(ERROR_usage(2), "%s", optusage(NiL
));
158 argv
+= opt_info
.index
;
159 argc
-= opt_info
.index
;
160 #if _ANCIENT_BSD_COMPATIBILITY
161 if (*argv
&& streq(*argv
, "-"))
163 signal(SIGINT
, SIG_IGN
);
170 if (tp
= (Tee_t
*)stakalloc(sizeof(Tee_t
) + argc
* sizeof(int)))
172 memset(&tp
->disc
, 0, sizeof(tp
->disc
));
173 tp
->disc
.writef
= tee_write
;
175 sh_context(context
)->data
= (void*)tp
;
180 if ((*hp
= open(cp
, oflag
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
)) < 0)
181 error(ERROR_system(0), "%s: cannot create", cp
);
190 sfdisc(sfstdout
, &tp
->disc
);
194 error(ERROR_exit(0), "out of space");
196 if ((sfmove(sfstdin
, sfstdout
, SF_UNBOUND
, -1) < 0 || !sfeof(sfstdin
)) && errno
!= EPIPE
)
197 error(ERROR_system(0), "read error");
198 if (sfsync(sfstdout
))
199 error(ERROR_system(0), "write error");
201 return error_info
.errors
;