File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / usr / src / usr.bin / bsc / cmd / batch / bsctrace.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:26:12 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

/*	D.L.Buck and Associates, Inc. - 8/27/84
 *
 *	COPYRIGHT NOTICE:
 *		Copyright c 8/27/84 - An unpublished work by 
 *		D.L.Buck and Associates, Inc.
 *
 *	PROPRIETARY RIGHTS NOTICE:
 *		All rights reserved. This document and program contains
 *		proprietary information of D.L.Buck and Associates,Inc.
 *		of San Jose, California, U.S.A., embodying confidential
 *		information,  ideas, and expressions,  no part of which
 *		may be reproduced, or transmitted in any form or by any
 *		means,  electronic,  mechanical,  or otherwise, without
 *		the written permission of D.L.Buck and Associates, Inc.
 *
 *	NAME
 *		bsctrace - BISYNC Monitor Information Display Utility
 *
 *	SYNOPSIS
 *		bsctrace [-data=tttt] [-verbose] [file]
 *
 *	DESCRIPTION
 *		BSCTRACE interprets trace information as recorded by
 *		BSCMON.   The -data option is used to cause printing
 *		of the actual data, in addition to the state trace.
 *
 *	ALGORITHM
 *		I. Initialize:
 *			A. trace messages
 *			B. ASCII character set table
 *			C. trmat (trace matrix -- index to all bsc state
 *			   transitions and their meanings)
 *			D. trace buffer
 *	      		E. command line options: 
 *				1. verbose
 *				2. data display format (hex, ASCII, EBCDIC)
 *	       		F. if data or verbose options set, set up trace
 *			   report header
 *			G. open trace device
 *	       II. Process trace data:
 *			A. Read a trace buffer full of stuff from the trace
 *			   device
 *			B. for-loop: keep extracting trace packets until the
 *			   end of the trace buffer is reached, and:
 *				1. if data or verbose set and new page,
 *				   print trace report header
 *				2. switch on trace type:
 *					a. send, receive,decision,error, or
 *					   function types:
 *						i. get time packet was received
 *					       ii. if data and verbose not set:
 *							print only time rcv'd,
 *							state #, and state type
 *					           else 
 *							pull transition meaning
 *							from trmat and print it
 *							with time rcv'd, state # *							and state type
 *					       iii. get another packet from the
 *						    trace buffer
 *						iv. if it's not complete, set
 *					            trace buffer pointer to end
 *						    of buffer to end loop and
 *						    force another read beginning *					            at next trace packet.
 *						 v. break switch
 *					b. class trace type:
 *						i. get time packet was received
 *					       ii. if data and verbose not set:
 *						   print only time rcv'd, state
 *						   #, and state type
 *						   else pull class message
 *						   and print it, too.
 *					      iii. get another packet from the
 *						   trace buffer
 *					       iv. if it's not complete, set
 *					           trace buffer pointer to end
 *						   of buffer to end loop and
 *						   force another read beginning 
 *						   at next trace packet.
 *						v. break switch
 *					c. overruns trace type:
 *						i. i-v as above, except that
 *						   if data or verbose set,
 *					           print number of overruns.
 *					           overrun count is kept in
 *						   the trace state postion of
 *						   trace packets.
 *					d. data packet sent/received type:
 *						i. i-v as above, except that
 *						   if data or verbose set,
 *						   display data one character
 *						   at a time, using the ASCII
 *						   character set table to 
 *						   display in hex, ASCII, or
 *						   EBCDIC as user specified.
 *			C. close trace device
 */

#include <stdio.h>
/*
#include <sys/types.h>
*/
#include <bsc/bsctr.h>
#include "local.h"
#if defined BSD42
#include <sys/time.h>
#else
#include <time.h>
#endif

extern int errno;
extern char *sys_errlist[];

#define	HEX	1
#define	ASCII	2
#define	EBCDIC	3
#define PAGELEN 60	/* for date and verbose mode reports */

#ifndef lint
static char sccsid[] = "@(#)bsctrace.c	1.15 REL";
#endif

