# 2.11BSD#431 - /usr/src/usr.sbin/rwhod/rwhod.c

##### Functions

    configure         X
    getboottime       X
    interval          X
    main              X
    onalrm            X
    sendto            X
    verify            X

##### Variables

    Utmp              X
    alarmcount        X
    copyright         X
    myname            X
    mywd              X
    neighbors         X
    s                 X
    sin               X
    sp                X
    utmp              X
    utmpent           X
    utmpf             X
    utmpsize          X
    utmptime          X

##### Macros

    ALLREAD           X
    AL_INTERVAL       X
    RWHODIR           X
    WHDRSIZE          X

##### struct's

    neighbor          X

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

#### Defined functions

configure defined in line 341; used 1 times

- in line 144

getboottime defined in line 320; used 4 times

- in line 69, 109, 130, 248

interval defined in line 463; used 2 times

- in line 434-438(2)

main defined in line 72; never used
onalrm defined in line 237; used 3 times

- in line 69, 146-147(2)

sendto defined in line 424; used 1 times

- in line 310

verify defined in line 218; used 1 times

- in line 168

#### Defined variables

Utmp defined in line 70; used 5 times

- in line 121-127(4), 268

alarmcount defined in line 235; used 2 times

- in line 247-249(2)

copyright defined in line 8; never used
myname defined in line 45; used 5 times

- in line 114-120(5)

mywd defined in line 62; used 14 times

- in line 66(2), 120, 241, 271, 284, 296, 304-310(6), 334

neighbors defined in line 61; used 4 times

- in line 309, 359, 417-418(2)

s defined in line 64; used 23 times

- in line 92-101(9), 131-144(4), 152, 310, 341-342(2), 353, 383, 395, 405, 424-425(2)

sccsid defined in line 12; never used
sin defined in line 43; used 9 times

- in line 139-140(3), 347, 415-416(2), 433-436(3)

sp defined in line 63; used 5 times

- in line 84-85(2), 139, 159, 416

utmp defined in line 234; used 10 times

- in line 255-259(5), 266, 274-279(4)

utmpent defined in line 232; used 6 times

- in line 272-273(2), 284, 292-297(2), 312

utmpf defined in line 64; used 7 times

- in line 121-126(4), 250, 265-266(2)

utmpsize defined in line 233; used 6 times

- in line 251-261(6)

utmptime defined in line 231; used 2 times

- in line 251-252(2)

#### Defined struct's

neighbor defined in line 53; used 10 times

- in line 54(2), 61(2), 245(2), 348(2), 366(2)

#### Defined macros

ALLREAD defined in line 206; used 3 times

- in line 207-208(3)

AL_INTERVAL defined in line 41; used 1 times

- in line 317

RWHODIR defined in line 67; used 4 times

- in line 105-106(2), 312-313(2)

WHDRSIZE defined in line 66; used 2 times

- in line 185, 442

Last modified: 1999-09-15 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2204 |