home *** CD-ROM | disk | FTP | other *** search
- /*
- * ru - remote users(1)
- * usage: ru [-acdmrsuw] [-D domain] [-h host ... | -l user ...]
- * List users on all "visible" hosts.
- *
- * Copyright (c) 1989 University of Toronto. All rights reserved.
- * Anyone may use or copy this software, except that it may not be
- * sold for profit, that this copyright notice remain intact, and that
- * credit is given where it is due. The University of Toronto and the
- * author make no warranty and accept no liability for this software.
- *
- * Written by P. Kern (pkern@utcsri)
- * with bug fixes and suggestions from
- * nispa@hutcs.hut.fi <Tapani Lindgren>
- * kusalik@damask.uucp
- * pkh%cs.nott.ac.uk@nss.cs.ucl.ac.uk <Kevin Hopkins>
- * lamy@ai.toronto.edu <Jean-Francois Lamy>
- * moraes@csri.toronto.edu <Mark Moraes>
- *
- * $Header: ru.c,v 2.9 89/02/26 13:48:36 pkern Exp $
- */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/dir.h>
- #include <sys/file.h>
- #include <netdb.h>
-
- #define MINSTR 8 /* minimum string length */
- #define HNSZ 32 /* hostname length */
- #define RWFSZ HNSZ+5 /* spool-file name length */
- #define MRGN 10 /* margin "tab" size */
- #define HOUR 3600 /* seconds in an hour */
- #define RWPERIOD 300 /* std. 5 minute rwho refresh period */
- #define MAXPORTS 160 /* max tty ports per host */
-
- struct rw_utmp { /* rwho file user info */
- char tty[MINSTR]; /* user's tty */
- char name[MINSTR]; /* user's login */
- long time; /* login time */
- long idle; /* idle time */
- } rut;
-
- struct rw_hdr { /* rwho data/host info */
- char pad[4]; /* ignore first 4 bytes */
- int sent, rcvd; /* time sent, time rec'vd */
- char host[HNSZ]; /* host's name */
- int loadav[3]; /* load averages */
- int boot; /* boot date */
- } hdr;
-
- int rutsize, hdrsize;
- #ifdef debug
- #define RWHODIR "rwho"
- #else
- #define RWHODIR "/usr/spool/rwho"
- #endif
-
- long now; /* it won't be ... (long now :-) */
- int n, fd;
- struct stat st;
- char *hnbuf, *hp; /* hostname buffer & extra pointer */
- char *rubuf, *ep; /* utmp data buffer & end pointer */
- char *program, *domain;
- /* Flags: if (flag) then ... */
- int aflag=1; /* ... only show users with <1 HR idle time */
- int sflag=1; /* ... show output by domains (not by hosts) */
- int mflag=1; /* ... drop multiple logins */
- int cflag=0; /* ... (if mflag) show login counts */
- int dflag=1; /* ... sort hostnames within domains */
- int Dflag=0; /* ... show users in a given domain */
- int hflag=0; /* ... show users on a given host */
- int lflag=0; /* ... show hosts with given user */
- int rflag=0; /* ... retro -- imitiate rwho */
- int uflag=0; /* ... show uptimes (like ruptime) */
- int wflag=0; /* ... break lines before wraparound */
- int errflag=0;
-
- int wlim=80; /* default screen width */
-
- extern char *rindex(), *malloc(), *getenv();
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- DIR *dirp;
- struct direct *dp;
- int rwfcmp(), rutcmp(), drwcmp(); /* qsort() routines */
- extern int optind; /* see getopt(3C) */
- extern char *optarg; /* see getopt(3C) */
-
- program = argv[0];
- now = time(0);
- rutsize = sizeof(rut);
- hdrsize = sizeof(hdr);
-
- while ((n = getopt(argc, argv, "acdhlmrsuwD:")) != EOF)
- switch(n) {
- case 'a': aflag=0; break; /* same as rwho(1) */
- case 'c': cflag=1; break; /* show login count */
- case 'd': dflag=0; break; /* domain-wise sort */
- case 'm': mflag=0; break; /* show multi-logins */
- case 'r': rflag++; break; /* rwho-style output */
- case 's': sflag=0; break; /* domain-only lists */
- case 'u': uflag++; break; /* show uptimes */
- case 'w': wflag++; break; /* break long lines */
- case 'D': Dflag++; domain = optarg; break;
- case 'h': hflag++; break; /* host-list follows */
- case 'l': lflag++; break; /* user-list follows */
- default: errflag++;
- }
-
- /*
- * Note: -h and -l are mutually exclusive since both options
- * use the remaining arguments as a search list. Either option
- * should be followed by at least one name. The getopt switch
- * could have been arranged to only use whichever flag (l or h)
- * was typed last but this way the user will know that there is
- * a potential problem.
- */
- if (errflag || (lflag && hflag)
- || (optind >= argc && (lflag || hflag))) {
- fprintf(stderr, "Usage: %s [-acdmrsuw] [-D domain] [-h host ... | -l user ... ]\n", program);
- exit(1);
- }
-
- if (!dflag || lflag || rflag || uflag) sflag=0;
- if (!mflag) cflag=0; /* not really needed (see burp()) */
-
- if (chdir(RWHODIR) < 0) { /* cd RWHODIR */
- perror(RWHODIR);
- exit(1);
- }
-
- if (wflag) { /* wrapping, eh? ok, get screen width */
- int n;
- char buf[1024];
-
- if ((hp = getenv("TERM")) == NULL) {
- wflag = 0;
- #ifdef SQUAWK
- fprintf(stderr, "%s: no TERM?\n", program);
- #endif
- }
- if (wflag && tgetent(buf, hp) < 0) {
- wflag = 0;
- #ifdef SQUAWK
- fprintf(stderr, "%s: no TERMCAP?\n", program);
- #endif
- }
- if (wflag && (n = tgetnum("co")) > 0 && n > MRGN+MINSTR)
- wlim = n;
- }
-
- if (hflag) {
- sflag=0;
- for ( ;optind < argc; optind++)
- dohost(argv[optind]);
- exit(0);
- }
-
- /*
- * read "." directory (assuming chdir() worked),
- * and get all files with the "whod." prefix.
- * if Dflag, only get files ending with "domain".
- */
- if ((dirp = opendir(".")) == NULL
- || stat(".", &st) < 0) {
- perror(RWHODIR);
- exit(1);
- }
- dp = readdir(dirp); /* get "." */
- n = (st.st_size/(DIRSIZ(dp)+8))*RWFSZ;
- hnbuf = malloc((unsigned)n);
- n = 0; ep = hnbuf;
- while (dp = readdir(dirp)) {
- strncpy(ep, dp->d_name, dp->d_namlen);
- *(ep+dp->d_namlen) = '\0';
- if (strncmp(ep, "whod.", 5) == 0 &&
- (!Dflag || strcmp(rindex(ep,'.')+1,domain) == 0)) {
- ep += RWFSZ;
- n++;
- }
- }
- /* ep should now point to the end of the host name buffer */
- closedir(dirp);
-
- if (dflag) /* sort host names within domains */
- qsort(hnbuf, n, RWFSZ, drwcmp);
- else /* sort full host name */
- qsort(hnbuf, n, RWFSZ, rwfcmp);
-
- if (sflag) { /* process by domains only */
- dodomains();
- exit(0);
- }
-
- /*
- * process each "whod." file in hnbuf list.
- * - get <filesize> bytes of mem
- * - gobble rutmp data from file
- * - sort names alphabetically
- * - print names (burp)
- * - free up mem
- */
- hp = hnbuf;
- while (hp < ep) {
- if ((fd = open(hp, O_RDONLY)) < 0
- || fstat(fd, &st) < 0) {
- perror(hp);
- exit(1);
- }
- if ((n = st.st_size-hdrsize) || uflag) {
- if ((rubuf = malloc((unsigned)n)) == 0) {
- perror(program);
- exit(1);
- }
- n = read(fd, (char *)&hdr, hdrsize);
- n = ldrut(fd,rubuf,st.st_size-hdrsize);
- if (uflag)
- slurp(&hdr, n/rutsize);
- else
- #ifdef debug
- if (n > 0){
- #else
- if (now-hdr.rcvd <= RWPERIOD && n > 0){
- #endif
- qsort(rubuf, n/rutsize, rutsize, rutcmp);
- if (!lflag || chew(rubuf,n,argc,argv))
- burp(hp, rubuf, n);
- }
- }
- free(rubuf);
- close(fd);
- hp += RWFSZ;
- }
- }
-
- /*
- * compare rwho spool-file names
- */
- rwfcmp(p, q)
- register char *p, *q;
- {
- return(strncmp(p, q, RWFSZ));
- }
-
- /*
- * compare utmp name entries
- */
- rutcmp(p, q)
- register struct rw_utmp *p, *q;
- {
- return(strncmp(p->name, q->name, MINSTR));
- }
-
- /*
- * compare sub-domain names
- */
- drwcmp(p, q)
- register char *p, *q;
- {
- int x;
- char *s, *t;
-
- s = rindex(p, '.');
- t = rindex(q, '.');
- if (s) s++; else s = p;
- if (t) t++; else t = q;
- if(x = strncmp(s, t, RWFSZ))
- return(x);
- return(strncmp(p, q, RWFSZ));
- }
-
- /*
- * print "host: user1 user2 ... "
- * or whatever format the flags dictate.
- * (blame creeping featurism for this mass of spaghetti)
- */
- burp(s, r, n)
- register char *s, *r;
- int n;
- {
- int wdent;
- register int l, wo, sl;
- register char *xp;
- char tbuf[RWFSZ+MINSTR+2];
-
- if (!sflag) s += 5; /* skip "whod." prefix */
-
- if (rflag) { /* rwho-like output */
- register struct rw_utmp *rp;
-
- sprintf(tbuf, "%.*s:", HNSZ, s);
- sl = strlen(tbuf);
- for (xp = r; xp < (r+n); xp += rutsize) {
- rp = (struct rw_utmp *)xp;
- strncpy(tbuf + sl, rp->tty, MINSTR);
- printf("%-8.8s %-23s %.12s",
- rp->name, tbuf, ctime(&rp->time) + 4);
- if (rp->idle < 60)
- printf("\n");
- else {
- l = rp->idle/HOUR;
- wo = (rp->idle % HOUR)/60;
- if (l > 99)
- wo = 59, l = 99;
- printf((l) ? " %2d" : " ", l);
- printf(":%02d\n", wo);
- }
- }
- return;
- }
-
- /* print host- or domain-name */
- if (sflag && cflag) /* include # of hosts in domain */
- sprintf(tbuf, "%.*s/%d:", MRGN, s, sflag);
- else
- sprintf(tbuf, "%.*s:", MRGN+((!sflag) * 4), s);
-
- printf("%-*s", wo = wdent = MRGN+((!sflag) * 5), s = tbuf);
-
- if (n && mflag) { /* print "user1 user2 ..." */
- for(l=0, xp=s=r+MINSTR; s < (r+n); s += rutsize)
- if (strncmp(s, xp, MINSTR)) {
- sprintf(tbuf,
- (l>1)?" %.*s/%d":" %.*s",
- MINSTR, xp, l);
- if (wflag) { /* wrap and indent */
- if ((sl=strlen(tbuf)) > wlim-wo)
- printf("\n%*s",
- wo = wdent, "");
- wo += sl;
- }
- fputs(tbuf, stdout);
- xp = s; l = cflag;
- }
- else
- l += cflag;
- /* still one name left to do */
- sprintf(tbuf,(l>1)?" %.*s/%d\n":" %.*s\n",MINSTR,xp,l);
- if (wflag && (strlen(tbuf)-1) > wlim - wo)
- printf("\n%*s", wo = wdent, "");
- fputs(tbuf, stdout);
- return;
- }
-
- /* ... else don't ignore multi-logins */
- for (s = r+MINSTR; s < (r+n); s += rutsize) {
- if (wflag) { /* wrap and indent */
- if ((sl = strlen(s)) > MINSTR)
- sl = MINSTR;
- if (++sl > wlim - wo)
- printf("\n%*s", wo = wdent, "");
- wo += sl;
- }
- printf(" %.*s", MINSTR, s);
- }
- printf("\n");
- }
-
- /*
- * print uptimes (like ruptime(1))
- */
- slurp(h, n)
- struct rw_hdr *h;
- int n;
- {
- char tbuf[128];
- register char *p;
- register int tdif;
-
- /* host name */
- p = tbuf;
- sprintf(p, "%-15.15s", h->host);
-
- /* if rcvd-time is >1 hour old then assume host is down */
- tdif = now - h->rcvd; p += 15;
- if (tdif > HOUR) {
- if (tdif > (24 * HOUR))
- sprintf(p, "down %3d+%02d:%02d\n",
- (tdif / (24 * HOUR)),
- (tdif % (24 * HOUR)) / HOUR,
- (tdif % HOUR) / 60);
- else
- sprintf(p, "down %6d:%02d\n",
- tdif / HOUR, (tdif % HOUR) / 60);
- fputs(tbuf, stdout);
- return;
- }
-
- /* print host's uptime but include a '*' if
- * rcvd-time is between 5 mins and 1 hour old */
- sprintf(p, "%c up ", (tdif > RWPERIOD) ? '*' : ' ');
- tdif = now - h->boot; p += 5;
- if (tdif < 1) /* host's boottime > our current time */
- sprintf(p, " ??:??");
- else if (tdif > (24 * HOUR))
- sprintf(p, "%3d+%02d:%02d",
- (tdif / (24 * HOUR)),
- (tdif % (24 * HOUR)) / HOUR,
- (tdif % HOUR) / 60);
- else
- sprintf(p, "%6d:%02d", tdif / HOUR, (tdif % HOUR) / 60);
-
- /* print # of users and the 3 load numbers */
- p += 9;
- sprintf(p, ", %5d user%s load: %2d.%02d, %2d.%02d, %2d.%02d\n",
- n, (n == 1) ? ", " : "s,",
- h->loadav[0]/100, h->loadav[0]%100,
- h->loadav[1]/100, h->loadav[1]%100,
- h->loadav[2]/100, h->loadav[2]%100);
- fputs(tbuf, stdout);
- }
-
- /*
- * show users on a specific host
- */
- dohost(host)
- char *host;
- {
- struct hostent *h, *gethostbyname();
-
- /*
- * try to get host's proper name
- * and try to find the proper spool file
- */
- if((h = gethostbyname(host)) == NULL) {
- hp = malloc(strlen(host)+MINSTR);
- sprintf(hp, "whod.%s", host);
- /*
- perror(host);
- return(1);
- */
- }
- else {
- hp = malloc(strlen(h->h_name)+MINSTR);
- sprintf(hp, "whod.%s", h->h_name);
- }
- if ((fd = open(hp, O_RDONLY)) < 0 && h != NULL) {
- char **s;
- /*
- * can't find file related to h_name
- * try the aliases instead.
- */
- s = h->h_aliases;
- while(*s) {
- free(hp);
- hp = malloc(strlen(*s)+MINSTR);
- sprintf(hp, "whod.%s", *s);
- if ((fd = open(hp, O_RDONLY)) > 0)
- break;
- s++;
- }
- if (*s == NULL) {
- fprintf(stderr, "%s: no data\n", host);
- return(1);
- }
- }
- if ((fd > 0 && fstat(fd, &st) < 0) || stat(hp, &st) < 0) {
- if (fd < 0)
- fprintf(stderr, "%s: unknown host\n", host);
- else
- perror(hp);
- return(1);
- }
- n = st.st_size - hdrsize;
- if ((rubuf = malloc((unsigned)n)) == 0) {
- perror(program);
- exit(1);
- }
- n = read(fd, (char *)&hdr, hdrsize);
- n = ldrut(fd,rubuf,st.st_size-hdrsize);
- if (uflag)
- slurp(&hdr, n/rutsize);
- else {
- if (now-hdr.rcvd > RWPERIOD)
- strcat(hp, "*");
- qsort(rubuf, n/rutsize, rutsize, rutcmp);
- burp(hp, rubuf, n);
- }
- }
-
- /*
- * show users by domain
- */
- dodomains()
- {
- int z;
- register int i;
- char *p0, *p1, *fnp, *rbp;
-
- fnp = hp = hnbuf;
-
- if ((rubuf = malloc(n * MAXPORTS * rutsize)) == NULL) {
- perror(program);
- exit(1);
- }
-
- p0 = rindex(fnp, '.') + 1;
- if ((int)p0 == 1) p0 = fnp;
-
- while (fnp < ep) {
- rbp = rubuf;
- for (p1=p0, n=i=0; fnp < ep && !strcmp(p1, p0); i++) {
- if ((fd = open(fnp, O_RDONLY)) < 0
- || fstat(fd, &st) < 0) {
- perror(fnp);
- exit(1);
- }
- read(fd, (char *)&hdr, hdrsize);
- z = ldrut(fd,rbp,st.st_size-hdrsize);
- #ifdef debug
- if (z > 0) {
- #else
- if (now-hdr.rcvd <= RWPERIOD && z > 0) {
- #endif
- n += z;
- rbp += z;
- }
- close(fd);
- fnp += RWFSZ;
- p1 = p0;
- p0 = rindex(fnp, '.') + 1;
- if ((int)p0 == 1) p0 = fnp;
- }
- if (!n) continue;
- *rbp = '\0';
- qsort(rubuf, n/rutsize, rutsize, rutcmp);
- sflag = i;
- burp(p1, rubuf, n);
- }
- free(rubuf);
- }
-
- /*
- * load rutmp data into buffer.
- */
- ldrut(fd, p, n)
- int fd, n;
- char *p;
- {
- register int m1, m2, nr;
- register char *s;
-
- if (!aflag) return(read(fd, p, n));
-
- s = p;
- m1 = m2 = 0;
-
- while (m2 < n && (nr = read(fd, s, rutsize)) > 0) {
- m2 += nr;
- if (((struct rw_utmp *)s)->idle > HOUR)
- /* ignore entries with >1 hr idle time */
- continue;
- m1 += nr;
- s += nr;
- }
- return(m1);
- }
-
- /*
- * search a file's data for given users
- */
- chew(r, n, ac, av)
- char *r, *av[];
- int n, ac;
- {
- register int i;
- register char *p;
- extern int optind;
-
- /* grotty old standard linear search */
- for (p = r+MINSTR; p < (r+n); p += rutsize)
- for (i=optind; i<ac; i++)
- if (*p == av[i][0]
- && !strncmp(av[i], p, MINSTR))
- return (1);
- return(0);
- }
-