1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 static char sccsid[] = "@(#)ttymsg.c 5.5 (Berkeley) 06/29/90"; 20 #endif /* not lint */ 21 22 #include <sys/types.h> 23 #include <sys/uio.h> 24 #include <sys/file.h> 25 #include <sys/signal.h> 26 #include <dirent.h> 27 #include <errno.h> 28 #include <paths.h> 29 #include <stdio.h> 30 31 /* 32 * display the contents of a uio structure on a terminal. Used by 33 * wall(1) and syslogd(8). Forks and finishes in child if write 34 * would block, waiting at most five minutes. 35 * Returns pointer to error string on unexpected error; 36 * string is not newline-terminated. Various "normal" errors 37 * are ignored (exclusive-use, lack of permission, etc.). 38 */ 39 char * 40 ttymsg(iov, iovcnt, line) 41 struct iovec *iov; 42 int iovcnt; 43 char *line; 44 { 45 extern int errno; 46 static char device[MAXNAMLEN] = _PATH_DEV; 47 static char errbuf[1024]; 48 register int cnt, fd, left, wret; 49 char *strcpy(), *strerror(); 50 struct iovec localiov[6]; 51 int forked = 0; 52 53 if (iovcnt > 6) 54 return ("too many iov's (change code in wall/ttymsg.c)"); 55 /* 56 * open will fail on slip lines or exclusive-use lines 57 * if not running as root; not an error. 58 */ 59 (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); 60 if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { 61 if (errno != EBUSY && errno != EACCES) { 62 (void) sprintf(errbuf, "open %s: %s", device, 63 strerror(errno)); 64 return (errbuf); 65 } else 66 return (NULL); 67 } 68 69 for (cnt = left = 0; cnt < iovcnt; ++cnt) 70 left += iov[cnt].iov_len; 71 72 for (;;) { 73 if ((wret = writev(fd, iov, iovcnt)) < 0) { 74 if (errno == EWOULDBLOCK) { 75 int off = 0; 76 int cpid; 77 78 if (forked) { 79 (void) close(fd); 80 /* return ("already forked"); */ 81 /* "can't happen" */ 82 exit(1); 83 } 84 cpid = fork(); 85 if (cpid < 0) { 86 (void) sprintf(errbuf, "can't fork: %s", 87 strerror(errno)); 88 (void) close(fd); 89 return (errbuf); 90 } 91 if (cpid) { /* parent */ 92 (void) close(fd); 93 return (NULL); 94 } 95 forked++; 96 /* wait at most 5 minutes */ 97 (void) signal(SIGALRM, SIG_DFL); 98 (void) signal(SIGTERM, SIG_DFL); /* XXX */ 99 (void) sigsetmask(0); 100 (void) alarm((u_int)(60 * 5)); 101 (void) fcntl(fd, FNDELAY, &off); 102 continue; 103 } else { 104 /* 105 * we get ENODEV on a slip line if we're 106 * running as root, and EIO if the line 107 * just went away 108 */ 109 if (errno == ENODEV || errno == EIO) 110 break; 111 (void) sprintf(errbuf, "writing %s: %s", 112 device, strerror(errno)); 113 (void) close(fd); 114 return (errbuf); 115 } 116 } 117 if (wret < left) { 118 left -= wret; 119 if (iov != localiov) { 120 bcopy(iov, localiov, 121 iovcnt * sizeof (struct iovec)); 122 iov = localiov; 123 } 124 for (cnt = 0; wret >= iov->iov_len; ++cnt) { 125 wret -= iov->iov_len; 126 ++iov; 127 --iovcnt; 128 } 129 if (wret) { 130 iov->iov_base += wret; 131 iov->iov_len -= wret; 132 } 133 } else 134 break; 135 } 136 if (forked) 137 exit(0); 138 (void) close(fd); 139 return (NULL); 140 } 141