update intrEXIT for new signal mechanism
[unix-history] / usr / src / usr.sbin / rwhod / rwhod.c
CommitLineData
52b4fb0c 1#ifndef lint
86fcf481 2static char sccsid[] = "@(#)rwhod.c 4.19 (Berkeley) 83/07/01";
52b4fb0c
BJ
3#endif
4
52b4fb0c 5#include <sys/types.h>
52b4fb0c 6#include <sys/socket.h>
52b4fb0c 7#include <sys/stat.h>
52b4fb0c 8#include <sys/ioctl.h>
9bd66dcf 9#include <sys/file.h>
de3b21e8 10
7af17b3e 11#include <net/if.h>
de3b21e8
SL
12#include <netinet/in.h>
13
14#include <nlist.h>
15#include <stdio.h>
16#include <signal.h>
17#include <errno.h>
18#include <utmp.h>
a0f59ac1
SL
19#include <ctype.h>
20#include <netdb.h>
86fcf481 21#include "rwhod.h"
de3b21e8 22
a0f59ac1 23struct sockaddr_in sin = { AF_INET };
52b4fb0c
BJ
24
25extern errno;
26
7af17b3e 27char myname[32];
52b4fb0c
BJ
28
29struct nlist nl[] = {
30#define NL_AVENRUN 0
31 { "_avenrun" },
de3b21e8
SL
32#define NL_BOOTTIME 1
33 { "_boottime" },
52b4fb0c
BJ
34 0
35};
36
7af17b3e
SL
37/*
38 * We communicate with each neighbor in
39 * a list constructed at the time we're
40 * started up. Neighbors are currently
41 * directly connected via a hardware interface.
42 */
43struct neighbor {
44 struct neighbor *n_next;
45 char *n_name; /* interface name */
46 char *n_addr; /* who to send to */
47 int n_addrlen; /* size of address */
48 int n_flags; /* should forward?, interface flags */
49};
50
51struct neighbor *neighbors;
52b4fb0c 52struct whod mywd;
7af17b3e 53struct servent *sp;
52b4fb0c
BJ
54int s, utmpf, kmemf = -1;
55
7af17b3e
SL
56#define WHDRSIZE (sizeof (mywd) - sizeof (mywd.wd_we))
57#define RWHODIR "/usr/spool/rwho"
fea387f0 58
52b4fb0c 59int onalrm();
7af17b3e 60char *strcpy(), *sprintf(), *malloc();
52b4fb0c
BJ
61long lseek();
62int getkmem();
7af17b3e 63struct in_addr inet_makeaddr();
52b4fb0c
BJ
64
65main()
66{
67 struct sockaddr_in from;
68 char path[64];
69 int addr;
7af17b3e 70 struct hostent *hp;
52b4fb0c 71
a0f59ac1
SL
72 sp = getservbyname("who", "udp");
73 if (sp == 0) {
74 fprintf(stderr, "rwhod: udp/who: unknown service\n");
75 exit(1);
76 }
52b4fb0c
BJ
77#ifndef DEBUG
78 if (fork())
79 exit(0);
80 { int s;
81 for (s = 0; s < 10; s++)
82 (void) close(s);
83 (void) open("/", 0);
84 (void) dup2(0, 1);
85 (void) dup2(0, 2);
86 s = open("/dev/tty", 2);
87 if (s >= 0) {
88 ioctl(s, TIOCNOTTY, 0);
89 (void) close(s);
90 }
91 }
92#endif
93 (void) chdir("/dev");
94 (void) signal(SIGHUP, getkmem);
95 if (getuid()) {
a0f59ac1 96 fprintf(stderr, "rwhod: not super user\n");
52b4fb0c
BJ
97 exit(1);
98 }
7af17b3e
SL
99 /*
100 * Establish host name as returned by system.
101 */
102 if (gethostname(myname, sizeof (myname) - 1) < 0) {
103 perror("gethostname");
52b4fb0c
BJ
104 exit(1);
105 }
7af17b3e 106 strncpy(mywd.wd_hostname, myname, sizeof (myname) - 1);
9bd66dcf 107 utmpf = open("/etc/utmp", O_RDONLY);
52b4fb0c
BJ
108 if (utmpf < 0) {
109 (void) close(creat("/etc/utmp", 0644));
9bd66dcf 110 utmpf = open("/etc/utmp", O_RDONLY);
52b4fb0c
BJ
111 }
112 if (utmpf < 0) {
a0f59ac1 113 perror("rwhod: /etc/utmp");
52b4fb0c
BJ
114 exit(1);
115 }
116 getkmem();
9bd66dcf 117 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
a0f59ac1 118 perror("rwhod: socket");
de3b21e8
SL
119 exit(1);
120 }
7af17b3e
SL
121 hp = gethostbyname(myname);
122 if (hp == NULL) {
123 fprintf(stderr, "%s: don't know my own name\n", myname);
124 exit(1);
125 }
126 sin.sin_family = hp->h_addrtype;
127 sin.sin_port = sp->s_port;
9bd66dcf 128 if (bind(s, &sin, sizeof (sin)) < 0) {
de3b21e8
SL
129 perror("rwhod: bind");
130 exit(1);
52b4fb0c 131 }
7af17b3e
SL
132 if (!configure(s))
133 exit(1);
8a53982e 134 signal(SIGALRM, onalrm);
52b4fb0c
BJ
135 onalrm();
136 for (;;) {
137 struct whod wd;
7af17b3e 138 int cc, whod, len = sizeof (from);
52b4fb0c 139
7af17b3e
SL
140 cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
141 &from, &len);
52b4fb0c
BJ
142 if (cc <= 0) {
143 if (cc < 0 && errno != EINTR)
de3b21e8 144 perror("rwhod: recv");
52b4fb0c
BJ
145 continue;
146 }
a0f59ac1
SL
147 if (from.sin_port != sp->s_port) {
148 fprintf(stderr, "rwhod: %d: bad from port\n",
149 ntohs(from.sin_port));
52b4fb0c
BJ
150 continue;
151 }
a0f59ac1
SL
152#ifdef notdef
153 if (gethostbyname(wd.wd_hostname) == 0) {
154 fprintf(stderr, "rwhod: %s: unknown host\n",
155 wd.wd_hostname);
156 continue;
157 }
158#endif
aaddf8a1
SL
159 if (wd.wd_vers != WHODVERSION)
160 continue;
7af17b3e
SL
161 if (wd.wd_type != WHODTYPE_STATUS)
162 continue;
a0f59ac1
SL
163 if (!verify(wd.wd_hostname)) {
164 fprintf(stderr, "rwhod: malformed host name from %x\n",
165 from.sin_addr);
52b4fb0c
BJ
166 continue;
167 }
a82aa56a 168 (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname);
52b4fb0c
BJ
169 whod = creat(path, 0666);
170 if (whod < 0) {
a0f59ac1
SL
171 fprintf(stderr, "rwhod: ");
172 perror(path);
52b4fb0c
BJ
173 continue;
174 }
fea387f0
SL
175#if vax || pdp11
176 {
9bd66dcf 177 int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
fea387f0
SL
178 struct whoent *we;
179
180 /* undo header byte swapping before writing to file */
181 wd.wd_sendtime = ntohl(wd.wd_sendtime);
182 for (i = 0; i < 3; i++)
183 wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
184 wd.wd_boottime = ntohl(wd.wd_boottime);
185 we = wd.wd_we;
186 for (i = 0; i < n; i++) {
187 we->we_idle = ntohl(we->we_idle);
1cccbcb3
SL
188 we->we_utmp.out_time =
189 ntohl(we->we_utmp.out_time);
fea387f0
SL
190 we++;
191 }
192 }
193#endif
52b4fb0c
BJ
194 (void) time(&wd.wd_recvtime);
195 (void) write(whod, (char *)&wd, cc);
196 (void) close(whod);
197 }
198}
199
a0f59ac1
SL
200/*
201 * Check out host name for unprintables
202 * and other funnies before allowing a file
203 * to be created. Sorry, but blanks aren't allowed.
204 */
205verify(name)
206 register char *name;
207{
208 register int size = 0;
209
210 while (*name) {
211 if (!isascii(*name) || !isalnum(*name))
212 return (0);
213 name++, size++;
214 }
215 return (size > 0);
216}
217
52b4fb0c
BJ
218int utmptime;
219int utmpent;
76886f32 220struct utmp utmp[100];
52b4fb0c
BJ
221int alarmcount;
222
223onalrm()
224{
225 register int i;
226 struct stat stb;
76886f32 227 register struct whoent *we = mywd.wd_we, *wlast;
52b4fb0c
BJ
228 int cc;
229 double avenrun[3];
230 time_t now = time(0);
7af17b3e 231 register struct neighbor *np;
52b4fb0c
BJ
232
233 if (alarmcount % 10 == 0)
234 getkmem();
235 alarmcount++;
236 (void) fstat(utmpf, &stb);
237 if (stb.st_mtime != utmptime) {
9bd66dcf 238 (void) lseek(utmpf, (long)0, L_SET);
52b4fb0c
BJ
239 cc = read(utmpf, (char *)utmp, sizeof (utmp));
240 if (cc < 0) {
241 perror("/etc/utmp");
08d10f57 242 goto done;
52b4fb0c 243 }
7af17b3e 244 wlast = &mywd.wd_we[1024 / sizeof (struct whoent) - 1];
52b4fb0c
BJ
245 utmpent = cc / sizeof (struct utmp);
246 for (i = 0; i < utmpent; i++)
247 if (utmp[i].ut_name[0]) {
b1456c48
SL
248 bcopy(utmp[i].ut_line, we->we_utmp.out_line,
249 sizeof (utmp[i].ut_line));
250 bcopy(utmp[i].ut_name, we->we_utmp.out_name,
251 sizeof (utmp[i].ut_name));
b1456c48 252 we->we_utmp.out_time = htonl(utmp[i].ut_time);
76886f32
SL
253 if (we >= wlast)
254 break;
52b4fb0c
BJ
255 we++;
256 }
257 utmpent = we - mywd.wd_we;
258 }
259 we = mywd.wd_we;
260 for (i = 0; i < utmpent; i++) {
b1456c48 261 if (stat(we->we_utmp.out_line, &stb) >= 0)
b1456c48 262 we->we_idle = htonl(now - stb.st_atime);
52b4fb0c
BJ
263 we++;
264 }
9bd66dcf 265 (void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, L_SET);
52b4fb0c
BJ
266 (void) read(kmemf, (char *)avenrun, sizeof (avenrun));
267 for (i = 0; i < 3; i++)
353c1281 268 mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100));
b1456c48 269 cc = (char *)we - (char *)&mywd;
b1456c48 270 mywd.wd_sendtime = htonl(time(0));
7af17b3e
SL
271 mywd.wd_vers = WHODVERSION;
272 mywd.wd_type = WHODTYPE_STATUS;
273 for (np = neighbors; np != NULL; np = np->n_next)
274 (void) sendto(s, (char *)&mywd, cc, 0,
275 np->n_addr, np->n_addrlen);
08d10f57 276done:
52b4fb0c
BJ
277 (void) alarm(60);
278}
279
280getkmem()
281{
282 struct nlist *nlp;
283
52b4fb0c
BJ
284 if (kmemf >= 0)
285 (void) close(kmemf);
286loop:
287 for (nlp = &nl[sizeof (nl) / sizeof (nl[0])]; --nlp >= nl; ) {
288 nlp->n_value = 0;
289 nlp->n_type = 0;
290 }
291 nlist("/vmunix", nl);
292 if (nl[0].n_value == 0) {
293 fprintf(stderr, "/vmunix namelist botch\n");
294 sleep(300);
295 goto loop;
296 }
9bd66dcf 297 kmemf = open("/dev/kmem", O_RDONLY);
52b4fb0c
BJ
298 if (kmemf < 0) {
299 perror("/dev/kmem");
300 sleep(300);
301 goto loop;
302 }
9bd66dcf
SL
303 (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, L_SET);
304 (void) read(kmemf, (char *)&mywd.wd_boottime,
305 sizeof (mywd.wd_boottime));
b1456c48 306 mywd.wd_boottime = htonl(mywd.wd_boottime);
52b4fb0c 307}
7af17b3e
SL
308
309/*
310 * Figure out device configuration and select
311 * networks which deserve status information.
312 */
313configure(s)
314 int s;
315{
316 char buf[BUFSIZ];
317 struct ifconf ifc;
318 struct ifreq ifreq, *ifr;
7af17b3e
SL
319 struct sockaddr_in *sin;
320 register struct neighbor *np;
9bd66dcf 321 int n;
7af17b3e
SL
322
323 ifc.ifc_len = sizeof (buf);
324 ifc.ifc_buf = buf;
325 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
326 perror("rwhod: ioctl (get interface configuration)");
327 return (0);
328 }
329 ifr = ifc.ifc_req;
330 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
331 for (np = neighbors; np != NULL; np = np->n_next)
332 if (np->n_name &&
333 strcmp(ifr->ifr_name, np->n_name) == 0)
334 break;
335 if (np != NULL)
336 continue;
337 ifreq = *ifr;
338 np = (struct neighbor *)malloc(sizeof (*np));
339 if (np == NULL)
340 continue;
341 np->n_name = malloc(strlen(ifr->ifr_name) + 1);
342 if (np->n_name == NULL) {
343 free((char *)np);
344 continue;
345 }
346 strcpy(np->n_name, ifr->ifr_name);
347 np->n_addrlen = sizeof (ifr->ifr_addr);
348 np->n_addr = malloc(np->n_addrlen);
349 if (np->n_addr == NULL) {
350 free(np->n_name);
351 free((char *)np);
352 continue;
353 }
354 bcopy((char *)&ifr->ifr_addr, np->n_addr, np->n_addrlen);
355 if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
356 perror("rwhod: ioctl (get interface flags)");
357 free((char *)np);
358 continue;
359 }
360 if ((ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) {
361 free((char *)np);
362 continue;
363 }
364 np->n_flags = ifreq.ifr_flags;
365 if (np->n_flags & IFF_POINTOPOINT) {
366 if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
367 perror("rwhod: ioctl (get dstaddr)");
368 free((char *)np);
369 continue;
370 }
371 /* we assume addresses are all the same size */
372 bcopy((char *)&ifreq.ifr_dstaddr,
373 np->n_addr, np->n_addrlen);
374 }
375 if (np->n_flags & IFF_BROADCAST) {
376 /* we assume addresses are all the same size */
377 sin = (struct sockaddr_in *)np->n_addr;
378 sin->sin_addr =
379 inet_makeaddr(inet_netof(sin->sin_addr), INADDR_ANY);
380 }
381 /* gag, wish we could get rid of Internet dependencies */
382 sin = (struct sockaddr_in *)np->n_addr;
383 sin->sin_port = sp->s_port;
384 np->n_next = neighbors;
385 neighbors = np;
386 }
387 return (1);
388}
b1456c48
SL
389
390#ifdef DEBUG
391sendto(s, buf, cc, flags, to, tolen)
392 int s;
393 char *buf;
394 int cc, flags;
395 char *to;
396 int tolen;
397{
398 register struct whod *w = (struct whod *)buf;
399 register struct whoent *we;
400 struct sockaddr_in *sin = (struct sockaddr_in *)to;
401 char *interval();
402
403 printf("sendto %x.%d\n", ntohl(sin->sin_addr), ntohs(sin->sin_port));
404 printf("hostname %s %s\n", w->wd_hostname,
9bd66dcf 405 interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up"));
b1456c48 406 printf("load %4.2f, %4.2f, %4.2f\n",
9bd66dcf
SL
407 ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,
408 ntohl(w->wd_loadav[2]) / 100.0);
b1456c48
SL
409 cc -= WHDRSIZE;
410 for (we = w->wd_we, cc /= sizeof (struct whoent); cc > 0; cc--, we++) {
9bd66dcf 411 time_t t = ntohl(we->we_utmp.out_time);
b1456c48 412 printf("%-8.8s %s:%s %.12s",
9bd66dcf
SL
413 we->we_utmp.out_name,
414 w->wd_hostname, we->we_utmp.out_line,
415 ctime(&t)+4);
416 we->we_idle = ntohl(we->we_idle) / 60;
b1456c48
SL
417 if (we->we_idle) {
418 if (we->we_idle >= 100*60)
419 we->we_idle = 100*60 - 1;
420 if (we->we_idle >= 60)
421 printf(" %2d", we->we_idle / 60);
422 else
423 printf(" ");
424 printf(":%02d", we->we_idle % 60);
425 }
426 printf("\n");
427 }
428}
429
430char *
431interval(time, updown)
432 int time;
433 char *updown;
434{
435 static char resbuf[32];
436 int days, hours, minutes;
437
438 if (time < 0 || time > 3*30*24*60*60) {
439 (void) sprintf(resbuf, " %s ??:??", updown);
440 return (resbuf);
441 }
442 minutes = (time + 59) / 60; /* round to minutes */
443 hours = minutes / 60; minutes %= 60;
444 days = hours / 24; hours %= 24;
445 if (days)
446 (void) sprintf(resbuf, "%s %2d+%02d:%02d",
447 updown, days, hours, minutes);
448 else
449 (void) sprintf(resbuf, "%s %2d:%02d",
450 updown, hours, minutes);
451 return (resbuf);
452}
453#endif