home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / auucp+-1.02 / fuucp_plus_src.lzh / inpaths.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-17  |  10.6 KB  |  382 lines

  1. /* inpaths.c -- track the paths of incoming news articles and prepare
  2.  *          in a format suitable for decwrl pathsurveys
  3.  *
  4.  *
  5.  * This program inputs a list of filenames of news articles, and outputs a
  6.  * data report which should be mailed to the decwrl Network Monitoring
  7.  * Project at address "pathsurvey@decwrl.dec.com". Please run it once a month
  8.  * if you can, in time so that the results arrive at decwrl by the 1st
  9.  * day of the month.
  10.  *
  11.  *
  12.  * Run it like this:
  13.  *
  14.  *  cd /usr/spool/news
  15.  *  find . -type f -print | inpaths "yourhost" | mail pathsurvey@decwrl.dec.com
  16.  *
  17.  *  where "yourhost" is the host name of your computer, e.g. "decwrl".
  18.  *
  19.  * The input to "inpaths" must be a list of the file names of news articles,
  20.  * relative to the spooling directory. "./news/config/2771" and
  21.  * "news/config/2771" are both legal inputs, but "/usr/spool/news/config/2771"
  22.  * is not.  * If you have some other way of generating a list of news file
  23.  * names, such as running a script over the history file, you can use that
  24.  * instead. Inpaths handles crossposting regardless of which technique
  25.  * you use.
  26.  *
  27.  * If you get an error message "no traffic found. Check $CWD", then the
  28.  * problem is most likely that the path names you are giving it are not
  29.  * relative to the spooling directory, e.g. you are feeding it lines like
  30.  * "/usr/spool/news/news/config/2771" instead of "./news/config/2771"
  31.  * 
  32.  * There are 3 options: -s, -m, and -l for short, medium, and long report.
  33.  * The default is to produce a long report. If you are worried about mail
  34.  * expenses you can send a shorter report. The long report is typically
  35.  * about 50K bytes for a major site, and perhaps 25K bytes for a smaller
  36.  * site. 
  37.  *
  38.  * Brian Reid
  39.  *    V1     Sep 1986
  40.  *    V2.4     May 1989
  41.  *
  42.  * Special thanks to Mel Pleasant and Bob Thrush for significant help with
  43.  * portability bugs.
  44.  *     
  45.  */
  46.  
  47. /* if you are compiling on a USG machine (SysV, etc),
  48.    please uncomment the following line: */
  49.  
  50. /* #define SYSV */
  51.  
  52.  
  53.  
  54. #define VERSION "2.4"
  55. #include <stdio.h>
  56. #include <fcntl.h>
  57. #include <ctype.h>
  58. #include <sys/types.h>
  59. #include <sys/stat.h>
  60.  
  61. #define HEADBYTES 1024
  62.  
  63. #ifdef SYSV
  64.     long time();
  65. #else SYSV
  66.     time_t time();
  67. #endif SYSV
  68.  
  69. extern int exit();
  70. extern char *malloc();
  71. extern char *strcpy();
  72.  
  73. /* this is index() or strchr() included here for portability */
  74.  
  75. char *index(ptr,chr)
  76. char *ptr,chr;
  77.  {
  78.     do {if (*ptr==chr) return(ptr);} while (*ptr++);
  79.     return ( (char *) NULL);
  80.  }
  81.  
  82. main (argc,argv)
  83.   int argc;
  84.   char **argv;
  85.  {
  86.     char linebuf[1024], jc, *lptr, *cp, *cp1, *cp2;
  87.     char rightdelim;
  88.     char *pathfield, *groupsfield;
  89.     int crossposted;
  90.     char artbuf[HEADBYTES], ngfilename[256];
  91.     struct stat statbuf, *sbptr;
  92.     char *scanlimit;
  93.     char *hostname;
  94.     char hostString[128];
  95.     int needHost;
  96.     static int passChar[256];
  97.     int isopen,columns,verbose,totalTraffic;
  98.     long nowtime,age,agesum;
  99.     float avgAge;
  100.  
  101.     /* definitions for getopt */
  102.     extern int optind;
  103.     extern char *optarg;
  104.  
  105.  /* structure used to tally the traffic between two hosts */
  106.     typedef struct trec {
  107.     struct trec *rlink;
  108.     struct nrec *linkid;
  109.     int tally;
  110.     } ;
  111.  
  112.  /* structure to hold the information about a host */
  113.     typedef struct nrec {
  114.     struct nrec *link;
  115.     struct trec *rlink;
  116.     char *id;
  117.     long sentto; /* tally of articles sent to somebody from here */
  118.     } ;
  119.     struct nrec *hosthash[128], *hnptr, *list, *relay;
  120.     struct trec *rlist;
  121.     int i, article, gotbytes, c;
  122.     extern errno;
  123.  
  124.     hostname = "unknown";
  125.     verbose = 2;
  126.     while (( c=getopt(argc, argv, "sml" )) != EOF)
  127.     switch (c) {
  128.     case 's': verbose=0; break;
  129.     case 'm': verbose=1; break;
  130.     case 'l': verbose=2; break;
  131.     case '?': fprintf(stderr,
  132.     "usage: %s [-s] [-m] [-l] hostname\n",argv[0]);
  133.     exit(1);
  134.     }
  135.     if (optind < argc) {
  136.         hostname = argv[optind];
  137.     } else {
  138.     fprintf(stderr,"usage: %s [-s] [-m] [-l] `hostname`\n",argv[0]);
  139.     exit(1);
  140.     }
  141.  
  142.     fprintf(stderr,"computing %s inpaths for host %s\n",
  143.     verbose==0 ? "short" : (verbose==1 ? "medium" : "long"),hostname);
  144.     for (i = 0; i<128; i++) hosthash[i] = (struct nrec *) NULL;
  145.  
  146. /* precompute character types to speed up scan */
  147.     for (i = 0; i<=255; i++) {
  148.         passChar[i] = 0;
  149.     if (isalpha(i) || isdigit(i)) passChar[i] = 1;
  150.     if (i == '-' || i == '.' || i == '_') passChar[i] = 1;
  151.     }
  152.     totalTraffic = 0;
  153.     nowtime = (long) time(0L);
  154.     agesum = 0;
  155.  
  156.     while (gets(linebuf) != (char *) NULL) {
  157.         lptr = linebuf;
  158.     isopen = 0;
  159.  
  160. /* Skip blank lines */
  161.     if (linebuf[0] == '\0') goto bypass;
  162.  
  163. /* Skip files that do not have pure numeric names */
  164.     i = strlen(lptr)-1;
  165.     do {
  166.         if (!isdigit(linebuf[i])) {
  167.             if (linebuf[i]=='/') break;
  168.         goto bypass;
  169.         }
  170.         i--;
  171.     } while (i>=0);
  172.  
  173. /* Open the file for reading */
  174.     article = open(lptr, O_RDONLY);
  175.     isopen = (article > 0);
  176.     if (!isopen) goto bypass;
  177.     sbptr = &statbuf;
  178.     if (stat(lptr, sbptr) == 0) {
  179.  
  180. /* Record age of file in hours */
  181.         age = (nowtime - statbuf.st_mtime) / 3600;
  182.         agesum += age;
  183. /* Reject names that are not ordinary files         */
  184.         if ((statbuf.st_mode & S_IFREG) == 0) goto bypass;
  185. /* Pick the file name apart into an equivalent newsgroup name */
  186.         if (*lptr == '.') {
  187.             lptr++;
  188.         if (*lptr == '/') lptr++;
  189.         }
  190.         cp = ngfilename;
  191.         while (*lptr != 0) {
  192.             if (*lptr == '/') *cp++ = '.';
  193.         else *cp++ = *lptr;
  194.         lptr++;
  195.         }
  196.         cp--; while (isdigit(*cp)) *cp-- = NULL;
  197.         if (*cp == '.') *cp = NULL;
  198.         } else goto bypass;
  199.  
  200. /* Read in the first few bytes of the article; find the end of the header */
  201.     gotbytes = read(article, artbuf, HEADBYTES);
  202.     if (gotbytes < 10) goto bypass;
  203.  
  204. /* Find "Path:" header field */
  205.     pathfield = (char *) 0;
  206.         groupsfield = (char *) 0;
  207.     scanlimit = &artbuf[gotbytes];
  208.     for (cp=artbuf; cp <= scanlimit; cp++) {
  209.         if (*cp == '\n') break;
  210.         if (pathfield && groupsfield) goto gotpath;
  211.         if (strncmp(cp, "Path: ", 6) == 0) {
  212.         pathfield = cp; goto nextgr;
  213.         }
  214.         if (strncmp(cp, "Newsgroups: ", 12) == 0) {
  215.         groupsfield = cp; goto nextgr;
  216.         }
  217.    nextgr:
  218.         while (*cp != '\n' && cp <= scanlimit) cp++;
  219.     }
  220.     if (groupsfield == (char *) 0 || (pathfield == (char *) 0)) 
  221.         goto bypass; 
  222.  
  223. gotpath: ;
  224.  
  225. /* Determine the name of the newsgroup to which this is charged. It is not
  226.    necessarily the name of the file in which we found it; rather, use the
  227.    "Newsgroups:" field.                             */
  228.  
  229.     crossposted = 0;
  230.     groupsfield += 12;    /* skip 'Newsgroups: ' */
  231.     while (*groupsfield == ' ') groupsfield++;
  232.     cp= (char *) index(groupsfield,'\n'); *cp = 0;
  233.     cp=(char *) index(groupsfield,',');
  234.     if (cp) {
  235.         crossposted++;
  236.         *cp = 0;
  237.     }
  238.  
  239. /* To avoid double-billing, only charge the newsgroup if the pathname matches
  240.    the contents of the Newsgroups: field. This will also prevent picking up
  241.    junk and control messages.
  242.  */
  243.     if (strcmp(ngfilename,groupsfield)) goto bypass;
  244.  
  245. /* Extract all of the host names from the "Path:" field and put them in our
  246. host table.                                 */
  247.     cp = pathfield;
  248.     while (*cp != NULL && *cp != '\n') cp++;
  249.     if (cp == NULL) {
  250.         fprintf(stderr,"%s: end of Path line not in buffer.\n",lptr);
  251.         goto bypass;
  252.     }
  253.  
  254.     totalTraffic++;
  255.     *cp = 0;
  256.     pathfield += 5;    /* skip 'Path:' */
  257.     cp1 = pathfield;
  258.     relay = (struct nrec *) NULL;
  259.     rightdelim = '!';
  260.     while (cp1 < cp) {
  261.         /* get next field */
  262.         while (*cp1=='!') cp1++;
  263.         cp2 = ++cp1;
  264.         while (passChar[(int) (*cp2)]) cp2++;
  265.  
  266.         rightdelim = *cp2; *cp2 = 0;
  267.         if (rightdelim=='!' && *cp1 != (char) NULL) {
  268.         /* see if already in the table */
  269.         list = hosthash[*cp1];
  270.         while (list != NULL) {
  271.             /*
  272.              * Attempt to speed things up here a bit.  Since we hash
  273.              * on the first char, we see if the second char is a match
  274.              * before calling strcmp()
  275.              */
  276.             if (list->id[1] == cp1[1] && !strcmp(list->id, cp1)) {
  277.             hnptr = list;
  278.             break;        /* I hate unnecessary goto's */
  279.             }
  280.             list = list->link;
  281.         }
  282.         if(list == NULL) {
  283.             /* get storage and splice in a new one */
  284.             hnptr = (struct nrec *) malloc(sizeof (struct nrec));
  285.             hnptr->id = (char *) strcpy(malloc(1+strlen(cp1)),cp1);
  286.             hnptr->link = hosthash[*cp1];
  287.             hnptr->rlink = (struct trec *) NULL;
  288.             hnptr->sentto = (long) 0;
  289.             hosthash[*cp1] = hnptr;
  290.         }
  291.         }
  292. /* 
  293. At this point "hnptr" points to the host record of the current host. If
  294. there was a relay host, then "relay" points to its host record (the relay
  295. host is just the previous host on the Path: line. Since this Path means
  296. that news has flowed from host "hnptr" to host "relay", we want to tally
  297. one message in a data structure corresponding to that link. We will
  298. increment the tally record that is attached to the source host "hnptr".
  299. */
  300.  
  301.         if (relay != NULL && relay != hnptr) {
  302.         rlist = relay->rlink;
  303.         while (rlist != NULL) {
  304.             if (rlist->linkid == hnptr) goto have2;
  305.             rlist = rlist->rlink;
  306.         }
  307.         rlist = (struct trec *) malloc(sizeof (struct trec));
  308.         rlist->rlink = relay->rlink;
  309.         relay->rlink = rlist;
  310.         rlist->linkid = hnptr;
  311.         rlist->tally = 0;
  312.  
  313.     have2:      rlist->tally++;
  314.         hnptr->sentto++;
  315.         }
  316.  
  317.         cp1 = cp2;
  318.         relay = hnptr;
  319.         if (rightdelim == ' ' || rightdelim == '(') break;
  320.     }
  321. bypass: if (isopen) close(article) ;
  322.     }
  323. /* Now dump the host table */
  324.     if (!totalTraffic) {
  325.     fprintf(stderr,"%s: error--no traffic found. Check $CWD.\n",argv[0]);
  326.     exit(1);
  327.     }
  328.  
  329.     avgAge = ((double) agesum) / (24.0*(double) totalTraffic);
  330.     printf("ZCZC begin inhosts %s %s %d %d %3.1f\n",
  331.         VERSION,hostname,verbose,totalTraffic,avgAge);
  332.     for (jc=0; jc<127; jc++) {
  333.     list = hosthash[jc];
  334.     while (list != NULL) {
  335.         if (list->rlink != NULL) {
  336.         if (verbose > 0 || (100*list->sentto > totalTraffic))
  337.             printf("%ld\t%s\n",list->sentto, list->id);
  338.         }
  339.         list = list->link;
  340.     }
  341.     }
  342.     printf("ZCZC end inhosts %s\n",hostname);
  343.  
  344.     printf("ZCZC begin inpaths %s %s %d %d %3.1f\n",
  345.         VERSION,hostname,verbose,totalTraffic,avgAge);
  346.     for (jc=0; jc<127; jc++) {
  347.     list = hosthash[jc];
  348.     while (list != NULL) {
  349.         if (verbose > 1 || (100*list->sentto > totalTraffic)) {
  350.         if (list->rlink != NULL) {
  351.             columns = 3+strlen(list->id);
  352.             sprintf(hostString,"%s H ",list->id);
  353.             needHost = 1;
  354.             rlist = list->rlink;
  355.             while (rlist != NULL) {
  356.                 if (
  357.                  (100*rlist->tally > totalTraffic)
  358.               || ((verbose > 1)&&(5000*rlist->tally>totalTraffic))
  359.                ) {
  360.                 if (needHost) printf("%s",hostString);
  361.                 needHost = 0;
  362.                 relay = rlist->linkid;
  363.                 if (columns > 70) {
  364.                 printf("\n%s",hostString);
  365.                 columns = 3+strlen(list->id);
  366.                 }
  367.                 printf("%d Z %s U ", rlist->tally, relay->id);
  368.                 columns += 9+strlen(relay->id);
  369.             }
  370.             rlist = rlist->rlink;
  371.             }
  372.             if (!needHost) printf("\n");
  373.         }
  374.         }
  375.         list = list->link;
  376.     }
  377.     }
  378.     printf("ZCZC end inpaths %s\n",hostname);
  379.     fclose(stdout);
  380.     exit(0);
  381. }
  382.