[comp.sources.misc] finger for VAX/VMS under Eunice

leres@ucbarpa.Berkeley.EDU (Craig Leres) (07/26/87)

Here's my Eunice emulation of /usr/ucb/finger for VAX/VMS. More
information can be found in README. When unpacking, don't forget
to make the sharchive a vms text file before trying to execute it
as a shell script.

		Craig
------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	README
#	ddbdef.i
#	dsc.h
#	finger.c
#	getidle.c
#	item_list_3.h
#	rmtinfo.c
#	syssym.awk
#	ucbdef.i
#	vms
#	vmsperror.c
# This archive created: Tue Jul 21 19:24:05 1987
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(2949 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X# Eunice finger makefile
X
XCFLAGS= -O
XSRCS= finger.c getidle.c rmtinfo.c vmsperror.c
XOBJS= finger.o getidle.o rmtinfo.o vmsperror.o syssym.o
X
X# Ignore vms_struct exit status, it's random.
XVMSSTRUCT= -/etc/vms/vms_struct
X
X# Map can be in different places if running a cluster.
X#SYSMAP= /sys/sysexe/sys.map
XSYSMAP= /sys/syscommon/sysexe/sys.map
X
Xfinger: ${OBJS}
X	${CC} -noshare -notraceback finger.c -o finger ${OBJS}
X
Xlint:
X	lint -hbx ${COPTS} ${SRCS}
X
Xclean:
X	rm -f ${OBJS} syssym.s *.mar vms/*.h finger core
X
Xfinger.o: finger.c vms/dvidef.h vms/jpidef.h vms/ssdef.h \
X	    vms/statedef.h vms/tt2def.h vms/ttdef.h
X
Xgetidle.o: getidle.c vms/dcdef.h vms/ddbdef.h vms/devdef.h \
X	    vms/ssdef.h vms/ttyucbdef.h vms/ucbdef.h
X
Xrmtinfo.o: rmtinfo.c vms/nfbdef.h vms/ssdef.h vms/iodef.h
X
Xsyssym.s:
X	egrep 'GL_ABSTIM|GL_DEVLIST|IPID_TO_EPID' ${SYSMAP} | \
X	    tr A-Z a-z | awk -f syssym.awk >syssym.s
X
Xsyssym.o: syssym.s
X	as -o syssym.o syssym.s
X
Xvms/dcdef.h:
X	vms library 'sys$$library:starlet.mlb /extra=($$dcdef) /out=dcdef.mar'
X	${VMSSTRUCT} dcdef.mar >vms/dcdef.h
X	rm -f dcdef.mar
X
Xvms/ddbdef.h: ddbdef.i
X	vms library 'sys$$library:lib.mlb /extra=($$ddbdef) /out=ddbdef.mar'
X	${VMSSTRUCT} -i ddbdef.i ddbdef.mar >vms/ddbdef.h
X	rm -f ddbdef.mar
X
Xvms/devdef.h:
X	vms library 'sys$$library:starlet.mlb /extra=($$devdef) /out=devdef.mar'
X	${VMSSTRUCT} devdef.mar >vms/devdef.h
X	rm -f devdef.mar
X
Xvms/dvidef.h:
X	vms library 'sys$$library:starlet.mlb /extra=($$dvidef) /out=dvidef.mar'
X	${VMSSTRUCT} dvidef.mar >vms/dvidef.h
X	rm -f dvidef.mar
X
Xvms/iodef.h:
X	vms library 'sys$$library:starlet.mlb /extra=($$iodef) /out=iodef.mar'
X	${VMSSTRUCT} iodef.mar >vms/iodef.h
X	rm -f iodef.mar
X
Xvms/jpidef.h:
X	vms library 'sys$$library:starlet.mlb /extra=($$jpidef) /out=jpidef.mar'
X	${VMSSTRUCT} jpidef.mar >vms/jpidef.h
X	rm -f jpidef.mar
X
Xvms/nfbdef.h:
X	vms library 'sys$$library:lib.mlb /extra=($$nfbdef) /out=nfbdef.mar'
X	${VMSSTRUCT} nfbdef.mar >vms/nfbdef.h
X	rm -f nfbdef.mar
X
Xvms/ssdef.h:
X	vms library 'sys$$library:starlet.mlb /extra=($$ssdef) /out=ssdef.mar'
X	${VMSSTRUCT} ssdef.mar >vms/ssdef.h
X	rm -f ssdef.mar
X
Xvms/statedef.h:
X	vms library 'sys$$library:lib.mlb /extra=($$statedef) /out=statedef.mar'
X	${VMSSTRUCT} statedef.mar >vms/statedef.h
X	rm -f statedef.mar
X
Xvms/tt2def.h:
X	vms library 'sys$$library:starlet.mlb /extra=($$tt2def) /out=tt2def.mar'
X	${VMSSTRUCT} tt2def.mar >vms/tt2def.h
X	rm -f tt2def.mar
X
Xvms/ttdef.h:
X	vms library 'sys$$library:starlet.mlb /extra=($$ttdef) /out=ttdef.mar'
X	${VMSSTRUCT} ttdef.mar >vms/ttdef.h
X	rm -f ttdef.mar
X
Xvms/ttyucbdef.h:
X	vms library 'sys$$library:lib.mlb /extra=($$ttyucbdef) /out=ttyucbdef.mar'
X	egrep -v 'W_TT_DESIZE|W_RTT_SYSTYPE' ttyucbdef.mar >ttyucbdef.mar2
X	${VMSSTRUCT} ttyucbdef.mar2 >vms/ttyucbdef.h
X	rm -f ttyucbdef.mar ttyucbdef.mar2
X
Xvms/ucbdef.h: ucbdef.i
X	vms library 'sys$$library:lib.mlb /extra=($$ucbdef) /out=ucbdef.mar'
X	${VMSSTRUCT} -i ucbdef.i ucbdef.mar >vms/ucbdef.h
X	rm -f ucbdef.mar
SHAR_EOF
if test 2949 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 2949 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(1196 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
X21-Jul-1987
X
XHere's a Eunice emulation of /usr/ucb/finger. I've attempted to make it
Xnot depend on local features of the Eunice I run, but I'm sure people
Xwith older versions of Eunice will have some difficulty getting it to
Xrun. (I have the 4.3 BSD Eunice and use this program under VMS V4.5.)
X
XThis program requires CMKRNL, WORLD, and NETMBX for normal use. Since
Xit uses CMKRNL too look at kernel data structures (to get things like
Xidle time and network location), I highly recommend that you test it on
Xan unused system since simple errors in the building of this program
Xcan crash your machine.
X
XThis version of finger displays username, real name, terminal, idle and
Xlogin time, and location. Terminals with broadcasts disabled are noted
Xwith an asterisk. It uses getpwent() to get the real name. Hardwired
Xport locations are found in /etc/locations which looks similar this:
X
X	opa0:,Console
X	tta0:,Machine room vt100
X	tta1:,Machine room vt100
X	tta2:,Dialup 666-1234
X	tta3:,Dialup 666-1235
X	tta4:,Portselector
X	tta5:,Portselector
X	tta6:,
X	tta7:,Craig's office
X
XInternet locations are determined by consulting gethostbyaddr().
XDECnet locations are determined by consulting NETACP.
X
X		Craig
SHAR_EOF
if test 1196 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 1196 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ddbdef.i'" '(67 characters)'
if test -f 'ddbdef.i'
then
	echo shar: will not over-write existing file "'ddbdef.i'"
else
sed 's/^X//' << \SHAR_EOF > 'ddbdef.i'
Xstruct DDB *ddb$l_link
Xstruct UCB *ddb$l_ucb
Xstruct DDT *ddb$l_ddt
SHAR_EOF
if test 67 -ne "`wc -c < 'ddbdef.i'`"
then
	echo shar: error transmitting "'ddbdef.i'" '(should have been 67 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'dsc.h'" '(85 characters)'
if test -f 'dsc.h'
then
	echo shar: will not over-write existing file "'dsc.h'"
else
sed 's/^X//' << \SHAR_EOF > 'dsc.h'
X/*
X * Standard VMS string descriptor
X */
X
Xstruct dsc {
X	int d_len;
X	char * d_buf;
X};
SHAR_EOF
if test 85 -ne "`wc -c < 'dsc.h'`"
then
	echo shar: error transmitting "'dsc.h'" '(should have been 85 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'finger.c'" '(13167 characters)'
if test -f 'finger.c'
then
	echo shar: will not over-write existing file "'finger.c'"
else
sed 's/^X//' << \SHAR_EOF > 'finger.c'
X#ifndef lint
Xstatic char rcsid[] =
X    "@(#) $Header: finger.c,v 1.13 87/04/21 17:50:03 leres Exp $ (LBL)";
X#endif
X/*
X * VAX/VMS finger
X *
X * Craig Leres, Lawrence Berkeley Laboratory
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netdb.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
X#include <eunice/eunice.h>
X
X#include "vms/jpidef.h"
X#include "vms/dvidef.h"
X#include "vms/ttdef.h"
X#include "vms/tt2def.h"
X#include "vms/ssdef.h"
X#include "vms/statedef.h"
X
X#include "item_list_3.h"
X#include "dsc.h"
X
X/* People list */
Xstruct plist {
X	struct plist *p_next;
X	char *p_realname;
X	char *p_location;
X	u_long p_logintime;
X	long p_idletime;
X	u_long p_pid;
X	u_long p_state;
X	u_long p_net;
X	int p_nomesg;
X	char p_username[16];
X	char p_terminal[8];
X};
X
X/* Remote locations */
Xstatic struct rlist {
X	struct rlist *r_next;
X	u_long r_net;
X	char *r_location;
X};
X
X/* Variables for jpi call */
Xstatic char busername[13];
Xstatic short lusername;
Xstatic char bterminal[8];
Xstatic short lterminal;
Xstatic u_long blogintime[2];
Xstatic u_long bstate;
X
Xstatic struct item_list_3 itmlst[] = {
X	sizeof(busername) - 1, JPI$_USERNAME, busername, &lusername,
X	sizeof(bterminal) - 1, JPI$_TERMINAL, bterminal, &lterminal,
X	sizeof(blogintime), JPI$_LOGINTIM, (char *)blogintime, 0,
X	sizeof(bstate), JPI$_STATE, (char *)&bstate, 0,
X	0, 0, 0, 0
X};
X
X/* Variables for dvi call */
Xstatic u_long bdevdepend, bdevdepend2;
X
Xstatic struct item_list_3 dvilst[] = {
X	sizeof(bdevdepend), DVI$_DEVDEPEND, (char *)&bdevdepend, 0,
X	sizeof(bdevdepend2), DVI$_DEVDEPEND2, (char *)&bdevdepend2, 0,
X	0, 0, 0, 0
X};
X
X/* Function declarations */
Xchar *malloc(), *pidle(), *ptime(), *getstate(), *getnetloc();
Xu_long cvt_to_unix_time();
Xstruct plist *makelist();
X
X/* Globals */
Xchar *argv0;				/* Program name pointer */
Xstruct rlist *netlocs = 0;		/* List of remote locations */
Xint doseconds = 0;			/* display seconds of idle time */
Xint dofast = 0;				/* display locations by default */
X
Xextern int vmserrno;
X
X#define SAVESTR(cp) strcpy(malloc(strlen(cp) + 1), cp)
X
Xmain(argc, argv)
X	int argc;
X	char *argv[];
X{
X	register int i;
X	register char *cp;
X	register struct plist *pp;
X	int didany;
X	char *usage = "usage: %s [-fs] [[user]@host] ...\n";
X
X	argv0 = argv[0];
X
X	/* Handle arguments */
X	didany = 0;
X	for (i = 1; i < argc; i++) {
X		cp = argv[i];
X		if (netfinger(cp)) {
X			didany++;
X			continue;
X		}
X		if (*cp != '-') {
X			fprintf(stderr, usage, argv0);
X			exit(1);
X		}
X		for (cp++; *cp != '\0'; cp++)
X			switch (*cp) {
X
X			case 'f':
X				dofast++;
X				break;
X			case 's':
X				doseconds++;
X				break;
X			default:
X				fprintf(stderr, usage, argv0);
X				exit(1);
X			}
X	}
X	if (didany)
X		exit(0);
X
X	/* Get the stuff */
X	pp = makelist();
X
X	/* Fill in the locations */
X	getlocs(pp);
X
X	/* Fill in the real names */
X	getreal(pp);
X
X	/* Output the data */
X	printf("Login        Name                 TTY  Idle When       Location\n");
X	while (pp) {
X		/*
X		 *	Print out info about one user
X		 */
X		printf("%-12.12s %-20.20s%c%4s %4s %9.9s",
X		    pp->p_username,
X		    pp->p_realname ? pp->p_realname : "",
X		    pp->p_nomesg ? '*' : ' ',
X		    pp->p_terminal,
X		    pidle(pp->p_idletime),
X		    pp->p_logintime ?
X			ptime(pp->p_logintime) : getstate(pp->p_state));
X		if (pp->p_location)
X			printf("  %s", pp->p_location);
X		putchar('\n');
X		pp = pp->p_next;
X	}
X	exit(0);
X}
X
X/*
X * Create the list of logged in users
X */
Xstruct plist *
Xmakelist()
X{
X	register int i, j;
X	long *lp_tim;
X	u_long *lp_pid;
X	u_long *lp_net;
X	struct plist *p, *pp, *plast, pjunk;
X	long iosb[2];
X
X	/* Get the idle time info */
X	vmserrno = getidle(&lp_tim, &lp_pid, &lp_net);
X	if ((vmserrno & 1) == 0) {
X		fprintf(stderr, "%s: ", argv0);
X		vmsperror("getidle()");
X		exit(1);
X	}
X
X	/* Loop through the idle info and build the list */
X	bzero((char *)&pjunk, sizeof(struct plist));
X	for (i = 0; lp_pid[i]; i++) {
X		bterminal[0] = '\0';
X		vmserrno = sys$getjpiw(0, &lp_pid[i], 0, itmlst, iosb, 0, 0);
X		if (vmserrno & 1 || vmserrno == SS$_SUSPENDED)
X			vmserrno = iosb[0];
X		if (vmserrno == SS$_NONEXPR)
X			continue;
X		if ((vmserrno & 1) == 0 && vmserrno != SS$_SUSPENDED) {
X			fprintf(stderr, "%s: ", argv0);
X			vmsperror("sys$getjpiw()");
X			exit(1);
X		}
X		if (bterminal[0] == '\0')
X			continue;
X		p = (struct plist *) malloc(sizeof(struct plist));
X		bzero((char *)p, sizeof(struct plist));
X		busername[lusername] = '\0';
X		munch(busername);
X		(void) strcpy(p->p_username, busername);
X		if (lterminal > 1 && bterminal[lterminal-1] == ':')
X			lterminal--;
X		bterminal[lterminal] = '\0';
X		munch(bterminal);
X		(void) strcpy(p->p_terminal, bterminal);
X		if (vmserrno != SS$_SUSPENDED)
X			p->p_logintime = cvt_to_unix_time(blogintime);
X		else
X			p->p_logintime = 0;
X		p->p_state = bstate;
X		p->p_idletime = lp_tim[i];
X		p->p_pid = lp_pid[i];
X		p->p_nomesg = nomesg(bterminal);
X		if (p->p_net = lp_net[i])
X			p->p_location = getnetloc(p->p_net, p->p_terminal);
X
X		/* Insert in proper order */
X		plast = &pjunk;
X		for (pp = plast->p_next; pp; pp = pp->p_next) {
X			if ((j = ttycmp(p->p_terminal, pp->p_terminal)) < 0) {
X				/* Insert in front */
X				p->p_next = plast->p_next;
X				plast->p_next = p;
X				p = 0;
X				break;
X			} else if (j == 0 && p->p_pid == pp->p_pid) {
X				/*
X				 * Managed to get some terminal twice.
X				 * This can happen if someone allocates
X				 * a terminal that isn't logged in...
X				 *
X				 * Keep one of the two entries. Keep the new
X				 * entry if it has a location (implying it's a
X				 * network entry) or has a non zero idle time.
X				 */
X				if (p->p_location != 0 || p->p_idletime > 0) {
X					pp->p_idletime = p->p_idletime;
X					pp->p_net = p->p_net;
X					pp->p_location = p->p_location;
X				}
X				p = 0;
X				break;
X			}
X			plast = pp;
X		}
X		if (p)
X			plast->p_next = p;
X	}
X	return(pjunk.p_next);
X}
X
X/*
X * Pound a string to lowercase and lose trailing spaces
X */
Xstatic munch(str)
X	char *str;
X{
X	register char *cp;
X
X	for (cp = str; *cp != ' ' && *cp != '\0' && *cp != '\n'; cp++)
X		if (isupper(*cp))
X			*cp = tolower(*cp);
X	*cp = '\0';
X}
X
X/*
X * Add locations to the list
X */
Xgetlocs(p)
X	struct plist *p;
X{
X	int todo;
X	register struct plist *pp;
X	register char *cp;
X	char line[256];
X	FILE *f;
X
X	/* If no locations file, no thing to do */
X	if ((f = fopen("/etc/locations","r")) == NULL)
X		return;
X
X	/* Count number of entries to do */
X	todo = 0;
X	for (pp = p; pp; pp = pp->p_next)
X		if (pp->p_location == 0)
X			todo++;
X
X	/* Read the locations file once, updating list as we go along */
X	while (todo > 0 && fgets(line, sizeof(line), f) != NULL) {
X		line[sizeof(line)-1] = '\0';
X		if ((cp = index(line, '\n')) != NULL)
X			*cp = '\0';
X		if ((cp = index(line, ',')) != NULL)
X			*cp++ = '\0';
X		for (pp = p; pp; pp = pp->p_next)
X			if (pp->p_location == 0 && strcmpn(pp->p_terminal,
X			    line, strlen(pp->p_terminal)) == 0) {
X				pp->p_location = SAVESTR(cp);
X				todo--;
X				break;
X			}
X	}
X	(void) fclose(f);
X	return;
X}
X
X/*
X * Add real names to the list
X */
Xgetreal(p)
X	struct plist *p;
X{
X	register struct plist *pp;
X	register struct passwd *pw;
X	register char *cp, *name;
X	int todo;
X
X	/* Can't do much here without the password file */
X	if (setpwent() == 0)
X		return;
X
X	/* Count number of entries */
X	todo = 0;
X	for (pp = p; pp; pp = pp->p_next)
X		todo++;
X
X	/* Read the password file once, updating list as we go along */
X	while (todo > 0 && (pw = getpwent())) {
X		name = 0;
X		for (pp = p; pp; pp = pp->p_next)
X			if (strcmp(pp->p_username, pw->pw_name) == 0) {
X				if (name == 0) {
X					name = SAVESTR(pw->pw_gecos);
X					if ((cp = index(name, ',')) != NULL)
X						*cp = '\0';
X				}
X				pp->p_realname = name;
X				todo--;
X			}
X	}
X	(void) endpwent();
X	return;
X}
X
X/*
X * Format idle time
X */
Xchar *
Xpidle(idle)
X	long idle;
X{
X	register long l;
X	static char idlebuf[16];
X
X	if ((l = idle/60) == 0) {
X		if (idle > 0 && doseconds)
X			(void) sprintf(idlebuf, "%ds", idle);
X		else
X			idlebuf[0] = '\0';
X	} else if (l < 60)
X		(void) sprintf(idlebuf, "%d", l);
X	else if (l/60 < 10)
X		(void) sprintf(idlebuf, "%d:%02d", l/60, l%60);
X	else if ((l = l/60) < 24)
X		(void) sprintf(idlebuf, "%dh", l);
X	else
X		(void) sprintf(idlebuf, "%dd", l/24);
X	return(idlebuf);
X}
X
X/*
X * Format the time
X */
Xchar *
Xptime(u)
X	u_long u;
X{
X	static char timebuf[32];
X	struct tm *tp;
X	static char days[][4] = {
X		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
X	};
X
X	if (u == 0)
X		return("<susp>");
X
X	tp = localtime(&u);
X	(void) sprintf(timebuf,"%s %2d:%02d",
X	    days[tp->tm_wday],
X	    tp->tm_hour,
X	    tp->tm_min);
X	return(timebuf);
X}
X
X/*
X * Determine if a terminal has broadcasts disabled
X */
Xnomesg(tty)
X	char *tty;
X{
X	struct dsc tdsc;
X	long iosb[2];
X
X	tdsc.d_buf = tty;
X	tdsc.d_len = strlen(tdsc.d_buf);
X
X	vmserrno = sys$getdviw(0, 0, &tdsc, dvilst, iosb, 0, 0, 0);
X	if (vmserrno & 1)
X		vmserrno = iosb[0];
X	if ((vmserrno & 1) == 0) {
X		fprintf(stderr, "%s: ", argv0);
X		vmsperror("sys$getdviw()");
X		exit(1);
X	}
X	return((bdevdepend & TT$M_NOBRDCST) != 0 &&
X	       (bdevdepend2 & TT2$M_BRDCSTMBX) == 0);
X}
X
X/*
X * Determine the network location of a terminal
X */
Xchar *
Xgetnetloc(n, tty)
X	u_long n;
X	char *tty;
X{
X	register struct rlist *rp;
X	struct hostent *hp;
X	char host[32], loc[256];
X	long node;
X
X	/* First, check if we've already figured this one out */
X	for (rp = netlocs; rp; rp = rp->r_next)
X		if (n == rp->r_net)
X			return(rp->r_location);
X
X	/* Figure this one out for the first time */
X	if (strcmpn(tty, "nty", 3) == 0 || strcmpn(tty, "nta", 3) == 0) {
X		if (dofast == 0 &&
X		    (hp = gethostbyaddr(&n, sizeof(u_long), AF_INET)))
X			(void) strcpy(loc, hp->h_name);
X		else
X			(void) sprintf(loc, "%d.%d.%d.%d",
X			    n & 0xff,
X			    n >> 8 & 0xff,
X			    n >> 16 & 0xff,
X			    n >> 24 & 0xff);
X	} else {
X		host[0] = '\0';
X		if (((vmserrno = rmtinfo(n, &node, host)) & 1) == 0) {
X			fprintf(stderr, "%s: ", argv0);
X			vmsperror("rmtinfo()");
X			exit(1);
X		}
X		if (host[0] != '\0')
X			(void) strcpy(loc, host);
X		else
X			(void) sprintf(loc, "node %d", node);
X	}
X
X	/* Add this one to our list */
X	rp = (struct rlist *) malloc(sizeof(struct rlist));
X	bzero((char *)rp, sizeof(struct rlist));
X	rp->r_net = n;
X	rp->r_location = SAVESTR(loc);
X	if (netlocs) {
X		rp->r_next = netlocs->r_next;
X		netlocs->r_next = rp;
X	} else
X		netlocs = rp;
X
X	return(rp->r_location);
X}
X
Xchar *
Xgetstate(state)
X	u_long state;
X{
X	static char buf[32];
X
X	switch (state) {
X
X	case SCH$C_CEF:
X		return("<cef>");
X	case SCH$C_COM:
X		return("<com>");
X	case SCH$C_COMO:
X		return("<como>");
X	case SCH$C_CUR:
X		return("<cur>");
X	case SCH$C_COLPG:
X		return("<colpg>");
X	case SCH$C_FPG:
X		return("<fpg>");
X	case SCH$C_HIB:
X		return("<hib>");
X	case SCH$C_HIBO:
X		return("<hibo>");
X	case SCH$C_LEF:
X		return("<lef>");
X	case SCH$C_LEFO:
X		return("<lefo>");
X	case SCH$C_MWAIT:
X		return("<mwait>");
X	case SCH$C_PFW:
X		return("<pfw>");
X	case SCH$C_SUSP:
X		return("<susp>");
X	case SCH$C_SUSPO:
X		return("<suspo>");
X	}
X	return(sprintf(buf, "<%d>", state));
X}
X
X/*
X *  Similar to strcmp() but handles trailing unit number part numerically.
X */
Xttycmp(s1, s2)
X	register char *s1, *s2;
X{
X
X	while (isalpha(*s1) && isalpha(*s2) && *s1 == *s2++)
X		if (*s1++=='\0')
X			return(0);
X	if (isdigit(*s1) && isdigit(*s2))
X		return(atoi(s1) - atoi(s2));
X	return(*s1 - *--s2);
X}
X
X/*
X * Finger a remote machine
X */
Xnetfinger(name)
X	char *name;
X{
X	char *host;
X	struct hostent *hp;
X	struct servent *sp;
X	struct sockaddr_in sin;
X	int s;
X	register FILE *f;
X	register int c;
X	register int lastc;
X
X	if (name == 0)
X		return (0);
X	if ((host = rindex(name, '@')) == 0)
X		return (0);
X	*host++ = '\0';
X	bzero((char *)&sin, sizeof (sin));
X	if ((sin.sin_addr.s_addr = inet_addr(host)) != -1)
X		sin.sin_family = AF_INET;
X	else if ((hp = gethostbyname(host)) != 0) {
X		sin.sin_family = hp->h_addrtype;
X		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
X		host = hp->h_name;
X	} else {
X		printf("%s: unknown host\n", host);
X		return(1);
X	}
X	printf("[%s]", host);
X	if ((sp = getservbyname("finger", "tcp")) == 0) {
X		printf("tcp/finger: unknown service\n");
X		return (1);
X	}
X	sin.sin_port = sp->s_port;
X	s = socket(sin.sin_family, SOCK_STREAM, 0);
X	if (s < 0) {
X		(void) fflush(stdout);
X		perror("socket");
X		return (1);
X	}
X	if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
X		(void) fflush(stdout);
X		perror("connect");
X		(void) close(s);
X		return (1);
X	}
X	putchar('\n');
X#ifdef notdef
X	if (large)
X		write(s, "/W ", 3);
X#endif
X	write(s, name, strlen(name));
X	write(s, "\r\n", 2);
X	f = fdopen(s, "r");
X	while ((c = getc(f)) != EOF) {
X		switch(c) {
X		case 0210:
X		case 0211:
X		case 0212:
X		case 0214:
X			c -= 0200;
X			break;
X		case 0215:
X			c = '\n';
X			break;
X		}
X		lastc = c;
X		if (isprint(c) || isspace(c))
X			putchar(c);
X		else
X			putchar(c ^ 100);
X	}
X	if (lastc != '\n')
X		putchar('\n');
X	(void) fclose(f);
X	return (1);
X}
X
X/*
X * Convert a VMS time quadword to Unix format
X */
Xstatic u_long
Xcvt_to_unix_time(time)
X	u_long time[2];
X{
X	u_long local[2];
X	int dummy;
X	static int January_1_1970[2] = {0x4bec0000,0x007c9567};
X
X	local[0] = time[0]; local[1] = time[1];
X	_$Subtract_Quadword(January_1_1970, local);
X	if (!(_$Cache_Flags & _$GMT_VALID)) _$Get_GMT_Info();
X	return(_$EDIV(10000000, local, &dummy) + _$Seconds_From_GMT);
X}
SHAR_EOF
if test 13167 -ne "`wc -c < 'finger.c'`"
then
	echo shar: error transmitting "'finger.c'" '(should have been 13167 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'getidle.c'" '(3921 characters)'
