]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - gnu/libexec/uucp/contrib/uurate.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / gnu / libexec / uucp / contrib / uurate.c
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  *      Stephan Niemz <stephan@sunlab.ka.sub.org> - Fri Apr 9 1993
28  *      - Print totals in summary report,
29  *      - show all commands in execution report,
30  *      - count incoming calls correctly,
31  *      - suppress empty tables,
32  *      - don't divide by zero in efficiency report,
33  *      - limit the efficiency to 100% (could be more with the i-protocol),
34  *      - suppress some zeros to improve readability,
35  *      - check for failure of calloc,
36  *      - -h option changed to -s for consistency with all other uucp commands
37  *        (but -h was left in for comptibility).
38  *
39  *      Scott Boyd <scott@futures.com> - Thu Aug 26 13:21:34 PDT 1993
40  *      - Changed hosts linked-list insertion routine so that hosts
41  *        are always listed in alphabetical order on reports.
42  *
43  *      Klaus Dahlenburg <kdburg@incoahe.hanse.de> - Fri Jun 18 1993 (1.2.2)
44  *      - redesigned the printed layout (sticked to those 80 column tubes).
45  *      - 'Retry time not ...' and ' ERROR: All matching ports ...' will now be
46  *        counted as calls and will raise the failed-call counter.
47  *      - times now shown as hh:mm:ss; the fields may hold up to 999 hrs  
48  *        (a month equals 744 hrs at max). Printing will be as follows:
49  *
50  *         hrs > 0  hh:mm:ss
51  *         min > 0     mm:ss
52  *         sec > 0        ss
53  *         leading zeroes are suppressed.
54  *
55  *      - the bytes xfered will be given in thousands only (we're counting 
56  *        so 1K is 1000 bytes!). Sums up to 9,999,999.9 thousand can be shown.
57  *      - dropped the fractions of a byte in columns: bytes/second (avg cps).
58  *      - File statistic changed to display in/out in one row instead of 2
59  *        separate reports.
60  *      - eliminated the goto in command report and tightened the code; also
61  *        the 'goto usage' has been replaced by a call to void usage() with no
62  *        return (exit 1).
63  *      - a totaling is done for all reports now; the total values are held 
64  *        within the structure; after finishing read there will be an alloc
65  *        for a site named 'Total' so that the totals line will be printed
66  *        more or less automatically.
67  *      - option -t implemented: that is every possible report will be given.
68  *      - the start and end date/time of the input files are printed; can be
69  *        dropped by the -q option at run time.
70  *      - it is now possible to use Log/Stats files from V2_LOGGING configs.
71  *        They must however not be mixed together (with each other).
72  *      - the Log/Stats files are taken from config which is passed via
73  *        Makefile at compile time. Variable to set is: newconfigdir. If the
74  *        default config can't be read the default values are used
75  *        (the config is optional!).
76  *        Note: keyword/filename must be on the same line (no continuation).
77  *      - -I option implemented to run with a different config file. In case
78  *        the file can't be opened the run is aborted!
79  *      - -q option implemented to run without environment report (default is
80  *        FALSE: print the report).
81  *      - -p option added to print protocol statistics: one for the packets
82  *        and one for the errors encountered
83  *      - reapplied patch by Scott Boyd <scott@futures.com> that I did not
84  *        get knowledge of
85  */
86 /* Log: uurate.c,v
87  * Revision 1.15  1994/04/07  21:47:11  kdburg
88  * printed 'no data avail' while there was data; layout chnaged
89  * (cosmetic only)
90  *
91  * Revision 1.14  1994/04/07  21:16:32  kdburg
92  * the layout of the protocol-used line within the LOGFILE changed
93  * from 1.04 to 1.05; both formats may be used together; output
94  * changed for packet report (columns adjusted)
95  *
96  * Revision 1.13  1994/04/04  10:04:35  kdburg
97  * cosmetic change to the packet-report (separator lines)
98  *
99  * Revision 1.12  1994/03/30  19:52:04  kdburg
100  * incorporated patch by Scott Boyd which was missing from this version
101  * of uurate.c. Left the comment in cronological order.
102  *
103  * Revision 1.11  1994/03/28  18:53:22  kdburg
104  * config not checked properly for 'logfile/statsfile' overwrites, bail-out
105  * possible; wrong file name written to log for statsfile when found
106  *
107  * Revision 1.10  1993/09/28  16:46:51  kdburg
108  * transmission failures denoted by: failed after ... in stats file
109  * have not been counted at all.
110  *
111  * Revision 1.9  1993/08/17  23:38:36  kdburg
112  * sometimes a line(site) was missing from the protocol stats due
113  * to a missing +; added option -d and -v reassing option -h to print
114  * the help; a zero was returned instead of a null-pointer by
115  * prot_sum
116  *
117  * Revision 1.8  1993/07/03  06:58:55  kdburg
118  * empty input not handled properly; assigned some buffer to input; msg
119  * not displayed when no protocol data was available
120  *
121  * Revision 1.7  1993/06/27  10:31:53  kdburg
122  * rindex was replaced by strchr must be strrchr
123  *
124  * Revision 1.6  1993/06/26  06:59:18  kdburg
125  * switch hdr_done not reset at beginning of protocol report
126  *
127  * Revision 1.5  1993/06/25  22:22:30  kdburg
128  * changed rindex to strchr; if there is no NEWCONFIG defined take
129  * appropriate action
130  *
131  * Revision 1.4  1993/06/25  20:04:07  kdburg
132  * added comment about -p option; inserted proto for rindex
133  *
134  * Revision 1.3  1993/06/25  19:31:14  kdburg
135  * major rework done; added protocol reports (normal/errors)
136  *
137  * Revision 1.2  1993/06/21  19:53:54  kdburg
138  * init
139  * */
140
141 char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2.2";
142 static char rcsid[] = "$FreeBSD$";
143 #include <ctype.h>            /* Character Classification      */
144 #include <math.h>
145 #include "uucp.h"
146 /* uucp.h includes string.h or strings.h, no include here. */
147
148 #if HAVE_SYS_PARAM_H
149 #include <sys/param.h>
150 #endif
151
152 #define _DEBUG_ 0
153
154 /*
155  * Direction of Calling and Data Transmission
156  */
157
158 #define IN      0            /* Inbound            */
159 #define OUT     1            /* Outbound            */
160
161 /*
162  *  define some limits
163  */
164 #define MAXCOLS    8        /* report has this # of columns incl. 'name' */
165 #define MAXREP     6        /* number of reports available */
166 #define MAXFNAME  64        /* max input file name length incl. path*/
167 #define MAXDNAME   8        /* max display (Hostname) name length  */
168
169 /*
170  * Data structures used to collect information
171  */
172 struct File_Stats
173     {
174     int files;                      /* Files Transferred      */
175     unsigned long bytes;      /* Data Size Transferred*/
176     double time;                /* Transmission Time      */
177     };
178
179 struct Phone_Call
180     {
181     int calls;                           /* Call Count            */
182     int succs;                           /* Successful calls     */
183     double connect_time;           /* Connect Time Spent      */
184     struct File_Stats flow[2];       /* Rcvd & Sent Data      */
185     };
186
187 struct Execution_Command
188     {
189     struct Execution_Command *next;
190     char Commandname[64];
191     int count;
192     };
193
194 struct Protocol_Summary
195     {
196     struct Protocol_Summary *next;
197     char type[3];
198     long int  pr_cnt;
199     long int  pr_psent;
200     long int  pr_present;
201     long int  pr_preceived;
202     long int  pr_eheader;
203     long int  pr_echksum;
204     long int  pr_eorder;
205     long int  pr_ereject;
206     long int  pr_pwinmin;
207     long int  pr_pwinmax;
208     long int  pr_psizemin;
209     long int  pr_psizemax;
210     };
211
212 struct Host_entry
213     {
214     struct Host_entry *next;
215     char Hostname[32];
216     struct Execution_Command *cmds;      /* Local Activities */
217     struct Phone_Call call[2];            /* In & Out Activities */
218     struct Protocol_Summary *proto;
219     };
220
221   struct Host_entry *hosts = NULL;
222   struct Host_entry *tot = NULL;
223   struct Host_entry *cur = NULL;
224   struct Execution_Command *cmd, *t_cmds = NULL;
225   struct Protocol_Summary *prot, *t_prot, *s_prot, *ss_prot = NULL;
226 /*
227  * Stuff for getopt()
228  */
229
230 extern int optind;                /* GETOPT : Option Index */
231 extern char *optarg;            /* GETOPT : Option Value */
232 #if ! HAVE_STDLIB_H
233    extern pointer *calloc();
234 #endif  /* HAVE_STDLIB_H */
235 /*
236  * Default files to read. Taken from Taylor compile-time configuration.
237  * def_logs must look like an argvec, hence the dummy argv[0].
238  * Maybe later modified by scanning the config
239  */
240
241 static char *def_logs[3] = { NULL, NULL, NULL};
242 char *I_conf = NULL;            /* points to config lib given by -I option */
243 char *D_conf = NULL;            /* points to config lib from makefile */
244 char *Tlog = NULL;              /* points to Log-file */
245 char *Tstat = NULL;             /* points to Stats-file */
246 char Pgm_name[64];              /* our pgm-name */
247 char logline[BUFSIZ+1];         /* input area */
248 char noConf[] = "- not defined -";
249 char buff[16*BUFSIZ];
250 char sbuff[2*BUFSIZ];
251
252 /*
253  * Boolean switches for various decisions
254  */
255
256   int p_done = FALSE;           /* TRUE: start date/time of file printed */
257   int hdr_done = FALSE;         /* TRUE: report header printed */
258   int show_files = FALSE;       /* TRUE: -f option given */
259   int show_calls = FALSE;       /* TRUE: -c option given */
260   int show_commands = FALSE;    /* TRUE: -x option given */
261   int show_efficiency = FALSE;  /* TRUE: -e option given */
262   int show_all = FALSE;         /* TRUE: -t option given */
263   int show_proto = FALSE;       /* TRUE: -p option given */
264   int use_stdin = FALSE;        /* TRUE: -i option given */
265   int be_quiet = FALSE;         /* TRUE: -q option given */
266   int have_files[2];            /* TRUE: [IN] or [OUT] files found */
267   int have_calls = FALSE;       /* TRUE: in/out calls found */
268   int have_commands = FALSE;    /* TRUE: found uuxqt records */
269   int have_proto = FALSE;       /* TRUE: protocol data found */
270   int no_records = TRUE;        /* FALSE: got one record from file */
271
272 /*
273  * protos
274  */
275
276 static pointer *getmem(unsigned n);
277 static void inc_cmd(struct Execution_Command **, char *name);
278 static void fmtime(double sec, char *buf);
279 static void fmbytes(unsigned long n, char *buf);
280 static void usage();
281 static int  chk_config(char *conf, int n, int type);
282 static void hdrprt(char c, int bot);
283 struct Protocol_Summary *prot_sum(struct Protocol_Summary **, char *, int);
284
285 /*
286  * BEGIN EXECUTION
287  */
288
289 int main(argc, argv)
290          int argc;
291          char *argv[];
292 {
293   FILE *Log = NULL;
294   int c; 
295   char *p, *s, *stt, *flq = NULL;
296   char Hostname[MAXHOSTNAMELEN]; /* def taken from <sys/param.h> */
297   char Filename[15];             /* filename to be printed */
298   char in_date[14];              /* holds the date info of record read*/
299   char in_time[14];              /* holds the time info of record read */
300   char dt_info[31];  /* holds the date info from the last record read */
301   char *logmsg;
302   int sent, called = IN;
303   int report = 0;            /* if <= 0 give msg that no report was avail. */
304   int junk;
305
306   /* --------------------------------------------------------------------
307    *           P r o l o g
308    * --------------------------------------------------------------------
309    */
310
311    Hostname[0] = '\0';
312    have_files[IN]= have_files[OUT]= FALSE;
313    setvbuf(stdout,sbuff,_IOFBF,sizeof(sbuff));
314
315   /*
316    * get how we've been called isolate the name from the path
317    */
318
319    if ((stt = strrchr(argv[0],'/')) != NULL)
320       strcpy(Pgm_name,++stt);
321    else
322       strcpy(Pgm_name,argv[0]);
323    def_logs[0] = Pgm_name;
324    
325   /*
326    * I wish the compiler had the #error directive!
327    */
328
329 #if !HAVE_TAYLOR_LOGGING && !HAVE_V2_LOGGING
330   fprintf(stderr,"\a%s: (E) %s\n",Pgm_name,"Your config of Taylor UUCP is not yet supported.");
331   fprintf(stderr,"%s: (E) %s\n",Pgm_name,"Current support is for V2 or TAYLOR logging only.");
332   puts("   Run aborted due to errors\n")
333   exit(1);
334 #endif
335
336   /*
337    *  get some mem to store the default config name (def's are in
338    *  policy.h )
339    */
340
341   if (sizeof(NEWCONFIGLIB) > 1)       /* defined at compile time */
342   {
343      D_conf = (char *)getmem((sizeof(NEWCONFIGLIB) + sizeof("/config")));
344      strcpy(D_conf,NEWCONFIGLIB);       /* passed by makefile */
345      strcat(D_conf,"/config");
346   }
347   Tlog   = (char *)getmem(sizeof(LOGFILE));
348   Tstat  = (char *)getmem(sizeof(STATFILE));
349   Tlog   = LOGFILE;
350   Tstat  = STATFILE;
351   
352   /*
353    * Process the command line arguments
354    */
355
356   while((c = getopt(argc, argv, "I:s:cfdexaitphv")) != EOF)
357   {
358     switch(c)
359     {
360          case 'h':
361                   (void) usage();
362          case 's':
363                   strcpy(Hostname, optarg);
364                     break;
365          case 'c':
366                   show_calls = TRUE;
367                   ++report;
368                   break;
369          case 'd':
370                   printf("%s: (I) config-file default: %s\n",Pgm_name,D_conf);
371                   exit (0);
372                   break;
373          case 'f':
374                   show_files = TRUE;
375                   ++report;
376                   break;
377          case 'x':
378                   show_commands = TRUE;
379                   ++report;
380                   break;
381          case 'e':
382                   show_efficiency = TRUE;
383                   ++report;
384                   break;
385          case 'a':
386                   show_calls = show_files = show_commands = show_efficiency = TRUE;
387                   report = 4;
388                   break;
389          case 'i':
390                   use_stdin = TRUE;
391                   break;
392          case 't':
393                   show_all = TRUE;
394                   report = MAXREP;
395                   break;
396          case 'p':
397                   show_proto = TRUE;
398                   ++report;
399                   break;
400          case 'I':
401                   I_conf = (char *)getmem(sizeof(optarg));
402                   I_conf = optarg;
403                   break;
404                   case 'q':
405                   be_quiet = TRUE;
406                   break;
407          case 'v':
408                   printf("%s\n",rcsid);
409                   exit (0);
410          default :
411                   (void) usage();
412      }
413   }
414   if (report == 0)           /* no options given */
415      ++report;               /* at least summary can be printed */
416   if (! be_quiet)
417      hdrprt('i',0);         /* print header for environment info */
418
419   /*
420    * Adjust argv and argc to account for the args processed above.
421    */
422
423   argc -= (optind - 1);
424   argv += (optind - 1);
425
426   /*
427    * If further args present, Assume rest are logfiles for us to process
428    * which should be given in pairs (log plus stat) otherwise the results may
429    * not come out as expected! If no further args are present take input from 
430    * Log and Stat files provided in the compilation environment of Taylor UUCP. 
431    * If -i was given, Log already points to stdin and no file args are accepted.
432    */
433
434    if (use_stdin)           /* If -i, read from stdin */
435    {
436       if (argc != 1)            /* No file arguments allowed */
437       {
438          fprintf(stderr,"\a%s: (E) %s\n",Pgm_name,
439                          "it's not posssible to give file args with '-i'");
440          (void) usage();
441       }
442       else
443       {
444          argc = 2;
445          Log = stdin;
446          if (! be_quiet)
447             puts("   Input from stdin; no other files will be used\n");
448       }
449    }
450    else
451    {
452       if (argc != 1)                    /* file arguments are present */
453       {
454          if (! be_quiet)
455             puts("   No defaults used; will use passed file arguments\n");
456       }
457       else                            /* Read from current logs */
458       {
459          def_logs[1] = Tlog;      /* prime the */
460          def_logs[2] = Tstat;     /*   file names */   
461          if (! be_quiet)
462             printf("   Config for this run: ");
463
464          if (I_conf != NULL)
465          {
466             junk = 0;
467             if (! be_quiet)
468                 printf("%s\n",I_conf);
469             if (0 != (chk_config(I_conf,be_quiet,junk)))
470                return (8);
471          }
472          else
473          {
474            if (D_conf != NULL)
475            {
476               junk = 1;             /* indicate default (compiled) config */
477               if (! be_quiet)
478                  printf("%s\n",D_conf);
479               chk_config(D_conf,be_quiet,junk);
480            }
481            else
482               if (! be_quiet)
483                  printf("%s\n",noConf);
484          }
485          def_logs[1] = Tlog;      /* final setting of */
486          def_logs[2] = Tstat;     /*   file names */   
487          argv = def_logs;            /* Bash argvec to log/stat files */
488          argc = sizeof(def_logs) / sizeof(def_logs[0]);
489        }
490    }
491
492   /* --------------------------------------------------------------------
493    *                 MAIN LOGFILE PROCESSING LOOP
494    * --------------------------------------------------------------------
495    */
496
497   if (!use_stdin)
498   {
499      if (argc < 3 && ! be_quiet)
500      {
501         puts("   (W) there is only one input file!");
502         puts("   (W) some reports may not be printed");
503      }
504      if (! be_quiet)
505         hdrprt('d',0);      /* give subheaderline  */
506   }
507
508   while (argc > 1)
509   {
510     if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
511     {
512        perror(argv[1]);
513        exit (8);
514     }
515     setvbuf(Log,buff,_IOFBF,sizeof(buff));
516     if ((flq = strrchr(argv[1], '/')) == NULL)
517        strncpy(Filename,argv[1],sizeof(Filename)-1);
518     else
519        strncpy(Filename,++flq,sizeof(Filename)-1);
520        
521     strcpy(in_date,"   n/a");
522     strcpy(in_time,"   n/a");
523     p_done = FALSE;             /* no info printed yet */
524     no_records = TRUE;          /* not read any record yet */
525
526     /*
527      * Read each line of the logfile and collect information
528      */
529
530     while (fgets(logline, sizeof(logline), Log))
531     {
532         /*
533          * The host name of the other end of the connection is
534          * always the second field of the log line, whether we
535          * are reading a Log file or a Stats file. Set 'p' to
536          * point to the second field, null-terminated. Skip
537          * the line if something is funny. V2 and Taylor ar identical
538          * up to this part. Put out the start/end date of the files read;
539          */
540
541       if (NULL == (p = strchr(logline, ' ')))
542          continue;
543       no_records = FALSE;          /* got one (usable) record at least */
544       ++p;
545
546       if (NULL != (stt = strchr(p, '(')))
547       {
548          if (! p_done && ! use_stdin && ! be_quiet)
549          {  
550
551 #if HAVE_TAYLOR_LOGGING
552          sscanf(++stt,"%s%*c%[^.]",in_date,in_time);
553 #endif /* HAVE_TAYLOR_LOGGING */
554
555 #if HAVE_V2_LOGGING
556          sscanf(++stt,"%[^-]%*c%[1234567890:]",in_date,in_time);
557 #endif /* HAVE_V2_LOGGING */
558
559             printf("   %-14s %10s %8s",Filename, in_date, in_time);
560             strcpy(in_date,"   n/a");         /* reset to default */
561             strcpy(in_time,"   n/a");
562             p_done = TRUE;
563          }
564          else
565          {
566             if (! use_stdin && ! be_quiet)  /* save for last time stamp prt. */
567                strncpy(dt_info,++stt,sizeof(dt_info)-1);
568          }
569       }
570
571       if (NULL != (s = strchr(p, ' ')))
572          *s = '\0';
573       for (s = p; *s; ++s)
574           if (isupper(*s))
575              *s = tolower(*s);
576
577         /*
578          * Skip this line if we got -s <host> and
579          * this line does not contain that host name.
580          * Don't skip the `incoming call' line with the system name `-'.
581          */
582
583       if (Hostname[0] != '\0')
584          if ( (p[0] != '-' || p[1] != '\0') && 0 != strcmp(p, Hostname) )
585             continue;
586
587         /*
588          * We are within a call block now. If this line is a file
589          * transfer record, determine the direction. If not then
590          * skip the line if it is not interesting.
591          */
592       
593       if ((s = strchr(++s, ')')) == NULL)
594          continue;
595
596 #if ! HAVE_TAYLOR_LOGGING
597 #if HAVE_V2_LOGGING
598       if ((strncmp(s,") (",3)) ==  0)      /* are we in stats file ?) */
599          if ((s = strchr(++s, ')')) == NULL)
600             continue;                     /* yes but strange layout */
601 #endif /* HAVE_V2_LOGGING */
602 #endif /* ! HAVE_TAYLOR_LOGGING  */ 
603
604        logmsg = s + 2;            /* Message is 2 characters after ')' */
605        if ((0 != strncmp(logmsg, "Call complete", 13)) &&
606           (0 != strncmp(logmsg, "Calling system", 14)) &&
607           (0 != strncmp(logmsg, "Incoming call", 13)) &&
608           (0 != strncmp(logmsg, "Handshake successful", 20)) &&
609           (0 != strncmp(logmsg, "Retry time not", 14)) &&
610           (0 != strncmp(logmsg, "ERROR: All matching ports", 25)) &&
611           (0 != strncmp(logmsg, "Executing", 9)) &&
612           (0 != strncmp(logmsg, "Protocol ", 9)) &&
613           (0 != strncmp(logmsg, "sent ", 5)) &&
614           (0 != strncmp(logmsg, "received ", 9)) &&
615           (0 != strncmp(logmsg, "failed after ", 13)) &&
616           (0 != strncmp(logmsg, "Errors: ", 8)))
617           continue;
618
619         /*
620          * Find the Host_entry for this host, or create a new
621          * one and link it on to the list.
622          */
623
624        if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
625        {
626           struct Host_entry *e, *last;
627
628           for (e= cur= hosts; cur != NULL ; e= cur, cur= cur->next)
629               if (0 == strcmp(cur->Hostname, p))
630                  break;
631               if (cur == NULL)
632               {
633                  cur= (struct Host_entry *)getmem(sizeof(*hosts));
634                  strcpy(cur->Hostname, p);
635                  if (hosts == NULL)
636                     e= hosts= cur;
637                  else {
638                     e = hosts;
639                     last = NULL;
640                     while (e != NULL) {
641                           if (strcmp(e->Hostname, cur->Hostname) <= 0) {
642                              if (e->next == NULL) {
643                                 e->next = cur;
644                                 break;
645                              }
646                              last = e;
647                              e = e->next;
648                           }
649                           else {
650                              cur->next = e;
651                              if (last == NULL)
652                                 hosts = cur;
653                              else
654                                 last->next = cur;
655                              break;
656                           }
657                      }   /*  while (e != NULL) */ 
658                  }    /*  hosts == NULL  */ 
659               }   /* cur == NULL */
660        }
661
662         /*
663          * OK, if this is a uuxqt record, find the Execution_Command
664          * structure for the command being executed, or create a new
665          * one. Then count an execution of this command.
666          * (Log file only)
667          */
668
669         if (0 == strncmp(logmsg, "Executing", 9))
670         {
671             if (NULL == (p = strchr(logmsg, '(')))
672                continue;
673             if ((s = strpbrk(++p, " )")) == NULL)
674                continue;
675             *s = '\0';
676             inc_cmd(&cur->cmds, p);
677             inc_cmd(&t_cmds, p);
678             have_commands = TRUE;
679             continue;
680         }
681
682         /*
683          * Count start of outgoing call.
684          */
685
686         if ((0 == strncmp(logmsg, "Calling system", 14)) ||
687             (0 == strncmp(logmsg, "Retry time not", 14)) ||
688             (0 == strncmp(logmsg, "ERROR: All matching ports", 25)))
689         {
690            called = OUT;
691            cur->call[OUT].calls++;
692            have_calls = TRUE;
693            s_prot = NULL;              /* destroy pointer to protocol */
694            continue;
695         }
696
697         /*
698          * Count start of incoming call.
699          */
700
701         if (0 == strncmp(logmsg, "Incoming call", 13))
702         {
703            called = IN;
704            s_prot = NULL;              /* destroy pointer to protocol */
705            continue;
706         }
707
708         /*
709          * On an incoming call, get system name from the second line.
710          * Get protocol type and size/window too
711          */
712
713         if (0 == strncmp(logmsg, "Handshake successful", 20))
714         {
715            if ( called==IN )
716               cur->call[IN].calls++;
717            have_calls = TRUE;
718            s_prot = NULL;              /* destroy pointer to protocol */
719            if (NULL == (p = strchr(logmsg, '(')))
720               continue;
721            if (0 == strncmp(p, "(protocol ", 10))
722            {
723               if (NULL == (p = strchr(p, '\'')))
724                  continue;
725               ss_prot = prot_sum(&cur->proto, ++p, 1);
726               s_prot  = prot_sum(&t_prot, p, 1);
727               continue;
728            }
729         }
730
731         /*
732          * check protocol type and get stats
733          *
734          */
735
736         if (0 == strncmp(logmsg, "Protocol ", 9))
737         {
738            s_prot = NULL;              /* destroy pointer to protocol */
739            if (NULL == (p = strchr(logmsg, '\'')))
740               continue;
741            ss_prot = prot_sum(&cur->proto, ++p, 2);
742            s_prot = prot_sum(&t_prot, p, 2);
743            continue;
744         }
745
746         /*
747          * check protocol errors. Unfortunately the line does not contain
748          * the used protocol, so if any previous line did contain that
749          * information and we did process that line we will save the pointer
750          * to that particular segment into s_prot. If this pointer is not set
751          * the error info is lost for we don't know where to store.
752          *
753          */
754
755         if ((0 == strncmp(logmsg, "Errors: header", 14)) && s_prot != NULL)
756         {
757           int i1,i2,i3,i4 = 0;
758           sscanf(logmsg,"%*s %*s %d%*c%*s %d%*c%*s %d%*c%*s %*s%*c %d",&i1,&i2,&i3,&i4);
759           ss_prot->pr_eheader += i1;
760           ss_prot->pr_echksum += i2;
761           ss_prot->pr_eorder += i3;
762           ss_prot->pr_ereject += i4;
763           s_prot->pr_eheader += i1;
764           s_prot->pr_echksum += i2;
765           s_prot->pr_eorder += i3;
766           s_prot->pr_ereject += i4;
767           s_prot = NULL;
768           continue;
769         }
770
771         /*
772          * Handle end of call. Pick up the connect time.
773          * position is on the closing paren of date/time info
774          * i.e: ) text....  
775          */
776
777         if (0 == strncmp(logmsg, "Call complete", 13))
778         {
779            cur->call[called].succs++;
780            s_prot = NULL;              /* destroy pointer to protocol */
781            if (NULL == (s = strchr(logmsg, '(')))
782               continue;
783            cur->call[called].connect_time += atof(s+1);
784            continue;
785         }
786
787         /*
788          * We are definitely in a Stats file now.
789          * If we reached here, this must have been a file transfer
790          * record. Count it in the field corresponding to the
791          * direction of the transfer. Count bytes transferred and
792          * the time to transfer as well.
793          * Position within the record is at the word 'received' or 'sent'
794          * depending on the direction.
795          */
796
797         sent = IN;              /* give it an initial value */
798         if (0 == strncmp(logmsg, "failed after ",13))
799            logmsg += 13;        /* the transmission failed for any reason */
800                                 /* so advance pointer */
801         if (0 == strncmp(logmsg, "sent", 4)) 
802            sent = OUT;
803         else if (0 == strncmp(logmsg, "received", 8))
804                 sent = IN;
805         have_files[sent] = TRUE;
806         cur->call[called].flow[sent].files++;
807         if (NULL == (s = strchr(logmsg, ' ')))       /* point past keyword */
808            continue;                                 /* nothing follows */
809                                    /* we should be at the bytes column now*/
810 #if HAVE_TAYLOR_LOGGING
811         cur->call[called].flow[sent].bytes += atol(++s);
812 #endif /* HAVE_TAYLOR_LOGGING */
813 #if HAVE_V2_LOGGING
814         if (NULL == (s = strpbrk(s, "0123456789")))  /* point to # bytes */
815            continue;
816         cur->call[called].flow[sent].bytes += atol(s);
817 #endif /* HAVE_V2_LOGGING */
818         if (NULL == (s = strchr(s, ' ')))          /* point past # of bytes */
819            continue;
820         if (NULL == (s = strpbrk(s, "0123456789"))) /* point to # of seconds */
821            continue;
822         cur->call[called].flow[sent].time += atof(s);
823
824     }   /* end of while (fgets(logline...)) */
825
826     if (stt != NULL && ! use_stdin && ! be_quiet && ! no_records)
827     {  
828
829 #if HAVE_TAYLOR_LOGGING
830          sscanf(dt_info,"%s%*c%[^.]",in_date,in_time);
831 #endif /* HAVE_TAYLOR_LOGGING */
832
833 #if HAVE_V2_LOGGING
834          sscanf(dt_info,"%[^-]%*c%[1234567890:]",in_date,in_time);
835 #endif /* HAVE_V2_LOGGING */
836
837        printf("  %10s %8s\n",in_date, in_time);
838        p_done = FALSE;
839     }
840     if (Log != stdin)
841     {
842        if (0 != ferror(Log))
843        {
844           if (! be_quiet)
845              printf("   %-14s data is incomplete; read error"," ");
846           else
847             fprintf(stderr,"%s (W) data is incomplete; read error on %s\n",
848                                    Pgm_name,argv[1]);
849        }
850        else
851        {
852           if (! be_quiet && no_records)
853              printf("   %-14s %10s\n",Filename, " is empty ");
854        }         
855      }
856      fclose(Log);
857
858     argc--;
859     argv++;
860   }  /* end of while (for (argv ....) */
861
862   /*
863    *   do we have *any* data ?
864    */
865
866   if (cur == NULL)
867   {
868      puts("\n(I) Sorry! No data is available for any requested report\n");
869      exit(0);
870   }
871
872   /*
873    *   truncate hostname, alloc the structure holding the totals and
874    *   collect the totals data
875    */
876
877   for (cur = hosts; cur != NULL;cur = cur->next)
878   {
879       cur->Hostname[MAXDNAME] = '\0';
880       if (cur->next == NULL)            /* last so will have to alloc totals */
881       {
882          cur->next = (struct Host_entry *)getmem(sizeof(*hosts));
883          strcpy(cur->next->Hostname,"Totals");
884          tot = cur->next;
885          for (cur = hosts; cur != NULL; cur = cur->next)
886          {
887            if (cur->next != NULL)        /* don't count totals to totals */
888            {
889               tot->call[IN].flow[IN].bytes += cur->call[IN].flow[IN].bytes;
890               tot->call[OUT].flow[IN].bytes += cur->call[OUT].flow[IN].bytes;
891               tot->call[IN].flow[OUT].bytes  += cur->call[IN].flow[OUT].bytes;
892               tot->call[OUT].flow[OUT].bytes += cur->call[OUT].flow[OUT].bytes;
893               tot->call[IN].flow[IN].time  += cur->call[IN].flow[IN].time;
894               tot->call[OUT].flow[IN].time += cur->call[OUT].flow[IN].time;
895               tot->call[IN].flow[OUT].time  += cur->call[IN].flow[OUT].time;
896               tot->call[OUT].flow[OUT].time += cur->call[OUT].flow[OUT].time;
897               tot->call[IN].flow[IN].files  += cur->call[IN].flow[IN].files;
898               tot->call[OUT].flow[IN].files += cur->call[OUT].flow[IN].files;
899               tot->call[IN].flow[OUT].files  += cur->call[IN].flow[OUT].files;
900               tot->call[OUT].flow[OUT].files += cur->call[OUT].flow[OUT].files;
901               tot->call[OUT].succs += cur->call[OUT].succs; 
902               tot->call[OUT].calls += cur->call[OUT].calls; 
903               tot->call[OUT].connect_time += cur->call[OUT].connect_time;
904               tot->call[IN].succs += cur->call[IN].succs; 
905               tot->call[IN].calls += cur->call[IN].calls; 
906               tot->call[IN].connect_time += cur->call[IN].connect_time;
907            }
908          }
909          break;                   /* totals is last in Host_Entry */
910      }
911   }
912
913   /*
914    *                       ***********
915    *                       * REPORTS *
916    *                       ***********
917    */
918
919 #if _DEBUG_
920   putchar('\n');
921 #endif
922
923   /* ------------------------------------------------------------------
924    *
925    * Summary report only when no other report except option -t is given
926    *
927    * I know, this code could be tightened (rbd)...
928    * ------------------------------------------------------------------
929    */
930
931   if (  !(show_calls || show_files ||
932           show_efficiency || show_commands || show_proto) || show_all)
933   {
934      if (have_calls || have_files[IN] || have_files[OUT])
935      {
936         char t1[32], t2[32], t3[32], t4[32], t5[32];
937         long ib, ob, b, rf, sf;
938         double it, ot, ir, or;
939
940         hdr_done = FALSE;
941         for (cur = hosts; cur != NULL; cur = cur->next)
942         {
943            ib = (cur->call[IN].flow[IN].bytes +
944                 cur->call[OUT].flow[IN].bytes);
945            fmbytes(ib, t1);
946
947            ob = (cur->call[IN].flow[OUT].bytes +
948                 cur->call[OUT].flow[OUT].bytes);
949            fmbytes(ob, t2);
950
951                  /* Don't print null-lines. */
952            if (( b= ib+ob ) == 0 )
953               continue;
954                  /* Don't print the header twice. */
955              if (! hdr_done)
956              {
957                 hdrprt('s',0);            /* print the header line(s) */
958                 hdr_done = TRUE;
959              }
960
961              fmbytes(b, t3);
962
963              it = cur->call[IN].flow[IN].time +
964                   cur->call[OUT].flow[IN].time;
965              fmtime(it, t4);
966
967              ot = cur->call[IN].flow[OUT].time +
968                   cur->call[OUT].flow[OUT].time;
969              fmtime(ot, t5);
970
971              rf = cur->call[IN].flow[IN].files +
972                   cur->call[OUT].flow[IN].files;
973
974              sf = cur->call[IN].flow[OUT].files +
975                   cur->call[OUT].flow[OUT].files;
976
977              ir = (it == 0.0) ? 0.0 : (ib / it);
978              or = (ot == 0.0) ? 0.0 : (ob / ot);
979
980              if (cur->next == NULL)            /* totals line reached ? */
981                 hdrprt('s',1);                 /* print the separator line */
982
983              printf("%-8s %4d %4d %9s %9s %9s %9s %9s %5.0f %5.0f\n",
984                    cur->Hostname, rf, sf,
985                    t1, t2, t3, t4, t5,
986                    ir, or);
987         } 
988         if (! hdr_done)
989         {
990             puts("\n(I) No data found to print Compact summary report");
991         }
992      }
993      else
994      {
995         puts("\n(I) No data available for Compact summary report");
996         --report;
997      }
998   }
999
1000   /* ------------------------------------------------------------------
1001    *                     Protocol statistics report
1002    * ------------------------------------------------------------------
1003    */
1004
1005   if (show_proto || show_all)
1006   {
1007      if (have_proto)
1008      {
1009                         /* ---------------------  */
1010                         /* protocol packet report */
1011                         /* ---------------------  */
1012
1013         char *type = NULL;
1014         hdr_done = FALSE;
1015         for (cur = hosts; cur != NULL; cur = cur->next)
1016         {
1017             type = cur->Hostname;
1018             if (cur->next == NULL)
1019             {
1020                if (hdr_done)
1021    puts("-------------------------------------------------------------------");
1022             cur->proto = t_prot;
1023             }
1024             for (prot = cur->proto; prot != NULL; prot = prot->next)
1025             {
1026                 if (! hdr_done)
1027                 {
1028                     hdrprt('p',0);            /* print the header line(s) */
1029                     hdr_done = TRUE;
1030                 }
1031                 printf("%-8s %3s  %4d %4d %5d %4d    %10d %7d %10d\n",
1032                                     type == NULL ? " ":cur->Hostname,
1033                                     prot->type,
1034                                     prot->pr_psizemin,
1035                                     prot->pr_psizemax,
1036                                     prot->pr_pwinmin,
1037                                     prot->pr_pwinmax,
1038                                     prot->pr_psent,
1039                                     prot->pr_present,
1040                                     prot->pr_preceived);
1041                 type = NULL;
1042              }
1043          }
1044          if (! hdr_done)
1045             puts("\n(I) No data found to print Protocol packet report");
1046
1047                         /* --------------------- */
1048                         /* protocol error report */
1049                         /* --------------------- */
1050
1051         type = NULL;
1052         hdr_done = FALSE;
1053         if (t_prot != NULL)
1054         {
1055            for (cur = hosts; cur != NULL; cur = cur->next)
1056            {
1057                type = cur->Hostname;
1058                if (cur->next == NULL)
1059                {
1060                   if (hdr_done)
1061         puts("--------------------------------------------------------------");
1062                cur->proto = t_prot;
1063                }
1064
1065                for (prot = cur->proto; prot != NULL; prot = prot->next)
1066                {
1067                    if ((prot->pr_eheader + prot->pr_echksum +
1068                       prot->pr_eorder + prot->pr_ereject) != 0)
1069                    {
1070                       if (! hdr_done)
1071                       {
1072                          hdrprt('p',1);       /* print the header line(s) */
1073                          hdr_done = TRUE;
1074                       }
1075                       printf("%-8s %3s  %11d %11d  %11d %11d\n",
1076                                     type == NULL ? " ":cur->Hostname,
1077                                     prot->type,
1078                                     prot->pr_eheader,
1079                                     prot->pr_echksum,
1080                                     prot->pr_eorder,
1081                                     prot->pr_ereject);
1082                       type = NULL;
1083                    } 
1084                 }
1085             }
1086         }
1087         if (! hdr_done)
1088            puts("\n(I) No data found to print Protocol error report");
1089      }
1090      else
1091      {
1092         puts("\n(I) No data available for Protocol reports");
1093         --report;
1094      }
1095   }
1096
1097   /* ------------------------------------------------------------------
1098    *                     Call statistics report
1099    * ------------------------------------------------------------------
1100    */
1101
1102   if (show_calls || show_all)
1103   {
1104      if (have_calls)
1105      {
1106         char t1[32], t2[32];
1107
1108         hdr_done = FALSE;
1109         for (cur = hosts; cur != NULL; cur = cur->next)
1110         {
1111             if (cur->next == NULL)
1112             {
1113                if (hdr_done)
1114                   hdrprt('c',1);                 /* print the separator line */
1115             }
1116             else
1117             {
1118                   /* Don't print null-lines on deatail lines */
1119                if ( cur->call[OUT].calls + cur->call[IN].calls == 0 )
1120                   continue;
1121
1122                  /* Don't print the header twice. */
1123                if (! hdr_done)
1124                {
1125                    hdrprt('c',0);               /* print the header line(s) */
1126                    hdr_done = TRUE;
1127                }
1128             }
1129             if ( cur->call[OUT].calls > 0 || cur->next == NULL)
1130             {
1131                fmtime(cur->call[OUT].connect_time, t1);
1132                printf( "   %-8s %7d %7d %7d %9s",
1133                      cur->Hostname,
1134                      cur->call[OUT].succs,
1135                      cur->call[OUT].calls - cur->call[OUT].succs,
1136                      cur->call[OUT].calls,
1137                      t1 );
1138              }
1139              else
1140              {
1141                 printf( "   %-42s", cur->Hostname );
1142              }
1143              if ( cur->call[IN].calls > 0 || cur->next == NULL )
1144              {
1145                 fmtime(cur->call[IN].connect_time, t2);
1146                 printf( " %7d %7d %7d %9s",
1147                        cur->call[IN].succs,
1148                        cur->call[IN].calls - cur->call[IN].succs,
1149                        cur->call[IN].calls,
1150                        t2 );
1151               }
1152               putchar('\n');
1153         }
1154         if (! hdr_done)
1155         {
1156             puts("\n(I) No data found to print Call statistics report");
1157         }
1158      }
1159      else
1160      {
1161         puts("\n(I) No data available for Call statistics report");
1162         --report;
1163      }
1164   }
1165
1166   /* ------------------------------------------------------------------
1167    *                    File statistics report
1168    * ------------------------------------------------------------------
1169    */
1170
1171   if (show_files || show_all)
1172   {
1173      if (have_files[IN] || have_files[OUT])
1174      {
1175         char t1[32], t2[32];
1176         double rate = 0, time = 0;
1177         int b = 0; 
1178         int lineOut = 0;
1179
1180         hdr_done = FALSE;
1181         for (cur = hosts; cur != NULL; cur = cur->next)
1182         {
1183             lineOut = 0;
1184             for (sent= IN; sent <= OUT; ++sent)
1185             {  
1186                 b    = cur->call[IN].flow[sent].bytes +
1187                        cur->call[OUT].flow[sent].bytes;
1188                 time = cur->call[IN].flow[sent].time +
1189                        cur->call[OUT].flow[sent].time;
1190
1191                    /* Don't print null-lines on detail lines. */
1192                 if ( (b != 0 && time != 0.0) || cur->next == NULL)
1193                 {
1194                       /* Don't print the header twice. */
1195                    if (! hdr_done)
1196                    {
1197                       hdrprt('f',0);          /* print the header line(s) */
1198                       hdr_done = TRUE;
1199                    }
1200                    fmbytes(b, t1);
1201                    rate = (cur->call[IN].flow[sent].bytes +
1202                           cur->call[OUT].flow[sent].bytes) / time;
1203                    fmtime((cur->call[IN].flow[sent].time +
1204                           cur->call[OUT].flow[sent].time), t2);
1205
1206                    if (lineOut == 0)         /* first half not printed yet ? */
1207                    {
1208                       if (cur->next == NULL)       /* totals line ? */
1209                          hdrprt('f',1);          /* print the separator line */
1210                       printf("   %-8s", cur->Hostname);
1211                       if (sent == OUT)     /* can't happen whith totals line */
1212                          printf("%34s", " ");
1213                     }
1214
1215                     printf(" %5d %11s %9s %5.0f",
1216                           cur->call[IN].flow[sent].files +
1217                           cur->call[OUT].flow[sent].files,
1218                           t1, t2, rate);
1219                     lineOut = 1;
1220                  }
1221             }    /* end:  for (sent ... ) */  
1222             if (lineOut)
1223                 printf("\n");
1224         }    /* end:  for (cur= ... ) */
1225         if (! hdr_done)
1226         {
1227            puts("\n(I) No data found to print File statistics report");
1228         }
1229      }
1230      else
1231      {
1232         puts("\n(I) No data available for File statistics report");
1233         --report;
1234      }
1235   }
1236
1237   /* ------------------------------------------------------------------
1238    *                       Efficiency report
1239    * ------------------------------------------------------------------
1240    */
1241
1242   if (show_efficiency || show_all)
1243   {
1244      if (have_files[IN] || have_files[OUT])
1245      {
1246         char t1[32], t2[32], t3[32];
1247         double total, flow;
1248
1249         hdr_done = FALSE;
1250         for (cur = hosts; cur != NULL; cur = cur->next)
1251         {
1252                  /* Don't print null-lines. */
1253             if ( 0 == cur->call[IN].flow[IN].files +
1254                       cur->call[IN].flow[OUT].files +
1255                       cur->call[OUT].flow[IN].files +
1256                       cur->call[OUT].flow[OUT].files ||
1257                  0.0 == (total= cur->call[IN].connect_time +
1258                         cur->call[OUT].connect_time))
1259             {
1260                continue;
1261             }
1262
1263             if (! hdr_done)
1264             {
1265                hdrprt('e',0);                 /* print the header line(s) */
1266                hdr_done = TRUE;
1267             }
1268
1269             flow = cur->call[IN].flow[IN].time + 
1270                    cur->call[IN].flow[OUT].time +
1271                    cur->call[OUT].flow[IN].time +
1272                    cur->call[OUT].flow[OUT].time;
1273              fmtime(total, t1);
1274              fmtime(flow, t2);
1275              fmtime(total-flow, t3);
1276
1277             if (cur->next == NULL)
1278                hdrprt('e',1);                 /* print the separator line */
1279
1280             printf("   %-8s %10s %10s %10s %7.2f\n",
1281                    cur->Hostname, t1, t2, t3,
1282             flow >= total ? 100.0: flow*100.0/total);
1283         }   /* end: for (cur= .. */
1284         if (! hdr_done)
1285         {
1286            puts("\n(I) No data found to print Efficiency report");
1287         }
1288      }
1289      else
1290      {
1291         puts("\n(I) No data available for Efficiency report");
1292         --report;
1293      }
1294   }
1295
1296   /* ------------------------------------------------------------------
1297    *                   Command execution report
1298    * ------------------------------------------------------------------
1299    */
1300
1301   if (show_commands || show_all)
1302   { 
1303      if (have_commands)
1304      {
1305         int ncmds, i, match;
1306
1307         /* 
1308          *  layout the header line. The column's header is the command name
1309          */
1310
1311         hdr_done = FALSE;
1312         for (ncmds= 0, cmd= t_cmds;
1313              cmd != NULL && ncmds <= MAXCOLS-1;
1314              ncmds++, cmd= cmd->next)
1315         {
1316             if (! hdr_done)
1317             {
1318                puts("\nCommand executions:");
1319                puts("-------------------");
1320                puts("   Name of ");
1321                fputs("   site    ", stdout);
1322                hdr_done = TRUE;
1323             }
1324             printf(" %7s", cmd->Commandname);
1325          }
1326          if (! hdr_done)
1327          {
1328             puts("\n(I) No data found to print Command execution report");
1329          }
1330          else
1331          {
1332            fputs("\n   --------", stdout);
1333            for (i= 0; i<ncmds; i++)
1334                fputs("  ------", stdout);
1335            putchar('\n');
1336
1337         /* 
1338          *  print out the number of executions for each host/command
1339          */
1340
1341            for (cur= hosts; cur != NULL; cur= cur->next)
1342            {
1343                if (cur->next == NULL)
1344                   break;
1345
1346                  /* Don't print null-lines. */
1347
1348               if (cur->cmds == NULL)
1349                  continue;
1350
1351               printf("   %-8s", cur->Hostname);
1352               for (cmd= t_cmds; cmd != NULL; cmd= cmd->next)
1353               {
1354                   struct Execution_Command *ec;
1355                   match = FALSE;
1356                   for(ec= cur->cmds; ec != NULL; ec= ec->next)
1357                   {
1358                      if ( 0 == strcmp(cmd->Commandname, ec->Commandname) )
1359                      { 
1360                         printf(" %7d", ec->count);
1361                         match = TRUE;
1362                         break;
1363                      }
1364                    }
1365                    if (! match)
1366                       printf("%8s"," ");    /* blank out column */
1367                }
1368                putchar('\n');
1369             }
1370
1371          /*
1372           *  print the totals line 
1373           */
1374
1375             fputs("   --------", stdout);
1376             for (i= 0; i<ncmds; i++)
1377                 fputs("--------", stdout);
1378             printf("\n   %-8s", cur->Hostname);
1379             for (cmd= t_cmds; cmd != NULL; cmd= cmd->next)
1380             {
1381                 printf(" %7d", cmd->count);
1382             }
1383             putchar('\n');
1384         }
1385      }
1386      else
1387      {
1388         puts("\n(I) No data available for Command execution report");
1389         --report;
1390      }
1391   }
1392   if (report <= 0 )       /* any reports ? */
1393   {
1394      puts("\n(I) Sorry! No data is available for any requested report\n");
1395      exit(1);
1396   }
1397
1398   puts("\n(I) End of reports\n");
1399   exit (0);
1400 }  /* end of main */
1401
1402   /* ------------------------------------------------------------------
1403    *                       * Functions *
1404    * ------------------------------------------------------------------
1405    */
1406
1407   /* ------------------------------------------------------------------
1408    *                    display the help 
1409    * ------------------------------------------------------------------
1410    */
1411
1412 void usage()
1413 {
1414   fprintf(stderr,"Usage uurate [-acdefhiptvx] [-s hostname] [-I config file] [logfile(s) ... logfile(s)]\n");
1415   fprintf(stderr,"where:\t-a\tPrint reports c,e,f,x\n");
1416   fprintf(stderr,"\t-c\tReport call statistics\n");
1417   fprintf(stderr,"\t-d\tPrint the name of the default config file\n");
1418   fprintf(stderr,"\t-e\tReport efficiency statistics\n");
1419   fprintf(stderr,"\t-f\tReport file transfer statistics\n");
1420   fprintf(stderr,"\t-h\tPrint this help\n");
1421   fprintf(stderr,"\t-i\tRead log info from standard input\n");
1422   fprintf(stderr,"\t-p\tReport protocol statistics\n");
1423   fprintf(stderr,"\t-t\tAll available reports plus compact summary report\n");
1424   fprintf(stderr,"\t-v\tPrint version number\n");
1425   fprintf(stderr,"\t-x\tReport command execution statistics\n");
1426   fprintf(stderr,"\t-s host\tReport activities involving HOST only\n");
1427   fprintf(stderr,"\t-I config Use config instead of standard config file\n");
1428   fprintf(stderr,"If no report options given, a compact summary report is printed.\n");
1429   fprintf(stderr,"log files should be given as pairs that is Log/Stats ... .\n");
1430   fprintf(stderr,"If neither -i nor logfiles given, those names found in config will be used\n");
1431
1432   exit (1);
1433 }
1434
1435  /* ------------------------------------------------------------------
1436   *                    getmem - get some memory
1437   * ------------------------------------------------------------------
1438   */
1439
1440 static pointer *getmem(n)
1441                     unsigned n;
1442 {
1443   pointer *p;
1444
1445   if( NULL== (p= calloc(1, n)) )
1446     {
1447       fprintf(stderr,"\a%s (C) %s\n",Pgm_name, "out of memory\n");
1448       exit (8);
1449     }
1450   return p;
1451 }
1452
1453   /* ------------------------------------------------------------------
1454    *             inc_cmd - increment command count
1455    * ------------------------------------------------------------------
1456    */
1457
1458 static void inc_cmd(cmds, name)
1459                     struct Execution_Command **cmds;
1460                     char *name;
1461 {
1462   int cnt = 0;
1463   struct Execution_Command *cmd, *ec;
1464
1465   for (ec = cmd = *cmds; cmd != NULL; ec= cmd, cmd= cmd->next, cnt++)
1466       if ( (0 == strcmp(cmd->Commandname, name)) ||
1467            (0 == strcmp(cmd->Commandname, "Misc.")) )
1468          break;
1469   if (cmd == NULL)
1470   {
1471      cmd= (struct Execution_Command *)getmem(sizeof(*cmd));
1472      if (cnt <= MAXCOLS-1)   /* first col prints site name therefore < max-1 */
1473      {
1474         strcpy(cmd->Commandname, name);
1475         if (*cmds == NULL)
1476            ec = *cmds = cmd;
1477         else
1478            ec->next= cmd;
1479      }
1480      else
1481      {
1482         strcpy(ec->Commandname, "Misc.");  /* reached high-water-mark */
1483         cmd = ec;                          /* backtrack */
1484      }
1485   }
1486   cmd->count++;
1487 }
1488
1489
1490   /* ------------------------------------------------------------------
1491    *             prot_sum - collect protocol data
1492    * ------------------------------------------------------------------
1493    */
1494
1495    struct Protocol_Summary *
1496    prot_sum(proto, ptype, ind)
1497                     struct Protocol_Summary **proto;
1498                     char *ptype;
1499                     int ind;
1500 {
1501   int cnt = 0;
1502   int i1, i2, i3 = 0;
1503   struct Protocol_Summary *cur, *first;
1504
1505   for (first = cur = *proto; cur != NULL; first= cur, cur= cur->next, cnt++)
1506   {
1507       if ( (0 == strncmp(cur->type, ptype,strlen(cur->type))))
1508          break;
1509   }
1510   if (cur == NULL)
1511   {
1512      cur= (struct Protocol_Summary *)getmem(sizeof(*cur));
1513      sscanf(ptype,"%[^\' ]3",cur->type);
1514      if (*proto == NULL)
1515         first = *proto = cur;
1516      else
1517         first->next= cur;
1518   }
1519   if (NULL == (ptype = strchr(ptype, ' ')))
1520          return (NULL);
1521   cur->pr_cnt++;
1522   have_proto = TRUE;
1523   ++ptype;
1524   switch(ind)
1525   {
1526      case 1:              /* used protocol line */
1527   /*
1528    * uucp-1.04 format: .... packet size ssss window ww)
1529    * uucp-1.05 format: .... remote packet/window ssss/ww local ssss/ww)
1530    *           (the remote packet/window will be used!)
1531    */
1532
1533           i1 = i2 = 0;    /* reset */
1534
1535           if (NULL == (strchr(ptype, '/')))
1536              sscanf(ptype,"%*s %*s %d %*s %d",&i1,&i2);
1537           else
1538              sscanf(ptype,"%*s %*s %d/%d",&i1,&i2);
1539
1540           if (i1 > cur->pr_psizemax)
1541              cur->pr_psizemax = i1;
1542           if (i1 < cur->pr_psizemin || cur->pr_psizemin == 0)
1543              cur->pr_psizemin = i1;
1544
1545           if (i2 > cur->pr_pwinmax)
1546              cur->pr_pwinmax = i2;
1547           if (i2 < cur->pr_pwinmin || cur->pr_pwinmin == 0)
1548              cur->pr_pwinmin = i2;
1549           break;
1550      case 2:              /* protocol statistics line */
1551           i1 = i2 = i3 = 0;    /* reset */
1552           sscanf(ptype,"%*s %*s %d%*c %*s %d%*c %*s %d",&i1,&i2,&i3);
1553           cur->pr_psent += i1;
1554           cur->pr_present += i2;
1555           cur->pr_preceived += i3;
1556           break;
1557      default:
1558           break;
1559   }
1560   return (cur);
1561 }
1562   /* ------------------------------------------------------------------
1563    *           fmtime() - Format time in hours & minutes & seconds;
1564    * ------------------------------------------------------------------
1565    */
1566
1567 static void fmtime(dsec, buf)
1568                   double dsec;
1569                   char *buf;
1570 {
1571   long hrs, min, lsec;
1572
1573   if( dsec <= 0 )
1574     {
1575       strcpy(buf, "0" );
1576       return;
1577     }
1578   lsec = fmod(dsec+0.5, 60L);        /* round to the next full second */
1579   hrs = dsec / 3600L;
1580   min = ((long)dsec / 60L) % 60L;
1581   if (hrs == 0)
1582      if (min == 0)
1583        sprintf(buf,"%6s%2ld"," ",lsec);
1584      else
1585        sprintf(buf,"%3s%2ld:%02ld"," ",min,lsec);
1586   else
1587     sprintf(buf,"%2ld:%02ld:%02ld",hrs,min,lsec);
1588
1589 }
1590
1591   /* ------------------------------------------------------------------
1592    *                 fmbytes - Format size in bytes
1593    * ------------------------------------------------------------------
1594    */
1595
1596 static void fmbytes(n, buf)
1597                    unsigned long n;
1598                    char *buf;
1599 {
1600   if ( n == 0 )
1601   {
1602      strcpy( buf, "0.0" );
1603      return;
1604   }
1605   sprintf(buf, "%.1f", (double)n / 1000.0);    /* Display in Kilobytes */
1606 }
1607
1608
1609   /* ------------------------------------------------------------------
1610    *                 chk_config - Read the config file
1611    *    check on keywords: logfile and statfile. When found override
1612    *    the corresponding default
1613    * ------------------------------------------------------------------
1614    */
1615
1616 int chk_config(char *T_conf,int be_quiet, int type)
1617 {
1618    FILE *Conf;
1619    char keywrd[9];
1620    char name[MAXPATHLEN+1];
1621    char *pos1, *pos2;
1622    int i = 0;
1623    int logf = FALSE;
1624    int statf = FALSE;
1625
1626    if ((Conf = fopen(T_conf, "r")) == NULL)
1627    {
1628       if (! be_quiet)
1629       {
1630          puts("   Could not open config");
1631          if (type == 0)
1632          {
1633             puts("   The run will be aborted\n");
1634             return (8);
1635          }
1636       }
1637       else
1638       {
1639          fprintf(stderr,"%s (E) %s %s \n",Pgm_name,
1640                                      "could not open config:",
1641                                       T_conf);
1642          if (type != 0)
1643             fprintf(stderr,"%s (W) defaults used for all files\n",
1644                                                Pgm_name);
1645          else
1646          {
1647             fprintf(stderr,"%s (C) ended due to errors\n",
1648                                                Pgm_name);
1649             return (8);
1650          } 
1651       }
1652    }
1653    else
1654    {
1655       while (fgets(logline, sizeof(logline), Conf))
1656       {
1657         if (logline[0] == '#')
1658            continue;
1659         sscanf(logline,"%8s %s",keywrd,name);
1660         if (0 == strncmp(keywrd,"logfile",7))
1661         {
1662            pos1 = pos2 = name;
1663            for (i=0;(i<=MAXPATHLEN && *pos1 != '\0');pos1++,pos2++,i++)
1664            {
1665                if (*pos1 == '#')     /* name immed followed by comment */
1666                   break;
1667                if (*pos1 == '\\')    /* quoted comment (filename has #) */
1668                {
1669                   ++pos1;               /* skip escape char */
1670                   if (*pos1 != '#')     /* continuation ? */
1671                   {
1672                      puts("   Config error:");
1673                      puts("   Found filename continuation; bailing out\n");
1674                      exit (8);
1675                   }
1676                }
1677                *pos2 = *pos1;        /* move char */
1678            }
1679            *pos2 = '\0';             /* terminate string */
1680            Tlog   = (char *)getmem(strlen(name)+1);
1681            strcpy(Tlog,name);
1682            if (! be_quiet)
1683               printf("   logfile used:        %s\n",Tlog);
1684            logf = TRUE;
1685            if  (statf)                /* statsfile still to come ? */
1686                break;                 /* no finished */
1687            continue;
1688         }
1689
1690         if (0 == strncmp(keywrd,"statfile",8))
1691         {
1692            pos1 = pos2 = name;
1693            for (i=0;(i<=MAXPATHLEN && *pos1 != '\0');pos1++,pos2++,i++)
1694            {
1695                if (*pos1 == '#')     /* name immed followed by comment */
1696                   break;
1697                if (*pos1 == '\\')    /* quoted comment (filename has #) */
1698                {
1699                   ++pos1;               /* skip escape char */
1700                   if (*pos1 != '#')     /* continuation ? */
1701                   {
1702                      puts("   Config error:");
1703                      puts("   Found filename continuation; bailing out\n");
1704                      exit (8);
1705                   }
1706                }
1707                *pos2 = *pos1;        /* move char */
1708            }
1709            *pos2 = '\0';             /* terminate string */
1710            Tstat   = (char *)getmem(strlen(name)+1);
1711            strcpy(Tstat,name);
1712            if (! be_quiet)
1713               printf("   statfile used:       %s\n",Tstat);
1714            statf = TRUE;
1715            if  (logf)                 /* logfile still to come ? */
1716                break;                 /* no finished */
1717            continue;
1718         }
1719       }
1720       fclose(Conf);
1721    }
1722
1723    if (! be_quiet)
1724    {
1725       if (! logf)
1726          puts("   logfile used:        - default -");
1727       if (! statf)
1728          puts("   statfile used:       - default -");
1729    }
1730
1731 return 0;
1732 }
1733
1734
1735   /* ------------------------------------------------------------------
1736    *   hdrprt - Print Header/Trailer lines (constant data)
1737    * ------------------------------------------------------------------
1738    */
1739
1740 static void hdrprt(char head, int bot)
1741 {
1742   switch(head)
1743   {
1744      case('s'):                   /* standard summary report */
1745           if (bot == 0)
1746           {
1747              puts("\nCompact summary:");
1748              puts("----------------");
1749              puts("\
1750 Name of  + Files + +------- Bytes/1000 --------+ +------ Time -----+ + Avg CPS +\n\
1751 site       in  out   inbound  outbound     total   inbound  outbound    in   out\n\
1752 -------- ---- ---- --------- --------- --------- --------- --------- ----- -----");
1753           }
1754           else
1755              puts("\
1756 --------------------------------------------------------------------------------");
1757           break;
1758
1759
1760      case('f'):                   /* file statistic report */
1761           if (bot == 0)
1762           {
1763              puts("\nFile statistics:");
1764              puts("----------------");
1765              puts("   Name of  +----------- Inbound -----------+ +---------- Outbound -----------+");
1766             puts("   site     files  Bytes/1000  xfr time B/sec files  Bytes/1000  xfr time B/sec");
1767             puts("   -------- ----- ----------- --------- ----- ----- ----------- --------- -----");
1768           }
1769           else
1770             puts("\
1771    ----------------------------------------------------------------------------");
1772           break;
1773
1774
1775      case('c'):                   /* calls statistic report */
1776           if (bot == 0)
1777           {
1778              puts("\nCall statistics:");
1779              puts("----------------");
1780              puts("   Name of   +------- Outbound Calls -------+  +-------- Inbound Calls  ------+");
1781              puts("   site       succ.  failed   total      time   succ.  failed   total      time");
1782             puts("   --------  ------  ------  ------ ---------  ------  ------  ------ ---------");
1783           }
1784           else
1785             puts("\
1786    ----------------------------------------------------------------------------");
1787           break;
1788
1789
1790      case('e'):                   /* efficiency statistic report */
1791           if (bot == 0)
1792           {
1793              puts("\nEfficiency:");
1794              puts("-----------");
1795              puts("   Name of   +------ Times inbound/outbound -------+");
1796              puts("   site      connected   xfr time   overhead  eff. %");
1797              puts("   --------  ---------  ---------  ---------  ------");
1798           }
1799           else
1800             puts("   -------------------------------------------------");
1801           break;
1802
1803      case('i'):                   /* Environment information */
1804           if (bot == 0)
1805           {
1806              puts("\nEnvironment Information:");
1807              puts("------------------------");
1808              printf("   Default config:      %s\n",D_conf == NULL ?
1809                                                    noConf:D_conf);
1810              printf("   Default logfile:     %s\n",Tlog);
1811              printf("   Default statfile:    %s\n\n",Tstat);
1812           }
1813           break;
1814
1815      case('d'):                   /* Date/time coverage */
1816           if (bot == 0)
1817           {
1818              puts("\n   Date coverage of input files:");
1819              puts("   Name of        +----- Start -----+  +------ End ------+");
1820              puts("   file                 date     time        date     time");
1821              puts("   --------       ---------- --------  ---------- --------");
1822           }
1823           break;
1824
1825      case('p'):                   /* Protocol stats */
1826           if (bot == 0)
1827           {
1828              puts("\nProtocol packet report:");
1829              puts("-----------------------");
1830              puts("          +------- protocol -----+   +--------- Packets ----------+");
1831              puts("Name of         packet     window ");
1832              puts("site      typ  min  max   min  max          sent  resent   received");
1833             puts("--------  --- ---- ----  ---- ----   ----------- ------- ----------");
1834           }
1835           else
1836           {
1837              puts("\nProtocol error report:");
1838              puts("----------------------");
1839              puts("Name of   +----------------- Error Types --------------------+");
1840              puts("site      typ      header    checksum        order  rem-reject");
1841              puts("--------  --- -----------  ----------  -----------  ----------");
1842           }
1843           break;
1844
1845      default:
1846           if (bot == 0)
1847           {
1848              puts("\nNo header for this report defined:");
1849           }
1850           else
1851             puts("  ");
1852          break;
1853    }
1854 }