tee.c revision 307773
1214501Srpaulo/*
2214501Srpaulo * Copyright (c) 1988, 1993
3252726Srpaulo *	The Regents of the University of California.  All rights reserved.
4214501Srpaulo *
5252726Srpaulo * Redistribution and use in source and binary forms, with or without
6252726Srpaulo * modification, are permitted provided that the following conditions
7214501Srpaulo * are met:
8214501Srpaulo * 1. Redistributions of source code must retain the above copyright
9214501Srpaulo *    notice, this list of conditions and the following disclaimer.
10214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
11214501Srpaulo *    notice, this list of conditions and the following disclaimer in the
12214501Srpaulo *    documentation and/or other materials provided with the distribution.
13214501Srpaulo * 4. Neither the name of the University nor the names of its contributors
14214501Srpaulo *    may be used to endorse or promote products derived from this software
15214501Srpaulo *    without specific prior written permission.
16214501Srpaulo *
17214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20214501Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21214501Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22252726Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25252726Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27214501Srpaulo * SUCH DAMAGE.
28214501Srpaulo */
29214501Srpaulo
30214501Srpaulo#ifndef lint
31214501Srpaulostatic const char copyright[] =
32214501Srpaulo"@(#) Copyright (c) 1988, 1993\n\
33214501Srpaulo	The Regents of the University of California.  All rights reserved.\n";
34214501Srpaulo#endif /* not lint */
35214501Srpaulo
36214501Srpaulo#ifndef lint
37214501Srpaulo#if 0
38252726Srpaulostatic char sccsid[] = "@(#)tee.c	8.1 (Berkeley) 6/6/93";
39252726Srpaulo#endif
40252726Srpaulostatic const char rcsid[] =
41252726Srpaulo  "$FreeBSD: stable/11/usr.bin/tee/tee.c 307773 2016-10-22 13:20:02Z bapt $";
42214501Srpaulo#endif /* not lint */
43281806Srpaulo
44214501Srpaulo#include <sys/capsicum.h>
45214501Srpaulo#include <sys/stat.h>
46252726Srpaulo#include <sys/types.h>
47252726Srpaulo
48252726Srpaulo#include <err.h>
49281806Srpaulo#include <errno.h>
50252726Srpaulo#include <fcntl.h>
51252726Srpaulo#include <signal.h>
52252726Srpaulo#include <stdio.h>
53252726Srpaulo#include <stdlib.h>
54252726Srpaulo#include <string.h>
55252726Srpaulo#include <termios.h>
56252726Srpaulo#include <unistd.h>
57252726Srpaulo
58252726Srpaulotypedef struct _list {
59252726Srpaulo	struct _list *next;
60252726Srpaulo	int fd;
61252726Srpaulo	const char *name;
62281806Srpaulo} LIST;
63281806Srpaulostatic LIST *head;
64281806Srpaulo
65281806Srpaulostatic void add(int, const char *);
66281806Srpaulostatic void usage(void);
67281806Srpaulo
68281806Srpauloint
69281806Srpaulomain(int argc, char *argv[])
70252726Srpaulo{
71252726Srpaulo	LIST *p;
72252726Srpaulo	int n, fd, rval, wval;
73252726Srpaulo	char *bp;
74252726Srpaulo	int append, ch, exitval;
75252726Srpaulo	char *buf;
76252726Srpaulo	cap_rights_t rights;
77252726Srpaulo	unsigned long cmd;
78252726Srpaulo#define	BSIZE (8 * 1024)
79252726Srpaulo
80252726Srpaulo	append = 0;
81252726Srpaulo	while ((ch = getopt(argc, argv, "ai")) != -1)
82252726Srpaulo		switch((char)ch) {
83252726Srpaulo		case 'a':
84252726Srpaulo			append = 1;
85252726Srpaulo			break;
86281806Srpaulo		case 'i':
87252726Srpaulo			(void)signal(SIGINT, SIG_IGN);
88252726Srpaulo			break;
89252726Srpaulo		case '?':
90252726Srpaulo		default:
91252726Srpaulo			usage();
92252726Srpaulo		}
93252726Srpaulo	argv += optind;
94252726Srpaulo	argc -= optind;
95281806Srpaulo
96281806Srpaulo	if ((buf = malloc(BSIZE)) == NULL)
97214501Srpaulo		err(1, "malloc");
98214501Srpaulo
99214501Srpaulo	cap_rights_init(&rights, CAP_READ, CAP_FSTAT);
100214501Srpaulo	if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
101214501Srpaulo		err(EXIT_FAILURE, "unable to limit rights for stdin");
102214501Srpaulo	cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT, CAP_IOCTL);
103281806Srpaulo	if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
104281806Srpaulo		err(EXIT_FAILURE, "unable to limit rights for stderr");
105281806Srpaulo	cmd = TIOCGETA;
106281806Srpaulo	if (cap_ioctls_limit(STDERR_FILENO, &cmd, 1) < 0 && errno != ENOSYS)
107281806Srpaulo		err(EXIT_FAILURE, "unable to limit ioctls for stderr");
108281806Srpaulo
109281806Srpaulo	add(STDOUT_FILENO, "stdout");
110281806Srpaulo
111281806Srpaulo	for (exitval = 0; *argv; ++argv)
112281806Srpaulo		if ((fd = open(*argv, append ? O_WRONLY|O_CREAT|O_APPEND :
113214501Srpaulo		    O_WRONLY|O_CREAT|O_TRUNC, DEFFILEMODE)) < 0) {
114214501Srpaulo			warn("%s", *argv);
115214501Srpaulo			exitval = 1;
116214501Srpaulo		} else
117214501Srpaulo			add(fd, *argv);
118214501Srpaulo
119214501Srpaulo	if (cap_enter() < 0 && errno != ENOSYS)
120214501Srpaulo		err(EXIT_FAILURE, "unable to enter capability mode");
121214501Srpaulo	while ((rval = read(STDIN_FILENO, buf, BSIZE)) > 0)
122214501Srpaulo		for (p = head; p; p = p->next) {
123214501Srpaulo			n = rval;
124214501Srpaulo			bp = buf;
125214501Srpaulo			do {
126281806Srpaulo				if ((wval = write(p->fd, bp, n)) == -1) {
127214501Srpaulo					warn("%s", p->name);
128214501Srpaulo					exitval = 1;
129281806Srpaulo					break;
130281806Srpaulo				}
131281806Srpaulo				bp += wval;
132281806Srpaulo			} while (n -= wval);
133281806Srpaulo		}
134214501Srpaulo	if (rval < 0)
135214501Srpaulo		err(1, "read");
136214501Srpaulo	exit(exitval);
137214501Srpaulo}
138214501Srpaulo
139214501Srpaulostatic void
140214501Srpaulousage(void)
141214501Srpaulo{
142214501Srpaulo	(void)fprintf(stderr, "usage: tee [-ai] [file ...]\n");
143214501Srpaulo	exit(1);
144214501Srpaulo}
145214501Srpaulo
146214501Srpaulostatic void
147214501Srpauloadd(int fd, const char *name)
148214501Srpaulo{
149214501Srpaulo	LIST *p;
150214501Srpaulo	cap_rights_t rights;
151214501Srpaulo	unsigned long cmd;
152214501Srpaulo
153214501Srpaulo	if (fd == STDOUT_FILENO)
154214501Srpaulo		cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT, CAP_IOCTL);
155214501Srpaulo	else
156214501Srpaulo		cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT);
157214501Srpaulo	if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS)
158214501Srpaulo		err(EXIT_FAILURE, "unable to limit rights");
159214501Srpaulo
160214501Srpaulo	if (fd == STDOUT_FILENO) {
161214501Srpaulo		cmd = TIOCGETA;
162214501Srpaulo		if (cap_ioctls_limit(fd, &cmd, 1) < 0 && errno != ENOSYS)
163214501Srpaulo			err(EXIT_FAILURE, "unable to limit ioctls for stdout");
164214501Srpaulo	}
165252726Srpaulo
166252726Srpaulo	if ((p = malloc(sizeof(LIST))) == NULL)
167252726Srpaulo		err(1, "malloc");
168214501Srpaulo	p->fd = fd;
169214501Srpaulo	p->name = name;
170214501Srpaulo	p->next = head;
171214501Srpaulo	head = p;
172214501Srpaulo}
173214501Srpaulo