Commit | Line | Data |
---|---|---|
02072412 | 1 | /* |
6bfd2df7 KB |
2 | * Copyright (c) 1988 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
02072412 DF |
16 | */ |
17 | ||
18 | #ifndef lint | |
19 | char copyright[] = | |
6bfd2df7 | 20 | "@(#) Copyright (c) 1988 Regents of the University of California.\n\ |
02072412 | 21 | All rights reserved.\n"; |
6bfd2df7 | 22 | #endif /* not lint */ |
02072412 DF |
23 | |
24 | #ifndef lint | |
e41c016c | 25 | static char sccsid[] = "@(#)wall.c 5.6 (Berkeley) %G%"; |
6bfd2df7 | 26 | #endif /* not lint */ |
02072412 | 27 | |
1addde1c | 28 | /* |
1addde1c BJ |
29 | * This program is not related to David Wall, whose Stanford Ph.D. thesis |
30 | * is entitled "Mechanisms for Broadcast and Selective Broadcast". | |
31 | */ | |
32 | ||
6bfd2df7 | 33 | #include <sys/param.h> |
3071a7ff | 34 | #include <sys/time.h> |
6bfd2df7 | 35 | #include <sys/signal.h> |
734f8abe | 36 | #include <sys/stat.h> |
6bfd2df7 KB |
37 | #include <sys/dir.h> |
38 | #include <fcntl.h> | |
39 | #include <utmp.h> | |
40 | #include <pwd.h> | |
41 | #include <errno.h> | |
42 | #include <stdio.h> | |
3071a7ff | 43 | |
6bfd2df7 KB |
44 | #define IGNOREUSER "sleeper" |
45 | #define UTMP "/etc/utmp" | |
1addde1c | 46 | |
6bfd2df7 KB |
47 | static int mbufsize; |
48 | static char *mbuf; | |
3071a7ff | 49 | |
6bfd2df7 | 50 | /* ARGSUSED */ |
1addde1c | 51 | main(argc, argv) |
6bfd2df7 KB |
52 | int argc; |
53 | char **argv; | |
1addde1c | 54 | { |
6bfd2df7 KB |
55 | struct utmp utmp; |
56 | FILE *fp; | |
57 | ||
58 | if (argc > 2) { | |
59 | fprintf(stderr, "usage: wall [file]\n"); | |
1addde1c BJ |
60 | exit(1); |
61 | } | |
6bfd2df7 KB |
62 | makemsg(argv); |
63 | ||
64 | if (!(fp = fopen(UTMP, "r"))) { | |
65 | fprintf(stderr, "wall: cannot read /etc/utmp.\n"); | |
66 | exit(1); | |
df3e00cc | 67 | } |
6bfd2df7 | 68 | /* NOSTRICT */ |
e41c016c KB |
69 | while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) |
70 | if (utmp.ut_name[0] && | |
71 | strncmp(utmp.ut_name, IGNOREUSER, sizeof(utmp.ut_name))) | |
72 | sendmsg(utmp.ut_line); | |
1addde1c BJ |
73 | exit(0); |
74 | } | |
75 | ||
6bfd2df7 KB |
76 | makemsg(argv) |
77 | char **argv; | |
1addde1c | 78 | { |
6bfd2df7 KB |
79 | register int ch, cnt; |
80 | struct tm *lt; | |
81 | struct passwd *pw, *getpwuid(); | |
82 | struct stat sbuf; | |
83 | time_t now, time(); | |
84 | FILE *fp; | |
85 | int fd; | |
86 | char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[15]; | |
87 | char *getlogin(), *malloc(), *strcpy(), *ttyname(); | |
1addde1c | 88 | |
6bfd2df7 KB |
89 | (void)strcpy(tmpname, "/tmp/wall.XXX"); |
90 | if (!(fd = mkstemp(tmpname)) || !(fp = fdopen(fd, "r+"))) { | |
91 | fprintf(stderr, "wall: can't open temporary file.\n"); | |
92 | exit(1); | |
93 | } | |
94 | (void)unlink(tmpname); | |
95 | ||
96 | if (!(whom = getlogin())) | |
97 | whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; | |
98 | (void)gethostname(hostname, sizeof(hostname)); | |
99 | (void)time(&now); | |
100 | lt = localtime(&now); | |
101 | ||
102 | /* | |
103 | * all this stuff is to blank out a square for the message; we | |
104 | * limit message lines to 75 characters, and blank out to 79. | |
105 | * Not 80 'cause some terminals do weird stuff then. | |
106 | */ | |
107 | fprintf(fp, "\r%79s\r\n", " "); | |
108 | (void)sprintf(lbuf, "Broadcast Message from %s@%s", whom, hostname); | |
109 | fprintf(fp, "%-79.79s\007\007\r\n", lbuf); | |
110 | (void)sprintf(lbuf, " (%s) at %d:%02d ...", ttyname(2), | |
111 | lt->tm_hour, lt->tm_min); | |
112 | fprintf(fp, "%-79.79s\r\n", lbuf); | |
113 | fprintf(fp, "%79s\r\n", " "); | |
3071a7ff | 114 | |
6bfd2df7 KB |
115 | if (*++argv && !(freopen(*argv, "r", stdin))) { |
116 | fprintf(stderr, "wall: can't read %s.\n", *argv); | |
117 | exit(1); | |
118 | } | |
119 | while (fgets(lbuf, sizeof(lbuf), stdin)) | |
120 | for (cnt = 0, p = lbuf; ch = *p; ++p, ++cnt) | |
121 | if (cnt == 75 || ch == '\n') { | |
122 | for (; cnt < 79; ++cnt) | |
123 | putc(' ', fp); | |
124 | putc('\r', fp); | |
125 | putc('\n', fp); | |
126 | cnt = 1; | |
127 | } else | |
128 | putc(ch, fp); | |
129 | fprintf(fp, "%79s\r\n", " "); | |
130 | rewind(fp); | |
131 | ||
132 | if (fstat(fd, &sbuf)) { | |
133 | fprintf(stderr, "wall: can't stat temporary file.\n"); | |
134 | exit(1); | |
3071a7ff | 135 | } |
6bfd2df7 KB |
136 | mbufsize = sbuf.st_size; |
137 | if (!(mbuf = malloc((u_int)mbufsize))) { | |
138 | fprintf(stderr, "wall: out of memory.\n"); | |
139 | exit(1); | |
3071a7ff | 140 | } |
e41c016c KB |
141 | if (fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize) { |
142 | fprintf(stderr, "wall: can't read temporary file.\n"); | |
143 | exit(1); | |
144 | } | |
6bfd2df7 KB |
145 | (void)close(fd); |
146 | } | |
147 | ||
148 | sendmsg(line) | |
149 | char *line; | |
150 | { | |
151 | extern int errno; | |
152 | static char device[MAXNAMLEN] = "/dev/"; | |
e41c016c | 153 | register int fd, flags, left, wret; |
6bfd2df7 KB |
154 | char *lp, *strcpy(); |
155 | ||
156 | (void)strcpy(device + 5, line); | |
157 | if ((fd = open(device, O_WRONLY, 0)) < 0) { | |
158 | fprintf(stderr, "wall: %s: ", device); | |
159 | perror((char *)NULL); | |
3071a7ff | 160 | } |
6bfd2df7 KB |
161 | flags = fcntl(fd, F_GETFL, 0); |
162 | if (!(flags & FNDELAY)) { | |
163 | /* NDELAY bit not set; if can't set, fork instead */ | |
164 | if (fcntl(fd, F_SETFL, flags|FNDELAY) == -1) { | |
165 | flags = 0; | |
166 | goto forkit; | |
167 | } | |
3071a7ff | 168 | } |
6bfd2df7 KB |
169 | else |
170 | flags = 0; | |
171 | lp = mbuf; | |
e41c016c KB |
172 | left = mbufsize; |
173 | while ((wret = write(fd, lp, left)) != left) { | |
174 | if (wret >= 0) { | |
175 | lp += wret; | |
176 | left -= wret; | |
6bfd2df7 KB |
177 | } else if (errno == EWOULDBLOCK) { |
178 | /* child resets FNDELAY if necessary; parent leaves */ | |
179 | forkit: if (fork()) { | |
180 | (void)close(fd); | |
181 | return; | |
182 | } | |
183 | if (flags) | |
184 | (void)fcntl(fd, F_SETFL, flags); | |
185 | /* wait 5 minutes and then quit */ | |
186 | (void)alarm((u_int)(60 * 5)); | |
187 | (void)write(fd, mbuf, mbufsize); | |
188 | exit(0); | |
189 | } else { | |
190 | fprintf(stderr, "wall: %s: ", device); | |
191 | perror((char *)NULL); | |
192 | break; | |
df3e00cc | 193 | } |
1addde1c | 194 | } |
6bfd2df7 KB |
195 | /* write was successful, or error != EWOULDBLOCK; cleanup */ |
196 | if (flags) | |
197 | (void)fcntl(fd, F_SETFL, flags); | |
198 | (void)close(fd); | |
1addde1c | 199 | } |