xref: /freebsd/usr.bin/tee/tee.c (revision 0b8224d1cc9dc6c9778ba04a75b2c8d47e5d7481)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1988, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes  * are met:
109b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes  *    without specific prior written permission.
189b50d902SRodney W. Grimes  *
199b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes  * SUCH DAMAGE.
309b50d902SRodney W. Grimes  */
319b50d902SRodney W. Grimes 
32d33dad44SBaptiste Daroussin #include <sys/capsicum.h>
3341ba691fSPietro Cerutti #include <sys/queue.h>
349b50d902SRodney W. Grimes #include <sys/stat.h>
35d33dad44SBaptiste Daroussin #include <sys/types.h>
36d33dad44SBaptiste Daroussin 
37a4e3fc54SMariusz Zaborski #include <capsicum_helpers.h>
38c10d7afbSPhilippe Charnier #include <err.h>
39d33dad44SBaptiste Daroussin #include <errno.h>
409b50d902SRodney W. Grimes #include <fcntl.h>
41c10d7afbSPhilippe Charnier #include <signal.h>
429b50d902SRodney W. Grimes #include <stdio.h>
439b50d902SRodney W. Grimes #include <stdlib.h>
44821df508SXin LI #include <string.h>
45c10d7afbSPhilippe Charnier #include <unistd.h>
469b50d902SRodney W. Grimes 
4741ba691fSPietro Cerutti struct entry {
489b50d902SRodney W. Grimes 	int fd;
49c83caf7bSDavid Malone 	const char *name;
5041ba691fSPietro Cerutti 	STAILQ_ENTRY(entry) entries;
5141ba691fSPietro Cerutti };
5241ba691fSPietro Cerutti static STAILQ_HEAD(, entry) head = STAILQ_HEAD_INITIALIZER(head);
539b50d902SRodney W. Grimes 
5485528ab7SEd Schouten static void add(int, const char *);
55*cccdaf50SAlfonso Gregory static void usage(void) __dead2;
569b50d902SRodney W. Grimes 
579b50d902SRodney W. Grimes int
main(int argc,char * argv[])58f4ac32deSDavid Malone main(int argc, char *argv[])
599b50d902SRodney W. Grimes {
6041ba691fSPietro Cerutti 	struct entry *p;
61f4ac32deSDavid Malone 	int n, fd, rval, wval;
62f4ac32deSDavid Malone 	char *bp;
639b50d902SRodney W. Grimes 	int append, ch, exitval;
649b50d902SRodney W. Grimes 	char *buf;
659b50d902SRodney W. Grimes #define	BSIZE (8 * 1024)
669b50d902SRodney W. Grimes 
679b50d902SRodney W. Grimes 	append = 0;
681c8af878SWarner Losh 	while ((ch = getopt(argc, argv, "ai")) != -1)
699b50d902SRodney W. Grimes 		switch((char)ch) {
709b50d902SRodney W. Grimes 		case 'a':
719b50d902SRodney W. Grimes 			append = 1;
729b50d902SRodney W. Grimes 			break;
739b50d902SRodney W. Grimes 		case 'i':
749b50d902SRodney W. Grimes 			(void)signal(SIGINT, SIG_IGN);
759b50d902SRodney W. Grimes 			break;
769b50d902SRodney W. Grimes 		case '?':
779b50d902SRodney W. Grimes 		default:
78c10d7afbSPhilippe Charnier 			usage();
799b50d902SRodney W. Grimes 		}
809b50d902SRodney W. Grimes 	argv += optind;
819b50d902SRodney W. Grimes 	argc -= optind;
829b50d902SRodney W. Grimes 
83307a7436SJuli Mallett 	if ((buf = malloc(BSIZE)) == NULL)
847dd4ac68STim J. Robbins 		err(1, "malloc");
859b50d902SRodney W. Grimes 
86a4e3fc54SMariusz Zaborski 	if (caph_limit_stdin() == -1 || caph_limit_stderr() == -1)
87a4e3fc54SMariusz Zaborski 		err(EXIT_FAILURE, "unable to limit stdio");
88d33dad44SBaptiste Daroussin 
899b50d902SRodney W. Grimes 	add(STDOUT_FILENO, "stdout");
909b50d902SRodney W. Grimes 
919b50d902SRodney W. Grimes 	for (exitval = 0; *argv; ++argv)
929b50d902SRodney W. Grimes 		if ((fd = open(*argv, append ? O_WRONLY|O_CREAT|O_APPEND :
939b50d902SRodney W. Grimes 		    O_WRONLY|O_CREAT|O_TRUNC, DEFFILEMODE)) < 0) {
94c10d7afbSPhilippe Charnier 			warn("%s", *argv);
959b50d902SRodney W. Grimes 			exitval = 1;
969b50d902SRodney W. Grimes 		} else
979b50d902SRodney W. Grimes 			add(fd, *argv);
989b50d902SRodney W. Grimes 
997672a014SMariusz Zaborski 	if (caph_enter() < 0)
100d33dad44SBaptiste Daroussin 		err(EXIT_FAILURE, "unable to enter capability mode");
1019b50d902SRodney W. Grimes 	while ((rval = read(STDIN_FILENO, buf, BSIZE)) > 0)
10241ba691fSPietro Cerutti 		STAILQ_FOREACH(p, &head, entries) {
1039b50d902SRodney W. Grimes 			n = rval;
1049b50d902SRodney W. Grimes 			bp = buf;
1059b50d902SRodney W. Grimes 			do {
1069b50d902SRodney W. Grimes 				if ((wval = write(p->fd, bp, n)) == -1) {
107c10d7afbSPhilippe Charnier 					warn("%s", p->name);
1089b50d902SRodney W. Grimes 					exitval = 1;
1099b50d902SRodney W. Grimes 					break;
1109b50d902SRodney W. Grimes 				}
1119b50d902SRodney W. Grimes 				bp += wval;
1129b50d902SRodney W. Grimes 			} while (n -= wval);
1139b50d902SRodney W. Grimes 		}
1149b50d902SRodney W. Grimes 	if (rval < 0)
115c10d7afbSPhilippe Charnier 		err(1, "read");
116621e56b6SJuli Mallett 	exit(exitval);
1179b50d902SRodney W. Grimes }
1189b50d902SRodney W. Grimes 
119c10d7afbSPhilippe Charnier static void
usage(void)120f4ac32deSDavid Malone usage(void)
121c10d7afbSPhilippe Charnier {
122c10d7afbSPhilippe Charnier 	(void)fprintf(stderr, "usage: tee [-ai] [file ...]\n");
123c10d7afbSPhilippe Charnier 	exit(1);
124c10d7afbSPhilippe Charnier }
125c10d7afbSPhilippe Charnier 
12685528ab7SEd Schouten static void
add(int fd,const char * name)127f4ac32deSDavid Malone add(int fd, const char *name)
1289b50d902SRodney W. Grimes {
12941ba691fSPietro Cerutti 	struct entry *p;
130d33dad44SBaptiste Daroussin 	cap_rights_t rights;
131d33dad44SBaptiste Daroussin 
132a4e3fc54SMariusz Zaborski 	if (fd == STDOUT_FILENO) {
133a4e3fc54SMariusz Zaborski 		if (caph_limit_stdout() == -1)
134a4e3fc54SMariusz Zaborski 			err(EXIT_FAILURE, "unable to limit stdout");
135a4e3fc54SMariusz Zaborski 	} else {
136d33dad44SBaptiste Daroussin 		cap_rights_init(&rights, CAP_WRITE, CAP_FSTAT);
137377421dfSMariusz Zaborski 		if (caph_rights_limit(fd, &rights) < 0)
138d33dad44SBaptiste Daroussin 			err(EXIT_FAILURE, "unable to limit rights");
139d33dad44SBaptiste Daroussin 	}
1409b50d902SRodney W. Grimes 
14141ba691fSPietro Cerutti 	if ((p = malloc(sizeof(struct entry))) == NULL)
1427dd4ac68STim J. Robbins 		err(1, "malloc");
1439b50d902SRodney W. Grimes 	p->fd = fd;
1449b50d902SRodney W. Grimes 	p->name = name;
14541ba691fSPietro Cerutti 	STAILQ_INSERT_HEAD(&head, p, entries);
1469b50d902SRodney W. Grimes }
147