|
|
/*
* HrSWRunEntry.c v0.10 * Generated in conjunction with Management Factory scripts: * script version: SNMPv1, 0.16, Apr 25, 1996 * project: D:\TEMP\EXAMPLE\HOSTMIB **************************************************************************** * * * (C) Copyright 1995 DIGITAL EQUIPMENT CORPORATION * * * * This software is an unpublished work protected under the * * the copyright laws of the United States of America, all * * rights reserved. * * * * In the event this software is licensed for use by the United * * States Government, all use, duplication or disclosure by the * * United States Government is subject to restrictions as set * * forth in either subparagraph (c)(1)(ii) of the Rights in * * Technical Data And Computer Software Clause at DFARS * * 252.227-7013, or the Commercial Computer Software Restricted * * Rights Clause at FAR 52.221-19, whichever is applicable. * * * **************************************************************************** * * Facility: * * Windows NT SNMP Extension Agent * * Abstract: * * This module contains the code for dealing with the get, set, and * instance name routines for the HrSWRunEntry. Actual instrumentation code is * supplied by the developer. * * Functions: * * A get and set routine for each attribute in the class. * * The routines for instances within the class. * * Author: * * D. D. Burns @ Webenable Inc * * Revision History: * * V1.00 - 05/14/97 D. D. Burns Genned: Thu Nov 07 16:47:29 1996 * */
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <malloc.h>
#include <snmp.h>
#include "mib.h"
#include "smint.h"
#include "hostmsmi.h"
#include "user.h" /* Developer supplied include file */
#include "HMCACHE.H" /* Cache-related definitions */
#include <string.h>
/*
|============================================================================== | Function prototypes for this module. | */ /* AddHrSWRunRow - Generate another Row Entry in HrSWRun/Perf Table cache */ static BOOL AddHrSWRunRow(PSYSTEM_PROCESS_INFORMATION ProcessInfo);
/* FetchProcessParams - Fetch Path & Parameter String from Process Cmd line */ void FetchProcessParams( PSYSTEM_PROCESS_INFORMATION ProcessInfo, /* Process for parameters */ CHAR **path_str, /* Returned PATH string */ CHAR **params_str /* Returned Parameters string */ );
#if defined(CACHE_DUMP)
/* debug_print_hrswrun - Prints a Row from HrSWRun(Perf) Table */ static void debug_print_hrswrun( CACHEROW *row /* Row in hrSWRun(Perf) table */ ); #endif
/*
|============================================================================== | Cache Refresh Time | | The cache for the hrSWRun and hrSWRunPerf tables is refreshed automatically | when a request arrives --AND-- the cache is older than CACHE_MAX_AGE | in seconds. | */ static LARGE_INTEGER cache_time; // 100ns Timestamp of cache (when last refreshed)
#define CACHE_MAX_AGE 120 // Maximum age in seconds
/*
|============================================================================== | Create the list-head for the HrSWRun(Perf) Table cache. | | This cache contains info for both the hrSWRun and hrSWRunPerf tables. | (This macro is defined in "HMCACHE.H"). | | This is global so code for the hrSWRunPerf table ("HRSWPREN.C") can | reference it. */ CACHEHEAD_INSTANCE(hrSWRunTable_cache, debug_print_hrswrun);
/*
|============================================================================== | Operating System Index | | SNMP attribute "HrSWOSIndex" is the index into hrSWRun to the entry that | primary operating system running on the host. This value is computed in | this module in function "AddHrSWRunRow()" and stored here for reference | by code in "HRSWRUN.C". */ ULONG SWOSIndex;
/*
* GetHrSWRunIndex * A unique value for each piece of software running on the host. Wherever * possible, this should be the system's native, unique id * * Gets the value for HrSWRunIndex. * * Arguments: * * outvalue address to return variable value * accesss Reserved for future security use * instance address of instance name as ordered native * data type(s) * * Return Codes: * * Standard PDU error codes. * * SNMP_ERRORSTATUS_NOERROR Successful get * SNMP_ERRORSTATUS_GENERR Catch-all failure code * mibtget.c v0.10 * | =============== From WebEnable Design Spec Rev 3 04/11/97================== | hrSWRunIndex | | ACCESS SYNTAX | read-only INTEGER (1..2147483647) | | "A unique value for each piece of software running on the host. Wherever | possible, this should be the system's native, unique identification number." | | DISCUSSION: | | By using performance monitoring information from the Registry (using code | from "PVIEW") this attribute is given the value of the Process ID. | |============================================================================ | 1.3.6.1.2.1.25.4.2.1.1.<instance> | | | | | | | | | *-hrSWRunIndex | | | *-hrSWRunEntry | | *-hrSWRunTable | *-hrSWRun */
UINT GetHrSWRunIndex( OUT Integer *outvalue , IN Access_Credential *access , IN InstanceName *instance )
{ ULONG index; /* As fetched from instance structure */ CACHEROW *row; /* Row entry fetched from cache */
/*
| Grab the instance information */ index = GET_INSTANCE(0);
/*
| Use it to find the right entry in the cache */ if ((row = FindTableRow(index, &hrSWRunTable_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; }
*outvalue = row->attrib_list[HRSR_INDEX].u.number_value; return SNMP_ERRORSTATUS_NOERROR ;
} /* end of GetHrSWRunIndex() */
/*
* GetHrSWRunName * A textual description of this running piece of software, including the * manufacturer, revision, and the name by which it is commo * * Gets the value for HrSWRunName. * * Arguments: * * outvalue address to return variable value * accesss Reserved for future security use * instance address of instance name as ordered native * data type(s) * * Return Codes: * * Standard PDU error codes. * * SNMP_ERRORSTATUS_NOERROR Successful get * SNMP_ERRORSTATUS_GENERR Catch-all failure code * mibtget.c v0.10 * | =============== From WebEnable Design Spec Rev 3 04/11/97================== | hrSWRunName | | ACCESS SYNTAX | read-only InternationalDisplayString (SIZE (0..64)) | | "A textual description of this running piece of software, including the | manufacturer, revision, and the name by which it is commonly known. If this | software was installed locally, this should be the same string as used in the | corresponding hrSWInstalledName." | | DISCUSSION: | | By using performance monitoring information from the Registry (using code | from "PVIEW") this attribute is given the value of the Process name. | |============================================================================ | 1.3.6.1.2.1.25.4.2.1.2.<instance> | | | | | | | | | *-hrSWRunName | | | *-hrSWRunEntry | | *-hrSWRunTable | *-hrSWRun */
UINT GetHrSWRunName( OUT InternationalDisplayString *outvalue , IN Access_Credential *access , IN InstanceName *instance )
{ ULONG index; /* As fetched from instance structure */ CACHEROW *row; /* Row entry fetched from cache */
/*
| Grab the instance information */ index = GET_INSTANCE(0);
/*
| Use it to find the right entry in the cache */ if ((row = FindTableRow(index, &hrSWRunTable_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; }
/* Return the name that was computed at cache-build time */ outvalue->length = strlen(row->attrib_list[HRSR_NAME].u.string_value); outvalue->string = row->attrib_list[HRSR_NAME].u.string_value; if (outvalue->length > 64) { outvalue->length = 64; /* Truncate */ }
return SNMP_ERRORSTATUS_NOERROR ;
} /* end of GetHrSWRunName() */
/*
* GetHrSWRunID * The product ID of this running piece of software. * * Gets the value for HrSWRunID. * * Arguments: * * outvalue address to return variable value * accesss Reserved for future security use * instance address of instance name as ordered native * data type(s) * * Return Codes: * * Standard PDU error codes. * * SNMP_ERRORSTATUS_NOERROR Successful get * SNMP_ERRORSTATUS_GENERR Catch-all failure code * mibtget.c v0.10 * | =============== From WebEnable Design Spec Rev 3 04/11/97================== | hrSWRunID | | ACCESS SYNTAX | read-only ProductID | | "The product ID of this running piece of software." | | DISCUSSION: | | <POA-16> I anticipate always using "unknownProduct" as the value for this | attribute, as I can envision no systematic means of acquiring a registered | OID for all process software to be used as the value for this attribute. | | RESOLVED >>>>>>> | <POA-16> Returning an unknown Product ID is acceptable. | RESOLVED >>>>>>> | |============================================================================ | 1.3.6.1.2.1.25.4.2.1.3.<instance> | | | | | | | | | *-hrSWRunID | | | *-hrSWRunEntry | | *-hrSWRunTable | *-hrSWRun */
UINT GetHrSWRunID( OUT ProductID *outvalue , IN Access_Credential *access , IN InstanceName *instance )
{
/*
| The deal on this attribute is that we'll never have a valid OID value | for this attribute. Consequently, we always return the standard | "unknown" OID value ("0.0") regardless of the instance value (which | by now in the calling sequence of things has been validated anyway). */
if ( (outvalue->ids = SNMP_malloc(2 * sizeof( UINT ))) == NULL) { return SNMP_ERRORSTATUS_GENERR; } outvalue->idLength = 2;
/*
| Load in the OID value for "unknown" for ProductID: "0.0" */ outvalue->ids[0] = 0; outvalue->ids[1] = 0;
return SNMP_ERRORSTATUS_NOERROR ;
} /* end of GetHrSWRunID() */
/*
* GetHrSWRunPath * A description of the location on long-term storage (e.g. a disk drive) * from which this software was loaded. * * Gets the value for HrSWRunPath. * * Arguments: * * outvalue address to return variable value * accesss Reserved for future security use * instance address of instance name as ordered native * data type(s) * * Return Codes: * * Standard PDU error codes. * * SNMP_ERRORSTATUS_NOERROR Successful get * SNMP_ERRORSTATUS_GENERR Catch-all failure code * mibtget.c v0.10 * | =============== From WebEnable Design Spec Rev 3 04/11/97================== | hrSWRunPath | | ACCESS SYNTAX | read-only InternationalDisplayString (SIZE(0..128)) | | "A description of the location on long-term storage (e.g. a disk drive) from | which this software was loaded." | | DISCUSSION: | | <POA-17> This information is not extracted by the sample PVIEW code from the | performance monitoring statistics kept in the Registry. If this information | is available from the Registry or some other source, I need to acquire the | description of how to get it. | | RESOLVED >>>>>>>> | <POA-17> This is obtained using PerfMon code pointers provided by Bob Watson. | RESOLVED >>>>>>>> | |============================================================================ | 1.3.6.1.2.1.25.4.2.1.4.<instance> | | | | | | | | | *-hrSWRunPath | | | *-hrSWRunEntry | | *-hrSWRunTable | *-hrSWRun */
UINT GetHrSWRunPath( OUT InternationalDisplayString *outvalue , IN Access_Credential *access , IN InstanceName *instance )
{ ULONG index; /* As fetched from instance structure */ CACHEROW *row; /* Row entry fetched from cache */
/*
| Grab the instance information */ index = GET_INSTANCE(0);
/*
| Use it to find the right entry in the cache */ if ((row = FindTableRow(index, &hrSWRunTable_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; }
/*
| Return the Path string that was computed at cache-build time. | NOTE: This string might be NULL. */ if (row->attrib_list[HRSR_PATH].u.string_value == NULL) { outvalue->length = 0; } else { outvalue->length = strlen(row->attrib_list[HRSR_PATH].u.string_value); outvalue->string = row->attrib_list[HRSR_PATH].u.string_value; if (outvalue->length > 128) { outvalue->length = 128; /* Truncate */ } }
return SNMP_ERRORSTATUS_NOERROR ;
} /* end of GetHrSWRunPath() */
/*
* GetHrSWRunParameters * * A description of the parameters supplied to this software when it was * initially loaded." * * Gets the value for HrSWRunParameters. * * Arguments: * * outvalue address to return variable value * accesss Reserved for future security use * instance address of instance name as ordered native * data type(s) * * Return Codes: * * Standard PDU error codes. * * SNMP_ERRORSTATUS_NOERROR Successful get * SNMP_ERRORSTATUS_GENERR Catch-all failure code * mibtget.c v0.10 * | =============== From WebEnable Design Spec Rev 3 04/11/97================== | hrSWRunParameters | | ACCESS SYNTAX | read-only InternationalDisplayString (SIZE(0..128)) | | "A description of the parameters supplied to this software when it was | initially loaded." | | DISCUSSION: | | <POA-18> This information is not extracted by the sample PVIEW code from the | performance monitoring statistics kept in the Registry. If this information | is available from the Registry or some other source, I need to acquire the | description of how to get it. | | RESOLVED >>>>>>>> | <POA-18> See discussion for "hrSWRunPath" above. | RESOLVED >>>>>>>> | |============================================================================ | NOTE: This function edited in by hand, as it was not originally generated. |============================================================================ | 1.3.6.1.2.1.25.4.2.1.5.<instance> | | | | | | | | | *-hrSWRunParameters | | | *-hrSWRunEntry | | *-hrSWRunTable | *-hrSWRun */
UINT GetHrSWRunParameters( OUT InternationalDisplayString *outvalue , IN Access_Credential *access , IN InstanceName *instance )
{ ULONG index; /* As fetched from instance structure */ CACHEROW *row; /* Row entry fetched from cache */
/*
| Grab the instance information */ index = GET_INSTANCE(0);
/*
| Use it to find the right entry in the cache */ if ((row = FindTableRow(index, &hrSWRunTable_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; }
/*
| Return the Parameter string that was computed at cache-build time. | NOTE: This string might be NULL. */ if (row->attrib_list[HRSR_PARAM].u.string_value == NULL) { outvalue->length = 0; } else { outvalue->length = strlen(row->attrib_list[HRSR_PARAM].u.string_value); outvalue->string = row->attrib_list[HRSR_PARAM].u.string_value; if (outvalue->length > 128) { outvalue->length = 128; /* Truncate */ } }
return SNMP_ERRORSTATUS_NOERROR ;
} /* end of GetHrSWRunParameters() */
/*
* GetHrSWRunType * The type of this software. * * Gets the value for HrSWRunType. * * Arguments: * * outvalue address to return variable value * accesss Reserved for future security use * instance address of instance name as ordered native * data type(s) * * Return Codes: * * Standard PDU error codes. * * SNMP_ERRORSTATUS_NOERROR Successful get * SNMP_ERRORSTATUS_GENERR Catch-all failure code * mibtget.c v0.10 * | =============== From WebEnable Design Spec Rev 3 04/11/97================== | hrSWRunType | | ACCESS SYNTAX | read-only INTEGER {unknown(1),operatingSystem(2),deviceDriver(3), | application(4)} | | "The type of this software." | | DISCUSSION: | | <POA-19> This information is not extracted by the sample PVIEW code from the | performance monitoring statistics kept in the Registry. If this information | is available from the Registry or some other source, I need to acquire the | description of how to get it. | | >>>>>>>> | <POA-19> I am not sure whether this information is included in the perfmon | data block. I will investigate further. | >>>>>>>> | |============================================================================ | 1.3.6.1.2.1.25.4.2.1.6.<instance> | | | | | | | | | *-hrSWRunType | | | *-hrSWRunEntry | | *-hrSWRunTable | *-hrSWRun */
UINT GetHrSWRunType( OUT INTSWType *outvalue , IN Access_Credential *access , IN InstanceName *instance )
{ ULONG index; /* As fetched from instance structure */ CACHEROW *row; /* Row entry fetched from cache */
/*
| Grab the instance information */ index = GET_INSTANCE(0);
/*
| Use it to find the right entry in the cache */ if ((row = FindTableRow(index, &hrSWRunTable_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; }
*outvalue = row->attrib_list[HRSR_TYPE].u.number_value; return SNMP_ERRORSTATUS_NOERROR ;
} /* end of GetHrSWRunType() */
/*
* GetHrSWRunStatus * The status of this running piece of software. Setting this value to * invalid(4) shall cause this software to stop running and be * * Gets the value for HrSWRunStatus. * * Arguments: * * outvalue address to return variable value * accesss Reserved for future security use * instance address of instance name as ordered native * data type(s) * * Return Codes: * * Standard PDU error codes. * * SNMP_ERRORSTATUS_NOERROR Successful get * SNMP_ERRORSTATUS_GENERR Catch-all failure code * mibtget.c v0.10 * | =============== From WebEnable Design Spec Rev 3 04/11/97================== | hrSWRunStatus | | ACCESS SYNTAX | read-write INTEGER { | running(1), | runnable(2), -- waiting for resource (CPU, memory, IO) | notRunnable(3), -- loaded but waiting for event | invalid(4) -- not loaded | } | | "The status of this running piece of software. Setting this value to | invalid(4) shall cause this software to stop running and to be unloaded." | | DISCUSSION: | | <POA-20> For an SNMP "GET" on this attribute, this information is not extracted | by the sample PVIEW code from the performance monitoring statistics kept in | the Registry. If this information is available from the Registry or some | other source, I need to acquire the description of how to get it. | | RESOLVED >>>>>>> | <POA-20> I think running and notRunnable will be all that are applicable | here (that latter being returned in situations which are currently labeled | "not responding"). | RESOLVED >>>>>>> | |============================================================================ | 1.3.6.1.2.1.25.4.2.1.7.<instance> | | | | | | | | | *-hrSWRunStatus | | | *-hrSWRunEntry | | *-hrSWRunTable | *-hrSWRun */
UINT GetHrSWRunStatus( OUT INThrSWRunStatus *outvalue , IN Access_Credential *access , IN InstanceName *instance )
{ ULONG index; /* As fetched from instance structure */ CACHEROW *row; /* Row entry fetched from cache */
/*
| Grab the instance information */ index = GET_INSTANCE(0);
/*
| Use it to find the right entry in the cache */ if ((row = FindTableRow(index, &hrSWRunTable_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; }
*outvalue = row->attrib_list[HRSR_STATUS].u.number_value; return SNMP_ERRORSTATUS_NOERROR ;
} /* end of GetHrSWRunStatus() */
/*
* SetHrSWRunStatus * The status of this running piece of software. Setting this value to * invalid(4) shall cause this software to stop running and be * * Sets the HrSWRunStatus value. * * Arguments: * * invalue address of value to set the variable * outvalue address to return the set variable value * access Reserved for future security use * instance address of instance name as ordered native * data type(s) * * Return Codes: * * Standard PDU error codes. * * SNMP_ERRORSTATUS_NOERROR Successful get * SNMP_ERRORSTATUS_BADVALUE Set value not in range * SNMP_ERRORSTATUS_GENERR Catch-all failure code * mibtset.ntc v0.10 */
UINT SetHrSWRunStatus( IN INThrSWRunStatus *invalue , OUT INThrSWRunStatus *outvalue , IN Access_Credential *access , IN InstanceName *instance )
{
return SNMP_ERRORSTATUS_NOSUCHNAME ;
} /* end of SetHrSWRunStatus() */
/*
* HrSWRunEntryFindInstance * * This routine is used to verify that the specified instance is * valid. * * Arguments: * * FullOid Address for the full oid - group, variable, * and instance information * instance Address for instance specification as an oid * * Return Codes: * * SNMP_ERRORSTATUS_NOERROR Instance found and valid * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance * */
UINT HrSWRunEntryFindInstance( IN ObjectIdentifier *FullOid , IN OUT ObjectIdentifier *instance ) { UINT tmp_instance ;
//
// Developer instrumentation code to find appropriate instance goes here.
// For non-tables, it is not necessary to modify this routine. However, if
// there is any context that needs to be set, it can be done here.
//
if ( FullOid->idLength <= HRSWRUNENTRY_VAR_INDEX ) // No instance was specified
return SNMP_ERRORSTATUS_NOSUCHNAME ; else if ( FullOid->idLength != HRSWRUNENTRY_VAR_INDEX + 1 ) // Instance length is more than 1
return SNMP_ERRORSTATUS_NOSUCHNAME ; else // The only valid instance for a non-table are instance 0. If this
// is a non-table, the following code validates the instances. If this
// is a table, developer modification is necessary below.
tmp_instance = FullOid->ids[ HRSWRUNENTRY_VAR_INDEX ] ;
/*
| Check for age-out and possibly refresh the entire cache for the | hrSWRun table before we check to see if the instance is there. */ if (hrSWRunCache_Refresh() == FALSE) { return SNMP_ERRORSTATUS_GENERR; }
/*
| For hrSWRun, the instance arc(s) is a single arc, and it must | correctly select an entry in the hrSWRun Table cache. | Check that here. */ if ( FindTableRow(tmp_instance, &hrSWRunTable_cache) == NULL ) { return SNMP_ERRORSTATUS_NOSUCHNAME ; } else { // the instance is valid. Create the instance portion of the OID
// to be returned from this call.
instance->ids[ 0 ] = tmp_instance ; instance->idLength = 1 ; }
return SNMP_ERRORSTATUS_NOERROR ;
} /* end of HrSWRunEntryFindInstance() */
/*
* HrSWRunEntryFindNextInstance * * This routine is called to get the next instance. If no instance * was passed than return the first instance (1). * * Arguments: * * FullOid Address for the full oid - group, variable, * and instance information * instance Address for instance specification as an oid * * Return Codes: * * SNMP_ERRORSTATUS_NOERROR Instance found and valid * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance * */
UINT HrSWRunEntryFindNextInstance( IN ObjectIdentifier *FullOid , IN OUT ObjectIdentifier *instance ) { //
// Developer supplied code to find the next instance of class goes here.
// If this is a class with cardinality 1, no modification of this routine
// is necessary unless additional context needs to be set.
// If the FullOid does not specify an instance, then the only instance
// of the class is returned. If this is a table, the first row of the
// table is returned.
//
// If an instance is specified and this is a non-table class, then NOSUCHNAME
// is returned so that correct MIB rollover processing occurs. If this is
// a table, then the next instance is the one following the current instance.
// If there are no more instances in the table, return NOSUCHNAME.
//
CACHEROW *row; ULONG tmp_instance;
if ( FullOid->idLength <= HRSWRUNENTRY_VAR_INDEX ) { /*
| Too short: must return the instance arc that selects the first | entry in the table if there is one. */ tmp_instance = 0; } else { /*
| There is at least one instance arc. Even if it is the only arc | we use it as the "index" in a request for the "NEXT" one. */ tmp_instance = FullOid->ids[ HRSWRUNENTRY_VAR_INDEX ] ; }
/*
| Check for age-out and possibly refresh the entire cache for the | hrSWRun table before we check to see if the instance is there. */ if (hrSWRunCache_Refresh() == FALSE) { return SNMP_ERRORSTATUS_GENERR; }
/* Now go off and try to find the next instance in the table */ if ((row = FindNextTableRow(tmp_instance, &hrSWRunTable_cache)) == NULL) { return SNMP_ERRORSTATUS_NOSUCHNAME ; }
instance->ids[ 0 ] = row->index ; instance->idLength = 1 ;
return SNMP_ERRORSTATUS_NOERROR ;
} /* end of HrSWRunEntryFindNextInstance() */
/*
* HrSWRunEntryConvertInstance * * This routine is used to convert the object id specification of an * instance into an ordered native representation. The object id format * is that object identifier that is returned from the Find Instance * or Find Next Instance routines. It is NOT the full object identifier * that contains the group and variable object ids as well. The native * representation is an argc/argv-like structure that contains the * ordered variables that define the instance. This is specified by * the MIB's INDEX clause. See RFC 1212 for information about the INDEX * clause. * * * Arguments: * * oid_spec Address of the object id instance specification * native_spec Address to return the ordered native instance * specification * * Return Codes: * * SUCCESS Conversion complete successfully * FAILURE Unable to convert object id into native format * */
UINT HrSWRunEntryConvertInstance( IN ObjectIdentifier *oid_spec , IN OUT InstanceName *native_spec ) { static char *array; /* The address of this (char *) is passed back */ /* as though it were an array of length 1 of these */ /* types. */
static ULONG inst; /* The address of this ULONG is passed back */ /* (Obviously, no "free()" action is needed) */
/* We only expect the one arc in "oid_spec" */ inst = oid_spec->ids[0]; array = (char *) &inst;
native_spec->count = 1; native_spec->array = &array; return SUCCESS ;
} /* end of HrSWRunEntryConvertInstance() */
/*
* HrSWRunEntryFreeInstance * * This routine is used to free an ordered native representation of an * instance name. * * Arguments: * * instance Address to return the ordered native instance * specification * * Return Codes: * * */
void HrSWRunEntryFreeInstance( IN OUT InstanceName *instance ) {
//
// Developer supplied code to free native representation of instance name goes here.
//
} /* end of HrSWRunEntryFreeInstance() */
/*
| End of Generated Code */
/* Gen_HrSWRun_Cache - Generate a initial cache for HrSWRun(Perf) Table */ /* Gen_HrSWRun_Cache - Generate a initial cache for HrSWRun(Perf) Table */ /* Gen_HrSWRun_Cache - Generate a initial cache for HrSWRun(Perf) Table */
BOOL Gen_HrSWRun_Cache( void )
/*
| EXPLICIT INPUTS: | | None. | | IMPLICIT INPUTS: | | The module-local head of the cache for the HrSWRun table, | "hrSWRunTable_cache". | | OUTPUTS: | | On Success: | Function returns TRUE indicating that the cache has been fully | populated with all "static" cache-able values. This function populates | the hrSWRun Table cache, but this cache also includes the two | attributes for the hrSWRunPerf Table. So in effect, one cache serves | two tables, but the hrSWRunPerf table is a "one-to-one" extension | of hrSWRun table.. that is a row in hrSWRun always has a corresponding | "two-entry" row in hrSWRunPerf. | | On any Failure: | Function returns FALSE (indicating "not enough storage"). | | THE BIG PICTURE: | | At subagent startup time, the cache for each table in the MIB is | populated with rows for each row in the table. This function is | invoked by the start-up code in "UserMibInit()" ("MIB.C") to | populate the cache for the HrSWRun table (which also serves the | hrSWRunPerf Table). | | It is also re-entered whenever a request for information from this | cache comes in and the cache is older than a certain age (symbol | "CACHE_MAX_AGE" defined at the beginning of this module). In this | case the cache is rebuilt, and in this way this function is different | from all the other "Gen_*_Cache()" functions which only build their | caches once (in the initial release). | | | OTHER THINGS TO KNOW: | | There is one of these function for every table that has a cache. | Each cachehead is found in the respective table's source file. | | The strategy on getting running software enumerated revolves around | NtQuerySystemInformation(SystemProcessInformation...) invocation. | | Once we have a list of processes, additional information (such as | the parameters on the command-line) are fetched by opening the | process (if possible) and reading process memory. | | Note that unlike the other cache's in the initial release, this cache | for hrSWRun and hrSWRunPerf is updated before it is read if it is | older than a specified period of time (set by #define at the beginning | of this file). | |============================================================================ | 1.3.6.1.2.1.25.4.1.0 | | | | | *-hrSWOSIndex | *-hrSWRun | | 1.3.6.1.2.1.25.4.2.1.. | | | | | | | *-hrSWRunEntry | | *-hrSWRunTable | *-hrSWRun */ #define LARGE_BUFFER_SIZE (4096*8)
#define INCREMENT_BUFFER_SIZE (4096*2)
{ DWORD ProcessBufSize = LARGE_BUFFER_SIZE; /* Initial ProcessBuffer size */ LPBYTE pProcessBuffer = NULL; /* Re-used and re-expanded as needed */
PSYSTEM_PROCESS_INFORMATION ProcessInfo; /* --> Next process to process */ ULONG ProcessBufferOffset=0; /* Accumulating offset cell */ NTSTATUS ntstatus; /* Generic return status */ DWORD dwReturnedBufferSize; /* From NtQuerySystemInformation() */
/*
| Blow away any old copy of the cache */ DestroyTable( &hrSWRunTable_cache );
/*
| Grab an initial buffer for Process Information */ if ((pProcessBuffer = malloc ( ProcessBufSize )) == NULL) { return ( FALSE ); }
/*
| Go for a (new/refreshed) buffer of current Process Info */ while( (ntstatus = NtQuerySystemInformation( SystemProcessInformation, pProcessBuffer, ProcessBufSize, &dwReturnedBufferSize ) ) == STATUS_INFO_LENGTH_MISMATCH ) {
LPBYTE pNewProcessBuffer = NULL; // For use on realloc
/* expand buffer & retry */ ProcessBufSize += INCREMENT_BUFFER_SIZE;
if ( !(pNewProcessBuffer = realloc(pProcessBuffer,ProcessBufSize)) ) { // If realloc failed and left us with the old buffer, free it
if (pProcessBuffer != NULL) { free(pProcessBuffer); } return (FALSE); // Out of memory
} else { // Successful Realloc
pProcessBuffer = pNewProcessBuffer; } }
/*
| Freshen the time on the cache | | Get the current system-time in 100ns intervals . . . */ ntstatus = NtQuerySystemTime (&cache_time); if (ntstatus != STATUS_SUCCESS) { free( pProcessBuffer ); return ( FALSE ); }
/*
| Loop over each instance of Process Information in the ProcessBuffer | and build a row in the cache for hrSWRun and hrSWRunPerf tables. */ for (ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) pProcessBuffer; ; /* Exit check below */ ProcessBufferOffset += ProcessInfo->NextEntryOffset, ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &pProcessBuffer[ProcessBufferOffset] ) {
/* Add a Row to the cache */ if (AddHrSWRunRow(ProcessInfo) != TRUE) { if (pProcessBuffer != NULL) { free(pProcessBuffer); } return ( FALSE ); // Out of memory
}
/* If this is the last process, bag it */ if (ProcessInfo->NextEntryOffset == 0) { break; } }
#if defined(CACHE_DUMP)
PrintCache(&hrSWRunTable_cache); #endif
if (pProcessBuffer != NULL) { free(pProcessBuffer); }
/* Cache (re)-build successful */ return ( TRUE ); }
/* AddHrSWRunRow - Generate another Row Entry in HrSWRun/Perf Table */ /* AddHrSWRunRow - Generate another Row Entry in HrSWRun/Perf Table */ /* AddHrSWRunRow - Generate another Row Entry in HrSWRun/Perf Table */
static BOOL AddHrSWRunRow(
PSYSTEM_PROCESS_INFORMATION ProcessInfo /* --> Next process to process */
)
/*
| EXPLICIT INPUTS: | | "ProcessInfo" points to the next process (as described by a | SYSTEM_PROCESS_INFORMATION structure) for which a row is to be | inserted into the HrSWRun(Perf) table cache. | | IMPLICIT INPUTS: | | The module-local head of the cache for the HrDevice table, | "hrSWRunTable_cache". | | OUTPUTS: | | On Success: | Function creates a new row entry populated with all "static" cache-able | values for HrSWRun(Perf) table and returns TRUE. Note that if the | process is the "System Process", the row entry index is stored in | module cell "SWOSIndex" for reference by code in "HRSWRUN.C". | | On any Failure: | Function returns FALSE (indicating "not enough storage" or other | internal logic error). | | | THE BIG PICTURE: | | At subagent startup time, the cache for each table in the MIB is | populated with rows for each row in the table. This function is | invoked by the cache-build code in "Gen_HrSWRun_Cache()" above. | | OTHER THINGS TO KNOW: | | The cache being (re)built by this function serves two tables, hrSWRun | and hrSWRunPerf. | | In general, we use the Process's "ProcessID" as the index in the | hrSWRun(Perf) table. However special handling is done for the Idle | Process because it's Process ID is zero. We convert it to "1" to meet | the SNMP requirement that indexes be greater than zero. We note that | as of this writing, no process id of 1 is seen in build 1515 (the "System" | process has a processID of 2). | | The "type" of software can be unknown(1), operatingSystem(2), | deviceDriver(3) and application(4). We only detect the Idle and System | processes (by their names) as "operatingSystem(2)", everything else | is presumed "application(4)". | | As for "status", it can be running(1), runnable(2), notRunnable(3) or | invalid(4). If the number of threads is greater than 0, it is presumed | "running(1)", otherwise "invalid(4)". */ #define ANSI_PNAME_LEN 256
{ ANSI_STRING pname; /* ANSI version of UNICODE process name */ CHAR pbuf[ANSI_PNAME_LEN+1]; /* Buffer for "pname" */ CHAR *pname_str; /* Pointer to our final process name */ CHAR *path_str=NULL; /* Pointer to our Path name */ CHAR *params=NULL; /* Pointer to any parameters fnd on cmdline*/ UINT type; /* SNMP code for type of software */ UINT status; /* SNMP code for the status of software */ CACHEROW *row; /* --> Cache structure for row-being built */ NTSTATUS ntstatus; /* Generic return status */
/*
| OK, the caller wants another row in the table, get a row-entry created. */ if ((row = CreateTableRow( HRSR_ATTRIB_COUNT ) ) == NULL) { return ( FALSE ); // Out of memory
}
/*
| Set up the standard-hrSWRun(Perf) attributes in the new row */
type = 4; /* Presume "application(4)" type software */
if (ProcessInfo->NumberOfThreads > 0) { status = 1; /* Presume "running(1)" for software status */ } else { status = 4; /* "invalid(4)", process on the way out */ }
/* =========== HrSWRunIndex ==========*/ row->attrib_list[HRSR_INDEX].attrib_type = CA_NUMBER; row->attrib_list[HRSR_INDEX].u.unumber_value = HandleToUlong(ProcessInfo->UniqueProcessId) ;
/* Special check for system idle process, roll it from 0 to 1 */ if (ProcessInfo->UniqueProcessId == 0) { row->attrib_list[HRSR_INDEX].u.unumber_value = 1; }
/* =========== HrSWRunName ==========*/ row->attrib_list[HRSR_NAME].attrib_type = CA_STRING;
/* If we actually have a process name for this process . . . */ if (ProcessInfo->ImageName.Buffer != NULL) {
/* Prep the STRING structure */ pname.Buffer = pbuf; pname.MaximumLength = ANSI_PNAME_LEN;
/* Convert from Unicode */ ntstatus = RtlUnicodeStringToAnsiString(&pname, // Target string
(PUNICODE_STRING)&ProcessInfo->ImageName,//Src
FALSE); // = Don't Allocate buf
if (ntstatus != STATUS_SUCCESS) { DestroyTableRow(row); return ( FALSE ); } /*
| Here we parse not only the process name but any path that may be | prepended to it. (We make no attempt to eliminate any ".EXE" that | may be on the end of the image name). | | NOTE: If you are going to rip off this code, be aware that as-of | build 1515, we NEVER seem to get an image name that has the | path prepended on the front... so most of this code to skip | the possibly-present path is almost certainly superfluous. */
/* Try to "backup" until we hit any "\" */ if ( (pname_str = strrchr(pname.Buffer,'\\')) != NULL) { pname_str++; /* Pop to first char after "\" */ } else { pname_str = pname.Buffer; /* Use entire string, no "\" found */
/*
| A piece of software with no path means it could be the "System" | process. Check for that here. */ if (strcmp(pname_str, "System") == 0) { type = 2; /* Mark the software as "operatingSystem(2)" type */
/*
| We're processing the main System Process, so record it's index | in module-level cell for reference from "HRSWRUN.C". */ SWOSIndex = row->attrib_list[HRSR_INDEX].u.unumber_value; } } } else { /* The system idle process has no name */ pname_str = "System Idle Process"; type = 2; /* Mark the software as "operatingSystem(2)" type */ }
/* Allocate cache storage and copy the process name to it */ if ( (row->attrib_list[HRSR_NAME].u.string_value = ( LPSTR ) malloc(strlen(pname_str) + 1)) == NULL) { DestroyTableRow(row); return ( FALSE ); /* out of memory */ } strcpy(row->attrib_list[HRSR_NAME].u.string_value, pname_str);
/*
| We bother to do the overhead of trying to extract path & parameters from | the command-line that started the process by reading process memory | only if the type of the software is "application(4)" and status is | "running(1)". */ if (status == 1 && type == 4) { /* If it is a runnable application . . . */
FetchProcessParams(ProcessInfo, &path_str, ¶ms); }
/* =========== HrSWRunPath ==========*/ row->attrib_list[HRSR_PATH].attrib_type = CA_STRING; row->attrib_list[HRSR_PATH].u.string_value = NULL;
/* If we did detect a path . . . */ if (path_str != NULL) {
/* Allocate cache storage and copy the path string to it */ if ( (row->attrib_list[HRSR_PATH].u.string_value = ( LPSTR ) malloc(strlen(path_str) + 1)) == NULL) { DestroyTableRow(row); return ( FALSE ); /* out of memory */ } strcpy(row->attrib_list[HRSR_PATH].u.string_value, path_str); }
/* =========== HrSWRunParameters ==========*/ row->attrib_list[HRSR_PARAM].attrib_type = CA_STRING; row->attrib_list[HRSR_PARAM].u.string_value = NULL; /* In case of none */
/* If we did find parameters . . . */ if (params != NULL) {
/* Allocate cache storage and copy the parameter string to it */ if ( (row->attrib_list[HRSR_PARAM].u.string_value = ( LPSTR ) malloc(strlen(params) + 1)) == NULL) { DestroyTableRow(row); return ( FALSE ); /* out of memory */ } strcpy(row->attrib_list[HRSR_PARAM].u.string_value, params); }
/* =========== HrSWRunType ========== */ row->attrib_list[HRSR_TYPE].attrib_type = CA_NUMBER; row->attrib_list[HRSR_TYPE].u.unumber_value = type;
/* =========== HrSWRunStatus ========== */ row->attrib_list[HRSR_STATUS].attrib_type = CA_NUMBER; row->attrib_list[HRSR_STATUS].u.unumber_value = status;
/*
| For hrSWRunPerf Table: */
/* =========== HrSWRunPerfCPU ==========
| UserTime + KernelTime are in 100ns (1/10th of a millionth of a second) | units and HrSWRunPerfCPU is supposed to be in 1/100th of a second units. | | So .01 - second intervals | is .010 000 0 - 100nanoseconds intervals, | | so dividing 100ns intervals by 100,000 gives centi-seconds. */
row->attrib_list[HRSP_CPU].attrib_type = CA_NUMBER; row->attrib_list[HRSP_CPU].u.unumber_value = (ULONG) ((ProcessInfo->UserTime.QuadPart + ProcessInfo->KernelTime.QuadPart) / 100000);
/* =========== HrSWRunPerfMem ========== */ row->attrib_list[HRSP_MEM].attrib_type = CA_NUMBER; row->attrib_list[HRSP_MEM].u.unumber_value = (ULONG)(ProcessInfo->WorkingSetSize / 1024);
/*
| Now insert the filled-in CACHEROW structure into the | cache-list for the hrSWRun(Perf) Table. */ if (AddTableRow(row->attrib_list[HRSR_INDEX].u.unumber_value, /* Index */ row, /* Row */ &hrSWRunTable_cache /* Cache */ ) == FALSE) { DestroyTableRow(row); return ( FALSE ); /* Internal Logic Error! */ }
return ( TRUE ); }
/* hrSWRunCache_Refresh - hrSWRun(Perf) Cache Refresh-Check Routine */ /* hrSWRunCache_Refresh - hrSWRun(Perf) Cache Refresh-Check Routine */ /* hrSWRunCache_Refresh - hrSWRun(Perf) Cache Refresh-Check Routine */
BOOL hrSWRunCache_Refresh( void )
/*
| EXPLICIT INPUTS: | | None. | | IMPLICIT INPUTS: | | The "hrSWRunTable_cache" CACHEHEAD structure and the time when | it was last refreshed in module-local cell "cache_time". | | OUTPUTS: | | On Success/Failure: | The function returns TRUE. Only if the cache-time has aged-out | is the cache actually rebuilt. | | On any Failure: | If during a rebuild there is an error, this function returns FALSE. | The state of the cache is indeterminate. | | THE BIG PICTURE: | | This function is invoked before any reference is made to any SNMP | variable in the hrSWRun or hrSWRunPerf table. It checks to see | if the cache needs to be rebuilt based on the last time it was built. | | The calls to this function are strategically located in the | "FindInstance" and "FindNextInstance" functions in "HRSWRUNE.C" | (this module) and "HRSWPREN.C" (for the RunPerf table) as well | as in "HRSWRUN.C" for the stand-alone attribute "hrSWOSIndex". | | OTHER THINGS TO KNOW: | */ { LARGE_INTEGER now_time; /* Current System time in 100 ns ticks */
/* Get the current time in 100 ns ticks*/ if (NtQuerySystemTime (&now_time) != STATUS_SUCCESS ) return FALSE;
/* If the cache is older than the maximum allowed time (in ticks) . . . */ if ( (now_time.QuadPart - cache_time.QuadPart) > (CACHE_MAX_AGE * 10000000) ){ return ( Gen_HrSWRun_Cache() ); }
return ( TRUE ); /* No Error (because no refresh) */ }
/* FetchProcessParams - Fetch Path & Parameter String from Process Cmd line */ /* FetchProcessParams - Fetch Path & Parameter String from Process Cmd line */ /* FetchProcessParams - Fetch Path & Parameter String from Process Cmd line */
void FetchProcessParams(
PSYSTEM_PROCESS_INFORMATION ProcessInfo, /* Process for parameters */ CHAR **path_str, /* Returned PATH string */ CHAR **params_str /* Returned Parameters string */ ) /*
| EXPLICIT INPUTS: | | "ProcessInfo" points to the process (as described by a | SYSTEM_PROCESS_INFORMATION structure) for which the path & parameters | (from the command-line) are desired. | | "path_str" is the address of a pointer to be set to any "path" string. | "params" is the address of a pointer to be set to any "parameters" | string. | | IMPLICIT INPUTS: | | None. | | OUTPUTS: | | On Success: | Function returns pointers to a static buffer containing the | path & parameters section of the command line. There may be nothing | in the buffer (ie just the null-termination). | | On any Failure: | Function returns NULLS indicating a problem was encountered | attempting to obtain the command-line image from which the | path & parameter portion is to be extracted, or indicating that | one or both were not present. | | THE BIG PICTURE: | | Called from "AddHrSWRunRow()" above, this is a helper function | that serves to isolate the code lifted from "TLIST" from | the rest of the subagent. | | OTHER THINGS TO KNOW: | | The black magic here was lifted from sections of "TLIST". */ { HANDLE hProcess; PEB Peb; NTSTATUS Status; PROCESS_BASIC_INFORMATION BasicInfo; WCHAR szT[(MAX_PATH * 2)+1]; UNICODE_STRING u_param; RTL_USER_PROCESS_PARAMETERS ProcessParameters;
#define ANSI_PARAM_LEN (MAX_PATH * 2)
ANSI_STRING param; /* ANSI version of UNICODE command line */ static CHAR pbuf[ANSI_PARAM_LEN+1]; /* Buffer for "parameters" */ CHAR *param_str; /* Pointer to our final parameter string */ SIZE_T dwbytesret; /* Count of bytes read from process memory */
pbuf[ANSI_PARAM_LEN] = 0; szT[MAX_PATH * 2] = 0;
/* Presume failure/nothing obtained */ *path_str = NULL; *params_str = NULL;
/* get a handle to the process */ hProcess = OpenProcess(PROCESS_VM_READ|PROCESS_QUERY_INFORMATION, FALSE, HandleToUlong(ProcessInfo->UniqueProcessId)); if (!hProcess) { return; }
Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL); if (!NT_SUCCESS(Status)) { CloseHandle(hProcess); return; }
// get the PEB
if (ReadProcessMemory(hProcess, BasicInfo.PebBaseAddress, &Peb, sizeof(PEB), NULL)) {
// get the processparameters
if (ReadProcessMemory(hProcess, Peb.ProcessParameters, &ProcessParameters, sizeof(ProcessParameters), NULL)) {
// get cmdline
if (ReadProcessMemory(hProcess, ProcessParameters.CommandLine.Buffer, szT, sizeof(szT)-2, // minus the last 2 bytes
&dwbytesret ) ) {
CHAR *scanner; /* Used for parsing the command-line */
/* Prep the STRING structure */ param.Buffer = pbuf; param.MaximumLength = ANSI_PARAM_LEN; u_param.Length = (USHORT) ((wcslen(szT) + 1) * 2); // bytes incl. NULL
u_param.Buffer = szT; /* Convert from Unicode */ Status = RtlUnicodeStringToAnsiString(¶m, // Target string
&u_param, /* Src */ FALSE); /* = Don't Allocate buf */
if (Status != STATUS_SUCCESS) { CloseHandle(hProcess); return; }
// Firstly, we need to check for command line of the form:
// "c:\program files\blah\blah" -parameter1 -parameter2
// "C:\Program Files\Internet Explorer\IEXPLORE.EXE"
// but not:
// C:\WINDOWS\system32\mmc.exe "C:\WINDOWS\system32\tsmmc.msc" /s
if ( pbuf[0] == '\"') { // get first '\"', see if there is another one
if ((scanner = strchr(pbuf+1, '\"')) != NULL) { // found the 2nd terminating '\"'
*params_str = (scanner + 1); *scanner = 0; // Terminate the base string
// Path
if ((scanner = strrchr(pbuf, '\\')) != NULL) { // Terminate the path
*(scanner+1) = 0;
// Return start of buffer as path
*path_str = pbuf+1; } else { // No path
*path_str = NULL; } } } else /*
| OK, we can have the following situations: | | 1) "\system\system32\smss.exe -parameter1 -parameter2" | --------path----- -------parameters------ | | 2) "\system\system32\smss.exe" | --------path----- | | 3) "smss.exe -parameter1 -parameter2" | -------parameters------ | | and we want to handle this by returning "path" and "parameter" | as shown, where: | | 1) both path and parameters are present | 2) only path is present | 3) only parameters are present | | We do this: | | - Scan forward for a blank. | If we get one: | + return the address following it as "parameters" | + set the blank to a null byte (cutting off parameters) | If not: | + return NULL as "parameters" | | ----Parameters are done. | | - Perform a reverse search for "\" on whatever is now in the | buffer | If we find a "\": | + Step forward one character and turn it into a null | byte (turning buffer into string containing path). | + Return the buffer address as "path" | If not: | + return NULL as "path" */ /* Parameter */ { if ((scanner = strchr(pbuf, ' ')) != NULL) {
/* Return address of char after blank as start of parameters */ *params_str = (scanner + 1); *scanner = '\0'; /* Terminate base string */ } else { /* No parameters */ *params_str = NULL; }
/* Path */ if ((scanner = strrchr(pbuf, '\\')) != NULL) { /* Terminate the path */ *(scanner+1) = '\0';
/* Return start of buffer as path */ *path_str = pbuf; } else { /* No path */ *path_str = NULL; } }
CloseHandle(hProcess);
/* Return address of static ANSI string buffer */ return; } } }
CloseHandle(hProcess);
/* Nothing back */ return; }
#if defined(CACHE_DUMP)
/* debug_print_hrswrun - Prints a Row from HrSWRun(Perf) Table */ /* debug_print_hrswrun - Prints a Row from HrSWRun(Perf) Table */ /* debug_print_hrswrun - Prints a Row from HrSWRun(Perf) Table */
static void debug_print_hrswrun( CACHEROW *row /* Row in hrSWRun(Perf) table */ ) /*
| EXPLICIT INPUTS: | | "row" - points to the row to be dumped, if NULL, the function | merely prints a suitable title. | | IMPLICIT INPUTS: | | - Symbols used to reference the attributes in the row entry. | - File handle defined by OFILE, presumed to be open. | | OUTPUTS: | | On Success: | Function prints a dump of the row in ASCII for debugging purposes | on file handle OFILE. | | THE BIG PICTURE: | | Debugging only. | | OTHER THINGS TO KNOW: */ {
if (row == NULL) { fprintf(OFILE, "=================================\n"); fprintf(OFILE, "hrSWRun & hrSWRunPerf Table Cache\n"); fprintf(OFILE, "=================================\n"); return; }
fprintf(OFILE, "HrSWRunIndex . . . . . . %d\n", row->attrib_list[HRSR_INDEX].u.unumber_value);
fprintf(OFILE, "HrSWRunName. . . . . . . \"%s\"\n", row->attrib_list[HRSR_NAME].u.string_value);
fprintf(OFILE, "HrSWRunPath. . . . . . . \"%s\"\n", row->attrib_list[HRSR_PATH].u.string_value);
fprintf(OFILE, "HRSWRunParameters. . . . \"%s\"\n", row->attrib_list[HRSR_PARAM].u.string_value);
fprintf(OFILE, "HrSWRunType. . . . . . . %d ", row->attrib_list[HRSR_TYPE].u.unumber_value);
switch (row->attrib_list[HRSR_TYPE].u.unumber_value) { case 1: fprintf(OFILE, "(unknown)\n"); break; case 2: fprintf(OFILE, "(operatingSystem)\n"); break; case 3: fprintf(OFILE, "(deviceDriver)\n"); break; case 4: fprintf(OFILE, "(application)\n"); break; default: fprintf(OFILE, "(???)\n"); }
fprintf(OFILE, "HrSWRunStatus. . . . . . %d ", row->attrib_list[HRSR_STATUS].u.unumber_value);
switch (row->attrib_list[HRSR_STATUS].u.unumber_value) { case 1: fprintf(OFILE, "(running)\n"); break; case 2: fprintf(OFILE, "(runnable)\n"); break; case 3: fprintf(OFILE, "(notRunnable)\n"); break; case 4: fprintf(OFILE, "(invalid)\n"); break; default: fprintf(OFILE, "(???)\n"); }
fprintf(OFILE, "HrSWRunPerfCpu . . . . . %d (Centi-seconds)\n", row->attrib_list[HRSP_CPU].u.unumber_value);
fprintf(OFILE, "HrSWRunPerfMem . . . . . %d (Kbytes)\n", row->attrib_list[HRSP_MEM].u.unumber_value); } #endif
|