shuf: tiny simplification
[coreutils.git] / src / tee.c
blobeb074427cb4afd975e14f30a5d53d8eb84c0fcb1
1 /* tee - read from standard input and write to standard output and files.
2 Copyright (C) 1985-2024 Free Software Foundation, Inc.
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.
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.
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/>. */
17 /* Mike Parker, Richard M. Stallman, and David MacKenzie */
19 #include <config.h>
20 #include <sys/types.h>
21 #include <signal.h>
22 #include <getopt.h>
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"
32 /* The official name of this program (e.g., no 'g' prefix). */
33 #define PROGRAM_NAME "tee"
35 #define AUTHORS \
36 proper_name ("Mike Parker"), \
37 proper_name ("Richard M. Stallman"), \
38 proper_name ("David MacKenzie")
40 static bool tee_files (int nfiles, char **files, bool);
42 /* If true, append to output files rather than truncating them. */
43 static bool append;
45 /* If true, ignore interrupts. */
46 static bool ignore_interrupts;
48 enum output_error
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. */
57 static enum output_error output_error;
59 static struct option const long_options[] =
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}
69 static char const *const output_error_args[] =
71 "warn", "warn-nopipe", "exit", "exit-nopipe", nullptr
73 static enum output_error const output_error_types[] =
75 output_error_warn, output_error_warn_nopipe,
76 output_error_exit, output_error_exit_nopipe
78 ARGMATCH_VERIFY (output_error_args, output_error_types);
80 void
81 usage (int status)
83 if (status != EXIT_SUCCESS)
84 emit_try_help ();
85 else
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 (_("\
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);
115 exit (status);
119 main (int argc, char **argv)
121 initialize_main (&argc, &argv);
122 set_program_name (argv[0]);
123 setlocale (LC_ALL, "");
124 bindtextdomain (PACKAGE, LOCALEDIR);
125 textdomain (PACKAGE);
127 atexit (close_stdout);
129 append = false;
130 ignore_interrupts = false;
132 int optc;
133 while ((optc = getopt_long (argc, argv, "aip", long_options, nullptr)) != -1)
135 switch (optc)
137 case 'a':
138 append = true;
139 break;
141 case 'i':
142 ignore_interrupts = true;
143 break;
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;
153 case_GETOPT_HELP_CHAR;
155 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
157 default:
158 usage (EXIT_FAILURE);
162 if (ignore_interrupts)
163 signal (SIGINT, SIG_IGN);
165 if (output_error != output_error_sigpipe)
166 signal (SIGPIPE, SIG_IGN);
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));
174 /* Do *not* warn if tee is given no file arguments.
175 POSIX requires that it work when given no arguments. */
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"));
181 return ok ? EXIT_SUCCESS : EXIT_FAILURE;
185 /* Return the index of the first non-null descriptor after idx,
186 or -1 if all are null. */
188 ATTRIBUTE_PURE
189 static int
190 get_next_out (FILE **descriptors, int nfiles, int idx)
192 for (idx++; idx <= nfiles; idx++)
193 if (descriptors[idx])
194 return idx;
195 return -1; /* no outputs remaining */
198 /* Remove descriptors[i] due to write failure or broken pipe.
199 Return true if this indicates a reportable error. */
201 static bool
202 fail_output (FILE **descriptors, char **files, int i)
204 int w_errno = errno;
205 bool fail = errno != EPIPE
206 || output_error == output_error_exit
207 || output_error == output_error_warn;
208 if (descriptors[i] == stdout)
209 clearerr (stdout); /* Avoid redundant close_stdout diagnostic. */
210 if (fail)
212 error (output_error == output_error_exit
213 || output_error == output_error_exit_nopipe,
214 w_errno, "%s", quotef (files[i]));
216 descriptors[i] = nullptr;
217 return fail;
221 /* Copy the standard input into each of the NFILES files in FILES
222 and into the standard output. As a side effect, modify FILES[-1].
223 Return true if successful. */
225 static bool
226 tee_files (int nfiles, char **files, bool pipe_check)
228 size_t n_outputs = 0;
229 FILE **descriptors;
230 bool *out_pollable IF_LINT ( = nullptr);
231 char buffer[BUFSIZ];
232 ssize_t bytes_read = 0;
233 int i;
234 int first_out = 0; /* idx of first non-null output in descriptors */
235 bool ok = true;
236 char const *mode_string =
237 (O_BINARY
238 ? (append ? "ab" : "wb")
239 : (append ? "a" : "w"));
241 xset_binary_mode (STDIN_FILENO, O_BINARY);
242 xset_binary_mode (STDOUT_FILENO, O_BINARY);
243 fadvise (stdin, FADVISE_SEQUENTIAL);
245 /* Set up FILES[0 .. NFILES] and DESCRIPTORS[0 .. NFILES].
246 In both arrays, entry 0 corresponds to standard output. */
248 descriptors = xnmalloc (nfiles + 1, sizeof *descriptors);
249 if (pipe_check)
250 out_pollable = xnmalloc (nfiles + 1, sizeof *out_pollable);
251 files--;
252 descriptors[0] = stdout;
253 if (pipe_check)
254 out_pollable[0] = iopoll_output_ok (fileno (descriptors[0]));
255 files[0] = bad_cast (_("standard output"));
256 setvbuf (stdout, nullptr, _IONBF, 0);
257 n_outputs++;
259 for (i = 1; i <= nfiles; i++)
261 /* Do not treat "-" specially - as mandated by POSIX. */
262 descriptors[i] = fopen (files[i], mode_string);
263 if (descriptors[i] == nullptr)
265 if (pipe_check)
266 out_pollable[i] = false;
267 error (output_error == output_error_exit
268 || output_error == output_error_exit_nopipe,
269 errno, "%s", quotef (files[i]));
270 ok = false;
272 else
274 if (pipe_check)
275 out_pollable[i] = iopoll_output_ok (fileno (descriptors[i]));
276 setvbuf (descriptors[i], nullptr, _IONBF, 0);
277 n_outputs++;
281 while (n_outputs)
283 if (pipe_check && out_pollable[first_out])
285 /* Monitor for input, or errors on first valid output. */
286 int err = iopoll (STDIN_FILENO, fileno (descriptors[first_out]),
287 true);
289 /* Close the output if it became a broken pipe. */
290 if (err == IOPOLL_BROKEN_OUTPUT)
292 errno = EPIPE; /* behave like write produced EPIPE */
293 if (fail_output (descriptors, files, first_out))
294 ok = false;
295 n_outputs--;
296 first_out = get_next_out (descriptors, nfiles, first_out);
297 continue;
299 else if (err == IOPOLL_ERROR)
301 error (0, errno, _("iopoll error"));
302 ok = false;
306 bytes_read = read (STDIN_FILENO, buffer, sizeof buffer);
307 if (bytes_read < 0 && errno == EINTR)
308 continue;
309 if (bytes_read <= 0)
310 break;
312 /* Write to all NFILES + 1 descriptors.
313 Standard output is the first one. */
314 for (i = 0; i <= nfiles; i++)
315 if (descriptors[i]
316 && ! fwrite_wait (buffer, bytes_read, descriptors[i]))
318 if (fail_output (descriptors, files, i))
319 ok = false;
320 n_outputs--;
321 if (i == first_out)
322 first_out = get_next_out (descriptors, nfiles, first_out);
326 if (bytes_read == -1)
328 error (0, errno, _("read error"));
329 ok = false;
332 /* Close the files, but not standard output. */
333 for (i = 1; i <= nfiles; i++)
334 if (descriptors[i] && ! fclose_wait (descriptors[i]))
336 error (0, errno, "%s", quotef (files[i]));
337 ok = false;
340 free (descriptors);
341 if (pipe_check)
342 free (out_pollable);
344 return ok;