static long trmat[55][55];	/* index to trace text file; 
				   trace text file contains all possible bsc
				   state transitions and their meanings */

#define MAX_C 11	/* # of packet types */
char *c_info[] = {
		"Receive timeout",
		"Enquiry message",
		"End of transmission, or disconnect",
		"Negative acknowledgement",
		"Text block - last of series",
		"Text block - not last of series",
		"Wait acknowledgement",
		"Reverse interrupt",
		"Even acknowledgement",
		"Odd acknowledgement",
		"Temporary transmit delay"
	};

/* ASCII character set */
char *tbl1[] = {
	"00 NU NU ",
	"01 SH SH ",
	"02 SX SX ",
	"03 EX EX ",
	"04 04 ET ",
	"05 HT EQ ",
	"06 06 AK ",
	"07 RB BL ",
	"08 08 BS ",
	"09 09 HT ",
	"0A 0A LF ",
	"0B VT VT ",
	"0C FF FF ",
	"0D CR CR ",
	"0E SO SO ",
	"0F SI SI ",
	"10 DL DL ",
	"11 D1 D1 ",
	"12 D2 D2 ",
	"13 D3 D3 ",
	"14 14 D4 ",
	"15 15 NK ",
	"16 BS SY ",
	"17 17 EB ",
	"18 CN CN ",
	"19 EM EM ",
	"1A 1A SB ",
	"1B 1B EC ",
	"1C 1C FS ",
	"1D GS GS ",
	"1E 1E RS ",
	"1F US US ",
	"20 20 SP ",
	"21 21  ! ",
	"22 FS  \" ",
	"23 23  # ",
	"24 24  $ ",
	"25 LF  % ",
	"26 EB  & ",
	"27 EC  ' ",
	"28 28  ( ",
	"29 29  ) ",
	"2A 2A  * ",
	"2B 2B  + ",
	"2C 2C  , ",
	"2D EQ  - ",
	"2E AK  . ",
	"2F BL  / ",
	"30 30  0 ",
	"31 31  1 ",
	"32 SY  2 ",
	"33 33  3 ",
	"34 34  4 ",
	"35 RS  5 ",
	"36 36  6 ",
	"37 ET  7 ",
	"38 38  8 ",
	"39 39  9 ",
	"3A 3A  : ",
	"3B 3B  ; ",
	"3C D4  < ",
	"3D NK  = ",
	"3E 3E  > ",
	"3F SB  ? ",
	"40 SP  @ ",
	"41 41  A ",
	"42 42  B ",
	"43 43  C ",
	"44 44  D ",
	"45 45  E ",
	"46 46  F ",
	"47 47  G ",
	"48 48  H ",
	"49 49  I ",
	"4A 4A  J ",
	"4B  .  K ",
	"4C  <  L ",
	"4D  (  M ",
	"4E  +  N ",
	"4F 4F  O ",
	"50  &  P ",
	"51 51  Q ",
	"52 52  R ",
	"53 53  S ",
	"54 54  T ",
	"55 55  U ",
	"56 56  V ",
	"57 57  W ",
	"58 58  X ",
	"59 59  Y ",
	"5A  !  Z ",
	"5B  $  [ ",
	"5C  *  \\ ",
	"5D  )  ] ",
	"5E  ;  ^ ",
	"5F  ^  _ ",
	"60  -  `",
	"61  /  a",
	"62 62  b",
	"63 63  c",
	"64 64  d",
	"65 65  e",
	"66 66  f",
	"67 67  g",
	"68 68  h",
	"69 69  i",
	"6A  |  j",
	"6B  ,  k",
	"6C  %  l",
	"6D  _  m",
	"6E  >  n",
	"6F  ?  o",
	"70 70  p",
	"71 71  q",
	"72 72  r",
	"73 73  s",
	"74 74  t",
	"75 75  u",
	"76 76  v",
	"77 77  w",
	"78 78  x",
	"79  `  y",
	"7A  :  z",
	"7B  #  {",
	"7C  @  |",
	"7D  '  }",
	"7E  =  ~",
	"7F  \" RB" };
