BBN-V6/progs/netstat.c

Compare this file to the similar file:
Show the results in this format:

#
/*
 * ncc -sO netstat.c -ln -lj
 */

#include "../h/param.h"
#include "../h/netparam.h"
#include "../h/leader.h"
#include "../h/contab.h"
#include "../h/net.h"

char *hs_file "/etc/host_status";
/*
module name:
	netstat.c

function:
	a program to display the status of connections on the arpa network

globals contained:
	r_contab
	w_contab
	rfnm_map
	socket
	hstat_tab
	reasons
	days
	corefd
	coreref

routines contained:
	main
	pr_con
	pr_skt
	pr_ldr
	find_symbol
	seek_to
	host_status
	printoptions
	printflags

modules referenced:
	../contab.h
	../net.h

modules referencing:

history:
	Designed and coded by Mark Kampe, UCLA-ATS, 3/76 as a debugging aid
	Modified by Dan Franklin 7/14/78 to show flags as letters instead of octal #;
	   added -f option to explain meaning of flags
	   and made to do -c if no args supplied
	Modified by Dan Franklin ????? to print entire foreign socket number
		added -o option to print link and socket numbers in octal
	Modified by Dan Franklin 9/12/78 to check that userid is indeed in table
		and print ?? if it is not recognized.
        Modified by Dan Franklin 9/15/78 to use locvo and locv to print 32-bit
                socket number instead of using longs
	long host mods jsq bbn 1-31-79
	changed so reading from /etc/host_status and /usr/net/lhnames (rdhosts)
		is done only when needed jsq BBN 3-20-79

*/
#define true 0177777
#define false 000000
#define then  /**/

 int corefd, octal;     /* octal is nonzero if octal format desired */
 char *coreref {"/dev/kmem"};
 struct rdskt socket;
 struct leader  leader;
 int rfnm_map[LIMPS];
struct hstat_tab {
	long hs_host;
	int hs_up;
} hstat_tab[host_ken];

long gethost(), stolhost();
char *hostname(), puthost();
long localhost;
int localnet;

/**/
char *reasons[]
{
	"Unknown",
	"Ready line off",
	"Tardy",
	"Non-existant",
	"dest. IMP reinitialization",
	"Scheduled PM",
	"Scheduled Hardware",
	"Scheduled Software",
	"Emergency Restart",
	"Power Outage",
	"Software Breakpoint",
	"Hardware Failure",
	"Not scheduled up",
	"Unknown",
	"Unknown",
	"Coming up"
};
char *days[]
{
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday",
	"Sunday",
	"Monday"
};

/* name:
	main

function:
	to get all of the data from kernel memory, and cause it
	to be formatted

algorithm:

parameters:
	-k	use /usr/sys/core instead of /dev/kmem
	-c	tell about connections
	-l	show last sent and received leaders
	-r	print out any hosts with outstanding rfnms
	-s	status of all sockets
	-h	which hosts are known to be alive
	-n      show what netstat system call returns
	name	status of host with that name

returns:

globals:
	r_contab
	w_contab
	corefd
	coreref
	leader

calls:
	open	(sys)
	read	(sys)
	close	(sys)
	printf
	find_symbol
	seek_to
	pr_con

history:

 */
