|
|
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.10 (Berkeley) 10/22/87"; ! 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(), *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.