Subject: bin/34152: envstat(8) can't find some sensors when there is a hole in sensor numbers
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <bsh@netbsd.org>
List: netbsd-bugs
Date: 08/07/2006 07:15:01
>Number:         34152
>Category:       bin
>Synopsis:       envstat(8) can't find some sensors when there is a `hole' in sensor numbers
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Aug 07 07:15:00 +0000 2006
>Originator:     Hiroyuki Bessho
>Release:        NetBSD 3.99.24
>Organization:

>Environment:
	
	
System: NetBSD nekozame.a.grotto.jp 3.99.24 NetBSD 3.99.24 (TSUYUBERA) #11: Sat Aug 5 16:42:19 JST 2006 bsh@nekozame.a.grotto.jp:/u1/proj/netbsd/tnf/current/src/sys/arch/i386/compile/obj.i386/TSUYUBERA i386
Architecture: i386
Machine: i386
>Description:
	envsys assigns a number to each sensor.  envstat(8) assumes
these sensor numbers are continuous beginning from 0.  If the lowest
sensor number is not 0, or there is a hole in assigned sensor numbers,
envstat will fail to find some sensors.

	It can happen when a driver for the sensors is an LKM, and the
driver is unloaded.
>How-To-Repeat:
	Load LKM for envsys sensors, and unload it. run envstat.

	If you don't have such LKM (I know you don't :-), try
following patch to lm driver.

Index: nslm7x.c
===================================================================
RCS file: /remote/kamasu/u0/cvsupbase/cvsroot-netbsd/src/sys/dev/ic/nslm7x.c,v
retrieving revision 1.27
diff -u -u -r1.27 nslm7x.c
--- nslm7x.c	8 Jun 2006 10:56:49 -0000	1.27
+++ nslm7x.c	7 Aug 2006 06:46:27 -0000
@@ -218,6 +218,10 @@
 	if (sysmon_envsys_register(&lmsc->sc_sysmon))
 		printf("%s: unable to register with sysmon\n",
 		    lmsc->sc_dev.dv_xname);
+
+	/* Make a hole in register numbers for test. */
+	sysmon_envsys_unregister(&lmsc->sc_sysmon);
+	sysmon_envsys_register(&lmsc->sc_sysmon);
 }
 
 int

	
>Fix:
Index: envstat.c
===================================================================
RCS file: /remote/kamasu/u0/cvsupbase/cvsroot-netbsd/src/usr.sbin/envstat/envstat.c,v
retrieving revision 1.22
diff -u -u -r1.22 envstat.c
--- envstat.c	3 Jun 2004 16:48:53 -0000	1.22
+++ envstat.c	7 Aug 2006 06:57:11 -0000
@@ -55,8 +55,8 @@
 
 int main(int, char **);
 void listsensors(envsys_basic_info_t *, size_t);
-size_t numsensors(int);
-void fillsensors(int, envsys_tre_data_t *, envsys_basic_info_t *, size_t);
+void getrange(int, envsys_range_t *);
+int fillsensors(int, envsys_tre_data_t *, envsys_basic_info_t *, int, int);
 size_t longestname(envsys_basic_info_t *, size_t);
 int marksensors(envsys_basic_info_t *, int *, char *, size_t);
 int strtosnum(envsys_basic_info_t *, const char *, size_t);
@@ -79,6 +79,7 @@
 	int *cetds;
 	char *sensors;
 	const char *dev;
+	struct envsys_range rng;
 
 	fd = -1;
 	ls = 0;
@@ -133,9 +134,11 @@
 	 * Determine number of sensors, allocate and fill arrays with
 	 * initial information.  Determine column width
 	 */
-	if ((ns = numsensors(fd)) == 0)
+	getrange(fd, &rng);
+	if (rng.low > rng.high)
 		errx(1, "No sensors found");
 
+	ns = rng.high - rng.low + 1;
 	cetds = (int *)malloc(ns * sizeof(int));
 	etds = (envsys_tre_data_t *)malloc(ns * sizeof(envsys_tre_data_t));
 	ebis = (envsys_basic_info_t *)malloc(ns * sizeof(envsys_basic_info_t));
@@ -143,7 +146,8 @@
 	if ((cetds == NULL) || (etds == NULL) || (ebis == NULL))
 		err(1, "Out of memory");
 
