|
|
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);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.