char *tbl2[] = {
	"80 80 ",
	"81  a ",
	"82  b ",
	"83  c ",
	"84  d ",
	"85  e ",
	"86  f ",
	"87  g ",
	"88  h ",
	"89  i ",
	"8A 8A ",
	"8B 8B ",
	"8C 8C ",
	"8D 8D ",
	"8E 8E ",
	"8F 8F ",
	"90 90 ",
	"91  j ",
	"92  k ",
	"93  l ",
	"94  m ",
	"95  n ",
	"96  o ",
	"97  p ",
	"98  q ",
	"99  r ",
	"9A 9A ",
	"9B 9B ",
	"9C 9C ",
	"9D 9D ",
	"9E 9E ",
	"9F 9F ",
	"A0 A0 ",
	"A1  ~ ",
	"A2  s ",
	"A3  t ",
	"A4  u ",
	"A5  v ",
	"A6  w ",
	"A7  x ",
	"A8  y ",
	"A9  z ",
	"AA AA ",
	"AB AB ",
	"AC AC ",
	"AD  [ ",
	"AE AE ",
	"AF AF ",
	"B0 B0 ",
	"B1 B1 ",
	"B2 B2 ",
	"B3 B3 ",
	"B4 B4 ",
	"B5 B5 ",
	"B6 B6 ",
	"B7 B7 ",
	"B8 B8 ",
	"B9 B9 ",
	"BA BA ",
	"BB BB ",
	"BC BC ",
	"BD  ] ",
	"BE BE ",
	"BF BF ",
	"C0  { ",
	"C1  A ",
	"C2  B ",
	"C3  C ",
	"C4  D ",
	"C5  E ",
	"C6  F ",
	"C7  G ",
	"C8  H ",
	"C9  I ",
	"CA CA ",
	"CB CB ",
	"CC CC ",
	"CD CD ",
	"CE CE ",
	"CF CF ",
	"D0  } ",
	"D1  J ",
	"D2  K ",
	"D3  L ",
	"D4  M ",
	"D5  N ",
	"D6  O ",
	"D7  P ",
	"D8  Q ",
	"D9  R ",
	"DA DA ",
	"DB DB ",
	"DC DC ",
	"DD DD ",
	"DE DE ",
	"DF DF ",
	"E0  \\",
	"E1 E1",
	"E2  S",
	"E3  T",
	"E4  U",
	"E5  V",
	"E6  W",
	"E7  X",
	"E8  Y",
	"E9  Z",
	"EA EA",
	"EB EB",
	"EC EC",
	"ED ED",
	"EE EE",
	"EF EF",
	"F0  0",
	"F1  1",
	"F2  2",
	"F3  3",
	"F4  4",
	"F5  5",
	"F6  6",
	"F7  7",
	"F8  8",
	"F9  9",
	"FA FA",
	"FB FB",
	"FC FC ",
	"FD FD ",
	"FE FE ",
	"FF FF"
	};
char tracebuf[TBUFSIZE];	/* trace information buffer */

int xy_ctr;			/* count # of data chars on a line */
char first[81];			/* 1st 4 bytes of characters for data display
			   	   go here */
char second[81];		/* 2nd 4 bytes of characters for data display
			   	   go here */
char *header[] = { "\f\n",
		"\t\t\tBSC State Trace Report\n",
		"\t\t\t\tmm/dd/yy\n",
"---------------------------------------------------------------------------\n",
		"  Time\t |State\t|  Type\t|  Message\n",
"---------------------------------------------------------------------------\n"
};
char *fptr;			/* first pointer */
char *sptr;			/* second pointer */
int counter;			/* report line count for verbose mode */
void exit();

