xref: /original-bsd/usr.bin/wall/ttymsg.c (revision 86ed09e7)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)ttymsg.c	5.6 (Berkeley) 09/07/90";
10 #endif /* not lint */
11 
12 #include <sys/types.h>
13 #include <sys/uio.h>
14 #include <sys/file.h>
15 #include <sys/signal.h>
16 #include <dirent.h>
17 #include <errno.h>
18 #include <paths.h>
19 #include <stdio.h>
20 
21 /*
22  * display the contents of a uio structure on a terminal.  Used by
23  * wall(1) and syslogd(8).  Forks and finishes in child if write
24  * would block, waiting at most five minutes.
25  * Returns pointer to error string on unexpected error;
26  * string is not newline-terminated.  Various "normal" errors
27  * are ignored (exclusive-use, lack of permission, etc.).
28  */
29 char *
30 ttymsg(iov, iovcnt, line)
31 	struct iovec *iov;
32 	int iovcnt;
33 	char *line;
34 {
35 	extern int errno;
36 	static char device[MAXNAMLEN] = _PATH_DEV;
37 	static char errbuf[1024];
38 	register int cnt, fd, left, wret;
39 	char *strcpy(), *strerror();
40 	struct iovec localiov[6];
41 	int forked = 0;
42 
43 	if (iovcnt > 6)
44 		return ("too many iov's (change code in wall/ttymsg.c)");
45 	/*
46 	 * open will fail on slip lines or exclusive-use lines
47 	 * if not running as root; not an error.
48 	 */
49 	(void) strcpy(device + sizeof(_PATH_DEV) - 1, line);
50 	if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
51 		if (errno != EBUSY && errno != EACCES) {
52 			(void) sprintf(errbuf, "open %s: %s", device,
53 			    strerror(errno));
54 			return (errbuf);
55 		} else
56 			return (NULL);
57 	}
58 
59 	for (cnt = left = 0; cnt < iovcnt; ++cnt)
60 		left += iov[cnt].iov_len;
61 
62 	for (;;) {
63 		if ((wret = writev(fd, iov, iovcnt)) < 0) {
64 			if (errno == EWOULDBLOCK) {
65 				int off = 0;
66 				int cpid;
67 
68 				if (forked) {
69 					(void) close(fd);
70 					/* return ("already forked"); */
71 					/* "can't happen" */
72 					exit(1);
73 				}
74 				cpid = fork();
75 				if (cpid < 0) {
76 					(void) sprintf(errbuf, "can't fork: %s",
77 						strerror(errno));
78 					(void) close(fd);
79 					return (errbuf);
80 				}
81 				if (cpid) {	/* parent */
82 					(void) close(fd);
83 					return (NULL);
84 				}
85 				forked++;
86 				/* wait at most 5 minutes */
87 				(void) signal(SIGALRM, SIG_DFL);
88 				(void) signal(SIGTERM, SIG_DFL); /* XXX */
89 				(void) sigsetmask(0);
90 				(void) alarm((u_int)(60 * 5));
91 				(void) fcntl(fd, FNDELAY, &off);
92 				continue;
93 			} else {
94 				/*
95 				 * we get ENODEV on a slip line if we're
96 				 * running as root, and EIO if the line
97 				 * just went away
98 				 */
99 				if (errno == ENODEV || errno == EIO)
100 					break;
101 				(void) sprintf(errbuf, "writing %s: %s",
102 				    device, strerror(errno));
103 				(void) close(fd);
104 				return (errbuf);
105 			}
106 		}
107 		if (wret < left) {
108 			left -= wret;
109 			if (iov != localiov) {
110 				bcopy(iov, localiov,
111 					iovcnt * sizeof (struct iovec));
112 				iov = localiov;
113 			}
114 			for (cnt = 0; wret >= iov->iov_len; ++cnt) {
115 				wret -= iov->iov_len;
116 				++iov;
117 				--iovcnt;
118 			}
119 			if (wret) {
120 				iov->iov_base += wret;
121 				iov->iov_len -= wret;
122 			}
123 		} else
124 			break;
125 	}
126 	if (forked)
127 		exit(0);
128 	(void) close(fd);
129 	return (NULL);
130 }
131