Module Name:    src
Committed By:   martin
Date:           Thu Nov  8 11:56:56 UTC 2018

Modified Files:
        src/usr.sbin/sysinst: disks.c

Log Message:
Untangle disk enumeration a bit more.


To generate a diff of this commit:
cvs rdiff -u -r1.20 -r1.21 src/usr.sbin/sysinst/disks.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/sysinst/disks.c
diff -u src/usr.sbin/sysinst/disks.c:1.20 src/usr.sbin/sysinst/disks.c:1.21
--- src/usr.sbin/sysinst/disks.c:1.20	Thu Nov  8 11:15:58 2018
+++ src/usr.sbin/sysinst/disks.c	Thu Nov  8 11:56:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: disks.c,v 1.20 2018/11/08 11:15:58 martin Exp $ */
+/*	$NetBSD: disks.c,v 1.21 2018/11/08 11:56:56 martin Exp $ */
 
 /*
  * Copyright 1997 Piermont Information Systems Inc.
@@ -110,6 +110,8 @@ static int fsck_preen(const char *, int,
 static void fixsb(const char *, const char *, char);
 static bool is_gpt(const char *);
 static int incoregpt(pm_devs_t *, partinfo *);
+static bool enumerate_disks(void *state,
+	bool (*func)(void *state, const char *dev));
 
 
 static bool tmpfs_on_var_shm(void);
@@ -351,46 +353,48 @@ done:
 		strcpy(dd->dd_descr, dd->dd_name);
 }
 
-/* disknames - contains device names without partition letters
- * cdrom_devices - contains devices including partition letters
- * returns the first entry in hw.disknames matching a cdrom_device, or
- * first entry on error or no match
+/*
+ * State for helper callback for get_default_cdrom
+ */
+struct default_cdrom_data {
+	char *device;
+	size_t max_len;
+	bool found;
+};
+
+/*
+ * Helper function for get_default_cdrom, gets passed a device
+ * name and a void pointer to default_cdrom_data.
+ */
+static bool
+get_default_cdrom_helper(void *state, const char *dev)
+{
+	struct default_cdrom_data *data = state;
+
+	strlcpy(data->device, dev, data->max_len);
+	data->found = true;
+
+	return false;	/* one is enough, stop iteration */
+}
+
+/*
+ * Set the argument to the name of the first CD devices actually
+ * available, leave it unmodified otherwise.
+ * Return true if a device has been found.
  */
 bool
 get_default_cdrom(char *cd, size_t max_len)
 {
-	static const char *cdrom_devices[] = { CD_NAMES, 0 };
-	static const char mib_name[] = "hw.disknames";
-	size_t len;
-	char *disknames;
-	char *last;
-	char *name;
-	const char **arg;
-	const char *cd_dev;
-
-	/* On error just use first entry in cdrom_devices */
-	if (sysctlbyname(mib_name, NULL, &len, NULL, 0) == -1)
-		return cdrom_devices[0];
-	if ((disknames = malloc(len + 2)) == 0) /* skip on malloc fail */
-		return cdrom_devices[0];
-
-	(void)sysctlbyname(mib_name, disknames, &len, NULL, 0);
-	for ((name = strtok_r(disknames, " ", &last)); name;
-	    (name = strtok_r(NULL, " ", &last))) {
-		for (arg = cdrom_devices; *arg; ++arg) {
-			cd_dev = *arg;
-			/* skip unit and partition */
-			if (strncmp(cd_dev, name, strlen(cd_dev) - 2) != 0)
-				continue;
-			if (name != disknames)
-				strcpy(disknames, name);
-			strcat(disknames, "a");
-			/* XXX: leaks, but so what? */
-			return disknames;
-		}
-	}
-	free(disknames);
-	return cdrom_devices[0];
+	struct default_cdrom_data state;
+
+	state.device = cd;
+	state.max_len = max_len;
+	state.found = false;
+
+	if (enumerate_disks(&state, get_default_cdrom_helper))
+		return state.found;
+
+	return false;
 }
 
 static void
@@ -520,109 +524,139 @@ is_cdrom_device(const char *dev)
 
 /*
  * Multi-purpose helper function:
- * iterate all known disks, either
- *  - skip all CD devices
- *  - recognize the first available CD device and set its name
- * When doing non-CDs, optionally skip non-partionable devices
- * (i.e. wedges).
+ * iterate all known disks, invoke a callback for each.
+ * Stop iteration when the callback returns false.
+ * Return true when iteration actually happend, false on error.
  */
-static int
-get_disks(struct disk_desc *dd, bool with_non_partitionable,
-	char *cd_dev, size_t max_len)
+static bool
+enumerate_disks(void *state, bool (*func)(void *state, const char *dev))
 {
 	static const int mib[] = { CTL_HW, HW_DISKNAMES };
 	static const unsigned int miblen = __arraycount(mib);
 	const char *xd;
-	struct disklabel l;
-	int numdisks;
-	size_t len;
 	char *disk_names;
-
-	/* initialize */
-	numdisks = 0;
+	size_t len;
 
 	if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1)
-		return 0;
+		return false;
+
 	disk_names = malloc(len);
 	if (disk_names == NULL)
-		return 0;
+		return false;
 
 	if (sysctl(mib, miblen, disk_names, &len, NULL, 0) == -1) {
 		free(disk_names);
-		return 0;
+		return false;
 	}
 
 	for (xd = strtok(disk_names, " "); xd != NULL; xd = strtok(NULL, " ")) {
-		/* is this a CD device? */
-		if (is_cdrom_device(xd)) {
-			if (cd_dev && max_len) {
-				/* return first found CD device name */
-				strlcpy(cd_dev, xd, max_len);
-				return 1;
-			} else {
-				/* skip this device */
-				continue;
-			}
-		}
+		if (!(*func)(state, xd))
+			break;
+	}
+	free(disk_names);
 