main(argc,argv)
int argc;
char * argv[];
{
	struct tm *localtime();
	register int len;		/* length of data just read from trfd*/
	register int left = 0;		/* # of chars left in the tracebuf */
	int data = 0;			/* data display indicator */
	register int idx = 0;		/* convenient index */
	int trfd = 0;			/* trace information file descriptor */
	register struct bsctr *trb;	/* ptr to current trace packet */
	char *tptr;			/* ptr to ascii char set table */
	register int chr_count;
	int verbose = 0;
	FILE *fopen();
	FILE *trtxt;
	long ftell();		/* function returns current value of offset
				   relative to beginning of file */
	long whence;		/* contains value returned by ftell */
	long time();
	long currtime;

	char line[81];

	char *lptr;
	register char *pos;		/* trb->tr_data pointer */
	register char last_type = ' ';	/* last packet type */
	register int from;		/* bsc state this packet started from */
	register int to;		/* bsc state this packet went to */
	register int last_state, save_state;
	register struct tm *t;
	long xtime;
#ifdef ZEROTIME
	struct tm tm;
	t = &tm;
#endif

	lptr = &line[0];

/* get options from command line */
	for (counter = 1; counter < argc; ++counter) {
		if (strcmp(argv[counter],"-verbose") == 0 ||
		    strncmp(argv[counter],"-data",5) == 0) {

		/* set up trmat */
			if ((trtxt = fopen("trace.text","r")) == NULL &&
			    (trtxt=fopen("/usr/lib/bsc/trace.text","r"))== NULL)
			{	fprintf(stderr,
				"bsctrace: can't open trace text file\n");
				exit(1);	}

/* fill the trace text matrix (trmat) -- open trace.text file, which contains
   a list of state transitions and explanations for each one, e.g.
	1 0   Start
	8 9   Correct ACK
	.
	.
	.
   save the offset at which the explanation occurs in "whence". 
   trmat[from][to] becomes the value in whence. this saves much
   file manipulation later when the trace report is prepared. */
   
			whence = ftell(trtxt);
			while (fgets(line,sizeof line,trtxt) != NULL)	{
			/* "from" state is line[0] */
				from = atoi(lptr);
			/* "to" state is line[2] */
				lptr += 2;
				to = atoi(lptr);
				whence += 6L; /* offset in tracetext file where
					         description of state transition
						 [from][to] is kept */
				trmat[from][to] = whence;
				lptr = &line[0];
				whence = ftell(trtxt);
			}
			if (strcmp(argv[counter],"-data=hex") == 0) {
				data = HEX;
				continue;
			}
			if (strcmp(argv[counter],"-data=ebcdic") == 0) {
				data = EBCDIC;
				continue;
			}
			if (strcmp(argv[counter],"-data=ascii") == 0) {
				data = ASCII;
				continue;
			}
			if (strcmp(argv[counter],"-verbose") == 0)	{
				++verbose;
				continue;
			}
		}
		if (argv[counter][0] == '-' || counter != argc-1) {
			fprintf(stderr,"bsctrace: invalid parameter (%s)\n",
				 argv[counter]);
			exit(1);
		}


		trfd = open(argv[counter],0);	/* open the trace device */
		if (trfd < 0) {
			fprintf(stderr,
			 "bsctrace: can't read trace information file %s: %s\n",
				argv[counter],sys_errlist[errno]);
			exit(1);
		}
	}

	if (data || verbose)	{ /* set up trace report header */
		currtime = time((long*)0);
		t = localtime(&currtime);
		sprintf(header[2],"\t\t\t\t%02d/%02d/%02d\n",
		t->tm_mon+1,t->tm_mday,t->tm_year);
	}

	/* begin reading trace information */
	last_state = 0;
	counter = PAGELEN;	/* force headers to display first */

again:
	while ((len = left + read(trfd,&tracebuf[left],sizeof tracebuf - left)) > 0)

		for(trb = (struct bsctr *)tracebuf;
		    trb < (struct bsctr *) &tracebuf[len]; ) {
			if ((data || verbose) && counter >= PAGELEN)
				disp_header();

		    switch (trb->tr_type) {
		    case 'd':	/* decision */
		    case 'e':	/* error    */
		    case 'f':	/* function */
		    case 'r':	/* receive  */
		    case 's':	/* send     */

/* if ZEROTIME is defined in local.h, use time as is. Otherwise do localtime
   to get the actual time. */
			xtime = btol(&trb->tr_time);
#ifndef ZEROTIME
			t = localtime(&xtime);
#else
			t->tm_hour = (xtime/60)/60;
			t->tm_min = (xtime/60)%60;
			t->tm_sec = xtime%60;
#endif
			if (!verbose && !data)
				printf("%02d:%02d:%02d %2d %c\n",
					t->tm_hour,t->tm_min,t->tm_sec,
					trb->tr_state,trb->tr_type);
			else 	{
				if (last_type >= 'x')
					disp_data();

			        save_state = last_state;
				whence = trmat[last_state][trb->tr_state];
			        last_state = trb->tr_state;
				if (whence)	{
					fseek(trtxt,whence,0);
				      if (fgets(line,sizeof line, trtxt) == NULL) {
				      fprintf(stderr,
				      "bsctrace: last_state %d, whernce %d\n",
					save_state,whence);
				      fprintf(stderr,
				      "bsctrace: can't read trace text file\n");
				       exit(1);	}

					line[strlen(line)-1] = '\0';
				}
				else
					line[0] = '\0';

				printf("%02d:%02d:%02d | %2d\t| %c\t| ",
					t->tm_hour,t->tm_min,t->tm_sec,
					trb->tr_state,trb->tr_type);
				chr_count = strlen(line);
				if (chr_count < 50 || chr_count == 0) 
					printf("%s\n",line);
				else	{
					bcopy(first,line,50);
					lptr = &line[50];
					printf("%s\n",first);
					printf("\t |\t|\t| %s\n",lptr);
					if (++counter>=PAGELEN)
						disp_header();
				}
				++counter;
			}

			last_type = trb->tr_type;
			trb = (struct bsctr *)&trb->tr_val;
			left=chk_left(trb,len);
			break;

		    case 'c':	/* class */
			xtime = btol(&trb->tr_time);
#ifndef ZEROTIME
			t = localtime(&xtime);
#else
			t->tm_hour = (xtime/60)/60;
			t->tm_min = (xtime/60)%60;
			t->tm_sec = xtime%60;
#endif
			if (!verbose && !data)
				printf("%02d:%02d:%02d %2d %c\n",
					t->tm_hour,t->tm_min,t->tm_sec,
					trb->tr_state,trb->tr_type);
			else 	{
				if (last_type >= 'x')
					disp_data();

				printf("%02d:%02d:%02d | %2d\t| %c\t|",
					t->tm_hour,t->tm_min,t->tm_sec,
					trb->tr_state,trb->tr_type);
				if (trb->tr_state + 1 < MAX_C)
					printf(" %s\n",c_info[trb->tr_state+1]);
				else
					fputs("\n",stdout);
				++counter;
			}
			last_type = trb->tr_type;
			trb = (struct bsctr *)&trb->tr_val;
			left = chk_left (trb, len);
			break;
		
		    case 'o':	/* overruns */
			xtime = btol(&trb->tr_time);
#ifndef ZEROTIME
			t = localtime(&xtime);
#else
			t->tm_hour = (xtime/60)/60;
			t->tm_min = (xtime/60)%60;
			t->tm_sec = xtime%60;
#endif
			if (!verbose && !data)
				printf("%02d:%02d:%02d %2d %c\n",
				t->tm_hour,t->tm_min,t->tm_sec,
				trb->tr_state,trb->tr_type);
			else	{	
				if (last_type >= 'x')
					disp_data();

				printf ("%02d:%02d:%02d | %2d\t| %c\t| %s %d\n",
				t->tm_hour,t->tm_min,t->tm_sec,trb->tr_state,
				trb->tr_type,"Trace overruns:",trb->tr_state);

				++counter;
			}
			last_type = trb->tr_type;
			trb = (struct bsctr *)&trb->tr_val;
			left = chk_left (trb, len);
			break;

		   case 'y':
		   case 'x':	/* data being sent (x) or rcv'ed (y) */
			xtime = btol(&trb->tr_time);
#ifndef ZEROTIME
			t = localtime(&xtime);
#else
			t->tm_hour = (xtime/60)/60;
			t->tm_min = (xtime/60)%60;
			t->tm_sec = xtime%60;
#endif
			if (!data && !verbose)	{
				if (last_type != trb->tr_type)
					printf("%02d:%02d:%02d %2d %s\n",
					t->tm_hour,t->tm_min,t->tm_sec,
					trb->tr_state,
					(trb->tr_type == 'x')?"TD":"RD");
			}
			else 	{
				if (last_type>='x' && last_type!=trb->tr_type) 
					disp_data();
				if (last_type != trb->tr_type)	{
					printf("%02d:%02d:%02d | %2d\t| %s\t| ",
					t->tm_hour,t->tm_min,t->tm_sec,
					trb->tr_state,
					(trb->tr_type == 'x')?"TD":"RD");

					xy_ctr = 0;
					fptr = first;
					sptr = second;
				}

				if (data && trb->tr_val)	{
				pos = &trb->tr_data[0];

				while (pos != &trb->tr_data[trb->tr_val]){
					idx = *pos & 0xff;
					tptr=((idx< 0x80)?tbl1[idx]:tbl2[idx-0x80]);
						pos++;
					if (data == EBCDIC)	{
						*fptr++ = tptr[3];
						*sptr++ = tptr[4];
					}
					if (data == ASCII)	{	
						*fptr++ = tptr[6];
						*sptr++ = tptr[7];
					}
					if (data == HEX)	{
						*fptr++ = tptr[0];
						*sptr++ = tptr[1];
					}
					++xy_ctr;
					if (xy_ctr == 50)	{
						*fptr = *sptr = '\0';
						printf("%s\n",first);
						if (++counter>=PAGELEN)
							disp_header();
						printf("\t |\t|\t| %s\n",
						       second);
						xy_ctr = 0;
						fptr = first;
						sptr = second;
						if (++counter >= PAGELEN)
							disp_header();
					printf("\t |\t|\t| ");
					}
					continue;
				    }
				}
			}
			if (trb->tr_val & 1)	/* round to word */
				++trb->tr_val;
			last_type = trb->tr_type;
			trb = (struct bsctr *)&trb->tr_data[trb->tr_val];
			left = chk_left (trb, len);
			break;

		    default:
			printf("*** Unknown trace type: %c (0x%x) 0x%X 0x%x\n",
				trb->tr_type,trb->tr_type,trb->tr_time,
				trb->tr_state);
			goto again;
			/* abort() */
		}
		if (left) break;	/* need to read more */
	}
	close(trfd);
}

