home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / ru2 / ru.c < prev    next >
C/C++ Source or Header  |  1989-04-19  |  14KB  |  583 lines

  1. /*
  2.  * ru - remote users(1)
  3.  *    usage: ru [-acdmrsuw] [-D domain] [-h host ... | -l user ...]
  4.  * List users on all "visible" hosts.
  5.  *
  6.  * Copyright (c) 1989 University of Toronto. All rights reserved.
  7.  * Anyone may use or copy this software, except that it may not be
  8.  * sold for profit, that this copyright notice remain intact, and that
  9.  * credit is given where it is due. The University of Toronto and the
  10.  * author make no warranty and accept no liability for this software.
  11.  *
  12.  * Written by P. Kern (pkern@utcsri)
  13.  * with bug fixes and suggestions from
  14.  *    nispa@hutcs.hut.fi <Tapani Lindgren>
  15.  *    kusalik@damask.uucp
  16.  *    pkh%cs.nott.ac.uk@nss.cs.ucl.ac.uk <Kevin Hopkins>
  17.  *    lamy@ai.toronto.edu <Jean-Francois Lamy>
  18.  *    moraes@csri.toronto.edu <Mark Moraes>
  19.  *
  20.  * $Header: ru.c,v 2.9 89/02/26 13:48:36 pkern Exp $
  21.  */
  22.  
  23. #include <stdio.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <sys/dir.h>
  27. #include <sys/file.h>
  28. #include <netdb.h>
  29.  
  30. #define MINSTR    8        /* minimum string length */
  31. #define HNSZ    32        /* hostname length */
  32. #define RWFSZ    HNSZ+5        /* spool-file name length */
  33. #define MRGN    10        /* margin "tab" size */
  34. #define HOUR    3600        /* seconds in an hour */
  35. #define RWPERIOD    300    /* std. 5 minute rwho refresh period */
  36. #define MAXPORTS    160    /* max tty ports per host */
  37.  
  38. struct rw_utmp {    /* rwho file user info */
  39.     char tty[MINSTR];    /* user's tty */
  40.     char name[MINSTR];    /* user's login */
  41.     long time;        /* login time */
  42.     long idle;        /* idle time */
  43. } rut;
  44.  
  45. struct rw_hdr {        /* rwho data/host info */
  46.     char pad[4];        /* ignore first 4 bytes */
  47.     int sent, rcvd;        /* time sent,  time rec'vd */
  48.     char host[HNSZ];    /* host's name */
  49.     int loadav[3];        /* load averages */
  50.     int boot;        /* boot date */
  51. } hdr;
  52.  
  53. int rutsize, hdrsize;
  54. #ifdef debug
  55. #define RWHODIR    "rwho"
  56. #else
  57. #define RWHODIR "/usr/spool/rwho"
  58. #endif
  59.  
  60. long now;        /* it won't be ... (long now :-) */
  61. int n, fd;
  62. struct stat st;
  63. char *hnbuf, *hp;    /* hostname buffer & extra pointer */
  64. char *rubuf, *ep;    /* utmp data buffer & end pointer */
  65. char *program, *domain;
  66.     /* Flags: if (flag) then ... */
  67. int aflag=1;    /* ... only show users with <1 HR idle time */
  68. int sflag=1;    /* ... show output by domains (not by hosts) */
  69. int mflag=1;    /* ... drop multiple logins */
  70. int cflag=0;    /* ... (if mflag) show login counts */
  71. int dflag=1;    /* ... sort hostnames within domains */
  72. int Dflag=0;    /* ... show users in a given domain */
  73. int hflag=0;    /* ... show users on a given host */
  74. int lflag=0;    /* ... show hosts with given user */
  75. int rflag=0;    /* ... retro -- imitiate rwho */
  76. int uflag=0;    /* ... show uptimes (like ruptime) */
  77. int wflag=0;    /* ... break lines before wraparound */
  78. int errflag=0;
  79.  
  80. int wlim=80;    /* default screen width */
  81.  
  82. extern char *rindex(), *malloc(), *getenv();
  83.  
  84. main(argc, argv)
  85. int argc;
  86. char *argv[];
  87. {
  88.     DIR *dirp;
  89.     struct direct *dp;
  90.     int rwfcmp(), rutcmp(), drwcmp();    /* qsort() routines */
  91.     extern int optind;    /* see getopt(3C) */
  92.     extern char *optarg;    /* see getopt(3C) */
  93.  
  94.     program = argv[0];
  95.     now = time(0);
  96.     rutsize = sizeof(rut);
  97.     hdrsize = sizeof(hdr);
  98.  
  99.     while ((n = getopt(argc, argv, "acdhlmrsuwD:")) != EOF)
  100.         switch(n) {
  101.         case 'a': aflag=0; break;    /* same as rwho(1) */
  102.         case 'c': cflag=1; break;    /* show login count */
  103.         case 'd': dflag=0; break;    /* domain-wise sort */
  104.         case 'm': mflag=0; break;    /* show multi-logins */
  105.         case 'r': rflag++; break;    /* rwho-style output */
  106.         case 's': sflag=0; break;    /* domain-only lists */
  107.         case 'u': uflag++; break;    /* show uptimes */
  108.         case 'w': wflag++; break;    /* break long lines */
  109.         case 'D': Dflag++; domain = optarg; break;
  110.         case 'h': hflag++; break;    /* host-list follows */
  111.         case 'l': lflag++; break;    /* user-list follows */
  112.         default: errflag++;
  113.         }
  114.  
  115.     /*
  116.      * Note: -h and -l are mutually exclusive since both options
  117.      * use the remaining arguments as a search list. Either option
  118.      * should be followed by at least one name.  The getopt switch
  119.      * could have been arranged to only use whichever flag (l or h)
  120.      * was typed last but this way the user will know that there is
  121.      * a potential problem.
  122.      */
  123.     if (errflag || (lflag && hflag)
  124.         || (optind >= argc && (lflag || hflag))) {
  125.         fprintf(stderr, "Usage: %s [-acdmrsuw] [-D domain] [-h host ... | -l user ... ]\n", program);
  126.         exit(1);
  127.     }
  128.  
  129.     if (!dflag || lflag || rflag || uflag) sflag=0;
  130.     if (!mflag) cflag=0;    /* not really needed (see burp()) */
  131.  
  132.     if (chdir(RWHODIR) < 0) {    /* cd RWHODIR */
  133.         perror(RWHODIR);
  134.         exit(1);
  135.     }
  136.  
  137.     if (wflag) {    /* wrapping, eh? ok, get screen width */
  138.         int n;
  139.         char buf[1024];
  140.  
  141.         if ((hp = getenv("TERM")) == NULL) {
  142.             wflag = 0;
  143. #ifdef SQUAWK
  144.             fprintf(stderr, "%s: no TERM?\n", program);
  145. #endif
  146.         }
  147.         if (wflag && tgetent(buf, hp) < 0) {
  148.             wflag = 0;
  149. #ifdef SQUAWK
  150.             fprintf(stderr, "%s: no TERMCAP?\n", program);
  151. #endif
  152.         }
  153.         if (wflag && (n = tgetnum("co")) > 0 && n > MRGN+MINSTR)
  154.             wlim = n;
  155.     }
  156.  
  157.     if (hflag) {
  158.         sflag=0;
  159.         for ( ;optind < argc; optind++)
  160.             dohost(argv[optind]);
  161.         exit(0);
  162.     }
  163.  
  164.     /*
  165.      * read "." directory (assuming chdir() worked), 
  166.      * and get all files with the "whod." prefix.
  167.      * if Dflag, only get files ending with "domain".
  168.      */
  169.     if ((dirp = opendir(".")) == NULL
  170.         || stat(".", &st) < 0) { 
  171.         perror(RWHODIR);
  172.         exit(1);
  173.     }
  174.     dp = readdir(dirp);    /* get "." */
  175.     n = (st.st_size/(DIRSIZ(dp)+8))*RWFSZ;
  176.     hnbuf = malloc((unsigned)n);
  177.     n = 0; ep = hnbuf;
  178.     while (dp = readdir(dirp)) {
  179.         strncpy(ep, dp->d_name, dp->d_namlen);
  180.         *(ep+dp->d_namlen) = '\0';
  181.         if (strncmp(ep, "whod.", 5) == 0 &&
  182.            (!Dflag || strcmp(rindex(ep,'.')+1,domain) == 0)) {
  183.             ep += RWFSZ;
  184.             n++;
  185.         }
  186.     }
  187.     /* ep should now point to the end of the host name buffer */
  188.     closedir(dirp);
  189.  
  190.     if (dflag)    /* sort host names within domains */
  191.         qsort(hnbuf, n, RWFSZ, drwcmp);
  192.     else        /* sort full host name */
  193.         qsort(hnbuf, n, RWFSZ, rwfcmp);
  194.  
  195.     if (sflag) {    /* process by domains only */
  196.         dodomains();
  197.         exit(0);
  198.     }
  199.  
  200.     /*
  201.      * process each "whod." file in hnbuf list.
  202.      * - get <filesize> bytes of mem
  203.      * - gobble rutmp data from file
  204.      * - sort names alphabetically
  205.      * - print names (burp)
  206.      * - free up mem
  207.      */
  208.     hp = hnbuf;
  209.     while (hp < ep) {
  210.         if ((fd = open(hp, O_RDONLY)) < 0
  211.             || fstat(fd, &st) < 0) {
  212.             perror(hp);
  213.             exit(1);
  214.         }
  215.         if ((n = st.st_size-hdrsize) || uflag) {
  216.             if ((rubuf = malloc((unsigned)n)) == 0) {
  217.                 perror(program);
  218.                 exit(1);
  219.             }
  220.             n = read(fd, (char *)&hdr, hdrsize);
  221.             n = ldrut(fd,rubuf,st.st_size-hdrsize);
  222.             if (uflag)
  223.                 slurp(&hdr, n/rutsize);
  224.             else
  225. #ifdef debug
  226.             if (n > 0){
  227. #else
  228.             if (now-hdr.rcvd <= RWPERIOD && n > 0){
  229. #endif
  230.                 qsort(rubuf, n/rutsize, rutsize, rutcmp);
  231.                 if (!lflag || chew(rubuf,n,argc,argv))
  232.                     burp(hp, rubuf, n);
  233.             }
  234.         }
  235.         free(rubuf);
  236.         close(fd);
  237.         hp += RWFSZ;
  238.     }
  239. }
  240.  
  241. /*
  242.  * compare rwho spool-file names
  243.  */
  244. rwfcmp(p, q)
  245. register char *p, *q;
  246. {
  247.     return(strncmp(p, q, RWFSZ));
  248. }
  249.  
  250. /*
  251.  * compare utmp name entries
  252.  */
  253. rutcmp(p, q)
  254. register struct rw_utmp *p, *q;
  255. {
  256.     return(strncmp(p->name, q->name, MINSTR));
  257.  
  258. /*
  259.  * compare sub-domain names
  260.  */
  261. drwcmp(p, q)
  262. register char *p, *q;
  263. {
  264.     int x;
  265.     char *s, *t;
  266.  
  267.     s = rindex(p, '.');
  268.     t = rindex(q, '.');
  269.     if (s) s++; else s = p;
  270.     if (t) t++; else t = q;
  271.     if(x = strncmp(s, t, RWFSZ))
  272.         return(x);
  273.     return(strncmp(p, q, RWFSZ));
  274. }
  275.  
  276. /*
  277.  * print "host:       user1 user2 ... "
  278.  *    or whatever format the flags dictate.
  279.  * (blame creeping featurism for this mass of spaghetti)
  280.  */
  281. burp(s, r, n)
  282. register char *s, *r;
  283. int n;
  284. {    
  285.     int wdent;
  286.     register int l, wo, sl;
  287.     register char *xp;
  288.     char tbuf[RWFSZ+MINSTR+2];
  289.  
  290.     if (!sflag) s += 5;        /* skip "whod." prefix */
  291.  
  292.     if (rflag) {    /* rwho-like output */
  293.         register struct rw_utmp *rp;
  294.  
  295.         sprintf(tbuf, "%.*s:", HNSZ, s);
  296.         sl = strlen(tbuf);
  297.         for (xp = r; xp < (r+n); xp += rutsize) {
  298.             rp = (struct rw_utmp *)xp;
  299.             strncpy(tbuf + sl, rp->tty, MINSTR);
  300.             printf("%-8.8s %-23s %.12s",
  301.                  rp->name, tbuf, ctime(&rp->time) + 4);
  302.             if (rp->idle < 60)
  303.                 printf("\n");
  304.             else {
  305.                 l = rp->idle/HOUR;
  306.                 wo = (rp->idle % HOUR)/60;
  307.                 if (l > 99)
  308.                     wo = 59, l = 99;
  309.                 printf((l) ? " %2d" : "   ", l);
  310.                 printf(":%02d\n", wo);
  311.             }
  312.         }
  313.         return;
  314.     }
  315.  
  316.     /* print host- or domain-name */
  317.     if (sflag && cflag)    /* include # of hosts in domain */
  318.         sprintf(tbuf, "%.*s/%d:", MRGN, s, sflag);
  319.     else
  320.         sprintf(tbuf, "%.*s:", MRGN+((!sflag) * 4), s);
  321.  
  322.     printf("%-*s", wo = wdent = MRGN+((!sflag) * 5), s = tbuf);
  323.  
  324.     if (n && mflag) {    /* print "user1 user2 ..." */
  325.         for(l=0, xp=s=r+MINSTR; s < (r+n); s += rutsize)
  326.             if (strncmp(s, xp, MINSTR)) {
  327.                 sprintf(tbuf,
  328.                     (l>1)?" %.*s/%d":" %.*s",
  329.                     MINSTR, xp, l);
  330.                 if (wflag) {    /* wrap and indent */
  331.                     if ((sl=strlen(tbuf)) > wlim-wo)
  332.                         printf("\n%*s",
  333.                             wo = wdent, "");
  334.                     wo += sl;
  335.                 }
  336.                 fputs(tbuf, stdout);
  337.                 xp = s; l = cflag;
  338.             }
  339.             else
  340.                 l += cflag;
  341.         /* still one name left to do */
  342.         sprintf(tbuf,(l>1)?" %.*s/%d\n":" %.*s\n",MINSTR,xp,l);
  343.         if (wflag && (strlen(tbuf)-1) > wlim - wo)
  344.             printf("\n%*s", wo = wdent, "");
  345.         fputs(tbuf, stdout);
  346.         return;
  347.     }
  348.  
  349.     /* ... else don't ignore multi-logins */
  350.     for (s = r+MINSTR; s < (r+n); s += rutsize) {
  351.         if (wflag) {    /* wrap and indent */
  352.             if ((sl = strlen(s)) > MINSTR)
  353.                 sl = MINSTR;
  354.             if (++sl > wlim - wo)
  355.                 printf("\n%*s", wo = wdent, "");
  356.             wo += sl;
  357.         }
  358.         printf(" %.*s", MINSTR, s);
  359.     }
  360.     printf("\n");
  361. }
  362.  
  363. /*
  364.  * print uptimes (like ruptime(1))
  365.  */
  366. slurp(h, n)
  367. struct rw_hdr *h;
  368. int n;
  369. {
  370.     char tbuf[128];
  371.     register char *p;
  372.     register int tdif;
  373.  
  374.     /* host name */
  375.     p = tbuf;
  376.     sprintf(p, "%-15.15s", h->host);
  377.  
  378.     /* if rcvd-time is >1 hour old then assume host is down */
  379.     tdif = now - h->rcvd; p += 15;
  380.     if (tdif > HOUR) {
  381.         if (tdif > (24 * HOUR)) 
  382.             sprintf(p, "down %3d+%02d:%02d\n",
  383.                 (tdif / (24 * HOUR)),
  384.                 (tdif % (24 * HOUR)) / HOUR,
  385.                 (tdif % HOUR) / 60);
  386.         else
  387.             sprintf(p, "down %6d:%02d\n",
  388.                 tdif / HOUR, (tdif % HOUR) / 60);
  389.         fputs(tbuf, stdout);
  390.         return;
  391.     }
  392.  
  393.     /* print host's uptime but include a '*' if
  394.      * rcvd-time is between 5 mins and 1 hour old */
  395.     sprintf(p, "%c up ", (tdif > RWPERIOD) ? '*' : ' ');
  396.     tdif = now - h->boot; p += 5;
  397.     if (tdif < 1)    /* host's boottime > our current time */
  398.         sprintf(p, "    ??:??");
  399.     else if (tdif > (24 * HOUR)) 
  400.         sprintf(p, "%3d+%02d:%02d",
  401.             (tdif / (24 * HOUR)),
  402.             (tdif % (24 * HOUR)) / HOUR,
  403.             (tdif % HOUR) / 60);
  404.     else
  405.         sprintf(p, "%6d:%02d", tdif / HOUR, (tdif % HOUR) / 60);
  406.  
  407.     /* print # of users and the 3 load numbers */
  408.     p += 9;
  409.     sprintf(p, ", %5d user%s load: %2d.%02d, %2d.%02d, %2d.%02d\n",
  410.         n, (n == 1) ? ", " : "s,",
  411.         h->loadav[0]/100, h->loadav[0]%100,
  412.         h->loadav[1]/100, h->loadav[1]%100,
  413.         h->loadav[2]/100, h->loadav[2]%100);
  414.     fputs(tbuf, stdout);
  415. }
  416.  
  417. /*
  418.  * show users on a specific host
  419.  */
  420. dohost(host)
  421. char *host;
  422. {
  423.     struct hostent *h, *gethostbyname();
  424.  
  425.     /*
  426.      * try to get host's proper name
  427.      * and try to find the proper spool file
  428.      */
  429.     if((h = gethostbyname(host)) == NULL) {
  430.         hp = malloc(strlen(host)+MINSTR);
  431.         sprintf(hp, "whod.%s", host);
  432. /*
  433.         perror(host);
  434.         return(1);
  435.  */
  436.     }
  437.     else {
  438.         hp = malloc(strlen(h->h_name)+MINSTR);
  439.         sprintf(hp, "whod.%s", h->h_name);
  440.     }
  441.     if ((fd = open(hp, O_RDONLY)) < 0 && h != NULL) {
  442.         char **s;
  443.         /*
  444.          * can't find file related to h_name
  445.          * try the aliases instead.
  446.          */
  447.         s = h->h_aliases;
  448.         while(*s) {
  449.             free(hp);
  450.             hp = malloc(strlen(*s)+MINSTR);
  451.             sprintf(hp, "whod.%s", *s);
  452.             if ((fd = open(hp, O_RDONLY)) > 0)
  453.                 break;
  454.             s++;
  455.         }
  456.         if (*s == NULL) {
  457.             fprintf(stderr,  "%s: no data\n",  host);
  458.             return(1);
  459.         }
  460.     }
  461.     if ((fd > 0 && fstat(fd, &st) < 0) || stat(hp, &st) < 0) {
  462.         if (fd < 0)
  463.             fprintf(stderr, "%s: unknown host\n", host);
  464.         else
  465.             perror(hp);
  466.         return(1);
  467.     }
  468.     n = st.st_size - hdrsize;
  469.     if ((rubuf = malloc((unsigned)n)) == 0) {
  470.         perror(program);
  471.         exit(1);
  472.     }
  473.     n = read(fd, (char *)&hdr, hdrsize);
  474.     n = ldrut(fd,rubuf,st.st_size-hdrsize);
  475.     if (uflag)
  476.         slurp(&hdr, n/rutsize);
  477.     else {
  478.         if (now-hdr.rcvd > RWPERIOD)
  479.             strcat(hp, "*");
  480.         qsort(rubuf, n/rutsize, rutsize, rutcmp);
  481.         burp(hp, rubuf, n);
  482.     }
  483. }
  484.  
  485. /*
  486.  * show users by domain
  487.  */
  488. dodomains()
  489. {
  490.     int z;
  491.     register int i;
  492.     char *p0, *p1, *fnp, *rbp;
  493.  
  494.     fnp = hp = hnbuf;
  495.  
  496.     if ((rubuf = malloc(n * MAXPORTS * rutsize)) == NULL) {
  497.         perror(program);
  498.         exit(1);
  499.     }
  500.  
  501.     p0 = rindex(fnp, '.') + 1;
  502.     if ((int)p0 == 1) p0 = fnp;
  503.  
  504.     while (fnp < ep) {
  505.         rbp = rubuf;
  506.         for (p1=p0, n=i=0; fnp < ep && !strcmp(p1, p0); i++) {
  507.             if ((fd = open(fnp, O_RDONLY)) < 0
  508.                 || fstat(fd, &st) < 0) {
  509.                 perror(fnp);
  510.                 exit(1);
  511.             }
  512.             read(fd, (char *)&hdr, hdrsize);
  513.             z = ldrut(fd,rbp,st.st_size-hdrsize);
  514. #ifdef debug
  515.             if (z > 0) {
  516. #else
  517.             if (now-hdr.rcvd <= RWPERIOD && z > 0) {
  518. #endif
  519.                 n += z;
  520.                 rbp += z;
  521.             }
  522.             close(fd);
  523.             fnp += RWFSZ;
  524.             p1 = p0;
  525.             p0 = rindex(fnp, '.') + 1;
  526.             if ((int)p0 == 1) p0 = fnp;
  527.         }
  528.         if (!n) continue;
  529.         *rbp = '\0';
  530.         qsort(rubuf, n/rutsize, rutsize, rutcmp);
  531.         sflag = i;
  532.         burp(p1, rubuf, n);
  533.     }
  534.     free(rubuf);
  535. }
  536.  
  537. /*
  538.  * load rutmp data into buffer.
  539.  */
  540. ldrut(fd, p, n)
  541. int fd, n;
  542. char *p;
  543. {
  544.     register int m1, m2, nr;
  545.     register char *s;
  546.  
  547.     if (!aflag) return(read(fd, p, n));
  548.  
  549.     s = p;
  550.     m1 = m2 = 0;
  551.  
  552.     while (m2 < n && (nr = read(fd, s, rutsize)) > 0) {
  553.         m2 += nr;
  554.         if (((struct rw_utmp *)s)->idle > HOUR)
  555.             /* ignore entries with >1 hr idle time */
  556.             continue;
  557.         m1 += nr;
  558.         s += nr;
  559.     }
  560.     return(m1);
  561. }
  562.  
  563. /*
  564.  * search a file's data for given users
  565.  */
  566. chew(r, n, ac, av)
  567. char *r, *av[];
  568. int n, ac;
  569. {
  570.     register int i;
  571.     register char *p;
  572.     extern int optind;
  573.  
  574.     /* grotty old standard linear search */
  575.     for (p = r+MINSTR; p < (r+n); p += rutsize)
  576.         for (i=optind; i<ac; i++)
  577.             if (*p == av[i][0]
  578.                 && !strncmp(av[i], p, MINSTR))
  579.                 return (1);
  580.     return(0);
  581. }
  582.