main(argc, argv)
 int argc;
 char **argv;
{	register int i;
	register int addr;
	register char *s;
	int cflag;
	int lflag;
	int rflag;
	int sflag;
	int hflag;
	int impstatus;

	cflag = 0;
	lflag = 0;
	rflag = 0;
	sflag = 0;
	hflag = 0;

	for(i = 1; i < argc; i++)
	{	if (argv[i][0] != '-')
		then	host_status(argv[i]);
		else	for(s = argv[i] + 1; *s; s++)
		switch (*s)
		{	case 'k':
				coreref = "sysdump";
				break;
                        case 'o':
                                octal++;
			case 'c':
				cflag++;
				break;
			case 'f':
				printflags();
				break;
			case 'l':
				lflag++;
				break;
			case 'r':
				rflag++;
				break;
			case 's':
				sflag++;
				break;
			case 'h':
				hflag++;
				break;
			case 'n':
				donetstat();
				break;
			default:
				printoptions();
				break;
		};

	}
	if (argc == 1)
		cflag++;	/* Print connections by default */
	corefd = open(coreref,0);
	if (corefd < 0) then
	{	printf("Unable to access %s\n", coreref);
		exit(-1);
	}

  /*    seek_to(0164004);
	read(corefd, &impstatus, 2);
	if (impstatus > 0) then
		printf("IMP thinks we're up\n");
	else
	{	printf("IMP thinks we're down\n");
		exit(-1);
	}
  */
	if (lflag) then
	{	i = find_symbol("_imp");
		seek_to(i+2);
		read(corefd, &leader, sizeof leader);
		printf("\nin: ");
		pr_ldr(&leader);
		i = find_symbol("_oimp");
		seek_to(i);
		read(corefd, &leader, sizeof leader);
		printf("out: ");
		pr_ldr(&leader);
	}

	if (cflag) then
	{
		addr = find_symbol("_r_contab");
		seek_to(addr);
		read(corefd, &r_contab, sizeof r_contab);
	
		addr = find_symbol("_w_contab");
		seek_to(addr);
		read(corefd, &w_contab, sizeof w_contab);
	
		printf(
"D   hostname  lnk  l-skt    f-skt     flags   p-id user-id bs m-all b-all b-q'd\n");
		printf(
"- ----------- --- ------ ----------- -------- ---- ------- -- ----- ----- -----\n");
		for(i = 0; i < CONSIZE; i++) pr_con(&r_contab[i], 'R');
		for(i = 0; i < CONSIZE; i++) pr_con(&w_contab[i], 'W');
	}

	if (rflag) then
	{	addr = find_symbol("_host_map");
		seek_to(addr);
		read(corefd, rfnm_map, sizeof rfnm_map);
		pr_rfnm( rfnm_map );
	}

	if (hflag) then host_status(0);

	close(corefd);
	exit();
}
/* name:
	pr_con

function:
	to print out a connection table entry

algorithm:
	if entry is not in use, ignore it;
	print out the direction, host# and link#;
          print out the local and foreign socket #s;
	read in the associated socket structure;
	call pr_skt on it;

parameters:
contab	pointer to a connection table entry;
	char	direction of link (R or W)

returns:
	true	if the entry was in use
	false	otherwise

globals:
	socket
	hostname

calls:
	seek_to
	read	(sys)
	printf

called by:
	main

history:

*/
pr_con( contabp , dir )
 struct conentry *contabp;
 char dir;
{       register struct conentry *ctp;
	long i;
	register int j;
        char *locv();
        char *locvo();
	char *hname;

	ctp = contabp;
	i = ctp -> c_host;
	j = ctp -> c_link;
	if (( i == 0 && j == 0 ) || ctp -> c_siptr == 0) then return(false);

	hname = hostname(i);
	if (*hname == '?') hname = puthost(i, 0);
	printf(octal? "%c %-11.11s %3o ":"%c %-11.11s %3d ", dir, hname, j & 0177);
        printf(octal? "%6o %11s ":"%6d %11s ", ctp->c_localskt,
               octal? locvo(ctp->c_fskt[0], ctp->c_fskt[1])
                    : locv(ctp->c_fskt[0], ctp->c_fskt[1])
               );
	seek_to(ctp->c_siptr);
	read(corefd, &socket, sizeof socket);
	pr_skt(&socket, dir);
	return(true);
}
/* name:
	pr_skt

function:
	to format the information in a socket structure

algorithm:
	use a read or write structure pointer as is appropriate;
	print out the bytesize, pid, flags and message allocation;
	if a read socket:
		print out the bytes allocation and number of queued bytes;
	else
		print out the bytes allocation;

parameters:
	pointer to a socket structure
	a direction	('R' for read, 'W' for write)

returns:

globals:

calls:
	printf

called by:
	pr_con

history:

 */
/* FLAG TABLE */

