Package: nut-snmp Version: 2.6.4-2.3 Severity: normal Tags: upstream patch Dear Maintainer,
After upgrading to Debian 7 I discovered that snmp-ups would no longer work with our HP UPSs that use the CPQPOWER-MIB. It would crash on start-up. A build from source of 2.6.5 had the same problem. A build from the nut svn trunk, however did not crash. I have managed to build a debian package that works by taking the nut-2.6.4 source package, taking the snmp-ups.c and snmp-ups.h files from trunk, removing the delta-ups and pulizzi references and building the package. I will attempt to attach the necessary patch to this bug report. Thanks, Philip Ward. -- System Information: Debian Release: 7.1 APT prefers stable APT policy: (500, 'stable') Architecture: amd64 (x86_64) Kernel: Linux 3.2.0-4-amd64 (SMP w/24 CPU cores) Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages nut-snmp depends on: ii libc6 2.13-38 ii libsnmp15 5.4.3~dfsg-2.7 ii nut 2.6.4-2.3 nut-snmp recommends no packages. nut-snmp suggests no packages. -- no debconf information -- The University of Stirling has been ranked in the top 12 of UK universities for graduate employment*. 94% of our 2012 graduates were in work and/or further study within six months of graduation. *The Telegraph The University of Stirling is a charity registered in Scotland, number SC 011159.
--- /root/snmp-ups.c 2013-08-29 15:13:21.901303987 +0100 +++ snmp-ups.c 2013-08-29 15:21:25.983297855 +0100 @@ -91,7 +91,7 @@ static void disable_transfer_oids(void); #define DRIVER_NAME "Generic SNMP UPS driver" -#define DRIVER_VERSION "0.66" +#define DRIVER_VERSION "0.69" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -122,13 +122,10 @@ void upsdrv_initinfo(void) { snmp_info_t *su_info_p; - char version[128]; upsdebugx(1, "SNMP UPS driver : entering upsdrv_initinfo()"); - snprintf(version, sizeof version, "%s (mib: %s %s)", - DRIVER_VERSION, mibname, mibvers); - dstate_setinfo("driver.version.internal", "%s", version); + dstate_setinfo("driver.version.data", "%s MIB %s", mibname, mibvers); /* add instant commands to the info database. * outlet commands are processed later, during initial walk */ @@ -955,7 +952,7 @@ info_lkp_t *info_lkp; for (info_lkp = oid2info; (info_lkp != NULL) && - (strcmp(info_lkp->info_value, "NULL")); info_lkp++) { + (strcmp(info_lkp->info_value, "NULL")) && (info_lkp->info_value != NULL); info_lkp++) { if (info_lkp->oid_value == value) { upsdebugx(1, "su_find_infoval: found %s (value: %ld)", @@ -1055,6 +1052,32 @@ return (outlet_index_base==0)?1:0; } +/* try to determine the number of outlets, using a template definition, + * that we walk, until we can't get anymore values */ +static int guestimate_outlet_count(const char *OID_template) +{ + int base_index = 0; + char test_OID[SU_INFOSIZE]; + int base_count; + + upsdebugx(1, "guestimate_outlet_count(%s)", OID_template); + + /* Determine if OID index starts from 0 or 1? */ + sprintf(test_OID, OID_template, base_index); + if (nut_snmp_get(test_OID) == NULL) + base_index++; + + /* Now, actually iterate */ + for (base_count = 0 ; ; base_count++) { + sprintf(test_OID, OID_template, base_index + base_count); + if (nut_snmp_get(test_OID) == NULL) + break; + } + + upsdebugx(3, "guestimate_outlet_count: %i", base_count); + return base_count; +} + /* process a single data from a walk */ bool_t get_and_process_data(int mode, snmp_info_t *su_info_p) { @@ -1236,55 +1259,71 @@ if(dstate_getinfo("outlet.count") == NULL) { /* FIXME: should we disable it? - * su_info_p->flags &= ~SU_FLAG_OK; */ - continue; + * su_info_p->flags &= ~SU_FLAG_OK; + * or rely on guestimation? */ + if ((outlet_count = guestimate_outlet_count(su_info_p->OID)) == -1) { + /* Failed */ + continue; + } + else { + /* Publish the count estimation */ + dstate_setinfo("outlet.count", "%i", outlet_count); + } + } + else { + outlet_count = atoi(dstate_getinfo("outlet.count")); } - outlet_count = atoi(dstate_getinfo("outlet.count")); - - /* general init of data using the template */ - instantiate_info(su_info_p, &cur_info_p); - - for (cur_outlet_number = base_snmp_outlet_index(su_info_p->OID) ; - cur_outlet_number < (outlet_count + base_snmp_outlet_index(su_info_p->OID)) ; - cur_outlet_number++) - { - cur_nut_index = cur_outlet_number + base_nut_outlet_offset(); - sprintf((char*)cur_info_p.info_type, su_info_p->info_type, - cur_nut_index); - /* check if default value is also a template */ - if ((cur_info_p.dfl != NULL) && - (strstr(su_info_p->dfl, "%i") != NULL)) { - cur_info_p.dfl = (char *)xmalloc(SU_INFOSIZE); - sprintf((char *)cur_info_p.dfl, su_info_p->dfl, cur_nut_index); - } + /* Only instantiate outlets if needed! */ + if (outlet_count > 0) { + /* general init of data using the template */ + instantiate_info(su_info_p, &cur_info_p); + + for (cur_outlet_number = base_snmp_outlet_index(su_info_p->OID) ; + cur_outlet_number < (outlet_count + base_snmp_outlet_index(su_info_p->OID)) ; + cur_outlet_number++) + { + cur_nut_index = cur_outlet_number + base_nut_outlet_offset(); + sprintf((char*)cur_info_p.info_type, su_info_p->info_type, + cur_nut_index); + + /* check if default value is also a template */ + if ((cur_info_p.dfl != NULL) && + (strstr(su_info_p->dfl, "%i") != NULL)) { + cur_info_p.dfl = (char *)xmalloc(SU_INFOSIZE); + sprintf((char *)cur_info_p.dfl, su_info_p->dfl, cur_nut_index); + } - if (cur_info_p.OID != NULL) { - sprintf((char *)cur_info_p.OID, su_info_p->OID, cur_outlet_number); + if (cur_info_p.OID != NULL) { + sprintf((char *)cur_info_p.OID, su_info_p->OID, cur_outlet_number); - /* add outlet instant commands to the info database. */ - if (SU_TYPE(su_info_p) == SU_TYPE_CMD) { - /* FIXME: only add if "su_ups_get(cur_info_p) == TRUE" */ - if (mode == SU_WALKMODE_INIT) - dstate_addcmd(cur_info_p.info_type); + /* add outlet instant commands to the info database. */ + if (SU_TYPE(su_info_p) == SU_TYPE_CMD) { + /* FIXME: only add if "su_ups_get(cur_info_p) == TRUE" */ + if (mode == SU_WALKMODE_INIT) + dstate_addcmd(cur_info_p.info_type); + } + else /* get and process this data */ + status = get_and_process_data(mode, &cur_info_p); + } else { + /* server side (ABSENT) data */ + su_setinfo(&cur_info_p, NULL); } - else /* get and process this data */ - status = get_and_process_data(mode, &cur_info_p); - } else { - /* server side (ABSENT) data */ - su_setinfo(&cur_info_p, NULL); + /* set back the flag */ + su_info_p->flags = cur_info_p.flags; } - /* set back the flag */ - su_info_p->flags = cur_info_p.flags; + free((char*)cur_info_p.info_type); + if (cur_info_p.OID != NULL) + free((char*)cur_info_p.OID); + if ((cur_info_p.dfl != NULL) && + (strstr(su_info_p->dfl, "%i") != NULL)) + free((char*)cur_info_p.dfl); } - free((char*)cur_info_p.info_type); - if (cur_info_p.OID != NULL) - free((char*)cur_info_p.OID); - if ((cur_info_p.dfl != NULL) && - (strstr(su_info_p->dfl, "%i") != NULL)) - free((char*)cur_info_p.dfl); - - } else { + else { + upsdebugx(1, "No outlet present, discarding template definition..."); + } + } + else { /* get and process this data */ status = get_and_process_data(mode, su_info_p); } @@ -1495,11 +1534,14 @@ snmp_info_t *su_info_p = NULL; int status; int retval = STAT_INSTCMD_FAILED; + int cmd_offset = 0; upsdebugx(2, "entering su_instcmd(%s, %s)", cmdname, extradata); - if (strncmp(cmdname, "outlet", 6)) + /* FIXME: this should only apply if strchr(%)! */ + if (strncmp(cmdname, "outlet", 6)) { su_info_p = su_find_info(cmdname); + } else { snmp_info_t *tmp_info_p; char *outlet_number_ptr = strchr(cmdname, '.'); @@ -1539,8 +1581,15 @@ } /* adapt the OID */ if (su_info_p->OID != NULL) { + /* Workaround buggy Eaton Pulizzi implementation + * which have different offsets index for data & commands! */ + if (su_info_p->flags & SU_CMD_OFFSET) { + upsdebugx(3, "Adding command offset"); + cmd_offset++; + } + sprintf((char *)su_info_p->OID, tmp_info_p->OID, - outlet_number - base_nut_outlet_offset()); + outlet_number - base_nut_outlet_offset() + cmd_offset); } else { free_info(su_info_p); return STAT_INSTCMD_UNKNOWN;