/* chk_left - check whether or not there are enough characters left in the
   trace buffer for a complete packet */
chk_left(trb,len)
register struct bsctr *trb;
register int len;
{
	register int left;

	left = &tracebuf[len] - (char *)trb;
	if (left < 6 || (trb->tr_type >= 'x' && left < 8) ||
	    (trb->tr_type >= 'x' && left < (8 + trb->tr_val))) {
		bcopy (tracebuf, (char *)trb, left);
		return(left);
	}
	else return(0);
}
/* disp_data - display x and/or y packet data */
disp_data()
{
	if (xy_ctr)	{
		*fptr = *sptr = '\0';
		puts(first);
		if (++counter >= PAGELEN)
			disp_header();
		printf("\t |\t|\t| %s\n",second);
		xy_ctr = 0;
		++counter;
	}
	else	{
		putchar('\n');
		++counter;
	}

	if (counter >= PAGELEN)
		disp_header();
}

/* disp_header - display verbose/data mode report header */
disp_header()
{
	for (counter = 0; counter < 6; ++counter)
		fputs(header[counter],stdout);
}

btol(bptr)
char *bptr;
{	register long lx;
	lx = (bptr[0] << 24) | (bptr[1] << 16) | (bptr[2] << 8) | (bptr[3]); 	
	return(lx);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.