struct flgstruc
{
   int flagbit;
   char flagc;
   char *flagmsg;
}
    flgstruc[]
{
   n_hhchanwt,  'h', "n_hhchanwt -- read socket waiting for link 0",
   n_rcvwt,     'r', "n_rcvwt -- read socket waiting for input",
   n_prevmerr,  'x', "n_prevmerr -- transmission error on last send operation",
   n_sendwt,    'w', "n_sendwt -- write socket waiting for send to complete",
   n_allwt,     'a', "n_allwt -- write socket waiting for allocation",
   n_xmterr,    'X', "n_xmterr -- incomplete transmission occurred, proc not yet awakened",
   n_open,      'o', "n_open -- socket is open and usable",
   n_toncp,     'i', "n_toncp -- all communication over this socket goes to ncp",
   n_usriu,     'u', "n_usriu -- user still using this socket",
   n_ncpiu,     'n', "n_ncpiu -- ncp still using this socket",
   n_eof,       'c', "n_eof -- socket has been closed",
   n_rfnmwt,    'R', "n_rfnmwt -- RFNM received, proc not yet awakened",
   n_allocwt,   'A', "n_allocwt -- ALL received, proc not yet awakened",
   0, ' ', ""
};

pr_skt(sptr,dir)
 struct rdskt *sptr;
 char dir;
{	register struct rdskt *sp;
	register int i;
	register int j;
	int flags;
        struct flgstruc *fsp;
	char flagstr[16];
	char *flagp;
	struct	{
		char	*qlink;
		char p_stat;
		char	p_flag;
		char	p_pri;
		char	p_sig;
		char	p_uid;
		char	p_time;
		char	p_cpu;
		char	p_nice;
		int	p_pgrp;
		int	p_pid;
		int	p_ppid;
		int	p_addr;
		int	p_size;
		int	p_wchan;
		int	*p_textp;
		int	p_clktim;
		} proc;
	char linebuf[120];


	sp = sptr;

        if (sp->r_flags & n_usriu) then
	{	seek_to(sp->r_rdproc);
		read(corefd, &proc, sizeof proc);

                if (getpw(proc.p_uid, linebuf))
                     {
                     linebuf[0] = '?';
                     linebuf[1] = '?';
                     linebuf[2] = '\0';
                     }
                else
                  {
                  for(i = 0; i < 7; i++)
                      	if (linebuf[i] == ':') then break;
                  linebuf[i] = '\000';
                  }
	}
	else
	{	linebuf[0] = '\000';
		proc.p_pid = 0;
	}

	flags = sp->r_flags & n_flgfld;
        flagp = flagstr;
        for (fsp = &flgstruc[0]; fsp->flagbit; fsp++)
                if (flags & fsp->flagbit)
                        *flagp++ = fsp->flagc;
        *flagp = '\0';

        printf("%8s %4d %7s %2d %5d ", flagstr, proc.p_pid,
		linebuf, sp->r_bsize, sp->r_msgs);

	if (dir == 'R') then
		printf("%5d %5d\n", sp->r_bytes&077777, sp->r_qtotal&077777);
	else
	{	i = (sp->w_falloc[1] >> 3) & 017777;
		j = (sp->w_falloc[0] << 13) & 0060000;
		printf("%5d\n", (i | j));
	}

	return(true);
}
/* name:
	pr_ldr

function:
	to format and print an ih or hi leadr

algorithm:
	print out the type, host, link, subtype, bytesize and count

parameters:
	pointer to a leader structure

returns:

globals:

calls:
	printf

called by:
	main

history:

*/
pr_ldr( leaderp )
 struct leader *leaderp;
{	register struct leader *lp;
	long host;

