Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 16 Jan 2011 18:46:17 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r217480 - user/nwhitehorn/bsdinstall/partedit
Message-ID:  <201101161846.p0GIkHXe073337@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Sun Jan 16 18:46:17 2011
New Revision: 217480
URL: http://svn.freebsd.org/changeset/base/217480

Log:
  Improve the robustness of the partition wizard.

Modified:
  user/nwhitehorn/bsdinstall/partedit/gpart_ops.c
  user/nwhitehorn/bsdinstall/partedit/part_wizard.c
  user/nwhitehorn/bsdinstall/partedit/partedit.c
  user/nwhitehorn/bsdinstall/partedit/partedit.h

Modified: user/nwhitehorn/bsdinstall/partedit/gpart_ops.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/gpart_ops.c	Sun Jan 16 18:04:01 2011	(r217479)
+++ user/nwhitehorn/bsdinstall/partedit/gpart_ops.c	Sun Jan 16 18:46:17 2011	(r217480)
@@ -517,6 +517,105 @@ set_default_part_metadata(const char *na
 	}
 }
 
+static
+int part_compare(const void *xa, const void *xb)
+{
+	struct gprovider **a = (struct gprovider **)xa;
+	struct gprovider **b = (struct gprovider **)xb;
+	intmax_t astart, bstart;
+	struct gconfig *gc;
+	
+	astart = bstart = 0;
+	LIST_FOREACH(gc, &(*a)->lg_config, lg_config)
+		if (strcmp(gc->lg_name, "start") == 0) {
+			astart = strtoimax(gc->lg_val, NULL, 0);
+			break;
+		}
+	LIST_FOREACH(gc, &(*b)->lg_config, lg_config)
+		if (strcmp(gc->lg_name, "start") == 0) {
+			bstart = strtoimax(gc->lg_val, NULL, 0);
+			break;
+		}
+
+	if (astart < bstart)
+		return -1;
+	else if (astart > bstart)
+		return 1;
+	else
+		return 0;
+}
+
+intmax_t
+gpart_max_free(struct ggeom *geom, intmax_t *npartstart)
+{
+	struct gconfig *gc;
+	struct gprovider *pp, **providers;
+	intmax_t lastend;
+	intmax_t start, end;
+	intmax_t maxsize, maxstart;
+	intmax_t partstart, partend;
+	int i, nparts;
+
+	/* Now get the maximum free size and free start */
+	start = end = 0;
+	LIST_FOREACH(gc, &geom->lg_config, lg_config) {
+		if (strcmp(gc->lg_name, "first") == 0)
+			start = strtoimax(gc->lg_val, NULL, 0);
+		if (strcmp(gc->lg_name, "last") == 0)
+			end = strtoimax(gc->lg_val, NULL, 0);
+	}
+
+	i = nparts = 0;
+	LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
+		nparts++;
+	providers = calloc(nparts, sizeof(providers[0]));
+	LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
+		providers[i++] = pp;
+	qsort(providers, nparts, sizeof(providers[0]), part_compare);
+
+	lastend = start - 1;
+	maxsize = 0;
+	for (i = 0; i < nparts; i++) {
+		pp = providers[i];
+
+		LIST_FOREACH(gc, &pp->lg_config, lg_config) {
+			if (strcmp(gc->lg_name, "start") == 0)
+				partstart = strtoimax(gc->lg_val, NULL, 0);
+			if (strcmp(gc->lg_name, "end") == 0)
+				partend = strtoimax(gc->lg_val, NULL, 0);
+		}
+
+		if (partstart - lastend > maxsize) {
+			maxsize = partstart - lastend - 1;
+			maxstart = lastend + 1;
+		}
+
+		lastend = partend;
+	}
+
+	if (end - lastend > maxsize) {
+		maxsize = end - lastend - 1;
+		maxstart = lastend + 1;
+	}
+
+	pp = LIST_FIRST(&geom->lg_consumer)->lg_provider;
+
+	/* Compute beginning of new partition and maximum available space */
+	if (pp->lg_stripesize > 0 &&
+	    (maxstart*pp->lg_sectorsize % pp->lg_stripesize) != 0) {
+		intmax_t offset = (pp->lg_stripesize -
+		    ((maxstart*pp->lg_sectorsize) % pp->lg_stripesize)) /
+		    pp->lg_sectorsize;
+		maxstart += offset;
+		maxsize -= offset;
+	}
+
+	if (npartstart != NULL)
+		*npartstart = maxstart;
+
+	return (maxsize);
+}
+
 void
 gpart_create(struct gprovider *pp, char *default_type, char *default_size,
      char *default_mountpoint, char **partname, int interactive)
