source: MondoRescue/branches/3.3/mindi-busybox/coreutils/tee.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 3.1 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * tee implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10/* BB_AUDIT SUSv3 compliant */
11/* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */
12
13//usage:#define tee_trivial_usage
14//usage: "[-ai] [FILE]..."
15//usage:#define tee_full_usage "\n\n"
16//usage: "Copy stdin to each FILE, and also to stdout\n"
17//usage: "\n -a Append to the given FILEs, don't overwrite"
18//usage: "\n -i Ignore interrupt signals (SIGINT)"
19//usage:
20//usage:#define tee_example_usage
21//usage: "$ echo \"Hello\" | tee /tmp/foo\n"
22//usage: "$ cat /tmp/foo\n"
23//usage: "Hello\n"
24
25#include "libbb.h"
26#include "common_bufsiz.h"
27
28int tee_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
29int tee_main(int argc, char **argv)
30{
31 const char *mode = "w\0a";
32 FILE **files;
33 FILE **fp;
34 char **names;
35 char **np;
36 char retval;
37//TODO: make unconditional
38#if ENABLE_FEATURE_TEE_USE_BLOCK_IO
39 ssize_t c;
40# define buf bb_common_bufsiz1
41 setup_common_bufsiz();
42#else
43 int c;
44#endif
45 retval = getopt32(argv, "ia"); /* 'a' must be 2nd */
46 argc -= optind;
47 argv += optind;
48
49 mode += (retval & 2); /* Since 'a' is the 2nd option... */
50
51 if (retval & 1) {
52 signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction. (why?) */
53 }
54 retval = EXIT_SUCCESS;
55 /* gnu tee ignores SIGPIPE in case one of the output files is a pipe
56 * that doesn't consume all its input. Good idea... */
57 signal(SIGPIPE, SIG_IGN);
58
59 /* Allocate an array of FILE *'s, with one extra for a sentinel. */
60 fp = files = xzalloc(sizeof(FILE *) * (argc + 2));
61 np = names = argv - 1;
62
63 files[0] = stdout;
64 goto GOT_NEW_FILE;
65 do {
66 *fp = stdout;
67 if (NOT_LONE_DASH(*argv)) {
68 *fp = fopen_or_warn(*argv, mode);
69 if (*fp == NULL) {
70 retval = EXIT_FAILURE;
71 argv++;
72 continue;
73 }
74 }
75 *np = *argv++;
76 GOT_NEW_FILE:
77 setbuf(*fp, NULL); /* tee must not buffer output. */
78 fp++;
79 np++;
80 } while (*argv);
81 /* names[0] will be filled later */
82
83#if ENABLE_FEATURE_TEE_USE_BLOCK_IO
84 while ((c = safe_read(STDIN_FILENO, buf, COMMON_BUFSIZE)) > 0) {
85 fp = files;
86 do
87 fwrite(buf, 1, c, *fp);
88 while (*++fp);
89 }
90 if (c < 0) { /* Make sure read errors are signaled. */
91 retval = EXIT_FAILURE;
92 }
93#else
94 setvbuf(stdout, NULL, _IONBF, 0);
95 while ((c = getchar()) != EOF) {
96 fp = files;
97 do
98 putc(c, *fp);
99 while (*++fp);
100 }
101#endif
102
103 /* Now we need to check for i/o errors on stdin and the various
104 * output files. Since we know that the first entry in the output
105 * file table is stdout, we can save one "if ferror" test by
106 * setting the first entry to stdin and checking stdout error
107 * status with fflush_stdout_and_exit()... although fflush()ing
108 * is unnecessary here. */
109 np = names;
110 fp = files;
111 names[0] = (char *) bb_msg_standard_input;
112 files[0] = stdin;
113 do { /* Now check for input and output errors. */
114 /* Checking ferror should be sufficient, but we may want to fclose.
115 * If we do, remember not to close stdin! */
116 die_if_ferror(*fp++, *np++);
117 } while (*fp);
118
119 fflush_stdout_and_exit(retval);
120}
Note: See TracBrowser for help on using the repository browser.