if test -f 'getidle.c'
then
	echo shar: will not over-write existing file "'getidle.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getidle.c'
X/*
X *	getidle() - determine idle information for terminals (privileged)
X *
X * revision history
X *
X * 05b 18Jul86 cal .Modified to reference system variables as externs.
X *                  Wrote exe_ipid_to_epid() using asm()s.
X * 05a 01Apr86 cal .Converted to VMS V4.
X * 04a 19Mar84 cal .First "c" version.
X *
X * synopsis
X *
X * #include <sys/types.h>
X *
X * int status, getidle();
X * long *ap_tim;
X * u_long *ap_tim;
X * u_long *ap_tim;
X *
X * status = getidle([&ap_tim], &ap_pid, [&ap_net]);
X *
X *	ap_tim - pointer to receive idle time buffer (optional)
X *	ap_pid - pointer to receive pid buffer
X *	ap_net - pointer to receive net address buffer (optional)
X *	status - returned VMS status
X *
X * The optional arguments may be replaced with "0". The idle times,
X * process ids, and net values are stored in the buffers in consecutive
X * elements with a zero longword in the pid buffer to mark end of the
X * list.
X *
X * The net address buffer contains either the Decnet logical link number
X * for a remote terminal or else the host address for a "nty" port.
X *
X * The information is ordered by terminal name.
X *
X * Note: Use of this routine requires the privilege CMKRNL.
X *
X */
X
X#include <sys/types.h>
X#include <netinet/in.h>
X
X#include "vms/ucbdef.h"
X#include "vms/ddbdef.h"
X#include "vms/ttyucbdef.h"
X#include "vms/dcdef.h"
X#include "vms/devdef.h"
X#include "vms/ssdef.h"
X
Xstatic struct XUCB {
X	char xucb_dummy[0x13c];
X	u_long xucb$x_netaddr;
X};
X
Xextern struct DDB *ioc$gl_devlist;
Xextern int exe$gl_abstim;
X
Xstatic int idlekrn();
Xstatic u_long exe_ipid_to_epid();
X
X/*
X *	Useful constants
X */
X
X#define FUDGE 2				/* add this to exe$gl_abstim */
X#define MAX_UNITS 128			/* max units to report about */
X
Xstatic long bl_tim[MAX_UNITS];
Xstatic u_long bl_pid[MAX_UNITS];
Xstatic u_long bl_net[MAX_UNITS];
X
Xgetidle(ap_tim, ap_pid, ap_net)
X	long **ap_tim;
X	u_long **ap_pid;
X	u_long **ap_net;
X{
X	register int i;
X
X#ifdef notdef
X	status = sys$lkwset();
X	if (status != SS$_WASCLR && status != SS$_WASSET)
X		return(status);
X#endif
X	i = sys$cmkrnl(idlekrn, 0);
X#ifdef notdef
X	status = sys$ulwset();
X	if (status != SS$_WASCLR && status != SS$_WASSET)
X		return(status);
X#endif
X	if (i != SS$_NORMAL)
X		return(i);
X	if (ap_tim)
X		*ap_tim = bl_tim;
X	*ap_pid = bl_pid;
X	if (ap_net)
X		*ap_net = bl_net;
X	return(SS$_NORMAL);
X}
X
X
X/*
X *	Entry point for the privileged search and slurp.
X */
X
Xstatic u_long *nty = (u_long *)"\003NTY";
Xstatic u_long *nta = (u_long *)"\003NTA";
X
Xstatic idlekrn()
X{
X	register int i;
X	register struct UCB *up;
X	register struct DDB *dp;
X	register u_long *p_pid;
X	register long *p_tim;
X	register u_long *p_net;
X	char *cp;
X	int now;
X	int status;
X	 
X	i = 0;
X	status = SS$_NORMAL;
X	p_tim = bl_tim;
X	p_pid = bl_pid;
X	p_net = bl_net;
X
X	now = exe$gl_abstim + FUDGE;
X#ifdef notdef
X	asm("jsb	_sch$iolockr");
X#endif
X
X	for (dp = ioc$gl_devlist; dp; dp = dp->ddb$l_link) {
X		if ((up = dp->ddb$l_ucb) == 0 || up->ucb$b_devclass != DC$_TERM)
X			continue;
X		for ( ; up; up = up->ucb$l_link) {
X			if (up->ucb$l_pid == 0)
X				continue;
X
X			/* Store process id */
X			*p_pid++ = exe_ipid_to_epid(up->ucb$l_pid);
X
X			/* Get idle time */
X			if ((up->ucb$w_sts & UCB$M_TIM) != 0 ||
X			    (up->ucb$w_sts & UCB$M_BSY) == 0 ||
X			    (*p_tim = now - up->ucb$l_duetim) < 0)
X				*p_tim = 0;
X			p_tim++;
X
X			/* Get network info (if a rta, nty, or nta) */
X			*p_net = 0;
X			if ((up->ucb$l_devchar2 & DEV$M_RTT) != 0)
X				*p_net = ((struct TTYUCB *)up)->ucb$w_rtt_link;
X			else if (*nty == *(u_long *)dp->ddb$t_name ||
X				 *nta == *(u_long *)dp->ddb$t_name)
X				*p_net = ((struct XUCB *)up)->xucb$x_netaddr;
X			p_net++;
X
X			if (++i >= MAX_UNITS) {
X				status = SS$_BUFFEROVF;
X				goto done;
X			}
X		}
X	}
Xdone:
X
X#ifdef notdef
X	asm("jsb	_sch$iounlock");
X#endif
X	*p_pid = 0;
X	return(status);
X}
X
Xstatic u_long
Xexe_ipid_to_epid(pid)
X	u_long pid;
X{
X#ifdef lint
X	return(pid);
X#else
X	asm("movl	4(ap),r0");
X	asm("jsb	_exe$ipid_to_epid");
X	asm("ret");
X#endif
X}
SHAR_EOF
if test 3921 -ne "`wc -c < 'getidle.c'`"
then
	echo shar: error transmitting "'getidle.c'" '(should have been 3921 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'item_list_3.h'" '(258 characters)'