@@ -527,7 +626,7 @@ gpart_create(struct gprovider *pp, char 
 	struct ggeom *geom;
 	const char *errstr, *scheme;
 	char sizestr[32], startstr[32], output[64];
-	intmax_t maxsize, size, start, end, sector, firstfree, stripe;
+	intmax_t maxsize, size, sector, firstfree, stripe;
 	uint64_t bytes;
 	int nitems, choice, junk;
 	unsigned i;
@@ -586,34 +685,12 @@ gpart_create(struct gprovider *pp, char 
 	if (geom == NULL)
 		return;
 
-	/* Now get the maximum free size and free start */
-	start = end = 0;
-	LIST_FOREACH(gc, &geom->lg_config, lg_config) {
-		if (strcmp(gc->lg_name, "first") == 0)
-			start = strtoimax(gc->lg_val, NULL, 0);
-		if (strcmp(gc->lg_name, "last") == 0)
-			end = strtoimax(gc->lg_val, NULL, 0);
+	/* Now get the partition scheme */
+	LIST_FOREACH(gc, &geom->lg_config, lg_config) 
 		if (strcmp(gc->lg_name, "scheme") == 0)
 			scheme = gc->lg_val;
-	}
-
-	firstfree = start;
-	LIST_FOREACH(pp, &geom->lg_provider, lg_provider) {
-		LIST_FOREACH(gc, &pp->lg_config, lg_config) {
-			if (strcmp(gc->lg_name, "end") == 0) {
-				intmax_t partend;
-				partend = strtoimax(gc->lg_val, NULL, 0);
-				if (partend > firstfree)
-					firstfree = partend + 1;
-			}
-		}
-	}
-
-	/* Compute beginning of new partition and maximum available space */
-	if (stripe > 0 && (firstfree*sector % stripe) != 0) 
-		firstfree += (stripe - ((firstfree*sector) % stripe)) / sector;
 
-	size = end - firstfree;
+	size = gpart_max_free(geom, &firstfree);
 	if (size <= 0) {
 		dialog_msgbox("Error", "No free space left on device.", 0, 0,
 		    TRUE);
@@ -621,8 +698,8 @@ gpart_create(struct gprovider *pp, char 
 	}
 
 	/* Leave a free megabyte in case we need to write a boot partition */
-	if (size*sector >= 1024*1024)
-		size -= 1024*1024/sector;
+	if (size*sector >= (intmax_t)bootpart_size(scheme))
+		size -= bootpart_size(scheme)/sector;
 	maxsize = size;
 
 	humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE,

Modified: user/nwhitehorn/bsdinstall/partedit/part_wizard.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/part_wizard.c	Sun Jan 16 18:04:01 2011	(r217479)
+++ user/nwhitehorn/bsdinstall/partedit/part_wizard.c	Sun Jan 16 18:46:17 2011	(r217480)
@@ -9,11 +9,12 @@
 
 #include "partedit.h"
 
-#define GPART_FLAGS "x" /* Do not commit changes by default */
+#define MIN_FREE_SPACE		(1024*1024*1024) /* 1 GB */
+#define SWAP_SIZE(available)	MIN(available/20, 4*1024*1024*1024LL)
 
 static char *boot_disk(struct gmesh *mesh);
 static char *wizard_partition(struct gmesh *mesh, const char *disk);
-static void wizard_makeparts(struct gmesh *mesh, const char *disk);
+static int wizard_makeparts(struct gmesh *mesh, const char *disk);
 
 int
 part_wizard(void) {
@@ -21,6 +22,7 @@ part_wizard(void) {
 	struct gmesh mesh;
 	char *disk, *schemeroot;
 
+startwizard:
 	error = geom_gettree(&mesh);
 
 	dlg_put_backtitle();
@@ -40,7 +42,9 @@ part_wizard(void) {
 	geom_deletetree(&mesh);
 	error = geom_gettree(&mesh);
 
-	wizard_makeparts(&mesh, schemeroot);
+	error = wizard_makeparts(&mesh, schemeroot);
+	if (error)
+		goto startwizard;
 	free(schemeroot);
 	
 	geom_deletetree(&mesh);
@@ -212,7 +216,7 @@ query:
 	return (retval);
 }
 
-static void
+static int
 wizard_makeparts(struct gmesh *mesh, const char *disk)
 {
 	struct gmesh submesh;
@@ -221,9 +225,9 @@ wizard_makeparts(struct gmesh *mesh, con
 	struct gconfig *gc;
 	const char *scheme;
 	struct gprovider *pp;
-	intmax_t start, end;
-	intmax_t swapsize;
+	intmax_t swapsize, available;
 	char swapsizestr[10], rootsizestr[10];
+	int retval;
 
 	LIST_FOREACH(classp, &mesh->lg_class, lg_class)
 		if (strcmp(classp->lg_name, "PART") == 0)
@@ -233,23 +237,37 @@ wizard_makeparts(struct gmesh *mesh, con
 		if (strcmp(gp->lg_name, disk) == 0)
 			break;
 
-	LIST_FOREACH(gc, &gp->lg_config, lg_config) {
-		if (strcmp(gc->lg_name, "first") == 0)
-			start = strtoimax(gc->lg_val, NULL, 0);
-		if (strcmp(gc->lg_name, "last") == 0)
-			end = strtoimax(gc->lg_val, NULL, 0);
+	LIST_FOREACH(gc, &gp->lg_config, lg_config) 
 		if (strcmp(gc->lg_name, "scheme") == 0) 
 			scheme = gc->lg_val;
-	}
 
 	pp = provider_for_name(mesh, disk);
 
-	swapsize = MIN((end - start)*pp->lg_sectorsize/50,
-	    4*1024*1024*(intmax_t)(1024));
+	available = gpart_max_free(gp, NULL)*pp->lg_sectorsize;
+	if (available < MIN_FREE_SPACE) {
+		char availablestr[10], neededstr[10], message[512];
+		humanize_number(availablestr, 7, available, "B", HN_AUTOSCALE,
+		    HN_DECIMAL);
+		humanize_number(neededstr, 7, MIN_FREE_SPACE, "B", HN_AUTOSCALE,
+		    HN_DECIMAL);
+		sprintf(message, "There is not enough free space on %s to "
+		    "install FreeBSD (%s free, %s required). Would you like "
+		    "to choose another disk or to open the partition editor?",
+		    disk, availablestr, neededstr);
+
+		dialog_vars.yes_label = "Another Disk";
+		dialog_vars.no_label = "Editor";
+		retval = dialog_yesno("Warning", message, 0, 0);
+		dialog_vars.yes_label = NULL;
+		dialog_vars.no_label = NULL;
+
+		return (!retval); /* Editor -> return 0 */
+	}
+
+	swapsize = SWAP_SIZE(available);
 	humanize_number(swapsizestr, 7, swapsize, "B", HN_AUTOSCALE,
 	    HN_NOSPACE | HN_DECIMAL);
-	humanize_number(rootsizestr, 7,
-	    (end - start)*pp->lg_sectorsize - swapsize - 1024*1024,
+	humanize_number(rootsizestr, 7, available - swapsize - 1024*1024,
 	    "B", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL);
 
 	geom_gettree(&submesh);
@@ -261,4 +279,7 @@ wizard_makeparts(struct gmesh *mesh, con
 	pp = provider_for_name(&submesh, disk);
 	gpart_create(pp, "freebsd-swap", swapsizestr, NULL, NULL, 0);
 	geom_deletetree(&submesh);
+
+	return (0);
 }
+

Modified: user/nwhitehorn/bsdinstall/partedit/partedit.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/partedit.c	Sun Jan 16 18:04:01 2011	(r217479)
+++ user/nwhitehorn/bsdinstall/partedit/partedit.c	Sun Jan 16 18:46:17 2011	(r217480)
@@ -25,6 +25,7 @@ static int validate_setup(void);
 int
 main(int argc, const char **argv) {
 	struct partition_metadata *md;
+	const char *prompt;
 	struct partedit_item *items;
 	struct gmesh mesh;
 	int i, op, nitems, nscroll;
@@ -40,8 +41,14 @@ main(int argc, const char **argv) {
 	dialog_vars.item_help = TRUE;
 	nscroll = i = 0;
 
-	if (strcmp(basename(argv[0]), "autopart") == 0) /* Guided */
+	if (strcmp(basename(argv[0]), "autopart") == 0) { /* Guided */
+		prompt = "Please review the disk setup. When complete, press "
+		    "the Finished button.";
 		part_wizard();
+	} else {
+		prompt = "Create partitions for FreeBSD. No changes will be "
+		    "made until you select Finished.";
+	}
 
 	/* Show the part editor either immediately, or to confirm wizard */
 	while (1) {
@@ -53,9 +60,7 @@ main(int argc, const char **argv) {
 
 		if (i >= nitems)
 			i = nitems - 1;
-		op = diskeditor_show("Partition Editor",
-		    "Create partitions for FreeBSD. No changes will be made "
-		    "until you select Finished.",
+		op = diskeditor_show("Partition Editor", prompt,
 		    items, nitems, &i, &nscroll);
 
 		switch (op) {
@@ -95,7 +100,7 @@ main(int argc, const char **argv) {
 		if (op == 4 && validate_setup()) { /* Finished */
 			dialog_vars.extra_button = TRUE;
 			dialog_vars.extra_label =
-			    __DECONST(char *, "Don't Save");
+			    __DECONST(char *, "Abort");
 			dialog_vars.ok_label = __DECONST(char *, "Save");
 			op = dialog_yesno("Confirmation", "Your changes will "
 			    "now be written to disk. If you have chosen to "

Modified: user/nwhitehorn/bsdinstall/partedit/partedit.h
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/partedit.h	Sun Jan 16 18:04:01 2011	(r217479)
+++ user/nwhitehorn/bsdinstall/partedit/partedit.h	Sun Jan 16 18:46:17 2011	(r217480)
@@ -1,4 +1,5 @@
 #include <sys/queue.h>
+#include <inttypes.h>
 #include <fstab.h>
 
 struct gprovider;
@@ -30,6 +31,7 @@ void gpart_destroy(struct ggeom *lg_geom
 void gpart_edit(struct gprovider *pp);
 void gpart_create(struct gprovider *pp, char *default_type, char *default_size,
     char *default_mountpoint, char **output, int interactive);
+intmax_t gpart_max_free(struct ggeom *gp, intmax_t *start);
 void gpart_revert(struct gprovider *pp);
 void gpart_revert_all(struct gmesh *mesh);
 void gpart_commit(struct gmesh *mesh);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101161846.p0GIkHXe073337>