139422Sbostic /* 239422Sbostic * Copyright (c) 1989 The Regents of the University of California. 339422Sbostic * All rights reserved. 439422Sbostic * 5*45220Sbostic * %sccs.include.redist.c% 639422Sbostic */ 739422Sbostic 839422Sbostic #ifndef lint 9*45220Sbostic static char sccsid[] = "@(#)ttymsg.c 5.6 (Berkeley) 09/07/90"; 1039422Sbostic #endif /* not lint */ 1139422Sbostic 1239422Sbostic #include <sys/types.h> 1339422Sbostic #include <sys/uio.h> 1439422Sbostic #include <sys/file.h> 1539496Skarels #include <sys/signal.h> 1639422Sbostic #include <dirent.h> 1739422Sbostic #include <errno.h> 1839422Sbostic #include <paths.h> 1944590Smarc #include <stdio.h> 2039422Sbostic 2139422Sbostic /* 2239422Sbostic * display the contents of a uio structure on a terminal. Used by 2339496Skarels * wall(1) and syslogd(8). Forks and finishes in child if write 2439496Skarels * would block, waiting at most five minutes. 2540222Skarels * Returns pointer to error string on unexpected error; 2640222Skarels * string is not newline-terminated. Various "normal" errors 2740222Skarels * are ignored (exclusive-use, lack of permission, etc.). 2839422Sbostic */ 2939422Sbostic char * 3044590Smarc ttymsg(iov, iovcnt, line) 3139422Sbostic struct iovec *iov; 3239422Sbostic int iovcnt; 3339422Sbostic char *line; 3439422Sbostic { 3539422Sbostic extern int errno; 3639422Sbostic static char device[MAXNAMLEN] = _PATH_DEV; 3739422Sbostic static char errbuf[1024]; 3844590Smarc register int cnt, fd, left, wret; 3939422Sbostic char *strcpy(), *strerror(); 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) { 5140221Skarels if (errno != EBUSY && errno != EACCES) { 5240221Skarels (void) sprintf(errbuf, "open %s: %s", device, 5339496Skarels strerror(errno)); 5439496Skarels return (errbuf); 5539496Skarels } else 5639496Skarels return (NULL); 5744590Smarc } 5839422Sbostic 5944590Smarc for (cnt = left = 0; cnt < iovcnt; ++cnt) 6044590Smarc left += iov[cnt].iov_len; 6139422Sbostic 6244590Smarc for (;;) { 6344590Smarc if ((wret = writev(fd, iov, iovcnt)) < 0) { 6439422Sbostic if (errno == EWOULDBLOCK) { 6544590Smarc int off = 0; 6644590Smarc int cpid; 6744590Smarc 6844590Smarc if (forked) { 6939496Skarels (void) close(fd); 7044590Smarc /* return ("already forked"); */ 7144590Smarc /* "can't happen" */ 7244590Smarc exit(1); 7344590Smarc } 7444590Smarc cpid = fork(); 7544590Smarc if (cpid < 0) { 7644590Smarc (void) sprintf(errbuf, "can't fork: %s", 7744590Smarc strerror(errno)); 7844590Smarc (void) close(fd); 7944590Smarc return (errbuf); 8044590Smarc } 8144590Smarc if (cpid) { /* parent */ 8244590Smarc (void) close(fd); 8339496Skarels return (NULL); 8439496Skarels } 8544590Smarc forked++; 8639422Sbostic /* wait at most 5 minutes */ 8739496Skarels (void) signal(SIGALRM, SIG_DFL); 8839496Skarels (void) signal(SIGTERM, SIG_DFL); /* XXX */ 8939496Skarels (void) sigsetmask(0); 9039496Skarels (void) alarm((u_int)(60 * 5)); 9144590Smarc (void) fcntl(fd, FNDELAY, &off); 9244590Smarc continue; 9339422Sbostic } else { 9439422Sbostic /* 9539422Sbostic * we get ENODEV on a slip line if we're 9640222Skarels * running as root, and EIO if the line 9740222Skarels * just went away 9839422Sbostic */ 9940222Skarels if (errno == ENODEV || errno == EIO) 10039422Sbostic break; 10140221Skarels (void) sprintf(errbuf, "writing %s: %s", 10239496Skarels device, strerror(errno)); 10339496Skarels (void) close(fd); 10439496Skarels return (errbuf); 10539422Sbostic } 10644590Smarc } 10744590Smarc if (wret < left) { 10844590Smarc left -= wret; 10944590Smarc if (iov != localiov) { 11044590Smarc bcopy(iov, localiov, 11144590Smarc iovcnt * sizeof (struct iovec)); 11244590Smarc iov = localiov; 11344590Smarc } 11439422Sbostic for (cnt = 0; wret >= iov->iov_len; ++cnt) { 11539422Sbostic wret -= iov->iov_len; 11639422Sbostic ++iov; 11739422Sbostic --iovcnt; 11839422Sbostic } 11939422Sbostic if (wret) { 12039422Sbostic iov->iov_base += wret; 12139422Sbostic iov->iov_len -= wret; 12239422Sbostic } 12344590Smarc } else 12444590Smarc break; 12544590Smarc } 12644590Smarc if (forked) 12744590Smarc exit(0); 12839496Skarels (void) close(fd); 12939496Skarels return (NULL); 13039422Sbostic } 131