|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)rwhod.c 5.9 (Berkeley) 3/5/86";
15: #endif not lint
16:
17: #include <sys/types.h>
18: #include <sys/socket.h>
19: #include <sys/stat.h>
20: #include <sys/ioctl.h>
21: #include <sys/file.h>
22:
23: #include <net/if.h>
24: #include <netinet/in.h>
25:
26: #include <nlist.h>
27: #include <stdio.h>
28: #include <signal.h>
29: #include <errno.h>
30: #include <utmp.h>
31: #include <ctype.h>
32: #include <netdb.h>
33: #include <syslog.h>
34: #include <protocols/rwhod.h>
35:
36: /*
37: * Alarm interval. Don't forget to change the down time check in ruptime
38: * if this is changed.
39: */
40: #define AL_INTERVAL (3 * 60)
41:
42: struct sockaddr_in sin = { AF_INET };
43:
44: extern errno;
45:
46: char myname[32];
47:
48: struct nlist nl[] = {
49: #define NL_AVENRUN 0
50: { "_avenrun" },
51: #define NL_BOOTTIME 1
52: { "_boottime" },
53: 0
54: };
55:
56: /*
57: * We communicate with each neighbor in
58: * a list constructed at the time we're
59: * started up. Neighbors are currently
60: * directly connected via a hardware interface.
61: */
62: struct neighbor {
63: struct neighbor *n_next;
64: char *n_name; /* interface name */
65: char *n_addr; /* who to send to */
66: int n_addrlen; /* size of address */
67: int n_flags; /* should forward?, interface flags */
68: };
69:
70: struct neighbor *neighbors;
71: struct whod mywd;
72: struct servent *sp;
73: int s, utmpf, kmemf = -1;
74:
75: #define WHDRSIZE (sizeof (mywd) - sizeof (mywd.wd_we))
76: #define RWHODIR "/usr/spool/rwho"
77:
78: int onalrm();
79: char *strcpy(), *sprintf(), *malloc();
80: long lseek();
81: int getkmem();
82: struct in_addr inet_makeaddr();
83:
84: main()
85: {
86: struct sockaddr_in from;
87: struct stat st;
88: char path[64];
89: int on = 1;
90: char *cp;
91: extern char *index();
92:
93: if (getuid()) {
94: fprintf(stderr, "rwhod: not super user\n");
95: exit(1);
96: }
97: sp = getservbyname("who", "udp");
98: if (sp == 0) {
99: fprintf(stderr, "rwhod: udp/who: unknown service\n");
100: exit(1);
101: }
102: #ifndef DEBUG
103: if (fork())
104: exit(0);
105: { int s;
106: for (s = 0; s < 10; s++)
107: (void) close(s);
108: (void) open("/", 0);
109: (void) dup2(0, 1);
110: (void) dup2(0, 2);
111: s = open("/dev/tty", 2);
112: if (s >= 0) {
113: ioctl(s, TIOCNOTTY, 0);
114: (void) close(s);
115: }
116: }
117: #endif
118: if (chdir(RWHODIR) < 0) {
119: perror(RWHODIR);
120: exit(1);
121: }
122: (void) signal(SIGHUP, getkmem);
123: openlog("rwhod", LOG_PID, LOG_DAEMON);
124: /*
125: * Establish host name as returned by system.
126: */
127: if (gethostname(myname, sizeof (myname) - 1) < 0) {
128: syslog(LOG_ERR, "gethostname: %m");
129: exit(1);
130: }
131: if ((cp = index(myname, '.')) != NULL)
132: *cp = '\0';
133: strncpy(mywd.wd_hostname, myname, sizeof (myname) - 1);
134: utmpf = open("/etc/utmp", O_RDONLY);
135: if (utmpf < 0) {
136: (void) close(creat("/etc/utmp", 0644));
137: utmpf = open("/etc/utmp", O_RDONLY);
138: }
139: if (utmpf < 0) {
140: syslog(LOG_ERR, "/etc/utmp: %m");
141: exit(1);
142: }
143: getkmem();
144: if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
145: syslog(LOG_ERR, "socket: %m");
146: exit(1);
147: }
148: if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
149: syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
150: exit(1);
151: }
152: sin.sin_port = sp->s_port;
153: if (bind(s, &sin, sizeof (sin)) < 0) {
154: syslog(LOG_ERR, "bind: %m");
155: exit(1);
156: }
157: if (!configure(s))
158: exit(1);
159: signal(SIGALRM, onalrm);
160: onalrm();
161: for (;;) {
162: struct whod wd;
163: int cc, whod, len = sizeof (from);
164:
165: cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
166: &from, &len);
167: if (cc <= 0) {
168: if (cc < 0 && errno != EINTR)
169: syslog(LOG_WARNING, "recv: %m");
170: continue;
171: }
172: if (from.sin_port != sp->s_port) {
173: syslog(LOG_WARNING, "%d: bad from port",
174: ntohs(from.sin_port));
175: continue;
176: }
177: #ifdef notdef
178: if (gethostbyname(wd.wd_hostname) == 0) {
179: syslog(LOG_WARNING, "%s: unknown host",
180: wd.wd_hostname);
181: continue;
182: }
183: #endif
184: if (wd.wd_vers != WHODVERSION)
185: continue;
186: if (wd.wd_type != WHODTYPE_STATUS)
187: continue;
188: if (!verify(wd.wd_hostname)) {
189: syslog(LOG_WARNING, "malformed host name from %x",
190: from.sin_addr);
191: continue;
192: }
193: (void) sprintf(path, "whod.%s", wd.wd_hostname);
194: /*
195: * Rather than truncating and growing the file each time,
196: * use ftruncate if size is less than previous size.
197: */
198: whod = open(path, O_WRONLY | O_CREAT, 0644);
199: if (whod < 0) {
200: syslog(LOG_WARNING, "%s: %m", path);
201: continue;
202: }
203: #if vax || pdp11
204: {
205: int i, n = (cc - WHDRSIZE)/sizeof(struct whoent);
206: struct whoent *we;
207:
208: /* undo header byte swapping before writing to file */
209: wd.wd_sendtime = ntohl(wd.wd_sendtime);
210: for (i = 0; i < 3; i++)
211: wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
212: wd.wd_boottime = ntohl(wd.wd_boottime);
213: we = wd.wd_we;
214: for (i = 0; i < n; i++) {
215: we->we_idle = ntohl(we->we_idle);
216: we->we_utmp.out_time =
217: ntohl(we->we_utmp.out_time);
218: we++;
219: }
220: }
221: #endif
222: (void) time(&wd.wd_recvtime);
223: (void) write(whod, (char *)&wd, cc);
224: if (fstat(whod, &st) < 0 || st.st_size > cc)
225: ftruncate(whod, cc);
226: (void) close(whod);
227: }
228: }
229:
230: /*
231: * Check out host name for unprintables
232: * and other funnies before allowing a file
233: * to be created. Sorry, but blanks aren't allowed.
234: */
235: verify(name)
236: register char *name;
237: {
238: register int size = 0;
239:
240: while (*name) {
241: if (!isascii(*name) || !(isalnum(*name) || ispunct(*name)))
242: return (0);
243: name++, size++;
244: }
245: return (size > 0);
246: }
247:
248: int utmptime;
249: int utmpent;
250: int utmpsize = 0;
251: struct utmp *utmp;
252: int alarmcount;
253:
254: onalrm()
255: {
256: register int i;
257: struct stat stb;
258: register struct whoent *we = mywd.wd_we, *wlast;
259: int cc;
260: double avenrun[3];
261: time_t now = time(0);
262: register struct neighbor *np;
263:
264: if (alarmcount % 10 == 0)
265: getkmem();
266: alarmcount++;
267: (void) fstat(utmpf, &stb);
268: if ((stb.st_mtime != utmptime) || (stb.st_size > utmpsize)) {
269: utmptime = stb.st_mtime;
270: if (stb.st_size > utmpsize) {
271: utmpsize = stb.st_size + 10 * sizeof(struct utmp);
272: if (utmp)
273: utmp = (struct utmp *)realloc(utmp, utmpsize);
274: else
275: utmp = (struct utmp *)malloc(utmpsize);
276: if (! utmp) {
277: fprintf(stderr, "rwhod: malloc failed\n");
278: utmpsize = 0;
279: goto done;
280: }
281: }
282: (void) lseek(utmpf, (long)0, L_SET);
283: cc = read(utmpf, (char *)utmp, stb.st_size);
284: if (cc < 0) {
285: perror("/etc/utmp");
286: goto done;
287: }
288: wlast = &mywd.wd_we[1024 / sizeof (struct whoent) - 1];
289: utmpent = cc / sizeof (struct utmp);
290: for (i = 0; i < utmpent; i++)
291: if (utmp[i].ut_name[0]) {
292: bcopy(utmp[i].ut_line, we->we_utmp.out_line,
293: sizeof (utmp[i].ut_line));
294: bcopy(utmp[i].ut_name, we->we_utmp.out_name,
295: sizeof (utmp[i].ut_name));
296: we->we_utmp.out_time = htonl(utmp[i].ut_time);
297: if (we >= wlast)
298: break;
299: we++;
300: }
301: utmpent = we - mywd.wd_we;
302: }
303:
304: /*
305: * The test on utmpent looks silly---after all, if no one is
306: * logged on, why worry about efficiency?---but is useful on
307: * (e.g.) compute servers.
308: */
309: if (utmpent && chdir("/dev")) {
310: syslog(LOG_ERR, "chdir(/dev): %m");
311: exit(1);
312: }
313: we = mywd.wd_we;
314: for (i = 0; i < utmpent; i++) {
315: if (stat(we->we_utmp.out_line, &stb) >= 0)
316: we->we_idle = htonl(now - stb.st_atime);
317: we++;
318: }
319: (void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, L_SET);
320: (void) read(kmemf, (char *)avenrun, sizeof (avenrun));
321: for (i = 0; i < 3; i++)
322: mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100));
323: cc = (char *)we - (char *)&mywd;
324: mywd.wd_sendtime = htonl(time(0));
325: mywd.wd_vers = WHODVERSION;
326: mywd.wd_type = WHODTYPE_STATUS;
327: for (np = neighbors; np != NULL; np = np->n_next)
328: (void) sendto(s, (char *)&mywd, cc, 0,
329: np->n_addr, np->n_addrlen);
330: if (utmpent && chdir(RWHODIR)) {
331: syslog(LOG_ERR, "chdir(%s): %m", RWHODIR);
332: exit(1);
333: }
334: done:
335: (void) alarm(AL_INTERVAL);
336: }
337:
338: getkmem()
339: {
340: static ino_t vmunixino;
341: static time_t vmunixctime;
342: struct stat sb;
343:
344: if (stat("/vmunix", &sb) < 0) {
345: if (vmunixctime)
346: return;
347: } else {
348: if (sb.st_ctime == vmunixctime && sb.st_ino == vmunixino)
349: return;
350: vmunixctime = sb.st_ctime;
351: vmunixino= sb.st_ino;
352: }
353: if (kmemf >= 0)
354: (void) close(kmemf);
355: loop:
356: if (nlist("/vmunix", nl)) {
357: syslog(LOG_WARNING, "/vmunix namelist botch");
358: sleep(300);
359: goto loop;
360: }
361: kmemf = open("/dev/kmem", O_RDONLY);
362: if (kmemf < 0) {
363: syslog(LOG_ERR, "/dev/kmem: %m");
364: exit(1);
365: }
366: (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, L_SET);
367: (void) read(kmemf, (char *)&mywd.wd_boottime,
368: sizeof (mywd.wd_boottime));
369: mywd.wd_boottime = htonl(mywd.wd_boottime);
370: }
371:
372: /*
373: * Figure out device configuration and select
374: * networks which deserve status information.
375: */
376: configure(s)
377: int s;
378: {
379: char buf[BUFSIZ];
380: struct ifconf ifc;
381: struct ifreq ifreq, *ifr;
382: struct sockaddr_in *sin;
383: register struct neighbor *np;
384: int n;
385:
386: ifc.ifc_len = sizeof (buf);
387: ifc.ifc_buf = buf;
388: if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
389: syslog(LOG_ERR, "ioctl (get interface configuration)");
390: return (0);
391: }
392: ifr = ifc.ifc_req;
393: for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
394: for (np = neighbors; np != NULL; np = np->n_next)
395: if (np->n_name &&
396: strcmp(ifr->ifr_name, np->n_name) == 0)
397: break;
398: if (np != NULL)
399: continue;
400: ifreq = *ifr;
401: np = (struct neighbor *)malloc(sizeof (*np));
402: if (np == NULL)
403: continue;
404: np->n_name = malloc(strlen(ifr->ifr_name) + 1);
405: if (np->n_name == NULL) {
406: free((char *)np);
407: continue;
408: }
409: strcpy(np->n_name, ifr->ifr_name);
410: np->n_addrlen = sizeof (ifr->ifr_addr);
411: np->n_addr = malloc(np->n_addrlen);
412: if (np->n_addr == NULL) {
413: free(np->n_name);
414: free((char *)np);
415: continue;
416: }
417: bcopy((char *)&ifr->ifr_addr, np->n_addr, np->n_addrlen);
418: if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
419: syslog(LOG_ERR, "ioctl (get interface flags)");
420: free((char *)np);
421: continue;
422: }
423: if ((ifreq.ifr_flags & IFF_UP) == 0 ||
424: (ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) {
425: free((char *)np);
426: continue;
427: }
428: np->n_flags = ifreq.ifr_flags;
429: if (np->n_flags & IFF_POINTOPOINT) {
430: if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
431: syslog(LOG_ERR, "ioctl (get dstaddr)");
432: free((char *)np);
433: continue;
434: }
435: /* we assume addresses are all the same size */
436: bcopy((char *)&ifreq.ifr_dstaddr,
437: np->n_addr, np->n_addrlen);
438: }
439: if (np->n_flags & IFF_BROADCAST) {
440: if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
441: syslog(LOG_ERR, "ioctl (get broadaddr)");
442: free((char *)np);
443: continue;
444: }
445: /* we assume addresses are all the same size */
446: bcopy((char *)&ifreq.ifr_broadaddr,
447: np->n_addr, np->n_addrlen);
448: }
449: /* gag, wish we could get rid of Internet dependencies */
450: sin = (struct sockaddr_in *)np->n_addr;
451: sin->sin_port = sp->s_port;
452: np->n_next = neighbors;
453: neighbors = np;
454: }
455: return (1);
456: }
457:
458: #ifdef DEBUG
459: sendto(s, buf, cc, flags, to, tolen)
460: int s;
461: char *buf;
462: int cc, flags;
463: char *to;
464: int tolen;
465: {
466: register struct whod *w = (struct whod *)buf;
467: register struct whoent *we;
468: struct sockaddr_in *sin = (struct sockaddr_in *)to;
469: char *interval();
470:
471: printf("sendto %x.%d\n", ntohl(sin->sin_addr), ntohs(sin->sin_port));
472: printf("hostname %s %s\n", w->wd_hostname,
473: interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up"));
474: printf("load %4.2f, %4.2f, %4.2f\n",
475: ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0,
476: ntohl(w->wd_loadav[2]) / 100.0);
477: cc -= WHDRSIZE;
478: for (we = w->wd_we, cc /= sizeof (struct whoent); cc > 0; cc--, we++) {
479: time_t t = ntohl(we->we_utmp.out_time);
480: printf("%-8.8s %s:%s %.12s",
481: we->we_utmp.out_name,
482: w->wd_hostname, we->we_utmp.out_line,
483: ctime(&t)+4);
484: we->we_idle = ntohl(we->we_idle) / 60;
485: if (we->we_idle) {
486: if (we->we_idle >= 100*60)
487: we->we_idle = 100*60 - 1;
488: if (we->we_idle >= 60)
489: printf(" %2d", we->we_idle / 60);
490: else
491: printf(" ");
492: printf(":%02d", we->we_idle % 60);
493: }
494: printf("\n");
495: }
496: }
497:
498: char *
499: interval(time, updown)
500: int time;
501: char *updown;
502: {
503: static char resbuf[32];
504: int days, hours, minutes;
505:
506: if (time < 0 || time > 3*30*24*60*60) {
507: (void) sprintf(resbuf, " %s ??:??", updown);
508: return (resbuf);
509: }
510: minutes = (time + 59) / 60; /* round to minutes */
511: hours = minutes / 60; minutes %= 60;
512: days = hours / 24; hours %= 24;
513: if (days)
514: (void) sprintf(resbuf, "%s %2d+%02d:%02d",
515: updown, days, hours, minutes);
516: else
517: (void) sprintf(resbuf, "%s %2d:%02d",
518: updown, hours, minutes);
519: return (resbuf);
520: }
521: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.