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