xref: /original-bsd/usr.bin/wall/ttymsg.c (revision da818fbb)
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.4 (Berkeley) 02/24/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 
30 /*
31  * display the contents of a uio structure on a terminal.  Used by
32  * wall(1) and syslogd(8).  Forks and finishes in child if write
33  * would block, waiting at most five minutes.
34  * Returns pointer to error string on unexpected error;
35  * string is not newline-terminated.  Various "normal" errors
36  * are ignored (exclusive-use, lack of permission, etc.).
37  */
38 char *
39 ttymsg(iov, iovcnt, line, nonblock)
40 	struct iovec *iov;
41 	int iovcnt;
42 	char *line;
43 	int nonblock;
44 {
45 	extern int errno;
46 	static char device[MAXNAMLEN] = _PATH_DEV;
47 	static char errbuf[1024];
48 	register int cnt, fd, total, wret;
49 	char *strcpy(), *strerror();
50 
51 	/*
52 	 * open will fail on slip lines or exclusive-use lines
53 	 * if not running as root; not an error.
54 	 */
55 	(void) strcpy(device + sizeof(_PATH_DEV) - 1, line);
56 	if ((fd = open(device, O_WRONLY|(nonblock ? O_NONBLOCK : 0), 0)) < 0)
57 		if (errno != EBUSY && errno != EACCES) {
58 			(void) sprintf(errbuf, "open %s: %s", device,
59 			    strerror(errno));
60 			return (errbuf);
61 		} else
62 			return (NULL);
63 
64 	for (cnt = total = 0; cnt < iovcnt; ++cnt)
65 		total += iov[cnt].iov_len;
66 
67 	for (;;)
68 		if ((wret = writev(fd, iov, iovcnt)) < 0)
69 			if (errno == EWOULDBLOCK) {
70 				if (fork()) {
71 					(void) close(fd);
72 					return (NULL);
73 				}
74 				/* wait at most 5 minutes */
75 				(void) signal(SIGALRM, SIG_DFL);
76 				(void) signal(SIGTERM, SIG_DFL); /* XXX */
77 				(void) sigsetmask(0);
78 				(void) alarm((u_int)(60 * 5));
79 				(void) ttymsg(iov, iovcnt, line, 0);
80 				exit(0);
81 			} else {
82 				/*
83 				 * we get ENODEV on a slip line if we're
84 				 * running as root, and EIO if the line
85 				 * just went away
86 				 */
87 				if (errno == ENODEV || errno == EIO)
88 					break;
89 				(void) sprintf(errbuf, "writing %s: %s",
90 				    device, strerror(errno));
91 				(void) close(fd);
92 				return (errbuf);
93 			}
94 		else if (wret) {
95 			if (wret == total)
96 				break;
97 			for (cnt = 0; wret >= iov->iov_len; ++cnt) {
98 				wret -= iov->iov_len;
99 				++iov;
100 				--iovcnt;
101 			}
102 			if (wret) {
103 				iov->iov_base += wret;
104 				iov->iov_len -= wret;
105 			}
106 		}
107 	(void) close(fd);
108 	return (NULL);
109 }
110