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