home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume06 / pathrpt < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  24.1 KB

  1. From decwrl!ucbvax!tut.cis.ohio-state.edu!mailrus!ames!lll-winken!uunet!allbery Sun Apr 23 15:40:52 PDT 1989
  2. Article 862 of comp.sources.misc:
  3. Path: decwrl!ucbvax!tut.cis.ohio-state.edu!mailrus!ames!lll-winken!uunet!allbery
  4. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5. Newsgroups: comp.sources.misc
  6. Subject: v06i093: pathrpt -- a reporting tool companion for pathalias
  7. Message-ID: <53144@uunet.UU.NET>
  8. Date: 23 Apr 89 19:31:48 GMT
  9. Sender: allbery@uunet.UU.NET
  10. Reply-To: david@dhw68k.cts.com (David H. Wolfskill)
  11. Lines: 665
  12. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  13.  
  14. Posting-number: Volume 6, Issue 93
  15. Submitted-by: david@dhw68k.cts.com (David H. Wolfskill)
  16. Archive-name: pathrpt
  17.  
  18. I asked the folks in comp.mail.uucp if they would find a program such as
  19. this useful or helpful; the overwhelming response was "Yes!" (along with
  20. requests to mail copies).  Anyway, I think comp.sources.misc would be a
  21. better place for it than comp.sources.unix, mostly because it's not
  22. terribly sophisticated -- it's really just a little filter to accompany
  23. pathalias.
  24.  
  25. I've been using it for several months (in one form or another), and
  26. I've sent copies off to some folks.  The only reported problems I've
  27. heard with its use came from a VMS site, and I didn't understand what
  28. the problems were....
  29.  
  30. What this thing is:  pathrpt makes a report based on the output of
  31. pathalias.  The report indicates how many of the paths (from the
  32. pathalias output) start at each of your uucp neighbors.  It also gives
  33. some clue as to the lengths of those paths -- and it checks to see if
  34. the uucp maps indicate you have a neighbor you don't think you have.
  35.  
  36. The above report(s) come out on stderr, so make it easier to use the
  37. program for its other purpose in life -- taking the place of the "sed"
  38. step in the pathproc distributed with smail.  (The smail-format
  39. pathalias output comes out on stdout.)
  40.  
  41. Folks who don't run pathalias probably have no use for this program.
  42.  
  43. Thanks,
  44. david  (Wed Apr 19 07:02:55 PDT 1989)
  45.  
  46. #! /bin/sh
  47. # This is a shell archive, meaning:
  48. # 1. Remove everything above the #! /bin/sh line.
  49. # 2. Save the resulting text in a file.
  50. # 3. Execute the file with /bin/sh (not csh) to create the files:
  51. #    pathrpt.c
  52. # This archive created: Wed Apr 19 06:47:00 1989
  53. export PATH; PATH=/bin:$PATH
  54. echo shar: extracting "'pathrpt.c'" '(20748 characters)'
  55. if test -f 'pathrpt.c'
  56. then
  57.     echo shar: will not over-write existing file "'pathrpt.c'"
  58. else
  59. sed 's/^    X//' << \SHAR_EOF > 'pathrpt.c'
  60.     X/*
  61.     X *
  62.     X * This program is Copyright 1989, by David H. Wolfskill.
  63.     X *
  64.     X * Anyone may freely copy it and use it for any purpose, as long as:
  65.     X * 1) it is not sold, and
  66.     X * 2) no one else attempts to claim authorship of the program.
  67.     X * (In all humility and honesty, I can't imagine why anyone would want to do
  68.     X * either of the above, but human nature is a truly marvelous thing....)
  69.     X *
  70.     X * [First part of above is freely adapted from "rn," by Larry Wall.... dhw]
  71.     X *
  72.     X * Disclaimer: Although the author finds the program useful, there is no
  73.     X *             guarantee that anyone else will find it useful for any given
  74.     X *             purpose.  Caveat Emptor, and all that.
  75.     X *             
  76.     X * I cannot, of course, promise to fix things that some folks may think are
  77.     X * broken; nor can I promise to implement enhancements.  However, I have a
  78.     X * strong desire to do what I can to help improve email, especially over dialup
  79.     X * 'phone lines; accordingly, it is my present intent to support this program
  80.     X * as a tool that can be helpful in some circumstances... as long as what it
  81.     X * reports isn't trusted too much....  :-)
  82.     X *
  83.     X * In all seriousness, comments & suggestions may be sent to me via
  84.     X *
  85.     X * InterNet: david@dhw68k.cts.com
  86.     X * uucp: ...{spsd,zardoz,felix}!dhw68k!david    
  87.     X *
  88.     X * and -- unless you have been explicitly informed otherwise by someone
  89.     X * in a position to know (such as me) -- I welcome suggestions for improvement.
  90.     X *
  91.     X * David H. Wolfskill    16 April, 1989
  92.     X *
  93.     X */
  94.     X
  95.     X/*
  96.     X *    Program to list statistics, some of which may be of interest,
  97.     X *    regarding the output of "pathalias," as well as do a basic
  98.     X *    "reality check" on that output.
  99.     X
  100.     X *    By its nature, this program is intended to be used in conjunction
  101.     X *    with pathalias.  I really don't think you should spend any time
  102.     X *    or other resources on this program if you neither run nor have
  103.     X *    any intent to run pathalias.
  104.     X
  105.     X *    This version can read the pathalias output either in the
  106.     X *    original order, or either of the 2 rotations:
  107.     X
  108.     X *    "pathalias":    <cost>    <destination>    <path>
  109.     X *    "smail":    <destination>    <path>    <cost>
  110.     X *    unknown:    <path>    <cost>    <destination>
  111.     X
  112.     X *    It does *not* (presently) handle "<destination>    <cost>    <path>"
  113.     X *    (or any of its rotations); if you really think it's something
  114.     X *    worth doing, I'm willing to discuss it further, but really...!
  115.     X
  116.     X *    In order to make the determination of the stdin format, the
  117.     X *    first line is read, and its 3 fields are scanned to find one
  118.     X *    that ends in "%s".  If no such field is found, the program
  119.     X *    claims that the input is not pathalias output, and exits.  If
  120.     X *    one *is* found, however (the normal case, we hope!), that field
  121.     X *    is assumed to be the <path> field; the next field (to the right,
  122.     X *    wrapping around if necessary) is the <cost>, and the next is
  123.     X *    <destination>.
  124.     X
  125.     X *    smail likes the second order, so the stdout of this program
  126.     X *    is the same information in "smail" order (regardless of the
  127.     X *    order in which stdin is).  This program may thus be used in
  128.     X *    place of the "sed" segment of the "pathproc" pipeline that is
  129.     X *    distributed with smail.
  130.     X
  131.     X *    To facilitate its use in that application, the report the
  132.     X *    program generates comes out on stderr.
  133.     X
  134.     X *    The overall method is straightforward, brute-force:  uuname (or
  135.     X *    whatever -- see macro NBRLIST) is used to generate a list of
  136.     X *    known immediate uucp neighbors; that is run through sort.  (I
  137.     X *    do it this way because uuname is set[gu]id; I think it
  138.     X *    appropriate to minimize the need for programs to run as
  139.     X *    set[gu]id, so I use the facilities provided by a common tool,
  140.     X *    rather than require special privileges for this program.)  Then
  141.     X *    a "neighbor" (spelled "nbr" for typing constraint relief)
  142.     X *    struct is allocated for each neighbor thus found -- after one
  143.     X *    of these structs is allocated for the totals.  The nbr structs
  144.     X *    are allocated as a linked list.  (A temporary file is created
  145.     X *    to hold the output of sort; after the nbr structs are all
  146.     X *    allocated, it is unlinked and closed.)
  147.     X
  148.     X *    Once this housekeeping is finished, a single pass through stdin
  149.     X *    (which is expected to be in the above-documented -- possibly
  150.     X *    rotated -- pathalias output format) is made, updating the
  151.     X *    appropriate counters in the various nbr structs:  the "tots"
  152.     X *    nbr struct is always updated; the "first hop" in the path is
  153.     X *    determined, and the nbr struct that corresponds to it is also
  154.     X *    updated.
  155.     X
  156.     X *    A <path> field that consists entirely of "%s" is assumed to
  157.     X *    have a "first hop" of the local host.  The program will
  158.     X *    determine this by using the -l flag (ala' pathalias); if -l was
  159.     X *    not specified, routine hostname() is invoked, which either uses
  160.     X *    uname() (if UNAME is defined during compilation) or
  161.     X *    gethostname() (if it wasn't).  If hostname() is invoked and
  162.     X *    fails, the program complains bitterly and exits -- in such a
  163.     X *    case, you may wish to change the logic in hostname() or specify
  164.     X *    the -l flag, depending on how ambitious you are.
  165.     X
  166.     X *    For a <path> field that is more than "%s", everything from the
  167.     X *    beginning of the field up to (but not including) the first
  168.     X *    occurrence of '!' is assumed to be the name of the "first hop"
  169.     X *    -- which ought to be the name of one of the specified host's
  170.     X *    neighbors.
  171.     X
  172.     X *    (Note the pathological case of the pathalias output claiming
  173.     X *    the existence of a neighbor that NBRLIST doesn't know about.
  174.     X *    That actually happened in the early testing of the program, and
  175.     X *    as a result of that experience, I put in code to create a "nbr"
  176.     X *    struct on demand (as it were) in such a case, then in the
  177.     X *    output phase, spit out a warning message.)
  178.     X
  179.     X *    Once EOF is reached on stdin, a pair of traversals through the
  180.     X *    linked list is made; each prints a report based on the
  181.     X *    accumulated totals, and the second one also frees the elements
  182.     X *    of the list.  The second report shows a distribution of how
  183.     X *    long the paths are; its width -- how far out to count distinct
  184.     X *    pathlengths -- is controlled by the MAXDIST macro and the -d
  185.     X *    flag.
  186.     X
  187.     X *    Then we're done -- what could be simpler...?  :-)
  188.     X
  189.     X
  190.     X
  191.     X *    Notes about the flags:
  192.     X
  193.     X *    Since the program was first written, the number of flags
  194.     X *    ("command line arguments" for picky folk) has become large;
  195.     X *    herewith is a list of them:
  196.     X
  197.     X *    -B <limit>      <limit> specifies an OUTPUT limit: if the
  198.     X *            cost to reach a destination is below the
  199.     X *            specified limit, the stdout will not contain
  200.     X *            that line of input data.  To make this flag
  201.     X *            ineffective, use a value of 0.  Default is
  202.     X *            BOTOUT (0).
  203.     X
  204.     X *    -T <limit>      <limit> specifies an OUTPUT limit: if the
  205.     X *            cost to reach a destination is above the
  206.     X *            specified limit, the stdout will not contain
  207.     X *            that line of input data.  To make this flag
  208.     X *            ineffective, use a value of 0.  Default is
  209.     X *            TOPOUT (0).
  210.     X
  211.     X *    -b <limit>    <limit> specifies a REPORTING limit: if the
  212.     X *            cost to reach a destination is below the
  213.     X *            specified limit, the reports (on stderr) will
  214.     X *            not reflect that line of input data.  To make
  215.     X *            this flag ineffective, use a value of 0.
  216.     X *            Default is BOTCNT (0).
  217.     X
  218.     X *    -t <limit>    <limit> specifies a REPORTING limit: if the
  219.     X *            cost to reach a destination is above the
  220.     X *            specified limit, the reports (on stderr) will
  221.     X *            not reflect that line of input data.  To make
  222.     X *            this flag ineffective, use a value of 0.
  223.     X *            Default is TOPCNT (0).
  224.     X
  225.     X *    -d <dist>    <dist> specifies the number of "distribution
  226.     X *            buckets" for the 2nd report -- the one that
  227.     X *            (sort of) shows a "histogram" of the hopcounts
  228.     X *            of the paths to each of the neighboring sites.
  229.     X *            The default value is DDIST (20).
  230.     X
  231.     X *    -l <host>    <host> specifies a local hostname other than
  232.     X *            the default; it is intended to be similar in
  233.     X *            operation to the pathalias flag of similar name
  234.     X *            and intent.
  235.     X
  236.     X *    -z         specifies that the reports are not to include
  237.     X *            lines for neighboring sites that are not "first
  238.     X *            hops" in the stdin.
  239.     X
  240.     X *    Note that each of the flags is completely independent of any
  241.     X *    other flag -- and that some combinations are (arguably) useful,
  242.     X *    while some are misleading or dangerous.
  243.     X
  244.     X *    In the normal course of the use of the program, it is expected
  245.     X *    that it will be executed in a shell script, so once the flags
  246.     X *    have been figured out, this should be substantially less of a
  247.     X *    burden than typing all that stuff....  Of course, the defaults
  248.     X *    for each of the -b, -t, -B, -T, and -d flags can be compiled
  249.     X *    in, too....
  250.     X
  251.     X */
  252.     X
  253.     X
  254.     X
  255.     X#include <stdio.h>
  256.     X#include <string.h>
  257.     X
  258.     X#ifndef    MAXLINE
  259.     X#define    MAXLINE    256    /* Assumed maximum field length from input */
  260.     X#endif    MAXLINE
  261.     X
  262.     X#ifndef    ERRLEN
  263.     X#define    ERRLEN    256    /* Assumed maximum line length for error message */
  264.     X#endif    ERRLEN
  265.     X
  266.     X#ifndef    HOSTLEN
  267.     X#define    HOSTLEN    128    /* Assumed maximum length for host name */
  268.     X#endif    HOSTLEN
  269.     X
  270.     X#ifndef    SYSLEN
  271.     X#define    SYSLEN    80    /* Assumed maximum length for "system (2)" call */
  272.     X#endif    SYSLEN
  273.     X
  274.     X#ifndef    NBRLIST
  275.     X#ifdef    UNAME
  276.     X#define    NBRLIST    "(uuname -l;uuname) | sort"    /* Command for list of hosts */
  277.     X#else    /*  !UNAME  */
  278.     X#define    NBRLIST    "(hostname;uuname) | sort"    /* Command for list of hosts */
  279.     X#endif    /* UNAME */
  280.     X#endif    NBRLIST
  281.     X
  282.     X#ifndef    MAXDIST
  283.     X#define    MAXDIST    20    /* max # "buckets" for pathlength distribution chart */
  284.     X#endif    MAXDIST
  285.     X
  286.     X#ifndef    DDIST
  287.     X#define    DDIST    MAXDIST    /* default # "buckets" for pathlength distribution chart */
  288.     X#endif    DDIST
  289.     X
  290.     X#ifndef    STRCHR
  291.     X#define    STRCHR    strchr    /* strchr() or index() function */
  292.     X#endif    STRCHR
  293.     X
  294.     X#ifndef    DEAD
  295.     X#define    DEAD    30000000    /* Intended to match the pathalias value */
  296.     X#endif    DEAD
  297.     X
  298.     X#ifndef    TOPOUT
  299.     X#define    TOPOUT    0    /* "0" == don't supress any output; !0 == threshhold */
  300.     X#endif    TOPOUT
  301.     X
  302.     X#ifndef    BOTOUT
  303.     X#define    BOTOUT    0    /* "0" == don't supress any output; !0 == threshhold */
  304.     X#endif    BOTOUT
  305.     X
  306.     X#ifndef    TOPCNT
  307.     X#define    TOPCNT    0    /* "0" == don't supress any output; !0 == threshhold */
  308.     X#endif    TOPCNT
  309.     X
  310.     X#ifndef    BOTCNT
  311.     X#define    BOTCNT    0    /* "0" == don't supress any output; !0 == threshhold */
  312.     X#endif    BOTCNT
  313.     X
  314.     Xstruct nbr {        /* struct for "neighbor" host                 */
  315.     X    struct nbr *next;    /* pointer to next neighbor on the list       */
  316.     X    char    *host;        /* name of neighboring host                   */
  317.     X    int    firsthop;    /* count of times this appears as "1st hop"   */
  318.     X    int    hopcount;    /* sum of path lengths that start here        */
  319.     X    int    pthlng[MAXDIST];    /* buckets for pathlength dist.       */
  320.     X    double    cost;        /* sum of COSTS for paths that start here     */
  321.     X};
  322.     X
  323.     Xint    main(argc, argv)  /* find interesting statistics about a "paths" file */
  324.     Xint    argc;
  325.     Xchar    *argv[];
  326.     X
  327.     X{
  328.     X    struct nbr *tots;    /* "pseudo-neighbor" for totals               */
  329.     X    struct nbr *tnbr;    /* temporary pointer to a "nbr" struct        */
  330.     X    struct nbr *lnbr;    /* pointer to last-allocated "nbr" struct     */
  331.     X    struct nbr *bnbr;    /* pointer to first "bad" "nbr" struct        */
  332.     X    struct nbr *getnbr();    /* routine to create a new nbr struct */
  333.     X
  334.     X    extern int    errno;        /* used by perror() and friends       */
  335.     X    extern int    optind;        /* for getopt()                  */
  336.     X    extern char    *optarg;    /* for getopt()                  */
  337.     X
  338.     X    char    *tempnam();    /* function to generate name of work file     */
  339.     X    char    *tmpf;        /* points to pathname of temporary file       */
  340.     X    FILE    * tf;        /* FILE pointer for temporary file            */
  341.     X
  342.     X    char    sys[SYSLEN];    /* command line used to get list of neighbors */
  343.     X
  344.     X    char    *hostname();    /* function to go find out where I am         */
  345.     X    char    site[HOSTLEN];    /* char array to hold name of site            */
  346.     X
  347.     X    char    str[3][MAXLINE];/* input strings for pathalias output         */
  348.     X    int    field;        /* index for str[][] array                    */
  349.     X    int    strl;        /* length of str[][] array                    */
  350.     X    char    *dest;        /* used for both "destination" and "1st hop"  */
  351.     X    char    *path;        /* string for uucp "path" to get to dest      */
  352.     X    char    *scost;        /* pointer to cost data in string form        */
  353.     X    double    cost;        /* pathalias "COST" to get to a given dest    */
  354.     X
  355.     X    int    top_out;    /* controls high end of output suppression    */
  356.     X    int    bot_out;    /* controls low end of output suppression     */
  357.     X    int    top_cnt;    /* controls high end of counting              */
  358.     X    int    bot_cnt;    /* controls low end of counting               */
  359.     X    int    zflag;        /* controls reporting neighbors w/ 0 paths    */
  360.     X
  361.     X    int    error;        /* "error" flag returned by program           */
  362.     X    int    hops;        /* number of "hops" to get to given dest      */
  363.     X    int    dist;        /* number of "buckets" for pathlength distr.  */
  364.     X    int    ch;        /* garden-variety character/EOF-holder        */
  365.     X    char    *name;        /* name of program -- as invoked, for msgs    */
  366.     X    char    errmsg[ERRLEN];    /* string for constructing error messages     */
  367.     X    char    *chptr;        /* garden-variety pointer-to-char work var    */
  368.     X
  369.     X    name = argv[0];
  370.     X    error = 0;
  371.     X    dist = DDIST;
  372.     X    bnbr = NULL;
  373.     X    site[0] = 0;
  374.     X    top_out = TOPOUT;
  375.     X    bot_out = BOTOUT;
  376.     X    top_cnt = TOPCNT;
  377.     X    bot_cnt = BOTCNT;
  378.     X    zflag = 1;
  379.     X
  380.     X    while ((ch = getopt(argc, argv, "b:B:d:l:t:T:z")) != EOF)
  381.     X        switch (ch) {
  382.     X        case 'B':
  383.     X            (void)sscanf(optarg, "%d", &bot_out);
  384.     X            break;
  385.     X        case 'b':
  386.     X            (void)sscanf(optarg, "%d", &bot_cnt);
  387.     X            break;
  388.     X        case 'd':
  389.     X            (void)sscanf(optarg, "%d", &dist);
  390.     X            break;
  391.     X        case 'l':
  392.     X            if (strlen(optarg) < HOSTLEN) 
  393.     X                (void)strcpy(site, optarg);
  394.     X            else     {
  395.     X                (void)strncpy(site, optarg, HOSTLEN - 1);
  396.     X                site[HOSTLEN-1] = 0;
  397.     X            }
  398.     X            break;
  399.     X        case 'T':
  400.     X            (void)sscanf(optarg, "%d", &top_out);
  401.     X            break;
  402.     X        case 't':
  403.     X            (void)sscanf(optarg, "%d", &top_cnt);
  404.     X            break;
  405.     X        case 'z':
  406.     X            zflag = 0;
  407.     X            break;
  408.     X        default:
  409.     X            (void)fprintf(stderr, "usage: %s -d dist -l host -b limit -B limit -t limit -T limit -z\n", name);
  410.     X            exit(error = 1);
  411.     X        }
  412.     X
  413.     X    if ((site[0] == 0) && (hostname(site) == NULL)) {
  414.     X        (void)sprintf(errmsg, "%s: hostname() failed", name);
  415.     X        (void)perror(errmsg);
  416.     X        exit(error = errno);
  417.     X    }
  418.     X
  419.     X    dist = dist > MAXDIST ? MAXDIST : dist;
  420.     X
  421.     X    if ((tots = tnbr = getnbr("TOTALS")) == NULL) {
  422.     X        (void)sprintf(errmsg, "%s: getnbr(\"TOTALS\") failed", name);
  423.     X        (void)perror(errmsg);
  424.     X        exit(error = errno);
  425.     X    }
  426.     X
  427.     X    tmpf = tempnam((char *)NULL, (char *)NULL);
  428.     X    (void)sprintf(sys, "%s >%s", NBRLIST, tmpf);
  429.     X    (void)system(sys);
  430.     X
  431.     X    if ((tf = fopen(tmpf, "r")) == NULL) {
  432.     X        (void)sprintf(errmsg, "%s: fopen(%s, \"r\") failed", name, tmpf);
  433.     X        (void)perror(errmsg);
  434.     X        exit(error = errno);
  435.     X    }
  436.     X
  437.     X    while (fscanf(tf, "%s", str[0]) != EOF) {
  438.     X        if ((tnbr->next = getnbr(str[0])) == NULL) {
  439.     X            (void)sprintf(errmsg, "%s: getnbr(%s) failed", name, str[0]);
  440.     X            (void)perror(errmsg);
  441.     X            exit(error = errno);
  442.     X        }
  443.     X        tnbr = tnbr->next;
  444.     X    }
  445.     X
  446.     X    if (unlink(tmpf) != 0) {
  447.     X        (void)sprintf(errmsg, "%s: unlink(%s) failed", name, tmpf);
  448.     X        (void)perror(errmsg);
  449.     X        exit(error = errno);
  450.     X    }
  451.     X
  452.     X    if (fclose(tf) == EOF) {
  453.     X        (void)sprintf(errmsg, "%s: fclose(tf) failed", name);
  454.     X        (void)perror(errmsg);
  455.     X        exit(error = errno);
  456.     X    }
  457.     X
  458.     X    if (scanf("%s%s%s", &str[0][0], &str[1][0], &str[2][0]) != EOF) {
  459.     X        for (field = 0; field < 3; field++) {
  460.     X            if ((strl = strlen(str[field])) > 1) {
  461.     X                if (strcmp(&str[field][strl-2], "%s") == 0)
  462.     X                    break;
  463.     X            }
  464.     X        }
  465.     X        if (field > 2) {
  466.     X            (void)fprintf(stderr, "%s: input is not pathalias format\n", name);
  467.     X            exit(error = field);
  468.     X        }
  469.     X        path = &str[field++][0];
  470.     X        scost = &str[(field++)%3][0];
  471.     X        dest = &str[(field++)%3][0];
  472.     X
  473.     X        do {
  474.     X            (void)sscanf(scost, "%lg", &cost);
  475.     X            if ((bot_out <= cost) && ((top_out == 0) || (top_out >= cost)))
  476.     X                (void)printf("%s\t%s\t%s\n", dest, path, scost);
  477.     X            if ((bot_cnt <= cost) && ((top_cnt == 0) || (top_cnt >= cost))) {
  478.     X                tots->firsthop++;
  479.     X                tots->cost += cost;
  480.     X                chptr = path;
  481.     X                hops = strcspn(path, "!");
  482.     X                (void)strncpy(dest, path, hops);    /* save name of "first hop" */
  483.     X                *(dest + hops) = 0;        /* ensure proper null term. */
  484.     X
  485.     X                hops = 0;
  486.     X                while ((chptr = STRCHR(chptr, '!')) != NULL) {
  487.     X                    chptr++;
  488.     X                    hops++;
  489.     X                }
  490.     X
  491.     X                tots->hopcount += hops;
  492.     X                tots->pthlng[hops<dist?hops:dist-1]++;
  493.     X                if (hops == 0 && strcmp(dest, "%s") == 0) 
  494.     X                    (void)strcpy(dest, site);
  495.     X
  496.     X                if (tnbr->next == NULL) 
  497.     X                    tnbr = tots;
  498.     X                if ((strcmp(dest, tnbr->next->host)) != 0) {
  499.     X                    tnbr = tots;
  500.     X                    while ((tnbr->next != NULL) && (strcmp(dest, tnbr->next->host)) != 0)
  501.     X                        tnbr = tnbr->next;
  502.     X                }
  503.     X
  504.     X                if (tnbr->next == NULL) {
  505.     X                    if ((lnbr = getnbr(dest)) == NULL) {
  506.     X                        (void)sprintf(errmsg, "%s: getnbr(%s) failed", name, dest);
  507.     X                        (void)perror(errmsg);
  508.     X                        exit(error = errno);
  509.     X                    }
  510.     X                    tnbr->next = lnbr;
  511.     X                    if (bnbr == NULL) 
  512.     X                        bnbr = lnbr;
  513.     X                }
  514.     X
  515.     X                tnbr->next->firsthop++;
  516.     X                tnbr->next->cost += cost;
  517.     X                tnbr->next->hopcount += hops;
  518.     X                tnbr->next->pthlng[hops<dist?hops:dist-1]++;
  519.     X            }
  520.     X
  521.     X        } while (scanf("%s%s%s", &str[0][0], &str[1][0], &str[2][0]) != EOF);
  522.     X    }
  523.     X
  524.     X    (void)fprintf(stderr, "\n Adj              Total         Total   #Hops        Cost");
  525.     X    (void)fprintf(stderr, "\nSite       #Dest  #Hops          Cost   /Dest       /Dest\n");
  526.     X
  527.     X    lnbr = tots;
  528.     X    while (tots != NULL) {
  529.     X        if (bnbr == tots)
  530.     X            (void)fprintf(stderr, "\n *** WARNING! Bogus \"neighbor\" sites follow! ***\n");
  531.     X        if (zflag | tots->firsthop)
  532.     X            (void)fprintf(stderr, "%-9s% 7d% 7d% 14.0f% 8.2f% 12.2f\n", tots->host,
  533.     X                tots->firsthop, tots->hopcount, tots->cost,
  534.     X                tots->firsthop ? (double)tots->hopcount / tots->firsthop : (double)0,
  535.     X                tots->firsthop ? (double)tots->cost / tots->firsthop : (double)0);
  536.     X        tots = tots->next;
  537.     X    }
  538.     X
  539.     X    tots = lnbr;
  540.     X    (void)fprintf(stderr, "\n Adj               #Hops       --- Pathlength Distribution ---");
  541.     X    (void)fprintf(stderr, "\nSite       #Dest   /Dest");
  542.     X    for (hops = 0; hops < dist; hops++) 
  543.     X        (void)fprintf(stderr, "% 5d", hops);
  544.     X    (void)fprintf(stderr, "+\n");
  545.     X
  546.     X    while (tots != NULL) {
  547.     X        if (bnbr == tots)
  548.     X            (void)fprintf(stderr, "\n *** WARNING! Bogus \"neighbor\" sites follow! ***\n");
  549.     X        if (zflag | tots->firsthop) {
  550.     X            (void)fprintf(stderr, "%-9s% 7d% 8.2f", tots->host,
  551.     X                tots->firsthop,
  552.     X                tots->firsthop ? (double)tots->hopcount / tots->firsthop : (double)0);
  553.     X            for (hops = 0; hops < dist; hops++) 
  554.     X                (void)fprintf(stderr, "% 5d", tots->pthlng[hops]);
  555.     X            (void)fprintf(stderr, "\n");
  556.     X        }
  557.     X        if (tots->host != NULL) 
  558.     X            (void)free((char *)tots->host);
  559.     X        tnbr = tots->next;
  560.     X        (void)free((char *)tots);
  561.     X        tots = tnbr;
  562.     X    }
  563.     X    exit(error);
  564.     X}
  565.     X
  566.     X
  567.     X
  568.     X
  569.     X/*
  570.     X *    This routine is given the name of a neighbor host ("nbrname"),
  571.     X *    then uses malloc() to acquire storage for a new "nbr" struct for
  572.     X *    that host.  It then uses malloc() again, this time to acquire
  573.     X *    enough storage for a copy of the nbrname, initializes that copy
  574.     X *    from the nbrname given, & anchors the nbrname in the newly-created
  575.     X *    nbr struct.
  576.     X
  577.     X *    Lastly, a pointer to the (newly-created) nbr struct is returned.
  578.     X
  579.     X *    If anything goes wrong during this, NULL is returned in lieu of a
  580.     X *    valid pointer to a nbr struct -- and any storage acquired in the
  581.     X *    process is freed.  (That is, there is a concious attempt to "back
  582.     X *    out" cleanly.)
  583.     X */
  584.     X
  585.     Xstruct nbr *(getnbr(nbrname)
  586.     X)
  587.     Xchar    *nbrname;
  588.     X
  589.     X{
  590.     X
  591.     X    char    *malloc();    /* to make lint less unhappy              */
  592.     X
  593.     X    extern int    errno;        /* used by perror() and friends       */
  594.     X
  595.     X    struct nbr *tnbr;    /* temporary anchor for new nbr struct        */
  596.     X    int    hops;        /* subscript for pathlength buckets           */
  597.     X
  598.     X    if ((tnbr = (struct nbr *)malloc((unsigned)sizeof(struct nbr))) == NULL) {
  599.     X        return((struct nbr *)NULL);
  600.     X    }
  601.     X    if ((tnbr->host = (char *)malloc((unsigned)(1 + strlen(nbrname)))) == NULL) {
  602.     X        (void)free((char *)tnbr);
  603.     X        return((struct nbr *)NULL);
  604.     X    }
  605.     X
  606.     X    tnbr->next = NULL;
  607.     X    (void)strcpy(tnbr->host, nbrname);
  608.     X    tnbr->firsthop = 0;
  609.     X    tnbr->hopcount = 0;
  610.     X    tnbr->cost = 0;
  611.     X    for (hops = 0; hops < MAXDIST; hops++) 
  612.     X        tnbr->pthlng[hops] = 0;
  613.     X    return(tnbr);
  614.     X}
  615.     X
  616.     X
  617.     X
  618.     X
  619.     X/*
  620.     X *    This routine is called to find the name of the host from whose
  621.     X *    perspective the pathalias data was created.
  622.     X
  623.     X *    Unfortunately, I do not know of a way to ensure consistency in
  624.     X *    this respect; I have tried to make consistency easy to accomplish,
  625.     X *    however, by providing the same mechanism pathalias uses to determine
  626.     X *    the name of the current host -- including the use of the l flag.
  627.     X
  628.     X *    (Thus, this routine isn't invoked if the l flag is specified when
  629.     X *    the program is invoked.)
  630.     X
  631.     X *    [The following source is basically plagiarized from the sources for
  632.     X *    pathalias.  I hope that neither Peter Honeyman nor Steve Bellovin
  633.     X *    mind too much.... dhw]
  634.     X
  635.     X *    Anyway, if a problem occurs, NULL is returned.
  636.     X */
  637.     X
  638.     Xchar    *hostname(nmptr)
  639.     Xchar    *nmptr;
  640.     X
  641.     X{
  642.     X
  643.     X    extern int    errno;        /* used by perror() and friends               */
  644.     X
  645.     X#ifdef    UNAME
  646.     X#include <sys/utsname.h>
  647.     X
  648.     X    int    uname();    /* system call to find out where I am         */
  649.     X    struct utsname ustrct;    /* utsname struct for uname()                 */
  650.     X
  651.     X    if (uname(&ustrct) < 0) 
  652.     X        return(NULL);
  653.     X    else {
  654.     X        (void)strcpy(nmptr, ustrct.nodename);
  655.     X
  656.     X#else    /*  !UNAME  */
  657.     X#include <sys/param.h>
  658.     X
  659.     X    int    gethostname();    /* system call to find out where I am         */
  660.     X    char    name[MAXHOSTNAMELEN];    /* array to hold the host name        */
  661.     X
  662.     X    if (gethostname(name, (int)MAXHOSTNAMELEN) < 0) 
  663.     X        return(NULL);
  664.     X    else {
  665.     X        (void)strcpy(nmptr, name);
  666.     X#endif    /* UNAME */
  667.     X        return(nmptr);
  668.     X    }
  669.     X
  670.     X}
  671. SHAR_EOF
  672. if test 20748 -ne "`wc -c < 'pathrpt.c'`"
  673. then
  674.     echo shar: error transmitting "'pathrpt.c'" '(should have been 20748 characters)'
  675. fi
  676. fi # end of overwriting check
  677. #    End of shell archive
  678. exit 0
  679.  
  680.  
  681.