home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char rcsid[] =
- "@(#) $Header: finger.c,v 1.13 87/04/21 17:50:03 leres Exp $ (LBL)";
- #endif
- /*
- * VAX/VMS finger
- *
- * Craig Leres, Lawrence Berkeley Laboratory
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <pwd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
- #include <eunice/eunice.h>
-
- #include "vms/jpidef.h"
- #include "vms/dvidef.h"
- #include "vms/ttdef.h"
- #include "vms/tt2def.h"
- #include "vms/ssdef.h"
- #include "vms/statedef.h"
-
- #include "item_list_3.h"
- #include "dsc.h"
-
- /* People list */
- struct plist {
- struct plist *p_next;
- char *p_realname;
- char *p_location;
- u_long p_logintime;
- long p_idletime;
- u_long p_pid;
- u_long p_state;
- u_long p_net;
- int p_nomesg;
- char p_username[16];
- char p_terminal[8];
- };
-
- /* Remote locations */
- static struct rlist {
- struct rlist *r_next;
- u_long r_net;
- char *r_location;
- };
-
- /* Variables for jpi call */
- static char busername[13];
- static short lusername;
- static char bterminal[8];
- static short lterminal;
- static u_long blogintime[2];
- static u_long bstate;
-
- static struct item_list_3 itmlst[] = {
- sizeof(busername) - 1, JPI$_USERNAME, busername, &lusername,
- sizeof(bterminal) - 1, JPI$_TERMINAL, bterminal, <erminal,
- sizeof(blogintime), JPI$_LOGINTIM, (char *)blogintime, 0,
- sizeof(bstate), JPI$_STATE, (char *)&bstate, 0,
- 0, 0, 0, 0
- };
-
- /* Variables for dvi call */
- static u_long bdevdepend, bdevdepend2;
-
- static struct item_list_3 dvilst[] = {
- sizeof(bdevdepend), DVI$_DEVDEPEND, (char *)&bdevdepend, 0,
- sizeof(bdevdepend2), DVI$_DEVDEPEND2, (char *)&bdevdepend2, 0,
- 0, 0, 0, 0
- };
-
- /* Function declarations */
- char *malloc(), *pidle(), *ptime(), *getstate(), *getnetloc();
- u_long cvt_to_unix_time();
- struct plist *makelist();
-
- /* Globals */
- char *argv0; /* Program name pointer */
- struct rlist *netlocs = 0; /* List of remote locations */
- int doseconds = 0; /* display seconds of idle time */
- int dofast = 0; /* display locations by default */
-
- extern int vmserrno;
-
- #define SAVESTR(cp) strcpy(malloc(strlen(cp) + 1), cp)
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- register int i;
- register char *cp;
- register struct plist *pp;
- int didany;
- char *usage = "usage: %s [-fs] [[user]@host] ...\n";
-
- argv0 = argv[0];
-
- /* Handle arguments */
- didany = 0;
- for (i = 1; i < argc; i++) {
- cp = argv[i];
- if (netfinger(cp)) {
- didany++;
- continue;
- }
- if (*cp != '-') {
- fprintf(stderr, usage, argv0);
- exit(1);
- }
- for (cp++; *cp != '\0'; cp++)
- switch (*cp) {
-
- case 'f':
- dofast++;
- break;
- case 's':
- doseconds++;
- break;
- default:
- fprintf(stderr, usage, argv0);
- exit(1);
- }
- }
- if (didany)
- exit(0);
-
- /* Get the stuff */
- pp = makelist();
-
- /* Fill in the locations */
- getlocs(pp);
-
- /* Fill in the real names */
- getreal(pp);
-
- /* Output the data */
- printf("Login Name TTY Idle When Location\n");
- while (pp) {
- /*
- * Print out info about one user
- */
- printf("%-12.12s %-20.20s%c%4s %4s %9.9s",
- pp->p_username,
- pp->p_realname ? pp->p_realname : "",
- pp->p_nomesg ? '*' : ' ',
- pp->p_terminal,
- pidle(pp->p_idletime),
- pp->p_logintime ?
- ptime(pp->p_logintime) : getstate(pp->p_state));
- if (pp->p_location)
- printf(" %s", pp->p_location);
- putchar('\n');
- pp = pp->p_next;
- }
- exit(0);
- }
-
- /*
- * Create the list of logged in users
- */
- struct plist *
- makelist()
- {
- register int i, j;
- long *lp_tim;
- u_long *lp_pid;
- u_long *lp_net;
- struct plist *p, *pp, *plast, pjunk;
- long iosb[2];
-
- /* Get the idle time info */
- vmserrno = getidle(&lp_tim, &lp_pid, &lp_net);
- if ((vmserrno & 1) == 0) {
- fprintf(stderr, "%s: ", argv0);
- vmsperror("getidle()");
- exit(1);
- }
-
- /* Loop through the idle info and build the list */
- bzero((char *)&pjunk, sizeof(struct plist));
- for (i = 0; lp_pid[i]; i++) {
- bterminal[0] = '\0';
- vmserrno = sys$getjpiw(0, &lp_pid[i], 0, itmlst, iosb, 0, 0);
- if (vmserrno & 1 || vmserrno == SS$_SUSPENDED)
- vmserrno = iosb[0];
- if (vmserrno == SS$_NONEXPR)
- continue;
- if ((vmserrno & 1) == 0 && vmserrno != SS$_SUSPENDED) {
- fprintf(stderr, "%s: ", argv0);
- vmsperror("sys$getjpiw()");
- exit(1);
- }
- if (bterminal[0] == '\0')
- continue;
- p = (struct plist *) malloc(sizeof(struct plist));
- bzero((char *)p, sizeof(struct plist));
- busername[lusername] = '\0';
- munch(busername);
- (void) strcpy(p->p_username, busername);
- if (lterminal > 1 && bterminal[lterminal-1] == ':')
- lterminal--;
- bterminal[lterminal] = '\0';
- munch(bterminal);
- (void) strcpy(p->p_terminal, bterminal);
- if (vmserrno != SS$_SUSPENDED)
- p->p_logintime = cvt_to_unix_time(blogintime);
- else
- p->p_logintime = 0;
- p->p_state = bstate;
- p->p_idletime = lp_tim[i];
- p->p_pid = lp_pid[i];
- p->p_nomesg = nomesg(bterminal);
- if (p->p_net = lp_net[i])
- p->p_location = getnetloc(p->p_net, p->p_terminal);
-
- /* Insert in proper order */
- plast = &pjunk;
- for (pp = plast->p_next; pp; pp = pp->p_next) {
- if ((j = ttycmp(p->p_terminal, pp->p_terminal)) < 0) {
- /* Insert in front */
- p->p_next = plast->p_next;
- plast->p_next = p;
- p = 0;
- break;
- } else if (j == 0 && p->p_pid == pp->p_pid) {
- /*
- * Managed to get some terminal twice.
- * This can happen if someone allocates
- * a terminal that isn't logged in...
- *
- * Keep one of the two entries. Keep the new
- * entry if it has a location (implying it's a
- * network entry) or has a non zero idle time.
- */
- if (p->p_location != 0 || p->p_idletime > 0) {
- pp->p_idletime = p->p_idletime;
- pp->p_net = p->p_net;
- pp->p_location = p->p_location;
- }
- p = 0;
- break;
- }
- plast = pp;
- }
- if (p)
- plast->p_next = p;
- }
- return(pjunk.p_next);
- }
-
- /*
- * Pound a string to lowercase and lose trailing spaces
- */
- static munch(str)
- char *str;
- {
- register char *cp;
-
- for (cp = str; *cp != ' ' && *cp != '\0' && *cp != '\n'; cp++)
- if (isupper(*cp))
- *cp = tolower(*cp);
- *cp = '\0';
- }
-
- /*
- * Add locations to the list
- */
- getlocs(p)
- struct plist *p;
- {
- int todo;
- register struct plist *pp;
- register char *cp;
- char line[256];
- FILE *f;
-
- /* If no locations file, no thing to do */
- if ((f = fopen("/etc/locations","r")) == NULL)
- return;
-
- /* Count number of entries to do */
- todo = 0;
- for (pp = p; pp; pp = pp->p_next)
- if (pp->p_location == 0)
- todo++;
-
- /* Read the locations file once, updating list as we go along */
- while (todo > 0 && fgets(line, sizeof(line), f) != NULL) {
- line[sizeof(line)-1] = '\0';
- if ((cp = index(line, '\n')) != NULL)
- *cp = '\0';
- if ((cp = index(line, ',')) != NULL)
- *cp++ = '\0';
- for (pp = p; pp; pp = pp->p_next)
- if (pp->p_location == 0 && strcmpn(pp->p_terminal,
- line, strlen(pp->p_terminal)) == 0) {
- pp->p_location = SAVESTR(cp);
- todo--;
- break;
- }
- }
- (void) fclose(f);
- return;
- }
-
- /*
- * Add real names to the list
- */
- getreal(p)
- struct plist *p;
- {
- register struct plist *pp;
- register struct passwd *pw;
- register char *cp, *name;
- int todo;
-
- /* Can't do much here without the password file */
- if (setpwent() == 0)
- return;
-
- /* Count number of entries */
- todo = 0;
- for (pp = p; pp; pp = pp->p_next)
- todo++;
-
- /* Read the password file once, updating list as we go along */
- while (todo > 0 && (pw = getpwent())) {
- name = 0;
- for (pp = p; pp; pp = pp->p_next)
- if (strcmp(pp->p_username, pw->pw_name) == 0) {
- if (name == 0) {
- name = SAVESTR(pw->pw_gecos);
- if ((cp = index(name, ',')) != NULL)
- *cp = '\0';
- }
- pp->p_realname = name;
- todo--;
- }
- }
- (void) endpwent();
- return;
- }
-
- /*
- * Format idle time
- */
- char *
- pidle(idle)
- long idle;
- {
- register long l;
- static char idlebuf[16];
-
- if ((l = idle/60) == 0) {
- if (idle > 0 && doseconds)
- (void) sprintf(idlebuf, "%ds", idle);
- else
- idlebuf[0] = '\0';
- } else if (l < 60)
- (void) sprintf(idlebuf, "%d", l);
- else if (l/60 < 10)
- (void) sprintf(idlebuf, "%d:%02d", l/60, l%60);
- else if ((l = l/60) < 24)
- (void) sprintf(idlebuf, "%dh", l);
- else
- (void) sprintf(idlebuf, "%dd", l/24);
- return(idlebuf);
- }
-
- /*
- * Format the time
- */
- char *
- ptime(u)
- u_long u;
- {
- static char timebuf[32];
- struct tm *tp;
- static char days[][4] = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
- };
-
- if (u == 0)
- return("<susp>");
-
- tp = localtime(&u);
- (void) sprintf(timebuf,"%s %2d:%02d",
- days[tp->tm_wday],
- tp->tm_hour,
- tp->tm_min);
- return(timebuf);
- }
-
- /*
- * Determine if a terminal has broadcasts disabled
- */
- nomesg(tty)
- char *tty;
- {
- struct dsc tdsc;
- long iosb[2];
-
- tdsc.d_buf = tty;
- tdsc.d_len = strlen(tdsc.d_buf);
-
- vmserrno = sys$getdviw(0, 0, &tdsc, dvilst, iosb, 0, 0, 0);
- if (vmserrno & 1)
- vmserrno = iosb[0];
- if ((vmserrno & 1) == 0) {
- fprintf(stderr, "%s: ", argv0);
- vmsperror("sys$getdviw()");
- exit(1);
- }
- return((bdevdepend & TT$M_NOBRDCST) != 0 &&
- (bdevdepend2 & TT2$M_BRDCSTMBX) == 0);
- }
-
- /*
- * Determine the network location of a terminal
- */
- char *
- getnetloc(n, tty)
- u_long n;
- char *tty;
- {
- register struct rlist *rp;
- struct hostent *hp;
- char host[32], loc[256];
- long node;
-
- /* First, check if we've already figured this one out */
- for (rp = netlocs; rp; rp = rp->r_next)
- if (n == rp->r_net)
- return(rp->r_location);
-
- /* Figure this one out for the first time */
- if (strcmpn(tty, "nty", 3) == 0 || strcmpn(tty, "nta", 3) == 0) {
- if (dofast == 0 &&
- (hp = gethostbyaddr(&n, sizeof(u_long), AF_INET)))
- (void) strcpy(loc, hp->h_name);
- else
- (void) sprintf(loc, "%d.%d.%d.%d",
- n & 0xff,
- n >> 8 & 0xff,
- n >> 16 & 0xff,
- n >> 24 & 0xff);
- } else {
- host[0] = '\0';
- if (((vmserrno = rmtinfo(n, &node, host)) & 1) == 0) {
- fprintf(stderr, "%s: ", argv0);
- vmsperror("rmtinfo()");
- exit(1);
- }
- if (host[0] != '\0')
- (void) strcpy(loc, host);
- else
- (void) sprintf(loc, "node %d", node);
- }
-
- /* Add this one to our list */
- rp = (struct rlist *) malloc(sizeof(struct rlist));
- bzero((char *)rp, sizeof(struct rlist));
- rp->r_net = n;
- rp->r_location = SAVESTR(loc);
- if (netlocs) {
- rp->r_next = netlocs->r_next;
- netlocs->r_next = rp;
- } else
- netlocs = rp;
-
- return(rp->r_location);
- }
-
- char *
- getstate(state)
- u_long state;
- {
- static char buf[32];
-
- switch (state) {
-
- case SCH$C_CEF:
- return("<cef>");
- case SCH$C_COM:
- return("<com>");
- case SCH$C_COMO:
- return("<como>");
- case SCH$C_CUR:
- return("<cur>");
- case SCH$C_COLPG:
- return("<colpg>");
- case SCH$C_FPG:
- return("<fpg>");
- case SCH$C_HIB:
- return("<hib>");
- case SCH$C_HIBO:
- return("<hibo>");
- case SCH$C_LEF:
- return("<lef>");
- case SCH$C_LEFO:
- return("<lefo>");
- case SCH$C_MWAIT:
- return("<mwait>");
- case SCH$C_PFW:
- return("<pfw>");
- case SCH$C_SUSP:
- return("<susp>");
- case SCH$C_SUSPO:
- return("<suspo>");
- }
- return(sprintf(buf, "<%d>", state));
- }
-
- /*
- * Similar to strcmp() but handles trailing unit number part numerically.
- */
- ttycmp(s1, s2)
- register char *s1, *s2;
- {
-
- while (isalpha(*s1) && isalpha(*s2) && *s1 == *s2++)
- if (*s1++=='\0')
- return(0);
- if (isdigit(*s1) && isdigit(*s2))
- return(atoi(s1) - atoi(s2));
- return(*s1 - *--s2);
- }
-
- /*
- * Finger a remote machine
- */
- netfinger(name)
- char *name;
- {
- char *host;
- struct hostent *hp;
- struct servent *sp;
- struct sockaddr_in sin;
- int s;
- register FILE *f;
- register int c;
- register int lastc;
-
- if (name == 0)
- return (0);
- if ((host = rindex(name, '@')) == 0)
- return (0);
- *host++ = '\0';
- bzero((char *)&sin, sizeof (sin));
- if ((sin.sin_addr.s_addr = inet_addr(host)) != -1)
- sin.sin_family = AF_INET;
- else if ((hp = gethostbyname(host)) != 0) {
- sin.sin_family = hp->h_addrtype;
- bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
- host = hp->h_name;
- } else {
- printf("%s: unknown host\n", host);
- return(1);
- }
- printf("[%s]", host);
- if ((sp = getservbyname("finger", "tcp")) == 0) {
- printf("tcp/finger: unknown service\n");
- return (1);
- }
- sin.sin_port = sp->s_port;
- s = socket(sin.sin_family, SOCK_STREAM, 0);
- if (s < 0) {
- (void) fflush(stdout);
- perror("socket");
- return (1);
- }
- if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
- (void) fflush(stdout);
- perror("connect");
- (void) close(s);
- return (1);
- }
- putchar('\n');
- #ifdef notdef
- if (large)
- write(s, "/W ", 3);
- #endif
- write(s, name, strlen(name));
- write(s, "\r\n", 2);
- f = fdopen(s, "r");
- while ((c = getc(f)) != EOF) {
- switch(c) {
- case 0210:
- case 0211:
- case 0212:
- case 0214:
- c -= 0200;
- break;
- case 0215:
- c = '\n';
- break;
- }
- lastc = c;
- if (isprint(c) || isspace(c))
- putchar(c);
- else
- putchar(c ^ 100);
- }
- if (lastc != '\n')
- putchar('\n');
- (void) fclose(f);
- return (1);
- }
-
- /*
- * Convert a VMS time quadword to Unix format
- */
- static u_long
- cvt_to_unix_time(time)
- u_long time[2];
- {
- u_long local[2];
- int dummy;
- static int January_1_1970[2] = {0x4bec0000,0x007c9567};
-
- local[0] = time[0]; local[1] = time[1];
- _$Subtract_Quadword(January_1_1970, local);
- if (!(_$Cache_Flags & _$GMT_VALID)) _$Get_GMT_Info();
- return(_$EDIV(10000000, local, &dummy) + _$Seconds_From_GMT);
- }
-