busybox/coreutils/tee.c
Rob Landley d921b2ecc0 Remove bb_ prefixes from xfuncs.c (and a few other places), consolidate
things like xasprintf() into xfuncs.c, remove xprint_file_by_name() (it only
had one user), clean up lots of #includes...  General cleanup pass.  What I've
been doing for the last couple days.

And it conflicts!  I've removed httpd.c from this checkin due to somebody else
touching that file.  It builds for me.  I have to catch a bus.  (Now you know
why I'm looking forward to Mercurial.)
2006-08-03 15:41:12 +00:00

100 lines
2.5 KiB
C

/* vi: set sw=4 ts=4: */
/*
* tee implementation for busybox
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */
#include "busybox.h"
int tee_main(int argc, char **argv)
{
const char *mode = "w\0a";
FILE **files;
FILE **p;
char **filenames;
int flags;
int retval = EXIT_SUCCESS;
#ifdef CONFIG_FEATURE_TEE_USE_BLOCK_IO
ssize_t c;
# define buf bb_common_bufsiz1
#else
int c;
#endif
flags = bb_getopt_ulflags(argc, argv, "ia"); /* 'a' must be 2nd */
mode += (flags & 2); /* Since 'a' is the 2nd option... */
if (flags & 1) {
signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction.*/
}
/* gnu tee ignores SIGPIPE in case one of the output files is a pipe
* that doesn't consume all its input. Good idea... */
signal(SIGPIPE, SIG_IGN); /* TODO - switch to sigaction.*/
/* Allocate an array of FILE *'s, with one extra for a sentinal. */
p = files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 2));
*p = stdout;
argv += optind - 1;
filenames = argv - 1;
*filenames = (char *) bb_msg_standard_input; /* for later */
goto GOT_NEW_FILE;
do {
if ((*p = bb_wfopen(*argv, mode)) == NULL) {
retval = EXIT_FAILURE;
continue;
}
filenames[(int)(p - files)] = *argv;
GOT_NEW_FILE:
setbuf(*p, NULL); /* tee must not buffer output. */
++p;
} while (*++argv);
*p = NULL; /* Store the sentinal value. */
#ifdef CONFIG_FEATURE_TEE_USE_BLOCK_IO
while ((c = safe_read(STDIN_FILENO, buf, BUFSIZ)) > 0) {
for (p=files ; *p ; p++) {
fwrite(buf, 1, c, *p);
}
}
if (c < 0) { /* Make sure read errors are signaled. */
retval = EXIT_FAILURE;
}
#else
setvbuf(stdout, NULL, _IONBF, 0);
while ((c = getchar()) != EOF) {
for (p=files ; *p ; p++) {
putc(c, *p);
}
}
#endif
/* Now we need to check for i/o errors on stdin and the various
* output files. Since we know that the first entry in the output
* file table is stdout, we can save one "if ferror" test by
* setting the first entry to stdin and checking stdout error
* status with bb_fflush_stdout_and_exit()... although fflush()ing
* is unnecessary here. */
p = files;
*p = stdin;
do { /* Now check for (input and) output errors. */
/* Checking ferror should be sufficient, but we may want to fclose.
* If we do, remember not to close stdin! */
xferror(*p, filenames[(int)(p - files)]);
} while (*++p);
bb_fflush_stdout_and_exit(retval);
}