diff options
Diffstat (limited to 'coreutils/tee.c')
-rw-r--r-- | coreutils/tee.c | 115 |
1 files changed, 82 insertions, 33 deletions
diff --git a/coreutils/tee.c b/coreutils/tee.c index 1c145426a..7e86f2e29 100644 --- a/coreutils/tee.c +++ b/coreutils/tee.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Mini tee implementation for busybox | 3 | * tee implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu> | 5 | * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -20,47 +20,96 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include "busybox.h" | 23 | /* BB_AUDIT SUSv3 compliant */ |
24 | #include <getopt.h> | 24 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */ |
25 | |||
25 | #include <stdio.h> | 26 | #include <stdio.h> |
27 | #include <stdlib.h> | ||
28 | #include <signal.h> | ||
29 | #include <unistd.h> | ||
30 | #include "busybox.h" | ||
26 | 31 | ||
27 | int | 32 | int tee_main(int argc, char **argv) |
28 | tee_main(int argc, char **argv) | ||
29 | { | 33 | { |
30 | char *mode = "w"; | 34 | const char *mode = "w\0a"; |
31 | int c, i, status = 0, nfiles = 0; | ||
32 | FILE **files; | 35 | FILE **files; |
36 | FILE **p; | ||
37 | char **filenames; | ||
38 | int flags; | ||
39 | int retval = EXIT_SUCCESS; | ||
40 | #ifdef CONFIG_FEATURE_TEE_USE_BLOCK_IO | ||
41 | size_t c; | ||
42 | RESERVE_CONFIG_BUFFER(buf, BUFSIZ); | ||
43 | #else | ||
44 | int c; | ||
45 | #endif | ||
46 | |||
47 | flags = bb_getopt_ulflags(argc, argv, "ia"); /* 'a' must be 2nd */ | ||
48 | |||
49 | mode += (flags & 2); /* Since 'a' is the 2nd option... */ | ||
50 | |||
51 | if (flags & 1) { | ||
52 | signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction.*/ | ||
53 | } | ||
54 | |||
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); /* TODO - switch to sigaction.*/ | ||
33 | 58 | ||
34 | while ((c = getopt(argc, argv, "a")) != EOF) { | 59 | /* Allocate an array of FILE *'s, with one extra for a sentinal. */ |
35 | switch (c) { | 60 | p = files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 2)); |
36 | case 'a': | 61 | *p = stdout; |
37 | mode = "a"; | 62 | argv += optind - 1; |
38 | break; | 63 | filenames = argv - 1; |
39 | default: | 64 | *filenames = (char *) bb_msg_standard_input; /* for later */ |
40 | show_usage(); | 65 | goto GOT_NEW_FILE; |
66 | |||
67 | do { | ||
68 | if ((*p = bb_wfopen(*argv, mode)) == NULL) { | ||
69 | retval = EXIT_FAILURE; | ||
70 | continue; | ||
71 | } | ||
72 | filenames[(int)(p - files)] = *argv; | ||
73 | GOT_NEW_FILE: | ||
74 | setbuf(*p, NULL); /* tee must not buffer output. */ | ||
75 | ++p; | ||
76 | } while (*++argv); | ||
77 | |||
78 | *p = NULL; /* Store the sentinal value. */ | ||
79 | |||
80 | #ifdef CONFIG_FEATURE_TEE_USE_BLOCK_IO | ||
81 | while ((c = fread(buf, 1, BUFSIZ, stdin)) != 0) { | ||
82 | for (p=files ; *p ; p++) { | ||
83 | fwrite(buf, 1, c, *p); | ||
41 | } | 84 | } |
42 | } | 85 | } |
43 | 86 | ||
44 | files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 1)); | 87 | #ifdef CONFIG_FEATURE_CLEAN_UP |
45 | files[nfiles++] = stdout; | 88 | RELEASE_CONFIG_BUFFER(buf); |
46 | while (optind < argc) { | 89 | #endif |
47 | if ((files[nfiles++] = wfopen(argv[optind++], mode)) == NULL) { | 90 | |
48 | nfiles--; | 91 | #else |
49 | status = 1; | 92 | while ((c = getchar()) != EOF) { |
93 | for (p=files ; *p ; p++) { | ||
94 | putc(c, *p); | ||
50 | } | 95 | } |
51 | } | 96 | } |
97 | #endif | ||
52 | 98 | ||
53 | while ((c = getchar()) != EOF) | 99 | /* Now we need to check for i/o errors on stdin and the various |
54 | for (i = 0; i < nfiles; i++) | 100 | * output files. Since we know that the first entry in the output |
55 | putc(c, files[i]); | 101 | * file table is stdout, we can save one "if ferror" test by |
102 | * setting the first entry to stdin and checking stdout error | ||
103 | * status with bb_fflush_stdout_and_exit()... although fflush()ing | ||
104 | * is unnecessary here. */ | ||
56 | 105 | ||
57 | return status; | 106 | p = files; |
58 | } | 107 | *p = stdin; |
108 | do { /* Now check for (input and) output errors. */ | ||
109 | /* Checking ferror should be sufficient, but we may want to fclose. | ||
110 | * If we do, remember not to close stdin! */ | ||
111 | bb_xferror(*p, filenames[(int)(p - files)]); | ||
112 | } while (*++p); | ||
59 | 113 | ||
60 | /* | 114 | bb_fflush_stdout_and_exit(retval); |
61 | Local Variables: | 115 | } |
62 | c-file-style: "linux" | ||
63 | c-basic-offset: 4 | ||
64 | tab-width: 4 | ||
65 | End: | ||
66 | */ | ||