]> git.ipfire.org Git - thirdparty/bash.git/blob - examples/loadables/tee.c
bash-5.1 distribution sources and documentation
[thirdparty/bash.git] / examples / loadables / tee.c
1 /* tee - duplicate standard input */
2
3 /* See Makefile for compilation details. */
4
5 /*
6 Copyright (C) 1999-2009 Free Software Foundation, Inc.
7
8 This file is part of GNU Bash.
9 Bash is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Bash is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Bash. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24
25 #include "bashtypes.h"
26 #include "posixstat.h"
27 #include "filecntl.h"
28
29 #include <signal.h>
30
31 #if defined (HAVE_UNISTD_H)
32 # include <unistd.h>
33 #endif
34
35 #include "bashansi.h"
36
37 #include <stdio.h>
38 #include <errno.h>
39
40 #include "builtins.h"
41 #include "shell.h"
42 #include "bashgetopt.h"
43 #include "common.h"
44
45 #if !defined (errno)
46 extern int errno;
47 #endif
48
49 typedef struct flist {
50 struct flist *next;
51 int fd;
52 char *fname;
53 } FLIST;
54
55 static FLIST *tee_flist;
56
57 #define TEE_BUFSIZE 8192
58
59 extern int interrupt_immediately;
60
61 extern char *strerror ();
62
63 int
64 tee_builtin (list)
65 WORD_LIST *list;
66 {
67 int opt, append, nointr, rval, fd, fflags;
68 int n, nr, nw;
69 FLIST *fl;
70 char *buf, *bp;
71
72 char *t;
73
74 reset_internal_getopt ();
75 append = nointr = 0;
76 tee_flist = (FLIST *)NULL;
77 while ((opt = internal_getopt (list, "ai")) != -1)
78 {
79 switch (opt)
80 {
81 case 'a':
82 append = 1;
83 break;
84 case 'i':
85 nointr = 1;
86 break;
87 CASE_HELPOPT;
88 default:
89 builtin_usage ();
90 return (EX_USAGE);
91 }
92 }
93 list = loptend;
94
95 if (nointr == 0)
96 interrupt_immediately++;
97
98 buf = xmalloc (TEE_BUFSIZE);
99
100 /* Initialize output file list. */
101 fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST));
102 tee_flist->fd = 1;
103 tee_flist->fname = "stdout";
104 tee_flist->next = (FLIST *)NULL;
105
106 /* Add file arguments to list of output files. */
107 fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC;
108 for (rval = EXECUTION_SUCCESS; list; list = list->next)
109 {
110 fd = open (list->word->word, fflags, 0666);
111 if (fd < 0)
112 {
113 builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno));
114 rval = EXECUTION_FAILURE;
115 }
116 else
117 {
118 fl->next = (FLIST *)xmalloc (sizeof(FLIST));
119 fl->next->fd = fd;
120 fl->next->fname = list->word->word;
121 fl = fl->next;
122 fl->next = (FLIST *)NULL;
123 }
124 }
125
126 while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
127 for (fl = tee_flist; fl; fl = fl->next)
128 {
129 n = nr;
130 bp = buf;
131 do
132 {
133 if ((nw = write (fl->fd, bp, n)) == -1)
134 {
135 builtin_error ("%s: write error: %s", fl->fname, strerror (errno));
136 rval = EXECUTION_FAILURE;
137 break;
138 }
139 bp += nw;
140 }
141 while (n -= nw);
142 }
143 if (nr < 0)
144 builtin_error ("read error: %s", strerror (errno));
145
146 /* Deallocate resources -- this is a builtin command. */
147 tee_flist = tee_flist->next; /* skip bogus close of stdout */
148 while (tee_flist)
149 {
150 fl = tee_flist;
151 if (close (fl->fd) < 0)
152 {
153 builtin_error ("%s: close_error: %s", fl->fname, strerror (errno));
154 rval = EXECUTION_FAILURE;
155 }
156 tee_flist = tee_flist->next;
157 free (fl);
158 }
159
160 return (rval);
161 }
162
163 char *tee_doc[] = {
164 "Duplicate standard output.",
165 "",
166 "Copy standard input to standard output, making a copy in each",
167 "filename argument. If the `-a' option is given, the specified",
168 "files are appended to, otherwise they are overwritten. If the",
169 "`-i' option is supplied, tee ignores interrupts.",
170 (char *)NULL
171 };
172
173 struct builtin tee_struct = {
174 "tee", /* builtin name */
175 tee_builtin, /* function implementing the builtin */
176 BUILTIN_ENABLED, /* initial flags for builtin */
177 tee_doc, /* array of long documentation strings. */
178 "tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */
179 0 /* reserved for internal use */
180 };