xref: /original-bsd/usr.bin/wall/ttymsg.c (revision ee109830)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)ttymsg.c	5.5 (Berkeley) 06/29/90";
20 #endif /* not lint */
21 
22 #include <sys/types.h>
23 #include <sys/uio.h>
24 #include <sys/file.h>
25 #include <sys/signal.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <paths.h>
29 #include <stdio.h>
30 
31 /*
32  * display the contents of a uio structure on a terminal.  Used by
33  * wall(1) and syslogd(8).  Forks and finishes in child if write
34  * would block, waiting at most five minutes.
35  * Returns pointer to error string on unexpected error;
36  * string is not newline-terminated.  Various "normal" errors
37  * are ignored (exclusive-use, lack of permission, etc.).
38  */
39 char *
40 ttymsg(iov, iovcnt, line)
41 	struct iovec *iov;
42 	int iovcnt;
43 	char *line;
44 {
45 	extern int errno;
46 	static char device[MAXNAMLEN] = _PATH_DEV;
47 	static char errbuf[1024];
48 	register int cnt, fd, left, wret;
49 	char *strcpy(), *strerror();
50 	struct iovec localiov[6];
51 	int forked = 0;
52 
53 	if (iovcnt > 6)
54 		return ("too many iov's (change code in wall/ttymsg.c)");
55 	/*
56 	 * open will fail on slip lines or exclusive-use lines
57 	 * if not running as root; not an error.
58 	 */
59 	(void) strcpy(device + sizeof(_PATH_DEV) - 1, line);
60 	if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
61 		if (errno != EBUSY && errno != EACCES) {
62 			(void) sprintf(errbuf, "open %s: %s", device,
63 			    strerror(errno));
64 			return (errbuf);
65 		} else
66 			return (NULL);
67 	}
68 
69 	for (cnt = left = 0; cnt < iovcnt; ++cnt)
70 		left += iov[cnt].iov_len;
71 
72 	for (;;) {
73 		if ((wret = writev(fd, iov, iovcnt)) < 0) {
74 			if (errno == EWOULDBLOCK) {
75 				int off = 0;
76 				int cpid;
77 
78 				if (forked) {
79 					(void) close(fd);
80 					/* return ("already forked"); */
81 					/* "can't happen" */
82 					exit(1);
83 				}
84 				cpid = fork();
85 				if (cpid < 0) {
86 					(void) sprintf(errbuf, "can't fork: %s",
87 						strerror(errno));
88 					(void) close(fd);
89 					return (errbuf);
90 				}
91 				if (cpid) {	/* parent */
92 					(void) close(fd);
93 					return (NULL);
94 				}
95 				forked++;
96 				/* wait at most 5 minutes */
97 				(void) signal(SIGALRM, SIG_DFL);
98 				(void) signal(SIGTERM, SIG_DFL); /* XXX */
99 				(void) sigsetmask(0);
100 				(void) alarm((u_int)(60 * 5));
101 				(void) fcntl(fd, FNDELAY, &off);
102 				continue;
103 			} else {
104 				/*
105 				 * we get ENODEV on a slip line if we're
106 				 * running as root, and EIO if the line
107 				 * just went away
108 				 */
109 				if (errno == ENODEV || errno == EIO)
110 					break;
111 				(void) sprintf(errbuf, "writing %s: %s",
112 				    device, strerror(errno));
113 				(void) close(fd);
114 				return (errbuf);
115 			}
116 		}
117 		if (wret < left) {
118 			left -= wret;
119 			if (iov != localiov) {
120 				bcopy(iov, localiov,
121 					iovcnt * sizeof (struct iovec));
122 				iov = localiov;
123 			}
124 			for (cnt = 0; wret >= iov->iov_len; ++cnt) {
125 				wret -= iov->iov_len;
126 				++iov;
127 				--iovcnt;
128 			}
129 			if (wret) {
130 				iov->iov_base += wret;
131 				iov->iov_len -= wret;
132 			}
133 		} else
134 			break;
135 	}
136 	if (forked)
137 		exit(0);
138 	(void) close(fd);
139 	return (NULL);
140 }
141