	lp = leaderp;
#ifndef SHORT
	host = 0;
	host.h_imp0 = lp -> l_ih.ih_imp0;
	host.h_imp1 = lp -> l_ih.ih_imp1;    /* swap imp field */
	host.h_hoi = lp -> l_ih.ih_hoi;      /* use host directly */
	if (host) host.h_net = localnet;
#endif
#ifdef SHORT
	host = lp -> l_ih.ih_host & 0377;
	host = stolhost(host);
#endif
	printf("host %s, link %d, type %d(%d), size %d(%d)\n",
		hostname(host), lp->l_ih.ih_link&0377, lp->l_ih.ih_type,
		lp->l_ih.ih_sbty, lp->l_hh.hh_bycnt, lp->l_hh.hh_bysz);
#ifndef SHORT
	printf("nff %d, net %d, flgs %o, htype %d\n",
		lp -> l_ih.ih_nff, lp -> l_ih.ih_net,
		lp -> l_ih.ih_flgs, lp -> l_ih.ih_htype);
#endif
}
/* name:
	pr_rfnm

function:
	to find which hosts have outstanding rfnms

algorithm:
	Do for each word in rfnm table
		Do for each bit in that word
			If bit is on, print the hostnumber

parameters:
	pointer to a rfnm table

returns:
	true

globals:

calls:
	printf

called by:
	main

history:

*/
pr_rfnm( rptr )
 int *rptr;
{	register int numout;
	register int word;
	register int bit;
	long host;

	printf("Hosts with outstanding rfnms:\n");
	numout = 0;
	for(word = 0; word < LIMPS; word++)
		for(bit = 0; bit < LHOI; bit++)
			if (  (rptr[word] >> bit) & 01 ) then
			{	if (numout) then printf(", ");
				host.h_hoi = bit;
				host.h_imp = word;
				host.h_net = localnet;
				printf("%10s", hostname(host));
				if (numout > 6) then
				{	printf("\n");
					numout = 0;
				}
			}
}
/* name:
	find_symbol

function:
	to find the address (in /unix) of a specified symbol

algorithm:
	put the symbol into an argument block;
	call nlist;
	if the symbol was found, return its value, else
		print an error message and exit

parameters:
	*char	pointer to the null terminated symbol name

returns:
	only if symbol was found
	int

globals:

calls:
	nlist
	printf
	exit

called by:
	main

history:

*/
find_symbol( symbolp )
 char *symbolp;
{	register char *p;
	register int i;
	static struct {
		char name[8];
		int  vtype;
		int  value;
		} nl[2];


	p = symbolp;
	for(i = 0; i < 8; i++)
		if (nl[0].name[i] = *p) then p++;

	nl[0].vtype = 0;
	nl[1].name[0] = '\000';

	nlist("/unix", nl);
	if (nl[0].vtype == 0) then
	{	printf("Unable to locate %s in /unix\n", symbolp);
		exit(-1);
	}
	else
		return( nl[0].value );
}
/* name:
	seek_to

function:
	to do a seek to a specified location on the file on corefd

algorithm:
	do an absolute seek to half the number;
	do a relative seek to half the number;

parameters:
	an address (16-bit) in the file

returns:

globals:

calls:
	seek	(sys)

called by:
	mail
	pr_con

history:
	written because many addresses in the system look like negative
	numbers and seek fucks up on them.

*/
seek_to(addr)
 int addr;
{	register int a;

	a = (addr>>1) & 077777;
	seek(corefd, a, 0);
	seek(corefd, a, 1);
}
/* name:
	printoptions

function:
	to print out help information

calls:
	printf

called by:
	main

history:

*/
printoptions()
{	printf("Netstat -- options\n\n");
	printf("option     meaning\n");
	printf("------     -------\n");
	printf("none        default to -c\n");
	printf("-c          display the status of all open connections\n");
        printf("-o          -c with octal socket and link numbers\n");
	printf("-f	    explain flags of connection list\n");
	printf("-k          use /usr/sys/core instead of /dev/mem\n");
	printf("-r          which hosts have oustanding rfnms\n");
	printf("-l          show the last sent and received leaders\n");
	printf("-h          which hosts are believed up\n");
	printf("-n          local host; daemon up?; what's in kernel\n");
	printf("hostname    display the status of that host\n");
	printf("\n");
}
/* name:

	host_status
function:
	to decode the status of a particular host

algorithm:

parameters:
	0               print all alive hosts
	host id string  give info on this host

returns:

globals:
	hstat_tab
	reasons
	days

calls:
	printf
	gethost, hostname       (libn)

called by:
	main

history:
	Stolen from steve holmgren's hstat program by Mark Kampe
	Fixed to print correct status jsq BBN 3-7-79
	Printing all living hosts and
		hstat_tab init moved here from main jsq BBN 3-20-79
*/
int hstatfd -1;

