diff options
Diffstat (limited to 'agent/mibgroup/ucd-snmp/disk_hw.c')
-rw-r--r-- | agent/mibgroup/ucd-snmp/disk_hw.c | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/agent/mibgroup/ucd-snmp/disk_hw.c b/agent/mibgroup/ucd-snmp/disk_hw.c new file mode 100644 index 0000000..93ecde3 --- /dev/null +++ b/agent/mibgroup/ucd-snmp/disk_hw.c @@ -0,0 +1,421 @@ +/* + * disk_hw.c + */ + +#include <net-snmp/net-snmp-config.h> + + +#include <stdio.h> + +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <signal.h> +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> +#include <net-snmp/agent/hardware/fsys.h> + +#include "struct.h" +#include "disk.h" +#include "util_funcs/header_simple_table.h" +#if USING_UCD_SNMP_ERRORMIB_MODULE +#include "errormib.h" +#else +#define setPerrorstatus(x) snmp_log_perror(x) +#endif + +/* + * * config file parsing routines + * */ +static void disk_free_config(void); +static void disk_parse_config(const char *, char *); +static void disk_parse_config_all(const char *, char *); + +static netsnmp_fsys_info ** _expand_disk_array( char *cptr ); + +#define MAX_INT_32 0x7fffffff +#define MAX_UINT_32 0xffffffff + +int numdisks; +int allDisksIncluded = 0; +int maxdisks = 0; +netsnmp_fsys_info **disks = NULL; + +struct variable2 extensible_disk_variables[] = { + {MIBINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {MIBINDEX}}, + {ERRORNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {ERRORNAME}}, + {DISKDEVICE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKDEVICE}}, + {DISKMINIMUM, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKMINIMUM}}, + {DISKMINPERCENT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKMINPERCENT}}, + {DISKTOTAL, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKTOTAL}}, + {DISKAVAIL, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKAVAIL}}, + {DISKUSED, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKUSED}}, + {DISKPERCENT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKPERCENT}}, + {DISKPERCENTNODE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKPERCENTNODE}}, + {ERRORFLAG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {ERRORFLAG}}, + {ERRORMSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {ERRORMSG}}, + {DISKTOTALLOW, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKTOTALLOW}}, + {DISKTOTALHIGH, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKTOTALHIGH}}, + {DISKAVAILLOW, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKAVAILLOW}}, + {DISKAVAILHIGH, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKAVAILHIGH}}, + {DISKUSEDLOW, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKUSEDLOW}}, + {DISKUSEDHIGH, ASN_UNSIGNED, NETSNMP_OLDAPI_RONLY, + var_extensible_disk, 1, {DISKUSEDHIGH}}, +}; + +/* + * Define the OID pointer to the top of the mib tree that we're + * registering underneath + */ +oid disk_variables_oid[] = { NETSNMP_UCDAVIS_MIB, NETSNMP_DISKMIBNUM, 1 }; + +void +init_disk_hw(void) +{ + /* + * register ourselves with the agent to handle our mib tree + */ + REGISTER_MIB("ucd-snmp/disk", extensible_disk_variables, variable2, + disk_variables_oid); + + snmpd_register_config_handler("disk", disk_parse_config, + disk_free_config, + "path [ minspace | minpercent% ]"); + snmpd_register_config_handler("includeAllDisks", disk_parse_config_all, + disk_free_config, + "minpercent%"); + allDisksIncluded = 0; +} + +static void +disk_free_config(void) +{ + netsnmp_fsys_info *entry; + + for ( entry = netsnmp_fsys_get_first(); + entry != NULL; + entry = netsnmp_fsys_get_next( entry )) { + + entry->minspace = -1; + entry->minpercent = -1; + entry->flags &= ~NETSNMP_FS_FLAG_UCD; + } + if (disks) { + free( disks ); + disks = NULL; + maxdisks = numdisks = 0; + } + allDisksIncluded = 0; +} + +static void +disk_parse_config(const char *token, char *cptr) +{ + char path[STRMAX]; + int minpercent; + int minspace; + netsnmp_fsys_info *entry; + + /* + * Ensure there is space for the new entry + */ + if (numdisks == maxdisks) { + if (!_expand_disk_array( cptr )) + return; + } + + /* + * read disk path (eg, /1 or /usr) + */ + copy_nword(cptr, path, sizeof(path)); + cptr = skip_not_white(cptr); + cptr = skip_white(cptr); + + /* + * read optional minimum disk usage spec + */ + if(cptr != NULL) { + if(strchr(cptr, '%') == NULL) { + minspace = atoi(cptr); + minpercent = -1; + } + else { + minspace = -1; + minpercent = atoi(cptr); + } + } else { + minspace = NETSNMP_DEFDISKMINIMUMSPACE; + minpercent = -1; + } + + /* + * check if the disk already exists, if so then modify its + * parameters. if it does not exist then add it + */ + entry = netsnmp_fsys_by_path( path, NETSNMP_FS_FIND_CREATE ); + if ( entry ) { + entry->minspace = minspace; + entry->minpercent = minpercent; + entry->flags |= NETSNMP_FS_FLAG_UCD; + disks[numdisks++] = entry; + } +} + +static void +disk_parse_config_all(const char *token, char *cptr) +{ + int minpercent = DISKMINPERCENT; + netsnmp_fsys_info *entry; + + /* + * read the minimum disk usage percent + */ + if(cptr != NULL) { + if(strchr(cptr, '%') != NULL) { + minpercent = atoi(cptr); + } + } + /* + * if we have already seen the "includeAllDisks" directive + * then search for the disk in the "disks" array and modify + * the values. if we havent seen the "includeAllDisks" + * directive then include this disk + */ + if(allDisksIncluded) { + config_perror("includeAllDisks already specified."); + netsnmp_config_error("\tignoring: includeAllDisks %s", cptr); + } + else { + + netsnmp_fsys_load( NULL, NULL ); /* Prime the fsys H/W module */ + for ( entry = netsnmp_fsys_get_first(); + entry != NULL; + entry = netsnmp_fsys_get_next( entry )) { + + if ( !(entry->flags & NETSNMP_FS_FLAG_ACTIVE )) + continue; + entry->minspace = -1; + entry->minpercent = minpercent; + entry->flags |= NETSNMP_FS_FLAG_UCD; + /* + * Ensure there is space for the new entry + */ + if (numdisks == maxdisks) { + if (!_expand_disk_array( entry->device )) + return; + } + disks[numdisks++] = entry; + } + allDisksIncluded = 1; + } +} + + +static int _percent( unsigned long long value, unsigned long long total ) { + float v=value, t=total, pct; + + /* avoid division by zero */ + if (total == 0) + return 0; + + pct = (v*100)/t; /* Calculate percentage using floating point + arithmetic, to avoid overflow errors */ + pct += 0.5; /* rounding */ + return (int)pct; +} + +static netsnmp_fsys_info ** +_expand_disk_array( char *cptr ) { + + if ( maxdisks == 0 ) + maxdisks = 50; + else + maxdisks *= 2; + + disks = realloc( disks, maxdisks * sizeof( netsnmp_fsys_info*)); + if (!disks) { + config_perror("malloc failed for new disk allocation."); + netsnmp_config_error("\tignoring: %s", cptr); + return NULL; + } + + if ( maxdisks == 50 ) + memset(disks, 0, maxdisks * sizeof( netsnmp_fsys_info*)); + else + memset(disks + maxdisks/2, 0, maxdisks/2 * sizeof( netsnmp_fsys_info*)); + + return disks; +} + + +/* + * var_extensible_disk(... + * 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 + * + */ +u_char * +var_extensible_disk(struct variable *vp, + oid * name, + size_t * length, + int exact, + size_t * var_len, WriteMethod ** write_method) +{ + int disknum = 0; + netsnmp_fsys_info *entry; + unsigned long long val; + static long long_ret; + static char errmsg[300]; + + netsnmp_fsys_load( NULL, NULL ); /* Update the fsys H/W module */ + +tryAgain: + if (header_simple_table + (vp, name, length, exact, var_len, write_method, numdisks)) + return (NULL); + disknum = name[*length - 1] - 1; + entry = disks[disknum]; + if ( !entry ) { + if (!exact || !(entry->flags & NETSNMP_FS_FLAG_UCD)) + goto tryAgain; + return NULL; + } + + switch (vp->magic) { + case MIBINDEX: + long_ret = disknum + 1; + return ((u_char *) (&long_ret)); + case ERRORNAME: /* DISKPATH */ + *var_len = strlen(entry->path); + return ((u_char *)entry->path); + case DISKDEVICE: + *var_len = strlen(entry->device); + return ((u_char *)entry->device); + case DISKMINIMUM: + long_ret = entry->minspace; + return ((u_char *) (&long_ret)); + case DISKMINPERCENT: + long_ret = entry->minpercent; + return ((u_char *) (&long_ret)); + + case DISKTOTAL: + val = netsnmp_fsys_size_ull(entry); + if (val > MAX_INT_32) + long_ret = MAX_INT_32; + else + long_ret = (long)val; + return ((u_char *) (&long_ret)); + case DISKTOTALLOW: + long_ret = netsnmp_fsys_size_ull(entry) & MAX_UINT_32; + return ((u_char *) (&long_ret)); + case DISKTOTALHIGH: + long_ret = netsnmp_fsys_size_ull(entry) >> 32; + return ((u_char *) (&long_ret)); + + case DISKAVAIL: + val = netsnmp_fsys_avail_ull(entry); + if (val > MAX_INT_32) + long_ret = MAX_INT_32; + else + long_ret = (long)val; + return ((u_char *) (&long_ret)); + case DISKAVAILLOW: + long_ret = netsnmp_fsys_avail_ull(entry) & MAX_UINT_32; + return ((u_char *) (&long_ret)); + case DISKAVAILHIGH: + long_ret = netsnmp_fsys_avail_ull(entry) >> 32; + return ((u_char *) (&long_ret)); + + case DISKUSED: + val = netsnmp_fsys_used_ull(entry); + if (val > MAX_INT_32) + long_ret = MAX_INT_32; + else + long_ret = (long)val; + return ((u_char *) (&long_ret)); + case DISKUSEDLOW: + long_ret = netsnmp_fsys_used_ull(entry) & MAX_UINT_32; + return ((u_char *) (&long_ret)); + case DISKUSEDHIGH: + long_ret = netsnmp_fsys_used_ull(entry) >> 32; + return ((u_char *) (&long_ret)); + + case DISKPERCENT: + long_ret = _percent( entry->used, entry->size ); + return ((u_char *) (&long_ret)); + + case DISKPERCENTNODE: + long_ret = _percent( entry->inums_total - entry->inums_avail, entry->inums_total ); + return ((u_char *) (&long_ret)); + + case ERRORFLAG: + long_ret = 0; + val = netsnmp_fsys_avail_ull(entry); + if (( entry->minspace >= 0 ) && + ( val < entry->minspace )) + long_ret = 1; + else if (( entry->minpercent >= 0 ) && + (_percent( entry->avail, entry->size ) < entry->minpercent )) + long_ret = 1; + return ((u_char *) (&long_ret)); + + case ERRORMSG: + errmsg[0] = 0; + val = netsnmp_fsys_avail_ull(entry); + if (( entry->minspace >= 0 ) && + ( val < entry->minspace )) + snprintf(errmsg, sizeof(errmsg), + "%s: less than %d free (= %d)", + entry->path, entry->minspace, + (int) val); + else if (( entry->minpercent >= 0 ) && + (_percent( entry->avail, entry->size ) < entry->minpercent )) + snprintf(errmsg, sizeof(errmsg), + "%s: less than %d%% free (= %d%%)", + entry->path, entry->minpercent, + _percent( entry->avail, entry->size )); + errmsg[ sizeof(errmsg)-1 ] = 0; + *var_len = strlen(errmsg); + return ((u_char *) (errmsg)); + } + return NULL; +} |