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