1331722Seadler/* 21590Srgrimes * Copyright (c) 1989, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 3087675Smarkm#include <sys/cdefs.h> 3187675Smarkm 3287675Smarkm__FBSDID("$FreeBSD: stable/11/usr.bin/wall/ttymsg.c 335059 2018-06-13 13:41:23Z ed $"); 3387675Smarkm 341590Srgrimes#ifndef lint 3587675Smarkmstatic const char sccsid[] = "@(#)ttymsg.c 8.2 (Berkeley) 11/16/93"; 3634800Scharnier#endif 371590Srgrimes 381590Srgrimes#include <sys/types.h> 391590Srgrimes#include <sys/uio.h> 401590Srgrimes#include <dirent.h> 411590Srgrimes#include <errno.h> 4234800Scharnier#include <fcntl.h> 431590Srgrimes#include <paths.h> 4434800Scharnier#include <signal.h> 451590Srgrimes#include <stdio.h> 461590Srgrimes#include <string.h> 47200462Sdelphij#include <stdlib.h> 4834800Scharnier#include <unistd.h> 491590Srgrimes 5083242Sdd#include "ttymsg.h" 5183242Sdd 521590Srgrimes/* 531590Srgrimes * Display the contents of a uio structure on a terminal. Used by wall(1), 541590Srgrimes * syslogd(8), and talkd(8). Forks and finishes in child if write would block, 551590Srgrimes * waiting up to tmout seconds. Returns pointer to error string on unexpected 561590Srgrimes * error; string is not newline-terminated. Various "normal" errors are 571590Srgrimes * ignored (exclusive-use, lack of permission, etc.). 581590Srgrimes */ 5983242Sddconst char * 6073255Simpttymsg(struct iovec *iov, int iovcnt, const char *line, int tmout) 611590Srgrimes{ 62335059Sed struct iovec localiov[TTYMSG_IOV_MAX]; 6383242Sdd ssize_t left, wret; 6483242Sdd int cnt, fd; 65286268Spfg char device[MAXNAMLEN] = _PATH_DEV; 661590Srgrimes static char errbuf[1024]; 67154898Sume char *p; 6873255Simp int forked; 691590Srgrimes 7073255Simp forked = 0; 7183242Sdd if (iovcnt > (int)(sizeof(localiov) / sizeof(localiov[0]))) 721590Srgrimes return ("too many iov's (change code in wall/ttymsg.c)"); 731590Srgrimes 74286268Spfg strlcat(device, line, sizeof(device)); 75154898Sume p = device + sizeof(_PATH_DEV) - 1; 76154898Sume if (strncmp(p, "pts/", 4) == 0) 77154898Sume p += 4; 78154898Sume if (strchr(p, '/') != NULL) { 791590Srgrimes /* A slash is an attempt to break security... */ 8073255Simp (void) snprintf(errbuf, sizeof(errbuf), 8173255Simp "Too many '/' in \"%s\"", device); 821590Srgrimes return (errbuf); 831590Srgrimes } 841590Srgrimes 851590Srgrimes /* 861590Srgrimes * open will fail on slip lines or exclusive-use lines 871590Srgrimes * if not running as root; not an error. 881590Srgrimes */ 891590Srgrimes if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { 901590Srgrimes if (errno == EBUSY || errno == EACCES) 911590Srgrimes return (NULL); 9273255Simp (void) snprintf(errbuf, sizeof(errbuf), "%s: %s", device, 9373255Simp strerror(errno)); 941590Srgrimes return (errbuf); 951590Srgrimes } 961590Srgrimes 9783242Sdd for (cnt = 0, left = 0; cnt < iovcnt; ++cnt) 981590Srgrimes left += iov[cnt].iov_len; 991590Srgrimes 1001590Srgrimes for (;;) { 1011590Srgrimes wret = writev(fd, iov, iovcnt); 1021590Srgrimes if (wret >= left) 1031590Srgrimes break; 1041590Srgrimes if (wret >= 0) { 1051590Srgrimes left -= wret; 1061590Srgrimes if (iov != localiov) { 10773255Simp bcopy(iov, localiov, 1081590Srgrimes iovcnt * sizeof(struct iovec)); 1091590Srgrimes iov = localiov; 1101590Srgrimes } 11183242Sdd for (cnt = 0; (size_t)wret >= iov->iov_len; ++cnt) { 1121590Srgrimes wret -= iov->iov_len; 1131590Srgrimes ++iov; 1141590Srgrimes --iovcnt; 1151590Srgrimes } 1161590Srgrimes if (wret) { 117104908Smike iov->iov_base = (char *)iov->iov_base + wret; 1181590Srgrimes iov->iov_len -= wret; 1191590Srgrimes } 1201590Srgrimes continue; 1211590Srgrimes } 1221590Srgrimes if (errno == EWOULDBLOCK) { 12361464Sghelmer int cpid; 1241590Srgrimes 1251590Srgrimes if (forked) { 1261590Srgrimes (void) close(fd); 1271590Srgrimes _exit(1); 1281590Srgrimes } 1291590Srgrimes cpid = fork(); 1301590Srgrimes if (cpid < 0) { 1311590Srgrimes (void) snprintf(errbuf, sizeof(errbuf), 1321590Srgrimes "fork: %s", strerror(errno)); 1331590Srgrimes (void) close(fd); 1341590Srgrimes return (errbuf); 1351590Srgrimes } 1361590Srgrimes if (cpid) { /* parent */ 1371590Srgrimes (void) close(fd); 1381590Srgrimes return (NULL); 1391590Srgrimes } 1401590Srgrimes forked++; 1411590Srgrimes /* wait at most tmout seconds */ 1421590Srgrimes (void) signal(SIGALRM, SIG_DFL); 1431590Srgrimes (void) signal(SIGTERM, SIG_DFL); /* XXX */ 1441590Srgrimes (void) sigsetmask(0); 1451590Srgrimes (void) alarm((u_int)tmout); 14661464Sghelmer (void) fcntl(fd, F_SETFL, 0); /* clear O_NONBLOCK */ 1471590Srgrimes continue; 1481590Srgrimes } 1491590Srgrimes /* 1501590Srgrimes * We get ENODEV on a slip line if we're running as root, 1511590Srgrimes * and EIO if the line just went away. 1521590Srgrimes */ 1531590Srgrimes if (errno == ENODEV || errno == EIO) 1541590Srgrimes break; 1551590Srgrimes (void) close(fd); 1561590Srgrimes if (forked) 1571590Srgrimes _exit(1); 1581590Srgrimes (void) snprintf(errbuf, sizeof(errbuf), 1591590Srgrimes "%s: %s", device, strerror(errno)); 1601590Srgrimes return (errbuf); 1611590Srgrimes } 1621590Srgrimes 1631590Srgrimes (void) close(fd); 1641590Srgrimes if (forked) 1651590Srgrimes _exit(0); 1661590Srgrimes return (NULL); 1671590Srgrimes} 168