if test -f 'item_list_3.h'
then
	echo shar: will not over-write existing file "'item_list_3.h'"
else
sed 's/^X//' << \SHAR_EOF > 'item_list_3.h'
X/*
X * Define the standard item list 3 struct.
X */
X
Xstruct item_list_3 {
X	short i_length;				/* length of user buffer */
X	short i_code;				/* request code number */
X	char *i_buffer;				/* buffer address */
X	short *i_rslength;			/* result length address */
X};
SHAR_EOF
if test 258 -ne "`wc -c < 'item_list_3.h'`"
then
	echo shar: error transmitting "'item_list_3.h'" '(should have been 258 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'rmtinfo.c'" '(3042 characters)'
if test -f 'rmtinfo.c'
then
	echo shar: will not over-write existing file "'rmtinfo.c'"
else
sed 's/^X//' << \SHAR_EOF > 'rmtinfo.c'
X#ifndef lint
Xstatic char rcsid[] =
X    "@(#) $Header: rmtinfo.c,v 1.3 87/04/09 20:20:51 leres Exp $ (LBL)";
X#endif
X/*
X *	The privilege NETMBX is required for use.
X *
X *	Warning: This routine is chalked full of undocumented MAGIC.
X */
X#include <ctype.h>
X#include <strings.h>
X
X#include "vms/nfbdef.h"
X#include "vms/ssdef.h"
X#include "vms/iodef.h"
X
X/*
X * Use nfb block to help define what we need.
X */
Xstatic struct XNFB {
X	struct NFB x;
X#define xnfb$b_fct x.nfb$b_fct
X#define xnfb$b_flags x.nfb$b_flags
X#define xnfb$b_database x.nfb$b_database
X#define xnfb$b_oper x.nfb$b_oper
X#define xnfb$l_srch_key x.nfb$l_srch_key
X#define xnfb$l_srch2_key x.nfb$l_srch2_key
X#define xnfb$l_x_lli_pna x.nfb$l_fldid
X	unsigned long xnfb$l_x_lli_pnn;
X	unsigned long xnfb$l_x_endoflist;
X} nfb;
X
Xstatic struct acpbuf {
X	long a_node;			/* decnet node number */
X	short a_length;			/* length of the decnet host name */
X	char a_name[6];			/* decnet host name */
X} abuf;
X
Xstatic struct dsc {
X	long d_length;
X	char *d_address;
X};
X
Xrmtinfo(link, node, name)
X	long link;
X	long *node;
X	char *name;
X{
X	register int i, status;
X	int sys$assign(), sys$qiow();
X	short iosb[4];
X	struct dsc netdsc, nfbdsc, keydsc, bufdsc;
X	long key[2];
X	static int chan = 0;
X
X	/*
X	 *	If necessary, assign a channel to NET
X	 */
X	if (!chan) {
X		netdsc.d_address = "NET:";
X		netdsc.d_length = strlen(netdsc.d_address);
X		if ((status = sys$assign(&netdsc, &chan, 0, 0)) != SS$_NORMAL)
X			return(status);
X	}
X	/*
X	 *	Set up the nfb request buffer
X	 */
X	bzero(&nfb, sizeof(nfb));
X	nfb.xnfb$b_fct = NFB$C_FC_SHOW;
X	nfb.xnfb$b_flags = NFB$M_NOCTX;		/* don't update the database */
X	nfb.xnfb$b_database = NFB$C_DB_LLI;	/* logical link info database */
X	nfb.xnfb$b_oper = NFB$C_OP_EQL;		/* match the key exactly */
X	nfb.xnfb$l_srch_key = NFB$C_LLI_LLN;	/* key is logical link number */
X	nfb.xnfb$l_srch2_key = NFB$C_WILDCARD;	/* search the whole database */
X	nfb.xnfb$l_x_lli_pna = NFB$C_LLI_PNA;	/* partner's node address */
X	nfb.xnfb$l_x_lli_pnn = NFB$C_LLI_PNN;	/* partner's node name */
X	nfb.xnfb$l_x_endoflist = NFB$C_ENDOFLIST;
X	/*
X	 *	Construct the nfb descriptor
X	 */
X	nfbdsc.d_address = (char *) &nfb;
X	nfbdsc.d_length = sizeof(nfb);
X	/*
X	 *	Construct the key descriptor
X	 */
X	keydsc.d_address = (char *) &key[0];
X	keydsc.d_length = sizeof(key);
X	/*
X	 *	Construct the logical link key descriptor
X	 */
X	key[0] = 0;
X	key[1] = link;
X	/*
X	 *	Construct the return buffer descriptor
X	 */
X	bufdsc.d_address = (char *) &abuf;
X	bufdsc.d_length = sizeof(abuf);
X	/*
X	 *	Ask NET about this port
X	 */
X	status = sys$qiow(0, chan, IO$_ACPCONTROL, iosb, 0, 0,
X	    &nfbdsc, &keydsc, 0, &bufdsc, 0, 0);
X	if (status != SS$_NORMAL)
X		return(status);
X	status = iosb[0];
X	if (status != SS$_NORMAL)
X		return(status);
X	/*
X	 *	Return the node number
X	 */
X	*node = abuf.a_node;
X	/*
X	 *	Return the node name
X	 */
X	if ((i = abuf.a_length) > sizeof(abuf.a_name))
X		i = sizeof(abuf.a_name);
X	name[i] = '\0';
X	for (--i; i >= 0; i--)
X		if (isupper(name[i] = abuf.a_name[i]))
X			name[i] = tolower(name[i]);
X	return(SS$_NORMAL);
X}
SHAR_EOF
if test 3042 -ne "`wc -c < 'rmtinfo.c'`"
then
	echo shar: error transmitting "'rmtinfo.c'" '(should have been 3042 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'syssym.awk'" '(115 characters)'
