/* * Host Resources MIB - storage group implementation - hrh_storage.c * */ #include #include #include #include #include #include "host_res.h" #include "hrh_filesys.h" #include "hrh_storage.h" #include "hr_disk.h" #include "hr_filesys.h" #include #include #if HAVE_SYS_PARAM_H #include #endif #if HAVE_UNISTD_H #include #endif #if TIME_WITH_SYS_TIME # ifdef WIN32 # include # include # include # else # include # endif # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if HAVE_FCNTL_H #include #endif #if HAVE_STRING_H #include #else #include #endif #include #include #include #define HRSTORE_MONOTONICALLY_INCREASING /********************* * * Kernel & interface information, * and internal forward declarations * *********************/ extern netsnmp_fsys_info *HRFS_entry; static void parse_storage_config(const char *, char *); /********************* * * Initialisation & common implementation functions * *********************/ int Get_Next_HR_Store(void); void Init_HR_Store(void); void* header_hrstoreEntry(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); Netsnmp_Node_Handler handle_memsize; #define HRSTORE_MEMSIZE 1 #define HRSTORE_INDEX 2 #define HRSTORE_TYPE 3 #define HRSTORE_DESCR 4 #define HRSTORE_UNITS 5 #define HRSTORE_SIZE 6 #define HRSTORE_USED 7 #define HRSTORE_FAILS 8 struct variable2 hrstore_variables[] = { {HRSTORE_INDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrstore, 1, {1}}, {HRSTORE_TYPE, ASN_OBJECT_ID, NETSNMP_OLDAPI_RONLY, var_hrstore, 1, {2}}, {HRSTORE_DESCR, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrstore, 1, {3}}, {HRSTORE_UNITS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrstore, 1, {4}}, {HRSTORE_SIZE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrstore, 1, {5}}, {HRSTORE_USED, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrstore, 1, {6}}, {HRSTORE_FAILS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, var_hrstore, 1, {7}} }; oid hrstore_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 2 }; oid hrMemorySize_oid[] = { 1, 3, 6, 1, 2, 1, 25, 2, 2 }; oid hrStorageTable_oid[] = { 1, 3, 6, 1, 2, 1, 25, 2, 3, 1 }; void init_hrh_storage(void) { char *appname; netsnmp_register_scalar( netsnmp_create_handler_registration("host/hrMemorySize", handle_memsize, hrMemorySize_oid, OID_LENGTH(hrMemorySize_oid), HANDLER_CAN_RONLY)); REGISTER_MIB("host/hr_storage", hrstore_variables, variable2, hrStorageTable_oid); appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE); netsnmp_ds_register_config(ASN_BOOLEAN, appname, "skipNFSInHostResources", NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES); netsnmp_ds_register_config(ASN_BOOLEAN, appname, "realStorageUnits", NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_REALSTORAGEUNITS); snmpd_register_config_handler("storageUseNFS", parse_storage_config, NULL, "1 | 2\t\t(1 = enable, 2 = disable)"); } static int storageUseNFS = 1; /* Default to reporting NFS mounts as NetworkDisk */ static void parse_storage_config(const char *token, char *cptr) { char *val; int ival; char *st; val = strtok_r(cptr, " \t", &st); if (!val) { config_perror("Missing FLAG parameter in storageUseNFS"); return; } ival = atoi(val); if (ival < 1 || ival > 2) { config_perror("storageUseNFS must be 1 or 2"); return; } storageUseNFS = (ival == 1) ? 1 : 0; } /* * header_hrstoreEntry(... * Arguments: * vp IN - pointer to variable entry that points here * name IN/OUT - IN/name requested, OUT/name found * length IN/OUT - length of IN/OUT oid's * exact IN - TRUE if an exact match was requested * var_len OUT - length of variable or 0 if function returned * write_method * */ void * header_hrstoreEntry(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #define HRSTORE_ENTRY_NAME_LENGTH 11 oid newname[MAX_OID_LEN]; int storage_idx, LowIndex = -1; int result; int idx = -1; netsnmp_memory_info *mem = NULL; DEBUGMSGTL(("host/hr_storage", "var_hrstoreEntry: request ")); DEBUGMSGOID(("host/hr_storage", name, *length)); DEBUGMSG(("host/hr_storage", " exact=%d\n", exact)); memcpy((char *) newname, (char *) vp->name, (int) vp->namelen * sizeof(oid)); result = snmp_oid_compare(name, *length, vp->name, vp->namelen); DEBUGMSGTL(("host/hr_storage", "var_hrstoreEntry: compare ")); DEBUGMSGOID(("host/hr_storage", vp->name, vp->namelen)); DEBUGMSG(("host/hr_storage", " => %d\n", result)); if (result < 0 || *length <= HRSTORE_ENTRY_NAME_LENGTH ) { /* * Requested OID too early or too short to refer * to a valid row (for the current column object). * GET requests should fail, GETNEXT requests * should use the first row. */ if ( exact ) return NULL; netsnmp_memory_load(); mem = netsnmp_memory_get_first( 0 ); } else { /* * Otherwise, retrieve the requested * (or following) row as appropriate. */ if ( exact && *length > HRSTORE_ENTRY_NAME_LENGTH+1 ) return NULL; /* Too long for a valid instance */ idx = name[ HRSTORE_ENTRY_NAME_LENGTH ]; if ( idx < NETSNMP_MEM_TYPE_MAX ) { netsnmp_memory_load(); mem = ( exact ? netsnmp_memory_get_byIdx( idx, 0 ) : netsnmp_memory_get_next_byIdx( idx, 0 )); } } /* * If this matched a memory-based entry, then * update the OID parameter(s) for GETNEXT requests. */ if ( mem ) { if ( !exact ) { newname[ HRSTORE_ENTRY_NAME_LENGTH ] = mem->idx; memcpy((char *) name, (char *) newname, ((int) vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; } } /* * If this didn't match a memory-based entry, * then consider the disk-based storage. */ else { Init_HR_Store(); for (;;) { storage_idx = Get_Next_HR_Store(); DEBUGMSG(("host/hr_storage", "(index %d ....", storage_idx)); if (storage_idx == -1) break; newname[HRSTORE_ENTRY_NAME_LENGTH] = storage_idx; DEBUGMSGOID(("host/hr_storage", newname, *length)); DEBUGMSG(("host/hr_storage", "\n")); result = snmp_oid_compare(name, *length, newname, vp->namelen + 1); if (exact && (result == 0)) { LowIndex = storage_idx; /* * Save storage status information */ break; } if ((!exact && (result < 0)) && (LowIndex == -1 || storage_idx < LowIndex)) { LowIndex = storage_idx; /* * Save storage status information */ #ifdef HRSTORE_MONOTONICALLY_INCREASING break; #endif } } if ( LowIndex != -1 ) { if ( !exact ) { newname[ HRSTORE_ENTRY_NAME_LENGTH ] = LowIndex; memcpy((char *) name, (char *) newname, ((int) vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; } mem = (netsnmp_memory_info*)0xffffffff; /* To indicate 'success' */ } } *write_method = (WriteMethod*)0; *var_len = sizeof(long); /* default to 'long' results */ /* * ... and return the appropriate row */ DEBUGMSGTL(("host/hr_storage", "var_hrstoreEntry: process ")); DEBUGMSGOID(("host/hr_storage", name, *length)); DEBUGMSG(("host/hr_storage", " (%p)\n", mem)); return (void*)mem; } oid storage_type_id[] = { 1, 3, 6, 1, 2, 1, 25, 2, 1, 1 }; /* hrStorageOther */ int storage_type_len = sizeof(storage_type_id) / sizeof(storage_type_id[0]); /********************* * * System specific implementation functions * *********************/ int handle_memsize(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_memory_info *mem_info; int val; /* * We just need to handle valid GET requests, as invalid instances * are rejected automatically, and (valid) GETNEXT requests are * converted into the appropriate GET request. * * We also only ever receive one request at a time. */ switch (reqinfo->mode) { case MODE_GET: netsnmp_memory_load(); mem_info = netsnmp_memory_get_byIdx( NETSNMP_MEM_TYPE_PHYSMEM, 0 ); if ( !mem_info || mem_info->size == -1 || mem_info->units == -1 ) netsnmp_set_request_error( reqinfo, requests, SNMP_NOSUCHOBJECT ); else { val = mem_info->size; /* memtotal */ val *= (mem_info->units/1024); snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *)&val, sizeof(val)); } return SNMP_ERR_NOERROR; default: /* * we should never get here, so this is a really bad error */ snmp_log(LOG_ERR, "unknown mode (%d) in handle_memsize\n", reqinfo->mode); return SNMP_ERR_GENERR; } return SNMP_ERR_NOERROR; } u_char * var_hrstore(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int store_idx = 0; static char string[1024]; void *ptr; netsnmp_memory_info *mem = NULL; really_try_next: ptr = header_hrstoreEntry(vp, name, length, exact, var_len, write_method); if (ptr == NULL) return NULL; store_idx = name[ HRSTORE_ENTRY_NAME_LENGTH ]; if (HRFS_entry && store_idx > NETSNMP_MEM_TYPE_MAX && ((netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES) && Check_HR_FileSys_NFS()) || Check_HR_FileSys_AutoFs())) return NULL; if (store_idx <= NETSNMP_MEM_TYPE_MAX ) { mem = (netsnmp_memory_info*)ptr; } switch (vp->magic) { case HRSTORE_INDEX: long_return = store_idx; return (u_char *) & long_return; case HRSTORE_TYPE: if (store_idx > NETSNMP_MEM_TYPE_MAX) if (HRFS_entry->flags & NETSNMP_FS_FLAG_REMOTE && storageUseNFS) storage_type_id[storage_type_len - 1] = 10; /* Network Disk */ else if (HRFS_entry->flags & NETSNMP_FS_FLAG_REMOVE ) storage_type_id[storage_type_len - 1] = 5; /* Removable Disk */ else storage_type_id[storage_type_len - 1] = 4; /* Assume fixed */ else switch (store_idx) { case NETSNMP_MEM_TYPE_PHYSMEM: case NETSNMP_MEM_TYPE_USERMEM: storage_type_id[storage_type_len - 1] = 2; /* RAM */ break; case NETSNMP_MEM_TYPE_VIRTMEM: case NETSNMP_MEM_TYPE_SWAP: storage_type_id[storage_type_len - 1] = 3; /* Virtual Mem */ break; default: storage_type_id[storage_type_len - 1] = 1; /* Other */ break; } *var_len = sizeof(storage_type_id); return (u_char *) storage_type_id; case HRSTORE_DESCR: if (store_idx > NETSNMP_MEM_TYPE_MAX) { strlcpy(string, HRFS_entry->path, sizeof(string)); *var_len = strlen(string); return (u_char *) string; } else { if ( !mem || !mem->descr ) goto try_next; *var_len = strlen(mem->descr); return (u_char *) mem->descr; } case HRSTORE_UNITS: if (store_idx > NETSNMP_MEM_TYPE_MAX) { if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_REALSTORAGEUNITS)) long_return = HRFS_entry->units & 0x7fffffff; else long_return = HRFS_entry->units_32; } else { if ( !mem || mem->units == -1 ) goto try_next; long_return = mem->units & 0x7fffffff; } return (u_char *) & long_return; case HRSTORE_SIZE: if (store_idx > NETSNMP_MEM_TYPE_MAX) { if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_REALSTORAGEUNITS)) long_return = HRFS_entry->size & 0x7fffffff; else long_return = HRFS_entry->size_32; } else { if ( !mem || mem->size == -1 ) goto try_next; long_return = mem->size & 0x7fffffff; } return (u_char *) & long_return; case HRSTORE_USED: if (store_idx > NETSNMP_MEM_TYPE_MAX) { if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_REALSTORAGEUNITS)) long_return = HRFS_entry->used & 0x7fffffff; else long_return = HRFS_entry->used_32; } else { if ( !mem || mem->size == -1 || mem->free == -1 ) goto try_next; long_return = (mem->size - mem->free) & 0x7fffffff; } return (u_char *) & long_return; case HRSTORE_FAILS: if (store_idx > NETSNMP_MEM_TYPE_MAX) #if NETSNMP_NO_DUMMY_VALUES goto try_next; #else long_return = 0; #endif else { if ( !mem || mem->other == -1 ) goto try_next; long_return = mem->other; } return (u_char *) & long_return; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrstore\n", vp->magic)); } return NULL; try_next: if (!exact) goto really_try_next; return NULL; } /********************* * * Internal implementation functions * *********************/ static int HRS_index; void Init_HR_Store(void) { HRS_index = 0; Init_HR_FileSys(); } int Get_Next_HR_Store(void) { /* * File-based storage */ for (;;) { HRS_index = Get_Next_HR_FileSys(); if (HRS_index >= 0) { if (!(netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_SKIPNFSINHOSTRESOURCES) && Check_HR_FileSys_NFS()) && !Check_HR_FileSys_AutoFs()) { return HRS_index + NETSNMP_MEM_TYPE_MAX; } } else { return -1; } } }