-	fillsensors(fd, etds, ebis, ns);
+	if (fillsensors(fd, etds, ebis, rng.low, rng.high) <= 0)
+		errx(1, "No sensors found");
 
 	if (ls) {
 		listsensors(ebis, ns);
@@ -170,7 +174,7 @@
 		while (1) {
 			printrow(cetds, etds, ebis, ns, celsius, width);
 			sleep(interval);
-			fillsensors(fd, etds, ebis, ns);
+			fillsensors(fd, etds, ebis, rng.low, rng.high);
 			printf("\n");
 		}
 	}
@@ -199,7 +203,7 @@
 
 		sleep(interval);
 
-		fillsensors(fd, etds, ebis, ns);
+		fillsensors(fd, etds, ebis, rng.low, rng.high);
 	}
 
 	/* NOTREACHED */
@@ -373,52 +377,61 @@
 
 /*
  * pre:  fd contains a valid file descriptor of an envsys(4) supporting device
- * post: returns the number of valid sensors provided by the device
- *       or -1 on error
+ * post: returns the lowest and highest number of sensors
  */
-size_t
-numsensors(int fd)
+void
+getrange(int fd, struct envsys_range *rng)
 {
-	int count = 0, valid = 1;
+	int i;
 	envsys_tre_data_t etd;
-	etd.sensor = 0;
 
-	while (valid) {
+	rng->units = -1;			/* All type of sensors */
+	if (ioctl(fd, ENVSYS_GRANGE, rng))
+		err(1, "ioctl(ENVSYS_GRANGE) failed");
+	if (rng->low > rng->high)
+		return;
+
+	for (i=rng->low; i <= rng->high; ++i) {
+		etd.sensor = i;
 		if (ioctl(fd, ENVSYS_GTREDATA, &etd) == -1)
 			err(1, "Can't get sensor data");
 
-		valid = etd.validflags & ENVSYS_FVALID;
-		if (valid)
-			++count;
-
-		++etd.sensor;
+		if (etd.validflags & ENVSYS_FVALID)
+			break;
+		else if (i == rng->low)
+			rng->low++;
 	}
-
-	return count;
 }
 
 /*
  * pre:  fd contains a valid file descriptor of an envsys(4) supporting device
  *       && ns is the number of sensors
  *       && etds and ebis are arrays of sufficient size
- * post: returns 0 and etds and ebis arrays are filled with sensor info
- *       or returns -1 on failure
+ * post: return number of valid sensors.
  */
-void
+int
 fillsensors(int fd, envsys_tre_data_t *etds, envsys_basic_info_t *ebis,
-    size_t ns)
+    int low, int high)
 {
-	int i;
+	int i, n;
+	int count = 0;
 
-	for (i = 0; i < ns; ++i) {
-		ebis[i].sensor = i;
+	for (i=0, n = low; n <= high; ++i, ++n) {
+		ebis[i].sensor = n;
 		if (ioctl(fd, ENVSYS_GTREINFO, &ebis[i]) == -1)
 			err(1, "Can't get sensor info for sensor %d", i);
 
-		etds[i].sensor = i;
+		etds[i].sensor = n;
 		if (ioctl(fd, ENVSYS_GTREDATA, &etds[i]) == -1)
 			err(1, "Can't get sensor data for sensor %d", i);
+
+		if ((ebis[i].validflags & ENVSYS_FVALID) &&
+		    (etds[i].validflags & ENVSYS_FVALID))
+			++count;
+
 	}
+
+	return count;
 }
 
 
@@ -450,6 +463,7 @@
 {
 	size_t i;
 	char *s;
+	int found=0;
 
 	if (sensors == NULL) {
 		/* No sensors specified, include them all */
@@ -465,8 +479,10 @@
 	s = strtok(sensors, ",");
 	while (s != NULL) {
 		int snum;
-		if ((snum = strtosnum(ebis, s, ns)) != -1)
+		if ((snum = strtosnum(ebis, s, ns)) != -1) {
 			cetds[snum] = 1;
+			found=1;
+		}
 		else {
 			warnx("Unknown sensor %s", s);
 			return (-1);
@@ -476,9 +492,8 @@
 	}
 
 	/* Check if we have at least one sensor selected for output */
-	for (i = 0; i < ns; ++i)
-		if (cetds[i] == 1)
-			return (0);
+	if (found)
+		return (0);
 
 	warnx("No sensors selected for display");
 	return (-1);
@@ -497,7 +512,7 @@
 	for (i = 0; i < ns; ++i) {
 		if((ebis[i].validflags & ENVSYS_FVALID) &&
 		   !strcmp(s, ebis[i].desc))
-			return ebis[i].sensor;
+			return i;
 	}
 
 	return -1;

>Unformatted: