Bug 33070

Summary: libdisk::Disk_Names() returns empty strings
Product: Base System Reporter: AnarCat <AnarCat>
Component: binAssignee: Poul-Henning Kamp <phk>
Status: Closed FIXED    
Severity: Affects Only Me CC: AnarCat
Priority: Normal    
Version: 4.4-STABLE   
Hardware: Any   
OS: Any   

Description AnarCat 2001-12-21 22:10:01 UTC
Some recent MFC broke Disk_Names() on -stable:

revision 1.50.2.13.2.1
date: 2001/09/18 15:16:21;  author: murray;  state: Exp;  lines: +2 -2
MFS: Don't use kern.disks sysctl.

     Makefile (rev 1.27.2.5)
     disk.c (rev 1.50.2.14)

The diff is:

ndex: disk.c
===================================================================
RCS file: /home/ncvs/src/lib/libdisk/disk.c,v
retrieving revision 1.50.2.13
retrieving revision 1.50.2.13.2.1
diff -u -r1.50.2.13 -r1.50.2.13.2.1
--- disk.c      28 Aug 2001 03:45:47 -0000      1.50.2.13
+++ disk.c      18 Sep 2001 15:16:21 -0000      1.50.2.13.2.1
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.
  * Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- * $FreeBSD: src/lib/libdisk/disk.c,v 1.50.2.13 2001/08/28 03:45:47
  nyan Exp $
+ * $FreeBSD: src/lib/libdisk/disk.c,v 1.50.2.13.2.1 2001/09/18 15:16:21
murray Exp $
  *
  */
 
@@ -499,7 +499,7 @@
 
     disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
     memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
-#ifndef PC98
+#if !defined(PC98) && !defined(KERN_DISKS_BROKEN)
     error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
     if (!error) {
            disklist = (char *)malloc(listsize);

I do not understand why, but Disk_Names() returns a pointer to a list of
NULL strings. This is weird. 

It definitly breaks libh's libdisk.

Fix: 

Back out the change.
How-To-Repeat: 
#include <iostream>
extern "C" {
#include <sys/types.h>
#include <libdisk.h>
}

int main() {

	char** names = ::Disk_Names();
	cerr << "n: " << names << endl;
	for (char **n = names; *n != NULL; n++) {
		cerr << "disk" << *n << endl;
	}
	
	return 1;

}

Simply returns with "n: 0x..."

gdb also gives us the same sad stuff.
Comment 1 AnarCat 2001-12-23 01:02:03 UTC
This is because of a commit to libdisk which disables the use of
kern.disks because it doesn't sort its output.

The alternate method of getting the disk list is to stat devices and try
to open them which fails if you're a regular user.

Here is a proper fix that sort the output of kern.disks in Disk_Names()
instead.

Index: Makefile
===================================================================
RCS file: /home/ncvs/src/lib/libdisk/Makefile,v
retrieving revision 1.27.2.5
diff -u -r1.27.2.5 Makefile
--- Makefile	18 Sep 2001 06:47:30 -0000	1.27.2.5
+++ Makefile	22 Dec 2001 23:58:22 -0000
@@ -6,7 +6,7 @@
 INCS=	libdisk.h
 
-# Remove KERN_DISKS_BROKEN when kern.disks sysctl returns disks in sorted order
-CFLAGS+= 	-Wall -DKERN_DISKS_BROKEN
+CFLAGS+= 	-Wall
 .if ${MACHINE} == "pc98"
 CFLAGS+=	-DPC98
 .endif
Index: disk.c
===================================================================
RCS file: /home/ncvs/src/lib/libdisk/disk.c,v
retrieving revision 1.50.2.14
diff -u -r1.50.2.14 disk.c
--- disk.c	18 Sep 2001 06:47:30 -0000	1.50.2.14
+++ disk.c	23 Dec 2001 00:43:01 -0000
@@ -483,10 +483,18 @@
 static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
 #endif
 
+int qstrcmp(const void* a, const void* b) {
+
+	char *str1 = *(char**)a;
+	char *str2 = *(char**)b;
+	return strcmp(str1, str2);
+
+}
+
 char **
 Disk_Names()
 {
-    int i,j,k;
+    int i,j,disk_cnt;
     char disk[25];
     char diskname[25];
     struct stat st;
@@ -506,14 +514,16 @@
 	    error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
 	    if (error) 
 		    return NULL;
-	    k = 0;
-	    for (dp = disks; ((*dp = strsep(&disklist, " ")) != NULL) && k < MAX_NO_DISKS; k++, dp++);
-	    return disks;
-    }
+	    disk_cnt = 0;
+	    for (dp = disks; ((*dp = strsep(&disklist, " ")) != NULL) && 
+			 disk_cnt < MAX_NO_DISKS; disk_cnt++, dp++);
+    } else {
     warn("kern.disks sysctl not available");
 #endif
-    k = 0;
+    disk_cnt = 0;
 	for (j = 0; device_list[j]; j++) {
+		if(disk_cnt >= MAX_NO_DISKS)
+			break;
 		for (i = 0; i < MAX_NO_DISKS; i++) {
 			sprintf(diskname, "%s%d", device_list[j], i);
 			sprintf(disk, _PATH_DEV"%s", diskname);
@@ -529,12 +539,17 @@
 				continue;
 			}
 			close(fd);
-			disks[k++] = strdup(diskname);
-			if(k == MAX_NO_DISKS)
-				return disks;
+			disks[disk_cnt++] = strdup(diskname);
+			if(disk_cnt >= MAX_NO_DISKS)
+				break;
 		}
 	}
-	return disks;
+#if !defined(PC98) && !defined(KERN_DISKS_BROKEN)
+    }
+#endif
+    qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
+    
+    return disks;
 }
 
 #ifdef PC98
Comment 2 AnarCat 2001-12-23 22:08:48 UTC
Note that this behaviors shows up only as non-root users since the
problem is that the:

if ((fd = open(disk, O_RDWR)) == -1)

fails... 

Also note that the above patch is for -stable only. I'm not sure current
suffers from these problems.

a.
Comment 3 Sheldon Hearn freebsd_committer freebsd_triage 2002-01-08 16:41:16 UTC
State Changed
From-To: open->closed

Committed and merged onto the RELENG_4 branch in time for 
4.5-RELEASE, thanks! 


Comment 4 Sheldon Hearn freebsd_committer freebsd_triage 2002-01-08 16:41:16 UTC
Responsible Changed
From-To: freebsd-bugs->phk

Poul-Henning committed the patch.,