1 | /* tee - duplicate standard input */
|
---|
2 |
|
---|
3 | /* See Makefile for compilation details. */
|
---|
4 |
|
---|
5 | #include "config.h"
|
---|
6 |
|
---|
7 | #include "bashtypes.h"
|
---|
8 | #include "posixstat.h"
|
---|
9 | #include "filecntl.h"
|
---|
10 |
|
---|
11 | #include <signal.h>
|
---|
12 |
|
---|
13 | #if defined (HAVE_UNISTD_H)
|
---|
14 | # include <unistd.h>
|
---|
15 | #endif
|
---|
16 |
|
---|
17 | #include "bashansi.h"
|
---|
18 |
|
---|
19 | #include <stdio.h>
|
---|
20 | #include <errno.h>
|
---|
21 |
|
---|
22 | #include "builtins.h"
|
---|
23 | #include "shell.h"
|
---|
24 | #include "bashgetopt.h"
|
---|
25 |
|
---|
26 | #if !defined (errno)
|
---|
27 | extern int errno;
|
---|
28 | #endif
|
---|
29 |
|
---|
30 | typedef struct flist {
|
---|
31 | struct flist *next;
|
---|
32 | int fd;
|
---|
33 | char *fname;
|
---|
34 | } FLIST;
|
---|
35 |
|
---|
36 | static FLIST *tee_flist;
|
---|
37 |
|
---|
38 | #define TEE_BUFSIZE 8192
|
---|
39 |
|
---|
40 | extern int interrupt_immediately;
|
---|
41 |
|
---|
42 | extern char *strerror ();
|
---|
43 |
|
---|
44 | tee_builtin (list)
|
---|
45 | WORD_LIST *list;
|
---|
46 | {
|
---|
47 | int opt, append, nointr, rval, fd, fflags;
|
---|
48 | int n, nr, nw;
|
---|
49 | FLIST *fl;
|
---|
50 | char *buf, *bp;
|
---|
51 |
|
---|
52 | char *t;
|
---|
53 |
|
---|
54 | reset_internal_getopt ();
|
---|
55 | append = nointr = 0;
|
---|
56 | tee_flist = (FLIST *)NULL;
|
---|
57 | while ((opt = internal_getopt (list, "ai")) != -1)
|
---|
58 | {
|
---|
59 | switch (opt)
|
---|
60 | {
|
---|
61 | case 'a':
|
---|
62 | append = 1;
|
---|
63 | break;
|
---|
64 | case 'i':
|
---|
65 | nointr = 1;
|
---|
66 | break;
|
---|
67 | default:
|
---|
68 | builtin_usage ();
|
---|
69 | return (EX_USAGE);
|
---|
70 | }
|
---|
71 | }
|
---|
72 | list = loptend;
|
---|
73 |
|
---|
74 | if (nointr == 0)
|
---|
75 | interrupt_immediately++;
|
---|
76 |
|
---|
77 | buf = xmalloc (TEE_BUFSIZE);
|
---|
78 |
|
---|
79 | /* Initialize output file list. */
|
---|
80 | fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST));
|
---|
81 | tee_flist->fd = 1;
|
---|
82 | tee_flist->fname = "stdout";
|
---|
83 | tee_flist->next = (FLIST *)NULL;
|
---|
84 |
|
---|
85 | /* Add file arguments to list of output files. */
|
---|
86 | fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC;
|
---|
87 | for (rval = EXECUTION_SUCCESS; list; list = list->next)
|
---|
88 | {
|
---|
89 | fd = open (list->word->word, fflags, 0666);
|
---|
90 | if (fd < 0)
|
---|
91 | {
|
---|
92 | builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno));
|
---|
93 | rval = EXECUTION_FAILURE;
|
---|
94 | }
|
---|
95 | else
|
---|
96 | {
|
---|
97 | fl->next = (FLIST *)xmalloc (sizeof(FLIST));
|
---|
98 | fl->next->fd = fd;
|
---|
99 | fl->next->fname = list->word->word;
|
---|
100 | fl = fl->next;
|
---|
101 | fl->next = (FLIST *)NULL;
|
---|
102 | }
|
---|
103 | }
|
---|
104 |
|
---|
105 | while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
|
---|
106 | for (fl = tee_flist; fl; fl = fl->next)
|
---|
107 | {
|
---|
108 | n = nr;
|
---|
109 | bp = buf;
|
---|
110 | do
|
---|
111 | {
|
---|
112 | if ((nw = write (fl->fd, bp, n)) == -1)
|
---|
113 | {
|
---|
114 | builtin_error ("%s: write error: %s", fl->fname, strerror (errno));
|
---|
115 | rval = EXECUTION_FAILURE;
|
---|
116 | break;
|
---|
117 | }
|
---|
118 | bp += nw;
|
---|
119 | }
|
---|
120 | while (n -= nw);
|
---|
121 | }
|
---|
122 | if (nr < 0)
|
---|
123 | builtin_error ("read error: %s", strerror (errno));
|
---|
124 |
|
---|
125 | /* Deallocate resources -- this is a builtin command. */
|
---|
126 | tee_flist = tee_flist->next; /* skip bogus close of stdout */
|
---|
127 | while (tee_flist)
|
---|
128 | {
|
---|
129 | fl = tee_flist;
|
---|
130 | if (close (fl->fd) < 0)
|
---|
131 | {
|
---|
132 | builtin_error ("%s: close_error: %s", fl->fname, strerror (errno));
|
---|
133 | rval = EXECUTION_FAILURE;
|
---|
134 | }
|
---|
135 | tee_flist = tee_flist->next;
|
---|
136 | free (fl);
|
---|
137 | }
|
---|
138 |
|
---|
139 | return (rval);
|
---|
140 | }
|
---|
141 |
|
---|
142 | char *tee_doc[] = {
|
---|
143 | "Copy standard input to standard output, making a copy in each",
|
---|
144 | "filename argument. If the `-a' option is gived, the specified",
|
---|
145 | "files are appended to, otherwise they are overwritten. If the",
|
---|
146 | "`-i' option is supplied, tee ignores interrupts.",
|
---|
147 | (char *)NULL
|
---|
148 | };
|
---|
149 |
|
---|
150 | struct builtin tee_struct = {
|
---|
151 | "tee", /* builtin name */
|
---|
152 | tee_builtin, /* function implementing the builtin */
|
---|
153 | BUILTIN_ENABLED, /* initial flags for builtin */
|
---|
154 | tee_doc, /* array of long documentation strings. */
|
---|
155 | "tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */
|
---|
156 | 0 /* reserved for internal use */
|
---|
157 | };
|
---|