-		strlcpy(dd->dd_name, xd, sizeof dd->dd_name - 2);
-		dd->dd_no_mbr = false;
-		dd->dd_no_part = false;
-
-		if (strncmp(xd, "dk", 2) == 0) {
-			char *endp;
-			int e;
-
-			/* if this device is dkNNNN, no partitioning is possible */
-			strtou(xd+2, &endp, 10, 0, INT_MAX, &e);
-			if (endp && *endp == 0 && e == 0)
-				dd->dd_no_part = true;
-		}
-		if (dd->dd_no_part && !with_non_partitionable)
-			continue;
+	return true;
+}
 
-		if (!get_geom(dd->dd_name, &l)) {
-			if (errno == ENOENT)
-				break;
-			if (errno != ENOTTY || !dd->dd_no_part)
-				/*
-				 * Allow plain partitions,
-				 * like already existing wedges
-				 * (like dk0) if marked as
-				 * non-partitioning device.
-				 * For all other cases, continue
-				 * with the next disk.
-				 */
-				continue;
-			if (!is_ffs_wedge(dd->dd_name))
-				continue;
-		}
+/*
+ * Helper state for get_disks
+ */
+struct get_disks_state {
+	int numdisks;
+	struct disk_desc *dd;
+	bool with_non_partitionable;
+};
 
-		/*
-		 * Exclude a disk mounted as root partition,
-		 * in case of install-image on a USB memstick.
-		 */
-		if (is_active_rootpart(dd->dd_name, 0))
-			continue;
+/*
+ * Helper function for get_disks enumartion
+ */
+static bool
+get_disks_helper(void *arg, const char *dev)
+{
+	struct get_disks_state *state = arg;
+	struct disklabel l;
 
-		if (!dd->dd_no_part) {
-			dd->dd_cyl = l.d_ncylinders;
-			dd->dd_head = l.d_ntracks;
-			dd->dd_sec = l.d_nsectors;
-			dd->dd_secsize = l.d_secsize;
-			dd->dd_totsec = l.d_secperunit;
-		}
-		if (dd->dd_no_part)
-			get_wedge_descr(dd);
-		else
-			get_descr(dd);
-		dd++;
-		numdisks++;
-		if (numdisks == MAX_DISKS)
-			break;
+	/* is this a CD device? */
+	if (is_cdrom_device(dev))
+		return true;
+
+	strlcpy(state->dd->dd_name, dev, sizeof state->dd->dd_name - 2);
+	state->dd->dd_no_mbr = false;
+	state->dd->dd_no_part = false;
+
+	if (strncmp(dev, "dk", 2) == 0) {
+		char *endp;
+		int e;
+
+		/* if this device is dkNNNN, no partitioning is possible */
+		strtou(dev+2, &endp, 10, 0, INT_MAX, &e);
+		if (endp && *endp == 0 && e == 0)
+			state->dd->dd_no_part = true;
 	}
-	free(disk_names);
-	return numdisks;
+	if (state->dd->dd_no_part && !state->with_non_partitionable)
+		return true;
+
+	if (!get_geom(state->dd->dd_name, &l)) {
+		if (errno == ENOENT)
+			return true;
+		if (errno != ENOTTY || !state->dd->dd_no_part)
+			/*
+			 * Allow plain partitions,
+			 * like already existing wedges
+			 * (like dk0) if marked as
+			 * non-partitioning device.
+			 * For all other cases, continue
+			 * with the next disk.
+			 */
+			return true;
+		if (!is_ffs_wedge(state->dd->dd_name))
+			return true;
+	}
+
+	/*
+	 * Exclude a disk mounted as root partition,
+	 * in case of install-image on a USB memstick.
+	 */
+	if (is_active_rootpart(state->dd->dd_name, 0))
+		return true;
+
+	if (!state->dd->dd_no_part) {
+		state->dd->dd_cyl = l.d_ncylinders;
+		state->dd->dd_head = l.d_ntracks;
+		state->dd->dd_sec = l.d_nsectors;
+		state->dd->dd_secsize = l.d_secsize;
+		state->dd->dd_totsec = l.d_secperunit;
+	}
+	if (state->dd->dd_no_part)
+		get_wedge_descr(state->dd);
+	else
+		get_descr(state->dd);
+	state->dd++;
+	state->numdisks++;
+	if (state->numdisks == MAX_DISKS)
+		return false;
+
+	return true;
+}
+
+/*
+ * Get all disk devices that are not CDs.
+ * Optionally leave out those that can not be partitioned further.
+ */
+static int
+get_disks(struct disk_desc *dd, bool with_non_partitionable)
+{
+	struct get_disks_state state;
+
+	/* initialize */
+	state.numdisks = 0;
+	state.dd = dd;
+	state.with_non_partitionable = with_non_partitionable;
+
+	if (enumerate_disks(&state, get_disks_helper))
+		return state.numdisks;
+
+	return 0;
 }
 
 int
@@ -637,7 +671,7 @@ find_disks(const char *doingwhat)
 	pm_devs_t *pm_i, *pm_last = NULL;
 
 	/* Find disks. */
-	numdisks = get_disks(disks, partman_go <= 0, NULL, 0);
+	numdisks = get_disks(disks, partman_go <= 0);
 
 	/* need a redraw here, kernel messages hose everything */
 	touchwin(stdscr);

Reply via email to