Example of an Application Program Using a Subroutine

This example shows the user application PROBE.C. The application uses the subroutine approach to call the FFSTProbe function.
User Application using FFST and Trace Subroutines

  /**************************************************************************/
  /* probe.c: FFSTProbe sample                                              */
  /*                                                                        */
  /* This test program gives an example of using the FFSTProbe API and the  */
  /* TraceCreateEntry API by using 'wrapper' functions.  The dummy API      */
  /* My_Dummy_Api returns a return code which is then used as the basis of  */
  /* firing a FFSTProbe via the wrapper function, callFFST.  callFFST can   */
  /* be modified to include more or less data as needed.                    */
  /*                                                                        */
  /**************************************************************************/

  #define INCL_DOS
  #define INCL_DOSMEMMGR
  #define INCL_DOSPROCESS
  #define INCL_FFST
  #define NO_ERROR 0

  #include <os2.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <FFST.h>
  #include <trace.h>

  /**************************************************************************/
  /* Define probe ID for FFSTProbe called when dummy API fails.  Probe ID   */
  /* is the unique identifier you use later to find the source of the       */
  /* failure.  It should be unique within a DMI triplet (explained later)   */
  /* or within your product                                                 */
  /**************************************************************************/
  #define DUMMY_API_PROBE 22222

  void callFFST ( ULONG input_version,           /* FFST 'Wrapper' Function */
              /* input version lets you change the wrapper     */
              /* without changing each call, just make sure    */
              /* the wrapper still treats the 'old' version    */
              /* the same and that any new code is             */
              /* conditioned on a new input_version #          */

                  ULONG input_probe_flags,         /* FFSTProbe probe flags */
                  ULONG input_severity,               /* FFSTProbe severity */
                  ULONG input_probe_id,                     /* FFSTProbe ID */
                  CHAR* input_module_name,   /* module name passed to probe */
                  ULONG input_log_data_length, /* log data length for the
                                                  system error log          */
                  PVOID input_pError_log_data,  /* pointer to the data for
                                                   system error log         */
                  int   argc);

  /*****************************************************/
  /* This is for a common trace entry routine          */
  /*****************************************************/
  #define HKWD_TEST            220        /* major code */
  #define hkwd_test_entry      0x0001     /* minor code for entry */
  #define hkwd_test_exit       0x8001     /* minor code for exit */

  struct
  {
    int count;
    char textì12┘;
  } trace_capture_start, trace_capture_end;

  APIRET trace_out(ULONG major, ULONG minor, void *trace_data,
                    ULONG data_len);      /* trace wrapper function */

  /**************************************/
  /* End of trace declarations for Main */
  /**************************************/

  ULONG My_Dummy_API(ULONG Mydata);


  /**************************************************************************/
  /*                                                                        */
  /*  Main Application (this uses the callFFST wrapper function).           */
  /*                                                                        */
  /**************************************************************************/

  int main ( int argc, char * argvì┘, char * envp  )
  {
     ULONG  rc          = 0;
     ULONG  Mydata      = 2;
     ULONG  userDataLen = 0;
     PVOID  pUserData   = NULL;

     printf ( "Starting FFSTProbe Sample\n" );

  /**************************************/
  /* Do the trace entry point           */
  /**************************************/

     trace_capture_start.count = 3; /* just a number */
     strncpy(trace_capture_start.text, "Start main", 12);

  /******** CALL TraceCreateEntry function ****/
     trace_out(HKWD_TEST,
        hkwd_test_entry,
        &trace_capture_start,
        sizeof(trace_capture_start));

     /***********************************************************************/
     /* call the 'dummy'  API so it returns a non-zero rc                   */
     /***********************************************************************/
     rc = My_Dummy_API ( Mydata );
     if ( rc != NO_ERROR )
     {
        /********************************************************************/
        /* The API has failed. Setup the userData to contain the failing rc */
        /********************************************************************/
        pUserData = calloc ( 2, sizeof ( ULONG ) );
        memcpy ( pUserData, &rc, sizeof ( ULONG ) );
        memcpy ( ( PBYTE ) pUserData + sizeof ( ULONG )
               , &Mydata, sizeof ( ULONG ) );
  /****************************************************************************/
  /* Call the FFSTProbe wrapper function with a version of 1,                 */
  /* Have FFST post the process status and environment variables in the       */
  /* syslog, a severity of 4, a probe id of DUMMY_API_PROBE which was         */
  /* previously defined as 22222, a module name of 'my_module_1', the length  */
  /* of logusrdta, the logUserData (equal to the failing rc (1) as            */
  /* setup above) and Argc is passed in to determine whether or not data      */
  /* should be retrieved from DMI.                                            */
  /****************************************************************************/


           callFFST ( 1
                 , PSTAT_FLAG ║ PROC_ENV_FLAG
                 , SEVERITY4
                 , DUMMY_API_PROBE
                 , "my_module_1"
                 , 2 * sizeof ( ULONG )
                 , pUserData
                 , argc );
     }

     if (pUserData != NULL)
     {
       free(pUserData);
       pUserData = NULL;
     }

     if (argc > 1)
     {
        printf("\nFFSTProbe sample ended not using DMI component:\n\n\n");
     }
     else
     {
        printf("\nFFSTProbe sample ended using DMI component:\n\n\n");
     }

  /**************************************/
  /* Do the trace end point             */
  /**************************************/

     trace_capture_end.count = 99;
     strncpy(trace_capture_end.text, "End main", 12);

  /******** CALL TraceCreateEntry function ****/
     trace_out(HKWD_TEST,
        hkwd_test_entry,
        &trace_capture_end,
        sizeof(trace_capture_end));

     return 0;
  }



  /**************************************************************************/
  /* callFFST is the FFSTProbe wrapper function. It allows you to code the  */
  /* FFSTProbe API once with data that is static as far as your usage is    */
  /* concerned and allows you to pass in dynamic data.   It also helps      */
  /* insulate your code if you decide to change your 'static' options       */
  /**************************************************************************/

  void callFFST ( ULONG input_version,           /* FFST 'Wrapper' Function */
                  ULONG input_probe_flags,         /* FFSTProbe probe flags */
                  ULONG input_severity,               /* FFSTProbe severity */
                  ULONG input_probe_id,                     /* FFSTProbe ID */
                  CHAR* input_module_name,   /* module name passed to probe */
                  ULONG input_log_data_length, /* log data length for the
                                                  system error log          */
                  PVOID input_pError_log_data,   /* pointer to the data for
                                                    system error log        */
                  int   argc)
  {
    APIRET  rc = 0;
    PVOID   pvar_n0;
    ULONG   pvar_n1;

    /***********************************************************************/
    /* FFSTProbe API structures.    Described in the API Guide             */
    /***********************************************************************/
    FFSTPARMS     FFSTParms;
    PRODUCTINFO   productInfo;
    PRODUCTDATA   productData;
    DMIDATA       DMIData;
    DUMPUSERDATA  dumpUserData;
    MSGINSDATA    msgInsData;

    /***********************************************************************/
    /* The PRODUCTDATA structure defines the DMI triplet which allows      */
    /* additional product information, including template repository       */
    /* filename, to be retrieved from DMI.   DMI is a industry standard    */
    /* for desktop mgt                                                     */
    /***********************************************************************/
    productData.packet_size            = sizeof ( productData );
    productData.packet_revision_number = PRODUCTDATA_ASCII;
                                               /* data can be ASCII or UNI */
    productData.DMI_tag                = "FFSTProbe Sample";
                                             /* Customize for your program */
    productData.DMI_vendor_tag         = "IBM";
                                              /*Customize for your company */
    productData.DMI_revision           = "1.00";             /* Customize  */

    /***********************************************************************/
    /* The DMIDATA structure below is the information which can either be  */
    /* retrieved by DMI or passed in by the FFSTProbe function. The        */
    /* preferred method is to use DMI. In the example below, you can see   */
    /* the use of either depending on whether or not a parm was passed on  */
    /* call to this program                                                */
    /***********************************************************************/

    if ( !(argc > 1) )
    {
       /********************************************************************/
       /* Setting this structure to NULL indicates that the information is */
       /* to be retrieved from DMI using the DMI triplet as defined in the */
       /* productData structure.  This is the preferred method.            */
       /* Other files in this example show how to build your own DMI       */
       /********************************************************************/
       productInfo.pDMIData = NULL;

       /********************************************************************/
       /* Note: This shows the usage of message insert text and is NOT part*/
       /* of the information that could or could not be retrieved from DMI */
       /* This is included as an example of MsgInsTxt and how it can be    */
       /* used to send probe specific data to the SYSLOG (System Error Log)*/
       /********************************************************************/
       msgInsData.MsgInsTxtì0┘.insert_number = 1;
       msgInsData.MsgInsTxtì0┘.insert_text   = "We did use a DMI component";
    }
    else
     {
       /********************************************************************/
       /* fill the DMI data structure - useful only in test environments   */
       /********************************************************************/
       DMIData.packet_size              = sizeof ( DMIData );
       DMIData.packet_revision_number   = DMIDATA_ASCII;
                                               /* could be unicode instead */
       DMIData.DMI_product_ID           = "FFST_toolkt_sample";
                                        /* note this is different than tag */
       DMIData.DMI_modification_level   = "000000";
       DMIData.DMI_fix_level            = "010101";
       DMIData.template_filename        = "PROBE.REP";
                                         /* this file must be on the DPATH */
       DMIData.template_filename_length = strlen (DMIData.template_filename)
                                                 * sizeof ( char );
                                              /* since ascii is being used */
       productInfo.pDMIData             = &DMIData;

       /********************************************************************/
       /* Note: This shows the usage of message insert text and is NOT a   */
       /* of the information that could or could not be retrieved from DMI */
       /********************************************************************/
       msgInsData.MsgInsTxtì0┘.insert_number = 1;
       msgInsData.MsgInsTxtì0┘.insert_text   = "We did not use a DMI component";
      }

     /***********************************************************************/
     /* set the pointers up for PRODUCTINFO                                 */
     /***********************************************************************/

     productInfo.pProductData = &productData;   /* This points to the DMI
                                                   related data             */

     /***********************************************************************/
     /* set up some DUMPUSERDATA items                                      */
     /***********************************************************************/
     pvar_n0 = "Dump user data";              /* Anything can be dumped
                                                 here up to 32 Kbytes       */
     pvar_n1 = 2;
     dumpUserData.no_of_variables = 2;
     dumpUserData.DumpDataVarì0┘.var_n_length = strlen(pvar_n0) + 1;
     dumpUserData.DumpDataVarì0┘.var_n        = pvar_n0;
     dumpUserData.DumpDataVarì1┘.var_n_length = sizeof(ULONG);
     dumpUserData.DumpDataVarì1┘.var_n        = (PVOID)(&pvar_n1);

     /***********************************************************************/
     /* set up a couple of MSGINSDATA messages- just to show it can be done */
     /***********************************************************************/
     msgInsData.no_inserts   = 2;
     msgInsData.MsgInsTxtì1┘.insert_number = 2;
     msgInsData.MsgInsTxtì1┘.insert_text   = "Message insert variable 2";

     /***********************************************************************/
     /* set the FFSTPARMS structure, most values from DEFINEs above.        */
     /* See API GUIDE for details on each field and their possible values   */
     /***********************************************************************/
     FFSTParms.packet_size            = sizeof ( FFSTParms );
     FFSTParms.packet_revision_number = FFSTPARMS_OS2_ASCII;
                                                    /* ASCII vs UNICODE data */
     FFSTParms.module_name            = input_module_name;
     FFSTParms.probe_ID               = input_probe_id;
     FFSTParms.severity               = input_severity;
     FFSTParms.template_record_ID     = input_probe_id;
     FFSTParms.pMsgInsData            = &msgInsData;
     FFSTParms.probe_flags            = input_probe_flags;
     FFSTParms.pDumpUserData          = &dumpUserData;
                                       /* dump data is stored in .DMP files */
     FFSTParms.log_user_data_length   = input_log_data_length;
     FFSTParms.log_user_data          = input_pError_log_data;
                          /* log data is stored as part of the SYSLOG entry */

     /***********************************************************************/
     /* Call the FFSProbe API                                               */
     /***********************************************************************/
     if ( input_version == 1)
     {
        rc = FFSTProbe ( &productInfo, &FFSTParms);
     }

     printf("\n----- Fired the FFSTProbe, rc=%d\n",rc);
                 /* for example only, do not do this in customer level code */

  }

  /**************************************************************************/
  /*  This is the dummy  API for use in the example.  It can easily set     */
  /*  non-zero rc's                                                         */
  /**************************************************************************/

  ULONG My_Dummy_API ( ULONG Mydata )
  {
     if ( Mydata != 123456 )
     {
        return 1;
     }
     else
     {
        return 0;
     }
  }

  /**************************************************************************/
  /*  Trace events function                                                 */
  /**************************************************************************/
  APIRET trace_out(ULONG major, ULONG minor, void *trace_data, ULONG data_len)
  {
    TCEREQUEST packet;
    APIRET      rc;

    packet.packet_size = sizeof packet;      /* Size of packet in bytes       */
    packet.packet_revision_number = TRACE_RELEASE; /* Revision level of trace */
    packet.major_event_code = major;         /* Major code event to be logged */
    packet.minor_event_code = minor;         /* Minor code event to be logged */
    packet.event_data_length = data_len;     /* Length of callers event buffer*/
    packet.event_data = trace_data;          /* Pointer to callers buffer     */

    /* call the TraceCreateEntry function */
    rc = TraceCreateEntry(&packet);
    return rc;
  }



[Back: Examples of Code when Instrumenting for FFST and Trace]
[Next: Creating an Error Record Template Input File]