1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)ttymsg.c 8.1 (Berkeley) 06/06/93"; 10 #endif /* not lint */ 11 12 #include <sys/types.h> 13 #include <sys/uio.h> 14 #include <signal.h> 15 #include <fcntl.h> 16 #include <dirent.h> 17 #include <errno.h> 18 #include <paths.h> 19 #include <unistd.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <stdlib.h> 23 24 /* 25 * Display the contents of a uio structure on a terminal. Used by wall(1), 26 * syslogd(8), and talk(1). Forks and finishes in child if write would block, 27 * waiting up to tmout seconds. Returns pointer to error string on unexpected 28 * error; string is not newline-terminated. Various "normal" errors are 29 * ignored (exclusive-use, lack of permission, etc.). 30 */ 31 char * 32 ttymsg(iov, iovcnt, line, tmout) 33 struct iovec *iov; 34 int iovcnt; 35 char *line; 36 int tmout; 37 { 38 static char device[MAXNAMLEN] = _PATH_DEV; 39 static char errbuf[1024]; 40 register int cnt, fd, left, wret; 41 struct iovec localiov[6]; 42 int forked = 0; 43 44 if (iovcnt > 6) 45 return ("too many iov's (change code in wall/ttymsg.c)"); 46 /* 47 * open will fail on slip lines or exclusive-use lines 48 * if not running as root; not an error. 49 */ 50 (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); 51 if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { 52 if (errno == EBUSY || errno == EACCES) 53 return (NULL); 54 (void) snprintf(errbuf, sizeof(errbuf), 55 "%s: %s", device, strerror(errno)); 56 return (errbuf); 57 } 58 59 for (cnt = left = 0; cnt < iovcnt; ++cnt) 60 left += iov[cnt].iov_len; 61 62 for (;;) { 63 wret = writev(fd, iov, iovcnt); 64 if (wret >= left) 65 break; 66 if (wret >= 0) { 67 left -= wret; 68 if (iov != localiov) { 69 bcopy(iov, localiov, 70 iovcnt * sizeof(struct iovec)); 71 iov = localiov; 72 } 73 for (cnt = 0; wret >= iov->iov_len; ++cnt) { 74 wret -= iov->iov_len; 75 ++iov; 76 --iovcnt; 77 } 78 if (wret) { 79 iov->iov_base += wret; 80 iov->iov_len -= wret; 81 } 82 continue; 83 } 84 if (errno == EWOULDBLOCK) { 85 int cpid, off = 0; 86 87 if (forked) { 88 (void) close(fd); 89 _exit(1); 90 } 91 cpid = fork(); 92 if (cpid < 0) { 93 (void) snprintf(errbuf, sizeof(errbuf), 94 "fork: %s", strerror(errno)); 95 (void) close(fd); 96 return (errbuf); 97 } 98 if (cpid) { /* parent */ 99 (void) close(fd); 100 return (NULL); 101 } 102 forked++; 103 /* wait at most tmout seconds */ 104 (void) signal(SIGALRM, SIG_DFL); 105 (void) signal(SIGTERM, SIG_DFL); /* XXX */ 106 (void) sigsetmask(0); 107 (void) alarm((u_int)tmout); 108 (void) fcntl(fd, O_NONBLOCK, &off); 109 continue; 110 } 111 /* 112 * We get ENODEV on a slip line if we're running as root, 113 * and EIO if the line just went away. 114 */ 115 if (errno == ENODEV || errno == EIO) 116 break; 117 (void) close(fd); 118 if (forked) 119 _exit(1); 120 (void) snprintf(errbuf, sizeof(errbuf), 121 "%s: %s", device, strerror(errno)); 122 return (errbuf); 123 } 124 125 (void) close(fd); 126 if (forked) 127 _exit(0); 128 return (NULL); 129 } 130