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