aboutsummaryrefslogtreecommitdiff
path: root/gnu/libexec/uucp/contrib/uurate.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/libexec/uucp/contrib/uurate.c')
-rw-r--r--gnu/libexec/uucp/contrib/uurate.c657
1 files changed, 657 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/contrib/uurate.c b/gnu/libexec/uucp/contrib/uurate.c
new file mode 100644
index 000000000000..ceab41c53bfd
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uurate.c
@@ -0,0 +1,657 @@
+/*
+ * @(#)uurate.c 1.2 - Thu Sep 3 18:32:46 1992
+ *
+ * This program digests log and stats files in the "Taylor" format
+ * and outputs various statistical data to standard out.
+ *
+ * Author:
+ * Bob Denny (denny@alisa.com)
+ * Fri Feb 7 13:38:36 1992
+ *
+ * Original author:
+ * Mark Pizzolato mark@infopiz.UUCP
+ *
+ * Edits:
+ * Bob Denny - Fri Feb 7 15:04:54 1992
+ * Heavy rework for Taylor UUCP. This was the (very old) uurate from
+ * DECUS UUCP, which had a single logfile for activity and stats.
+ * Personally, I would have done things differently, with tables
+ * and case statements, but in the interest of time, I preserved
+ * Mark Pizzolato's techniques and style.
+ *
+ * Bob Denny - Sun Aug 30 14:18:50 1992
+ * Changes to report format suggested by Francois Pinard and others.
+ * Add summary report, format from uutraf.pl (perl script), again
+ * thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP.
+ */
+
+char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2";
+
+#include <ctype.h> /* Character Classification */
+#include <string.h>
+#include <math.h>
+
+#include "uucp.h"
+
+
+#define _DEBUG_ 0
+
+/*
+ * Direction of Calling and Data Transmission
+ */
+#define IN 0 /* Inbound */
+#define OUT 1 /* Outbound */
+
+/*
+ * Data structures used to collect information
+ */
+struct File_Stats
+ {
+ int files; /* Files Transferred */
+ unsigned long bytes; /* Data Size Transferred*/
+ double time; /* Transmission Time */
+ };
+
+struct Phone_Call
+ {
+ int calls; /* Call Count */
+ int succs; /* Successful calls */
+ double connect_time; /* Connect Time Spent */
+ struct File_Stats flow[2]; /* Rcvd & Sent Data */
+ };
+
+struct Execution_Command
+ {
+ struct Execution_Command *next;
+ char Commandname[64];
+ int count;
+ };
+
+struct Host_entry
+ {
+ struct Host_entry *next;
+ char Hostname[32];
+ struct Execution_Command *cmds; /* Local Activities */
+ struct Phone_Call call[2]; /* In & Out Activities */
+ };
+
+/*
+ * Stuff for getopt()
+ */
+extern int optind; /* GETOPT : Option Index */
+extern char *optarg; /* GETOPT : Option Value */
+extern void *calloc();
+
+static void fmtime();
+static void fmbytes();
+
+/*
+ * Default files to read. Taken from Taylor compile-time configuration.
+ * Must look like an argvec, hence the dummy argv[0].
+ */
+static char *(def_logs[3]) = { "", LOGFILE, STATFILE };
+
+/*
+ * Misc. strings for reports
+ */
+static char *(file_hdr[2]) = { "\nReceived file statistics:\n",
+ "\nSent file statistics\n" };
+
+/*
+ * BEGIN EXECUTION
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char c;
+ char *p, *s;
+ struct Host_entry *hosts = NULL;
+ struct Host_entry *cur = NULL;
+ struct Host_entry *e;
+ struct Execution_Command *cmd;
+ struct Execution_Command *ec;
+ char Hostname[64];
+ FILE *Log = NULL;
+ char logline[1024];
+ char *logmsg;
+ int sent;
+ int called;
+ int show_files = 0; /* I prefer boolean, but... */
+ int show_calls = 0;
+ int show_commands = 0;
+ int show_efficiency = 0;
+ int show_summary = 0;
+ int have_files = 0;
+ int have_calls = 0;
+ int have_commands = 0;
+ int use_stdin = 0;
+ Hostname[0] = '\0';
+
+ /*
+ * I wish the compiler had the #error directive!
+ */
+#if !HAVE_TAYLOR_LOGGING
+ fprintf(stderr, "uurate cannot be used with your configuration of\n");
+ fprintf(stderr, "Taylor UUCP. To use uurate you must be using the\n");
+ fprintf(stderr, "TAYLOR_LOGGING configuration.\n");
+ exit(1);
+#endif
+
+ /*
+ * Process the command line arguments
+ */
+ while((c = getopt(argc, argv, "h:cfexai")) != EOF)
+ {
+ switch(c)
+ {
+ case 'h':
+ strcpy(Hostname, optarg);
+ break;
+ case 'c':
+ show_calls = 1;
+ break;
+ case 'f':
+ show_files = 1;
+ break;
+ case 'x':
+ show_commands = 1;
+ break;
+ case 'e':
+ show_efficiency = 1;
+ break;
+ case 'a':
+ show_calls = show_files = show_commands = show_efficiency = 1;
+ break;
+ case 'i':
+ use_stdin = 1;
+ break;
+ default :
+ goto usage;
+ }
+ }
+
+ /*
+ * If no report switches given, show summary report.
+ */
+ if (show_calls == 0 && show_files == 0
+ && show_efficiency == 0 && show_commands == 0)
+ show_summary = 1;
+
+ /*
+ * Adjust argv and argc to account for the args processed above.
+ */
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ /*
+ * If further args present, Assume rest are logfiles for us to process,
+ * otherwise, take input from Log and Stat files provided in the
+ * compilation environment of Taylor UUCP. If -i was given, Log already
+ * points to stdin and no file args are accepted.
+ */
+ if(argc == 1) /* No file arguments */
+ {
+ if (use_stdin) /* If -i, read from stdin */
+ {
+ argc = 2;
+ Log = stdin;
+ }
+ else /* Read from current logs */
+ {
+ argc = 3; /* Bash argvec to default log/stat files */
+ argv = &def_logs[0];
+ }
+ }
+ else if (use_stdin) /* File args with -i is an error */
+ {
+ fprintf(stderr, "uurate (error): file args given with '-i'\n");
+ goto usage;
+ }
+
+#if _DEBUG_
+ printf("\n");
+#endif
+
+ /*
+ * MAIN LOGFILE PROCESSING LOOP
+ */
+ while (argc > 1)
+ {
+
+ if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
+ {
+ perror(argv[1]);
+ return;
+ }
+
+#if _DEBUG_
+ printf("Reading %s...\n", (use_stdin ? "stdin" : argv[1]));
+#endif
+
+ /*
+ * Read each line of the logfile and collect information
+ */
+ while (fgets(logline, sizeof(logline), Log))
+ {
+ /*
+ * The host name of the other end of the connection is
+ * always the second field of the log line, whether we
+ * are reading a Log file or a Stats file. Set 'p' to
+ * point to the second field, null-terminated. Skip
+ * the line if something is funny.
+ */
+ if (NULL == (p = strchr(logline, ' ')))
+ continue;
+ ++p;
+ if (NULL != (s = strchr(p, ' ')))
+ *s = '\0';
+ for (s = p; *s; ++s)
+ if (isupper(*s))
+ *s = tolower(*s);
+ /*
+ * Skip this line if we got -h <host> and
+ * this line does not contain that host name.
+ */
+ if (Hostname[0] != '\0')
+ if (0 != strcmp(p, Hostname))
+ continue;
+ /*
+ * We are within a call block now. If this line is a file
+ * transfer record, determine the direction. If not then
+ * skip the line if it is not interesting.
+ */
+ if ((s = strchr(++s, ')')) == NULL)
+ continue;
+ logmsg = s + 2; /* Message is 2 characters after ')' */
+ if (0 == strncmp(logmsg, "sent", 4))
+ sent = OUT;
+ else
+ if (0 == strncmp(logmsg, "received", 8))
+ sent = IN;
+ else
+ if ((0 != strncmp(logmsg, "Call complete", 13)) &&
+ (0 != strncmp(logmsg, "Calling system", 14)) &&
+ (0 != strncmp(logmsg, "Incoming call", 13)) &&
+ (0 != strncmp(logmsg, "Executing", 9)))
+ continue;
+ /*
+ * Find the Host_entry for this host, or create a new
+ * one and link it on to the list.
+ */
+ if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
+ {
+ for (cur = hosts; cur != NULL ; cur = cur->next)
+ if (0 == strcmp(cur->Hostname, p))
+ break;
+ if (cur == NULL)
+ {
+ cur = (struct Host_entry *)calloc(1, sizeof(*hosts));
+ strcpy(cur->Hostname, p);
+ if (hosts == NULL)
+ hosts = cur;
+ else
+ {
+ for (e = hosts; e->next != NULL; e = e->next);
+ e->next = cur;
+ }
+ }
+ }
+ /*
+ * OK, if this is a uuxqt record, find the Execution_Command
+ * structure for the command being executed, or create a new
+ * one. Then count an execution of this command.
+ */
+ if (0 == strncmp(logmsg, "Executing", 9))
+ {
+ if (NULL == (p = strchr(logmsg, '(')))
+ continue;
+ if ((s = strpbrk(++p, " )")) == NULL)
+ continue;
+ *s = '\0';
+ for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
+ if (0 == strcmp(cmd->Commandname, p))
+ break;
+ if (cmd == NULL)
+ {
+ cmd = (struct Execution_Command *)calloc(1, sizeof(*cmd));
+ strcpy(cmd->Commandname, p);
+ if (cur->cmds == NULL)
+ cur->cmds = cmd;
+ else
+ {
+ for (ec = cur->cmds; ec->next != NULL; ec = ec->next);
+ ec->next = cmd;
+ }
+ }
+ ++cmd->count;
+ have_commands = 1;
+ continue;
+ }
+ /*
+ * Count start of outgoing call.
+ */
+ if (0 == strncmp(logmsg, "Calling system", 14))
+ {
+ called = OUT;
+ cur->call[called].calls += 1;
+ have_calls = 1;
+ continue;
+ }
+ /*
+ * Count start of incoming call.
+ */
+ if (0 == strncmp(logmsg, "Incoming call", 13))
+ {
+ called = IN;
+ cur->call[called].calls += 1;
+ have_calls = 1;
+ continue;
+ }
+ /*
+ * Handle end of call. Pick up the connect time.
+ */
+ if (0 == strncmp(logmsg, "Call complete", 13))
+ {
+ cur->call[called].succs += 1;
+ if (NULL == (s = strchr(logmsg, '(')))
+ continue;
+ cur->call[called].connect_time += atof(s+1);
+ continue;
+ }
+ /*
+ * If we reached here, this must have been a file transfer
+ * record. Count it in the field corresponding to the
+ * direction of the transfer. Count bytes transferred and
+ * the time to transfer as well.
+ */
+ have_files = 1;
+ cur->call[called].flow[sent].files += 1;
+ if (NULL == (s = strchr(logmsg, ' ')))
+ continue;
+ cur->call[called].flow[sent].bytes += atol(++s);
+ if (NULL == (s = strchr(s, ' ')))
+ continue;
+ if (NULL == (s = strpbrk(s, "0123456789")))
+ continue;
+ cur->call[called].flow[sent].time += atof(s);
+ }
+ argc -= 1;
+ argv += 1;
+ if(Log != stdin)
+ fclose(Log);
+ }
+
+ /*
+ * ***********
+ * * REPORTS *
+ * ***********
+ */
+
+ /*
+ * Truncate the Hostnames to 8 characters at most.
+ */
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ cur->Hostname[8] = '\0';
+
+#if _DEBUG_
+ printf("\n");
+#endif
+
+ /*
+ * Summary report
+ *
+ * I know, this code could be tightened (rbd)...
+ */
+ if(show_summary)
+ {
+ char t1[32], t2[32], t3[32], t4[32], t5[32];
+ long ib, ob, b, rf, sf;
+ long t_ib=0, t_ob=0, t_b=0, t_rf=0, t_sf=0;
+ double it, ot, ir, or;
+ double t_it=0.0, t_ot=0.0;
+ int nhosts = 0;
+
+ printf("\n\
+ Remote ------- Bytes -------- --- Time ---- -- Avg CPS -- -- Files --\n");
+ printf("\
+ Host Rcvd Sent Total Rcvd Sent Rcvd Sent Rcvd Sent\n");
+ printf("\
+-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ ib = (cur->call[IN].flow[IN].bytes +
+ cur->call[OUT].flow[IN].bytes);
+ fmbytes(ib, t1);
+ t_ib += ib;
+
+ ob = (cur->call[IN].flow[OUT].bytes +
+ cur->call[OUT].flow[OUT].bytes);
+ fmbytes(ob, t2);
+ t_ob += ob;
+
+ b = ib + ob;
+ fmbytes(b, t3);
+ t_b += b;
+
+ it = cur->call[IN].flow[IN].time +
+ cur->call[OUT].flow[IN].time;
+ fmtime(it, t4);
+ t_it += it;
+
+ ot = cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[OUT].time;
+ fmtime(ot, t5);
+ t_ot += ot;
+
+ rf = cur->call[IN].flow[IN].files +
+ cur->call[OUT].flow[IN].files;
+ t_rf += rf;
+
+ sf = cur->call[IN].flow[OUT].files +
+ cur->call[OUT].flow[OUT].files;
+ t_sf += sf;
+
+ ir = (it == 0.0) ? 0.0 : (ib / it);
+ or = (ot == 0.0) ? 0.0 : (ob / ot);
+
+ printf("%-8s %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
+ cur->Hostname,
+ t1, t2, t3, t4, t5,
+ ir, or, rf, sf);
+ }
+
+ if(nhosts > 1)
+ {
+ fmbytes(t_ib, t1);
+ fmbytes(t_ob, t2);
+ fmbytes(t_b, t3);
+ fmtime(t_it, t4);
+ fmtime(t_ot, t5);
+ ir = (t_it == 0.0) ? 0.0 : (t_ib / t_it);
+ or = (t_ot == 0.0) ? 0.0 : (t_ob / t_ot);
+
+ printf("\
+-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n");
+ printf("\
+Totals %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n",
+ t1, t2, t3, t4, t5,
+ ir, or, t_rf, t_sf);
+ }
+ }
+
+
+ /*
+ * Call statistics report
+ */
+ if(show_calls && have_calls)
+ {
+ char t1[32], t2[32];
+
+ printf("\nCall statistics:\n");
+ printf("\
+ sysname callto failto totime callfm failfm fmtime\n");
+ printf("\
+ -------- ------ ------ -------- ------ ------ --------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ fmtime(cur->call[OUT].connect_time, t1);
+ fmtime(cur->call[IN].connect_time, t2),
+ printf(" %-8s %6d %6d %8s %6d %6d %8s\n",
+ cur->Hostname,
+ cur->call[OUT].calls,
+ cur->call[OUT].calls - cur->call[OUT].succs,
+ t1,
+ cur->call[IN].calls,
+ cur->call[IN].calls - cur->call[IN].succs,
+ t2);
+ }
+ }
+
+ /*
+ * File statistics report
+ */
+ if(show_files && have_files)
+ {
+ char t1[32], t2[32];
+
+ for (sent = IN; sent <= OUT; ++sent)
+ {
+ printf(file_hdr[sent]);
+ printf(" sysname files bytes xfr time byte/s\n");
+ printf(" -------- ------ -------- -------- ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ double rate;
+ double time;
+
+ time = cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time;
+ if (time == 0.0)
+ continue;
+ rate = (cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes) / time;
+ fmbytes((cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes), t1);
+ fmtime((cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time), t2);
+ printf(" %-8s %6d %8s %8s %6.1f\n",
+ cur->Hostname,
+ cur->call[IN].flow[sent].files +
+ cur->call[OUT].flow[sent].files,
+ t1, t2, rate);
+ }
+ }
+ }
+
+ /*
+ * Efficiency report
+ */
+ if (show_efficiency && have_files)
+ {
+ char t1[32], t2[32], t3[32];
+ double total, flow;
+
+ printf("\nEfficiency:\n");
+ printf(" sysname conntime flowtime ovhdtime eff. %%\n");
+ printf(" -------- -------- -------- -------- ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ total = cur->call[IN].connect_time + cur->call[OUT].connect_time;
+ flow = cur->call[IN].flow[IN].time + cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[IN].time + cur->call[OUT].flow[OUT].time;
+ fmtime(total, t1);
+ fmtime(flow, t2);
+ fmtime((total-flow), t3);
+ printf(" %-8s %8s %8s %8s %5.1f%%\n",
+ cur->Hostname, t1, t2, t3, ((flow / total) * 100.0));
+ }
+ }
+
+ /*
+ * Command execution report
+ */
+ if (show_commands & have_commands)
+ {
+ printf("\nCommand executions:\n");
+ printf(" sysname rmail rnews other\n");
+ printf(" -------- ------ ------ ------\n");
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ int rmail, rnews, other;
+
+ if (cur->cmds == NULL)
+ continue;
+ rmail = rnews = other = 0;
+ for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next)
+ {
+ if (strcmp(cmd->Commandname, "rmail") == 0)
+ rmail += cmd->count;
+ else if (strcmp(cmd->Commandname, "rnews") == 0)
+ rnews += cmd->count;
+ else
+ other += cmd->count;
+ }
+ printf(" %-8s %6d %6d %6d\n", cur->Hostname,
+ rmail, rnews, other);
+ }
+ }
+ return;
+
+ usage:
+ fprintf(stderr,
+ "Usage uurate [-cfexai] [-h hostname] [logfile ... logfile]\n");
+ fprintf(stderr,"where:\t-c\tReport call statistics\n");
+ fprintf(stderr, "\t-f\tReport file transfer statistics\n");
+ fprintf(stderr, "\t-e\tReport efficiency statistics\n");
+ fprintf(stderr, "\t-x\tReport command execution statistics\n");
+ fprintf(stderr, "\t-a\tAll of the above reports\n");
+ fprintf(stderr, "\t-h host\tReport activities involving ONLY host\n");
+ fprintf(stderr, "\t-i\tRead log info from standard input\n");
+ fprintf(stderr,
+ "If no report options given, a compact summary report is given.\n");
+ fprintf(stderr,
+ "If neither -i nor logfiles given, defaults to reading from\n");
+ fprintf(stderr, "%s and %s\n\n", LOGFILE, STATFILE);
+}
+
+/*
+ * fmtime() - Format time in hours & minutes;
+ */
+static void fmtime(dsec, buf)
+ double dsec;
+ char *buf;
+{
+ long hrs, min, lsec;
+
+ lsec = dsec;
+ hrs = lsec / 3600L;
+ min = (lsec - (hrs * 3600L)) / 60L;
+
+ sprintf(buf, "%02ld:%02ld", hrs, min);
+}
+
+/*
+ * fmbytes - Format size in bytes
+ */
+static void fmbytes(n, buf)
+ unsigned long n;
+ char *buf;
+{
+ char t;
+ double s = n;
+
+ if(s >= 10239897.6) /* More than 9999.9K ? */
+ {
+ s = (double)n / 1048576.0; /* Yes, display in Megabytes */
+ t = 'M';
+ }
+ else
+ {
+ s = (double)n / 1024.0; /* Display in Kilobytes */
+ t = 'K';
+ }
+
+ sprintf(buf, "%.1f%c", s, t);
+}
+