1 /* tee - read from standard input and write to standard output and files.
2 Copyright (C) 1985-2023 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 */
20 #include <sys/types.h>
30 #include "xbinary-io.h"
33 /* The official name of this program (e.g., no 'g' prefix). */
34 #define PROGRAM_NAME "tee"
37 proper_name ("Mike Parker"), \
38 proper_name ("Richard M. Stallman"), \
39 proper_name ("David MacKenzie")
41 static bool tee_files (int nfiles
, char **files
, bool);
43 /* If true, append to output files rather than truncating them. */
46 /* If true, ignore interrupts. */
47 static bool ignore_interrupts
;
51 output_error_sigpipe
, /* traditional behavior, sigpipe enabled. */
52 output_error_warn
, /* warn on EPIPE, but continue. */
53 output_error_warn_nopipe
, /* ignore EPIPE, continue. */
54 output_error_exit
, /* exit on any output error. */
55 output_error_exit_nopipe
/* exit on any output error except EPIPE. */
58 static enum output_error output_error
;
60 static struct option
const long_options
[] =
62 {"append", no_argument
, NULL
, 'a'},
63 {"ignore-interrupts", no_argument
, NULL
, 'i'},
64 {"output-error", optional_argument
, NULL
, 'p'},
65 {GETOPT_HELP_OPTION_DECL
},
66 {GETOPT_VERSION_OPTION_DECL
},
70 static char const *const output_error_args
[] =
72 "warn", "warn-nopipe", "exit", "exit-nopipe", NULL
74 static enum output_error
const output_error_types
[] =
76 output_error_warn
, output_error_warn_nopipe
,
77 output_error_exit
, output_error_exit_nopipe
79 ARGMATCH_VERIFY (output_error_args
, output_error_types
);
84 if (status
!= EXIT_SUCCESS
)
88 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
90 Copy standard input to each FILE, and also to standard output.\n\
92 -a, --append append to the given FILEs, do not overwrite\n\
93 -i, --ignore-interrupts ignore interrupt signals\n\
96 -p operate in a more appropriate MODE with pipes.\n\
97 --output-error[=MODE] set behavior on write error. See MODE below\n\
99 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
100 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
103 MODE determines behavior with write errors on the outputs:\n\
104 warn diagnose errors writing to any output\n\
105 warn-nopipe diagnose errors writing to any output not a pipe\n\
106 exit exit on error writing to any output\n\
107 exit-nopipe exit on error writing to any output not a pipe\n\
108 The default MODE for the -p option is 'warn-nopipe'.\n\
109 With \"nopipe\" MODEs, exit immediately if all outputs become broken pipes.\n\
110 The default operation when --output-error is not specified, is to\n\
111 exit immediately on error writing to a pipe, and diagnose errors\n\
112 writing to non pipe outputs.\n\
114 emit_ancillary_info (PROGRAM_NAME
);
120 main (int argc
, char **argv
)
122 initialize_main (&argc
, &argv
);
123 set_program_name (argv
[0]);
124 setlocale (LC_ALL
, "");
125 bindtextdomain (PACKAGE
, LOCALEDIR
);
126 textdomain (PACKAGE
);
128 atexit (close_stdout
);
131 ignore_interrupts
= false;
134 while ((optc
= getopt_long (argc
, argv
, "aip", long_options
, NULL
)) != -1)
143 ignore_interrupts
= true;
148 output_error
= XARGMATCH ("--output-error", optarg
,
149 output_error_args
, output_error_types
);
151 output_error
= output_error_warn_nopipe
;
154 case_GETOPT_HELP_CHAR
;
156 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
159 usage (EXIT_FAILURE
);
163 if (ignore_interrupts
)
164 signal (SIGINT
, SIG_IGN
);
166 if (output_error
!= output_error_sigpipe
)
167 signal (SIGPIPE
, SIG_IGN
);
169 /* Whether to detect and close a broken pipe output.
170 There is no need if the input is always ready for reading. */
171 bool pipe_check
= ((output_error
== output_error_warn_nopipe
172 || output_error
== output_error_exit_nopipe
)
173 && iopoll_input_ok (STDIN_FILENO
));
175 /* Do *not* warn if tee is given no file arguments.
176 POSIX requires that it work when given no arguments. */
178 bool ok
= tee_files (argc
- optind
, &argv
[optind
], pipe_check
);
179 if (close (STDIN_FILENO
) != 0)
180 die (EXIT_FAILURE
, errno
, "%s", _("standard input"));
182 return ok
? EXIT_SUCCESS
: EXIT_FAILURE
;
186 /* Return the index of the first non-NULL descriptor after idx,
187 or -1 if all are NULL. */
190 get_next_out (FILE **descriptors
, int nfiles
, int idx
)
192 for (idx
++; idx
<= nfiles
; idx
++)
193 if (descriptors
[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. */
202 fail_output (FILE **descriptors
, char **files
, int i
)
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. */
212 error (output_error
== output_error_exit
213 || output_error
== output_error_exit_nopipe
,
214 w_errno
, "%s", quotef (files
[i
]));
216 descriptors
[i
] = NULL
;
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. */
226 tee_files (int nfiles
, char **files
, bool pipe_check
)
228 size_t n_outputs
= 0;
232 ssize_t bytes_read
= 0;
234 int first_out
= 0; /* idx of first non-NULL output in descriptors */
236 char const *mode_string
=
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
);
250 out_pollable
= xnmalloc (nfiles
+ 1, sizeof *out_pollable
);
252 descriptors
[0] = stdout
;
254 out_pollable
[0] = iopoll_output_ok (fileno (descriptors
[0]));
255 files
[0] = bad_cast (_("standard output"));
256 setvbuf (stdout
, NULL
, _IONBF
, 0);
259 for (i
= 1; i
<= nfiles
; i
++)
261 /* Do not treat "-" specially - as mandated by POSIX. */
262 descriptors
[i
] = fopen (files
[i
], mode_string
);
264 out_pollable
[i
] = iopoll_output_ok (fileno (descriptors
[i
]));
265 if (descriptors
[i
] == NULL
)
267 error (output_error
== output_error_exit
268 || output_error
== output_error_exit_nopipe
,
269 errno
, "%s", quotef (files
[i
]));
274 setvbuf (descriptors
[i
], NULL
, _IONBF
, 0);
281 if (pipe_check
&& out_pollable
[first_out
])
283 /* Monitor for input, or errors on first valid output. */
284 int err
= iopoll (STDIN_FILENO
, fileno (descriptors
[first_out
]),
287 /* Close the output if it became a broken pipe. */
288 if (err
== IOPOLL_BROKEN_OUTPUT
)
290 errno
= EPIPE
; /* behave like write produced EPIPE */
291 if (fail_output (descriptors
, files
, first_out
))
294 first_out
= get_next_out (descriptors
, nfiles
, first_out
);
297 else if (err
== IOPOLL_ERROR
)
299 error (0, errno
, _("iopoll error"));
304 bytes_read
= read (STDIN_FILENO
, buffer
, sizeof buffer
);
305 if (bytes_read
< 0 && errno
== EINTR
)
310 /* Write to all NFILES + 1 descriptors.
311 Standard output is the first one. */
312 for (i
= 0; i
<= nfiles
; i
++)
314 && fwrite (buffer
, bytes_read
, 1, descriptors
[i
]) != 1)
316 if (fail_output (descriptors
, files
, i
))
320 first_out
= get_next_out (descriptors
, nfiles
, first_out
);
324 if (bytes_read
== -1)
326 error (0, errno
, _("read error"));
330 /* Close the files, but not standard output. */
331 for (i
= 1; i
<= nfiles
; i
++)
332 if (descriptors
[i
] && fclose (descriptors
[i
]) != 0)
334 error (0, errno
, "%s", quotef (files
[i
]));