if test -f 'syssym.awk'
then
	echo shar: will not over-write existing file "'syssym.awk'"
else
sed 's/^X//' << \SHAR_EOF > 'syssym.awk'
X/^8/ {
X	name = substr( $2, 3, length ( $2 ) - 2 )
X	printf("\n\t.globl\t_%s\n\t.set\t_%s,0x%s\n", name, name, $1)
X}
SHAR_EOF
if test 115 -ne "`wc -c < 'syssym.awk'`"
then
	echo shar: error transmitting "'syssym.awk'" '(should have been 115 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ucbdef.i'" '(284 characters)'
if test -f 'ucbdef.i'
then
	echo shar: will not over-write existing file "'ucbdef.i'"
else
sed 's/^X//' << \SHAR_EOF > 'ucbdef.i'
Xstruct FKB *ucb$l_fqfl
Xstruct FKB *ucb$l_fqbl
Xstruct CRB *ucb$l_crb
Xstruct DDB *ucb$l_ddb
Xstruct UCB *ucb$l_link
Xstruct VCB *ucb$l_vcb
Xstruct IRP *ucb$l_ioqfl
Xstruct IRP *ucb$l_ioqbl
Xstruct IRP *ucb$lirp
Xstruct UCB *ucb$l_amb
Xchar *ucb$l_svpn
Xchar *ucb$l_svapte
Xstruct DDT *ucb$l_ddt
SHAR_EOF
if test 284 -ne "`wc -c < 'ucbdef.i'`"
then
	echo shar: error transmitting "'ucbdef.i'" '(should have been 284 characters)'
