home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2404 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  14.2 KB

  1. From: jeff@onion.pdx.com (Jeff Beadles)
  2. Newsgroups: alt.sources
  3. Subject: Smail3 log file parser
  4. Message-ID: <1990Dec25.063653.14083@onion.pdx.com>
  5. Date: 25 Dec 90 06:36:53 GMT
  6.  
  7.  
  8.  
  9. [ Note:  Followup's are directed to alt.sources.d.  -Jeff]
  10.  
  11. { This is the smaillog.READ file. }
  12. Smail3 log file parser.  Copyright 1990, Jeff Beadles.  All rights reserved.
  13.         jeff@onion.pdx.com or  uunet!onion.pdx.com!jeff
  14.  
  15. Permission is granted to freely copy this program as long as it is not sold.
  16.  
  17. Source MUST be provided upon request, and this message must be kept on
  18. all copies of the program.
  19.  
  20.  
  21. What this program will do is simple.  It will take the smail3 logfile
  22. information, and produce a fairly human-readable report.  For example, it
  23. will take the smail3 logfile (/usr/spool/smail/log/logfile on my system)
  24. that looks like:
  25.  
  26.     12/24/90 00:33:55: [m0innd5-000NXgC] new msg: from root
  27.     12/24/90 00:33:56: [m0innd5-000NXgC] jeff ... delivered
  28.     12/24/90 01:24:26: [m0io4L3-000NUrC] new msg: from jeff@onion
  29.     12/24/90 01:24:29: [m0io4L3-000NUrC] <foo@bar.har.edu> ... delivered
  30.  
  31. on stdin, and,  on stdout display:
  32.  
  33.     Processing 4 lines.  (Used 352 bytes.)
  34.     00:33:56: root => jeff
  35.     01:24:29: jeff@onion => <foo@bar.har.edu>
  36.  
  37. I use this as a part of my nightly system checker.  Anyway, it's something
  38. that I originally wrote for sendmail.  I've changed the field definitions
  39. to work with smail3.  Yea, this could be in AWK, but I was in a 'C' kinda
  40. of mood at the time.
  41.  
  42. This is provided as-is, and you can use it at your own risk.  There's no man
  43. page currently.  One of these days, I might even write one for it.
  44. Until then, "Use the source."  I call it like:
  45.  
  46. % smaillog < /usr/spool/smail/log/OLD/logfile.0 | mail jeff
  47.  
  48. Have fun,
  49.     -Jeff
  50. -- 
  51. Jeff Beadles        jeff@onion.pdx.com
  52.  
  53.  
  54.  
  55. #--------------------------------CUT HERE-------------------------------------
  56. #! /bin/sh
  57. #
  58. # This is a shell archive.  Save this into a file, edit it
  59. # and delete all lines above this comment.  Then give this
  60. # file to sh by executing the command "sh file".  The files
  61. # will be extracted into the current directory owned by
  62. # you with default permissions.
  63. #
  64. # The files contained herein are:
  65. #
  66. # -rw-r--r--  1 jeff         1486 Dec 24 22:35 smaillog.READ
  67. # -r--r--r--  1 jeff         9628 Dec 24 22:23 smaillog.c
  68. #
  69. echo 'x - smaillog.READ'
  70. if test -f smaillog.READ; then echo 'shar: not overwriting smaillog.READ'; else
  71. sed 's/^X//' << '________This_Is_The_END________' > smaillog.READ
  72. X
  73. XSmail3 log file parser.  Copyright 1990, Jeff Beadles.  All rights reserved.
  74. X        jeff@onion.pdx.com or  uunet!onion.pdx.com!jeff
  75. X
  76. XPermission is granted to freely copy this program as long as it is not sold.
  77. X
  78. XSource MUST be provided upon request, and this message must be kept on
  79. Xall copies of the program.
  80. X
  81. X
  82. XWhat this program will do is simple.  It will take the smail3 logfile
  83. Xinformation, and produce a fairly human-readable report.  For example, it
  84. Xwill take the smail3 logfile (/usr/spool/smail/log/logfile on my system)
  85. Xthat looks like:
  86. X
  87. X    12/24/90 00:33:55: [m0innd5-000NXgC] new msg: from root
  88. X    12/24/90 00:33:56: [m0innd5-000NXgC] jeff ... delivered
  89. X    12/24/90 01:24:26: [m0io4L3-000NUrC] new msg: from jeff@onion
  90. X    12/24/90 01:24:29: [m0io4L3-000NUrC] <foo@bar.har.edu> ... delivered
  91. X
  92. Xon stdin, and,  on stdout display:
  93. X
  94. X    Processing 4 lines.  (Used 352 bytes.)
  95. X    00:33:56: root => jeff
  96. X    01:24:29: jeff@onion => <foo@bar.har.edu>
  97. X
  98. XI use this as a part of my nightly system checker.  Anyway, it's something
  99. Xthat I originally wrote for sendmail.  I've changed the field definitions
  100. Xto work with smail3.  Yea, this could be in AWK, but I was in a 'C' kinda
  101. Xof mood at the time.
  102. X
  103. XThis is provided as-is, and you can use it at your own risk.  There's no man
  104. Xpage currently.  One of these days, I might even write one for it.
  105. XUntil then, "Use the source."  I call it like:
  106. X
  107. X% smaillog < /usr/spool/smail/log/OLD/logfile.0 | mail jeff
  108. X
  109. XHave fun,
  110. X    -Jeff
  111. X-- 
  112. XJeff Beadles        jeff@onion.pdx.com
  113. ________This_Is_The_END________
  114. if test `wc -c < smaillog.READ` -ne 1486; then
  115.     echo 'shar: smaillog.READ was damaged during transit (should have been 1486 bytes)'
  116. fi
  117. fi        ; : end of overwriting check
  118. echo 'x - smaillog.c'
  119. if test -f smaillog.c; then echo 'shar: not overwriting smaillog.c'; else
  120. sed 's/^X//' << '________This_Is_The_END________' > smaillog.c
  121. X/*
  122. X *
  123. X * Parse smail3 log files.
  124. X *
  125. X * Copyright 1990, Jeff Beadles.  All rights reserved.
  126. X *
  127. X * Permission is granted to freely copy this program as long as it is
  128. X * not sold.  Source MUST be provided upon request.
  129. X *
  130. X * This message must be kept on all copies of the program.
  131. X *
  132. X *    jeff@onion.pdx.com
  133. X *  or  uunet!onion.pdx.com!jeff
  134. X *
  135. X *    $Header: smaillog.c,v 1.4 90/12/24 22:23:36 jeff Exp $
  136. X */
  137. X
  138. X
  139. X#include <stdio.h>
  140. X#include <ctype.h>
  141. X#include <strings.h>
  142. X
  143. Xvoid add_data();
  144. Xstruct qlist *lookup();
  145. Xchar *skipfields();
  146. X
  147. Xextern char *mspace();
  148. Xlong int malloc_space = 0L;    /* Space malloc had to allocate */
  149. X
  150. X/*
  151. X *    The qlist structure holds each unique "qid"'s entry.  It also
  152. X *    points to the data structures.
  153. X *    This is stored as a linked list with "qhead" pointing to the head
  154. X *    of the list.
  155. X */
  156. Xstruct qlist {
  157. X    char qid[32];
  158. X    char date[24];
  159. X    struct data *dp;
  160. X    struct qlist *next;
  161. X    };
  162. X
  163. X/*
  164. X *    The data structure is the data information for the qlist structure.
  165. X *    There can be (and most likely are) multiple data structs for each
  166. X *    qlist structure.
  167. X *    tfl == "to from list"
  168. X */
  169. X
  170. Xstruct data {
  171. X    char *tfl;
  172. X    struct data *next;
  173. X    };
  174. X
  175. X/*
  176. X *    The structures look like this:
  177. X *
  178. X *
  179. X *    (qhead)  qlist  -> data1 -> data2 -> data3
  180. X *          \|/
  181. X *         qlist  -> data1 -> data2
  182. X *          \|/
  183. X *         qlist  -> data1 -> data2 -> data3 -> data4 -> data5
  184. X *          \|/
  185. X *          NULL   (End of list )
  186. X *
  187. X */
  188. X
  189. Xstatic struct qlist *qhead;
  190. Xextern char *fgets();
  191. X
  192. X/* ARGSUSED */
  193. Xint
  194. Xmain(argc,argv)
  195. Xint argc;
  196. Xchar **argv;
  197. X{
  198. X    struct data  *dtmp;
  199. X    struct qlist *qtmp;
  200. X
  201. X    char linebuf[4096], buffer[4096];
  202. X    char line_date[24];
  203. X    char *fg, *cp;
  204. X    int lines = 0;
  205. X    char to[4096], from[4096];
  206. X    char *source, *dest;
  207. X    extern int strspn();
  208. X    int itmp;
  209. X    char *ctmp;
  210. X
  211. X    qhead =(struct qlist *)NULL;
  212. X
  213. X/*
  214. X * Give a terse usage message if called with arguements.
  215. X */
  216. X    if ( argc != 1) {
  217. X       fprintf(stderr, "Error:  Usage:  %s < input > output\n",argv[0]);
  218. X       exit(1);
  219. X    }
  220. X/*
  221. X * Read each line from stdin
  222. X */
  223. X    while ((fg=fgets(linebuf, sizeof(linebuf) - 1,stdin)) != (char *)NULL){
  224. X        lines++;
  225. X
  226. X/*
  227. X * Blast out the \n at the end... 
  228. X */
  229. X    ctmp = rindex(fg, '\n');
  230. X    if (ctmp) {
  231. X        *ctmp = '\0';
  232. X    }
  233. X
  234. X/* 
  235. X * Skip "01/01/90 "  This is meant to run daily.  If not, then remove this
  236. X * section of code.
  237. X */
  238. X
  239. X        if ((fg=skipfields(fg, 1)) == (char *)NULL) {
  240. X            printf("Error:  Skip 1 on %s\n", linebuf);
  241. X            continue;
  242. X        }
  243. X
  244. X/*
  245. X * Save the date, to be put in the qlist structure later
  246. X */
  247. X        (void)strncpy(line_date, fg, 8);
  248. X/* 
  249. X * Skip past the date field now, as we have it.
  250. X */
  251. X        if ((fg=skipfields(fg,1)) == (char *)NULL) {
  252. X            printf("Error:  Skip 1 on %s\n", linebuf);
  253. X            continue;
  254. X        }
  255. X/*
  256. X * Catches "open_spool:" and "pid ##: smail daemon started" and other stuff.
  257. X * This just copies them verbatium to the output file.
  258. X * (At the head of the list)
  259. X */
  260. X        if ( *fg != '[' ) {
  261. X            printf("Warning: %s\n", fg);
  262. X            continue;
  263. X        }
  264. X/* 
  265. X * Put qid in "buffer"  It looks like "[xxxxxx-xxxxxxx]".
  266. X * This is the identifier that is used to index into the qlist struct.
  267. X */
  268. X        cp=buffer;
  269. X        while(!isspace(*fg))
  270. X            *cp++ = *fg++;
  271. X        *cp = '\0';
  272. X
  273. X/*
  274. X * buffer now contains the qid, so look it up in the qlist.
  275. X * Lookup will always return success.  It will malloc a new area if this
  276. X * is a new record.
  277. X */
  278. X        qtmp = lookup(buffer);
  279. X        (void)strcpy(qtmp->date, line_date);
  280. X
  281. X/*
  282. X * Now, skip past the qid, and on to the ftl (to/from list).
  283. X * This is added to a data structure attached to the qlist.
  284. X */
  285. X        if ((fg=skipfields(fg,1)) == (char *)NULL) {
  286. X            printf("Error:  Skip 1 on %s\n", linebuf);
  287. X            continue;
  288. X        }
  289. X        add_data(qtmp, fg);
  290. X    }
  291. X/*
  292. X * Note:  We are now out of the fgets() loop, and have all of the information
  293. X * loaded in the struct.  Time to print some stats, and process the info.
  294. X */
  295. X
  296. X    printf("Processing %d lines.  (Used %ld bytes.)\n",lines,malloc_space);
  297. X
  298. X/*
  299. X * Time to start stepping thru the list.  Start at the head, and process each
  300. X * qlist structure and it's data elements.
  301. X */
  302. X    qtmp = qhead;
  303. X
  304. X    while(qtmp) {
  305. X        dtmp = qtmp->dp;
  306. X        *from = *to = '\0';
  307. X        while(dtmp) {
  308. X
  309. X/* This marks a "from" line.  If so, then strip off the first 14 characters,
  310. X * and set the variable "from" to point to it.  It will automatically
  311. X * append to the from line if needed.  It copies until it reaches the
  312. X * end of line, or a ','.  The comma starts showing the origination qid.
  313. X */
  314. X            if ( !strncmp(dtmp->tfl, "new msg: from ", 14)) {
  315. X                dest = from + strlen(from);
  316. X                source = dtmp->tfl + 14;
  317. X                while (*source && (*source != ',') )
  318. X                    *dest++ = *source++;
  319. X                *dest = '\0';
  320. X                dtmp = dtmp->next;
  321. X                continue;
  322. X            }
  323. X/* This is used to see if this is a "to" line.  If so, then the LAST 14
  324. X * characters will match the " ... delivered" string.  Do a little pointer
  325. X * fun to find the right position in the string, and check it.  If this is
  326. X * a "to" line, then append this to the "to" variable
  327. X */
  328. X            itmp = strlen(dtmp->tfl) - 14;
  329. X            if ( itmp >= 0) {
  330. X               ctmp = dtmp->tfl;
  331. X               ctmp += itmp;
  332. X                if (!strncmp(ctmp, " ... delivered",14)){
  333. X                    *ctmp = '\0';
  334. X                    dest = to + strlen(to);
  335. X                    source = dtmp->tfl ;
  336. X                    while (*source)
  337. X                        *dest++ = *source++;
  338. X                    *dest++ = ' ';
  339. X                    *dest   = '\0';
  340. X                    dtmp = dtmp->next;
  341. X                    continue;
  342. X                }
  343. X            }
  344. X/* A general error trap, that should not be reached, but you know how that
  345. X * goes... :-)
  346. X */
  347. X            printf("What is %s?\n", dtmp->tfl);
  348. X            dtmp = dtmp->next;
  349. X        }
  350. X/* At this point, we have traveled thru one entire message's data.
  351. X * Now, print the date, and the to and from information.  Try to figure
  352. X * out if this is to, or from someone on this machine, to do the "=>" "<="
  353. X * right.  If all else fails though, punt and guess.
  354. X */
  355. X        if ( *to && *from) {
  356. X            printf("%s: ", qtmp->date);
  357. X/*
  358. X * kill trailing ',' and whitespace in the 'to' and 'from' fields
  359. X */
  360. X            cp = to + strlen(to) - 1;
  361. X            while ((*cp) && (isspace(*cp) || (*cp == ',')))
  362. X                *cp-- = '\0';
  363. X
  364. X            cp = from + strlen(from) - 1;
  365. X            while ((*cp) && (isspace(*cp) || (*cp == ',')))
  366. X                *cp-- = '\0';
  367. X/*
  368. X * All of that for this to display it
  369. X */
  370. X            printf("%s => %s\n", from, to);
  371. X        }
  372. X/*
  373. X * Time to get the next element and process it.
  374. X */
  375. X        qtmp = qtmp->next;
  376. X    }
  377. X
  378. X
  379. X    exit(0);
  380. X}
  381. X
  382. X/*
  383. X * This routine will add the data (str) to the qlist member "q"
  384. X */
  385. X
  386. Xvoid
  387. Xadd_data(q, str)
  388. Xstruct qlist *q;
  389. Xchar *str;
  390. X{
  391. X    struct data *dtmp;
  392. X    char *cp;
  393. X
  394. X/*
  395. X * Save the string
  396. X */
  397. X    cp = mspace( (unsigned int)(strlen(str)));
  398. X    (void)strcpy(cp, str);
  399. X
  400. X/*
  401. X * If the data area is empty, then just load this into it.
  402. X * and point the "next" entry to null.
  403. X */
  404. X    if (q->dp == (struct data *)NULL) {
  405. X        q->dp = (struct data *)mspace(sizeof(struct data));
  406. X        dtmp = q->dp;
  407. X        dtmp->tfl = cp;
  408. X        dtmp->next = (struct data *)NULL;
  409. X        return;
  410. X    }
  411. X/*
  412. X * otherwise, search and find the end of the data list for this qlist.
  413. X * Then, add it to the end.
  414. X */
  415. X    dtmp = q->dp;
  416. X    while(dtmp->next != (struct data *)NULL) {
  417. X        dtmp= dtmp->next;
  418. X    }
  419. X/*
  420. X * Get space for the new element, and add it to the end of the list.
  421. X * Then, move to the new element, and add the data to it.
  422. X * After that, set the "next" flag to null, to show that this is now
  423. X * the end of the list.
  424. X */
  425. X    dtmp->next=(struct data *)mspace(sizeof (struct data));
  426. X    dtmp = dtmp->next;
  427. X    dtmp->tfl = cp;
  428. X    dtmp->next = (struct data *)NULL;
  429. X}
  430. X
  431. X
  432. X/*
  433. X * This routine will search the qlist for an element with the "key" of
  434. X * the qid this is called with.  If not found, then it will automatically
  435. X * allocate a new member, and initialize it properly
  436. X */
  437. Xstruct qlist *
  438. Xlookup(str)
  439. Xchar *str;
  440. X{
  441. X
  442. X    struct qlist *qtmp = qhead;
  443. X
  444. X
  445. X/*
  446. X * Is this an empty list?  If so, then add to head.
  447. X */
  448. X    if ( qhead == (struct qlist *)NULL) {
  449. X        qhead = (struct qlist *)mspace(sizeof (struct qlist));
  450. X        qtmp = qhead;
  451. X        (void)strcpy(qtmp->qid, str);
  452. X        qtmp->dp = (struct data *)NULL;
  453. X        qtmp->next = (struct qlist *) NULL;
  454. X        return (qtmp);
  455. X    }
  456. X    while (1) {
  457. X/*
  458. X * Does this one match?  If so, then return it.
  459. X */
  460. X        if (!strcmp(qtmp->qid, str)) {
  461. X            return(qtmp);
  462. X        }
  463. X/*
  464. X * If at the end of the list, then add it.
  465. X */
  466. X        if (qtmp->next == (struct qlist *)NULL) {
  467. X            qtmp->next=(struct qlist *)mspace(sizeof(struct qlist));
  468. X            qtmp = qtmp->next;
  469. X            (void)strcpy(qtmp->qid, str);
  470. X            qtmp->dp = (struct data *)NULL;
  471. X            qtmp->next = (struct qlist *) NULL;
  472. X            return (qtmp);
  473. X        }
  474. X        qtmp = qtmp->next;
  475. X    }
  476. X}
  477. X
  478. X
  479. X/*
  480. X * This routine just skips past whitespace-delimited fields in a string.
  481. X * IE:  If called as skipfields("a bb ccc dddd eeeee",2) it will return
  482. X *  "ccc dddd eeeee"
  483. X */
  484. Xchar *
  485. Xskipfields(str,count)
  486. Xchar *str;
  487. Xint count;
  488. X
  489. X{
  490. X    if ( count < 1 )
  491. X        return( (char *)NULL);
  492. X
  493. X    while (count--) {
  494. X        while((*str) && !(isspace(*str)))
  495. X            str++;
  496. X        if (!*str)
  497. X            return( (char *)NULL);
  498. X        while((*str) && (isspace(*str)))
  499. X            str++;
  500. X        if (!*str)
  501. X            return( (char *)NULL);
  502. X    }
  503. X    return(str);
  504. X}
  505. X
  506. X/* This routine is a general "malloc" routine.  It does two additional
  507. X * functions though.  One, is to keep track of how much space has been
  508. X * malloc'ed, and the second is to automatically check for errors, and bail-
  509. X * out if needed.  This prevents me from having to put the same code around
  510. X * all of the malloc's.
  511. X *
  512. X * It also allocates "FUZZ" more bytes than were requested.  If you're 
  513. X * having troubles with this, then change it to something >0.
  514. X * (Don't make it less than 0 though, snicker :-)
  515. X */
  516. X
  517. X#ifndef FUZZ
  518. X#define FUZZ 0
  519. X#endif /* !FUZZ */
  520. X
  521. Xchar *
  522. Xmspace(len)
  523. Xunsigned int len;
  524. X{
  525. X    static char *mp;
  526. X    extern char *malloc();
  527. X
  528. X    len += FUZZ;
  529. X
  530. X    mp = malloc(len);
  531. X
  532. X    if ( mp) { 
  533. X      malloc_space += len;
  534. X      return(mp);
  535. X    } else {
  536. X      fprintf(stderr, "Malloc:\tOut of space (Requested %d bytes)\n",len);
  537. X      fprintf(stderr, "\tAlready requested %ld bytes\n", malloc_space);
  538. X      exit(1);
  539. X    }
  540. X    /*NOTREACHED*/
  541. X}
  542. ________This_Is_The_END________
  543. if test `wc -c < smaillog.c` -ne 9628; then
  544.     echo 'shar: smaillog.c was damaged during transit (should have been 9628 bytes)'
  545. fi
  546. fi        ; : end of overwriting check
  547. exit 0
  548.