Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Jan 2011 05:31:51 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r217390 - user/nwhitehorn/bsdinstall/partedit
Message-ID:  <201101140531.p0E5VpGe076058@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Fri Jan 14 05:31:51 2011
New Revision: 217390
URL: http://svn.freebsd.org/changeset/base/217390

Log:
  Add a guided partitioning wizard as a replacement for sysinstall's
  "Auto Defaults" button. On x86, this uses GPT by default for new disks.
  Default partitioning layout on all systems is the "One Big /" philosophy.
  
  Swap is the second partition for now due to boot loader and BIOS
  limitations -- it may make sense in the future to make it first, so as
  to allow the data partition to be extended on systems with resizable disks
  (RAID, VMs).

Added:
  user/nwhitehorn/bsdinstall/partedit/part_wizard.c
Modified:
  user/nwhitehorn/bsdinstall/partedit/Makefile
  user/nwhitehorn/bsdinstall/partedit/gpart_ops.c
  user/nwhitehorn/bsdinstall/partedit/partedit.c
  user/nwhitehorn/bsdinstall/partedit/partedit.h
  user/nwhitehorn/bsdinstall/partedit/partedit_pc98.c
  user/nwhitehorn/bsdinstall/partedit/partedit_powerpc.c
  user/nwhitehorn/bsdinstall/partedit/partedit_sparc64.c
  user/nwhitehorn/bsdinstall/partedit/partedit_x86.c

Modified: user/nwhitehorn/bsdinstall/partedit/Makefile
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/Makefile	Fri Jan 14 05:25:44 2011	(r217389)
+++ user/nwhitehorn/bsdinstall/partedit/Makefile	Fri Jan 14 05:31:51 2011	(r217390)
@@ -15,7 +15,8 @@ PARTEDIT_ARCH= sparc64
 PARTEDIT_ARCH= generic
 .endif
 
-SRCS=	diskeditor.c partedit.c gpart_ops.c partedit_${PARTEDIT_ARCH}.c
+SRCS=	diskeditor.c partedit.c gpart_ops.c partedit_${PARTEDIT_ARCH}.c \
+	part_wizard.c
 
 WARNS?=	3
 NO_MAN=	true

Modified: user/nwhitehorn/bsdinstall/partedit/gpart_ops.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/gpart_ops.c	Fri Jan 14 05:25:44 2011	(r217389)
+++ user/nwhitehorn/bsdinstall/partedit/gpart_ops.c	Fri Jan 14 05:31:51 2011	(r217390)
@@ -37,7 +37,7 @@ gpart_show_error(const char *title, cons
 	dialog_msgbox(title, message, 0, 0, TRUE);
 }
 
-static int
+int
 gpart_partition(const char *lg_name, const char *scheme)
 {
 	int cancel, choice;
@@ -241,7 +241,7 @@ gpart_partcode(struct gprovider *pp)
 	}
 }
 
-static void
+void
 gpart_destroy(struct ggeom *lg_geom, int force)
 {
 	struct gprovider *pp;
@@ -518,7 +518,8 @@ set_default_part_metadata(const char *na
 }
 
 void
-gpart_create(struct gprovider *pp)
+gpart_create(struct gprovider *pp, char *default_type, char *default_size,
+     char *default_mountpoint, char **partname, int interactive)
 {
 	struct gctl_req *r;
 	struct gconfig *gc;
@@ -546,6 +547,9 @@ gpart_create(struct gprovider *pp)
 		    FALSE},
 	};
 
+	if (partname != NULL)
+		*partname = NULL;
+
 	/* Record sector and stripe sizes */
 	sector = pp->lg_sectorsize;
 	stripe = pp->lg_stripesize;
@@ -635,11 +639,20 @@ gpart_create(struct gprovider *pp)
 	else
 		nitems = 3;
 
-addpartform:
-	choice = dlg_form("Add Partition", "", 0, 0, 0, nitems, items, &junk);
+	if (default_type != NULL)
+		items[0].text = default_type;
+	if (default_size != NULL)
+		items[1].text = default_size;
+	if (default_mountpoint != NULL)
+		items[2].text = default_mountpoint;
 
-	if (choice) /* Cancel pressed */
-		return;
+addpartform:
+	if (interactive) {
+		choice = dlg_form("Add Partition", "", 0, 0, 0, nitems,
+		    items, &junk);
+		if (choice) /* Cancel pressed */
+			return;
+	}
 
 	size = maxsize;
 	if (strlen(items[1].text) > 0) {
@@ -693,9 +706,13 @@ addpartform:
 	 * the user to add one.
 	 */
 	if (strcmp(items[2].text, "/") == 0 && bootpart_size(scheme) > 0) {
-		choice = dialog_yesno("Boot Partition", "This partition scheme "
-		    "requires a boot partition for the disk to be bootable. "
-		    "Would you like to make one now?", 0, 0);
+		if (interactive)
+			choice = dialog_yesno("Boot Partition",
+			    "This partition scheme requires a boot partition "
+			    "for the disk to be bootable. Would you like to "
+			    "make one now?", 0, 0);
+		else
+			choice = 0;
 
 		if (choice == 0) { /* yes */
 			r = gctl_get_handle();
@@ -759,6 +776,9 @@ addpartform:
 		if (items[i].text_free)
 			free(items[i].text);
 	gctl_free(r);
+
+	if (partname != NULL)
+		*partname = strdup(strtok(output, " "));
 }
 	
 void

Added: user/nwhitehorn/bsdinstall/partedit/part_wizard.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/bsdinstall/partedit/part_wizard.c	Fri Jan 14 05:31:51 2011	(r217390)
@@ -0,0 +1,263 @@
+#include <sys/param.h>
+#include <errno.h>
+#include <libutil.h>
+#include <inttypes.h>
+
+#include <libgeom.h>
+#include <dialog.h>
+#include <dlg_keys.h>
+
+#include "partedit.h"
+
+#define GPART_FLAGS "x" /* Do not commit changes by default */
+
+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);
+
+int
+part_wizard(void) {
+	int error;
+	struct gmesh mesh;
+	char *disk, *schemeroot;
+
+	error = geom_gettree(&mesh);
+
+	dlg_put_backtitle();
+	error = geom_gettree(&mesh);
+	disk = boot_disk(&mesh);
+	if (disk == NULL)
+		return (1);
+
+	dlg_clear();
+	dlg_put_backtitle();
+	schemeroot = wizard_partition(&mesh, disk);
+	free(disk);
+	if (schemeroot == NULL)
+		return (1);
+	dlg_clear();
+
+	geom_deletetree(&mesh);
+	error = geom_gettree(&mesh);
+
+	wizard_makeparts(&mesh, schemeroot);
+	free(schemeroot);
+	
+	geom_deletetree(&mesh);
+
+	return (0);
+}
+
+static char *
+boot_disk(struct gmesh *mesh)
+{
+	struct gclass *classp;
+	struct ggeom *gp;
+	struct gprovider *pp;
+	DIALOG_LISTITEM *disks = NULL;
+	char diskdesc[512];
+	char *chosen;
+	int i, err, selected, n = 0;
+
+	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
+		if (strcmp(classp->lg_name, "DISK") != 0 &&
+		    strcmp(classp->lg_name, "MD") != 0)
+			continue;
+
+		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+			if (LIST_EMPTY(&gp->lg_provider))
+				continue;
+
+			LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+				disks = realloc(disks, (++n)*sizeof(disks[0]));
+				disks[n-1].name = pp->lg_name;
+				humanize_number(diskdesc, 7, pp->lg_mediasize,
+				    "B", HN_AUTOSCALE, HN_DECIMAL);
+				if (strncmp(pp->lg_name, "ad", 2) == 0)
+					strcat(diskdesc, " ATA Hard Disk");
+				else if (strncmp(pp->lg_name, "da", 2) == 0)
+					strcat(diskdesc, " SCSI Hard Disk");
+				else if (strncmp(pp->lg_name, "md", 2) == 0)
+					strcat(diskdesc, " Memory Disk");
+				else if (strncmp(pp->lg_name, "cd", 2) == 0) {
+					n--;
+					continue;
+				}
+				disks[n-1].text = strdup(diskdesc);
+				disks[n-1].help = NULL;
+				disks[n-1].state = 0;
+			}
+		}
+	}
+
+	if (n > 1) {
+		err = dlg_menu("Partitioning",
+		    "Select the disk on which to install FreeBSD.", 0, 0, 0,
+		    n, disks, &selected, NULL);
+
+		chosen = (err == 0) ? strdup(disks[selected].name) : NULL;
+	} else if (n == 1) {
+		chosen = strdup(disks[0].name);
+	} else {
+		chosen = NULL;
+	}
+
+	for (i = 0; i < n; i++)
+		free(disks[i].text);
+
+	return (chosen);
+}
+
+static struct gprovider *
+provider_for_name(struct gmesh *mesh, const char *name)
+{
+	struct gclass *classp;
+	struct gprovider *pp = NULL;
+	struct ggeom *gp;
+
+	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
+		if (strcmp(classp->lg_name, "DISK") != 0 &&
+		    strcmp(classp->lg_name, "PART") != 0 &&
+		    strcmp(classp->lg_name, "MD") != 0)
+			continue;
+
+		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+			if (LIST_EMPTY(&gp->lg_provider))
+				continue;
+
+			LIST_FOREACH(pp, &gp->lg_provider, lg_provider)
+				if (strcmp(pp->lg_name, name) == 0)
+					break;
+
+			if (pp != NULL) break;
+		}
+
+		if (pp != NULL) break;
+	}
+
+	return (pp);
+}
+
+static char *
+wizard_partition(struct gmesh *mesh, const char *disk)
+{
+	struct gclass *classp;
+	struct ggeom *gpart = NULL;
+	struct gconfig *gc;
+	char message[512];
+	const char *scheme;
+	char *retval = NULL;
+	int choice;
+
+	LIST_FOREACH(classp, &mesh->lg_class, lg_class)
+		if (strcmp(classp->lg_name, "PART") == 0)
+			break;
+
+	if (classp != NULL) {
+		LIST_FOREACH(gpart, &classp->lg_geom, lg_geom) 
+			if (strcmp(gpart->lg_name, disk) == 0)
+				break;
+	}
+
+	if (gpart != NULL) {
+		LIST_FOREACH(gc, &gpart->lg_config, lg_config) {
+			if (strcmp(gc->lg_name, "scheme") == 0) {
+				scheme = gc->lg_val;
+				break;
+			}
+		}
+	}
+
+query:
+	dialog_vars.yes_label = "Entire Disk";
+	dialog_vars.no_label = "Partition";
+	if (gpart != NULL)
+		dialog_vars.defaultno = TRUE;
+
+	snprintf(message, sizeof(message), "Would you like to use this entire "
+	    "disk (%s) for FreeBSD or partition it to share it with other "
+	    "operating systems? Using the entire disk will erase any data "
+	    "currently stored there.", disk);
+	choice = dialog_yesno("Partition", message, 0, 0);
+
+	dialog_vars.yes_label = NULL;
+	dialog_vars.no_label = NULL;
+	dialog_vars.defaultno = FALSE;
+
+	if (choice == 0) { /* Entire disk */
+		if (gpart != NULL) { /* Erase partitioned disk */
+			choice = dialog_yesno("Confirmation", "This will erase "
+			   "the disk. Are you sure you want to proceed?", 0, 0);
+			if (choice != 0)
+				goto query;
+
+			gpart_destroy(gpart, 1);
+		}
+
+		gpart_partition(disk, default_scheme());
+		scheme = default_scheme();
+	}
+
+	if (strcmp(scheme, "PC98") == 0 || strcmp(scheme, "MBR") == 0) {
+		struct gmesh submesh;
+		geom_gettree(&submesh);
+		gpart_create(provider_for_name(&submesh, disk),
+		    "freebsd", NULL, NULL, &retval, choice);
+		geom_deletetree(&submesh);
+	} else {
+		retval = strdup(disk);
+	}
+
+	return (retval);
+}
+
+static void
+wizard_makeparts(struct gmesh *mesh, const char *disk)
+{
+	struct gmesh submesh;
+	struct gclass *classp;
+	struct ggeom *gp;
+	struct gconfig *gc;
+	const char *scheme;
+	struct gprovider *pp;
+	intmax_t start, end;
+	intmax_t swapsize;
+	char swapsizestr[10], rootsizestr[10];
+
+	LIST_FOREACH(classp, &mesh->lg_class, lg_class)
+		if (strcmp(classp->lg_name, "PART") == 0)
+			break;
+
+	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) 
+		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);
+		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));
+	humanize_number(swapsizestr, 7, swapsize, "B", HN_AUTOSCALE,
+	    HN_NOSPACE | HN_DECIMAL);
+	humanize_number(rootsizestr, 7,
+	    (end - start)*pp->lg_sectorsize - swapsize - 1024*1024,
+	    "B", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL);
+
+	geom_gettree(&submesh);
+	pp = provider_for_name(&submesh, disk);
+	gpart_create(pp, "freebsd-ufs", rootsizestr, "/", NULL, 0);
+	geom_deletetree(&submesh);
+
+	geom_gettree(&submesh);
+	pp = provider_for_name(&submesh, disk);
+	gpart_create(pp, "freebsd-swap", swapsizestr, NULL, NULL, 0);
+	geom_deletetree(&submesh);
+}

