1*e4c12d7aSbluhm /* $OpenBSD: ttymsg.c,v 1.19 2021/09/03 16:28:33 bluhm Exp $ */
238182445Savsm /* $NetBSD: ttymsg.c,v 1.3 1994/11/17 07:17:55 jtc Exp $ */
338182445Savsm
438182445Savsm /*
53836e309Sbluhm * Copyright (c) 2014-2017 Alexander Bluhm <bluhm@genua.de>
63836e309Sbluhm *
73836e309Sbluhm * Permission to use, copy, modify, and distribute this software for any
83836e309Sbluhm * purpose with or without fee is hereby granted, provided that the above
93836e309Sbluhm * copyright notice and this permission notice appear in all copies.
103836e309Sbluhm *
113836e309Sbluhm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
123836e309Sbluhm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
133836e309Sbluhm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
143836e309Sbluhm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
153836e309Sbluhm * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
163836e309Sbluhm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
173836e309Sbluhm * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
183836e309Sbluhm */
193836e309Sbluhm
203836e309Sbluhm /*
2138182445Savsm * Copyright (c) 1989, 1993
2238182445Savsm * The Regents of the University of California. All rights reserved.
2338182445Savsm *
2438182445Savsm * Redistribution and use in source and binary forms, with or without
2538182445Savsm * modification, are permitted provided that the following conditions
2638182445Savsm * are met:
2738182445Savsm * 1. Redistributions of source code must retain the above copyright
2838182445Savsm * notice, this list of conditions and the following disclaimer.
2938182445Savsm * 2. Redistributions in binary form must reproduce the above copyright
3038182445Savsm * notice, this list of conditions and the following disclaimer in the
3138182445Savsm * documentation and/or other materials provided with the distribution.
3238182445Savsm * 3. Neither the name of the University nor the names of its contributors
3338182445Savsm * may be used to endorse or promote products derived from this software
3438182445Savsm * without specific prior written permission.
3538182445Savsm *
3638182445Savsm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3738182445Savsm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3838182445Savsm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3938182445Savsm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
4038182445Savsm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4138182445Savsm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4238182445Savsm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4338182445Savsm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4438182445Savsm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4538182445Savsm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4638182445Savsm * SUCH DAMAGE.
4738182445Savsm */
4838182445Savsm
4997e72a51Sbluhm #include <sys/stat.h>
50e868d397Sbluhm #include <sys/syslog.h>
5197e72a51Sbluhm
5238182445Savsm #include <dirent.h>
5338182445Savsm #include <errno.h>
54959a7adfSbluhm #include <event.h>
5538182445Savsm #include <paths.h>
56c65505c8Sbluhm #include <signal.h>
5738182445Savsm #include <stdio.h>
5838182445Savsm #include <stdlib.h>
59c65505c8Sbluhm #include <string.h>
60c65505c8Sbluhm #include <unistd.h>
6138182445Savsm
62ed00ae78Sbluhm #include "log.h"
6338182445Savsm #include "syslogd.h"
6438182445Savsm
65959a7adfSbluhm struct tty_delay {
66959a7adfSbluhm struct event td_event;
67959a7adfSbluhm size_t td_length;
68e868d397Sbluhm char td_line[LOG_MAXLINE];
69959a7adfSbluhm };
70959a7adfSbluhm int tty_delayed = 0;
71959a7adfSbluhm void ttycb(int, short, void *);
72959a7adfSbluhm
7338182445Savsm /*
7438182445Savsm * Display the contents of a uio structure on a terminal.
75959a7adfSbluhm * Schedules an event if write would block, waiting up to TTYMSGTIME
766545c74aSbluhm * seconds.
7738182445Savsm */
786545c74aSbluhm void
ttymsg(char * utline,struct iovec * iov)79*e4c12d7aSbluhm ttymsg(char *utline, struct iovec *iov)
8038182445Savsm {
8138182445Savsm static char device[MAXNAMLEN] = _PATH_DEV;
82*e4c12d7aSbluhm struct iovec localiov[IOVCNT];
83*e4c12d7aSbluhm int iovcnt = IOVCNT;
84c65505c8Sbluhm int cnt, fd;
85c65505c8Sbluhm size_t left;
8697e72a51Sbluhm ssize_t wret;
8738182445Savsm
8838182445Savsm /*
8938182445Savsm * Ignore lines that start with "ftp" or "uucp".
9038182445Savsm */
91c65505c8Sbluhm if ((strncmp(utline, "ftp", 3) == 0) ||
92c65505c8Sbluhm (strncmp(utline, "uucp", 4) == 0))
936545c74aSbluhm return;
9438182445Savsm
95c65505c8Sbluhm (void) strlcpy(device + sizeof(_PATH_DEV) - 1, utline,
9638182445Savsm sizeof(device) - (sizeof(_PATH_DEV) - 1));
9738182445Savsm if (strchr(device + sizeof(_PATH_DEV) - 1, '/')) {
9838182445Savsm /* A slash is an attempt to break security... */
996545c74aSbluhm log_warnx("'/' in tty device \"%s\"", device);
1006545c74aSbluhm return;
10138182445Savsm }
10238182445Savsm
10338182445Savsm /*
10438182445Savsm * open will fail on slip lines or exclusive-use lines
10538182445Savsm * if not running as root; not an error.
10638182445Savsm */
107df69c215Sderaadt if ((fd = priv_open_tty(device)) == -1) {
1086545c74aSbluhm if (errno != EBUSY && errno != EACCES)
1096545c74aSbluhm log_warn("priv_open_tty device \"%s\"", device);
1106545c74aSbluhm return;
11138182445Savsm }
11238182445Savsm
113c65505c8Sbluhm left = 0;
114c65505c8Sbluhm for (cnt = 0; cnt < iovcnt; ++cnt)
11538182445Savsm left += iov[cnt].iov_len;
11638182445Savsm
11738182445Savsm for (;;) {
11838182445Savsm wret = writev(fd, iov, iovcnt);
11938182445Savsm if (wret >= 0) {
120c65505c8Sbluhm if ((size_t)wret >= left)
121c65505c8Sbluhm break;
12238182445Savsm left -= wret;
12338182445Savsm if (iov != localiov) {
1247c4cfb82Sbluhm memmove(localiov, iov,
12538182445Savsm iovcnt * sizeof(struct iovec));
12638182445Savsm iov = localiov;
12738182445Savsm }
128c65505c8Sbluhm while ((size_t)wret >= iov->iov_len) {
12938182445Savsm wret -= iov->iov_len;
13038182445Savsm ++iov;
13138182445Savsm --iovcnt;
13238182445Savsm }
13338182445Savsm if (wret) {
134a4570f53Sdjm iov->iov_base = (char *)iov->iov_base + wret;
13538182445Savsm iov->iov_len -= wret;
13638182445Savsm }
13738182445Savsm continue;
13838182445Savsm }
13938182445Savsm if (errno == EWOULDBLOCK) {
140959a7adfSbluhm struct tty_delay *td;
141959a7adfSbluhm struct timeval to;
14238182445Savsm
143959a7adfSbluhm if (tty_delayed >= TTYMAXDELAY) {
1446545c74aSbluhm log_warnx("tty device \"%s\": %s",
1456545c74aSbluhm device, "too many delayed writes");
1466545c74aSbluhm break;
14738182445Savsm }
148ed00ae78Sbluhm log_debug("ttymsg delayed write");
149959a7adfSbluhm if (iov != localiov) {
1507c4cfb82Sbluhm memmove(localiov, iov,
151959a7adfSbluhm iovcnt * sizeof(struct iovec));
152959a7adfSbluhm iov = localiov;
15338182445Savsm }
154959a7adfSbluhm if ((td = malloc(sizeof(*td))) == NULL) {
1556545c74aSbluhm log_warn("allocate delay tty device \"%s\"",
1566545c74aSbluhm device);
1576545c74aSbluhm break;
158959a7adfSbluhm }
159959a7adfSbluhm td->td_length = 0;
160e868d397Sbluhm if (left > LOG_MAXLINE)
161e868d397Sbluhm left = LOG_MAXLINE;
162959a7adfSbluhm while (iovcnt && left) {
163959a7adfSbluhm if (iov->iov_len > left)
164959a7adfSbluhm iov->iov_len = left;
165959a7adfSbluhm memcpy(td->td_line + td->td_length,
166959a7adfSbluhm iov->iov_base, iov->iov_len);
167959a7adfSbluhm td->td_length += iov->iov_len;
168959a7adfSbluhm left -= iov->iov_len;
169959a7adfSbluhm ++iov;
170959a7adfSbluhm --iovcnt;
171959a7adfSbluhm }
172959a7adfSbluhm tty_delayed++;
173959a7adfSbluhm event_set(&td->td_event, fd, EV_WRITE, ttycb, td);
174959a7adfSbluhm to.tv_sec = TTYMSGTIME;
175959a7adfSbluhm to.tv_usec = 0;
176959a7adfSbluhm event_add(&td->td_event, &to);
1776545c74aSbluhm return;
17838182445Savsm }
17938182445Savsm /*
18038182445Savsm * We get ENODEV on a slip line if we're running as root,
18138182445Savsm * and EIO if the line just went away.
18238182445Savsm */
1836545c74aSbluhm if (errno != ENODEV && errno != EIO)
1846545c74aSbluhm log_warn("writev tty device \"%s\"", device);
18538182445Savsm break;
18638182445Savsm }
18738182445Savsm
18838182445Savsm (void) close(fd);
1896545c74aSbluhm return;
19038182445Savsm }
191959a7adfSbluhm
192959a7adfSbluhm void
ttycb(int fd,short event,void * arg)193959a7adfSbluhm ttycb(int fd, short event, void *arg)
194959a7adfSbluhm {
195959a7adfSbluhm struct tty_delay *td = arg;
196959a7adfSbluhm struct timeval to;
197959a7adfSbluhm ssize_t wret;
198959a7adfSbluhm
199959a7adfSbluhm if (event != EV_WRITE)
200959a7adfSbluhm goto done;
201959a7adfSbluhm
202959a7adfSbluhm wret = write(fd, td->td_line, td->td_length);
203df69c215Sderaadt if (wret == -1 && errno != EINTR && errno != EWOULDBLOCK)
204959a7adfSbluhm goto done;
205959a7adfSbluhm if (wret > 0) {
206959a7adfSbluhm td->td_length -= wret;
207959a7adfSbluhm if (td->td_length == 0)
208959a7adfSbluhm goto done;
209959a7adfSbluhm memmove(td->td_line, td->td_line + wret, td->td_length);
210959a7adfSbluhm }
211959a7adfSbluhm to.tv_sec = TTYMSGTIME;
212959a7adfSbluhm to.tv_usec = 0;
213959a7adfSbluhm event_add(&td->td_event, &to);
214959a7adfSbluhm return;
215959a7adfSbluhm
216959a7adfSbluhm done:
217959a7adfSbluhm tty_delayed--;
218959a7adfSbluhm close(fd);
219959a7adfSbluhm free(td);
220959a7adfSbluhm }
221