Ignore interrupt signals.
@item -p
-@itemx --write-error[=@var{mode}]
+@itemx --output-error[=@var{mode}]
@opindex -p
-@opindex --write-error
-Select the behavior with write errors on the outputs,
+@opindex --output-error
+Select the behavior with errors on the outputs,
where @var{mode} is one of the following:
@table @samp
@item warn
-Warn on error writing any output, including pipes.
+Warn on error opening or writing any output, including pipes.
Writing is continued to still open files/pipes.
Exit status indicates failure if any output has an error.
@item warn-nopipe
-Warn on error writing any output, except pipes.
+Warn on error opening or writing any output, except pipes.
Writing is continued to still open files/pipes.
Exit status indicates failure if any non pipe output had an error.
This is the default @var{mode} when not specified.
@item exit
-Exit on error writing any output, including pipes.
+Exit on error opening or writing any output, including pipes.
@item exit-nopipe
-Exit on error writing any output, except pipes.
+Exit on error opening or writing any output, except pipes.
@end table
@end table
/* If true, ignore interrupts. */
static bool ignore_interrupts;
-enum write_error
+enum output_error
{
- write_error_sigpipe, /* traditional behavior, sigpipe enabled. */
- write_error_warn, /* warn on EPIPE, but continue. */
- write_error_warn_nopipe, /* ignore EPIPE, continue. */
- write_error_exit, /* exit on any write error. */
- write_error_exit_nopipe /* exit on any write error except EPIPE. */
+ output_error_sigpipe, /* traditional behavior, sigpipe enabled. */
+ output_error_warn, /* warn on EPIPE, but continue. */
+ output_error_warn_nopipe, /* ignore EPIPE, continue. */
+ output_error_exit, /* exit on any output error. */
+ output_error_exit_nopipe /* exit on any output error except EPIPE. */
};
-static enum write_error write_error;
+static enum output_error output_error;
static struct option const long_options[] =
{
{"append", no_argument, NULL, 'a'},
{"ignore-interrupts", no_argument, NULL, 'i'},
- {"write-error", optional_argument, NULL, 'p'},
+ {"output-error", optional_argument, NULL, 'p'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
-static char const *const write_error_args[] =
+static char const *const output_error_args[] =
{
"warn", "warn-nopipe", "exit", "exit-nopipe", NULL
};
-static enum write_error const write_error_types[] =
+static enum output_error const output_error_types[] =
{
- write_error_warn, write_error_warn_nopipe,
- write_error_exit, write_error_exit_nopipe
+ output_error_warn, output_error_warn_nopipe,
+ output_error_exit, output_error_exit_nopipe
};
-ARGMATCH_VERIFY (write_error_args, write_error_types);
+ARGMATCH_VERIFY (output_error_args, output_error_types);
void
usage (int status)
-i, --ignore-interrupts ignore interrupt signals\n\
"), stdout);
fputs (_("\
- -p, --write-error[=MODE] behavior on write error. See MODE details below\n\
+ -p, --output-error[=MODE] behavior on write error. See MODE details below\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
'exit' exit on error writing to any output\n\
'exit-nopipe' exit on error writing to any output not a pipe\n\
The default MODE for the -p option is 'warn-nopipe'.\n\
-The default operation when --write-error is not specified, is to\n\
+The default operation when --output-error is not specified, is to\n\
exit immediately on error writing to a pipe, and diagnose errors\n\
writing to non pipe outputs.\n\
"), stdout);
case 'p':
if (optarg)
- write_error = XARGMATCH ("--write-error", optarg, write_error_args,
- write_error_types);
+ output_error = XARGMATCH ("--output-error", optarg,
+ output_error_args, output_error_types);
else
- write_error = write_error_warn_nopipe;
+ output_error = output_error_warn_nopipe;
break;
case_GETOPT_HELP_CHAR;
if (ignore_interrupts)
signal (SIGINT, SIG_IGN);
- if (write_error != write_error_sigpipe)
+ if (output_error != output_error_sigpipe)
signal (SIGPIPE, SIG_IGN);
/* Do *not* warn if tee is given no file arguments.
size_t n_outputs = 0;
FILE **descriptors;
char buffer[BUFSIZ];
- ssize_t bytes_read;
+ ssize_t bytes_read = 0;
int i;
bool ok = true;
char const *mode_string =
descriptors[i] = fopen (files[i], mode_string);
if (descriptors[i] == NULL)
{
- error (0, errno, "%s", files[i]);
+ error (output_error == output_error_exit
+ || output_error == output_error_exit_nopipe,
+ errno, "%s", files[i]);
ok = false;
}
else
}
}
- while (1)
+ while (n_outputs)
{
bytes_read = read (0, buffer, sizeof buffer);
if (bytes_read < 0 && errno == EINTR)
&& fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)
{
int w_errno = errno;
- bool fail = errno != EPIPE || (write_error == write_error_exit
- || write_error == write_error_warn);
+ bool fail = errno != EPIPE || (output_error == output_error_exit
+ || output_error == output_error_warn);
if (descriptors[i] == stdout)
clearerr (stdout); /* Avoid redundant close_stdout diagnostic. */
if (fail)
{
- error (write_error == write_error_exit
- || write_error == write_error_exit_nopipe,
+ error (output_error == output_error_exit
+ || output_error == output_error_exit_nopipe,
w_errno, "%s", files[i]);
}
descriptors[i] = NULL;
ok = false;
n_outputs--;
}
-
- if (n_outputs == 0)
- break;
}
if (bytes_read == -1)
fi
-# Ensure tee honors --write-error modes
+# Ensure tee honors --output-error modes
mkfifo_or_skip_ fifo
read_fifo() { timeout 10 dd count=1 if=fifo of=/dev/null status=none & }
yes >fifo
pipe_status=$?
-# Default operation is to exit silently on SIGPIPE
+# Default operation is to continue on output errors but exit silently on SIGPIPE
read_fifo
-yes | returns_ $pipe_status timeout 10 tee 2>err >fifo || fail=1
-test $(wc -l < err) = 0 || { cat err; fail=1; }
+yes | returns_ $pipe_status timeout 10 tee ./e/noent 2>err >fifo || fail=1
+test $(wc -l < err) = 1 || { cat err; fail=1; }
# With -p, SIGPIPE is suppressed, exit 0 for EPIPE when all outputs finished
read_fifo
yes | timeout 10 tee -p 2>err >fifo || fail=1
test $(wc -l < err) = 0 || { cat err; fail=1; }
-# With --write-error=warn, exit 1 for EPIPE when all outputs finished
+# With --output-error=warn, exit 1 for EPIPE when all outputs finished
+read_fifo
+yes | returns_ 1 timeout 10 tee --output-error=warn 2>err >fifo || fail=1
+test $(wc -l < err) = 1 || { cat err; fail=1; }
+
+# With --output-error=exit, exit 1 immediately for EPIPE
read_fifo
-yes | returns_ 1 timeout 10 tee --write-error=warn 2>err >fifo || fail=1
+yes | returns_ 1 timeout 10 tee --output-error=exit /dev/null 2>err >fifo \
+ || fail=1
test $(wc -l < err) = 1 || { cat err; fail=1; }
-# With --write-error=exit, exit 1 immediately for EPIPE
+# With --output-error=exit, exit 1 immediately on output error
read_fifo
-yes | returns_ 1 timeout 10 tee --write-error=exit /dev/null 2>err >fifo \
+yes | returns_ 1 timeout 10 tee --output-error=exit ./e/noent 2>err >fifo \
|| fail=1
test $(wc -l < err) = 1 || { cat err; fail=1; }
-# With --write-error=exit-nopipe, exit 0 for EPIPE
+# With --output-error=exit-nopipe, exit 0 for EPIPE
read_fifo
-yes | timeout 10 tee --write-error=exit-nopipe 2>err >fifo || fail=1
+yes | timeout 10 tee --output-error=exit-nopipe 2>err >fifo || fail=1
test $(wc -l < err) = 0 || { cat err; fail=1; }
wait