1/*	$OpenBSD: tee.c,v 1.15 2023/03/04 00:00:25 cheloha Exp $	*/
2/*	$NetBSD: tee.c,v 1.5 1994/12/09 01:43:39 jtc Exp $	*/
3
4/*
5 * Copyright (c) 1988, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/queue.h>
36
37#include <err.h>
38#include <errno.h>
39#include <fcntl.h>
40#include <signal.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46#define BSIZE (64 * 1024)
47
48struct list {
49	SLIST_ENTRY(list) next;
50	int fd;
51	char *name;
52};
53SLIST_HEAD(, list) head;
54
55static void
56add(int fd, char *name)
57{
58	struct list *p;
59
60	if ((p = malloc(sizeof(*p))) == NULL)
61		err(1, NULL);
62	p->fd = fd;
63	p->name = name;
64	SLIST_INSERT_HEAD(&head, p, next);
65}
66
67int
68main(int argc, char *argv[])
69{
70	struct list *p;
71	int fd;
72	ssize_t n, rval, wval;
73	int append, ch, exitval;
74	char *buf;
75
76	if (pledge("stdio wpath cpath", NULL) == -1)
77		err(1, "pledge");
78
79	SLIST_INIT(&head);
80
81	append = 0;
82	while ((ch = getopt(argc, argv, "ai")) != -1) {
83		switch(ch) {
84		case 'a':
85			append = 1;
86			break;
87		case 'i':
88			(void)signal(SIGINT, SIG_IGN);
89			break;
90		default:
91			(void)fprintf(stderr, "usage: tee [-ai] [file ...]\n");
92			return 1;
93		}
94	}
95	argv += optind;
96	argc -= optind;
97
98	add(STDOUT_FILENO, "stdout");
99
100	exitval = 0;
101	while (*argv) {
102		if ((fd = open(*argv, O_WRONLY | O_CREAT |
103		    (append ? O_APPEND : O_TRUNC), DEFFILEMODE)) == -1) {
104			warn("%s", *argv);
105			exitval = 1;
106		} else
107			add(fd, *argv);
108		argv++;
109	}
110
111	if (pledge("stdio", NULL) == -1)
112		err(1, "pledge");
113
114	buf = malloc(BSIZE);
115	if (buf == NULL)
116		err(1, NULL);
117	while ((rval = read(STDIN_FILENO, buf, BSIZE)) != 0 && rval != -1) {
118		SLIST_FOREACH(p, &head, next) {
119			for (n = 0; n < rval; n += wval) {
120				wval = write(p->fd, buf + n, rval - n);
121				if (wval == -1) {
122					warn("%s", p->name);
123					exitval = 1;
124					break;
125				}
126			}
127		}
128	}
129	free(buf);
130	if (rval == -1) {
131		warn("read");
132		exitval = 1;
133	}
134
135	SLIST_FOREACH(p, &head, next) {
136		if (close(p->fd) == -1) {
137			warn("%s", p->name);
138			exitval = 1;
139		}
140	}
141
142	return exitval;
143}
144