139422Sbostic /*
262435Sbostic * Copyright (c) 1989, 1993
362435Sbostic * The Regents of the University of California. All rights reserved.
439422Sbostic *
545220Sbostic * %sccs.include.redist.c%
639422Sbostic */
739422Sbostic
839422Sbostic #ifndef lint
9*64881Sbostic static char sccsid[] = "@(#)ttymsg.c 8.2 (Berkeley) 11/16/93";
1039422Sbostic #endif /* not lint */
1139422Sbostic
1239422Sbostic #include <sys/types.h>
1339422Sbostic #include <sys/uio.h>
1446663Sbostic #include <signal.h>
1546663Sbostic #include <fcntl.h>
1639422Sbostic #include <dirent.h>
1739422Sbostic #include <errno.h>
1839422Sbostic #include <paths.h>
1946663Sbostic #include <unistd.h>
2044590Smarc #include <stdio.h>
2146663Sbostic #include <string.h>
2246663Sbostic #include <stdlib.h>
2339422Sbostic
2439422Sbostic /*
2550739Smarc * Display the contents of a uio structure on a terminal. Used by wall(1),
26*64881Sbostic * syslogd(8), and talkd(8). Forks and finishes in child if write would block,
27*64881Sbostic * waiting up to tmout seconds. Returns pointer to error string on unexpected
28*64881Sbostic * error; string is not newline-terminated. Various "normal" errors are
2950739Smarc * ignored (exclusive-use, lack of permission, etc.).
3039422Sbostic */
3139422Sbostic char *
ttymsg(iov,iovcnt,line,tmout)3250739Smarc ttymsg(iov, iovcnt, line, tmout)
3339422Sbostic struct iovec *iov;
3439422Sbostic int iovcnt;
3539422Sbostic char *line;
3650739Smarc int tmout;
3739422Sbostic {
3839422Sbostic static char device[MAXNAMLEN] = _PATH_DEV;
3939422Sbostic static char errbuf[1024];
4044590Smarc register int cnt, fd, left, wret;
4144590Smarc struct iovec localiov[6];
4244590Smarc int forked = 0;
4339422Sbostic
44*64881Sbostic if (iovcnt > sizeof(localiov) / sizeof(localiov[0]))
4544590Smarc return ("too many iov's (change code in wall/ttymsg.c)");
46*64881Sbostic
47*64881Sbostic (void) strcpy(device + sizeof(_PATH_DEV) - 1, line);
48*64881Sbostic if (strchr(device + sizeof(_PATH_DEV) - 1, '/')) {
49*64881Sbostic /* A slash is an attempt to break security... */
50*64881Sbostic (void) snprintf(errbuf, sizeof(errbuf), "'/' in \"%s\"",
51*64881Sbostic device);
52*64881Sbostic return (errbuf);
53*64881Sbostic }
54*64881Sbostic
5539422Sbostic /*
5639422Sbostic * open will fail on slip lines or exclusive-use lines
5739422Sbostic * if not running as root; not an error.
5839422Sbostic */
5944590Smarc if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
6046663Sbostic if (errno == EBUSY || errno == EACCES)
6139496Skarels return (NULL);
6246663Sbostic (void) snprintf(errbuf, sizeof(errbuf),
6346663Sbostic "%s: %s", device, strerror(errno));
6446663Sbostic return (errbuf);
6544590Smarc }
6639422Sbostic
6744590Smarc for (cnt = left = 0; cnt < iovcnt; ++cnt)
6844590Smarc left += iov[cnt].iov_len;
6939422Sbostic
7044590Smarc for (;;) {
7146663Sbostic wret = writev(fd, iov, iovcnt);
7246663Sbostic if (wret >= left)
7346663Sbostic break;
7446663Sbostic if (wret >= 0) {
7544590Smarc left -= wret;
7644590Smarc if (iov != localiov) {
77*64881Sbostic bcopy(iov, localiov,
7846663Sbostic iovcnt * sizeof(struct iovec));
7944590Smarc iov = localiov;
8044590Smarc }
8139422Sbostic for (cnt = 0; wret >= iov->iov_len; ++cnt) {
8239422Sbostic wret -= iov->iov_len;
8339422Sbostic ++iov;
8439422Sbostic --iovcnt;
8539422Sbostic }
8639422Sbostic if (wret) {
8739422Sbostic iov->iov_base += wret;
8839422Sbostic iov->iov_len -= wret;
8939422Sbostic }
9046663Sbostic continue;
9146663Sbostic }
9246663Sbostic if (errno == EWOULDBLOCK) {
9346663Sbostic int cpid, off = 0;
9446663Sbostic
9546663Sbostic if (forked) {
9646663Sbostic (void) close(fd);
9746663Sbostic _exit(1);
9846663Sbostic }
9946663Sbostic cpid = fork();
10046663Sbostic if (cpid < 0) {
10146663Sbostic (void) snprintf(errbuf, sizeof(errbuf),
10246663Sbostic "fork: %s", strerror(errno));
10346663Sbostic (void) close(fd);
10446663Sbostic return (errbuf);
10546663Sbostic }
10646663Sbostic if (cpid) { /* parent */
10746663Sbostic (void) close(fd);
10846663Sbostic return (NULL);
10946663Sbostic }
11046663Sbostic forked++;
11150739Smarc /* wait at most tmout seconds */
11246663Sbostic (void) signal(SIGALRM, SIG_DFL);
11346663Sbostic (void) signal(SIGTERM, SIG_DFL); /* XXX */
11446663Sbostic (void) sigsetmask(0);
11550739Smarc (void) alarm((u_int)tmout);
11650347Sbostic (void) fcntl(fd, O_NONBLOCK, &off);
11746663Sbostic continue;
118*64881Sbostic }
11946663Sbostic /*
12046663Sbostic * We get ENODEV on a slip line if we're running as root,
12146663Sbostic * and EIO if the line just went away.
12246663Sbostic */
12346663Sbostic if (errno == ENODEV || errno == EIO)
12444590Smarc break;
12546663Sbostic (void) close(fd);
12646663Sbostic if (forked)
12746663Sbostic _exit(1);
12846663Sbostic (void) snprintf(errbuf, sizeof(errbuf),
12946663Sbostic "%s: %s", device, strerror(errno));
13046663Sbostic return (errbuf);
13144590Smarc }
13246663Sbostic
13346663Sbostic (void) close(fd);
13444590Smarc if (forked)
13546663Sbostic _exit(0);
13639496Skarels return (NULL);
13739422Sbostic }
138