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