Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcmd/tee.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1992-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
/*
23
* David Korn
24
* AT&T Bell Laboratories
25
*
26
* tee
27
*/
28
29
static const char usage[] =
30
"[-?\n@(#)$Id: tee (AT&T Research) 2012-05-31 $\n]"
31
USAGE_LICENSE
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.]"
45
"\n"
46
"\n[file ...]\n"
47
"\n"
48
"[+EXIT STATUS?]{"
49
"[+0?All files copies successfully.]"
50
"[+>0?An error occurred.]"
51
"}"
52
"[+SEE ALSO?\bcat\b(1), \bsignal\b(3)]"
53
;
54
55
#include <cmd.h>
56
#include <ls.h>
57
#include <sig.h>
58
59
typedef struct Tee_s
60
{
61
Sfdisc_t disc;
62
int line;
63
int fd[1];
64
} Tee_t;
65
66
/*
67
* This discipline writes to each file in the list given in handle
68
*/
69
70
static ssize_t
71
tee_write(Sfio_t* fp, const void* buf, size_t n, Sfdisc_t* handle)
72
{
73
register const char* bp;
74
register const char* ep;
75
register int* hp = ((Tee_t*)handle)->fd;
76
register int fd = sffileno(fp);
77
register ssize_t r;
78
79
do
80
{
81
bp = (const char*)buf;
82
ep = bp + n;
83
while (bp < ep)
84
{
85
if ((r = write(fd, bp, ep - bp)) <= 0)
86
return -1;
87
bp += r;
88
}
89
} while ((fd = *hp++) >= 0);
90
return n;
91
}
92
93
static void
94
tee_cleanup(register Tee_t* tp)
95
{
96
register int* hp;
97
register int n;
98
99
if (tp)
100
{
101
sfdisc(sfstdout, NiL);
102
if (tp->line >= 0)
103
sfset(sfstdout, SF_LINE, tp->line);
104
for (hp = tp->fd; (n = *hp) >= 0; hp++)
105
close(n);
106
}
107
}
108
109
int
110
b_tee(int argc, register char** argv, Shbltin_t* context)
111
{
112
register Tee_t* tp = 0;
113
register int oflag = O_WRONLY|O_TRUNC|O_CREAT|O_BINARY|O_cloexec;
114
register int* hp;
115
register char* cp;
116
int line;
117
118
if (argc <= 0)
119
{
120
if (context && (tp = (Tee_t*)sh_context(context)->data))
121
{
122
sh_context(context)->data = 0;
123
tee_cleanup(tp);
124
}
125
return 0;
126
}
127
cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_CALLBACK);
128
line = -1;
129
for (;;)
130
{
131
switch (optget(argv, usage))
132
{
133
case 'a':
134
oflag &= ~O_TRUNC;
135
oflag |= O_APPEND;
136
continue;
137
case 'i':
138
signal(SIGINT, SIG_IGN);
139
continue;
140
case 'l':
141
line = sfset(sfstdout, 0, 0) & SF_LINE;
142
if ((line == 0) == (opt_info.num == 0))
143
line = -1;
144
else
145
sfset(sfstdout, SF_LINE, !!opt_info.num);
146
continue;
147
case ':':
148
error(2, "%s", opt_info.arg);
149
break;
150
case '?':
151
error(ERROR_usage(2), "%s", opt_info.arg);
152
break;
153
}
154
break;
155
}
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, "-"))
162
{
163
signal(SIGINT, SIG_IGN);
164
argv++;
165
argc--;
166
}
167
#endif
168
if (argc > 0)
169
{
170
if (tp = (Tee_t*)stakalloc(sizeof(Tee_t) + argc * sizeof(int)))
171
{
172
memset(&tp->disc, 0, sizeof(tp->disc));
173
tp->disc.writef = tee_write;
174
if (context)
175
sh_context(context)->data = (void*)tp;
176
tp->line = line;
177
hp = tp->fd;
178
while (cp = *argv++)
179
{
180
while ((*hp = open(cp, oflag, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0 && errno == EINTR)
181
errno = 0;
182
if (*hp < 0)
183
error(ERROR_system(0), "%s: cannot create", cp);
184
else
185
hp++;
186
}
187
if (hp == tp->fd)
188
tp = 0;
189
else
190
{
191
*hp = -1;
192
sfdisc(sfstdout, &tp->disc);
193
}
194
}
195
else
196
error(ERROR_exit(0), "out of space");
197
}
198
if ((sfmove(sfstdin, sfstdout, SF_UNBOUND, -1) < 0 || !sfeof(sfstdin)) && !ERROR_PIPE(errno) && errno != EINTR)
199
error(ERROR_system(0), "read error");
200
if (sfsync(sfstdout))
201
error(ERROR_system(0), "write error");
202
tee_cleanup(tp);
203
return error_info.errors;
204
}
205
206