home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / uucp-1.04 / contrib / uurate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-15  |  16.1 KB  |  658 lines

  1. /*
  2.  * @(#)uurate.c 1.2 - Thu Sep  3 18:32:46 1992
  3.  *
  4.  * This program digests log and stats files in the "Taylor" format
  5.  * and outputs various statistical data to standard out.
  6.  *
  7.  * Author:
  8.  *    Bob Denny (denny@alisa.com)
  9.  *    Fri Feb  7 13:38:36 1992
  10.  *
  11.  * Original author:
  12.  *     Mark Pizzolato   mark@infopiz.UUCP
  13.  *
  14.  * Edits:
  15.  *    Bob Denny - Fri Feb  7 15:04:54 1992
  16.  *    Heavy rework for Taylor UUCP. This was the (very old) uurate from
  17.  *    DECUS UUCP, which had a single logfile for activity and stats.
  18.  *      Personally, I would have done things differently, with tables
  19.  *      and case statements, but in the interest of time, I preserved
  20.  *      Mark Pizzolato's techniques and style.
  21.  *
  22.  *      Bob Denny - Sun Aug 30 14:18:50 1992
  23.  *      Changes to report format suggested by Francois Pinard and others.
  24.  *      Add summary report, format from uutraf.pl (perl script), again
  25.  *      thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP.
  26.  */
  27.  
  28. char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2";
  29.  
  30. #include <ctype.h>        /* Character Classification    */
  31. #include <string.h>
  32. #include <math.h>
  33.  
  34. #include "uucp.h"
  35.  
  36.  
  37. #define _DEBUG_ 0
  38.     
  39. /*
  40.  * Direction of Calling and Data Transmission
  41.  */
  42. #define IN    0        /* Inbound        */
  43. #define OUT    1        /* Outbound         */
  44.  
  45. /*
  46.  * Data structures used to collect information
  47.  */
  48. struct File_Stats
  49.     {
  50.     int files;            /* Files Transferred    */
  51.     unsigned long bytes;    /* Data Size Transferred*/
  52.     double time;        /* Transmission Time    */
  53.     };
  54.  
  55. struct Phone_Call
  56.     {
  57.     int calls;            /* Call Count        */
  58.     int succs;            /* Successful calls     */
  59.     double connect_time;    /* Connect Time Spent    */
  60.     struct File_Stats flow[2];    /* Rcvd & Sent Data      */
  61.     };
  62.  
  63. struct Execution_Command
  64.     {
  65.     struct Execution_Command *next;
  66.     char Commandname[64];
  67.     int count;
  68.     };
  69.  
  70. struct Host_entry
  71.     {
  72.     struct Host_entry *next;
  73.     char Hostname[32];
  74.     struct Execution_Command *cmds;    /* Local Activities */
  75.     struct Phone_Call call[2];        /* In & Out Activities */
  76.     };
  77.  
  78. /*
  79.  * Stuff for getopt()
  80.  */
  81. extern int optind;        /* GETOPT : Option Index        */
  82. extern char *optarg;        /* GETOPT : Option Value        */
  83. extern void *calloc();
  84.  
  85. static void fmtime();
  86. static void fmbytes();
  87.  
  88. /*
  89.  * Default files to read. Taken from Taylor compile-time configuration.
  90.  * Must look like an argvec, hence the dummy argv[0].
  91.  */
  92. static char *(def_logs[3]) = { "", LOGFILE, STATFILE };
  93.  
  94. /*
  95.  * Misc. strings for reports
  96.  */
  97. static char *(file_hdr[2]) = { "\nReceived file statistics:\n",
  98.                  "\nSent file statistics\n" };
  99.   
  100. /*
  101.  * BEGIN EXECUTION
  102.  */
  103. main(argc, argv)
  104. int argc;
  105. char *argv[];
  106. {
  107.   char c;
  108.   char *p, *s;
  109.   struct Host_entry *hosts = NULL;
  110.   struct Host_entry *cur = NULL;
  111.   struct Host_entry *e;
  112.   struct Execution_Command *cmd;
  113.   struct Execution_Command *ec;
  114.   char Hostname[64];
  115.   FILE *Log = NULL;
  116.   char logline[1024];
  117.   char *logmsg;
  118.   int sent;
  119.   int called;
  120.   int show_files = 0;        /* I prefer boolean, but... */
  121.   int show_calls = 0;
  122.   int show_commands = 0;
  123.   int show_efficiency = 0;
  124.   int show_summary = 0;
  125.   int have_files = 0;
  126.   int have_calls = 0;
  127.   int have_commands = 0;  
  128.   int use_stdin = 0;
  129.   Hostname[0] = '\0';
  130.  
  131.   /*
  132.    * I wish the compiler had the #error directive!
  133.    */
  134. #if !HAVE_TAYLOR_LOGGING
  135.   fprintf(stderr, "uurate cannot be used with your configuration of\n");
  136.   fprintf(stderr, "Taylor UUCP. To use uurate you must be using the\n");
  137.   fprintf(stderr, "TAYLOR_LOGGING configuration.\n");
  138.   exit(1);
  139. #endif
  140.  
  141.   /*
  142.    * Process the command line arguments
  143.    */
  144.   while((c = getopt(argc, argv, "h:cfexai")) != EOF)
  145.     {
  146.       switch(c)
  147.     {
  148.     case 'h':
  149.       strcpy(Hostname, optarg);
  150.       break;
  151.     case 'c':
  152.       show_calls = 1;
  153.       break;
  154.     case 'f':
  155.       show_files = 1;
  156.       break;
  157.     case 'x':
  158.       show_commands = 1;
  159.       break;
  160.         case 'e':
  161.       show_efficiency = 1;
  162.       break;
  163.     case 'a':
  164.       show_calls = show_files = show_commands = show_efficiency = 1;
  165.       break;
  166.     case 'i':
  167.       use_stdin = 1;
  168.       break;
  169.         default :
  170.       goto usage;
  171.     }
  172.     }
  173.  
  174.   /*
  175.    * If no report switches given, show summary report.
  176.    */
  177.   if (show_calls == 0 && show_files == 0
  178.       && show_efficiency == 0 && show_commands == 0)
  179.     show_summary = 1;
  180.   
  181.   /*
  182.    * Adjust argv and argc to account for the args processed above.
  183.    */
  184.   argc -= (optind - 1);
  185.   argv += (optind - 1);
  186.  
  187.   /*
  188.    * If further args present, Assume rest are logfiles for us to process,
  189.    * otherwise, take input from Log and Stat files provided in the
  190.    * compilation environment of Taylor UUCP. If -i was given, Log already
  191.    * points to stdin and no file args are accepted.
  192.    */
  193.   if(argc == 1)            /* No file arguments */
  194.     {
  195.       if (use_stdin)        /* If -i, read from stdin */
  196.     {
  197.       argc = 2;
  198.       Log = stdin;
  199.     }
  200.       else            /* Read from current logs */
  201.     {
  202.           argc = 3;            /* Bash argvec to default log/stat files */
  203.           argv = &def_logs[0];
  204.         }
  205.     }
  206.   else if (use_stdin)        /* File args with -i is an error */
  207.     {
  208.       fprintf(stderr, "uurate (error): file args given with '-i'\n");
  209.       goto usage;
  210.     }
  211.  
  212. #if _DEBUG_
  213.   printf("\n");
  214. #endif
  215.  
  216.   /*
  217.    * MAIN LOGFILE PROCESSING LOOP
  218.    */
  219.   while (argc > 1)
  220.     {
  221.  
  222.       if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
  223.     {
  224.       perror(argv[1]);
  225.       return;
  226.     }
  227.  
  228. #if _DEBUG_
  229.       printf("Reading %s...\n", (use_stdin ? "stdin" : argv[1]));
  230. #endif
  231.       
  232.       /*
  233.        * Read each line of the logfile and collect information
  234.        */
  235.       while (fgets(logline, sizeof(logline), Log))
  236.     {
  237.       /*
  238.        * The host name of the other end of the connection is
  239.        * always the second field of the log line, whether we
  240.        * are reading a Log file or a Stats file. Set 'p' to
  241.        * point to the second field, null-terminated. Skip
  242.        * the line if something is funny.
  243.        */
  244.       if (NULL == (p = strchr(logline, ' ')))
  245.         continue;
  246.       ++p;
  247.       if (NULL != (s = strchr(p, ' ')))
  248.         *s = '\0';
  249.       for (s = p; *s; ++s)
  250.         if (isupper(*s))
  251.           *s = tolower(*s);
  252.       /*
  253.        * Skip this line if we got -h <host> and
  254.        * this line does not contain that host name.
  255.        */
  256.       if (Hostname[0] != '\0')
  257.         if (0 != strcmp(p, Hostname))
  258.           continue;
  259.       /*
  260.        * We are within a call block now. If this line is a file
  261.        * transfer record, determine the direction. If not then
  262.        * skip the line if it is not interesting.
  263.        */
  264.       if ((s = strchr(++s, ')')) == NULL)
  265.         continue;
  266.       logmsg = s + 2;        /* Message is 2 characters after ')' */
  267.       if (0 == strncmp(logmsg, "sent", 4))
  268.         sent = OUT;
  269.       else
  270.         if (0 == strncmp(logmsg, "received", 8))
  271.           sent = IN;
  272.         else
  273.           if ((0 != strncmp(logmsg, "Call complete", 13)) &&
  274.           (0 != strncmp(logmsg, "Calling system", 14)) &&
  275.           (0 != strncmp(logmsg, "Incoming call", 13)) &&
  276.           (0 != strncmp(logmsg, "Executing", 9)))
  277.         continue;
  278.       /*
  279.        * Find the Host_entry for this host, or create a new
  280.        * one and link it on to the list.
  281.        */
  282.       if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
  283.         {
  284.           for (cur = hosts; cur != NULL ; cur = cur->next)
  285.         if (0 == strcmp(cur->Hostname, p))
  286.           break;
  287.           if (cur == NULL)
  288.         {
  289.           cur = (struct Host_entry *)calloc(1, sizeof(*hosts));
  290.           strcpy(cur->Hostname, p);
  291.           if (hosts == NULL)
  292.             hosts = cur;
  293.           else
  294.             {
  295.               for (e = hosts; e->next != NULL; e = e->next);
  296.               e->next = cur;
  297.             }
  298.         }
  299.         }
  300.       /*
  301.        * OK, if this is a uuxqt record, find the Execution_Command
  302.        * structure for the command being executed, or create a new
  303.        * one. Then count an execution of this command.
  304.        */
  305.       if (0 == strncmp(logmsg, "Executing", 9))
  306.         {
  307.           if (NULL == (p = strchr(logmsg, '(')))
  308.         continue;
  309.           if ((s = strpbrk(++p, " )")) == NULL)
  310.         continue;
  311.           *s = '\0';
  312.           for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
  313.         if (0 == strcmp(cmd->Commandname, p))
  314.           break;
  315.           if (cmd == NULL)
  316.         {
  317.           cmd = (struct Execution_Command *)calloc(1, sizeof(*cmd));
  318.           strcpy(cmd->Commandname, p);
  319.           if (cur->cmds == NULL)
  320.             cur->cmds = cmd;
  321.           else
  322.             {
  323.               for (ec = cur->cmds; ec->next != NULL; ec = ec->next);
  324.               ec->next = cmd;
  325.             }
  326.         }
  327.           ++cmd->count;
  328.           have_commands = 1;
  329.           continue;
  330.         }
  331.       /*
  332.        * Count start of outgoing call.
  333.        */
  334.       if (0 == strncmp(logmsg, "Calling system", 14))
  335.         {
  336.           called = OUT;
  337.           cur->call[called].calls += 1;
  338.           have_calls = 1;
  339.           continue;
  340.         }
  341.       /*
  342.        * Count start of incoming call.
  343.        */
  344.       if (0 == strncmp(logmsg, "Incoming call", 13))
  345.         {
  346.           called = IN;
  347.           cur->call[called].calls += 1;
  348.           have_calls = 1;
  349.           continue;
  350.         }
  351.       /*
  352.        * Handle end of call. Pick up the connect time.
  353.        */
  354.       if (0 == strncmp(logmsg, "Call complete", 13))
  355.         {
  356.           cur->call[called].succs += 1;
  357.           if (NULL == (s = strchr(logmsg, '(')))
  358.         continue;
  359.           cur->call[called].connect_time += atof(s+1);
  360.           continue;
  361.         }
  362.       /*
  363.        * If we reached here, this must have been a file transfer
  364.        * record. Count it in the field corresponding to the
  365.        * direction of the transfer. Count bytes transferred and
  366.        * the time to transfer as well.
  367.        */
  368.       have_files = 1;
  369.       cur->call[called].flow[sent].files += 1;
  370.       if (NULL == (s = strchr(logmsg, ' ')))
  371.         continue;
  372.       cur->call[called].flow[sent].bytes += atol(++s);
  373.       if (NULL == (s = strchr(s, ' ')))
  374.         continue;
  375.       if (NULL == (s = strpbrk(s, "0123456789")))
  376.         continue;
  377.       cur->call[called].flow[sent].time += atof(s);
  378.     }
  379.       argc -= 1;
  380.       argv += 1;
  381.       if(Log != stdin)
  382.     fclose(Log);
  383.     }
  384.   
  385.   /*
  386.    *     ***********
  387.    *     * REPORTS *
  388.    *     ***********
  389.    */
  390.  
  391.   /*
  392.    * Truncate the Hostnames to 8 characters at most.
  393.    */
  394.   for (cur = hosts; cur != NULL; cur = cur->next)
  395.     cur->Hostname[8] = '\0';
  396.  
  397. #if _DEBUG_
  398.   printf("\n");
  399. #endif
  400.  
  401.   /*
  402.    * Summary report
  403.    *
  404.    * I know, this code could be tightened (rbd)...
  405.    */
  406.   if(show_summary)
  407.     {
  408.       char t1[32], t2[32], t3[32], t4[32], t5[32];
  409.       long ib, ob, b, rf, sf;
  410.       long t_ib=0, t_ob=0, t_b=0, t_rf=0, t_sf=0;
  411.       double it, ot, ir, or;
  412.       double t_it=0.0, t_ot=0.0;
  413.       int nhosts = 0;
  414.  
  415.       printf("\n\
  416.  Remote  ------- Bytes -------- --- Time ---- -- Avg CPS -- -- Files --\n");
  417.       printf("\
  418.   Host      Rcvd    Sent   Total   Rcvd   Sent   Rcvd   Sent  Rcvd  Sent\n");
  419.       printf("\
  420. -------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
  421.       for (cur = hosts; cur != NULL; cur = cur->next)
  422.     {
  423.       ib = (cur->call[IN].flow[IN].bytes + 
  424.         cur->call[OUT].flow[IN].bytes);
  425.       fmbytes(ib, t1);
  426.       t_ib += ib;
  427.  
  428.       ob = (cur->call[IN].flow[OUT].bytes + 
  429.         cur->call[OUT].flow[OUT].bytes);
  430.       fmbytes(ob, t2);
  431.       t_ob += ob;
  432.  
  433.       b = ib + ob;
  434.       fmbytes(b, t3);
  435.       t_b += b;
  436.  
  437.       it = cur->call[IN].flow[IN].time +
  438.         cur->call[OUT].flow[IN].time;
  439.       fmtime(it, t4);
  440.       t_it += it;
  441.  
  442.       ot = cur->call[IN].flow[OUT].time +
  443.         cur->call[OUT].flow[OUT].time;
  444.       fmtime(ot, t5);
  445.       t_ot += ot;
  446.  
  447.       rf = cur->call[IN].flow[IN].files +
  448.         cur->call[OUT].flow[IN].files;
  449.       t_rf += rf;
  450.  
  451.       sf = cur->call[IN].flow[OUT].files +
  452.         cur->call[OUT].flow[OUT].files;
  453.       t_sf += sf;
  454.  
  455.       ir = (it == 0.0) ? 0.0 : (ib / it);
  456.       or = (ot == 0.0) ? 0.0 : (ob / ot);
  457.  
  458.       printf("%-8s %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
  459.          cur->Hostname,
  460.          t1, t2, t3, t4, t5, 
  461.          ir, or, rf, sf);
  462.     }
  463.  
  464.       if(nhosts > 1)
  465.     {
  466.       fmbytes(t_ib, t1);
  467.       fmbytes(t_ob, t2);
  468.       fmbytes(t_b, t3);
  469.       fmtime(t_it, t4);
  470.       fmtime(t_ot, t5);
  471.       ir = (t_it == 0.0) ? 0.0 : (t_ib / t_it);
  472.       or = (t_ot == 0.0) ? 0.0 : (t_ob / t_ot);
  473.  
  474.       printf("\
  475. -------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
  476.       printf("\
  477. Totals   %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
  478.          t1, t2, t3, t4, t5,
  479.          ir, or, t_rf, t_sf);
  480.     }
  481.     }
  482.  
  483.       
  484.   /*
  485.    * Call statistics report
  486.    */
  487.   if(show_calls && have_calls)
  488.     {
  489.       char t1[32], t2[32];
  490.  
  491.       printf("\nCall statistics:\n");
  492.       printf("\
  493.      sysname   callto  failto    totime  callfm  failfm    fmtime\n");
  494.       printf("\
  495.      --------  ------  ------  --------  ------  ------  --------\n");
  496.       for (cur = hosts; cur != NULL; cur = cur->next)
  497.     {
  498.       fmtime(cur->call[OUT].connect_time, t1);
  499.       fmtime(cur->call[IN].connect_time, t2),
  500.       printf("     %-8s  %6d  %6d  %8s  %6d  %6d  %8s\n",
  501.          cur->Hostname,
  502.          cur->call[OUT].calls,
  503.          cur->call[OUT].calls - cur->call[OUT].succs,
  504.          t1,
  505.          cur->call[IN].calls,
  506.          cur->call[IN].calls - cur->call[IN].succs,
  507.          t2);
  508.     }
  509.     }
  510.  
  511.   /*
  512.    * File statistics report
  513.    */
  514.   if(show_files && have_files)
  515.     {
  516.       char t1[32], t2[32];
  517.  
  518.       for (sent = IN; sent <= OUT; ++sent)
  519.     {
  520.       printf(file_hdr[sent]);
  521.       printf("     sysname    files     bytes  xfr time  byte/s\n");
  522.       printf("     --------  ------  --------  --------  ------\n");
  523.       for (cur = hosts; cur != NULL; cur = cur->next)
  524.         {
  525.           double rate;
  526.           double time;
  527.           
  528.           time = cur->call[IN].flow[sent].time +
  529.         cur->call[OUT].flow[sent].time;
  530.           if (time == 0.0)
  531.         continue;
  532.           rate = (cur->call[IN].flow[sent].bytes +
  533.               cur->call[OUT].flow[sent].bytes) / time;
  534.           fmbytes((cur->call[IN].flow[sent].bytes + 
  535.               cur->call[OUT].flow[sent].bytes), t1);
  536.           fmtime((cur->call[IN].flow[sent].time + 
  537.              cur->call[OUT].flow[sent].time), t2);
  538.           printf("     %-8s  %6d  %8s  %8s  %6.1f\n",
  539.              cur->Hostname,
  540.              cur->call[IN].flow[sent].files + 
  541.              cur->call[OUT].flow[sent].files,
  542.              t1, t2, rate);
  543.         }
  544.     }
  545.     }
  546.  
  547.   /*
  548.    * Efficiency report
  549.    */
  550.   if (show_efficiency && have_files)
  551.     {
  552.       char t1[32], t2[32], t3[32];
  553.       double total, flow;
  554.  
  555.       printf("\nEfficiency:\n");
  556.       printf("     sysname   conntime  flowtime  ovhdtime  eff. %%\n");
  557.       printf("     --------  --------  --------  --------  ------\n");
  558.       for (cur = hosts; cur != NULL; cur = cur->next)
  559.     {
  560.       total = cur->call[IN].connect_time + cur->call[OUT].connect_time;
  561.       flow = cur->call[IN].flow[IN].time + cur->call[IN].flow[OUT].time +
  562.         cur->call[OUT].flow[IN].time + cur->call[OUT].flow[OUT].time;
  563.       fmtime(total, t1);
  564.       fmtime(flow, t2);
  565.       fmtime((total-flow), t3);
  566.       printf("     %-8s  %8s  %8s  %8s  %5.1f%%\n",
  567.          cur->Hostname, t1, t2, t3, ((flow / total) * 100.0));
  568.     }
  569.     }
  570.  
  571.   /*
  572.    * Command execution report
  573.    */  
  574.   if (show_commands & have_commands)
  575.     {
  576.       printf("\nCommand executions:\n");
  577.       printf("     sysname    rmail   rnews   other\n");
  578.       printf("     --------  ------  ------  ------\n");
  579.       for (cur = hosts; cur != NULL; cur = cur->next)
  580.     {
  581.           int rmail, rnews, other;
  582.       
  583.       if (cur->cmds == NULL)
  584.         continue;
  585.           rmail = rnews = other = 0;
  586.       for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
  587.         {
  588.           if (strcmp(cmd->Commandname, "rmail") == 0)
  589.         rmail += cmd->count;
  590.           else if (strcmp(cmd->Commandname, "rnews") == 0)
  591.         rnews += cmd->count;
  592.           else
  593.         other += cmd->count;
  594.         }
  595.       printf("     %-8s  %6d  %6d  %6d\n", cur->Hostname,
  596.          rmail, rnews, other);
  597.     }
  598.     }
  599.   return;
  600.   
  601.  usage:
  602.   fprintf(stderr,
  603.       "Usage uurate [-cfexai] [-h hostname] [logfile ... logfile]\n");
  604.   fprintf(stderr,"where:\t-c\tReport call statistics\n");
  605.   fprintf(stderr, "\t-f\tReport file transfer statistics\n");
  606.   fprintf(stderr, "\t-e\tReport efficiency statistics\n");
  607.   fprintf(stderr, "\t-x\tReport command execution statistics\n");
  608.   fprintf(stderr, "\t-a\tAll of the above reports\n");  
  609.   fprintf(stderr, "\t-h host\tReport activities involving ONLY host\n");
  610.   fprintf(stderr, "\t-i\tRead log info from standard input\n");
  611.   fprintf(stderr,
  612.       "If no report options given, a compact summary report is given.\n");
  613.   fprintf(stderr,
  614.       "If neither -i nor logfiles given, defaults to reading from\n");
  615.   fprintf(stderr, "%s and %s\n\n", LOGFILE, STATFILE);
  616. }
  617.  
  618. /*
  619.  * fmtime() - Format time in hours & minutes;
  620.  */
  621. static void fmtime(dsec, buf)
  622.      double dsec;
  623.      char *buf;
  624. {
  625.   long hrs, min, lsec;
  626.  
  627.   lsec = dsec;
  628.   hrs = lsec / 3600L;
  629.   min = (lsec - (hrs * 3600L)) / 60L;
  630.  
  631.   sprintf(buf, "%02ld:%02ld", hrs, min);
  632. }
  633.  
  634. /*
  635.  * fmbytes - Format size in bytes
  636.  */
  637. static void fmbytes(n, buf)
  638.      unsigned long n;
  639.      char *buf;
  640. {
  641.   char t;
  642.   double s = n;
  643.  
  644.   if(s >= 10239897.6)        /* More than 9999.9K ? */
  645.     {
  646.       s = (double)n / 1048576.0;    /* Yes, display in Megabytes */
  647.       t = 'M';
  648.     }
  649.   else
  650.     {
  651.       s = (double)n / 1024.0;    /* Display in Kilobytes */
  652.       t = 'K';
  653.     }
  654.  
  655.   sprintf(buf, "%.1f%c", s, t);
  656. }
  657.  
  658.