fi
fi # end of overwriting check
if test ! -d 'vms'
then
	echo shar: creating directory "'vms'"
	mkdir 'vms'
fi
echo shar: entering directory "'vms'"
cd 'vms'
echo shar: done with directory "'vms'"
cd ..
echo shar: extracting "'vmsperror.c'" '(491 characters)'
if test -f 'vmsperror.c'
then
	echo shar: will not over-write existing file "'vmsperror.c'"
else
sed 's/^X//' << \SHAR_EOF > 'vmsperror.c'
X#include <stdio.h>
X
X#include "dsc.h"
X
Xextern int vmserrno;
X
Xvmsperror(s)
X	char *s;
X{
X	int status;
X	unsigned short len;
X	struct dsc dsc;
X	char buf[128];
X
X	dsc.d_buf = buf;
X	dsc.d_len = sizeof(buf);
X	len = 0;
X	if (((status = sys$getmsg(vmserrno, &len, &dsc, 0xf, 0)) & 1) == 0) {
X		sprintf(buf, "0x%x (0x%x)", vmserrno, status);
X		len = strlen(buf);
X	}
X	write(fileno(stderr), s, strlen(s));
X	write(fileno(stderr), ": ", 2);
X	write(fileno(stderr), buf, len);
X	write(fileno(stderr), "\n", 1);
X}
SHAR_EOF
if test 491 -ne "`wc -c < 'vmsperror.c'`"
then
	echo shar: error transmitting "'vmsperror.c'" '(should have been 491 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0