1 /* tee - read from standard input and write to standard output and files.
2 Copyright (C) 1985-2015 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 <http://www.gnu.org/licenses/>. */
17 /* Mike Parker, Richard M. Stallman, and David MacKenzie */
20 #include <sys/types.h>
32 /* The official name of this program (e.g., no 'g' prefix). */
33 #define PROGRAM_NAME "tee"
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
);
42 /* If true, append to output files rather than truncating them. */
45 /* If true, ignore interrupts. */
46 static bool ignore_interrupts
;
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
, NULL
, 'a'},
62 {"ignore-interrupts", no_argument
, NULL
, 'i'},
63 {"output-error", optional_argument
, NULL
, 'p'},
64 {GETOPT_HELP_OPTION_DECL
},
65 {GETOPT_VERSION_OPTION_DECL
},
69 static char const *const output_error_args
[] =
71 "warn", "warn-nopipe", "exit", "exit-nopipe", NULL
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
);
83 if (status
!= EXIT_SUCCESS
)
87 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name
);
89 Copy standard input to each FILE, and also to standard output.\n\
91 -a, --append append to the given FILEs, do not overwrite\n\
92 -i, --ignore-interrupts ignore interrupt signals\n\
95 -p diagnose errors writing to non pipes\n\
96 --output-error[=MODE] set behavior on write error. See MODE below\n\
98 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
99 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
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 The default operation when --output-error is not specified, is to\n\
109 exit immediately on error writing to a pipe, and diagnose errors\n\
110 writing to non pipe outputs.\n\
112 emit_ancillary_info (PROGRAM_NAME
);
118 main (int argc
, char **argv
)
123 initialize_main (&argc
, &argv
);
124 set_program_name (argv
[0]);
125 setlocale (LC_ALL
, "");
126 bindtextdomain (PACKAGE
, LOCALEDIR
);
127 textdomain (PACKAGE
);
129 atexit (close_stdout
);
132 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 /* Do *not* warn if tee is given no file arguments.
170 POSIX requires that it work when given no arguments. */
172 ok
= tee_files (argc
- optind
, &argv
[optind
]);
173 if (close (STDIN_FILENO
) != 0)
174 error (EXIT_FAILURE
, errno
, "%s", _("standard input"));
176 return ok
? EXIT_SUCCESS
: EXIT_FAILURE
;
179 /* Copy the standard input into each of the NFILES files in FILES
180 and into the standard output. As a side effect, modify FILES[-1].
181 Return true if successful. */
184 tee_files (int nfiles
, char **files
)
186 size_t n_outputs
= 0;
189 ssize_t bytes_read
= 0;
192 char const *mode_string
=
194 ? (append
? "ab" : "wb")
195 : (append
? "a" : "w"));
197 if (O_BINARY
&& ! isatty (STDIN_FILENO
))
198 xfreopen (NULL
, "rb", stdin
);
199 if (O_BINARY
&& ! isatty (STDOUT_FILENO
))
200 xfreopen (NULL
, "wb", stdout
);
202 fadvise (stdin
, FADVISE_SEQUENTIAL
);
204 /* Set up FILES[0 .. NFILES] and DESCRIPTORS[0 .. NFILES].
205 In both arrays, entry 0 corresponds to standard output. */
207 descriptors
= xnmalloc (nfiles
+ 1, sizeof *descriptors
);
209 descriptors
[0] = stdout
;
210 files
[0] = bad_cast (_("standard output"));
211 setvbuf (stdout
, NULL
, _IONBF
, 0);
214 for (i
= 1; i
<= nfiles
; i
++)
216 /* Do not treat "-" specially - as mandated by POSIX. */
217 descriptors
[i
] = fopen (files
[i
], mode_string
);
218 if (descriptors
[i
] == NULL
)
220 error (output_error
== output_error_exit
221 || output_error
== output_error_exit_nopipe
,
222 errno
, "%s", quote (files
[i
]));
227 setvbuf (descriptors
[i
], NULL
, _IONBF
, 0);
234 bytes_read
= read (0, buffer
, sizeof buffer
);
235 if (bytes_read
< 0 && errno
== EINTR
)
240 /* Write to all NFILES + 1 descriptors.
241 Standard output is the first one. */
242 for (i
= 0; i
<= nfiles
; i
++)
244 && fwrite (buffer
, bytes_read
, 1, descriptors
[i
]) != 1)
247 bool fail
= errno
!= EPIPE
|| (output_error
== output_error_exit
248 || output_error
== output_error_warn
);
249 if (descriptors
[i
] == stdout
)
250 clearerr (stdout
); /* Avoid redundant close_stdout diagnostic. */
253 error (output_error
== output_error_exit
254 || output_error
== output_error_exit_nopipe
,
255 w_errno
, "%s", quote (files
[i
]));
257 descriptors
[i
] = NULL
;
264 if (bytes_read
== -1)
266 error (0, errno
, _("read error"));
270 /* Close the files, but not standard output. */
271 for (i
= 1; i
<= nfiles
; i
++)
272 if (descriptors
[i
] && fclose (descriptors
[i
]) != 0)
274 error (0, errno
, "%s", quote (files
[i
]));