139422Sbostic /* 239422Sbostic * Copyright (c) 1989 The Regents of the University of California. 339422Sbostic * All rights reserved. 439422Sbostic * 545220Sbostic * %sccs.include.redist.c% 639422Sbostic */ 739422Sbostic 839422Sbostic #ifndef lint 9*50347Sbostic static char sccsid[] = "@(#)ttymsg.c 5.8 (Berkeley) 07/01/91"; 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 /* 2546663Sbostic * Display the contents of a uio structure on a terminal. Used by wall(1) 2646663Sbostic * and syslogd(8). Forks and finishes in child if write would block, waiting 2746663Sbostic * at most five minutes. Returns pointer to error string on unexpected error; 2846663Sbostic * string is not newline-terminated. Various "normal" errors are ignored 2946663Sbostic * (exclusive-use, lack of permission, etc.). 3039422Sbostic */ 3139422Sbostic char * 3244590Smarc ttymsg(iov, iovcnt, line) 3339422Sbostic struct iovec *iov; 3439422Sbostic int iovcnt; 3539422Sbostic char *line; 3639422Sbostic { 3739422Sbostic static char device[MAXNAMLEN] = _PATH_DEV; 3839422Sbostic static char errbuf[1024]; 3944590Smarc register int cnt, fd, left, wret; 4044590Smarc struct iovec localiov[6]; 4144590Smarc int forked = 0; 4239422Sbostic 4344590Smarc if (iovcnt > 6) 4444590Smarc return ("too many iov's (change code in wall/ttymsg.c)"); 4539422Sbostic /* 4639422Sbostic * open will fail on slip lines or exclusive-use lines 4739422Sbostic * if not running as root; not an error. 4839422Sbostic */ 4939496Skarels (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); 5044590Smarc if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { 5146663Sbostic if (errno == EBUSY || errno == EACCES) 5239496Skarels return (NULL); 5346663Sbostic (void) snprintf(errbuf, sizeof(errbuf), 5446663Sbostic "%s: %s", device, strerror(errno)); 5546663Sbostic return (errbuf); 5644590Smarc } 5739422Sbostic 5844590Smarc for (cnt = left = 0; cnt < iovcnt; ++cnt) 5944590Smarc left += iov[cnt].iov_len; 6039422Sbostic 6144590Smarc for (;;) { 6246663Sbostic wret = writev(fd, iov, iovcnt); 6346663Sbostic if (wret >= left) 6446663Sbostic break; 6546663Sbostic if (wret >= 0) { 6644590Smarc left -= wret; 6744590Smarc if (iov != localiov) { 6844590Smarc bcopy(iov, localiov, 6946663Sbostic iovcnt * sizeof(struct iovec)); 7044590Smarc iov = localiov; 7144590Smarc } 7239422Sbostic for (cnt = 0; wret >= iov->iov_len; ++cnt) { 7339422Sbostic wret -= iov->iov_len; 7439422Sbostic ++iov; 7539422Sbostic --iovcnt; 7639422Sbostic } 7739422Sbostic if (wret) { 7839422Sbostic iov->iov_base += wret; 7939422Sbostic iov->iov_len -= wret; 8039422Sbostic } 8146663Sbostic continue; 8246663Sbostic } 8346663Sbostic if (errno == EWOULDBLOCK) { 8446663Sbostic int cpid, off = 0; 8546663Sbostic 8646663Sbostic if (forked) { 8746663Sbostic (void) close(fd); 8846663Sbostic _exit(1); 8946663Sbostic } 9046663Sbostic cpid = fork(); 9146663Sbostic if (cpid < 0) { 9246663Sbostic (void) snprintf(errbuf, sizeof(errbuf), 9346663Sbostic "fork: %s", strerror(errno)); 9446663Sbostic (void) close(fd); 9546663Sbostic return (errbuf); 9646663Sbostic } 9746663Sbostic if (cpid) { /* parent */ 9846663Sbostic (void) close(fd); 9946663Sbostic return (NULL); 10046663Sbostic } 10146663Sbostic forked++; 10246663Sbostic /* wait at most 5 minutes */ 10346663Sbostic (void) signal(SIGALRM, SIG_DFL); 10446663Sbostic (void) signal(SIGTERM, SIG_DFL); /* XXX */ 10546663Sbostic (void) sigsetmask(0); 10646663Sbostic (void) alarm((u_int)(60 * 5)); 107*50347Sbostic (void) fcntl(fd, O_NONBLOCK, &off); 10846663Sbostic continue; 10946663Sbostic } 11046663Sbostic /* 11146663Sbostic * We get ENODEV on a slip line if we're running as root, 11246663Sbostic * and EIO if the line just went away. 11346663Sbostic */ 11446663Sbostic if (errno == ENODEV || errno == EIO) 11544590Smarc break; 11646663Sbostic (void) close(fd); 11746663Sbostic if (forked) 11846663Sbostic _exit(1); 11946663Sbostic (void) snprintf(errbuf, sizeof(errbuf), 12046663Sbostic "%s: %s", device, strerror(errno)); 12146663Sbostic return (errbuf); 12244590Smarc } 12346663Sbostic 12446663Sbostic (void) close(fd); 12544590Smarc if (forked) 12646663Sbostic _exit(0); 12739496Skarels return (NULL); 12839422Sbostic } 129