mirror of
https://github.com/coreutils/coreutils.git
synced 2026-10-28 17:54:36 +08:00
tee: prefer file descriptors over streams
We disable buffering on the streams anyways, so we were effectively calling the write system call previously despite using streams. * src/iopoll.h (fclose_wait, fwrite_wait): Remove declarations. (close_wait, write_wait): Add declarations. * src/iopoll.c (fwait_for_nonblocking_write, fclose_wait, fwrite_wait): Remove functions. (wait_for_nonblocking_write): New function based on fwait_for_nonblocking_write. (close_wait): New function based on fclose_wait. (write_wait): New function based on fwrite_wait. * src/tee.c: Include fcntl--.h. Don't include stdio--.h. (get_next_out): Operate on file descriptors instead of streams. (fail_output): Likewise. Remove clearerr call since we no longer call fwrite on stdout. (tee_files): Operate on file descriptors instead of streams. Remove calls to setvbuf.
This commit is contained in:
1 parent
e644eea122
commit
9b855166ed
3 files changed
+43
-60
No files matched your search
+25
-34
@@ -177,62 +177,53 @@ iopoll_output_ok (int fdout)
|
||||
Return true, if EAGAIN has been successfully handled. */
|
||||
|
||||
static bool
|
||||
fwait_for_nonblocking_write (FILE *f)
|
||||
wait_for_nonblocking_write (int fd)
|
||||
{
|
||||
if (! IS_EAGAIN (errno))
|
||||
/* non-recoverable write error */
|
||||
return false;
|
||||
|
||||
int fd = fileno (f);
|
||||
if (fd == -1)
|
||||
goto fail;
|
||||
|
||||
/* wait for the file descriptor to become writable */
|
||||
if (iopoll_internal (-1, fd, true, false) != 0)
|
||||
goto fail;
|
||||
|
||||
/* successfully waited for the descriptor to become writable */
|
||||
clearerr (f);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
errno = EAGAIN;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* wrapper for fclose() that also waits for F if non blocking. */
|
||||
|
||||
extern bool
|
||||
fclose_wait (FILE *f)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (fflush (f) == 0)
|
||||
break;
|
||||
|
||||
if (! fwait_for_nonblocking_write (f))
|
||||
break;
|
||||
errno = EAGAIN;
|
||||
return false;
|
||||
}
|
||||
|
||||
return fclose (f) == 0;
|
||||
/* successfully waited for the descriptor to become writable */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* wrapper for close() that also waits for FD if non blocking. */
|
||||
|
||||
extern bool
|
||||
close_wait (int fd)
|
||||
{
|
||||
while (wait_for_nonblocking_write (fd))
|
||||
;
|
||||
return close (fd) == 0;
|
||||
}
|
||||
|
||||
|
||||
/* wrapper for fwrite() that also waits for F if non blocking. */
|
||||
/* wrapper for write() that also waits for FD if non blocking. */
|
||||
|
||||
extern bool
|
||||
fwrite_wait (char const *buf, ssize_t size, FILE *f)
|
||||
write_wait (int fd, void const *buffer, size_t size)
|
||||
{
|
||||
for (;;)
|
||||
unsigned char const *buf = buffer;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const size_t written = fwrite (buf, 1, size, f);
|
||||
ssize_t written = write (fd, buf, size);
|
||||
if (written < 0)
|
||||
written = 0;
|
||||
|
||||
size -= written;
|
||||
affirm (size >= 0);
|
||||
if (size <= 0) /* everything written */
|
||||
return true;
|
||||
|
||||
if (! fwait_for_nonblocking_write (f))
|
||||
if (! wait_for_nonblocking_write (fd))
|
||||
return false;
|
||||
|
||||
buf += written;
|
||||
|
||||
+2
-2
@@ -5,5 +5,5 @@ int iopoll (int fdin, int fdout, bool block);
|
||||
bool iopoll_input_ok (int fdin);
|
||||
bool iopoll_output_ok (int fdout);
|
||||
|
||||
bool fclose_wait (FILE *f);
|
||||
bool fwrite_wait (char const *buf, ssize_t size, FILE *f);
|
||||
bool close_wait (int fd);
|
||||
bool write_wait (int fd, void const *buffer, size_t size);
|
||||
@@ -24,8 +24,8 @@
|
||||
#include "system.h"
|
||||
#include "argmatch.h"
|
||||
#include "fadvise.h"
|
||||
#include "fcntl--.h"
|
||||
#include "iopoll.h"
|
||||
#include "stdio--.h"
|
||||
#include "xbinary-io.h"
|
||||
#include "iopoll.h"
|
||||
|
||||
@@ -194,10 +194,10 @@ main (int argc, char **argv)
|
||||
|
||||
ATTRIBUTE_PURE
|
||||
static int
|
||||
get_next_out (FILE **descriptors, int nfiles, int idx)
|
||||
get_next_out (int *descriptors, int nfiles, int idx)
|
||||
{
|
||||
for (idx++; idx <= nfiles; idx++)
|
||||
if (descriptors[idx])
|
||||
if (0 <= descriptors[idx])
|
||||
return idx;
|
||||
return -1; /* no outputs remaining */
|
||||
}
|
||||
@@ -206,21 +206,19 @@ get_next_out (FILE **descriptors, int nfiles, int idx)
|
||||
Return true if this indicates a reportable error. */
|
||||
|
||||
static bool
|
||||
fail_output (FILE **descriptors, char **files, int i)
|
||||
fail_output (int *descriptors, char **files, int i)
|
||||
{
|
||||
int w_errno = errno;
|
||||
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 (output_error == output_error_exit
|
||||
|| output_error == output_error_exit_nopipe,
|
||||
w_errno, "%s", quotef (files[i]));
|
||||
}
|
||||
descriptors[i] = NULL;
|
||||
descriptors[i] = -1;
|
||||
return fail;
|
||||
}
|
||||
|
||||
@@ -233,16 +231,13 @@ static bool
|
||||
tee_files (int nfiles, char **files, bool pipe_check)
|
||||
{
|
||||
size_t n_outputs = 0;
|
||||
FILE **descriptors;
|
||||
int *descriptors;
|
||||
bool *out_pollable IF_LINT ( = NULL);
|
||||
char buffer[BUFSIZ];
|
||||
ssize_t bytes_read = 0;
|
||||
int first_out = 0; /* idx of first non-null output in descriptors */
|
||||
bool ok = true;
|
||||
char const *mode_string =
|
||||
(O_BINARY
|
||||
? (append ? "ab" : "wb")
|
||||
: (append ? "a" : "w"));
|
||||
int flags = O_WRONLY | O_CREAT | O_BINARY | (append ? O_APPEND : O_TRUNC);
|
||||
|
||||
xset_binary_mode (STDIN_FILENO, O_BINARY);
|
||||
xset_binary_mode (STDOUT_FILENO, O_BINARY);
|
||||
@@ -255,18 +250,17 @@ tee_files (int nfiles, char **files, bool pipe_check)
|
||||
if (pipe_check)
|
||||
out_pollable = xnmalloc (nfiles + 1, sizeof *out_pollable);
|
||||
files--;
|
||||
descriptors[0] = stdout;
|
||||
descriptors[0] = STDOUT_FILENO;
|
||||
if (pipe_check)
|
||||
out_pollable[0] = iopoll_output_ok (fileno (descriptors[0]));
|
||||
out_pollable[0] = iopoll_output_ok (descriptors[0]);
|
||||
files[0] = bad_cast (_("standard output"));
|
||||
setvbuf (stdout, NULL, _IONBF, 0);
|
||||
n_outputs++;
|
||||
|
||||
for (int i = 1; i <= nfiles; i++)
|
||||
{
|
||||
/* Do not treat "-" specially - as mandated by POSIX. */
|
||||
descriptors[i] = fopen (files[i], mode_string);
|
||||
if (descriptors[i] == NULL)
|
||||
descriptors[i] = open (files[i], flags, MODE_RW_UGO);
|
||||
if (descriptors[i] < 0)
|
||||
{
|
||||
if (pipe_check)
|
||||
out_pollable[i] = false;
|
||||
@@ -278,8 +272,7 @@ tee_files (int nfiles, char **files, bool pipe_check)
|
||||
else
|
||||
{
|
||||
if (pipe_check)
|
||||
out_pollable[i] = iopoll_output_ok (fileno (descriptors[i]));
|
||||
setvbuf (descriptors[i], NULL, _IONBF, 0);
|
||||
out_pollable[i] = iopoll_output_ok (descriptors[i]);
|
||||
n_outputs++;
|
||||
}
|
||||
}
|
||||
@@ -289,8 +282,7 @@ tee_files (int nfiles, char **files, bool pipe_check)
|
||||
if (pipe_check && out_pollable[first_out])
|
||||
{
|
||||
/* Monitor for input, or errors on first valid output. */
|
||||
int err = iopoll (STDIN_FILENO, fileno (descriptors[first_out]),
|
||||
true);
|
||||
int err = iopoll (STDIN_FILENO, descriptors[first_out], true);
|
||||
|
||||
/* Close the output if it became a broken pipe. */
|
||||
if (err == IOPOLL_BROKEN_OUTPUT)
|
||||
@@ -318,8 +310,8 @@ tee_files (int nfiles, char **files, bool pipe_check)
|
||||
/* Write to all NFILES + 1 descriptors.
|
||||
Standard output is the first one. */
|
||||
for (int i = 0; i <= nfiles; i++)
|
||||
if (descriptors[i]
|
||||
&& ! fwrite_wait (buffer, bytes_read, descriptors[i]))
|
||||
if (0 <= descriptors[i]
|
||||
&& ! write_wait (descriptors[i], buffer, bytes_read))
|
||||
{
|
||||
if (fail_output (descriptors, files, i))
|
||||
ok = false;
|
||||
@@ -337,7 +329,7 @@ tee_files (int nfiles, char **files, bool pipe_check)
|
||||
|
||||
/* Close the files, but not standard output. */
|
||||
for (int i = 1; i <= nfiles; i++)
|
||||
if (descriptors[i] && ! fclose_wait (descriptors[i]))
|
||||
if (0 <= descriptors[i] && ! close_wait (descriptors[i]))
|
||||
{
|
||||
error (0, errno, "%s", quotef (files[i]));
|
||||
ok = false;
|
||||
|
||||
Reference in new issue
Block a user