xref: /csrg-svn/usr.bin/wall/ttymsg.c (revision 45220)
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