408 lines
8.5 KiB
C
408 lines
8.5 KiB
C
/* @(#)rusers.c 1.1 87/07/28 3.2/4.3 NFSSRC */
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)rusers.c 1.1 86/09/25 Copyr 1985 Sun Micro";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1985 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <netdb.h>
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <rpc/rpc.h>
|
|
#include <rpc/pmap_clnt.h>
|
|
#include <rpcsvc/rusers.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
struct rusers_utmp dummy;
|
|
#define NMAX sizeof(dummy.ut_name)
|
|
#define LMAX sizeof(dummy.ut_line)
|
|
#define HMAX sizeof(dummy.ut_host)
|
|
|
|
#define MACHINELEN 32 /* length of machine name printed out */
|
|
#define NUMENTRIES 200
|
|
#define MAXINT 0x7fffffff
|
|
#define min(a,b) ((a) < (b) ? (a) : (b))
|
|
|
|
struct entry {
|
|
struct in_addr addr;
|
|
int cnt;
|
|
int idle; /* set to MAXINT if not present */
|
|
char *machine;
|
|
struct utmpidle *users;
|
|
} *entry;
|
|
int numentries = NUMENTRIES; /*default number of host entries */
|
|
int curentry;
|
|
int nflag; /* caller specified number of host entires*/
|
|
int hflag; /* host: sort by machine name */
|
|
int iflag; /* idle: sort by idle time */
|
|
int uflag; /* users: sort by number of users */
|
|
int lflag; /* print out long form */
|
|
int aflag; /* all: list all machines */
|
|
int dflag; /* debug: list only first n machines */
|
|
int debug;
|
|
int vers;
|
|
|
|
int hcompare(), icompare(), ucompare();
|
|
int collectnames();
|
|
|
|
main(argc, argv)
|
|
char **argv;
|
|
{
|
|
struct utmpidlearr utmpidlearr;
|
|
enum clnt_stat clnt_stat;
|
|
int single;
|
|
|
|
single = 0;
|
|
entry = malloc (numentries * (sizeof *entry));
|
|
/* pre-allocate the default */
|
|
|
|
while (argc > 1) {
|
|
if (argv[1][0] != '-') {
|
|
single++;
|
|
singlehost(argv[1]);
|
|
}
|
|
else {
|
|
switch(argv[1][1]) {
|
|
|
|
case 'h':
|
|
hflag++;
|
|
break;
|
|
case 'a':
|
|
aflag++;
|
|
break;
|
|
case 'i':
|
|
iflag++;
|
|
break;
|
|
case 'l':
|
|
lflag++;
|
|
break;
|
|
case 'n':
|
|
nflag++;
|
|
if (argc < 3)
|
|
usage();
|
|
numentries = atoi(argv[2]);
|
|
free (entry); /* remove previous */
|
|
entry = malloc (numentries * (sizeof *entry));
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
|
|
case 'u':
|
|
uflag++;
|
|
break;
|
|
case 'd':
|
|
dflag++;
|
|
if (argc < 3)
|
|
usage();
|
|
debug = atoi(argv[2]);
|
|
argc--;
|
|
argv++;
|
|
break;
|
|
default:
|
|
usage();
|
|
}
|
|
}
|
|
argv++;
|
|
argc--;
|
|
}
|
|
if (iflag + hflag + uflag > 1)
|
|
usage();
|
|
if (single > 0) {
|
|
if (iflag || hflag || uflag)
|
|
printnames();
|
|
exit(0);
|
|
}
|
|
if (iflag || hflag || uflag) {
|
|
printf("collecting responses... ");
|
|
fflush(stdout);
|
|
}
|
|
|
|
vers = RUSERSVERS_IDLE;
|
|
utmpidlearr.uia_arr = NULL;
|
|
clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_IDLE,
|
|
RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmpidlearr,
|
|
&utmpidlearr, collectnames);
|
|
#ifdef TESTING
|
|
fprintf(stderr, "starting second round of broadcasting\n");
|
|
#endif
|
|
vers = RUSERSVERS_ORIG;
|
|
clnt_stat = clnt_broadcast(RUSERSPROG, RUSERSVERS_ORIG,
|
|
RUSERSPROC_NAMES, xdr_void, NULL, xdr_utmparr, &utmpidlearr,
|
|
collectnames);
|
|
if (iflag || hflag || uflag)
|
|
printnames();
|
|
}
|
|
|
|
singlehost(name)
|
|
char *name;
|
|
{
|
|
struct hostent *hp;
|
|
enum clnt_stat err;
|
|
struct sockaddr_in addr;
|
|
struct utmpidlearr utmpidlearr;
|
|
|
|
vers = RUSERSVERS_ORIG;
|
|
utmpidlearr.uia_arr = NULL;
|
|
err = (enum clnt_stat)callrpc(name, RUSERSPROG, RUSERSVERS_IDLE,
|
|
RUSERSPROC_NAMES, xdr_void, 0, xdr_utmpidlearr, &utmpidlearr);
|
|
if (err == RPC_PROGVERSMISMATCH) {
|
|
if (err = (enum clnt_stat)callrpc(name, RUSERSPROG,
|
|
RUSERSVERS_ORIG, RUSERSPROC_NAMES, xdr_void, 0,
|
|
xdr_utmparr, &utmpidlearr)) {
|
|
fprintf(stderr, "rusers: %s: ", name);
|
|
clnt_perrno(err);
|
|
fprintf(stderr, "\n");
|
|
return;
|
|
}
|
|
}
|
|
else if (err == RPC_SUCCESS)
|
|
vers = RUSERSVERS_IDLE;
|
|
else {
|
|
fprintf(stderr, "rusers: %s: ", name);
|
|
clnt_perrno(err);
|
|
fprintf(stderr, "\n");
|
|
return;
|
|
}
|
|
/*
|
|
* simulate calling from clnt_broadcast
|
|
*/
|
|
hp = gethostbyname(name);
|
|
if (hp == NULL) {
|
|
fprintf(stderr, "rusers: can't find %s in hosts database\n",
|
|
name);
|
|
exit(1);
|
|
}
|
|
addr.sin_addr.s_addr = *(int *)hp->h_addr;
|
|
collectnames(&utmpidlearr, &addr);
|
|
return;
|
|
}
|
|
|
|
collectnames(resultsp, raddrp)
|
|
char *resultsp;
|
|
struct sockaddr_in *raddrp;
|
|
{
|
|
struct utmpidlearr utmpidlearr;
|
|
struct utmpidle *uip;
|
|
struct rusers_utmp *up;
|
|
static int debugcnt;
|
|
int i, cnt, minidle;
|
|
struct in_addr addr;
|
|
register struct entry *entryp, *lim;
|
|
struct utmpidle *p, *q;
|
|
struct hostent *hp;
|
|
char *host;
|
|
|
|
utmpidlearr = *(struct utmpidlearr *)resultsp;
|
|
if ((cnt = utmpidlearr.uia_cnt) < 1 && !aflag)
|
|
return(0);
|
|
/*
|
|
* weed out duplicates
|
|
*/
|
|
addr = raddrp->sin_addr;
|
|
lim = entry + curentry;
|
|
for (entryp = entry; entryp < lim; entryp++)
|
|
if (addr.s_addr == entryp->addr.s_addr)
|
|
return (0);
|
|
debugcnt++;
|
|
entry[curentry].addr = addr;
|
|
hp = gethostbyaddr((char *)&raddrp->sin_addr.s_addr,
|
|
sizeof(int),AF_INET);
|
|
if (hp == NULL)
|
|
host = inet_ntoa(addr);
|
|
else
|
|
host = hp->h_name;
|
|
|
|
/*
|
|
* if raw, print this entry out immediately
|
|
* otherwise store for later sorting
|
|
*/
|
|
if (!iflag && !hflag && !uflag) {
|
|
if (lflag)
|
|
for (i = 0; i < cnt; i++)
|
|
putline(host, utmpidlearr.uia_arr[i], vers);
|
|
else {
|
|
printf("%-*s", MACHINELEN, host);
|
|
for (i = 0; i < cnt; i++)
|
|
printf(" %.*s", NMAX,
|
|
utmpidlearr.uia_arr[i]->ui_utmp.ut_name);
|
|
printf("\n");
|
|
}
|
|
}
|
|
else {
|
|
entry[curentry].cnt = cnt;
|
|
q = (struct utmpidle *)
|
|
malloc(cnt*sizeof(struct utmpidle));
|
|
p = q;
|
|
minidle = MAXINT;
|
|
for (i = 0; i < cnt; i++) {
|
|
bcopy(utmpidlearr.uia_arr[i], q,
|
|
sizeof(struct utmpidle));
|
|
if (vers == RUSERSVERS_IDLE)
|
|
minidle = min(minidle, q->ui_idle);
|
|
q++;
|
|
}
|
|
entry[curentry].users = p;
|
|
entry[curentry].idle = minidle;
|
|
}
|
|
if (curentry >= numentries) {
|
|
fprintf(stderr, "rusers: too many hosts on network\n");
|
|
exit(1);
|
|
}
|
|
curentry++;
|
|
if (dflag && debugcnt >= debug)
|
|
return (1);
|
|
return(0);
|
|
}
|
|
|
|
printnames()
|
|
{
|
|
char *host;
|
|
struct hostent *hp;
|
|
int i, j, v;
|
|
int (*compare)();
|
|
|
|
for (i = 0; i < curentry; i++) {
|
|
hp = gethostbyaddr((char *)&entry[i].addr,sizeof(int),AF_INET);
|
|
if (hp == NULL)
|
|
host = inet_ntoa(entry[i].addr);
|
|
else
|
|
host = hp->h_name;
|
|
entry[i].machine = (char *)malloc(MACHINELEN+1);
|
|
strcpy(entry[i].machine, host);
|
|
}
|
|
if (iflag)
|
|
compare = icompare;
|
|
else if (hflag)
|
|
compare = hcompare;
|
|
else
|
|
compare = ucompare;
|
|
qsort(entry, curentry, sizeof(struct entry), compare);
|
|
printf("\n");
|
|
for (i = 0; i < curentry; i++) {
|
|
if (!lflag) {
|
|
printf("%-*.*s", MACHINELEN,
|
|
MACHINELEN, entry[i].machine);
|
|
for (j = 0; j < entry[i].cnt; j++)
|
|
printf(" %.*s", NMAX,
|
|
entry[i].users[j].ui_utmp.ut_name);
|
|
printf("\n");
|
|
}
|
|
else {
|
|
if (entry[i].idle == MAXINT)
|
|
v = RUSERSVERS_ORIG;
|
|
else
|
|
v = RUSERSVERS_IDLE;
|
|
for (j = 0; j < entry[i].cnt; j++)
|
|
putline(entry[i].machine,
|
|
&entry[i].users[j], v);
|
|
}
|
|
}
|
|
}
|
|
|
|
hcompare(a,b)
|
|
struct entry *a, *b;
|
|
{
|
|
return (strcmp(a->machine, b->machine));
|
|
}
|
|
|
|
ucompare(a,b)
|
|
struct entry *a, *b;
|
|
{
|
|
return (b->cnt - a->cnt);
|
|
}
|
|
|
|
icompare(a,b)
|
|
struct entry *a, *b;
|
|
{
|
|
return (a->idle - b->idle);
|
|
}
|
|
|
|
putline(host, uip, vers)
|
|
char *host;
|
|
struct utmpidle *uip;
|
|
int vers;
|
|
{
|
|
register char *cbuf;
|
|
struct rusers_utmp *up;
|
|
struct hostent *hp;
|
|
char buf[MAXHOSTNAMELEN+LMAX+1];
|
|
|
|
up = &uip->ui_utmp;
|
|
printf("%-*.*s ", NMAX, NMAX, up->ut_name);
|
|
|
|
strcpy(buf, host);
|
|
strcat(buf, ":");
|
|
strncat(buf, up->ut_line, LMAX);
|
|
printf("%-*s", 30, buf);
|
|
|
|
cbuf = (char *)ctime(&up->ut_time);
|
|
printf(" %.12s ", cbuf+4);
|
|
if (vers == RUSERSVERS_IDLE && uip->ui_idle != MAXINT) {
|
|
prttime(uip->ui_idle, "");
|
|
}
|
|
else
|
|
printf(" ??");
|
|
if (up->ut_host[0])
|
|
printf(" (%.*s)", HMAX, up->ut_host);
|
|
putchar('\n');
|
|
}
|
|
|
|
/*
|
|
* prttime prints a time in hours and minutes.
|
|
* The character string tail is printed at the end, obvious
|
|
* strings to pass are "", " ", or "am".
|
|
*/
|
|
prttime(tim, tail)
|
|
time_t tim;
|
|
char *tail;
|
|
{
|
|
register int didhrs = 0;
|
|
|
|
if (tim >= 60) {
|
|
printf("%3d:", tim/60);
|
|
didhrs++;
|
|
} else {
|
|
printf(" ");
|
|
}
|
|
tim %= 60;
|
|
if (tim > 0 || didhrs) {
|
|
printf(didhrs&&tim<10 ? "%02d" : "%2d", tim);
|
|
} else {
|
|
printf(" ");
|
|
}
|
|
printf("%s", tail);
|
|
}
|
|
|
|
/*
|
|
* for debugging
|
|
*/
|
|
printit(i)
|
|
{
|
|
int j, v;
|
|
|
|
printf("%12.12s: ", entry[i].machine);
|
|
if (entry[i].cnt) {
|
|
if (entry[i].idle == MAXINT)
|
|
v = RUSERSVERS_ORIG;
|
|
else
|
|
v = RUSERSVERS_IDLE;
|
|
putline(&entry[i].users[0], v);
|
|
for (j = 1; j < entry[i].cnt; j++) {
|
|
printf("\t");
|
|
putline(&entry[i].users[j], vers);
|
|
}
|
|
}
|
|
else
|
|
printf("\n");
|
|
}
|
|
|
|
usage()
|
|
{
|
|
fprintf(stderr, "Usage: rusers [-a] [-h] [-i] [-l] [-u] [host ...]\n");
|
|
exit(1);
|
|
}
|