xref: /csrg-svn/usr.bin/wall/ttymsg.c (revision 46663)
139422Sbostic /*
239422Sbostic  * Copyright (c) 1989 The Regents of the University of California.
339422Sbostic  * All rights reserved.
439422Sbostic  *
545220Sbostic  * %sccs.include.redist.c%
639422Sbostic  */
739422Sbostic 
839422Sbostic #ifndef lint
9*46663Sbostic static char sccsid[] = "@(#)ttymsg.c	5.7 (Berkeley) 02/25/91";
1039422Sbostic #endif /* not lint */
1139422Sbostic 
1239422Sbostic #include <sys/types.h>
1339422Sbostic #include <sys/uio.h>
14*46663Sbostic #include <signal.h>
15*46663Sbostic #include <fcntl.h>
1639422Sbostic #include <dirent.h>
1739422Sbostic #include <errno.h>
1839422Sbostic #include <paths.h>
19*46663Sbostic #include <unistd.h>
2044590Smarc #include <stdio.h>
21*46663Sbostic #include <string.h>
22*46663Sbostic #include <stdlib.h>
2339422Sbostic 
2439422Sbostic /*
25*46663Sbostic  * Display the contents of a uio structure on a terminal.  Used by wall(1)
26*46663Sbostic  * and syslogd(8).  Forks and finishes in child if write would block, waiting
27*46663Sbostic  * at most five minutes.  Returns pointer to error string on unexpected error;
28*46663Sbostic  * string is not newline-terminated.  Various "normal" errors are ignored
29*46663Sbostic  * (exclusive-use, lack of permission, etc.).
3039422Sbostic  */
3139422Sbostic char *
3244590Smarc ttymsg(iov, iovcnt, line)
3339422Sbostic 	struct iovec *iov;
3439422Sbostic 	int iovcnt;
3539422Sbostic 	char *line;
3639422Sbostic {
3739422Sbostic 	static char device[MAXNAMLEN] = _PATH_DEV;
3839422Sbostic 	static char errbuf[1024];
3944590Smarc 	register int cnt, fd, left, wret;
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) {
51*46663Sbostic 		if (errno == EBUSY || errno == EACCES)
5239496Skarels 			return (NULL);
53*46663Sbostic 		(void) snprintf(errbuf, sizeof(errbuf),
54*46663Sbostic 		    "%s: %s", device, strerror(errno));
55*46663Sbostic 		return (errbuf);
5644590Smarc 	}
5739422Sbostic 
5844590Smarc 	for (cnt = left = 0; cnt < iovcnt; ++cnt)
5944590Smarc 		left += iov[cnt].iov_len;
6039422Sbostic 
6144590Smarc 	for (;;) {
62*46663Sbostic 		wret = writev(fd, iov, iovcnt);
63*46663Sbostic 		if (wret >= left)
64*46663Sbostic 			break;
65*46663Sbostic 		if (wret >= 0) {
6644590Smarc 			left -= wret;
6744590Smarc 			if (iov != localiov) {
6844590Smarc 				bcopy(iov, localiov,
69*46663Sbostic 				    iovcnt * sizeof(struct iovec));
7044590Smarc 				iov = localiov;
7144590Smarc 			}
7239422Sbostic 			for (cnt = 0; wret >= iov->iov_len; ++cnt) {
7339422Sbostic 				wret -= iov->iov_len;
7439422Sbostic 				++iov;
7539422Sbostic 				--iovcnt;
7639422Sbostic 			}
7739422Sbostic 			if (wret) {
7839422Sbostic 				iov->iov_base += wret;
7939422Sbostic 				iov->iov_len -= wret;
8039422Sbostic 			}
81*46663Sbostic 			continue;
82*46663Sbostic 		}
83*46663Sbostic 		if (errno == EWOULDBLOCK) {
84*46663Sbostic 			int cpid, off = 0;
85*46663Sbostic 
86*46663Sbostic 			if (forked) {
87*46663Sbostic 				(void) close(fd);
88*46663Sbostic 				_exit(1);
89*46663Sbostic 			}
90*46663Sbostic 			cpid = fork();
91*46663Sbostic 			if (cpid < 0) {
92*46663Sbostic 				(void) snprintf(errbuf, sizeof(errbuf),
93*46663Sbostic 				    "fork: %s", strerror(errno));
94*46663Sbostic 				(void) close(fd);
95*46663Sbostic 				return (errbuf);
96*46663Sbostic 			}
97*46663Sbostic 			if (cpid) {	/* parent */
98*46663Sbostic 				(void) close(fd);
99*46663Sbostic 				return (NULL);
100*46663Sbostic 			}
101*46663Sbostic 			forked++;
102*46663Sbostic 			/* wait at most 5 minutes */
103*46663Sbostic 			(void) signal(SIGALRM, SIG_DFL);
104*46663Sbostic 			(void) signal(SIGTERM, SIG_DFL); /* XXX */
105*46663Sbostic 			(void) sigsetmask(0);
106*46663Sbostic 			(void) alarm((u_int)(60 * 5));
107*46663Sbostic 			(void) fcntl(fd, FNDELAY, &off);
108*46663Sbostic 			continue;
109*46663Sbostic 		}
110*46663Sbostic 		/*
111*46663Sbostic 		 * We get ENODEV on a slip line if we're running as root,
112*46663Sbostic 		 * and EIO if the line just went away.
113*46663Sbostic 		 */
114*46663Sbostic 		if (errno == ENODEV || errno == EIO)
11544590Smarc 			break;
116*46663Sbostic 		(void) close(fd);
117*46663Sbostic 		if (forked)
118*46663Sbostic 			_exit(1);
119*46663Sbostic 		(void) snprintf(errbuf, sizeof(errbuf),
120*46663Sbostic 		    "%s: %s", device, strerror(errno));
121*46663Sbostic 		return (errbuf);
12244590Smarc 	}
123*46663Sbostic 
124*46663Sbostic 	(void) close(fd);
12544590Smarc 	if (forked)
126*46663Sbostic 		_exit(0);
12739496Skarels 	return (NULL);
12839422Sbostic }
129