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;

Reply via email to