Modified: user/nwhitehorn/bsdinstall/partedit/partedit.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/partedit.c	Fri Jan 14 05:25:44 2011	(r217389)
+++ user/nwhitehorn/bsdinstall/partedit/partedit.c	Fri Jan 14 05:31:51 2011	(r217390)
@@ -38,6 +38,19 @@ main(void) {
 	dialog_vars.item_help = TRUE;
 	nscroll = i = 0;
 
+	/* Ask about guided vs. manual partitioning */
+	dlg_put_backtitle();
+	dialog_vars.yes_label = "Guided";
+	dialog_vars.no_label = "Manual";
+	op = dialog_yesno("Partitioning", "Would you like to use the guided "
+	    "partitioning tool (recommended for beginners) or to set up "
+	    "partitions manual (experts)?", 0, 0);
+	dialog_vars.yes_label = NULL;
+	dialog_vars.no_label = NULL;
+	if (op == 0) /* Guided */
+		part_wizard();
+
+	/* Show the part editor either immediately, or to confirm wizard */
 	while (1) {
 		error = geom_gettree(&mesh);
 		items = read_geom_mesh(&mesh, &nitems);
@@ -54,7 +67,8 @@ main(void) {
 
 		switch (op) {
 		case 0: /* Create */
-			gpart_create((struct gprovider *)(items[i].cookie));
+			gpart_create((struct gprovider *)(items[i].cookie),
+			    NULL, NULL, NULL, NULL, 1);
 			break;
 		case 1: /* Delete */
 			gpart_delete((struct gprovider *)(items[i].cookie));

Modified: user/nwhitehorn/bsdinstall/partedit/partedit.h
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/partedit.h	Fri Jan 14 05:25:44 2011	(r217389)
+++ user/nwhitehorn/bsdinstall/partedit/partedit.h	Fri Jan 14 05:31:51 2011	(r217390)
@@ -3,6 +3,7 @@
 
 struct gprovider;
 struct gmesh;
+struct ggeom;
 
 TAILQ_HEAD(pmetadata_head, partition_metadata);
 extern struct pmetadata_head part_metadata;
@@ -21,17 +22,23 @@ struct partition_metadata {
 struct partition_metadata *get_part_metadata(const char *name, int create);
 void delete_part_metadata(const char *name);
 
+int part_wizard(void);
+
 /* gpart operations */
 void gpart_delete(struct gprovider *pp);
+void gpart_destroy(struct ggeom *lg_geom, int force);
 void gpart_edit(struct gprovider *pp);
-void gpart_create(struct gprovider *pp);
+void gpart_create(struct gprovider *pp, char *default_type, char *default_size,
+    char *default_mountpoint, char **output, int interactive);
 void gpart_revert(struct gprovider *pp);
 void gpart_revert_all(struct gmesh *mesh);
 void gpart_commit(struct gmesh *mesh);
+int gpart_partition(const char *lg_name, const char *scheme);
 void set_default_part_metadata(const char *name, const char *scheme,
     const char *type, const char *mountpoint, int newfs);
 
 /* machine-dependent bootability checks */
+const char *default_scheme(void);
 int is_scheme_bootable(const char *part_type);
 size_t bootpart_size(const char *part_type);
 const char *bootcode_path(const char *part_type);

Modified: user/nwhitehorn/bsdinstall/partedit/partedit_pc98.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/partedit_pc98.c	Fri Jan 14 05:25:44 2011	(r217389)
+++ user/nwhitehorn/bsdinstall/partedit/partedit_pc98.c	Fri Jan 14 05:31:51 2011	(r217390)
@@ -2,6 +2,11 @@
 
 #include "partedit.h"
 
+const char *
+default_scheme(void) {
+	return ("PC98");
+}
+
 int
 is_scheme_bootable(const char *part_type) {
 	if (strcmp(part_type, "PC98") == 0)

Modified: user/nwhitehorn/bsdinstall/partedit/partedit_powerpc.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/partedit_powerpc.c	Fri Jan 14 05:25:44 2011	(r217389)
+++ user/nwhitehorn/bsdinstall/partedit/partedit_powerpc.c	Fri Jan 14 05:31:51 2011	(r217390)
@@ -2,6 +2,11 @@
 
 #include "partedit.h"
 
+const char *
+default_scheme(void) {
+	return ("APM");
+}
+
 int
 is_scheme_bootable(const char *part_type) {
 	if (strcmp(part_type, "APM") == 0)

Modified: user/nwhitehorn/bsdinstall/partedit/partedit_sparc64.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/partedit_sparc64.c	Fri Jan 14 05:25:44 2011	(r217389)
+++ user/nwhitehorn/bsdinstall/partedit/partedit_sparc64.c	Fri Jan 14 05:31:51 2011	(r217390)
@@ -2,6 +2,11 @@
 
 #include "partedit.h"
 
+const char *
+default_scheme(void) {
+	return ("VTOC8");
+}
+
 int
 is_scheme_bootable(const char *part_type) {
 	if (strcmp(part_type, "VTOC8") == 0)

Modified: user/nwhitehorn/bsdinstall/partedit/partedit_x86.c
==============================================================================
--- user/nwhitehorn/bsdinstall/partedit/partedit_x86.c	Fri Jan 14 05:25:44 2011	(r217389)
+++ user/nwhitehorn/bsdinstall/partedit/partedit_x86.c	Fri Jan 14 05:31:51 2011	(r217390)
@@ -2,6 +2,11 @@
 
 #include "partedit.h"
 
+const char *
+default_scheme(void) {
+	return ("GPT");
+}
+
 int
 is_scheme_bootable(const char *part_type) {
 	if (strcmp(part_type, "BSD") == 0)



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