home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume16 / fido / fido.c < prev    next >
C/C++ Source or Header  |  1988-11-01  |  19KB  |  808 lines

  1. /*
  2.  *    Copyright 1988 Philip L. Budne.
  3.  *    All rights reserved.
  4.  *
  5.  *    This program may be freely distributed as long as this notice
  6.  *    and the above Copyright remain intact.
  7.  *
  8.  *    The author makes no claims of suitability for use.
  9.  */
  10.  
  11. /*
  12.  *    Phil Budne @ BU/DSG
  13.  *
  14.  *    prehistoric    users list compiled into struct. machine
  15.  *            watching was a seperate program.
  16.  *    8/1/86        read .fido file
  17.  *    1/87        check ppid
  18.  *    8/14/87        read rwho files directly (used to popen rwho!)
  19.  *    8/20/87        add beep again, add idletime
  20.  *            rework -- put found structure in target
  21.  *            report found users once -- now way to
  22.  *            track where someone is gone from. report idle.
  23.  *    8/21/87        add machines, hungry
  24.  *    4/19/88        look in HOME for .fido, quit if not found
  25.  *            stat WHODIR, keep list of files to avoid
  26.  *            re-reading spooldir constantly!
  27.  *    8/6/88        convert to open mhash. malloc targets.
  28.  *            add stomp. remove BEEP, STOMP, MT, HOST, AT
  29.  *            use static filenamestrings.
  30.  *    8/8/88!        keep boottime and sendtime in struct machine.
  31.  *            report reboots.
  32.  *    8/9/88        All dressed up. Ready to go!
  33.  */
  34.  
  35. /* do reverse video for machines? */
  36.  
  37. # include <sys/types.h>
  38. # include <sys/stat.h>
  39. # include <sys/dir.h>
  40. # include <strings.h>
  41. # include <stdio.h>
  42. # include <ctype.h>
  43. # include <protocols/rwhod.h>        /* But not on 4.2 systems!! */
  44.  
  45. # define EOS '\0'
  46. extern char *malloc();            /* from libc */
  47.  
  48. # define bool int
  49. # define TRUE 1
  50. # define FALSE 0
  51.  
  52. # define INITFILE ".fido"
  53.  
  54. # define DEF_BEEP    FALSE
  55. # define DEF_STAMP    TRUE
  56. # define DEF_MACHINES    TRUE
  57. # define DEF_DOWNTIME    8        /* minutes (less than 4 is noisy) */
  58. # define DEF_IDLETIME    15        /* minutes */
  59. # define DEF_SLEEPTIME    60        /* seconds */
  60. # define MIN_SLEEPTIME    32
  61.  
  62. # define MAXBUF 132            /* various buffers */
  63.  
  64. /* static lengths in target struct (fields from utmp) */
  65. # define MAXHST 33
  66. # define MAXUSR 9
  67. # define MAXTTY 9
  68.  
  69. # define NUMFILES 100        /* grrr -- a hardwired limit!! */
  70. # define BPHOST 32        /* avg length for hostnames ick!! */
  71.  
  72. struct target {
  73.     char *host, *user;
  74.     struct found {        /* count of entries found in each state */
  75.     int nidle, idle, hungry;
  76.     } found[2];            /* now and before */
  77.     struct target *tnext;
  78. };
  79. # define TOTAL(tp,t) ((tp)->found[t].idle + (tp)->found[t].nidle)
  80.  
  81. struct target *targets;        /* list of targets */
  82. struct target *lasttarget;    /* last target created */
  83. int numt = 0;            /* number of targets */
  84. int this = 0;            /* toggling index (0/1) into found array */
  85.  
  86. char wildhost[] = "*";
  87. # define WILDHOST wildhost    /* empty host for targets */
  88.  
  89. int beep = DEF_BEEP;
  90. int stamp = DEF_STAMP;
  91. int machines = DEF_MACHINES;
  92. int downtime = DEF_DOWNTIME * 60;
  93. int idletime = DEF_IDLETIME * 60;
  94. int sleeptime = DEF_SLEEPTIME;
  95.  
  96. char nowstr[ 50 ];            /* for time stomping */
  97.  
  98. struct machine {            /* hash table of machines */
  99.     char name[40];
  100.     enum { UP=1, DOWN=2 } state;
  101.     time_t latest;            /* last time seen up */
  102.     int boottime, sendtime;        /* from whod packet */
  103.     struct machine
  104.     *hnext,                /* next in hash chain */
  105.     *anext;                /* next in list of all hosts */
  106. };
  107.  
  108. # define MHSIZE 101            /* small prime */
  109. struct machine *mhash[ MHSIZE ], *allmachines;
  110. int firstpass = TRUE;
  111.  
  112. # if DEBUG > 0
  113. char *state_name[] = { "??", "UP", "DOWN" };
  114. # endif /* DEBUG > 0 */
  115.  
  116. # define WHODIR "/usr/spool/rwho"
  117.  
  118. # define ISHUNGRY(we) \
  119.     ((we->we_utmp.out_line[sizeof(we->we_utmp.out_line)-1] & 0200) != 0 )
  120.  
  121. # define CLEARHUNGRY(we) \
  122.     we->we_utmp.out_line[sizeof(we->we_utmp.out_line)-1] &= ~0200
  123.  
  124. main() {
  125.     int i;
  126.  
  127.     if( !readinit( INITFILE ) ) {    /* check current dir */
  128.     extern char *getenv();
  129.     char tname[ 1024 ], *hp;
  130.  
  131.     if( (hp = getenv("HOME")) == NULL ) { /* check 'home' */
  132.         /* getpwuid(getuid()) */
  133.         fprintf( stderr, "No ./.fido and HOME not set\n" );
  134.         exit( 1 );
  135.     } /* no HOME */
  136.     sprintf( tname, "%s/%s", hp, INITFILE );
  137.     if( !readinit( tname ) ) {
  138.         fprintf( stderr, "No ./.fido or %s\n", tname );
  139.         exit( 1 );
  140.     } /* readinit failed */
  141.     } /* no .fido in "." */
  142.  
  143. # if DEBUG > 0
  144.     dumpinit();
  145. # endif /* DEBUG > 0 */
  146.  
  147.     if( numt == 0 && !machines ) {
  148.     fprintf(stderr, "Nothing to do!!\n" );
  149.     exit( 1 );
  150.     } /* nothing to do!! */
  151.  
  152.     if( chdir( WHODIR ) < 0 ) {
  153.     perror( WHODIR );
  154.     exit( 1 );
  155.     } /* chdir failed */
  156.  
  157.     nice( 10 );                /* be nice to real users */
  158.  
  159.     for( ; ; ) {
  160.     dowho();            /* prowl rwho spool dir */
  161.     if( machines )            /* watching machines? */
  162.         scan();            /* yell about them */
  163.     this = !this;            /* toggle found index */
  164.     fflush( stdout );
  165.     sleep( sleeptime );        /* go to sleep */
  166.     if( getppid() == 1 )        /* child of init? */
  167.         exit( 1 );            /* quitting time */
  168.     } /* for ever */
  169. } /* main */
  170.  
  171. dowho() {                /* poke thru rwho spool */
  172.     register int i;
  173.     register struct target *tp;
  174.  
  175.     int now;
  176.     char **fp;
  177.     struct whod wd;
  178.     struct stat newstat;
  179.     char buf[MAXBUF], user[MAXUSR], host[MAXHST], tty[MAXTTY];
  180.  
  181.     static int nfiles;
  182.     static struct stat oldstat;
  183.     static char *filenames[ NUMFILES ];    /* ACK!! hardwired limits! */
  184.     static char filenamestrings[ NUMFILES * BPHOST ]; /* avoid malloc/free */
  185.  
  186.     if( stat( ".", &newstat ) < 0 )
  187.     return;
  188.  
  189.     if( newstat.st_mtime != oldstat.st_mtime ) {
  190.     DIR *dirp;
  191.     struct direct *d;
  192.     register char *dp;
  193.  
  194.     oldstat = newstat;
  195. # if DEBUG > 0
  196.     puts("(re)reading RWHODIR");
  197. # endif /* DEBUG > 0 */
  198.  
  199.     if( (dirp = opendir( "." )) == NULL )
  200.         return;
  201.  
  202.     nfiles = 0;
  203.     fp = filenames;
  204.     dp = filenamestrings;
  205.     while( (d = readdir( dirp )) != NULL ) {
  206.         register char *sp;
  207.  
  208.         if( strncmp( d->d_name, "whod.", 5 ) != 0 )
  209.         continue;
  210.  
  211. # if DEBUG > 4
  212.         printf("readdir: %s\n", d->d_name );
  213. # endif /* DEBUG > 4 */
  214.         if( nfiles == NUMFILES ) {
  215.         fprintf( stderr, "Too many files!! Increase NUMFILES!!\n");
  216.         break;
  217.         } /* too many files */
  218.  
  219.         nfiles++;
  220.         *fp++ = dp;
  221.         sp = d->d_name;
  222.         while( *dp++ = *sp++ )
  223.         ;
  224.     } /* while readdir */
  225.     closedir( dirp );
  226.     } /* rwhod mtime has changed */
  227.  
  228.     for( tp = targets, i = 0; i < numt; tp = tp->tnext, i++ ) {
  229.     tp->found[this].hungry = 0;
  230.     tp->found[this].nidle  = 0;
  231.     tp->found[this].idle   = 0;
  232.     } /* for i */
  233.  
  234.     time( &now );
  235.     if( stamp ) {
  236.     strcpy( nowstr, ctime( &now ) );
  237.     nowstr[ 16 ] = ' ';
  238.     nowstr[ 17 ] = EOS;        /* kill year and seconds */
  239.     } /* stamping */
  240.  
  241.     for( fp = filenames, i = 0; i < nfiles; i++, fp++ ) {
  242.     register struct whoent *we;
  243.     int f, cc, down;
  244.     time_t recvtime;
  245.     int try;
  246. # ifdef USEFILETIME
  247.     struct stat ftime;
  248. # endif /* USEFILETIME defined */
  249.  
  250. # if DEBUG > 19
  251.     printf("=== %s ===\n", *fp );
  252. # endif /* DEBUG > 19 */
  253.  
  254.     for( try = 0; try < 5; try++, sleep(1) ) {
  255.         cc = -1;
  256.         if( (f = open( *fp, 0 )) < 0 )
  257.         continue;        /* try to read again */
  258.  
  259.         cc = read( f, &wd, sizeof( wd ));
  260. # ifdef USEFILETIME
  261.         fstat( f, &ftime );
  262. # endif /* USEFILETIME defined */
  263.         close( f );
  264.  
  265.         cc -= sizeof( wd ) - sizeof ( wd.wd_we );
  266. # if DEBUG > 19
  267.         printf("%d chars\n", cc );
  268. # endif /* DEBUG > 19 */
  269.         if( cc < 0 ) {
  270. # if DEBUG > 0 && DEBUG < 20
  271.         printf("%s: %d chars\n", wd.wd_hostname, cc );
  272. # endif /* DEBUG > 0 && DEBUG < 20 */
  273.         continue;        /* re-read file */
  274.         } /* short file */
  275.         else
  276.         break;
  277.     } /* for each try */
  278.     if( cc < 0 )
  279.         continue;            /* re-read */
  280.  
  281. # ifdef USEFILETIME
  282.     recvtime = ftime.st_mtime;
  283. # else  /* USEFILETIME not defined */
  284.     recvtime = wd.wd_recvtime;
  285. # endif /* USEFILETIME not defined */
  286.  
  287.     down = now - recvtime;
  288. # if DEBUG > 19
  289.     printf( "down %d\n", down );
  290. # endif /* DEBUG > 19 */
  291.  
  292.     if( wd.wd_hostname[0] == EOS ) {
  293. # if DEBUG > 0
  294.         printf( "null hostname in file %s\n", *fp );
  295. # endif /* DEBUG > 0 */
  296.         continue;            /* re-read!? */
  297.     } /* hostname empty */
  298.  
  299.     if( machines )
  300.         if( wd.wd_hostname[0] != EOS )
  301.         process( &wd, recvtime );
  302.  
  303.     if( down > downtime )        /* host is down? */
  304.         continue;
  305.  
  306.     for( we = wd.wd_we; cc > 0 ; we++, cc -= sizeof( *we ) ) {
  307.         int tcnt;
  308.         int washungry;
  309.         register char *cp, *dp;
  310.  
  311.         washungry = ISHUNGRY(we);    /* save hungry bit */
  312.         CLEARHUNGRY(we);        /* clear to avoid bad comparisons */
  313.  
  314.         strncpy( user, we->we_utmp.out_name, 8 );
  315.         strcpy( host, wd.wd_hostname );
  316.         strcpy( tty, we->we_utmp.out_line );
  317.  
  318. # if DEBUG > 10
  319.         printf("%s@%s %s idle %d\n", user, host, tty, we->we_idle );
  320. # endif /* DEBUG > 10 */
  321.  
  322.         for( tp = targets, tcnt = 0; tcnt < numt; tcnt++, tp = tp->tnext ) {
  323.         if( strcmp(user, tp->user) == 0 ) { /* matching user */
  324.             if( (dp = index( host, '.' )) != NULL )
  325.             *dp = EOS;    /* strip domains */
  326.  
  327. # if DEBUG > 4
  328. # if DEBUG < 20
  329.             printf("%s@%s %s idle %d\n",
  330.                user, host, tty, we->we_idle );
  331. # endif /* DEBUG < 20 */
  332.             printf("%s %d %d\n", tp->user,
  333.                tp->found[this].nidle,
  334.                tp->found[this].idle );
  335. # endif /* DEBUG > 4 */
  336.  
  337.             if( tp->host == WILDHOST || /* wild or */
  338.                strcmp(host, tp->host) == 0 ) { /*matching host*/
  339.             if( we->we_idle > idletime )
  340.                 tp->found[this].idle++;
  341.             else {        /* not idle */
  342.                 if( tp->found[this].nidle++ == 0 && /*first*/
  343.                    tp->found[!this].nidle == 0 ) { /*none b4*/
  344. # if DEBUG > 0 && DEBUG < 5
  345.                 tprint( tp );
  346. # endif /* DEBUG > 0 && DEBUG < 5 */
  347.                 /* nothing before or, imbalance */
  348.                 if( tp->found[!this].idle == 0 ||
  349.                    TOTAL(tp,this) > TOTAL(tp,!this) )
  350.                     now_on( user, host, tty );
  351.                 else        /* return from idleness */
  352.                     now_active( user, host, tty );
  353.                 } /* first non idle where none before */
  354.             } /* not idle */
  355.             if( washungry )
  356.                 if( tp->found[this].hungry++ == 0 &&
  357.                    tp->found[!this].hungry == 0 )
  358.                 now_hungry( user, host, tty );
  359.             } /* matching host */
  360.             goto nextwhoent;
  361.         } /* matching user */
  362.         } /* for all targets */
  363.     nextwhoent: ;
  364.     } /* for we */
  365.     } /* for each file */
  366.    
  367.     for( tp = targets, i = 0; i < numt; i++, tp = tp->tnext ) {
  368. # if DEBUG > 49
  369.     tprint( tp );
  370. # endif /* DEBUG > 49 */
  371.     if( tp->found[!this].nidle > 0 ) {     /* was here before */
  372. # if DEBUG > 4 && DEBUG < 50
  373.         tprint( tp );
  374. # endif /* DEBUG > 4 && DEBUG < 50 */
  375.         if( tp->found[this].nidle == 0 ) {    /* no non idle users */
  376. # if DEBUG > 0 && DEBUG < 5
  377.         tprint( tp );
  378. # endif /* DEBUG > 0 && DEBUG < 5 */
  379.         if( tp->found[this].idle > 0 &&    /* have idle users */
  380.            TOTAL(tp,this) == TOTAL(tp,!this) ) /* no net change */
  381.             now_idle( tp->user, tp->host );
  382.         else
  383.             now_gone( tp->user, tp->host ); /* none idle or */
  384.                         /* net change. */
  385.                         /* must have logged out */
  386.         } /* no non-idle */
  387.     } /* prev had non-idle */
  388.     else if( tp->found[!this].idle > 0 ) {    /* prev idle? */
  389.         if( TOTAL(tp,this) == 0 ) {        /* no current */
  390. # if DEBUG > 0 && DEBUG < 5
  391.         tprint( tp );
  392. # endif /* DEBUG > 0 && DEBUG < 5 */
  393.         now_gone( tp->user, tp->host );
  394.         } 
  395.     } /* here but idle before */
  396.     } /* for tp */
  397. } /* do who */
  398.  
  399. now_on( user, host, tty )
  400.     char *user, *host, *tty;
  401. {
  402.     stomp();
  403.     printf("bow wow!! %s now on %s %s\n", user, host, tty );
  404. } /* now on */
  405.  
  406. now_active( user, host, tty )
  407.     char *user, *host, *tty;
  408. {
  409.     stomp();
  410.     printf("arf! %s active on %s %s\n", user, host, tty );
  411. } /* now active */
  412.  
  413. now_hungry( user, host, tty )
  414.     char *user, *host, *tty;
  415. {
  416.     stomp();
  417.     printf("woof! %s hungry on %s %s\n",  user, host, tty );
  418. } /* now hungry */
  419.  
  420. now_idle( user, host )
  421.     char *user, *host;
  422. {
  423.     stomp();
  424.     /* doggie noise here? */
  425.     fputs( user, stdout );
  426.     if( host != WILDHOST ) {
  427.     putchar('@');
  428.     fputs( host, stdout );
  429.     } /* have host */
  430.     puts(" is idle");
  431. } /* now idle */
  432.  
  433. now_gone( user, host )
  434.     char *user, *host;
  435. {
  436.     stomp();
  437.     /* doggie noise here? */
  438.     fputs( user, stdout );
  439.     if( host != WILDHOST ) {
  440.     putchar('@');
  441.     fputs( host, stdout );
  442.     } /* have host */
  443.     puts(" is gone");
  444. } /* now gone */
  445.  
  446. now_sated( user, host )
  447.     char *user, *host;
  448. {
  449.     stomp();
  450.     /* doggie noise here? */
  451.     fputs( user, stdout );
  452.     if( host != WILDHOST ) {
  453.     putchar('@');
  454.     fputs( host, stdout );
  455.     } /* have host */
  456.     puts(" is sated!!");
  457. } /* now sated */
  458.  
  459. bool
  460. checkflag( buf, name, ptr )
  461.     char *name, *buf;
  462.     bool *ptr;
  463. {
  464.     int l;
  465.  
  466.     l = strlen( name );
  467.     if( strncmp( name, buf, l ) == 0 )
  468.     *ptr = TRUE;
  469.     else if( buf[0] == 'n' && buf[1] == 'o' && strncmp( name, buf+2, l ) == 0 )
  470.     *ptr = FALSE;
  471.     else
  472.     return( FALSE );
  473.     return( TRUE );
  474. } /* checkflag */
  475.  
  476. bool
  477. numarg( buf, name, ptr, scale )
  478.     char *name, *buf;
  479.     int *ptr, scale;
  480. {
  481.     if( strncmp( name, buf, strlen( name ) ) == 0 ) {
  482.     int i;
  483.     if( sscanf( buf, "%*s %d", &i ) != 1 )
  484.         fprintf( stderr, "fido: bad line: %s\n", buf );
  485.     else
  486.         *ptr = i * scale;
  487.     return( TRUE );
  488.     } /* matches */
  489.     return( FALSE );
  490. } /* numarg */
  491.  
  492. bool
  493. readinit( file )
  494.     char *file;
  495. {
  496.     FILE *f;
  497.     char buf[ MAXBUF ];
  498.  
  499.     if( (f = fopen(file, "r")) == NULL )
  500.     return( FALSE );
  501.  
  502.     while( fgets(buf, sizeof buf, f) != NULL ) {
  503.     register char *cp;
  504.  
  505.     if( (cp = index(buf,'\n')) != NULL )
  506.         *cp = EOS;
  507.  
  508. # if DEBUG > 9
  509.     printf("%s\n", buf );
  510. # endif /* DEBUG > 9 */
  511.  
  512.     if( buf[0] == '#' )
  513.         continue;
  514.  
  515.     if( strncmp(buf, "user", 4) == 0 )
  516.         r_user( buf );
  517.     else if( checkflag(buf, "beep", &beep) )
  518.         continue;
  519.     else if( checkflag(buf, "machines", &machines) )
  520.         continue;
  521.     else if( checkflag(buf, "stamp", &stamp) )
  522.         continue;
  523.     else if( numarg(buf, "idletime", &idletime, 60)  )
  524.         continue;
  525.     else if( numarg(buf, "downtime", &downtime, 60)  )
  526.         continue;
  527.     else if( numarg(buf, "sleeptime", &sleeptime, 1) )
  528.         continue;
  529.     else
  530.         fprintf(stderr, "fido: bad line in %s: %s\n", file, buf );
  531.     } /* while */
  532.     if( sleeptime < MIN_SLEEPTIME )
  533.     sleeptime = MIN_SLEEPTIME;
  534.     fclose ( f );
  535.     return( TRUE );
  536. } /* readinit */
  537.  
  538. char *savestr( s )
  539. register char *s;
  540. {
  541.     register char *t;
  542.  
  543.     while( *s != EOS && isspace( *s ) )
  544.     s++;
  545.     if( *s == EOS )
  546.     return( "" );
  547.  
  548.     t = s;
  549.     while( *t != EOS && !isspace( *t ) && *t != '\n' )
  550.     t++;
  551.     if( *t != EOS )
  552.     *t = EOS;
  553.  
  554. # if DEBUG > 10
  555.     printf("savestr '%s'\n", s);
  556. # endif /* DEBUG > 10 */
  557.  
  558.     return( strcpy( malloc( strlen( s ) + 1 ), s) );
  559.     
  560. } /* savestr */
  561.  
  562. r_user( l )
  563. register char *l;
  564. {
  565.     register char *cp;
  566.     register struct target *tp;
  567.  
  568.     while( *l != EOS && !isspace( *l ) )
  569.       l++;
  570.  
  571.     while( *l != EOS && isspace( *l ) )
  572.       l++;
  573.  
  574.     if( *l == EOS )
  575.     return;
  576.  
  577.     tp = (struct target *) malloc( sizeof( struct target ) );
  578.     tp->tnext = NULL;
  579.  
  580.     if( targets == NULL )
  581.     targets = tp;
  582.     else
  583.     lasttarget->tnext = tp;
  584.  
  585.     if( (cp = index(l, '@')) != NULL ) {
  586.     *cp++ = EOS;            /* blast @ to tie off user */
  587.     if( *cp != EOS )        /* have host? */
  588.         tp->host = savestr( cp );    /* save it */
  589.     else                /* none? */
  590.         tp->host = WILDHOST;    /* WTF -- save as wild */
  591.     } /* have host */
  592.     else
  593.     tp->host = WILDHOST;
  594.     tp->user = savestr( l );
  595.  
  596.     tp->found[0].idle   = 0;
  597.     tp->found[0].nidle  = 0;
  598.     tp->found[0].hungry = 0;
  599.     tp->found[1].idle   = 0;
  600.     tp->found[1].nidle  = 0;
  601.     tp->found[1].hungry = 0;
  602.  
  603.     lasttarget = tp;
  604.     numt++;
  605. } /* r_user */
  606.  
  607. dumpinit() {
  608.     register int i;
  609.     register struct target *tp;
  610.  
  611.     for( tp = targets, i = 0; i < numt; tp = tp->tnext, i++ )
  612.     if( tp->host == WILDHOST )
  613.         printf("%s\n", tp->user );
  614.     else
  615.         printf("%s@%s\n", tp->user, tp->host );
  616. } /* dumpinit */
  617.  
  618. /**************** machine stuff ****************/
  619.  
  620. # define SH 7
  621. # define WS 32
  622. unsigned
  623. hash( n )
  624.     register char *n;
  625. {
  626.     register unsigned l, i;
  627.  
  628.     i = l = 0;
  629.     while( *n != EOS ) {
  630.     i = ((i << SH) | (i >> (WS-SH))) ^ *n++;
  631.     l++;
  632.     } /* while not end of string */
  633.     return( (i + l) % MHSIZE );
  634. } /* hash */
  635.  
  636. struct machine *
  637. findmachine( n )
  638.     char *n;
  639. {
  640.     int h;
  641.     register struct machine *mp;
  642.  
  643.     h = hash( n );
  644.     for( mp = mhash[ h ]; mp != NULL; mp = mp->hnext )
  645.     if( strcmp(mp->name, n) == 0 )
  646.         return( mp );
  647.     return( NULL );
  648. } /* findmachine */
  649.  
  650. struct machine *
  651. newmachine( n )
  652.     char *n;
  653. {
  654.     int h;
  655.     register struct machine *mp;
  656.  
  657.     mp = (struct machine *) malloc( sizeof( struct machine ) );
  658.     strcpy(mp->name, n);
  659.     mp->state = UP;
  660.  
  661.     mp->anext = allmachines;        /* put in list of all machines */
  662.     allmachines = mp;
  663.  
  664.     h = hash( n );            /* put in hash list */
  665.     mp->hnext = mhash[ h ];
  666.     mhash[ h ] = mp;
  667.  
  668.     if( !firstpass )
  669.     saynew( mp );
  670.  
  671.     return( mp );
  672. } /* newmachine */
  673.  
  674. process( wd, t )
  675.     struct whod *wd;
  676.     time_t t;
  677. {
  678.     struct machine *mp;
  679.  
  680.     if( (mp = findmachine( wd->wd_hostname )) != NULL ) {
  681. # if DEBUG > 10
  682.     printf("found machine: %s\n", wd->wd_hostname);
  683. # endif /* DEBUG > 10 */
  684.     if( wd->wd_boottime - mp->boottime > 120 ) { /* filter out freaks */
  685.         sayreboot( mp );
  686. # if DEBUG > 0        
  687.         printf("new %d old %d diff %d\n",
  688.            wd->wd_boottime,
  689.            mp->boottime,
  690.            wd->wd_boottime - mp->boottime );
  691. # endif /* DEBUG > 0 */
  692.     } /* new boottime */
  693.     } /* machine found */
  694.     else
  695.     mp = newmachine( wd->wd_hostname );
  696.  
  697.     mp->latest = t;            /* packet sendtime or file time */
  698.     mp->boottime = wd->wd_boottime;
  699.     mp->sendtime = wd->wd_sendtime;
  700. } /* process */
  701.  
  702. scan() {
  703.     register struct machine *mp;
  704.     int i;
  705.     time_t now;
  706.  
  707.     time( &now );
  708.     for( mp = allmachines; mp != NULL; mp = mp->anext ) {
  709. # if DEBUG > 4
  710.     printf("scan: %s (%s)\n", mp->name, state_name[ mp->state+1 ] );
  711. # endif /* DEBUG > 4 */
  712.     /*
  713.      * if /usr/spool/rwho is on another machine (via NFS) and our
  714.      * clocks differ we get alot of up/down noise.  there must be
  715.      * a good way to dampen this!!
  716.      *
  717.      * perhaps keep a new state "may be down" as a cushion
  718.      *
  719.      * perhaps keep threshold per host and increase each time the
  720.      * host comes "up" without having been rebooted (see
  721.      * wd_boottime)
  722.      */
  723.     if( now - mp->latest > downtime ) { /* now down */
  724.         if( mp->state != DOWN ) {
  725.         saydown( mp, now - mp->latest );
  726.         mp->state = DOWN;
  727.         } /* new state: down */
  728.     } /* now down */
  729.     else {            /* now up */
  730.         if( mp->state != UP ) {
  731.         sayup( mp );
  732.         mp->state = UP;
  733.         } /* new state: up */
  734.     } /* now up */
  735.     } /* for all machines */
  736.     firstpass = FALSE;
  737. } /* scan */
  738.  
  739. stomp() {
  740.     if( beep )
  741.     putchar('\007');
  742.     if( stamp )
  743.     fputs( nowstr, stdout );
  744. } /* stomp */
  745.  
  746. saydown( mp, t )
  747.     struct machine *mp;
  748.     int t;
  749. {
  750.     int d, h, m;
  751.  
  752.     stomp();
  753.     printf("%s is down (", mp->name );
  754.     t /= 60;                /* toss seconds */
  755.     m = t % 60;                /* get mins */
  756.     t /= 60;                /* toss mins */
  757.     d = t % 24;                /* get days */
  758.     t /= 24;                /* cast out days */
  759.     t %= 7;                /* get weeks!! */
  760.     if( t > 0 ) printf("%dw", t );
  761.     if( d > 0 ) printf("%dd", d );
  762.     if( h > 0 ) printf("%dh", h );
  763.     if( m > 0 ) printf("%dm", m );
  764.     puts(")");
  765. } /* saydown */
  766.  
  767. sayup( mp )
  768.     struct machine *mp;
  769. {
  770.     stomp();
  771.     printf("%s is up\n", mp->name );
  772. } /* sayup */
  773.  
  774. saynew( mp )
  775.     struct machine *mp;
  776. {
  777.     stomp();
  778.     printf("new machine: %s\n", mp->name );
  779. } /* saynew sayme */
  780.  
  781. sayreboot( mp )
  782.     struct machine *mp;
  783. {
  784.     stomp();
  785.     printf("%s rebooted\n", mp->name );
  786. } /* saynew sayme */
  787.  
  788. # if DEBUG > 0
  789. tprint( tp )
  790.     register struct target *tp;
  791. {
  792.     printf("%s (%d %d %d) (%d %d %d)",
  793.        tp->user,
  794.  
  795.        tp->found[this].nidle,
  796.        tp->found[this].idle,
  797.        tp->found[this].hungry,
  798.  
  799.        tp->found[!this].nidle,
  800.        tp->found[!this].idle,
  801.        tp->found[!this].hungry
  802.        );
  803.     if( TOTAL(tp,this) != TOTAL(tp,!this) )
  804.     printf(" ***** net imbalance!! *****");
  805.     puts("");
  806. } /* tprint */
  807. # endif /* DEBUG > 0 */
  808.