misc/161837: sysinstall has a 32 disk limit

Tim Brody tdb2 at ecs.soton.ac.uk
Thu Oct 20 16:20:05 UTC 2011


>Number:         161837
>Category:       misc
>Synopsis:       sysinstall has a 32 disk limit
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Oct 20 16:20:05 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Tim Brody
>Release:        8.20
>Organization:
University of Southampton
>Environment:
n/a
>Description:
sysinstall calls libdisk/Disk_Names that has a hard-limit of 32 disk devices. On systems (e.g. Sun X4540) with more disks than this some drives will be silently ignored. On the X4540 the missing drives include the 4 bootable devices, making it impossible to install with sysinstall/fdisk (hence severity=high).

This problem was first identified 10 years ago when the number was bumped from 20 to 32 - http://www.cz.freebsd.org/pub/FreeBSD-cvs/gnats/conf/24503.


Further (but unpatched), sysinstall/devices.c does not free the contents of the disks array so will cause a memory leak.
>How-To-Repeat:

>Fix:
Apply attached patch to libdisk, recompile/reinstall libdisk and sysinstall.

Patch attached with submission follows:

Index: libdisk.h
===================================================================
--- libdisk.h	(revision 226570)
+++ libdisk.h	(working copy)
@@ -17,9 +17,6 @@
 /* You can define a particular architecture here if you are debugging. */
 /* #define P_DEBUG p_sparc64 */
 
-#define MAX_NO_DISKS	32
-/* Max # of disks Disk_Names() will return */
-
 #define MAX_SEC_SIZE    2048  /* maximum sector size that is supported */
 #define MIN_SEC_SIZE	512   /* the sector size to end sensing at */
 
Index: disk.c
===================================================================
--- disk.c	(revision 226570)
+++ disk.c	(working copy)
@@ -190,7 +190,7 @@
 char **
 Disk_Names()
 {
-	int disk_cnt;
+	int i, disk_cnt;
 	char **disks;
 	int error;
 	size_t listsize;
@@ -205,30 +205,36 @@
 	if (listsize == 0)
 		return (NULL);
 
-	disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
-	if (disks == NULL)
+	disk1 = disklist = (char *)calloc(listsize + 1, sizeof *disklist);
+	if (disklist == NULL)
 		return NULL;
-	disk1 = disklist = (char *)malloc(listsize + 1);
-	if (disklist == NULL) {
-		free(disks);
-		return NULL;
-	}
-	memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
-	memset(disklist, 0, listsize + 1);
+
 	error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
 	if (error || disklist[0] == 0) {
 		free(disklist);
-		free(disks);
 		return NULL;
 	}
-	for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
+
+	disk_cnt = 1;
+	for (i = 0; i < listsize; ++i) {
+		if (disklist[i] == ' ')
+			disk_cnt++;
+	}
+
+	disks = calloc(disk_cnt + 1, sizeof *disks);
+	if (disks == NULL) {
+		free(disklist);
+		return NULL;
+	}
+
+	for (i = 0; i < disk_cnt; ++i) {
 		disk2 = strsep(&disk1, " ");
 		if (disk2 == NULL)
 			break;
-		disks[disk_cnt] = strdup(disk2);
-		if (disks[disk_cnt] == NULL) {
-			for (disk_cnt--; disk_cnt >= 0; disk_cnt--)
-				free(disks[disk_cnt]);
+		disks[i] = strdup(disk2);
+		if (disks[i] == NULL) {
+			for (i--; i >= 0; i--)
+				free(disks[i]);
 			free(disklist);
 			free(disks);
 			return (NULL);


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list