home *** CD-ROM | disk | FTP | other *** search
- From: morgan@ms.uky.edu (Wes Morgan)
- Newsgroups: bit.listserv.infonets,bit.listserv.rexxlist,alt.sources
- Subject: Tools for determining BITNET paths (source code included)
- Message-ID: <1991Jun27.155006.29927@ms.uky.edu>
- Date: 27 Jun 1991 15:50:06 GMT
-
-
- Occasionally, I find that I need to know the path between
- two BITNET nodes. I developed the tools included below to per-
- form this task.
-
- Both the REXX and Unix versions of this program require the
- BITNET LINKS file, which is available from LISTSERV@BITNIC.
- I have tested these programs using the most recent copy of
- BITNET LINKS; if you've made any local changes to BITNET
- LINKS (or its format), you're on your own.
-
- I can't take full credit for the REXX version; it was sent
- to me (in a very rough form) several years ago. I merely
- cleaned up the code, added the descriptive output, and
- added comments. The Unix script, however, is all mine.
-
- The REXX routine was tested under CMS Rel 5. The Unix script
- was tested under AT&T System V Release 3.2.3. If you're run-
- ning another operating system, you may need to alter the code.
- I only request that you clearly mark your changes before passing
- the code to other users; I don't want to receive questions about
- code I didn't write! 8)
-
- Comments/questions/suggestions/flames can be directed to me at
- any of the email addresses at the end of this posting.
-
- Having said all that, here's the code:
-
- ------------------begin REXX code------------------------
- /************************************************/
- /* NODE EXEC - find and list path between nodes */
- /* */
- /* Syntax NODE node1 node2 */
- /* or NODE node2 <home node is default> */
- /* */
- /* Original Author : Unknown */
- /* Version 2 by: Wes Morgan */
- /* morgan@engr.uky.edu */
- /* */
- /* Summary of revisions */
- /* Date by Comments */
- /* ???? Unknown Original code. Several */
- /* versions on BITNET. */
- /* 8804 WM Cleaned up code. Added */
- /* comments. */
- /* 8805 WM Added code to display */
- /* description of sites */
- /* for those people who */
- /* don't know node names */
- /* by heart. */
- /* */
- /* Requires: BITNET LINKS file, available from */
- /* LISTSERV@BITNIC */
- /************************************************/
-
-
- /* General setup. The user's home node is extracted from IDENTIFY. */
- /* Two arguments are expected: a start node and a destination node. */
- /* If no start node is given, the default is the user's home node. */
- /* Failure to give any arguments results in a help message. */
-
- 'identify (stack'
- parse pull . . localnode .
- parse arg from to .
- upper from to
- if from = ''
- then do
- say 'Syntax : NODE fromnode tonode'
- say ' or : NODE tonode'
- exit 1
- end
- if to = ''
- then do
- to = from
- from = localnode
- end
-
- /* Finding the routing path between the two nodes. The file */
- /* BITNET LINKS is read completely onto the stack. After get- */
- /* ting past the file header, the information for each node */
- /* is placed in an array indexed by node name. For instance, */
- /* the array element bitnet.UKCC contains the value "UKCCB", */
- /* which is UKCC's connection to the net at large. This loop */
- /* continues as long as there are lines on the stack. */
- /* */
- /* The array description. contains the site description. */
-
- say 'Finding path from 'from' to 'to
- say
- 'execio * diskr bitnet links * (finis'
- beforestart = 1
- bitnet. = ''
- description. = ''
- do queued()
- parse pull 6 node ' ' 15 root ' ' 25 sitename 62 .
- if root = 'ROOT' then beforestart = 0
- if beforestart then iterate
- bitnet.node = root
- description.node = sitename
- end
-
- /* Finding the path from the start node to the destination node. */
- /* The first element of the uplist structure is the start node. */
- /* The home node's connection node, as stored in the array cre- */
- /* ated above, is added to the uplist structure. The array is */
- /* then scanned for the next connection. This process continues */
- /* until we get to the "ROOT" entry, which means we've gone as */
- /* far as we can. Notice that this approach will rarely find the */
- /* complete path. That's fine; we don't want the complete path */
- /* yet. We want the path back to ROOT, which is CUNYVM. After */
- /* we find the path to CUNYVM for the destination node, we will */
- /* simply find the two paths' common ground and go from there. */
-
- uppoint = 0 /* Initialize counter */
- uplist.0 = from /* First element of uplist is start node */
- updesc.0 = description.from
- do while uplist.uppoint ^= 'ROOT' /* As long as connections exist */
- lookup = uplist.uppoint /* Index by node name */
- updesc.uppoint = description.lookup /* Get the site description */
- uppoint = uppoint + 1 /* Increment counter */
- uplist.uppoint = bitnet.lookup /* Next node = connection of last */
- if uplist.uppoint = '' /* If null, exit */
- then do
- say 'No entry for 'lookup' found'
- exit 999
- end
- end
-
- /* Find path back from destination node to CUNYVM (root). */
- /* This is accomplished in the same manner as the uplist */
- /* created above. */
-
- dnpoint = 0
- dnlist.0 = to
- dndesc.dnpoint = description.to
- do while dnlist.dnpoint ^= 'ROOT'
- lookup = dnlist.dnpoint
- dndesc.dnpoint = description.lookup
- dnpoint = dnpoint + 1
- dnlist.dnpoint = bitnet.lookup
- if dnlist.dnpoint = ''
- then do
- say 'No entry for 'lookup' found'
- exit 999
- end
- end
-
- /* Find the common ground between the two lists. Basically, */
- /* we are finding the halfway point, i.e. that point at which */
- /* the uplist and downlist merge. As the uplist is printed, */
- /* the downlist is scanned for a match. Once a match is found */
- /* in the downlist, the uplist is dropped, and the downlist */
- /* "takes up where we left off", working back to our goal. */
-
- count = 0 /* Initialize node count */
- do loop = 0 to uppoint /* Do as long as elements remain in uplist */
- prnt = justify(uplist.loop,12) /* Justify for nice printing */
- say prnt updesc.loop /* Output the information */
- count = count + 1 /* Increment node count */
- do search = 0 to dnpoint /* Search all elements of dnlist */
- match = 0 /* Set match flag low */
- if uplist.loop = dnlist.search /* If we find a match, */
- then do
- match = 1 /* set the flag high, */
- dnpoint = search -1 /* set startpoint for dnlist, */
- leave search /* and get out of here */
- end
- end
- if match then leave loop /* If match flag high, quit */
- end
- do loop = dnpoint to 0 by -1 /* Working back from match point, */
- prnt = justify(dnlist.loop,12) /* Justify for nice output */
- say prnt dndesc.loop /* Output site and description */
- count = count + 1 /* and increment node count */
- end
- say
- say count - 1' nodes away' /* Print node count */
- exit count -1 /* Returned value is node count */
- return /* That's all, folks! */
- --------------End REXX code----------------
-
- And now, the Unix shell script:
-
- --------------Begin Unix shell script-----------------
- #!/bin/sh
- #
- # bitpath - Determine path between two BITNET nodes
- #
- # Written by Wes Morgan, morgan@engr.uky.edu, 27 Jun 91
- #
- # This shell script requires the BITNET LINKS file, which is available
- # from LISTSERV@BITNIC (aka listserv@bitnic.bitnet).
- #
- # Syntax: bitpath [-f] [site1] site2
- # If -f is specified, a "full" listing is output, containing each
- # site's description and ISO country code.
- # If "site1" is specified, it will be used as the origin for the
- # search. If omitted, the site named in DEFAULT, below,
- # will be used as the origin.
- # "site2" is the destination node for the search.
- #
- # This shell script has been tested under AT&T System V Release 3.2.3
- #
- # Known problems:
- # Some entries contain descriptions which "run into" the ISO
- # country code. If this happens, you will see an extra field
- # (the "software" field) displayed for that site.
- #
-
- # LINKFILE should be set to the name of your copy of BITNET LINKS.
- LINKFILE=bitlinks
-
- # DEFAULT should be set to the default origin node for searches.
- # This nodename MUST be in CAPTIAL LETTERS!!
- # I use UKCC, which is the University of Kentucky Computing Center.
- DEFAULT=UKCC
-
- #
- # Parse the command line.
- #
- errflag=0
- full=0
- if [ -z "$1" ]
- then
- errflag=1
- fi
- if [ "$1" = "-f" -o "$1" = "-F" ]
- then
- full=1
- shift
- fi
- if [ -z "$1" ]
- then
- errflag=1
- else
- if [ -z "$2" ]
- then
- upnode=$DEFAULT
- uplist=$DEFAULT
- dnnode=`echo $1 | tr "[a-z]" "[A-Z]"`
- dnlist=$dnnode
- else
- upnode=`echo $1 | tr "[a-z]" "[A-Z]"`
- uplist=$upnode
- dnnode=`echo $2 | tr "[a-z]" "[A-Z]"`
- dnlist=$dnnode
- fi
- fi
-
- if [ $errflag -eq 1 ]
- then
- echo Syntax: bitpath [-f] [site1] site2
- exit 1
- fi
- echo
-
- #
- # BITNET is a tree-based network, originating from the City University
- # of New York (CUNYVM). Therefore, our initial task is to determine the
- # path from the origin node back to the "root" at CUNYVM.
- #
- # The format of BITNET LINKS is as follows:
- # 0693 UKCC UGA U Kentucky Comp Ctr ,US RSCS 91/03/31
- #
- # From right to left, the fields are:
- # - BITNET node number (unused in this script)
- # - Site name
- # - The next site up the network tree
- # - Description of the site
- # - ISO country code
- # - Network software used for BITNET (unused in this script)
- # - Last update of this site's entry (unused in this script)
- #
- # At this stage, we are only interested in the second and third fields.
- # We will construct a list of sites from the origin to CUNYVM. Since
- # CUNYVM is the root of the BITNET tree, it's "next site" entry is "ROOT";
- # we use that entry to end the search loop.
-
- updone=0
- while [ $updone -eq 0 ]
- do
- line=`grep $upnode $LINKFILE | awk '$2 ~ /^'"$upnode"'$/'`
- if [ -z "$line" ]
- then
- echo "No entry for $upnode found."
- exit 1
- fi
- next=`echo $line | awk '{ print $3 }'`
- if [ "$next" = "ROOT" ]
- then
- updone=1
- else
- upnode=$next
- uplist=`echo $uplist $next`
- fi
- done
-
- #
- # Construct a path from the destination node to CUNYVM (the root).
- # The algorithm is identical; the only change is that we construct
- # the list in reverse order.
- #
-
- dndone=0
- while [ $dndone -eq 0 ]
- do
- line=`grep $dnnode $LINKFILE | awk '$2 ~ /^'"$dnnode"'$/'`
- if [ -z "$line" ]
- then
- echo "No entry for $dnnode found."
- exit 1
- fi
- next=`echo $line | awk '{ print $3 }'`
- if [ "$next" = "ROOT" ]
- then
- dndone=1
- else
- dnnode=$next
- dnlist=`echo $next $dnlist`
- fi
- done
-
- #
- # Now that we have our two paths, we need to find the "common ground"
- # between them. We move through the list from left to right. At each
- # step, we scan ahead, looking for a duplicate entry. If we find one,
- # that site is the "common ground"; we skip over to the duplicate and
- # finish the path from that point.
- #
- # For instance, the path from UKCC (Kentucky) through CUNYVM (the root) to
- # SUVM (Syracuse) is generated as:
- # UKCC UGA CUNYVMV2 CUNYVM CUNYVM CUNYVMV2 CORNELLC SUVM
- # We don't need the redundant "CUNVMV2 CUNYVM CUNYVM CUNYVMV2" portion of
- # this path, because actual network traffic will not reach CUNYVM; it will
- # be routed from CUMYVMV2 to CORNELLC. Therefore, in this example, CUNYVMV2
- # is the "common ground" for which this section of code searches.
- #
-
- cleanlist=`echo "$uplist $dnlist" | awk ' { for(x=1;x<=NF;x++) {
- print $x;
- for(y=x+1;y<=NF;y++) {
- if($y == $x) {
- x = y;
- break;
- }
- }
- }
- }'`
-
- #
- # Output results. If the -f option is used, the listing includes
- # site description and country code; if not, only the node names
- # are printed, separated with "->".
- #
- if [ $full -eq 1 ]
- then
- echo $cleanlist |
- awk '{ for(x=1;x<=NF;x++) printf("%s\n",$x); }' |
- while read target
- do
- line=`grep $target $LINKFILE | awk '$2 ~ /^'"$target"'$/'`
- descrip=`echo $line | awk '{ for(x=4;x<NF;x++) {
- printf("%s ",$x);
- if (index($x,",") == 1) x=NF;
- }
- }
- END { printf("\n"); }'`
- justify=`echo $target | awk '{ printf("%-8s",$1); }'`
- echo "$justify\t$descrip"
- done
- echo
- else
- echo $cleanlist | sed "s/ /->/g"
- fi
- exit 0
- ------------------end Unix shell script----------------------
-
- --
- morgan@ms.uky.edu |Wes Morgan, not speaking for| ....!ukma!ukecc!morgan
- morgan@engr.uky.edu |the University of Kentucky's| morgan%engr.uky.edu@UKCC
- morgan@ie.pa.uky.edu |Engineering Computing Center| morgan@wuarchive.wustl.edu
-