/* * HrStorageEntry.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 HrStorageEntry. * 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, plus the cache * initialization function "Gen_Hrstorage_Cache()". * * Author: * * D. D. Burns @ Webenable Inc * * Revision History: * * V1.00 - 04/17/97 D. D. Burns Genned: Thu Nov 07 16:40:22 1996 * V1.01 - 05/15/97 D. D. Burns Move Disk Label/Size acquisitions * to cache from real-time * V1.02 - 06/18/97 D. D. Burns Add spt to scan event log for * allocation failures * */ #include #include #include #include #include #include #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" /* For string manipulation in "Gen_Hrstorage_Cache"*/ #include "stdio.h" /* For sprintf */ /* |============================================================================== | Function prototypes for this module. | */ /* ScanLog_Failures - Scan Event Log for Storage Allocation Failures */ static UINT ScanLog_Failures( CHAR *device ); #if defined(CACHE_DUMP) /* debug_print_hrstorage - Prints a Row from Hrstorage sub-table */ static void debug_print_hrstorage( CACHEROW *row /* Row in hrstorage table */ ); #endif /* |============================================================================== | Cache Refresh Time | | The cache for the hrStorage and hrFSTable tables are refreshed automatically | when a request arrives at the hrStorage --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 HrStorage table cache. | | This list-head is globally accessible so the logic that loads hrFSTable | can scan this cache for matches (among other reasons). | | (This macro is defined in "HMCACHE.H"). */ CACHEHEAD_INSTANCE(hrStorage_cache, debug_print_hrstorage); /* |============================================================================== | Local string for this kind of "storage". */ #define VM "Virtual Memory" /* * ============================================================================ * GetHrStorageIndex * A unique value for each logical storage are contained by the host. * * Gets the value for HrStorageIndex. * * 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================== | hrStorageIndex | | ACCESS SYNTAX | read-only INTEGER (1..2147483647) | | "A unique value for each logical storage area contained by the host." | | DISCUSSION: | | The value of this attribute is always the number of drives reported by | "GetLogicalDrives" (excepting network drives) plus one (for reporting on | "Virtual Memory"). | |============================================================================ | 1.3.6.1.2.1.25.2.3.1.1. | | | | | | | | | *hrStorageIndex | | | *hrStorageEntry | | *-hrStorageTable | *-hrStorage */ UINT GetHrStorageIndex( 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, &hrStorage_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; } /* | Return the "hrStorageIndex" value from this entry */ *outvalue = row->attrib_list[HRST_INDEX].u.unumber_value; return SNMP_ERRORSTATUS_NOERROR ; } /* end of GetHrStorageIndex() */ /* * ============================================================================ * GetHrStorageType * The type of strage represented by this entry. * * Gets the value for HrStorageType. * * 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================== | hrStorageType | | ACCESS SYNTAX | read-only OBJECT IDENTIFIER | | "The type of storage represented by this entry." | | -- Registration for some storage types, for use with hrStorageType | | hrStorageOther OBJECT IDENTIFIER ::= { hrStorageTypes 1 } | hrStorageRam OBJECT IDENTIFIER ::= { hrStorageTypes 2 } | -- hrStorageVirtualMemory is temporary storage of swapped | -- or paged memory | hrStorageVirtualMemory OBJECT IDENTIFIER ::= { hrStorageTypes 3 } | hrStorageFixedDisk OBJECT IDENTIFIER ::= { hrStorageTypes 4 } | hrStorageRemovableDisk OBJECT IDENTIFIER ::= { hrStorageTypes 5 } | hrStorageFloppyDisk OBJECT IDENTIFIER ::= { hrStorageTypes 6 } | hrStorageCompactDisc OBJECT IDENTIFIER ::= { hrStorageTypes 7 } | hrStorageRamDisk OBJECT IDENTIFIER ::= { hrStorageTypes 8 } | | DISCUSSION: | | The value returned for this attribute is determined by indications from | "GetDriveType" for disks. For the "Virtual Memory" entry, the OID for | "hrStorageVirtualMemory" is returned. | |============================================================================ | 1.3.6.1.2.1.25.2.3.1.2. | | | | | | | | | *hrStorageType | | | *hrStorageEntry | | *-hrStorageTable | *-hrStorage */ UINT GetHrStorageType( OUT ObjectIdentifier *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, &hrStorage_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; } /* | By convention with the cache-building function "Gen_Hrstorage_Cache()", | the cached value is the right-most arc we must return as the value. | | Hence whatever cache entry we retrieve, we tack the number retrieved | from the cache for this attribute onto { hrStorageTypes ... }. */ if ( (outvalue->ids = SNMP_malloc(10 * sizeof( UINT ))) == NULL) { return SNMP_ERRORSTATUS_GENERR; } outvalue->idLength = 10; /* | Load in the full hrStorageType OID: | | 1.3.6.1.2.1.25.2.1.n | | | | | | | *-Type indicator | | *-hrStorageTypes (OIDs specifying storage types) | *-hrStorage | */ outvalue->ids[0] = 1; outvalue->ids[1] = 3; outvalue->ids[2] = 6; outvalue->ids[3] = 1; outvalue->ids[4] = 2; outvalue->ids[5] = 1; outvalue->ids[6] = 25; outvalue->ids[7] = 2; outvalue->ids[8] = 1; /* Cached Type indicator */ outvalue->ids[9] = row->attrib_list[HRST_TYPE].u.unumber_value; return SNMP_ERRORSTATUS_NOERROR ; } /* end of GetHrStorageType() */ /* * GetHrStorageDesc * A description of the type and instance of the storage described by this * entry. * * Gets the value for HrStorageDesc. * * 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================== | hrStorageDescr | | ACCESS SYNTAX | read-only DisplayString | | "A description of the type and instance of the storage described by this | entry." | | DISCUSSION: | | For the Virtual Memory entry, the string "Virtual Memory" is returned. | | For disks, a string composed of: | + the logical drive letter followed by | + the Volume Identification (for drives containing a volume) | in double quotes | + the Volume Serial Number | | For instance, the value of this variable for drive C might be | C: Label="Main Disk" Serial #=0030-34FE | | For speed, the label acquisition is done at cache-build time, and | as a consequence the removable drives are sampled only once. | =========================================================================== | 1.3.6.1.2.1.25.2.3.1.3. | | | | | | | | | *hrStorageDescr | | | *hrStorageEntry | | *-hrStorageTable | *-hrStorage */ UINT GetHrStorageDesc( OUT Simple_DisplayString *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, &hrStorage_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; } /* Return the description that was computed at cache-build time */ outvalue->length = strlen(row->attrib_list[HRST_DESCR].u.string_value); outvalue->string = row->attrib_list[HRST_DESCR].u.string_value; return SNMP_ERRORSTATUS_NOERROR ; } /* end of GetHrStorageDesc() */ /* * GetHrStorageAllocationUnits * The size, in bytes, of the data objects allocated from this pool. If * this entry is monitoring sectors, blocks, buffers, or pack * * Gets the value for HrStorageAllocationUnits. * * 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================== | hrStorageAllocationUnits | | ACCESS SYNTAX | read-only INTEGER (1..2147483647) | | "The size, in bytes, of the data objects allocated from this pool. If this | entry is monitoring sectors, blocks, buffers, or packets, for example, this | number will commonly be greater than one. Otherwise this number will | typically be one." | | DISCUSSION: | | For Virtual Memory, the value returned is that provided as | "AllocationGranularity" after a call to "GetSystemInfo". | | For disks, the size of the "hrStorageAllocationUnits" value is computed as | the quantity "BytesPerSector * SectorsPerCluster" as returned by Win32 API | function "GetDiskFreeSpace". | | ============================================================================= | 1.3.6.1.2.1.25.2.3.1.4. | | | | | | | | | *hrStorageAllocationUnits | | | *hrStorageEntry | | *-hrStorageTable | *-hrStorage */ UINT GetHrStorageAllocationUnits( 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, &hrStorage_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; } *outvalue = row->attrib_list[HRST_ALLOC].u.number_value; return ( SNMP_ERRORSTATUS_NOERROR ); } /* end of GetHrStorageAllocationUnits() */ /* * GetHrStorageSize * The size of the storage represented by this entry, in units of * hrStorageAllocationUnits. * * Gets the value for HrStorageSize. * * 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================== | hrStorageSize | | ACCESS SYNTAX | read-write INTEGER (0..2147483647) | | "The size of the storage represented by this entry, in units of | hrStorageAllocationUnits." | | DISCUSSION: | | For Virtual Memory, the value returned is computed as "TotalPageFile" (as | returned by "GlobalMemoryStatus") divided by "AllocationGranularity" from | "GetSystemInfo". | | For disks, the "hrStorageSize" value is the value of "TotalNumberOfClusters" | as returned by Win32 API function "GetDiskFreeSpace". | | This variable is marked as ACCESS="read-write". It is unclear to me | what effect can be expected from a SET operation on this variable. I propose | making a SET operation have no effect. | | RESOLVED >>>>>>> | Leaving this read-only is fine. | RESOLVED >>>>>>> | | ============================================================================= | 1.3.6.1.2.1.25.2.3.1.5. | | | | | | | | | *hrStorageSize | | | *hrStorageEntry | | *-hrStorageTable | *-hrStorage */ UINT GetHrStorageSize( 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, &hrStorage_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; } *outvalue = row->attrib_list[HRST_SIZE].u.number_value; return ( SNMP_ERRORSTATUS_NOERROR ) ; } /* end of GetHrStorageSize() */ /* * SetHrStorageSize * The size of the storage represented by this entry, in units of * hrStorageAllocationUnits. * * Sets the HrStorageSize 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 * | ============================================================================= | 1.3.6.1.2.1.25.2.3.1.5. | | | | | | | | | *hrStorageSize | | | *hrStorageEntry | | *-hrStorageTable | *-hrStorage */ UINT SetHrStorageSize( IN Integer *invalue , OUT Integer *outvalue , IN Access_Credential *access , IN InstanceName *instance ) { #if 0 //debug debug debug debug debug static int x=0; if (x==0) { /* | If it is invoked here, the invocation | of it in mib.c must be removed. */ Gen_HrDevice_Cache(); x =1; } //debug debug debug debug debug #endif return SNMP_ERRORSTATUS_NOSUCHNAME ; } /* end of SetHrStorageSize() */ /* * GetHrStorageUsed * The amount of the storage represented by this entry that is allocated, * in units of hrStorageAllocationUnits. * * Gets the value for HrStorageUsed. * * 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================== | hrStorageUsed | | ACCESS SYNTAX | read-only INTEGER (0..2147483647) | | "The amount of the storage represented by this entry that is allocated, in | units of hrStorageAllocationUnits." | | DISCUSSION: | | For Virtual Memory, the value returned is computed as the quantity | "TotalPageFile" less "AvailPageFile" (as returned by "GlobalMemoryStatus") | divided by "AllocationGranularity" (as returned by "GetSystemInfo". | | For disks, the "hrStorageUsed" value is computed as the quantity | "TotalNumberOfClusters - NumberOfFreeClusters" as returned by Win32 API | function "GetDiskFreeSpace". | | =========================================================================== | 1.3.6.1.2.1.25.2.3.1.6. | | | | | | | | | *hrStorageUsed | | | *hrStorageEntry | | *-hrStorageTable | *-hrStorage */ UINT GetHrStorageUsed( 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, &hrStorage_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; } *outvalue = row->attrib_list[HRST_USED].u.number_value; return ( SNMP_ERRORSTATUS_NOERROR ) ; } /* end of GetHrStorageUsed() */ /* * GetHrStorageAllocationFailures * The number of requests for storage represented by this entry that could * not be honored due to not enough storage. It should be * * Gets the value for HrStorageAllocationFailures. * * 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 * |============================================================================= |hrStorageAllocationFailures | | ACCESS SYNTAX | read-only Counter | |"The number of requests for storage represented by this entry that could not |be honored due to not enough storage. It should be noted that as this object |has a SYNTAX of Counter, that it does not have a defined initial value. |However, it is recommended that this object be initialized to zero." | |DISCUSSION: | | This value as very problematical for both Virtual Memory and Disk |storage. There appear to be no Win32 APIs that report allocation failures for |either virtual memory or disk storage. I presume there may be performance |monitoring counters stored in the registry, however I'm not able to find the |documentation that describes where such information might be stored. For |disks, we need to be able to map whatever counters are stored into logical |drives (as that is how this table is organized). | |RESOLVED >>>>>>> | You would have to scan to event log looking for the out of virtual |memory and out of disk space events and count them. |RESOLVED >>>>>>> |============================================================================= | 1.3.6.1.2.1.25.2.3.1.7. | | | | | | | | | *hrStorageAllocationFailures | | | *hrStorageEntry | | *-hrStorageTable | *-hrStorage */ UINT GetHrStorageAllocationFailures( OUT Counter *outvalue , IN Access_Credential *access , IN InstanceName *instance ) { CHAR device[3]; /* Device Name build-buffer */ 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, &hrStorage_cache)) == NULL) { return SNMP_ERRORSTATUS_GENERR; } /* | Load the "device[]" array with two characters, either something like "C:" | (indicating we're interested in allocation failures for "C:") or "VM" | if we want VM storage allocation failures.... from the HRST_DESCR string. */ if (strcmp(row->attrib_list[HRST_DESCR].u.string_value, VM) == 0) { /* Storage is really "Virtual Memory" */ device[0] = 'V'; device[1] = 'M'; } else { device[0] = row->attrib_list[HRST_DESCR].u.string_value[0]; device[1] = row->attrib_list[HRST_DESCR].u.string_value[1]; } device[2] = '\0'; /* Null-terminate */ /* Riffle thru the Event Log looking for this device's failures */ *outvalue = ScanLog_Failures( device ); return SNMP_ERRORSTATUS_NOERROR ; } /* end of GetHrStorageAllocationFailures() */ /* * HrStorageEntryFindInstance * * 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 HrStorageEntryFindInstance( 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 <= HRSTORAGEENTRY_VAR_INDEX ) // No instance was specified return SNMP_ERRORSTATUS_NOSUCHNAME ; else if ( FullOid->idLength != HRSTORAGEENTRY_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[ HRSTORAGEENTRY_VAR_INDEX ] ; /* | Check for age-out and possibly refresh the entire cache for the | hrStorage table and hrFSTable before we check to see if the | instance is there. */ if (hrStorageCache_hrFSTableCache_Refresh() == FALSE) { return SNMP_ERRORSTATUS_GENERR; } /* | For hrStorage, the instance arc(s) is a single arc, and it must | correctly select an entry in the hrStorageTable cache. | Check that here. */ if ( FindTableRow(tmp_instance, &hrStorage_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 HrStorageEntryFindInstance() */ /* * HrStorageEntryFindNextInstance * * 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 HrStorageEntryFindNextInstance( IN ObjectIdentifier *FullOid , IN OUT ObjectIdentifier *instance ) { // Developer supplied code to find the next instance of class goes here. // // The purpose of this function is to indicate to the rest of the system // what the exact OID of the "next instance" is GIVEN THAT: // // a) The "FullOid" passed in will have enough arcs to specify // both the TABLE and the ATTRIBUTE in the table // // b) The "instance" OID array is always big enough to have // as many arcs as needed loaded into it by this function // to specify (exactly) the "next instance" // // // 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 is so short that it does not specify an instance, // then the only instance of the class should be returned. If this is a // table, the first row of the table is returned. To do these things, // set the "instance" OID to just the right arcs such that when // concatenated onto the FullOid, the concatenation exactly specifies // the first instance of this attribute in the table. // // 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 <= HRSTORAGEENTRY_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[ HRSTORAGEENTRY_VAR_INDEX ] ; } /* | Check for age-out and possibly refresh the entire cache for the | hrStorage table and hrFSTable before we check to see if the | instance is there. */ if (hrStorageCache_hrFSTableCache_Refresh() == FALSE) { return SNMP_ERRORSTATUS_GENERR; } /* Now go off and try to find the next instance in the table */ if ((row = FindNextTableRow(tmp_instance, &hrStorage_cache)) == NULL) { return SNMP_ERRORSTATUS_NOSUCHNAME ; } instance->ids[ 0 ] = row->index ; instance->idLength = 1 ; return SNMP_ERRORSTATUS_NOERROR ; } /* end of HrStorageEntryFindNextInstance() */ /* * HrStorageEntryConvertInstance * * 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 HrStorageEntryConvertInstance( 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 HrStorageEntryConvertInstance() */ /* * HrStorageEntryFreeInstance * * 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 HrStorageEntryFreeInstance( IN OUT InstanceName *instance ) { /* No action needed for hrStorageTable */ } /* end of HrStorageEntryFreeInstance() */ /* | End of Generated Code */ /* hrStorageCache_hrFSTableCache_Refresh Cache Refresh-Check Routine */ /* hrStorageCache_hrFSTableCache_Refresh Cache Refresh-Check Routine */ /* hrStorageCache_hrFSTableCache_Refresh Cache Refresh-Check Routine */ BOOL hrStorageCache_hrFSTableCache_Refresh( void ) /* | EXPLICIT INPUTS: | | None. | | IMPLICIT INPUTS: | | The "hrStorage_cache" CACHEHEAD structure and the time when | it was last refreshed in module-local cell "cache_time". | The "hrFSTable_cache" CACHEHEAD structure which depends on | the hrStorage_cache CACHEHEAD structure. | | 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 hrStorage table. It checks to see | if the cache needs to be rebuilt based on the last time it was built. | Since the hrFSTable_cache depends on the hrStorage table, | hrFSTable_cache will be rebuilt whenever hrStorage table is rebuilt. | | The calls to this function are strategically located in the | "FindInstance" and "FindNextInstance" functions in "HRSTOENT.C" | (this module). | | OTHER THINGS TO KNOW: | */ { LARGE_INTEGER now_time; /* Current System time in 100 ns ticks */ /* Get the current time in 100 ns ticks*/ NtQuerySystemTime (&now_time); /* If the cache is older than the maximum allowed time (in ticks) . . . */ if ( (now_time.QuadPart - cache_time.QuadPart) > (CACHE_MAX_AGE * 10000000) ) { if (Gen_Hrstorage_Cache()) { // hrFSStorageIndex attribute of hrFSTable depends on the // the index of the hrStorageEntry return (Gen_HrFSTable_Cache()); } else return FALSE; } return ( TRUE ); /* No Error (because no refresh) */ } /* Gen_Hrstorage_Cache - Generate a initial cache for HrStorage Table */ /* Gen_Hrstorage_Cache - Generate a initial cache for HrStorage Table */ /* Gen_Hrstorage_Cache - Generate a initial cache for HrStorage Table */ BOOL Gen_Hrstorage_Cache( void ) /* | EXPLICIT INPUTS: | | None. | | IMPLICIT INPUTS: | | The module-local head of the cache for the HrStorage table, | "hrStorage_cache". | | OUTPUTS: | | On Success: | Function returns TRUE indicating that the cache has been fully | populated with all "static" cache-able values. | | 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 HrStorage table. | | OTHER THINGS TO KNOW: | | There is one of these function for every table that has a cache. | Each is found in the respective source file. | |=============== From WebEnable Design Spec Rev 3 04/11/97================== | DISCUSSION: | | Since this table is meant for diagnosing "out-of-storage" situations and | given that the information is meant to be regarded from the point of view | of an application, we simply report every instance of what would appear | on the "Drive Bar" of the File Manager (excepting network drives) plus | one more table entry to reflect information on "Virtual Memory". | | To this end, a combination of Win32 API functions "GetLogicalDrives", | "GetVolumeInformation", "GetDriveType" and "GetDiskFreeSpace" are used to | acquire the information for the SNMP attributes in this table. | | For reporting on "Virtual Memory", functions "GlobalMemoryStatus" and | "GetSystemInfo" are invoked. |============================================================================ | 1.3.6.1.2.1.25.2.1.... | | | | | *-hrStorageTypes (OIDs specifying storage types) | *-hrStorage | | 1.3.6.1.2.1.25.2.2.... | | | | | *-hrMemorySize (standalone attribute) | *-hrStorage | | 1.3.6.1.2.1.25.2.3.... | | | | | *-hrStorageTable (the table) | *-hrStorage */ #define VOL_NAME_SIZE 256 #define DESCR_SIZE 384 { CHAR temp[8]; /* Temporary buffer for first call */ LPSTR pDrvStrings; /* --> allocated storage for drive strings */ LPSTR pOriginal_DrvStrings; /* (Needed for final deallocation */ DWORD DS_request_len; /* Storage actually needed */ DWORD DS_current_len; /* Storage used on 2nd call */ ULONG table_index=0; /* hrStorageTable index counter */ CACHEROW *row; /* --> Cache structure for row-being built */ SYSTEM_INFO sys_info; /* Filled in by GetSystemInfo for VM */ LPSTR str_descr; /* String for disk label/serial description*/ TCHAR volname[VOL_NAME_SIZE+2]; /* Volume Name returned here */ DWORD volnamesize=VOL_NAME_SIZE; /* Size of volname buffer */ DWORD serial_number; /* Volume Serial Number */ DWORD max_comp_len; /* File system file-name component length */ DWORD filesys_flags; /* File System flags (GetVolInformation) */ CHAR descr[DESCR_SIZE]; /* Full description possibly built here */ DWORD SectorsPerCluster; /* GetDiskFreeSpace() cells */ DWORD BytesPerSector; DWORD NumberOfFreeClusters; DWORD TotalNumberOfClusters; MEMORYSTATUS mem_status; /* Filled in by GlobalMemoryStatus */ NTSTATUS ntstatus; /* Generic return status */ /* | Blow away any old copy of the cache */ DestroyTable(&hrStorage_cache); /* | We're going to call GetLogicalDriveStrings() twice, once to get the proper | buffer size, and the second time to actually get the drive strings. | | Bogus: */ if ((DS_request_len = GetLogicalDriveStrings(2, temp)) == 0) { /* Request failed altogether, can't initialize */ return ( FALSE ); } /* | Grab enough storage for the drive strings plus one null byte at the end */ if ( (pOriginal_DrvStrings = pDrvStrings = malloc( (DS_request_len + 2) ) ) == NULL) { /* Storage Request failed altogether, can't initialize */ return ( FALSE ); } /* Go for all of the strings */ if ((DS_current_len = GetLogicalDriveStrings(DS_request_len, pDrvStrings)) == 0) { /* Request failed altogether, can't initialize */ free( pOriginal_DrvStrings ); return ( FALSE ); } /* | Freshen the time on the cache | | Get the current system-time in 100ns intervals . . . */ ntstatus = NtQuerySystemTime (&cache_time); /* |============================================================================== | As long as we've got an unprocessed drive-string. . . */ while ( strlen(pDrvStrings) > 0 ) { UINT drivetype; /* Type of the drive from "GetDriveType()" */ /* | Get the drive-type so we can decide whether it should participate in | this table. */ drivetype = GetDriveType(pDrvStrings); if ( drivetype == DRIVE_UNKNOWN || drivetype == DRIVE_NO_ROOT_DIR || drivetype == DRIVE_REMOTE /* No Remotes in HrStorage */ ) { /* Step to next string, if any */ pDrvStrings += strlen(pDrvStrings) + 1; continue; } /* | OK, we want this one in the table, get a row-entry created. */ if ((row = CreateTableRow( HRST_ATTRIB_COUNT ) ) == NULL) { return ( FALSE ); // Out of memory } /* =========== hrStorageIndex ==========*/ row->attrib_list[HRST_INDEX].attrib_type = CA_NUMBER; row->attrib_list[HRST_INDEX].u.unumber_value = ++table_index; /* =========== hrStorageType ==========*/ row->attrib_list[HRST_TYPE].attrib_type = CA_NUMBER; /* | Based on the drive-type returned, we store a single number as | the cached value of the hrStorageType attribute. When this attribute | is fetched, the cached number forms the last arc in the OBJECT IDENTIFIER | that actually specifies the type: { hrStorageTypes x }, where "x" is | what gets stored. */ switch (drivetype) { case DRIVE_REMOVABLE: row->attrib_list[HRST_TYPE].u.unumber_value = 5; break; case DRIVE_FIXED: row->attrib_list[HRST_TYPE].u.unumber_value = 4; break; case DRIVE_CDROM: row->attrib_list[HRST_TYPE].u.unumber_value = 7; break; case DRIVE_RAMDISK: row->attrib_list[HRST_TYPE].u.unumber_value = 8; break; default: row->attrib_list[HRST_TYPE].u.unumber_value = 1; // "Other" break; } /* =========== hrStorageDescr ========== | | We try and fetch the volume label here, to get a string | that may look like: | C: Label="Main Disk" Serial #=0030-34FE | | Handle all kinds of disk storage here: | | Try to get volume label and serial number. If we fail, we just give | 'em the root-path name. | | Presume that we'll fail, and just return the root-path string. */ str_descr = pDrvStrings; /* | Suppress any attempt by the system to make the user put a volume in a | removable drive. */ SetErrorMode(SEM_FAILCRITICALERRORS); if (GetVolumeInformation(pDrvStrings, /* drive name */ volname, /* Volume Name Buffer */ volnamesize, /* Size of buffer */ &serial_number, /* Vol. # Returned here */ &max_comp_len, /* Max filename length */ &filesys_flags, /* File System flags */ NULL, /* Name of Filesystem */ 0 /* Length of name */ )) { /* | We got something back. | | If we have room given string lengths, build a description: | | Label: Serial Number: <#> */ #define SPRINTF_FORMAT "%s Label:%s Serial Number %x" if ((strlen(SPRINTF_FORMAT) + strlen(volname) + strlen(str_descr)) < DESCR_SIZE) { sprintf(descr, SPRINTF_FORMAT, str_descr, // root-path volname, // volume name serial_number); // volume serial # str_descr = descr; } } row->attrib_list[HRST_DESCR].attrib_type = CA_STRING; /* | Note: | The convention is established that the first characters of | this description string is always the device-string (e.g. "C:") | or the value of local symbol "VM" ("Virtual Memory"). | | Code in "GetHrStorageAllocationFailures()" attempts to extract | the drive letter (or "Virtual Memory") from the beginning of this | string in order to determine allocation failures from the | Event Log(!). */ if ( (row->attrib_list[HRST_DESCR].u.string_value = ( LPSTR ) malloc(strlen(str_descr) + 1)) == NULL) { return ( FALSE ); /* out of memory */ } /* Copy the Value into the space */ strcpy(row->attrib_list[HRST_DESCR].u.string_value, str_descr); row->attrib_list[HRST_ALLOC].attrib_type = CA_NUMBER; row->attrib_list[HRST_SIZE].attrib_type = CA_NUMBER; row->attrib_list[HRST_USED].attrib_type = CA_NUMBER; /* | Handle all kinds of disk storage info here: | | Try to get volume statistics via GetDiskFreeSpace(). */ if (GetDiskFreeSpace(pDrvStrings, // drive &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters )) { /* Success */ /* =========== hrStorageAllocationUnits ==========*/ row->attrib_list[HRST_ALLOC].u.unumber_value = BytesPerSector * SectorsPerCluster; /* =========== hrStorageSize ==========*/ row->attrib_list[HRST_SIZE].u.unumber_value = TotalNumberOfClusters; /* =========== hrStorageUsed ==========*/ row->attrib_list[HRST_USED].u.unumber_value = TotalNumberOfClusters - NumberOfFreeClusters; } else { /* Failure */ /* =========== hrStorageAllocationUnits ==========*/ row->attrib_list[HRST_ALLOC].u.unumber_value = 0; /* =========== hrStorageSize ==========*/ row->attrib_list[HRST_SIZE].u.unumber_value = 0; /* =========== hrStorageUsed ==========*/ row->attrib_list[HRST_USED].u.unumber_value = 0; } /* =========== hrStorageAllocationFailures ==========*/ row->attrib_list[HRST_FAILS].attrib_type = CA_COMPUTED; SetErrorMode(0); /* Turn error suppression mode off */ /* | Now insert the filled-in CACHEROW structure into the | cache-list for the hrStorageTable. */ if (AddTableRow(row->attrib_list[HRST_INDEX].u.unumber_value, /* Index */ row, /* Row */ &hrStorage_cache /* Cache */ ) == FALSE) { return ( FALSE ); /* Internal Logic Error! */ } /* Step to next string, if any */ pDrvStrings += strlen(pDrvStrings) + 1; } free( pOriginal_DrvStrings ); /* |============================================================================== | Now handle Virtual Memory as a special case. |============================================================================== */ if ((row = CreateTableRow( HRST_ATTRIB_COUNT ) ) == NULL) { return ( FALSE ); // Out of memory } /* =========== hrStorageIndex ==========*/ row->attrib_list[HRST_INDEX].attrib_type = CA_NUMBER; row->attrib_list[HRST_INDEX].u.unumber_value = ++table_index; /* =========== hrStorageType ==========*/ row->attrib_list[HRST_TYPE].attrib_type = CA_NUMBER; row->attrib_list[HRST_TYPE].u.unumber_value = 3; /* Virtual Memory */ /* =========== hrStorageDescr ==========*/ row->attrib_list[HRST_DESCR].attrib_type = CA_STRING; if ( (row->attrib_list[HRST_DESCR].u.string_value = ( LPSTR ) malloc(strlen(VM) + 1)) == NULL) { return ( FALSE ); /* out of memory */ } strcpy(row->attrib_list[HRST_DESCR].u.string_value, VM); /* =========== hrStorageAllocationUnits ==========*/ GetSystemInfo(&sys_info); row->attrib_list[HRST_ALLOC].attrib_type = CA_NUMBER; row->attrib_list[HRST_ALLOC].u.unumber_value = sys_info.dwAllocationGranularity; /* =========== hrStorageSize ==========*/ /* Acquire current memory statistics */ GlobalMemoryStatus(&mem_status); row->attrib_list[HRST_SIZE].attrib_type = CA_NUMBER; row->attrib_list[HRST_SIZE].u.unumber_value = (DWORD)(mem_status.dwTotalPageFile / sys_info.dwAllocationGranularity); /* =========== hrStorageUsed ==========*/ row->attrib_list[HRST_USED].attrib_type = CA_NUMBER; row->attrib_list[HRST_USED].attrib_type = (int)((mem_status.dwTotalPageFile - mem_status.dwAvailPageFile) / sys_info.dwAllocationGranularity); /* =========== hrStorageAllocationFailures ==========*/ row->attrib_list[HRST_FAILS].attrib_type = CA_COMPUTED; /* | Now insert the filled-in CACHEROW structure into the | cache-list for the hrStorageTable. */ if (AddTableRow(row->attrib_list[HRST_INDEX].u.unumber_value, /* Index */ row, /* Row */ &hrStorage_cache /* Cache */ ) == FALSE) { return ( FALSE ); /* Internal Logic Error! */ } /* |============================================================================== | End of Virtual Memory |============================================================================== */ #if defined(CACHE_DUMP) PrintCache(&hrStorage_cache); #endif /* | Initialization of this table's cache succeeded */ return (TRUE); } /* ScanLog_Failures - Scan Event Log for Storage Allocation Failures */ /* ScanLog_Failures - Scan Event Log for Storage Allocation Failures */ /* ScanLog_Failures - Scan Event Log for Storage Allocation Failures */ static UINT ScanLog_Failures( CHAR *device ) /* | EXPLICIT INPUTS: | | "device" is either the string "VM" (for "Virtual Memory") or | the logical device for which we're looking for failures (e.g. "C:"). | | IMPLICIT INPUTS: | | The System Event log file. | | OUTPUTS: | | On Success/Failure: | Function returns the number of storage allocation failures | found for the specified device. | | THE BIG PICTURE: | | This is a "helper" function for routine "GetHrStorageAllocationFailures" | within this module. | | OTHER THINGS TO KNOW: | | We scan backwards (in time) thru the Event Log until we hit the | "Event Logging Started" event record (because, presumably, we don't | care about failures that happened before the system last came up). */ /* | These symbols select the "Event Log Started" informational message. */ #define EVENTLOG_START_ID 0x80001775 #define EVENTLOG_START_TYPE 4 #define EVENTLOG_START_SRC "EventLog" { #define EVL_BUFFER_SIZE 2048 EVENTLOGRECORD *pevlr; BYTE bBuffer[EVL_BUFFER_SIZE]; DWORD dwRead, dwNeeded, cRecords; HANDLE h; BOOL keep_scanning = TRUE; UINT alloc_failures = 0; /* | Open the System event log */ h = OpenEventLog(NULL, /* local computer */ "System" /* source name */ ); if (h == NULL) { return ( alloc_failures ); } pevlr = (EVENTLOGRECORD *) &bBuffer; /* | Read records sequentially "Backward in Time" until there | are no more, or we hit the "Event Logging Started" event. | | Read a "Slug 'o Records": */ while (ReadEventLog(h, // event log handle EVENTLOG_BACKWARDS_READ | // reads backward EVENTLOG_SEQUENTIAL_READ, // sequential read 0, // ignored for sequential reads pevlr, // address of buffer EVL_BUFFER_SIZE, // size of buffer &dwRead, // count of bytes read &dwNeeded) // bytes in next record && keep_scanning == TRUE) { /* Wind down thru this "slug" . . . */ while (dwRead > 0) { /* | Check for "Event Logging Started" | | (The source name is just past the end of the formal structure). */ if ( pevlr->EventID == EVENTLOG_START_ID && pevlr->EventType == EVENTLOG_START_TYPE && strcmp( ((LPSTR) ((LPBYTE) pevlr + sizeof(EVENTLOGRECORD))), EVENTLOG_START_SRC) == 0 ) { keep_scanning = FALSE; break; } //============================================================================ // INSERT RECORD CHECKING LOGIC OF THIS SORT HERE: // // IF ( == pevlr->EventID // && == pevlr->EventType // && == (is the same as..) // ( (LPSTR) ((LPBYTE) pevlr + sizeof(EVENTLOGRECORD)) ) // ) { // // It's an allocation-failure record, if it is for device // // "device", then count it. // IF (strcmp(device, ) { // alloc_failures += 1; // } // } //============================================================================ dwRead -= pevlr->Length; pevlr = (EVENTLOGRECORD *) ((LPBYTE) pevlr + pevlr->Length); } pevlr = (EVENTLOGRECORD *) &bBuffer; } CloseEventLog(h); /* Give 'em the count */ return (alloc_failures); } #if defined(CACHE_DUMP) /* debug_print_hrstorage - Prints a Row from Hrstorage sub-table */ /* debug_print_hrstorage - Prints a Row from Hrstorage sub-table */ /* debug_print_hrstorage - Prints a Row from Hrstorage sub-table */ static void debug_print_hrstorage( CACHEROW *row /* Row in hrstorage 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, "hrStorage Table Cache\n"); fprintf(OFILE, "=====================\n"); return; } fprintf(OFILE, "hrStorageIndex . . . . . %d\n", row->attrib_list[HRST_INDEX].u.unumber_value); fprintf(OFILE, "hrStorageType. . . . . . %d ", row->attrib_list[HRST_TYPE].u.unumber_value); switch (row->attrib_list[HRST_TYPE].u.unumber_value) { case 1: fprintf(OFILE, "(Other)\n"); break; case 2: fprintf(OFILE, "(RAM)\n"); break; case 3: fprintf(OFILE, "(Virtual Memory)\n"); break; case 4: fprintf(OFILE, "(Fixed Disk)\n"); break; case 5: fprintf(OFILE, "(Removable Disk)\n"); break; case 6: fprintf(OFILE, "(Floppy Disk)\n"); break; case 7: fprintf(OFILE, "(Compact Disk)\n"); break; case 8: fprintf(OFILE, "(RAM Disk)\n"); break; default: fprintf(OFILE, "(Unknown)\n"); } fprintf(OFILE, "hrStorageDescr . . . . . \"%s\"\n", row->attrib_list[HRST_DESCR].u.string_value); fprintf(OFILE, "hrStorageAllocationUnits %d\n", row->attrib_list[HRST_ALLOC].u.number_value); fprintf(OFILE, "hrStorageSize. . . . . . %d\n", row->attrib_list[HRST_SIZE].u.number_value); fprintf(OFILE, "hrStorageUsed. . . . . . %d\n", row->attrib_list[HRST_USED].u.number_value); fprintf(OFILE, "hrStorageAllocationFails (Computed)\n"); } #endif