139422Sbostic /* 239422Sbostic * Copyright (c) 1989 The Regents of the University of California. 339422Sbostic * All rights reserved. 439422Sbostic * 539422Sbostic * Redistribution and use in source and binary forms are permitted 639422Sbostic * provided that the above copyright notice and this paragraph are 739422Sbostic * duplicated in all such forms and that any documentation, 839422Sbostic * advertising materials, and other materials related to such 939422Sbostic * distribution and use acknowledge that the software was developed 1039422Sbostic * by the University of California, Berkeley. The name of the 1139422Sbostic * University may not be used to endorse or promote products derived 1239422Sbostic * from this software without specific prior written permission. 1339422Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1439422Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1539422Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1639422Sbostic */ 1739422Sbostic 1839422Sbostic #ifndef lint 19*44590Smarc static char sccsid[] = "@(#)ttymsg.c 5.5 (Berkeley) 06/29/90"; 2039422Sbostic #endif /* not lint */ 2139422Sbostic 2239422Sbostic #include <sys/types.h> 2339422Sbostic #include <sys/uio.h> 2439422Sbostic #include <sys/file.h> 2539496Skarels #include <sys/signal.h> 2639422Sbostic #include <dirent.h> 2739422Sbostic #include <errno.h> 2839422Sbostic #include <paths.h> 29*44590Smarc #include <stdio.h> 3039422Sbostic 3139422Sbostic /* 3239422Sbostic * display the contents of a uio structure on a terminal. Used by 3339496Skarels * wall(1) and syslogd(8). Forks and finishes in child if write 3439496Skarels * would block, waiting at most five minutes. 3540222Skarels * Returns pointer to error string on unexpected error; 3640222Skarels * string is not newline-terminated. Various "normal" errors 3740222Skarels * are ignored (exclusive-use, lack of permission, etc.). 3839422Sbostic */ 3939422Sbostic char * 40*44590Smarc ttymsg(iov, iovcnt, line) 4139422Sbostic struct iovec *iov; 4239422Sbostic int iovcnt; 4339422Sbostic char *line; 4439422Sbostic { 4539422Sbostic extern int errno; 4639422Sbostic static char device[MAXNAMLEN] = _PATH_DEV; 4739422Sbostic static char errbuf[1024]; 48*44590Smarc register int cnt, fd, left, wret; 4939422Sbostic char *strcpy(), *strerror(); 50*44590Smarc struct iovec localiov[6]; 51*44590Smarc int forked = 0; 5239422Sbostic 53*44590Smarc if (iovcnt > 6) 54*44590Smarc return ("too many iov's (change code in wall/ttymsg.c)"); 5539422Sbostic /* 5639422Sbostic * open will fail on slip lines or exclusive-use lines 5739422Sbostic * if not running as root; not an error. 5839422Sbostic */ 5939496Skarels (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); 60*44590Smarc if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { 6140221Skarels if (errno != EBUSY && errno != EACCES) { 6240221Skarels (void) sprintf(errbuf, "open %s: %s", device, 6339496Skarels strerror(errno)); 6439496Skarels return (errbuf); 6539496Skarels } else 6639496Skarels return (NULL); 67*44590Smarc } 6839422Sbostic 69*44590Smarc for (cnt = left = 0; cnt < iovcnt; ++cnt) 70*44590Smarc left += iov[cnt].iov_len; 7139422Sbostic 72*44590Smarc for (;;) { 73*44590Smarc if ((wret = writev(fd, iov, iovcnt)) < 0) { 7439422Sbostic if (errno == EWOULDBLOCK) { 75*44590Smarc int off = 0; 76*44590Smarc int cpid; 77*44590Smarc 78*44590Smarc if (forked) { 7939496Skarels (void) close(fd); 80*44590Smarc /* return ("already forked"); */ 81*44590Smarc /* "can't happen" */ 82*44590Smarc exit(1); 83*44590Smarc } 84*44590Smarc cpid = fork(); 85*44590Smarc if (cpid < 0) { 86*44590Smarc (void) sprintf(errbuf, "can't fork: %s", 87*44590Smarc strerror(errno)); 88*44590Smarc (void) close(fd); 89*44590Smarc return (errbuf); 90*44590Smarc } 91*44590Smarc if (cpid) { /* parent */ 92*44590Smarc (void) close(fd); 9339496Skarels return (NULL); 9439496Skarels } 95*44590Smarc forked++; 9639422Sbostic /* wait at most 5 minutes */ 9739496Skarels (void) signal(SIGALRM, SIG_DFL); 9839496Skarels (void) signal(SIGTERM, SIG_DFL); /* XXX */ 9939496Skarels (void) sigsetmask(0); 10039496Skarels (void) alarm((u_int)(60 * 5)); 101*44590Smarc (void) fcntl(fd, FNDELAY, &off); 102*44590Smarc continue; 10339422Sbostic } else { 10439422Sbostic /* 10539422Sbostic * we get ENODEV on a slip line if we're 10640222Skarels * running as root, and EIO if the line 10740222Skarels * just went away 10839422Sbostic */ 10940222Skarels if (errno == ENODEV || errno == EIO) 11039422Sbostic break; 11140221Skarels (void) sprintf(errbuf, "writing %s: %s", 11239496Skarels device, strerror(errno)); 11339496Skarels (void) close(fd); 11439496Skarels return (errbuf); 11539422Sbostic } 116*44590Smarc } 117*44590Smarc if (wret < left) { 118*44590Smarc left -= wret; 119*44590Smarc if (iov != localiov) { 120*44590Smarc bcopy(iov, localiov, 121*44590Smarc iovcnt * sizeof (struct iovec)); 122*44590Smarc iov = localiov; 123*44590Smarc } 12439422Sbostic for (cnt = 0; wret >= iov->iov_len; ++cnt) { 12539422Sbostic wret -= iov->iov_len; 12639422Sbostic ++iov; 12739422Sbostic --iovcnt; 12839422Sbostic } 12939422Sbostic if (wret) { 13039422Sbostic iov->iov_base += wret; 13139422Sbostic iov->iov_len -= wret; 13239422Sbostic } 133*44590Smarc } else 134*44590Smarc break; 135*44590Smarc } 136*44590Smarc if (forked) 137*44590Smarc exit(0); 13839496Skarels (void) close(fd); 13939496Skarels return (NULL); 14039422Sbostic } 141