home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / desktop / t / utils / !Logger_C_LOGGER < prev    next >
Encoding:
Text File  |  1993-11-21  |  19.9 KB  |  812 lines

  1. /*
  2.  *
  3.  *      Title     : Logger process.
  4.  *      System    : Any */
  5. #define Version     "3.0"
  6. /*      Copyright : (c) John H. Winters
  7.  *      Date      : 28th September, 1992
  8.  *      Author    : John H. Winters
  9.  *
  10.  *      Function  : Logs messages to the console and several log files.
  11.  *
  12.  *
  13.  *      Modification history.
  14.  *
  15.  *      Version   : 2.0
  16.  *      Date      : 28th September, 1992
  17.  *      Author    : John H. Winters
  18.  *      Changes   : Re-written to cater for prioritised messages.
  19.  *
  20.  *      Version   : 2.1
  21.  *      Date      : 18th October, 1992
  22.  *      Author    : John H. Winters
  23.  *      Changes   : Added OS/2 PM version.
  24.  *
  25.  *      Version   : 2.2
  26.  *      Date      : 13th November, 1992
  27.  *      Author    : John H. Winters
  28.  *      Changes   : Added the ability to handle a DROP_DEAD message on
  29.  *                  logger's own queue.
  30.  *
  31.  *      Version   : 3.0
  32.  *      Date      : 24th May, 1993
  33.  *      Author    : John H. Winters
  34.  *      Changes   : Updated for Risc OS 3.1
  35.  *
  36.  *      Version   : 
  37.  *      Date      : 
  38.  *      Author    : 
  39.  *      Changes   : 
  40.  *
  41.  */
  42.  
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include <time.h>
  47.  
  48. #if defined (OS2)
  49. #include <process.h>
  50. #define INCL_DOSERRORS
  51. #define INCL_DOSPROCESS
  52. #define INCL_DOSQUEUES
  53. #define INCL_VIO
  54. #include <os2.h>
  55. #endif
  56.  
  57. #include "global.h"
  58.  
  59. #if defined (ARTHUR)
  60. #include "winapp.h"
  61. #endif
  62.  
  63. #include "sdf.h"
  64. #include "logging.h"
  65. #include "fe.h"
  66. #include "internal.h"
  67.  
  68. /*
  69.  *============================================================================
  70.  *
  71.  *  Hash defines.
  72.  *
  73.  *============================================================================
  74.  */
  75.  
  76. #define MAX_FILES   5
  77. #define MAX_LINE    256
  78.  
  79. /*
  80.  *============================================================================
  81.  *
  82.  *  Type definitions.
  83.  *
  84.  *============================================================================
  85.  */
  86.  
  87. #if defined (OS2)
  88. typedef union {
  89.     t_old_msg   old_msg ;
  90.     t_NL_Header message ;
  91. } t_item ;
  92. #endif
  93.  
  94. /*
  95.  *============================================================================
  96.  *
  97.  *  Local data.
  98.  *
  99.  *============================================================================
  100.  */
  101.  
  102. static u8 *FileNames [MAX_FILES]   = {
  103.     NULL,
  104.     NULL,
  105.     NULL,
  106.     NULL,
  107.     NULL
  108. } ;
  109. static uint         FilesReady     = FALSE ;
  110. #if defined (OS2)
  111. static HQUEUE       LogQHandle     = 0 ;
  112. #endif
  113. #if defined (ARTHUR)
  114. static uint         MessageAction ;
  115. #endif
  116. static uint         NumFiles       = 0 ;
  117.  
  118. /*
  119.  *============================================================================
  120.  *
  121.  *  Forward declarations.
  122.  *
  123.  *============================================================================
  124.  */
  125.  
  126. #if defined (OS2)
  127. static uint CreateQueue (void) ;
  128.  
  129. static void Format (
  130.     const U8       *taskname,
  131.     t_LOG_Severity  severity,
  132.     const U8       *message,
  133.     uint            messagelen,
  134.     const U8       *timestamp) ;
  135. #endif
  136.  
  137. static void InitialiseFiles (
  138. #if defined (OS2)
  139.     uint  argc,
  140.     u8   *argv []
  141. #else
  142. void
  143. #endif
  144. ) ;
  145.  
  146. #if defined (ARTHUR)
  147. static uint IpmHandler (
  148.     t_poll_block *poll_block,
  149.     void         *reference) ;
  150. #endif
  151.  
  152. #if defined (OS2)
  153. static void LogText (
  154.     const u8   *text,
  155.     uint        length) ;
  156. #endif
  157.  
  158. static uint
  159. #if defined (OS2)
  160. _loadds
  161. #endif
  162. MessageHandler (
  163.     t_LOG_Severity  severity,
  164.     const U8       *message,
  165.     const U8       *timestamp) ;
  166.  
  167. #if defined (OS2)
  168. static void TidyUp (void) ;
  169. #endif
  170.  
  171. /*
  172.  *============================================================================
  173.  *
  174.  *  Externally visible routines.
  175.  *
  176.  *============================================================================
  177.  */
  178.  
  179. #if defined (OS2)
  180. sint main (
  181.     uint  argc,
  182.     u8   *argv [])
  183.  
  184. /*
  185.  *  Function :
  186.  *                  Main routine of the logger process.
  187.  *
  188.  *  Parameters :
  189.  *                  The usual for main.  Any command line parameter is
  190.  *                  taken as the name of a file to log to.
  191.  *
  192.  *  Returns :
  193.  *                  EXIT_SUCCESS.
  194.  *
  195.  */
  196.  
  197. {
  198.     static t_item     *item ;
  199.     static USHORT      itemlength ;
  200.     t_LOG_HandlerMask  mask = {{TRUE, TRUE, TRUE, TRUE, TRUE}} ;
  201.     u8                 priority ;
  202.     QUEUERESULT        queuestatus ;
  203.     USHORT             result ;
  204.  
  205.     atexit (TidyUp) ;
  206.     LOG_AddHandler (mask, MessageHandler) ;
  207.     if (argc > 1)
  208.     {
  209.         InitialiseFiles (argc, argv) ;
  210.     }
  211. #if defined (PM)
  212.     if ((FE_LoadResources ()) &&
  213.         (FE_BeginProcessing ()))
  214.     {
  215. #endif
  216.         LOG_Info ("Logger version " Version " compiled on " __DATE__ " at " __TIME__ "\n") ;
  217.         if (CreateQueue ())
  218.         {
  219.             LOG_Info ("Logger ready to receive log messages.\n") ;
  220.             /*
  221.              *  Now just wait for incoming messages and log them as they
  222.              *  occur.
  223.              */
  224.             for (;;)
  225.             {
  226.                 result = DosReadQueue (LogQHandle,
  227.                                        &queuestatus,
  228.                                        &itemlength,
  229.                                        &item,
  230.                                        0,
  231.                                        DCWW_WAIT,
  232.                                        &priority,
  233.                                        0) ;
  234.                 if (result == 0)
  235.                 {
  236.                     /*
  237.                      *  Read something.  Elementary security check.
  238.                      */
  239.                     if (item == MAKEP (queuestatus.usEventCode, 0))
  240.                     {
  241.                         if (item->old_msg.header.ident == OLD_LOG_IDENT)
  242.                         {
  243.                             /*
  244.                              *  This should be a message.
  245.                              */
  246.                             if (sizeof (t_old_msg_header) + item->old_msg.header.size ==
  247.                                 itemlength)
  248.                             {
  249.                                 LogText (item->old_msg.body,
  250.                                          item->old_msg.header.size) ;
  251.                             }
  252.                             else
  253.                             {
  254.                                 LOG_Warning ("Log message received with wrong length.\n") ;
  255.                             }
  256.                         }
  257.                         else if (item->message.ident == LOG_IDENT)
  258.                         {
  259.                             /*
  260.                              *  New format log message.
  261.                              */
  262.                             if (item->message.format_version == FORMAT_VERSION)
  263.                             {
  264.                                 if ((itemlength >= sizeof (t_NL_Header)) &&
  265.                                     ((sizeof (t_NL_Header) +
  266.                                       SDF_Getu16 (item->message.text_length)) ==
  267.                                      itemlength))
  268.                                 {
  269.                                     Format (item->message.task_name,
  270.                                             item->message.severity,
  271.                                             (u8 *) ((&item->message) + 1),
  272.                                             SDF_Getu16 (item->message.text_length),
  273.                                             item->message.timestamp) ;
  274.                                 }
  275.                                 else
  276.                                 {
  277.                                     LOG_Warning ("Badly structured log message received.\n") ;
  278.                                 }
  279.                             }
  280.                             else
  281.                             {
  282.                                 LOG_Warning ("Log message received with unknown format version (%d).\n",
  283.                                              item->message.format_version) ;
  284.                             }
  285.                         }
  286.                         else if (item->old_msg.header.ident == DROP_DEAD)
  287.                         {
  288.                             exit (EXIT_SUCCESS) ;
  289.                         }
  290.                         else
  291.                         {
  292.                             LOG_Warning ("Unknown message type - %d - received.\n",
  293.                                          item->message.ident) ;
  294.                         }
  295.                         /*
  296.                          *  Must deallocate the segment.
  297.                          */
  298.                         DosFreeSeg (queuestatus.usEventCode) ;
  299.                     }
  300.                     else
  301.                     {
  302.                         LOG_Warning ("Badly formatted message received.\n") ;
  303.                     }
  304.                 }
  305.             }
  306.         }
  307. #if defined (PM)
  308.     }
  309. #endif
  310.     return (EXIT_SUCCESS) ;
  311. }
  312. #endif
  313.  
  314. #if defined (ARTHUR)
  315. uint WA_BeginProcessing (void)
  316.  
  317. /*
  318.  *  Function :
  319.  *                  Begin processing under Risc-OS
  320.  *
  321.  *  Parameters :
  322.  *                  None.
  323.  *
  324.  *  Returns :
  325.  *                  TRUE for success, FALSE for failure.
  326.  *
  327.  */
  328.  
  329. {
  330.     u8 *string ;
  331.  
  332.     if (FE_BeginProcessing ())
  333.     {
  334.         InitialiseFiles () ;
  335.         LOG_Info ("Logger version " Version " compiled on " __DATE__ " at " __TIME__ "\n") ;
  336.         /*
  337.          *  Now need to register for the appropriate type of incoming messages.
  338.          */
  339.         string = getenv ("Logger$MessNo") ;
  340.         if (string == NULL)
  341.         {
  342.             LOG_Error ("Logger$MessNo is not defined.  Messages cannot be received.\n") ;
  343.             return (TRUE) ;
  344.         }
  345.         else
  346.         {
  347.             MessageAction = atoi (string) ;
  348.             if ((MessageAction & 0x80000) == 0)
  349.             {
  350.                 LOG_Warning ("Logger$MessNo is set to 0x%lx.\n",
  351.                              MessageAction) ;
  352.                 LOG_Warning ("This is not a suitable number for application software.\n") ;
  353.             }
  354.             LOG_Info ("Logger ready to receive log messages.\n") ;
  355.             return (WA_ClaimMessage (MessageAction,
  356.                                      IpmHandler,
  357.                                      NULL)) ;
  358.         }
  359.     }
  360.     else
  361.     {
  362.         return (FALSE) ;
  363.     }
  364. }
  365.  
  366.  
  367. uint WA_LoadResources (void)
  368.  
  369. /*
  370.  *  Function :
  371.  *                  Load our resources as required.
  372.  *
  373.  *  Parameters :
  374.  *                  As received by main ().
  375.  *
  376.  *  Returns :
  377.  *                  TRUE for success, FALSE for failure.
  378.  *
  379.  */
  380.  
  381. {
  382.     t_LOG_HandlerMask  mask = {{TRUE, TRUE, TRUE, TRUE, TRUE}} ;
  383.  
  384.     return ((LOG_AddHandler (mask, MessageHandler)) &&
  385.             (FE_LoadResources ())) ;
  386. }
  387.  
  388. #endif
  389.  
  390. /*
  391.  *============================================================================
  392.  *
  393.  *  Forward declarations.
  394.  *
  395.  *============================================================================
  396.  */
  397.  
  398. #if defined (OS2)
  399. static uint CreateQueue (void)
  400.  
  401. /*
  402.  *  Function :
  403.  *                  Create a queue for other processes to write to.
  404.  *
  405.  *  Parameters :
  406.  *                  None.
  407.  *
  408.  *  Returns :
  409.  *                  TRUE if it is successfully created, FALSE otherwise.
  410.  *
  411.  */
  412.  
  413. {
  414.     if (DosCreateQueue (&LogQHandle,
  415.                         QUE_FIFO,
  416.                         QUEUE_NAME) == 0)
  417.     {
  418.         return (TRUE) ;
  419.     }
  420.     else
  421.     {
  422.         LogQHandle = 0 ;
  423.         LOG_Error ("Failed to create a queue.\n") ;
  424.         return (FALSE) ;
  425.     }
  426. }
  427. #endif
  428.  
  429.  
  430. static void Format (
  431.     const U8       *taskname,
  432.     t_LOG_Severity  severity,
  433.     const U8       *message,
  434.     uint            messagelen,
  435.     const U8       *timestamp)
  436.  
  437. /*
  438.  *  Function :
  439.  *                  Format a chunk of text and send it to the console and all
  440.  *                  active log files.  Note that this routine can be called
  441.  *                  recursively, although not simultaneously from multiple
  442.  *                  threads.  (The LOGGING module guarantees only one call,
  443.  *                  but it is possible that we will be called due to an
  444.  *                  incoming IPM, and then call LOG_Xxxxxx, causing a second
  445.  *                  call on this routine.  Three calls are impossible).
  446.  *
  447.  *  Parameters :
  448.  *                  taskname    Name of the task generating the message.
  449.  *                  severity    Severity of the message.
  450.  *                  message     Text of the message.
  451.  *                  messagelen  Length of message text.
  452.  *                  timestamp   Textual timestamp.
  453.  *
  454.  *  Returns :
  455.  *                  None.
  456.  *
  457.  */
  458.  
  459. {
  460.     u8           buffer [MAX_LINE + 2] ; 
  461.     FILE        *handle ;
  462.     uint         index ;
  463.     u8          *name ;
  464.     static u8    severities [] = "DIWESU" ;
  465.     
  466.     if (LOG_MAX_TASKNAME + LOG_TIMESTAMP_LEN + 8 + messagelen > MAX_LINE)
  467.     {
  468.         messagelen = MAX_LINE - (LOG_MAX_TASKNAME + LOG_TIMESTAMP_LEN + 8) ;
  469.     }
  470.     while ((messagelen > 0) &&
  471.            (message [messagelen - 1] == '\n'))
  472.     {
  473.         messagelen-- ;
  474.     }
  475.     if ((severity < 0) ||
  476.         (severity > 5))
  477.     {
  478.         severity = 5 ;
  479.     }
  480.     sprintf (buffer,
  481.              "%*.*s :%c: %*.*s : %*.*s\n",
  482.              LOG_MAX_TASKNAME,
  483.              LOG_MAX_TASKNAME,
  484.              taskname,
  485.              severities [severity],
  486.              LOG_TIMESTAMP_LEN,
  487.              LOG_TIMESTAMP_LEN,
  488.              timestamp,
  489.              messagelen,
  490.              messagelen,
  491.              message) ;
  492. #if defined (OS2)
  493. #if defined (PM)
  494.     FE_PutText (buffer) ;
  495. #else
  496.     /*
  497.      *  Send it to the screen.
  498.      */
  499.     fwrite (buffer, strlen (buffer), 1, stdout) ;
  500. #endif
  501. #endif
  502. #if defined (ARTHUR)
  503.     FE_PutText (buffer) ;
  504. #endif
  505.     if (FilesReady)
  506.     {
  507.         /*
  508.          *  Send it to the files.
  509.          */
  510.         for (index = 0; index < NumFiles; index++)
  511.         {
  512.             if (FileNames [index] != NULL)
  513.             {
  514.                 handle = fopen (FileNames [index], "a") ;
  515.                 if (handle == NULL)
  516.                 {
  517.                     /*
  518.                      *  File has failed.  Recurse.
  519.                      */
  520.                     name = FileNames [index] ;
  521.                     FileNames [index] = NULL ;
  522.                     LOG_Warning ("Can't open log file \"%s\".\n",
  523.                                  name) ;
  524.                 }
  525.                 else
  526.                 {
  527.                     fwrite (buffer, strlen (buffer), 1, handle) ;
  528.                     fclose (handle) ;
  529.                 }
  530.             }
  531.         }
  532.     }
  533. }
  534.  
  535.  
  536. static void InitialiseFiles (
  537. #if defined (OS2)
  538.     uint  argc,
  539.     u8   *argv []
  540. #else
  541. void
  542. #endif
  543. )
  544.  
  545. /*
  546.  *  Function :
  547.  *                  See which files we can open and write a date
  548.  *                  stamp to each.  Record the active files.
  549.  *
  550.  *  Parameters :
  551.  *                  argc \  As received by main ().
  552.  *                  argv /
  553.  *
  554.  *  Returns :
  555.  *                  None, but updates the file records.
  556.  *
  557.  */
  558.  
  559. {
  560.     FILE   *handle ;
  561.     uint    index ;
  562.     u8     *name ;
  563.     time_t  tp ;
  564. #if !defined (OS2)
  565.     u8     *temp ;
  566.     u8      var_name [] = "Logger$FileN" ;
  567. #endif
  568.  
  569. #if defined (OS2)
  570.     for (index = 1; index < argc; index++)
  571.     {
  572.         name = malloc (strlen (argv [index]) + 1) ;
  573.         if (name == NULL)
  574.         {
  575.             LOG_Error ("Can't allocate space to record log file - \"%s\".\n",
  576.                        argv [index]) ;
  577.         }
  578.         else
  579.         {
  580.             strcpy (name, argv [index]) ;
  581.             if (NumFiles < MAX_FILES)
  582.             {
  583.                 FileNames [NumFiles] = name ;
  584.                 NumFiles++ ;
  585.             }
  586.             else
  587.             {
  588.                 LOG_Error ("Cannot log to \"%s\".  Maximum log files (%d) reached.\n",
  589.                            name,
  590.                            MAX_FILES) ;
  591.                 free (name) ;
  592.             }
  593.         }
  594.     }
  595. #else
  596.     for (index = 0; index < MAX_FILES; index++)
  597.     {
  598.         var_name [strlen (var_name) - 1] = (u8) ('0' + index) ;
  599.         name = getenv (var_name) ;
  600.         if (name != NULL)
  601.         {
  602.             temp = malloc (strlen (name) + 1) ;
  603.             if (temp == NULL)
  604.             {
  605.                 LOG_Error ("Can't allocate space to record log file - \"%s\".\n",
  606.                            name) ;
  607.             }
  608.             else
  609.             {
  610.                 strcpy (temp, name) ;
  611.                 if (NumFiles < MAX_FILES)
  612.                 {
  613.                     FileNames [NumFiles] = temp ;
  614.                     NumFiles++ ;
  615.                 }
  616.                 else
  617.                 {
  618.                     LOG_Error ("Cannot log to \"%s\".  Maximum log files (%d) reached.\n",
  619.                                temp,
  620.                                MAX_FILES) ;
  621.                     free (temp) ;
  622.                 }
  623.             }
  624.         }
  625.     }
  626. #endif
  627.     /*
  628.      *  Now start each of the files.
  629.      */
  630.     for (index = 0; index < NumFiles; index++)
  631.     {
  632.         /*
  633.          *  Try to write a date stamp to it.
  634.          */
  635.         LOG_Info ("Opening log file - \"%s\".\n",
  636.                   FileNames [index]) ;
  637.         handle = fopen (FileNames [index], "a") ;
  638.         if (handle == NULL)
  639.         {
  640.             LOG_Warning ("Can't open log file - \"%s\".\n",
  641.                          FileNames [index]) ;
  642.             free (FileNames [index]) ;
  643.             FileNames [index] = NULL ;
  644.         }
  645.         else
  646.         {
  647.             tp = time (NULL) ;
  648.             fprintf (handle,
  649.                      "++++++++ Log process started - %s",
  650.                      ctime (&tp)) ;
  651.             fclose (handle) ;
  652.         }
  653.     }
  654.     FilesReady = TRUE ;
  655. }
  656.  
  657.  
  658. #if defined (ARTHUR)
  659. static uint IpmHandler (
  660.     t_poll_block *poll_block,
  661.     void         *reference)
  662.  
  663. /*
  664.  *  Function :
  665.  *                  Handle incoming log messages in Risc-OS.
  666.  *
  667.  *  Parameters :
  668.  *                  poll_block  Poll block containing message.
  669.  *                  reference   Ignored.
  670.  *
  671.  *  Returns :
  672.  *                  TRUE if the message was for us, FALSE otherwise.
  673.  *
  674.  */
  675.  
  676. {
  677.     uint         calc_size ;
  678.     t_NL_Header *item ;
  679.  
  680.     reference = reference ;
  681.     /*
  682.      *  Looks like one for us.
  683.      */
  684.     item = (t_NL_Header *) (poll_block->data.mb.data.bytes) ;
  685.     calc_size = 20 + sizeof (t_NL_Header) + SDF_Getu16 (item->text_length) ;
  686.     calc_size = (((calc_size + 3) / 4) * 4) ;
  687.     if (poll_block->data.mb.size == calc_size)
  688.     {
  689.         Format (item->task_name,
  690.                 item->severity,
  691.                 (u8 *) (item + 1),
  692.                 SDF_Getu16 (item->text_length),
  693.                 item->timestamp) ; 
  694.     }
  695.     else
  696.     {
  697.         LOG_Warning ("Badly formatted log message received.\n") ;
  698.     }
  699.     return (TRUE) ;
  700. }
  701. #endif
  702.  
  703.  
  704. #if defined (OS2)
  705. static void LogText (
  706.     const u8   *text,
  707.     uint        length)
  708.  
  709. /*
  710.  *  Function :
  711.  *                  Send a chunk of text to the console and all
  712.  *                  active log files.
  713.  *
  714.  *  Parameters :
  715.  *                  text    The text to log.
  716.  *                  length  Length of the text.
  717.  *
  718.  *  Returns :
  719.  *                  None.
  720.  *
  721.  */
  722.  
  723. {
  724.     struct tm *broken_date ;
  725.     u8         buffer [18] ;
  726.     time_t     time_now ;
  727.  
  728.     time_now = time (NULL) ;
  729.     broken_date = localtime (&time_now) ;
  730.     sprintf (buffer,
  731.              "%02.2d/%02.2d/%02.2d %02.2d:%02.2d:%02.2d",
  732.              broken_date->tm_mday,
  733.              broken_date->tm_mon + 1,
  734.              broken_date->tm_year % 100,
  735.              broken_date->tm_hour,
  736.              broken_date->tm_min,
  737.              broken_date->tm_sec) ;
  738.     Format (text,
  739.             5,
  740.             text + 10,
  741.             length - 10,
  742.             buffer) ;
  743. }
  744. #endif
  745.  
  746. #if defined (OS2)
  747. #include "stackoff.h"
  748. #endif
  749.  
  750. static uint
  751. #if defined (OS2)
  752. _loadds
  753. #endif
  754. MessageHandler (
  755.     t_LOG_Severity  severity,
  756.     const U8       *message,
  757.     const U8       *timestamp)
  758.  
  759. /*
  760.  *  Function :
  761.  *                  Handle a locally generated log message.
  762.  *
  763.  *  Parameters :
  764.  *                  severity    Severity of the message.
  765.  *                  message     Text of the message.
  766.  *                  timestamp   Textual timestamp for the message.
  767.  *
  768.  *  Returns :
  769.  *                  TRUE
  770.  *
  771.  */
  772.  
  773. {
  774.     Format ("LOGGER  ",
  775.             severity,
  776.             message,
  777.             strlen (message),
  778.             timestamp) ;
  779.     return (TRUE) ;
  780. }
  781. #if defined (OS2)
  782. #include "stackon.h"
  783. #endif
  784.  
  785.  
  786. #if defined (OS2)
  787. static void TidyUp (void)
  788.  
  789. /*
  790.  *  Function :
  791.  *                  Tidy up before process exit.
  792.  *
  793.  *  Parameters :
  794.  *                  None.
  795.  *
  796.  *  Returns :
  797.  *                  None.
  798.  *
  799.  */
  800.  
  801. {
  802.     if (LogQHandle != 0)
  803.     {
  804.         DosCloseQueue (LogQHandle) ;
  805.         LogQHandle = 0 ;
  806.     }
  807. #if defined (PM)
  808.     FE_WindDown () ;
  809. #endif
  810. }
  811. #endif
  812.