blob: 2f7e4d0036311cd0978af11c72bed2987694242f [file] [log] [blame]
Jari Aaltoccc6cda1996-12-23 17:02:34 +00001/* tee - duplicate standard input */
2
3/* See Makefile for compilation details. */
4
Jari Aalto31859422009-01-12 13:36:28 +00005/*
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
Jari Aaltoccc6cda1996-12-23 17:02:34 +000023#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"
Jari Aalto31859422009-01-12 13:36:28 +000043#include "common.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000044
45#if !defined (errno)
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010046#include <errno.h>
Jari Aaltoccc6cda1996-12-23 17:02:34 +000047#endif
48
49typedef struct flist {
50 struct flist *next;
51 int fd;
52 char *fname;
53} FLIST;
54
55static FLIST *tee_flist;
56
57#define TEE_BUFSIZE 8192
58
59extern int interrupt_immediately;
60
61extern char *strerror ();
62
63tee_builtin (list)
64 WORD_LIST *list;
65{
66 int opt, append, nointr, rval, fd, fflags;
67 int n, nr, nw;
68 FLIST *fl;
69 char *buf, *bp;
70
71 char *t;
72
73 reset_internal_getopt ();
74 append = nointr = 0;
75 tee_flist = (FLIST *)NULL;
76 while ((opt = internal_getopt (list, "ai")) != -1)
77 {
78 switch (opt)
79 {
80 case 'a':
81 append = 1;
82 break;
83 case 'i':
84 nointr = 1;
85 break;
86 default:
87 builtin_usage ();
88 return (EX_USAGE);
89 }
90 }
91 list = loptend;
92
93 if (nointr == 0)
94 interrupt_immediately++;
95
96 buf = xmalloc (TEE_BUFSIZE);
97
98 /* Initialize output file list. */
99 fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST));
100 tee_flist->fd = 1;
101 tee_flist->fname = "stdout";
102 tee_flist->next = (FLIST *)NULL;
103
104 /* Add file arguments to list of output files. */
105 fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC;
106 for (rval = EXECUTION_SUCCESS; list; list = list->next)
107 {
108 fd = open (list->word->word, fflags, 0666);
109 if (fd < 0)
110 {
111 builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno));
112 rval = EXECUTION_FAILURE;
113 }
114 else
115 {
116 fl->next = (FLIST *)xmalloc (sizeof(FLIST));
117 fl->next->fd = fd;
118 fl->next->fname = list->word->word;
119 fl = fl->next;
120 fl->next = (FLIST *)NULL;
121 }
122 }
123
124 while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
125 for (fl = tee_flist; fl; fl = fl->next)
126 {
127 n = nr;
128 bp = buf;
129 do
130 {
131 if ((nw = write (fl->fd, bp, n)) == -1)
132 {
133 builtin_error ("%s: write error: %s", fl->fname, strerror (errno));
134 rval = EXECUTION_FAILURE;
135 break;
136 }
137 bp += nw;
138 }
139 while (n -= nw);
140 }
141 if (nr < 0)
142 builtin_error ("read error: %s", strerror (errno));
143
144 /* Deallocate resources -- this is a builtin command. */
145 tee_flist = tee_flist->next; /* skip bogus close of stdout */
146 while (tee_flist)
147 {
148 fl = tee_flist;
149 if (close (fl->fd) < 0)
150 {
151 builtin_error ("%s: close_error: %s", fl->fname, strerror (errno));
152 rval = EXECUTION_FAILURE;
153 }
154 tee_flist = tee_flist->next;
155 free (fl);
156 }
157
158 return (rval);
159}
160
161char *tee_doc[] = {
Jari Aalto31859422009-01-12 13:36:28 +0000162 "Duplicate standard output.",
163 "",
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000164 "Copy standard input to standard output, making a copy in each",
165 "filename argument. If the `-a' option is gived, the specified",
166 "files are appended to, otherwise they are overwritten. If the",
167 "`-i' option is supplied, tee ignores interrupts.",
168 (char *)NULL
169};
170
171struct builtin tee_struct = {
172 "tee", /* builtin name */
173 tee_builtin, /* function implementing the builtin */
174 BUILTIN_ENABLED, /* initial flags for builtin */
175 tee_doc, /* array of long documentation strings. */
176 "tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */
177 0 /* reserved for internal use */
178};