1 /* tee - read from standard input and write to standard output and files.
2 Copyright (C) 1985-2023 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 /* Mike Parker, Richard M. Stallman, and David MacKenzie */
18
19 #include <config.h>
20 #include <sys/types.h>
21 #include <signal.h>
22 #include <getopt.h>
23
24 #include "system.h"
25 #include "argmatch.h"
26 #include "fadvise.h"
27 #include "iopoll.h"
28 #include "stdio--.h"
29 #include "xbinary-io.h"
30 #include "iopoll.h"
31
32 /* The official name of this program (e.g., no 'g' prefix). */
33 #define PROGRAM_NAME "tee"
34
35 #define AUTHORS \
36 proper_name ("Mike Parker"), \
37 proper_name ("Richard M. Stallman"), \
38 proper_name ("David MacKenzie")
39
40 static bool tee_files (int nfiles, char **files, bool);
41
42 /* If true, append to output files rather than truncating them. */
43 static bool append;
44
45 /* If true, ignore interrupts. */
46 static bool ignore_interrupts;
47
48 enum output_error
49 {
50 output_error_sigpipe, /* traditional behavior, sigpipe enabled. */
51 output_error_warn, /* warn on EPIPE, but continue. */
52 output_error_warn_nopipe, /* ignore EPIPE, continue. */
53 output_error_exit, /* exit on any output error. */
54 output_error_exit_nopipe /* exit on any output error except EPIPE. */
55 };
56
57 static enum output_error output_error;
58
59 static struct option const long_options[] =
60 {
61 {"append", no_argument, nullptr, 'a'},
62 {"ignore-interrupts", no_argument, nullptr, 'i'},
63 {"output-error", optional_argument, nullptr, 'p'},
64 {GETOPT_HELP_OPTION_DECL},
65 {GETOPT_VERSION_OPTION_DECL},
66 {nullptr, 0, nullptr, 0}
67 };
68
69 static char const *const output_error_args[] =
70 {
71 "warn", "warn-nopipe", "exit", "exit-nopipe", nullptr
72 };
73 static enum output_error const output_error_types[] =
74 {
75 output_error_warn, output_error_warn_nopipe,
76 output_error_exit, output_error_exit_nopipe
77 };
78 ARGMATCH_VERIFY (output_error_args, output_error_types);
79
80 void
usage(int status)81 usage (int status)
82 {
83 if (status != EXIT_SUCCESS)
84 emit_try_help ();
85 else
86 {
87 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
88 fputs (_("\
89 Copy standard input to each FILE, and also to standard output.\n\
90 \n\
91 -a, --append append to the given FILEs, do not overwrite\n\
92 -i, --ignore-interrupts ignore interrupt signals\n\
93 "), stdout);
94 fputs (_("\
95 -p operate in a more appropriate MODE with pipes.\n\
96 --output-error[=MODE] set behavior on write error. See MODE below\n\
97 "), stdout);
98 fputs (HELP_OPTION_DESCRIPTION, stdout);
99 fputs (VERSION_OPTION_DESCRIPTION, stdout);
100 fputs (_("\
101 \n\
102 MODE determines behavior with write errors on the outputs:\n\
103 warn diagnose errors writing to any output\n\
104 warn-nopipe diagnose errors writing to any output not a pipe\n\
105 exit exit on error writing to any output\n\
106 exit-nopipe exit on error writing to any output not a pipe\n\
107 The default MODE for the -p option is 'warn-nopipe'.\n\
108 With \"nopipe\" MODEs, exit immediately if all outputs become broken pipes.\n\
109 The default operation when --output-error is not specified, is to\n\
110 exit immediately on error writing to a pipe, and diagnose errors\n\
111 writing to non pipe outputs.\n\
112 "), stdout);
113 emit_ancillary_info (PROGRAM_NAME);
114 }
115 exit (status);
116 }
117
118 int
main(int argc,char ** argv)119 main (int argc, char **argv)
120 {
121 initialize_main (&argc, &argv);
122 set_program_name (argv[0]);
123 setlocale (LC_ALL, "");
124 bindtextdomain (PACKAGE, LOCALEDIR);
125 textdomain (PACKAGE);
126
127 atexit (close_stdout);
128
129 append = false;
130 ignore_interrupts = false;
131
132 int optc;
133 while ((optc = getopt_long (argc, argv, "aip", long_options, nullptr)) != -1)
134 {
135 switch (optc)
136 {
137 case 'a':
138 append = true;
139 break;
140
141 case 'i':
142 ignore_interrupts = true;
143 break;
144
145 case 'p':
146 if (optarg)
147 output_error = XARGMATCH ("--output-error", optarg,
148 output_error_args, output_error_types);
149 else
150 output_error = output_error_warn_nopipe;
151 break;
152
153 case_GETOPT_HELP_CHAR;
154
155 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
156
157 default:
158 usage (EXIT_FAILURE);
159 }
160 }
161
162 if (ignore_interrupts)
163 signal (SIGINT, SIG_IGN);
164
165 if (output_error != output_error_sigpipe)
166 signal (SIGPIPE, SIG_IGN);
167
168 /* Whether to detect and close a broken pipe output.
169 There is no need if the input is always ready for reading. */
170 bool pipe_check = ((output_error == output_error_warn_nopipe
171 || output_error == output_error_exit_nopipe)
172 && iopoll_input_ok (STDIN_FILENO));
173
174 /* Do *not* warn if tee is given no file arguments.
175 POSIX requires that it work when given no arguments. */
176
177 bool ok = tee_files (argc - optind, &argv[optind], pipe_check);
178 if (close (STDIN_FILENO) != 0)
179 error (EXIT_FAILURE, errno, "%s", _("standard input"));
180
181 return ok ? EXIT_SUCCESS : EXIT_FAILURE;
182 }
183
184
185 /* Return the index of the first non-null descriptor after idx,
186 or -1 if all are null. */
187
188 static int
get_next_out(FILE ** descriptors,int nfiles,int idx)189 get_next_out (FILE **descriptors, int nfiles, int idx)
190 {
191 for (idx++; idx <= nfiles; idx++)
192 if (descriptors[idx])
193 return idx;
194 return -1; /* no outputs remaining */
195 }
196
197 /* Remove descriptors[i] due to write failure or broken pipe.
198 Return true if this indicates a reportable error. */
199
200 static bool
fail_output(FILE ** descriptors,char ** files,int i)201 fail_output (FILE **descriptors, char **files, int i)
202 {
203 int w_errno = errno;
204 bool fail = errno != EPIPE
205 || output_error == output_error_exit
206 || output_error == output_error_warn;
207 if (descriptors[i] == stdout)
208 clearerr (stdout); /* Avoid redundant close_stdout diagnostic. */
209 if (fail)
210 {
211 error (output_error == output_error_exit
212 || output_error == output_error_exit_nopipe,
213 w_errno, "%s", quotef (files[i]));
214 }
215 descriptors[i] = nullptr;
216 return fail;
217 }
218
219
220 /* Copy the standard input into each of the NFILES files in FILES
221 and into the standard output. As a side effect, modify FILES[-1].
222 Return true if successful. */
223
224 static bool
tee_files(int nfiles,char ** files,bool pipe_check)225 tee_files (int nfiles, char **files, bool pipe_check)
226 {
227 size_t n_outputs = 0;
228 FILE **descriptors;
229 bool *out_pollable IF_LINT ( = nullptr);
230 char buffer[BUFSIZ];
231 ssize_t bytes_read = 0;
232 int i;
233 int first_out = 0; /* idx of first non-null output in descriptors */
234 bool ok = true;
235 char const *mode_string =
236 (O_BINARY
237 ? (append ? "ab" : "wb")
238 : (append ? "a" : "w"));
239
240 xset_binary_mode (STDIN_FILENO, O_BINARY);
241 xset_binary_mode (STDOUT_FILENO, O_BINARY);
242 fadvise (stdin, FADVISE_SEQUENTIAL);
243
244 /* Set up FILES[0 .. NFILES] and DESCRIPTORS[0 .. NFILES].
245 In both arrays, entry 0 corresponds to standard output. */
246
247 descriptors = xnmalloc (nfiles + 1, sizeof *descriptors);
248 if (pipe_check)
249 out_pollable = xnmalloc (nfiles + 1, sizeof *out_pollable);
250 files--;
251 descriptors[0] = stdout;
252 if (pipe_check)
253 out_pollable[0] = iopoll_output_ok (fileno (descriptors[0]));
254 files[0] = bad_cast (_("standard output"));
255 setvbuf (stdout, nullptr, _IONBF, 0);
256 n_outputs++;
257
258 for (i = 1; i <= nfiles; i++)
259 {
260 /* Do not treat "-" specially - as mandated by POSIX. */
261 descriptors[i] = fopen (files[i], mode_string);
262 if (descriptors[i] == nullptr)
263 {
264 if (pipe_check)
265 out_pollable[i] = false;
266 error (output_error == output_error_exit
267 || output_error == output_error_exit_nopipe,
268 errno, "%s", quotef (files[i]));
269 ok = false;
270 }
271 else
272 {
273 if (pipe_check)
274 out_pollable[i] = iopoll_output_ok (fileno (descriptors[i]));
275 setvbuf (descriptors[i], nullptr, _IONBF, 0);
276 n_outputs++;
277 }
278 }
279
280 while (n_outputs)
281 {
282 if (pipe_check && out_pollable[first_out])
283 {
284 /* Monitor for input, or errors on first valid output. */
285 int err = iopoll (STDIN_FILENO, fileno (descriptors[first_out]),
286 true);
287
288 /* Close the output if it became a broken pipe. */
289 if (err == IOPOLL_BROKEN_OUTPUT)
290 {
291 errno = EPIPE; /* behave like write produced EPIPE */
292 if (fail_output (descriptors, files, first_out))
293 ok = false;
294 n_outputs--;
295 first_out = get_next_out (descriptors, nfiles, first_out);
296 continue;
297 }
298 else if (err == IOPOLL_ERROR)
299 {
300 error (0, errno, _("iopoll error"));
301 ok = false;
302 }
303 }
304
305 bytes_read = read (STDIN_FILENO, buffer, sizeof buffer);
306 if (bytes_read < 0 && errno == EINTR)
307 continue;
308 if (bytes_read <= 0)
309 break;
310
311 /* Write to all NFILES + 1 descriptors.
312 Standard output is the first one. */
313 for (i = 0; i <= nfiles; i++)
314 if (descriptors[i]
315 && ! fwrite_wait (buffer, bytes_read, descriptors[i]))
316 {
317 if (fail_output (descriptors, files, i))
318 ok = false;
319 n_outputs--;
320 if (i == first_out)
321 first_out = get_next_out (descriptors, nfiles, first_out);
322 }
323 }
324
325 if (bytes_read == -1)
326 {
327 error (0, errno, _("read error"));
328 ok = false;
329 }
330
331 /* Close the files, but not standard output. */
332 for (i = 1; i <= nfiles; i++)
333 if (descriptors[i] && ! fclose_wait (descriptors[i]))
334 {
335 error (0, errno, "%s", quotef (files[i]));
336 ok = false;
337 }
338
339 free (descriptors);
340 if (pipe_check)
341 free (out_pollable);
342
343 return ok;
344 }
345