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