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