home *** CD-ROM | disk | FTP | other *** search
- From: jeff@onion.pdx.com (Jeff Beadles)
- Newsgroups: alt.sources
- Subject: Smail3 log file parser
- Message-ID: <1990Dec25.063653.14083@onion.pdx.com>
- Date: 25 Dec 90 06:36:53 GMT
-
-
-
- [ Note: Followup's are directed to alt.sources.d. -Jeff]
-
- { This is the smaillog.READ file. }
- Smail3 log file parser. Copyright 1990, Jeff Beadles. All rights reserved.
- jeff@onion.pdx.com or uunet!onion.pdx.com!jeff
-
- Permission is granted to freely copy this program as long as it is not sold.
-
- Source MUST be provided upon request, and this message must be kept on
- all copies of the program.
-
-
- What this program will do is simple. It will take the smail3 logfile
- information, and produce a fairly human-readable report. For example, it
- will take the smail3 logfile (/usr/spool/smail/log/logfile on my system)
- that looks like:
-
- 12/24/90 00:33:55: [m0innd5-000NXgC] new msg: from root
- 12/24/90 00:33:56: [m0innd5-000NXgC] jeff ... delivered
- 12/24/90 01:24:26: [m0io4L3-000NUrC] new msg: from jeff@onion
- 12/24/90 01:24:29: [m0io4L3-000NUrC] <foo@bar.har.edu> ... delivered
-
- on stdin, and, on stdout display:
-
- Processing 4 lines. (Used 352 bytes.)
- 00:33:56: root => jeff
- 01:24:29: jeff@onion => <foo@bar.har.edu>
-
- I use this as a part of my nightly system checker. Anyway, it's something
- that I originally wrote for sendmail. I've changed the field definitions
- to work with smail3. Yea, this could be in AWK, but I was in a 'C' kinda
- of mood at the time.
-
- This is provided as-is, and you can use it at your own risk. There's no man
- page currently. One of these days, I might even write one for it.
- Until then, "Use the source." I call it like:
-
- % smaillog < /usr/spool/smail/log/OLD/logfile.0 | mail jeff
-
- Have fun,
- -Jeff
- --
- Jeff Beadles jeff@onion.pdx.com
-
-
-
- #--------------------------------CUT HERE-------------------------------------
- #! /bin/sh
- #
- # This is a shell archive. Save this into a file, edit it
- # and delete all lines above this comment. Then give this
- # file to sh by executing the command "sh file". The files
- # will be extracted into the current directory owned by
- # you with default permissions.
- #
- # The files contained herein are:
- #
- # -rw-r--r-- 1 jeff 1486 Dec 24 22:35 smaillog.READ
- # -r--r--r-- 1 jeff 9628 Dec 24 22:23 smaillog.c
- #
- echo 'x - smaillog.READ'
- if test -f smaillog.READ; then echo 'shar: not overwriting smaillog.READ'; else
- sed 's/^X//' << '________This_Is_The_END________' > smaillog.READ
- X
- XSmail3 log file parser. Copyright 1990, Jeff Beadles. All rights reserved.
- X jeff@onion.pdx.com or uunet!onion.pdx.com!jeff
- X
- XPermission is granted to freely copy this program as long as it is not sold.
- X
- XSource MUST be provided upon request, and this message must be kept on
- Xall copies of the program.
- X
- X
- XWhat this program will do is simple. It will take the smail3 logfile
- Xinformation, and produce a fairly human-readable report. For example, it
- Xwill take the smail3 logfile (/usr/spool/smail/log/logfile on my system)
- Xthat looks like:
- X
- X 12/24/90 00:33:55: [m0innd5-000NXgC] new msg: from root
- X 12/24/90 00:33:56: [m0innd5-000NXgC] jeff ... delivered
- X 12/24/90 01:24:26: [m0io4L3-000NUrC] new msg: from jeff@onion
- X 12/24/90 01:24:29: [m0io4L3-000NUrC] <foo@bar.har.edu> ... delivered
- X
- Xon stdin, and, on stdout display:
- X
- X Processing 4 lines. (Used 352 bytes.)
- X 00:33:56: root => jeff
- X 01:24:29: jeff@onion => <foo@bar.har.edu>
- X
- XI use this as a part of my nightly system checker. Anyway, it's something
- Xthat I originally wrote for sendmail. I've changed the field definitions
- Xto work with smail3. Yea, this could be in AWK, but I was in a 'C' kinda
- Xof mood at the time.
- X
- XThis is provided as-is, and you can use it at your own risk. There's no man
- Xpage currently. One of these days, I might even write one for it.
- XUntil then, "Use the source." I call it like:
- X
- X% smaillog < /usr/spool/smail/log/OLD/logfile.0 | mail jeff
- X
- XHave fun,
- X -Jeff
- X--
- XJeff Beadles jeff@onion.pdx.com
- ________This_Is_The_END________
- if test `wc -c < smaillog.READ` -ne 1486; then
- echo 'shar: smaillog.READ was damaged during transit (should have been 1486 bytes)'
- fi
- fi ; : end of overwriting check
- echo 'x - smaillog.c'
- if test -f smaillog.c; then echo 'shar: not overwriting smaillog.c'; else
- sed 's/^X//' << '________This_Is_The_END________' > smaillog.c
- X/*
- X *
- X * Parse smail3 log files.
- X *
- X * Copyright 1990, Jeff Beadles. All rights reserved.
- X *
- X * Permission is granted to freely copy this program as long as it is
- X * not sold. Source MUST be provided upon request.
- X *
- X * This message must be kept on all copies of the program.
- X *
- X * jeff@onion.pdx.com
- X * or uunet!onion.pdx.com!jeff
- X *
- X * $Header: smaillog.c,v 1.4 90/12/24 22:23:36 jeff Exp $
- X */
- X
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <strings.h>
- X
- Xvoid add_data();
- Xstruct qlist *lookup();
- Xchar *skipfields();
- X
- Xextern char *mspace();
- Xlong int malloc_space = 0L; /* Space malloc had to allocate */
- X
- X/*
- X * The qlist structure holds each unique "qid"'s entry. It also
- X * points to the data structures.
- X * This is stored as a linked list with "qhead" pointing to the head
- X * of the list.
- X */
- Xstruct qlist {
- X char qid[32];
- X char date[24];
- X struct data *dp;
- X struct qlist *next;
- X };
- X
- X/*
- X * The data structure is the data information for the qlist structure.
- X * There can be (and most likely are) multiple data structs for each
- X * qlist structure.
- X * tfl == "to from list"
- X */
- X
- Xstruct data {
- X char *tfl;
- X struct data *next;
- X };
- X
- X/*
- X * The structures look like this:
- X *
- X *
- X * (qhead) qlist -> data1 -> data2 -> data3
- X * \|/
- X * qlist -> data1 -> data2
- X * \|/
- X * qlist -> data1 -> data2 -> data3 -> data4 -> data5
- X * \|/
- X * NULL (End of list )
- X *
- X */
- X
- Xstatic struct qlist *qhead;
- Xextern char *fgets();
- X
- X/* ARGSUSED */
- Xint
- Xmain(argc,argv)
- Xint argc;
- Xchar **argv;
- X{
- X struct data *dtmp;
- X struct qlist *qtmp;
- X
- X char linebuf[4096], buffer[4096];
- X char line_date[24];
- X char *fg, *cp;
- X int lines = 0;
- X char to[4096], from[4096];
- X char *source, *dest;
- X extern int strspn();
- X int itmp;
- X char *ctmp;
- X
- X qhead =(struct qlist *)NULL;
- X
- X/*
- X * Give a terse usage message if called with arguements.
- X */
- X if ( argc != 1) {
- X fprintf(stderr, "Error: Usage: %s < input > output\n",argv[0]);
- X exit(1);
- X }
- X/*
- X * Read each line from stdin
- X */
- X while ((fg=fgets(linebuf, sizeof(linebuf) - 1,stdin)) != (char *)NULL){
- X lines++;
- X
- X/*
- X * Blast out the \n at the end...
- X */
- X ctmp = rindex(fg, '\n');
- X if (ctmp) {
- X *ctmp = '\0';
- X }
- X
- X/*
- X * Skip "01/01/90 " This is meant to run daily. If not, then remove this
- X * section of code.
- X */
- X
- X if ((fg=skipfields(fg, 1)) == (char *)NULL) {
- X printf("Error: Skip 1 on %s\n", linebuf);
- X continue;
- X }
- X
- X/*
- X * Save the date, to be put in the qlist structure later
- X */
- X (void)strncpy(line_date, fg, 8);
- X/*
- X * Skip past the date field now, as we have it.
- X */
- X if ((fg=skipfields(fg,1)) == (char *)NULL) {
- X printf("Error: Skip 1 on %s\n", linebuf);
- X continue;
- X }
- X/*
- X * Catches "open_spool:" and "pid ##: smail daemon started" and other stuff.
- X * This just copies them verbatium to the output file.
- X * (At the head of the list)
- X */
- X if ( *fg != '[' ) {
- X printf("Warning: %s\n", fg);
- X continue;
- X }
- X/*
- X * Put qid in "buffer" It looks like "[xxxxxx-xxxxxxx]".
- X * This is the identifier that is used to index into the qlist struct.
- X */
- X cp=buffer;
- X while(!isspace(*fg))
- X *cp++ = *fg++;
- X *cp = '\0';
- X
- X/*
- X * buffer now contains the qid, so look it up in the qlist.
- X * Lookup will always return success. It will malloc a new area if this
- X * is a new record.
- X */
- X qtmp = lookup(buffer);
- X (void)strcpy(qtmp->date, line_date);
- X
- X/*
- X * Now, skip past the qid, and on to the ftl (to/from list).
- X * This is added to a data structure attached to the qlist.
- X */
- X if ((fg=skipfields(fg,1)) == (char *)NULL) {
- X printf("Error: Skip 1 on %s\n", linebuf);
- X continue;
- X }
- X add_data(qtmp, fg);
- X }
- X/*
- X * Note: We are now out of the fgets() loop, and have all of the information
- X * loaded in the struct. Time to print some stats, and process the info.
- X */
- X
- X printf("Processing %d lines. (Used %ld bytes.)\n",lines,malloc_space);
- X
- X/*
- X * Time to start stepping thru the list. Start at the head, and process each
- X * qlist structure and it's data elements.
- X */
- X qtmp = qhead;
- X
- X while(qtmp) {
- X dtmp = qtmp->dp;
- X *from = *to = '\0';
- X while(dtmp) {
- X
- X/* This marks a "from" line. If so, then strip off the first 14 characters,
- X * and set the variable "from" to point to it. It will automatically
- X * append to the from line if needed. It copies until it reaches the
- X * end of line, or a ','. The comma starts showing the origination qid.
- X */
- X if ( !strncmp(dtmp->tfl, "new msg: from ", 14)) {
- X dest = from + strlen(from);
- X source = dtmp->tfl + 14;
- X while (*source && (*source != ',') )
- X *dest++ = *source++;
- X *dest = '\0';
- X dtmp = dtmp->next;
- X continue;
- X }
- X/* This is used to see if this is a "to" line. If so, then the LAST 14
- X * characters will match the " ... delivered" string. Do a little pointer
- X * fun to find the right position in the string, and check it. If this is
- X * a "to" line, then append this to the "to" variable
- X */
- X itmp = strlen(dtmp->tfl) - 14;
- X if ( itmp >= 0) {
- X ctmp = dtmp->tfl;
- X ctmp += itmp;
- X if (!strncmp(ctmp, " ... delivered",14)){
- X *ctmp = '\0';
- X dest = to + strlen(to);
- X source = dtmp->tfl ;
- X while (*source)
- X *dest++ = *source++;
- X *dest++ = ' ';
- X *dest = '\0';
- X dtmp = dtmp->next;
- X continue;
- X }
- X }
- X/* A general error trap, that should not be reached, but you know how that
- X * goes... :-)
- X */
- X printf("What is %s?\n", dtmp->tfl);
- X dtmp = dtmp->next;
- X }
- X/* At this point, we have traveled thru one entire message's data.
- X * Now, print the date, and the to and from information. Try to figure
- X * out if this is to, or from someone on this machine, to do the "=>" "<="
- X * right. If all else fails though, punt and guess.
- X */
- X if ( *to && *from) {
- X printf("%s: ", qtmp->date);
- X/*
- X * kill trailing ',' and whitespace in the 'to' and 'from' fields
- X */
- X cp = to + strlen(to) - 1;
- X while ((*cp) && (isspace(*cp) || (*cp == ',')))
- X *cp-- = '\0';
- X
- X cp = from + strlen(from) - 1;
- X while ((*cp) && (isspace(*cp) || (*cp == ',')))
- X *cp-- = '\0';
- X/*
- X * All of that for this to display it
- X */
- X printf("%s => %s\n", from, to);
- X }
- X/*
- X * Time to get the next element and process it.
- X */
- X qtmp = qtmp->next;
- X }
- X
- X
- X exit(0);
- X}
- X
- X/*
- X * This routine will add the data (str) to the qlist member "q"
- X */
- X
- Xvoid
- Xadd_data(q, str)
- Xstruct qlist *q;
- Xchar *str;
- X{
- X struct data *dtmp;
- X char *cp;
- X
- X/*
- X * Save the string
- X */
- X cp = mspace( (unsigned int)(strlen(str)));
- X (void)strcpy(cp, str);
- X
- X/*
- X * If the data area is empty, then just load this into it.
- X * and point the "next" entry to null.
- X */
- X if (q->dp == (struct data *)NULL) {
- X q->dp = (struct data *)mspace(sizeof(struct data));
- X dtmp = q->dp;
- X dtmp->tfl = cp;
- X dtmp->next = (struct data *)NULL;
- X return;
- X }
- X/*
- X * otherwise, search and find the end of the data list for this qlist.
- X * Then, add it to the end.
- X */
- X dtmp = q->dp;
- X while(dtmp->next != (struct data *)NULL) {
- X dtmp= dtmp->next;
- X }
- X/*
- X * Get space for the new element, and add it to the end of the list.
- X * Then, move to the new element, and add the data to it.
- X * After that, set the "next" flag to null, to show that this is now
- X * the end of the list.
- X */
- X dtmp->next=(struct data *)mspace(sizeof (struct data));
- X dtmp = dtmp->next;
- X dtmp->tfl = cp;
- X dtmp->next = (struct data *)NULL;
- X}
- X
- X
- X/*
- X * This routine will search the qlist for an element with the "key" of
- X * the qid this is called with. If not found, then it will automatically
- X * allocate a new member, and initialize it properly
- X */
- Xstruct qlist *
- Xlookup(str)
- Xchar *str;
- X{
- X
- X struct qlist *qtmp = qhead;
- X
- X
- X/*
- X * Is this an empty list? If so, then add to head.
- X */
- X if ( qhead == (struct qlist *)NULL) {
- X qhead = (struct qlist *)mspace(sizeof (struct qlist));
- X qtmp = qhead;
- X (void)strcpy(qtmp->qid, str);
- X qtmp->dp = (struct data *)NULL;
- X qtmp->next = (struct qlist *) NULL;
- X return (qtmp);
- X }
- X while (1) {
- X/*
- X * Does this one match? If so, then return it.
- X */
- X if (!strcmp(qtmp->qid, str)) {
- X return(qtmp);
- X }
- X/*
- X * If at the end of the list, then add it.
- X */
- X if (qtmp->next == (struct qlist *)NULL) {
- X qtmp->next=(struct qlist *)mspace(sizeof(struct qlist));
- X qtmp = qtmp->next;
- X (void)strcpy(qtmp->qid, str);
- X qtmp->dp = (struct data *)NULL;
- X qtmp->next = (struct qlist *) NULL;
- X return (qtmp);
- X }
- X qtmp = qtmp->next;
- X }
- X}
- X
- X
- X/*
- X * This routine just skips past whitespace-delimited fields in a string.
- X * IE: If called as skipfields("a bb ccc dddd eeeee",2) it will return
- X * "ccc dddd eeeee"
- X */
- Xchar *
- Xskipfields(str,count)
- Xchar *str;
- Xint count;
- X
- X{
- X if ( count < 1 )
- X return( (char *)NULL);
- X
- X while (count--) {
- X while((*str) && !(isspace(*str)))
- X str++;
- X if (!*str)
- X return( (char *)NULL);
- X while((*str) && (isspace(*str)))
- X str++;
- X if (!*str)
- X return( (char *)NULL);
- X }
- X return(str);
- X}
- X
- X/* This routine is a general "malloc" routine. It does two additional
- X * functions though. One, is to keep track of how much space has been
- X * malloc'ed, and the second is to automatically check for errors, and bail-
- X * out if needed. This prevents me from having to put the same code around
- X * all of the malloc's.
- X *
- X * It also allocates "FUZZ" more bytes than were requested. If you're
- X * having troubles with this, then change it to something >0.
- X * (Don't make it less than 0 though, snicker :-)
- X */
- X
- X#ifndef FUZZ
- X#define FUZZ 0
- X#endif /* !FUZZ */
- X
- Xchar *
- Xmspace(len)
- Xunsigned int len;
- X{
- X static char *mp;
- X extern char *malloc();
- X
- X len += FUZZ;
- X
- X mp = malloc(len);
- X
- X if ( mp) {
- X malloc_space += len;
- X return(mp);
- X } else {
- X fprintf(stderr, "Malloc:\tOut of space (Requested %d bytes)\n",len);
- X fprintf(stderr, "\tAlready requested %ld bytes\n", malloc_space);
- X exit(1);
- X }
- X /*NOTREACHED*/
- X}
- ________This_Is_The_END________
- if test `wc -c < smaillog.c` -ne 9628; then
- echo 'shar: smaillog.c was damaged during transit (should have been 9628 bytes)'
- fi
- fi ; : end of overwriting check
- exit 0
-