139422Sbostic /* 2*62435Sbostic * Copyright (c) 1989, 1993 3*62435Sbostic * The Regents of the University of California. All rights reserved. 439422Sbostic * 545220Sbostic * %sccs.include.redist.c% 639422Sbostic */ 739422Sbostic 839422Sbostic #ifndef lint 9*62435Sbostic static char sccsid[] = "@(#)ttymsg.c 8.1 (Berkeley) 06/06/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), 2650739Smarc * syslogd(8), and talk(1). Forks and finishes in child if write would block, 2750739Smarc * waiting up to tmout seconds. Returns pointer to error string on unexpected 2850739Smarc * error; string is not newline-terminated. Various "normal" errors are 2950739Smarc * ignored (exclusive-use, lack of permission, etc.). 3039422Sbostic */ 3139422Sbostic char * 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 4444590Smarc if (iovcnt > 6) 4544590Smarc return ("too many iov's (change code in wall/ttymsg.c)"); 4639422Sbostic /* 4739422Sbostic * open will fail on slip lines or exclusive-use lines 4839422Sbostic * if not running as root; not an error. 4939422Sbostic */ 5039496Skarels (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); 5144590Smarc if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { 5246663Sbostic if (errno == EBUSY || errno == EACCES) 5339496Skarels return (NULL); 5446663Sbostic (void) snprintf(errbuf, sizeof(errbuf), 5546663Sbostic "%s: %s", device, strerror(errno)); 5646663Sbostic return (errbuf); 5744590Smarc } 5839422Sbostic 5944590Smarc for (cnt = left = 0; cnt < iovcnt; ++cnt) 6044590Smarc left += iov[cnt].iov_len; 6139422Sbostic 6244590Smarc for (;;) { 6346663Sbostic wret = writev(fd, iov, iovcnt); 6446663Sbostic if (wret >= left) 6546663Sbostic break; 6646663Sbostic if (wret >= 0) { 6744590Smarc left -= wret; 6844590Smarc if (iov != localiov) { 6944590Smarc bcopy(iov, localiov, 7046663Sbostic iovcnt * sizeof(struct iovec)); 7144590Smarc iov = localiov; 7244590Smarc } 7339422Sbostic for (cnt = 0; wret >= iov->iov_len; ++cnt) { 7439422Sbostic wret -= iov->iov_len; 7539422Sbostic ++iov; 7639422Sbostic --iovcnt; 7739422Sbostic } 7839422Sbostic if (wret) { 7939422Sbostic iov->iov_base += wret; 8039422Sbostic iov->iov_len -= wret; 8139422Sbostic } 8246663Sbostic continue; 8346663Sbostic } 8446663Sbostic if (errno == EWOULDBLOCK) { 8546663Sbostic int cpid, off = 0; 8646663Sbostic 8746663Sbostic if (forked) { 8846663Sbostic (void) close(fd); 8946663Sbostic _exit(1); 9046663Sbostic } 9146663Sbostic cpid = fork(); 9246663Sbostic if (cpid < 0) { 9346663Sbostic (void) snprintf(errbuf, sizeof(errbuf), 9446663Sbostic "fork: %s", strerror(errno)); 9546663Sbostic (void) close(fd); 9646663Sbostic return (errbuf); 9746663Sbostic } 9846663Sbostic if (cpid) { /* parent */ 9946663Sbostic (void) close(fd); 10046663Sbostic return (NULL); 10146663Sbostic } 10246663Sbostic forked++; 10350739Smarc /* wait at most tmout seconds */ 10446663Sbostic (void) signal(SIGALRM, SIG_DFL); 10546663Sbostic (void) signal(SIGTERM, SIG_DFL); /* XXX */ 10646663Sbostic (void) sigsetmask(0); 10750739Smarc (void) alarm((u_int)tmout); 10850347Sbostic (void) fcntl(fd, O_NONBLOCK, &off); 10946663Sbostic continue; 11046663Sbostic } 11146663Sbostic /* 11246663Sbostic * We get ENODEV on a slip line if we're running as root, 11346663Sbostic * and EIO if the line just went away. 11446663Sbostic */ 11546663Sbostic if (errno == ENODEV || errno == EIO) 11644590Smarc break; 11746663Sbostic (void) close(fd); 11846663Sbostic if (forked) 11946663Sbostic _exit(1); 12046663Sbostic (void) snprintf(errbuf, sizeof(errbuf), 12146663Sbostic "%s: %s", device, strerror(errno)); 12246663Sbostic return (errbuf); 12344590Smarc } 12446663Sbostic 12546663Sbostic (void) close(fd); 12644590Smarc if (forked) 12746663Sbostic _exit(0); 12839496Skarels return (NULL); 12939422Sbostic } 130