host_status( hname )
 char *hname;
{
	register when, why;
	long entry_num;
	int hashednum, status;
	register struct hstat_tab *hs;
	char *as;

	if (hstatfd < 0) {
		hstatfd = open(hs_file , 0);
		if (hstatfd < 0) then
		{       printf("Unable to open %s\n", hs_file);
			exit(-1);
		}
		read(hstatfd , hstat_tab, sizeof(hstat_tab));
		close(hstatfd);
	}
	if (hstat_tab[0].hs_up != 0) {
		printf("\nCannot communicate with local IMP.\n");
		return;
	}
	if (hname == 0) {
		why = 0;
		printf("\nThe following hosts are up:\n");
		for(when = 1; when < host_ken - 1; when++)
			if (hstat_tab[when].hs_up == 0) then
			{
				entry_num = hstat_tab[when].hs_host;
				as = hostname(entry_num);
				if (*as == '?') as = puthost(entry_num, 0);
				printf("%12s  " , as);
				if ( (++why)%5 == 0 ) then printf("\n");
			}
		if (why == 0) then
			printf("\n\n\007Looks pretty bad, doesn't it\n\n");
		else	printf("\n");
		return;
	}
	entry_num = gethost(hname);
	if ( entry_num == -1 ) then
	{       printf("%s is not a known host\n" , hname);
		return(false);
	}

	hashednum = host_hash(entry_num);
	if (hstat_tab[hashednum].hs_host != entry_num) {
		hashednum = -1;
		for (hs = &hstat_tab[0]; hs < &hstat_tab[host_ken - 1]; hs++){
			if (hs -> hs_host == entry_num) {
				hashednum = hs - &hstat_tab[0];
				break;
	}       }       }
	if (hashednum == -1) {
		printf("no info on %s\n", hostname(entry_num));
		return(false);
	}
	if( (status = hstat_tab[hashednum].hs_up) == 0 )
		printf("Host %s is alive\n",hostname( entry_num ));
	else
	{
		why = ((status.hibyte)&017);
		printf("Host %s is Dead", hostname(entry_num));
		if (why) printf("; Cause: %s", reasons[why]);
		when = ((swab (status)) >> 4)& 07777;
		if (when != 07776) {
			printf("; Back up: %s %d:%d",
			days[ when&07 ], (when>>3)&037, (when>>8)&017*5 );
		}
		printf("\n");
	}
}
swab(an) {int i; i.hibyte = an.lobyte; i.lobyte = an.hibyte; return(i); }
/*

module name:
	printflags

function:
	prints explanation of the flags in the connection listing

globals contained:
	none

calls:
	printf

history:
	Coded by Dan Franklin 7/14/78
*/

printflags()
{
        struct flgstruc *fsp;

	printf("The flags field corresponds precisely to the flags kept in the NCP.\n");
	printf("The appearance of a letter means that the corresponding bit is on.\n");
        for (fsp = &flgstruc[0]; fsp->flagbit; fsp++)
                printf("%c %s\n", fsp->flagc, fsp->flagmsg);
	return;
}

/*

name:   donetstat
function:
	to print the results of the netstat system call
algorithm: call it and print it
parameters: none
returns: nothing
globals:daemon, compflags
called by: main
calls: netstat
history: intial coding jsq bbn 2-9-79
*/
char *daemon[] { "rawdaemon up", "daemon down", "ncpdaemon up" };
char *compflags[] { "NETWORK", "SHORT", "NCP", "RMI", "GATEWAY", "MSG" };

donetstat() {
	register i;

	if (netstat(&netparam) == -1){
		perror("netparam");
		return;
	}
	printf("%s  ", puthost(netparam.net_lhost, 0));
	printf("%s\n", puthost(netparam.net_lhost, 4));
	printf("%s\n", daemon[(ncpopnstate) + 1]);
	for (i = 0; i < sizeof(compflags)/sizeof(compflags[0]); i++) {
		printf("%s\t%s\n", compflags[i],
			((1 << i) & netparam.net_flags) ?
				"yes" : "no");
	}
}