home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / contrib / smail / smail-3.1 / smail-3 / smail-3.1.28 / src / log.c < prev    next >
C/C++ Source or Header  |  1992-09-20  |  20KB  |  819 lines

  1. /* @(#)src/log.c    1.10 9/20/92 18:45:29 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  *    Copyright (C) 1992  Ronald S. Karr
  6.  * 
  7.  * See the file COPYING, distributed with smail, for restriction
  8.  * and warranty information.
  9.  */
  10.  
  11. /*
  12.  * log.c:
  13.  *    system and per-message logging functions
  14.  *
  15.  *    These functions send information to a per-system log file and to
  16.  *    a per-message log file, manage the creation use and removal of
  17.  *    per-message logs and handle panic and fatal messages.
  18.  *
  19.  *    external functions:  open_system_logs, close_system_logs,
  20.  *                 open_msg_log, close_msg_log, unlink_msg_log,
  21.  *                 panic, write_log, send_log, scan_msg_log
  22.  */
  23. #include "defs.h"
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <errno.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #ifdef ANSI_C
  30. #include <stdarg.h>
  31. #else
  32. #include <varargs.h>
  33. #endif
  34. #include "smail.h"
  35. #include "dys.h"
  36. #include "log.h"
  37. #include "addr.h"
  38. #include "main.h"
  39. #include "spool.h"
  40. #include "exitcodes.h"
  41. #ifndef DEPEND
  42. # include "debug.h"
  43. # include "extern.h"
  44. #endif
  45.  
  46. #ifdef    UNIX_BSD
  47. # include <sys/file.h>
  48. #endif
  49. #ifdef    UNIX_SYS5
  50. # include <fcntl.h>
  51. #endif
  52.  
  53. /* exported variables */
  54. FILE *msg_logfile = NULL;        /* open stream to per-message log */
  55.  
  56. /* variables local to this file */
  57. static FILE *panicfile = NULL;        /* open stream to panic log file */
  58. static FILE *logfile = NULL;        /* open stream to system log file */
  59. static char *msg_log_fn;        /* name of per-message log file */
  60.  
  61. /* functions local to this file */
  62. static void build_msg_log_fn();
  63. static void try_mkdir();
  64. static void write_log_va();
  65.  
  66. /* variables imported from the C library */
  67. extern int errno;            /* system error number */
  68.  
  69.  
  70. /*
  71.  * open_system_logs - open the panic and the general information log files.
  72.  *
  73.  * Access to the system log should not require that much be functional
  74.  * or that resources be allocated to send to the system log.  For that
  75.  * reason, we allocate all resources in advance, while resources are
  76.  * available and the system is assumed to be somewhat sane.
  77.  *
  78.  * If reasonable, the system logs should be opened after a message has
  79.  * been read to a spool file so that if a panic occurs because a log
  80.  * could not be opened we can recover mail later when the problem is
  81.  * solved.
  82.  */
  83. void
  84. open_system_logs()
  85. {
  86.     int fd;
  87.     static char panicbuf[BUFSIZ];    /* stdio buffer to avoid mallocs */
  88.     static char logbuf[BUFSIZ];        /* stdio buffer to avoid mallocs */
  89.  
  90.     /*
  91.      * first open panic log so we can panic if we can't open
  92.      * the system log
  93.      */
  94. #ifdef    O_APPEND
  95.     fd = open(panic_fn, O_CREAT|O_APPEND|O_WRONLY, log_mode);
  96. #else
  97.     /* limited to V7 open semantics */
  98.     fd = open(panic_fn, 1);
  99.     if (fd < 0) {
  100.     fd = creat(panic_fn, log_mode);
  101.     } else {
  102.     (void) lseek(fd, 0L, 2);
  103.     }
  104. #endif
  105.     if (fd < 0) {
  106.     /* perhaps the directory just needs to be created */
  107.     if (auto_mkdir && errno == ENOENT) {
  108.         try_mkdir(panic_fn);
  109.         /* try opening the file again */
  110. #ifdef O_APPEND
  111.         fd = open(panic_fn, O_CREAT|O_APPEND|O_WRONLY, log_mode);
  112. #else
  113.         fd = creat(panic_fn, log_mode);
  114. #endif
  115.     }
  116.     if (fd < 0) {
  117.         panic(EX_OSFILE, "cannot open %s: %s", panic_fn, strerrno());
  118.         /*NOTREACHED*/
  119.     }
  120.     }
  121.     panicfile = fdopen(fd, "a");
  122.     (void) setbuf(panicfile, panicbuf);    /* associate stream and buffer */
  123.  
  124.     /*
  125.      * next open the system log file after which we can start issuing
  126.      * log messages.
  127.      */
  128. #ifdef    O_APPEND
  129.     fd = open(log_fn, O_CREAT|O_APPEND|O_WRONLY, log_mode);
  130. #else
  131.     /* limited to V7 open semantics */
  132.     fd = open(log_fn, 1);
  133.     if (fd < 0) {
  134.     fd = creat(log_fn, log_mode);
  135.     } else {
  136.     (void) lseek(fd, 0L, 2);
  137.     }
  138. #endif
  139.     if (fd < 0) {
  140.     /* perhaps the directory just needs to be created */
  141.     if (auto_mkdir && errno == ENOENT) {
  142.         try_mkdir(log_fn);
  143.         /* try opening the file again */
  144. #ifdef    O_APPEND
  145.         fd = open(log_fn, O_CREAT|O_APPEND|O_WRONLY, log_mode);
  146. #else
  147.         fd = creat(log_fn, log_mode);
  148. #endif
  149.     }
  150.     if (fd < 0) {
  151.         panic(EX_OSFILE, "cannot open %s: %s", log_fn, strerrno());
  152.         /*NOTREACHED*/
  153.     }
  154.     }
  155.     logfile = fdopen(fd, "a");
  156.     (void) setbuf(logfile, logbuf);    /* associate stream and buffer */
  157. }
  158.  
  159. /*
  160.  * try_mkdir - try to build the directory for the given filename
  161.  */
  162. static void
  163. try_mkdir(fn)
  164.     char *fn;
  165. {
  166.     char *slash = rindex(fn, '/');
  167.     char *dr;
  168.     struct stat st;
  169.  
  170.     if (slash == NULL) {
  171.     return;                /* ignore bad filename */
  172.     }
  173.  
  174.     /* figure directory name */
  175.     while (slash > fn && *(slash - 1) == '/')
  176.     --slash;
  177.     if (slash == fn)
  178.     return;            /* root directory */
  179.     dr = xmalloc(slash - fn + 1);
  180.     (void) memcpy(dr, fn, slash - fn);
  181.     dr[slash - fn] = '\0';
  182.  
  183.     DEBUG1(DBG_LOG_LO, "make directory %s\n", dr);
  184.     (void) mkdir(dr, auto_mkdir_mode);
  185.  
  186.     if (stat(dr, &st) == -1 && errno == ENOENT) {
  187.     char *slash2 = rindex(dr, '/');
  188.  
  189.     if (slash2) {
  190.         while (slash2 > dr && *(slash2 - 1) == '/')
  191.         --slash2;
  192.         if (slash2 != dr) {
  193.         *slash2 = '\0';
  194.         DEBUG1(DBG_LOG_LO, "    make parent directory %s\n", dr);
  195.         (void) mkdir(dr, auto_mkdir_mode);
  196.         *slash2 = '/';
  197.         (void) mkdir(dr, auto_mkdir_mode);
  198.         }
  199.     }
  200.     }
  201.  
  202.     xfree(dr);
  203. }
  204.  
  205. /*
  206.  * close_system_logs - close the panic and general info log files.
  207.  */
  208. close_system_logs()
  209. {
  210.     if (logfile) {
  211.     (void) fclose(logfile);
  212.     logfile = NULL;
  213.     }
  214.     if (panicfile) {
  215.     (void) fclose(panicfile);
  216.     panicfile = NULL;
  217.     }
  218. }
  219.  
  220.  
  221. /*
  222.  * open_msg_log - open message log file, one per message
  223.  *
  224.  * a per-message log should be opened once for each message and closed
  225.  * when done processing a message.  It is intended to be information
  226.  * that a sender might be interested in, and will be sent back to
  227.  * the sender if the return_to_sender flag is set when processing of
  228.  * the message is completed.
  229.  */
  230. void
  231. open_msg_log()
  232. {
  233.     int fd;
  234.     static char msgbuf[BUFSIZ];        /* stdio buffer to avoid mallocs */
  235.  
  236.     /*
  237.      * if msg_fn not yet set up create a suitably unique value
  238.      */
  239.     if (msg_logfile) {
  240.     (void) fclose(msg_logfile);
  241.     }
  242.     build_msg_log_fn();
  243. #ifdef    O_APPEND
  244.     fd = open(msg_log_fn, O_CREAT|O_APPEND|O_WRONLY, log_mode);
  245. #else
  246.     /* limited to V7 open semantics */
  247.     fd = open(msg_log_fn, 1);
  248.     if (fd < 0) {
  249.     fd = creat(msg_log_fn, log_mode);
  250.     } else {
  251.     (void) lseek(fd, 0L, 2);
  252.     }
  253. #endif
  254.     if (fd < 0) {
  255.     if (errno == ENOENT) {
  256.         /* the directory did not exist, try to create it */
  257.         DEBUG1(DBG_LOG_LO, "make directory %s/msglog\n",
  258.            spool_dir);
  259.         (void) mkdir("msglog", auto_mkdir_mode);
  260.     } else {
  261.         /* alternate idea, permissions wrong so try to remove it */
  262.         (void) unlink(panic_fn);
  263.     }
  264. #ifdef    O_APPEND
  265.     fd = open(msg_log_fn, O_CREAT|O_APPEND|O_WRONLY, log_mode);
  266. #else
  267.     /* limited to V7 open semantics */
  268.     fd = open(msg_log_fn, 1);
  269.     if (fd < 0) {
  270.         fd = creat(msg_log_fn, log_mode);
  271.     } else {
  272.         (void) lseek(fd, 0L, 2);
  273.     }
  274. #endif
  275.     if (fd < 0) {
  276.         /*
  277.          * otherwise, panic.  We are assuming that the mail
  278.          * queue entry can be scanned at a later date
  279.          */
  280.         panic(EX_OSFILE, "cannot open %s/%s: %s",
  281.           spool_dir, msg_log_fn, strerrno());
  282.         /*NOTREACHED*/
  283.     }
  284.     }
  285.     msg_logfile = fdopen(fd, "a");
  286.     (void) setbuf(msg_logfile, msgbuf);    /* associate stream and buffer */
  287. }
  288.  
  289. /*
  290.  * build_msg_log_fn - build the name for the per-message log file
  291.  */
  292. static void
  293. build_msg_log_fn()
  294. {
  295.     static char buf[sizeof("msglog/") + SPOOL_FN_LEN + 1];
  296.  
  297.     (void) sprintf(buf, "msglog/%s", spool_fn);
  298.     msg_log_fn = buf;
  299. }
  300.  
  301. /*
  302.  * close_msg_log - close the per-message log file
  303.  *
  304.  * This should be called when further processing of a message is
  305.  * being postponed to some point in the future.
  306.  */
  307. void
  308. close_msg_log()
  309. {
  310.     if (msg_logfile) {
  311.     (void) fclose(msg_logfile);
  312.     msg_logfile = NULL;
  313.     }
  314. }
  315.  
  316. /*
  317.  * unlink_msg_log - close and unlink the per-message log file
  318.  *
  319.  * use this when a message has been processed completely.
  320.  */
  321. void
  322. unlink_msg_log()
  323. {
  324.     close_msg_log();
  325.     if (msg_log_fn) {
  326.     (void) unlink(msg_log_fn);
  327.     msg_log_fn = NULL;
  328.     }
  329. }
  330.  
  331.  
  332. /*
  333.  * panic - panic and die, attempting to write to the panic log file.
  334.  *
  335.  * If we fail to write to the panic log file, write to the console.
  336.  * In all cases try to write to stderr.
  337.  *
  338.  * If this is called after spooling a message, then the message will
  339.  * stay around for further processing.
  340.  *
  341.  */
  342. /*VARARGS2*/
  343. #ifdef ANSI_C
  344. void
  345. panic(int exitcode, char *fmt, ...)
  346. #else
  347. void
  348. panic(exitcode, fmt, va_alist)
  349.     int exitcode;            /* we will call exit(exitcode) */
  350.     char *fmt;                /* printf(3) format */
  351.     va_dcl                              /* arguments for printf */
  352. #endif
  353. {
  354.     static int panic_count = 0;        /* panic not yet called once */
  355.     va_list ap;
  356.  
  357.     /*
  358.      * if panic has been called before, but the panic log is not open
  359.      * write to the console.
  360.      *
  361.      * NOTE:  This will happen when open_system_logs calls panic because
  362.      *          it could not open the panic log file.
  363.      */
  364.     if ((panicfile == NULL && panic_count == 1) || panic_count == 2) {
  365.     FILE *consfile;
  366.     static char consbuf[BUFSIZ];
  367.  
  368.     consfile = fopen(cons_fn, "a");
  369.     if (consfile == NULL) {
  370.         /*
  371.          * not many situations are more difficult to handle than
  372.          * this one--punt.
  373.          */
  374.         if (force_zero_exitvalue) {
  375.         /* if this is set, always exit with 0 */
  376.         exit(0);
  377.         }
  378.         exit(exitcode);
  379.     }
  380.     (void)setbuf(consfile, consbuf); /* avoid use of malloc */
  381.  
  382. #ifdef GLOTZNET
  383.     (void)fprintf(consfile, "%s ", glotzhost);
  384. #endif /* GLOTZNET */
  385.     (void)fprintf(consfile, "%s %s: mailer error: ",
  386.               program, time_stamp());
  387.     if (message_id) {
  388.         (void)fprintf(consfile, "[%s] ", message_id);
  389.     }
  390. #ifdef ANSI_C
  391.     va_start(ap, fmt);
  392. #else
  393.     va_start(ap);
  394. #endif
  395.     (void)vfprintf(consfile, fmt, ap);
  396.     va_end(ap);
  397.     /* log messages don't come with \n */
  398.     (void)fprintf(consfile, "\r\n");
  399.     (void)fclose(consfile);        /* flush */
  400.     } else {
  401.     panic_count++;            /* help stamp out recursion */
  402. #ifdef ANSI_C
  403.     va_start(ap, fmt);
  404. #else
  405.     va_start(ap);
  406. #endif
  407.     write_log_va(LOG_PANIC, fmt, ap);
  408.     va_end(ap);
  409. #ifdef ANSI_C
  410.     va_start(ap, fmt);
  411. #else
  412.     va_start(ap);
  413. #endif
  414.     write_log_va(LOG_TTY, fmt, ap);
  415.     va_end(ap);
  416.     }
  417.  
  418.     if (daemon_pid != 0 && daemon_pid == getpid()) {
  419.     write_log(LOG_SYS, "pid: smail daemon exiting on panic");
  420.     }
  421.     if (spool_fn) {
  422.     defer_message();        /* put message in error/ directory */
  423.     }
  424.     if (force_zero_exitvalue) {
  425.     exit(0);
  426.     }
  427.     exit(exitcode);
  428. }
  429.  
  430. #define LOG_DEBUG 0x0020
  431. /*
  432.  * write_log - write to the per-message log, and perhaps the system log
  433.  *
  434.  * write a log message to the various log files, where `who' is the
  435.  * bitwise OR of LOG_SYS, LOG_MLOG and/or LOG_PANIC.
  436.  */
  437. /*VARARGS2*/
  438. #ifdef ANSI_C
  439. void
  440. write_log(int who, char *fmt, ...)
  441. #else
  442. void
  443. write_log(who, fmt, va_alist)
  444.     int who;                /* mask of log files to be written */
  445.     char *fmt;                /* printf(3) format */
  446.     va_dcl                              /* arguments for printf */
  447. #endif
  448. {
  449.     va_list ap;
  450.  
  451. #ifndef NODEBUG
  452.     if (debug && errfile && (debug > 1 || fmt[0] != 'X')) {
  453. #ifdef ANSI_C
  454.     va_start(ap, fmt);
  455. #else
  456.     va_start(ap);
  457. #endif
  458.     write_log_va(LOG_DEBUG, fmt, ap);
  459.     va_end(ap);
  460.     }
  461. #endif
  462.     if (errfile && ((who & LOG_TTY) ||
  463.            ((who & (LOG_MLOG|LOG_PANIC)) &&
  464.             error_processing == TERMINAL &&
  465.             fmt[0] != 'X'))) {
  466. #ifdef ANSI_C
  467.     va_start(ap, fmt);
  468. #else
  469.     va_start(ap);
  470. #endif
  471.     write_log_va(LOG_TTY, fmt, ap);
  472.     va_end(ap);
  473.     }
  474.     if (who & LOG_SYS) {
  475. #ifdef ANSI_C
  476.     va_start(ap, fmt);
  477. #else
  478.     va_start(ap);
  479. #endif
  480.     write_log_va(who, fmt, ap);
  481.     va_end(ap);
  482.     }
  483.     if (who & LOG_PANIC) {
  484. #ifdef ANSI_C
  485.     va_start(ap, fmt);
  486. #else
  487.     va_start(ap);
  488. #endif
  489.     write_log_va(who, fmt, ap);
  490.     va_end(ap);
  491.     }
  492.     if (who & LOG_MLOG) {
  493. #ifdef ANSI_C
  494.     va_start(ap, fmt);
  495. #else
  496.     va_start(ap);
  497. #endif
  498.     write_log_va(who, fmt, ap);
  499.     va_end(ap);
  500.     }
  501. }
  502.  
  503. static void
  504. write_log_va(who, fmt, ap)
  505.     int who;                /* mask of log files to be written */
  506.     char *fmt;                /* printf(3) format */
  507.     va_list ap;                         /* arguments for printf */
  508. {
  509.     switch (who) {
  510. #ifndef NODEBUG
  511.     case LOG_DEBUG: {
  512.     int wct = 0;
  513.  
  514.     /* if we are debugging at all, print logging messages */
  515.     (void) fprintf(errfile, "write_log:");
  516.  
  517.     /* when debugging, tell which log files are to be used */
  518.     if (debug > 1 && (who & LOG_SYS)) {
  519.         (void) fprintf(errfile, " SYS");
  520.         wct++;
  521.     }
  522.     if (debug > 1 && (who & LOG_PANIC)) {
  523.         (void) fprintf(errfile, "%cPANIC", wct++? '|': ' ');
  524.     }
  525.     if (debug > 1 && (who & LOG_MLOG)) {
  526.         (void) fprintf(errfile, "%cMLOG", wct++? '|': ' ');
  527.     }
  528.     if (debug > 1 && (who & LOG_TTY)) {
  529.         (void) fprintf(errfile, "%cTTY", wct++? '|': ' ');
  530.     }
  531.     if (debug > 1) {
  532.         (void) fprintf(errfile, " ");
  533.     }
  534.     (void)vfprintf(errfile, fmt, ap);
  535.     /* log messages don't come with \n */
  536.     (void)fprintf(errfile, "\n");
  537.     (void)fflush(errfile);
  538.     }
  539.     break;
  540.  
  541. #endif    /* NODEBUG */
  542.  
  543.     case LOG_TTY:
  544.     {
  545.     (void) fprintf(errfile, "%s: ", program);
  546.     (void) vfprintf(errfile, fmt, ap);
  547.     /* log messages don't come with \n */
  548.     (void) fprintf(errfile, "\n");
  549.     (void) fflush(errfile);
  550.     }
  551.     break;
  552.  
  553.     case LOG_SYS:
  554.     {
  555.     /* write out permanent log to the system log file */
  556.     if (logfile == NULL || panicfile == NULL) {
  557.         open_system_logs();        /* if system log not open, open it */
  558.     }
  559.     (void)fprintf(logfile, "%s: ", time_stamp());
  560. #ifdef GLOTZNET
  561.     (void)fprintf(logfile, "%s: ", glotzhost);
  562. #endif /* GLOTZNET */
  563.     if (message_id) {
  564.         (void)fprintf(logfile, "[%s] ", message_id);
  565.     }
  566.     (void)vfprintf(logfile, fmt, ap);
  567.     /* log messages don't come with \n */
  568.     (void)fprintf(logfile, "\n");
  569.     (void)fflush(logfile);
  570.     if (ferror(logfile)) {
  571.         panic(EX_IOERR, "error writing %s: %s", log_fn, strerrno());
  572.         /*NOTREACHED*/
  573.     }
  574.     }
  575.     break;
  576.  
  577.     case LOG_PANIC:
  578.     {
  579.     if (panicfile == NULL) {
  580.         open_system_logs();        /* if system log not open, open it */
  581.     }
  582.     (void)fprintf(panicfile, "%s: ", time_stamp());
  583. #ifdef GLOTZNET
  584.     (void)fprintf(panicfile, "%s: ", glotzhost);
  585. #endif /* GLOTZNET */
  586.     if (message_id) {
  587.         (void)fprintf(panicfile, "[%s] ", message_id);
  588.     }
  589.     (void)vfprintf(panicfile, fmt, ap);
  590.     /* log messages don't come with \n */
  591.     (void)fprintf(panicfile, "\n");
  592.     (void)fflush(panicfile);
  593.     if (ferror(panicfile)) {
  594.         panicfile = NULL;
  595.         panic(EX_IOERR, "error writing %s: %s", log_fn, strerrno());
  596.         /*NOTREACHED*/
  597.     }
  598.     }
  599.     break;
  600.  
  601.     /*
  602.      * NOTE:  if there is no spool_dir set, then a per-message logfile
  603.      *          cannot be created, so don't bother writing per-message
  604.      *          log entries.
  605.      */
  606.     case LOG_MLOG:
  607.     if (spool_dir) {
  608.         if (msg_logfile == NULL) {
  609.         open_msg_log();        /* if message log not open, open it */
  610.         }
  611.  
  612.         /* write out the message to the per-message log file */
  613.         (void)vfprintf(msg_logfile, fmt, ap);
  614.         /* log messages don't come with \n */
  615.         (void)fprintf(msg_logfile, "\n");
  616.         (void)fflush(msg_logfile);
  617.         if (ferror(msg_logfile)) {
  618.         panic(EX_IOERR, "error writing %s/%s: %s",
  619.               spool_dir, msg_log_fn, strerrno());
  620.         /*NOTREACHED*/
  621.         }
  622.     }
  623.     break;
  624.  
  625.     }
  626. }
  627.  
  628. /*
  629.  * send_log - write out the per-message log file.
  630.  *
  631.  * Send the per-message log to a file with or without lines that begin
  632.  * with the magic X character.  Also, an optional banner string will
  633.  * be output before any log data.  If no log data is output then the
  634.  * banner string is also not output.
  635.  *
  636.  * Note: we reopen to keep from changing the write position while
  637.  *       reading.
  638.  */
  639. void
  640. send_log(f, all, banner)
  641.     FILE *f;                /* send to this file */
  642.     int all;                /* if TRUE, also send X lines */
  643.     char *banner;            /* if non-NULL precedes log output */
  644. {
  645.     FILE *mlog;                /* message log file */
  646.     register int c;            /* for copying data between files */
  647.     int last_c;
  648.  
  649.     build_msg_log_fn();
  650.     mlog = fopen(msg_log_fn, "r");    /* reopen log file */
  651.     if (mlog == NULL) {
  652.     return;                /* no message file found */
  653.     }
  654.     last_c = '\n';
  655.     while ((c = getc(mlog)) != EOF) {    /* copy from log to specified file */
  656.     if (last_c == '\n' && c == 'X' && !all) {
  657.         /* ignore lines beginning with X */
  658.         while ((c = getc(mlog)) != EOF && c != '\n') ;
  659.         if (c == EOF) {
  660.         break;
  661.         }
  662.         last_c = '\n';
  663.         continue;
  664.     }
  665.     if (last_c == '\n') {
  666.         if (banner) {
  667.         (void)fputs(banner, f);    /* output banner at most once */
  668.         banner = NULL;
  669.         }
  670.         (void)fputs(" ", f);
  671.     }
  672.     putc(c, f);
  673.     last_c = c;
  674.     }
  675.     (void)fclose(mlog);            /* don't need this anymore */
  676. }
  677.  
  678. /*
  679.  * scan_msg_log - scan for X entries in the per-message logfile
  680.  *
  681.  * if first is TRUE, open the message log and scan for the first line
  682.  * marked with an X, return that line.  On successive calls, where
  683.  * first is FALSE, return successive lines marked with an X.  Return
  684.  * NULL if no more such lines are found.
  685.  *
  686.  * returned value points to a string area which may be reused on subsequent
  687.  * calls to scan_msg_log.
  688.  */
  689. char *
  690. scan_msg_log(first)
  691.     int first;                /* TRUE to open the message log */
  692. {
  693.     static FILE *mlog = NULL;        /* opened message log */
  694.     static struct str line;        /* line marked with X */
  695.     static inited_line = FALSE;        /* TRUE if STR_INIT called for line */
  696.     register int c, last_c;
  697.  
  698.     build_msg_log_fn();
  699.     if (first && mlog) {
  700.     rewind(mlog);
  701.     }
  702.     if (mlog == NULL) {
  703.     mlog = fopen(msg_log_fn, "r");    /* reopen log file */
  704.     if (mlog == NULL) {
  705.         return NULL;
  706.     }
  707.     }
  708.     last_c = '\n';
  709.  
  710.     /* scan for line beginning with X */
  711.     while ((c = getc(mlog)) != EOF) {
  712.     if (c == 'X' && last_c == '\n') {
  713.         break;
  714.     }
  715.     last_c = '\n';
  716.     }
  717.     if (c == EOF) {
  718.     /* reached end of file without finding an X line */
  719.     (void) fclose(mlog);
  720.     mlog = NULL;
  721.     return NULL;
  722.     }
  723.     /* found a line marked with X, read it in */
  724.     if (! inited_line) {
  725.     STR_INIT(&line);
  726.     inited_line = TRUE;
  727.     } else {
  728.     line.i = 0;
  729.     }
  730.     STR_NEXT(&line, 'X');
  731.     while ((c = getc(mlog)) != EOF && c != '\n') {
  732.     STR_NEXT(&line, c);
  733.     }
  734.     STR_NEXT(&line, '\0');
  735.  
  736.     /* return that line */
  737.     DEBUG1(DBG_LOG_MID, "scan_msg_log returns: %s\n", line.p);
  738.     return line.p;
  739. }
  740.  
  741.  
  742. #ifdef STANDALONE
  743. char *panic_fn = "/usr/lib/smail/paniclog";
  744. char *log_fn = "/usr/lib/smail/log";
  745. char *cons_fn = "/dev/console";
  746. char *msg_log_dir = "/usr/tmp";
  747. char *program = "this-is-a-test";
  748. int exitvalue = 0;
  749. enum er_proc error_processing = MAIL_BACK;
  750. int return_to_sender = FALSE;
  751. int islocal = TRUE;
  752. char *sender = "nsc!tron";
  753. int force_zero_exitvalue = FALSE;
  754.  
  755. /*
  756.  * excersize the logging code by performing the various operations
  757.  * in a sequence given at run time on the standard input.
  758.  */
  759. void
  760. main()
  761. {
  762.     register int c;            /* hold key for current operation */
  763.     char line[4096];            /* buffer to hold a line of input */
  764.     char *p;
  765.  
  766.     while ((c = getchar()) != EOF) {
  767.     switch (c) {
  768.     case 'O':
  769.         open_system_logs();
  770.         break;
  771.     case 'C':
  772.         close_system_logs();
  773.         break;
  774.     case 'o':
  775.         open_msg_log();
  776.         break;
  777.     case 'c':
  778.         close_msg_log();
  779.         break;
  780.     case 's':
  781.         send_log(stdout, FALSE, "|----- log without X lines -----|\n");
  782.         break;
  783.     case 'S':
  784.         send_log(stdout, TRUE, "|----- log with X lines -----|\n");
  785.         break;
  786.     case 'X':
  787.         for (p = scan_msg_log(TRUE); p; p = scan_msg_log(FALSE)) {
  788.         printf("%s\n", p);
  789.         }
  790.         break;
  791.     case 'p':
  792.         gets(line);
  793.         panic(EX_OSERR, line);
  794.         break;
  795.     case 'l':
  796.         gets(line);
  797.         write_log(LOG_SYS, line);
  798.         break;
  799.     case 'm':
  800.         gets(line);
  801.         write_log(LOG_MLOG, line);
  802.         break;
  803.     case 'L':
  804.         gets(line);
  805.         write_log(LOG_MLOG|LOG_SYS|LOG_PANIC);
  806.         break;
  807.     case ' ':
  808.     case '\t':
  809.     case '\n':
  810.         break;
  811.     default:
  812.         (void)fprintf(stderr, "%c -- huh?\n", c);
  813.         break;
  814.     }
  815.     }
  816.     exit(EX_OK);
  817. }
  818. #endif    /* STANDALONE */
  819.