xref: /freebsd/usr.sbin/bsdinstall/partedit/gpart_ops.c (revision c67f41d01dd9fca603d1887a55931804888dca5b)
12118f387SNathan Whitehorn /*-
22118f387SNathan Whitehorn  * Copyright (c) 2011 Nathan Whitehorn
32118f387SNathan Whitehorn  * All rights reserved.
42118f387SNathan Whitehorn  *
52118f387SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
62118f387SNathan Whitehorn  * modification, are permitted provided that the following conditions
72118f387SNathan Whitehorn  * are met:
82118f387SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
92118f387SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
102118f387SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
112118f387SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
122118f387SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
132118f387SNathan Whitehorn  *
142118f387SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152118f387SNathan Whitehorn  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162118f387SNathan Whitehorn  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172118f387SNathan Whitehorn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182118f387SNathan Whitehorn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192118f387SNathan Whitehorn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202118f387SNathan Whitehorn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212118f387SNathan Whitehorn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222118f387SNathan Whitehorn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232118f387SNathan Whitehorn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242118f387SNathan Whitehorn  * SUCH DAMAGE.
252118f387SNathan Whitehorn  *
262118f387SNathan Whitehorn  * $FreeBSD$
272118f387SNathan Whitehorn  */
282118f387SNathan Whitehorn 
292118f387SNathan Whitehorn #include <sys/param.h>
302118f387SNathan Whitehorn #include <errno.h>
312118f387SNathan Whitehorn #include <libutil.h>
322118f387SNathan Whitehorn #include <inttypes.h>
332118f387SNathan Whitehorn 
342118f387SNathan Whitehorn #include <libgeom.h>
352118f387SNathan Whitehorn #include <dialog.h>
362118f387SNathan Whitehorn #include <dlg_keys.h>
372118f387SNathan Whitehorn 
382118f387SNathan Whitehorn #include "partedit.h"
392118f387SNathan Whitehorn 
402118f387SNathan Whitehorn #define GPART_FLAGS "x" /* Do not commit changes by default */
412118f387SNathan Whitehorn 
422118f387SNathan Whitehorn static void
432118f387SNathan Whitehorn gpart_show_error(const char *title, const char *explanation, const char *errstr)
442118f387SNathan Whitehorn {
452118f387SNathan Whitehorn 	char *errmsg;
462118f387SNathan Whitehorn 	char message[512];
472118f387SNathan Whitehorn 	int error;
482118f387SNathan Whitehorn 
492118f387SNathan Whitehorn 	if (explanation == NULL)
502118f387SNathan Whitehorn 		explanation = "";
512118f387SNathan Whitehorn 
522118f387SNathan Whitehorn 	error = strtol(errstr, &errmsg, 0);
532118f387SNathan Whitehorn 	if (errmsg != errstr) {
542118f387SNathan Whitehorn 		while (errmsg[0] == ' ')
552118f387SNathan Whitehorn 			errmsg++;
562118f387SNathan Whitehorn 		if (errmsg[0] != '\0')
572118f387SNathan Whitehorn 			sprintf(message, "%s%s. %s", explanation,
582118f387SNathan Whitehorn 			    strerror(error), errmsg);
592118f387SNathan Whitehorn 		else
602118f387SNathan Whitehorn 			sprintf(message, "%s%s", explanation, strerror(error));
612118f387SNathan Whitehorn 	} else {
622118f387SNathan Whitehorn 		sprintf(message, "%s%s", explanation, errmsg);
632118f387SNathan Whitehorn 	}
642118f387SNathan Whitehorn 
652118f387SNathan Whitehorn 	dialog_msgbox(title, message, 0, 0, TRUE);
662118f387SNathan Whitehorn }
672118f387SNathan Whitehorn 
68*c67f41d0SNathan Whitehorn static int
69*c67f41d0SNathan Whitehorn scheme_supports_labels(const char *scheme)
70*c67f41d0SNathan Whitehorn {
71*c67f41d0SNathan Whitehorn 	if (strcmp(scheme, "APM") == 0)
72*c67f41d0SNathan Whitehorn 		return (1);
73*c67f41d0SNathan Whitehorn 	if (strcmp(scheme, "GPT") == 0)
74*c67f41d0SNathan Whitehorn 		return (1);
75*c67f41d0SNathan Whitehorn 	if (strcmp(scheme, "PC98") == 0)
76*c67f41d0SNathan Whitehorn 		return (1);
77*c67f41d0SNathan Whitehorn 
78*c67f41d0SNathan Whitehorn 	return (0);
79*c67f41d0SNathan Whitehorn }
80*c67f41d0SNathan Whitehorn 
812118f387SNathan Whitehorn int
822118f387SNathan Whitehorn gpart_partition(const char *lg_name, const char *scheme)
832118f387SNathan Whitehorn {
842118f387SNathan Whitehorn 	int cancel, choice;
852118f387SNathan Whitehorn 	struct gctl_req *r;
862118f387SNathan Whitehorn 	const char *errstr;
872118f387SNathan Whitehorn 
882118f387SNathan Whitehorn 	DIALOG_LISTITEM items[] = {
892118f387SNathan Whitehorn 		{"APM", "Apple Partition Map",
902118f387SNathan Whitehorn 		    "Bootable on PowerPC Apple Hardware", 0 },
912118f387SNathan Whitehorn 		{"BSD", "BSD Labels",
922118f387SNathan Whitehorn 		    "Bootable on most x86 systems", 0 },
932118f387SNathan Whitehorn 		{"GPT", "GUID Partition Table",
942118f387SNathan Whitehorn 		    "Bootable on most x86 systems", 0 },
952118f387SNathan Whitehorn 		{"MBR", "DOS Partitions",
962118f387SNathan Whitehorn 		    "Bootable on most x86 systems", 0 },
972118f387SNathan Whitehorn 		{"PC98", "NEC PC9801 Partition Table",
982118f387SNathan Whitehorn 		    "Bootable on NEC PC9801 systems", 0 },
992118f387SNathan Whitehorn 		{"VTOC8", "Sun VTOC8 Partition Table",
1002118f387SNathan Whitehorn 		    "Bootable on Sun SPARC systems", 0 },
1012118f387SNathan Whitehorn 	};
1022118f387SNathan Whitehorn 
1032118f387SNathan Whitehorn schememenu:
1042118f387SNathan Whitehorn 	if (scheme == NULL) {
1052118f387SNathan Whitehorn 		dialog_vars.default_item = __DECONST(char *, default_scheme());
1062118f387SNathan Whitehorn 		cancel = dlg_menu("Partition Scheme",
1072118f387SNathan Whitehorn 		    "Select a partition scheme for this volume:", 0, 0, 0,
1082118f387SNathan Whitehorn 		    sizeof(items) / sizeof(items[0]), items, &choice, NULL);
1092118f387SNathan Whitehorn 		dialog_vars.default_item = NULL;
1102118f387SNathan Whitehorn 
1112118f387SNathan Whitehorn 		if (cancel)
1122118f387SNathan Whitehorn 			return (-1);
1132118f387SNathan Whitehorn 
1142118f387SNathan Whitehorn 		if (!is_scheme_bootable(items[choice].name)) {
1152118f387SNathan Whitehorn 			char message[512];
1162118f387SNathan Whitehorn 			sprintf(message, "This partition scheme (%s) is not "
1172118f387SNathan Whitehorn 			    "bootable on this platform. Are you sure you want "
1182118f387SNathan Whitehorn 			    "to proceed?", items[choice].name);
1192118f387SNathan Whitehorn 			dialog_vars.defaultno = TRUE;
1202118f387SNathan Whitehorn 			cancel = dialog_yesno("Warning", message, 0, 0);
1212118f387SNathan Whitehorn 			dialog_vars.defaultno = FALSE;
1222118f387SNathan Whitehorn 			if (cancel) /* cancel */
1232118f387SNathan Whitehorn 				goto schememenu;
1242118f387SNathan Whitehorn 		}
1252118f387SNathan Whitehorn 
1262118f387SNathan Whitehorn 		scheme = items[choice].name;
1272118f387SNathan Whitehorn 	}
1282118f387SNathan Whitehorn 
1292118f387SNathan Whitehorn 	r = gctl_get_handle();
1302118f387SNathan Whitehorn 	gctl_ro_param(r, "class", -1, "PART");
1312118f387SNathan Whitehorn 	gctl_ro_param(r, "arg0", -1, lg_name);
1322118f387SNathan Whitehorn 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
1332118f387SNathan Whitehorn 	gctl_ro_param(r, "scheme", -1, scheme);
1342118f387SNathan Whitehorn 	gctl_ro_param(r, "verb", -1, "create");
1352118f387SNathan Whitehorn 
1362118f387SNathan Whitehorn 	errstr = gctl_issue(r);
1372118f387SNathan Whitehorn 	if (errstr != NULL && errstr[0] != '\0') {
1382118f387SNathan Whitehorn 		gpart_show_error("Error", NULL, errstr);
1392118f387SNathan Whitehorn 		gctl_free(r);
1402118f387SNathan Whitehorn 		scheme = NULL;
1412118f387SNathan Whitehorn 		goto schememenu;
1422118f387SNathan Whitehorn 	}
1432118f387SNathan Whitehorn 	gctl_free(r);
1442118f387SNathan Whitehorn 
1452118f387SNathan Whitehorn 	if (bootcode_path(scheme) != NULL)
1462118f387SNathan Whitehorn 		get_part_metadata(lg_name, 1)->bootcode = 1;
1472118f387SNathan Whitehorn 	return (0);
1482118f387SNathan Whitehorn }
1492118f387SNathan Whitehorn 
1502118f387SNathan Whitehorn static void
1512118f387SNathan Whitehorn gpart_activate(struct gprovider *pp)
1522118f387SNathan Whitehorn {
1532118f387SNathan Whitehorn 	struct gconfig *gc;
1542118f387SNathan Whitehorn 	struct gctl_req *r;
1552118f387SNathan Whitehorn 	const char *errstr, *scheme;
1562118f387SNathan Whitehorn 	const char *attribute = NULL;
1572118f387SNathan Whitehorn 	intmax_t idx;
1582118f387SNathan Whitehorn 
1592118f387SNathan Whitehorn 	/*
1602118f387SNathan Whitehorn 	 * Some partition schemes need this partition to be marked 'active'
1612118f387SNathan Whitehorn 	 * for it to be bootable.
1622118f387SNathan Whitehorn 	 */
1632118f387SNathan Whitehorn 	LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) {
1642118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "scheme") == 0) {
1652118f387SNathan Whitehorn 			scheme = gc->lg_val;
1662118f387SNathan Whitehorn 			break;
1672118f387SNathan Whitehorn 		}
1682118f387SNathan Whitehorn 	}
1692118f387SNathan Whitehorn 
1702118f387SNathan Whitehorn 	if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "EBR") == 0 ||
1712118f387SNathan Whitehorn 	    strcmp(scheme, "PC98") == 0)
1722118f387SNathan Whitehorn 		attribute = "active";
1732118f387SNathan Whitehorn 	else
1742118f387SNathan Whitehorn 		return;
1752118f387SNathan Whitehorn 
1762118f387SNathan Whitehorn 	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
1772118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "index") == 0) {
1782118f387SNathan Whitehorn 			idx = atoi(gc->lg_val);
1792118f387SNathan Whitehorn 			break;
1802118f387SNathan Whitehorn 		}
1812118f387SNathan Whitehorn 	}
1822118f387SNathan Whitehorn 
1832118f387SNathan Whitehorn 	r = gctl_get_handle();
1842118f387SNathan Whitehorn 	gctl_ro_param(r, "class", -1, "PART");
1852118f387SNathan Whitehorn 	gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name);
1862118f387SNathan Whitehorn 	gctl_ro_param(r, "verb", -1, "set");
1872118f387SNathan Whitehorn 	gctl_ro_param(r, "attrib", -1, attribute);
1882118f387SNathan Whitehorn 	gctl_ro_param(r, "index", sizeof(idx), &idx);
1892118f387SNathan Whitehorn 
1902118f387SNathan Whitehorn 	errstr = gctl_issue(r);
1912118f387SNathan Whitehorn 	if (errstr != NULL && errstr[0] != '\0')
1922118f387SNathan Whitehorn 		gpart_show_error("Error", "Error marking partition active:",
1932118f387SNathan Whitehorn 		    errstr);
1942118f387SNathan Whitehorn 	gctl_free(r);
1952118f387SNathan Whitehorn }
1962118f387SNathan Whitehorn 
1972118f387SNathan Whitehorn static void
1982118f387SNathan Whitehorn gpart_bootcode(struct ggeom *gp)
1992118f387SNathan Whitehorn {
2002118f387SNathan Whitehorn 	const char *bootcode;
2012118f387SNathan Whitehorn 	struct gconfig *gc;
2022118f387SNathan Whitehorn 	struct gctl_req *r;
2032118f387SNathan Whitehorn 	const char *errstr, *scheme;
2042118f387SNathan Whitehorn 	uint8_t *boot;
2052118f387SNathan Whitehorn 	size_t bootsize, bytes;
2062118f387SNathan Whitehorn 	int bootfd;
2072118f387SNathan Whitehorn 
2082118f387SNathan Whitehorn 	/*
2092118f387SNathan Whitehorn 	 * Write default bootcode to the newly partitioned disk, if that
2102118f387SNathan Whitehorn 	 * applies on this platform.
2112118f387SNathan Whitehorn 	 */
2122118f387SNathan Whitehorn 	LIST_FOREACH(gc, &gp->lg_config, lg_config) {
2132118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "scheme") == 0) {
2142118f387SNathan Whitehorn 			scheme = gc->lg_val;
2152118f387SNathan Whitehorn 			break;
2162118f387SNathan Whitehorn 		}
2172118f387SNathan Whitehorn 	}
2182118f387SNathan Whitehorn 
2192118f387SNathan Whitehorn 	bootcode = bootcode_path(scheme);
2202118f387SNathan Whitehorn 	if (bootcode == NULL)
2212118f387SNathan Whitehorn 		return;
2222118f387SNathan Whitehorn 
2232118f387SNathan Whitehorn 	bootfd = open(bootcode, O_RDONLY);
2242118f387SNathan Whitehorn 	if (bootfd <= 0) {
2252118f387SNathan Whitehorn 		dialog_msgbox("Bootcode Error", strerror(errno), 0, 0,
2262118f387SNathan Whitehorn 		    TRUE);
2272118f387SNathan Whitehorn 		return;
2282118f387SNathan Whitehorn 	}
2292118f387SNathan Whitehorn 
2302118f387SNathan Whitehorn 	bootsize = lseek(bootfd, 0, SEEK_END);
2312118f387SNathan Whitehorn 	boot = malloc(bootsize);
2322118f387SNathan Whitehorn 	lseek(bootfd, 0, SEEK_SET);
2332118f387SNathan Whitehorn 	bytes = 0;
2342118f387SNathan Whitehorn 	while (bytes < bootsize)
2352118f387SNathan Whitehorn 		bytes += read(bootfd, boot + bytes, bootsize - bytes);
2362118f387SNathan Whitehorn 	close(bootfd);
2372118f387SNathan Whitehorn 
2382118f387SNathan Whitehorn 	r = gctl_get_handle();
2392118f387SNathan Whitehorn 	gctl_ro_param(r, "class", -1, "PART");
2402118f387SNathan Whitehorn 	gctl_ro_param(r, "arg0", -1, gp->lg_name);
2412118f387SNathan Whitehorn 	gctl_ro_param(r, "verb", -1, "bootcode");
2422118f387SNathan Whitehorn 	gctl_ro_param(r, "bootcode", bootsize, boot);
2432118f387SNathan Whitehorn 
2442118f387SNathan Whitehorn 	errstr = gctl_issue(r);
2452118f387SNathan Whitehorn 	if (errstr != NULL && errstr[0] != '\0')
2462118f387SNathan Whitehorn 		gpart_show_error("Bootcode Error", NULL, errstr);
2472118f387SNathan Whitehorn 	gctl_free(r);
2482118f387SNathan Whitehorn 	free(boot);
2492118f387SNathan Whitehorn }
2502118f387SNathan Whitehorn 
2512118f387SNathan Whitehorn static void
2522118f387SNathan Whitehorn gpart_partcode(struct gprovider *pp)
2532118f387SNathan Whitehorn {
2542118f387SNathan Whitehorn 	struct gconfig *gc;
2552118f387SNathan Whitehorn 	const char *scheme;
2562118f387SNathan Whitehorn 	const char *indexstr;
2572118f387SNathan Whitehorn 	char message[255], command[255];
2582118f387SNathan Whitehorn 
2592118f387SNathan Whitehorn 	LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) {
2602118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "scheme") == 0) {
2612118f387SNathan Whitehorn 			scheme = gc->lg_val;
2622118f387SNathan Whitehorn 			break;
2632118f387SNathan Whitehorn 		}
2642118f387SNathan Whitehorn 	}
2652118f387SNathan Whitehorn 
2662118f387SNathan Whitehorn 	/* Make sure this partition scheme needs partcode on this platform */
2672118f387SNathan Whitehorn 	if (partcode_path(scheme) == NULL)
2682118f387SNathan Whitehorn 		return;
2692118f387SNathan Whitehorn 
2702118f387SNathan Whitehorn 	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
2712118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "index") == 0) {
2722118f387SNathan Whitehorn 			indexstr = gc->lg_val;
2732118f387SNathan Whitehorn 			break;
2742118f387SNathan Whitehorn 		}
2752118f387SNathan Whitehorn 	}
2762118f387SNathan Whitehorn 
2772118f387SNathan Whitehorn 	/* Shell out to gpart for partcode for now */
2782118f387SNathan Whitehorn 	sprintf(command, "gpart bootcode -p %s -i %s %s",
2792118f387SNathan Whitehorn 	    partcode_path(scheme), indexstr, pp->lg_geom->lg_name);
2802118f387SNathan Whitehorn 	if (system(command) != 0) {
2812118f387SNathan Whitehorn 		sprintf(message, "Error installing partcode on partition %s",
2822118f387SNathan Whitehorn 		    pp->lg_name);
2832118f387SNathan Whitehorn 		dialog_msgbox("Error", message, 0, 0, TRUE);
2842118f387SNathan Whitehorn 	}
2852118f387SNathan Whitehorn }
2862118f387SNathan Whitehorn 
2872118f387SNathan Whitehorn void
2882118f387SNathan Whitehorn gpart_destroy(struct ggeom *lg_geom, int force)
2892118f387SNathan Whitehorn {
2902118f387SNathan Whitehorn 	struct gprovider *pp;
2912118f387SNathan Whitehorn 	struct gctl_req *r;
2922118f387SNathan Whitehorn 	const char *errstr;
2932118f387SNathan Whitehorn 
2942118f387SNathan Whitehorn 	/* Begin with the hosing: delete all partitions */
2952118f387SNathan Whitehorn 	LIST_FOREACH(pp, &lg_geom->lg_provider, lg_provider)
2962118f387SNathan Whitehorn 		gpart_delete(pp);
2972118f387SNathan Whitehorn 
2982118f387SNathan Whitehorn 	/* Now destroy the geom itself */
2992118f387SNathan Whitehorn 	r = gctl_get_handle();
3002118f387SNathan Whitehorn 	gctl_ro_param(r, "class", -1, "PART");
3012118f387SNathan Whitehorn 	gctl_ro_param(r, "arg0", -1, lg_geom->lg_name);
3022118f387SNathan Whitehorn 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
3032118f387SNathan Whitehorn 	gctl_ro_param(r, "verb", -1, "destroy");
3042118f387SNathan Whitehorn 	errstr = gctl_issue(r);
3052118f387SNathan Whitehorn 	if (errstr != NULL && errstr[0] != '\0')
3062118f387SNathan Whitehorn 		gpart_show_error("Error", NULL, errstr);
3072118f387SNathan Whitehorn 	gctl_free(r);
3082118f387SNathan Whitehorn 
3092118f387SNathan Whitehorn 	/* If asked, commit the change */
3102118f387SNathan Whitehorn 	if (force) {
3112118f387SNathan Whitehorn 		r = gctl_get_handle();
3122118f387SNathan Whitehorn 		gctl_ro_param(r, "class", -1, "PART");
3132118f387SNathan Whitehorn 		gctl_ro_param(r, "arg0", -1, lg_geom->lg_name);
3142118f387SNathan Whitehorn 		gctl_ro_param(r, "verb", -1, "commit");
3152118f387SNathan Whitehorn 		errstr = gctl_issue(r);
3162118f387SNathan Whitehorn 		if (errstr != NULL && errstr[0] != '\0')
3172118f387SNathan Whitehorn 			gpart_show_error("Error", NULL, errstr);
3182118f387SNathan Whitehorn 		gctl_free(r);
3192118f387SNathan Whitehorn 	}
3202118f387SNathan Whitehorn 
3212118f387SNathan Whitehorn 	/* And any metadata associated with the partition scheme itself */
3222118f387SNathan Whitehorn 	delete_part_metadata(lg_geom->lg_name);
3232118f387SNathan Whitehorn }
3242118f387SNathan Whitehorn 
3252118f387SNathan Whitehorn void
3262118f387SNathan Whitehorn gpart_edit(struct gprovider *pp)
3272118f387SNathan Whitehorn {
3282118f387SNathan Whitehorn 	struct gctl_req *r;
3292118f387SNathan Whitehorn 	struct gconfig *gc;
3302118f387SNathan Whitehorn 	struct gconsumer *cp;
3312118f387SNathan Whitehorn 	struct ggeom *geom;
3322118f387SNathan Whitehorn 	const char *errstr, *oldtype, *scheme;
3332118f387SNathan Whitehorn 	struct partition_metadata *md;
3342118f387SNathan Whitehorn 	char sizestr[32];
3352118f387SNathan Whitehorn 	intmax_t idx;
3362118f387SNathan Whitehorn 	int hadlabel, choice, junk, nitems;
3372118f387SNathan Whitehorn 	unsigned i;
3382118f387SNathan Whitehorn 
3392118f387SNathan Whitehorn 	DIALOG_FORMITEM items[] = {
3402118f387SNathan Whitehorn 		{0, "Type:", 5, 0, 0, FALSE, "", 11, 0, 12, 15, 0,
3412118f387SNathan Whitehorn 		    FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-swap)",
3422118f387SNathan Whitehorn 		    FALSE},
3432118f387SNathan Whitehorn 		{0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 0, 0,
3442118f387SNathan Whitehorn 		    FALSE, "Partition size. Append K, M, G for kilobytes, "
3452118f387SNathan Whitehorn 		    "megabytes or gigabytes.", FALSE},
3462118f387SNathan Whitehorn 		{0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0,
3472118f387SNathan Whitehorn 		    FALSE, "Path at which to mount this partition (leave blank "
3482118f387SNathan Whitehorn 		    "for swap, set to / for root filesystem)", FALSE},
3492118f387SNathan Whitehorn 		{0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE,
3502118f387SNathan Whitehorn 		    "Partition name. Not all partition schemes support this.",
3512118f387SNathan Whitehorn 		    FALSE},
3522118f387SNathan Whitehorn 	};
3532118f387SNathan Whitehorn 
3542118f387SNathan Whitehorn 	/*
3552118f387SNathan Whitehorn 	 * Find the PART geom we are manipulating. This may be a consumer of
3562118f387SNathan Whitehorn 	 * this provider, or its parent. Check the consumer case first.
3572118f387SNathan Whitehorn 	 */
3582118f387SNathan Whitehorn 	geom = NULL;
3592118f387SNathan Whitehorn 	LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
3602118f387SNathan Whitehorn 		if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
3612118f387SNathan Whitehorn 			char message[512];
3622118f387SNathan Whitehorn 			/*
3632118f387SNathan Whitehorn 			 * The PART object is a consumer, so the user wants to
3642118f387SNathan Whitehorn 			 * edit the partition table. gpart doesn't really
3652118f387SNathan Whitehorn 			 * support this, so we have to hose the whole table
3662118f387SNathan Whitehorn 			 * first.
3672118f387SNathan Whitehorn 			 */
3682118f387SNathan Whitehorn 
3692118f387SNathan Whitehorn 			sprintf(message, "Changing the partition scheme on "
3702118f387SNathan Whitehorn 			    "this disk (%s) requires deleting all existing "
3712118f387SNathan Whitehorn 			    "partitions on this drive. This will PERMANENTLY "
3722118f387SNathan Whitehorn 			    "ERASE any data stored here. Are you sure you want "
3732118f387SNathan Whitehorn 			    "to proceed?", cp->lg_geom->lg_name);
3742118f387SNathan Whitehorn 			dialog_vars.defaultno = TRUE;
3752118f387SNathan Whitehorn 			choice = dialog_yesno("Warning", message, 0, 0);
3762118f387SNathan Whitehorn 			dialog_vars.defaultno = FALSE;
3772118f387SNathan Whitehorn 
3782118f387SNathan Whitehorn 			if (choice == 1) /* cancel */
3792118f387SNathan Whitehorn 				return;
3802118f387SNathan Whitehorn 
3812118f387SNathan Whitehorn 			/* Destroy the geom and all sub-partitions */
3822118f387SNathan Whitehorn 			gpart_destroy(cp->lg_geom, 0);
3832118f387SNathan Whitehorn 
3842118f387SNathan Whitehorn 			/* Now re-partition and return */
3852118f387SNathan Whitehorn 			gpart_partition(cp->lg_geom->lg_name, NULL);
3862118f387SNathan Whitehorn 			return;
3872118f387SNathan Whitehorn 		}
3882118f387SNathan Whitehorn 
3892118f387SNathan Whitehorn 	if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
3902118f387SNathan Whitehorn 		geom = pp->lg_geom;
3912118f387SNathan Whitehorn 
3922118f387SNathan Whitehorn 	if (geom == NULL) {
3932118f387SNathan Whitehorn 		/* Disk not partitioned, so partition it */
3942118f387SNathan Whitehorn 		gpart_partition(pp->lg_geom->lg_name, NULL);
3952118f387SNathan Whitehorn 		return;
3962118f387SNathan Whitehorn 	}
3972118f387SNathan Whitehorn 
3982118f387SNathan Whitehorn 	LIST_FOREACH(gc, &geom->lg_config, lg_config) {
3992118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "scheme") == 0) {
4002118f387SNathan Whitehorn 			scheme = gc->lg_val;
4012118f387SNathan Whitehorn 			break;
4022118f387SNathan Whitehorn 		}
4032118f387SNathan Whitehorn 	}
4042118f387SNathan Whitehorn 
405*c67f41d0SNathan Whitehorn 	nitems = scheme_supports_labels(scheme) ? 4 : 3;
4062118f387SNathan Whitehorn 
4072118f387SNathan Whitehorn 	/* Edit editable parameters of a partition */
4082118f387SNathan Whitehorn 	hadlabel = 0;
4092118f387SNathan Whitehorn 	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
4102118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "type") == 0) {
4112118f387SNathan Whitehorn 			oldtype = gc->lg_val;
4122118f387SNathan Whitehorn 			items[0].text = gc->lg_val;
4132118f387SNathan Whitehorn 		}
4142118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "label") == 0 && gc->lg_val != NULL) {
4152118f387SNathan Whitehorn 			hadlabel = 1;
4162118f387SNathan Whitehorn 			items[3].text = gc->lg_val;
4172118f387SNathan Whitehorn 		}
4182118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "index") == 0)
4192118f387SNathan Whitehorn 			idx = atoi(gc->lg_val);
4202118f387SNathan Whitehorn 	}
4212118f387SNathan Whitehorn 
4222118f387SNathan Whitehorn 	TAILQ_FOREACH(md, &part_metadata, metadata) {
4232118f387SNathan Whitehorn 		if (md->name != NULL && strcmp(md->name, pp->lg_name) == 0) {
4242118f387SNathan Whitehorn 			if (md->fstab != NULL)
4252118f387SNathan Whitehorn 				items[2].text = md->fstab->fs_file;
4262118f387SNathan Whitehorn 			break;
4272118f387SNathan Whitehorn 		}
4282118f387SNathan Whitehorn 	}
4292118f387SNathan Whitehorn 
4302118f387SNathan Whitehorn 	humanize_number(sizestr, 7, pp->lg_mediasize, "B", HN_AUTOSCALE,
4312118f387SNathan Whitehorn 	    HN_NOSPACE | HN_DECIMAL);
4322118f387SNathan Whitehorn 	items[1].text = sizestr;
4332118f387SNathan Whitehorn 
4342118f387SNathan Whitehorn editpart:
4352118f387SNathan Whitehorn 	choice = dlg_form("Edit Partition", "", 0, 0, 0, nitems, items, &junk);
4362118f387SNathan Whitehorn 
4372118f387SNathan Whitehorn 	if (choice) /* Cancel pressed */
4382118f387SNathan Whitehorn 		return;
4392118f387SNathan Whitehorn 
4402118f387SNathan Whitehorn 	/* Check if the label has a / in it */
4412118f387SNathan Whitehorn 	if (strchr(items[3].text, '/') != NULL) {
4422118f387SNathan Whitehorn 		dialog_msgbox("Error", "Label contains a /, which is not an "
4432118f387SNathan Whitehorn 		    "allowed character.", 0, 0, TRUE);
4442118f387SNathan Whitehorn 		goto editpart;
4452118f387SNathan Whitehorn 	}
4462118f387SNathan Whitehorn 
4472118f387SNathan Whitehorn 	if (strncmp(items[0].text, "freebsd-", 8) != 0 &&
4482118f387SNathan Whitehorn 	    items[0].text[0] != '\0') {
4492118f387SNathan Whitehorn 		char message[512];
4502118f387SNathan Whitehorn 
4512118f387SNathan Whitehorn 		sprintf(message, "Cannot mount unknown file system %s!\n",
4522118f387SNathan Whitehorn 		    items[0].text);
4532118f387SNathan Whitehorn 		dialog_msgbox("Error", message, 0, 0, TRUE);
4542118f387SNathan Whitehorn 		goto editpart;
4552118f387SNathan Whitehorn 	}
4562118f387SNathan Whitehorn 
4572118f387SNathan Whitehorn 	r = gctl_get_handle();
4582118f387SNathan Whitehorn 	gctl_ro_param(r, "class", -1, "PART");
4592118f387SNathan Whitehorn 	gctl_ro_param(r, "arg0", -1, geom->lg_name);
4602118f387SNathan Whitehorn 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
4612118f387SNathan Whitehorn 	gctl_ro_param(r, "verb", -1, "modify");
4622118f387SNathan Whitehorn 	gctl_ro_param(r, "index", sizeof(idx), &idx);
4632118f387SNathan Whitehorn 	if (hadlabel || items[3].text[0] != '\0')
4642118f387SNathan Whitehorn 		gctl_ro_param(r, "label", -1, items[3].text);
4652118f387SNathan Whitehorn 	gctl_ro_param(r, "type", -1, items[0].text);
4662118f387SNathan Whitehorn 	errstr = gctl_issue(r);
4672118f387SNathan Whitehorn 	if (errstr != NULL && errstr[0] != '\0') {
4682118f387SNathan Whitehorn 		gpart_show_error("Error", NULL, errstr);
4692118f387SNathan Whitehorn 		gctl_free(r);
4702118f387SNathan Whitehorn 		goto editpart;
4712118f387SNathan Whitehorn 	}
4722118f387SNathan Whitehorn 	gctl_free(r);
4732118f387SNathan Whitehorn 
4742118f387SNathan Whitehorn 	set_default_part_metadata(pp->lg_name, scheme, items[0].text,
4752118f387SNathan Whitehorn 	    items[2].text, strcmp(oldtype, items[0].text) != 0);
4762118f387SNathan Whitehorn 
4772118f387SNathan Whitehorn 	for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++)
4782118f387SNathan Whitehorn 		if (items[i].text_free)
4792118f387SNathan Whitehorn 			free(items[i].text);
4802118f387SNathan Whitehorn }
4812118f387SNathan Whitehorn 
4822118f387SNathan Whitehorn void
4832118f387SNathan Whitehorn set_default_part_metadata(const char *name, const char *scheme,
4842118f387SNathan Whitehorn     const char *type, const char *mountpoint, int newfs)
4852118f387SNathan Whitehorn {
4862118f387SNathan Whitehorn 	struct partition_metadata *md;
4872118f387SNathan Whitehorn 
4882118f387SNathan Whitehorn 	/* Set part metadata */
4892118f387SNathan Whitehorn 	md = get_part_metadata(name, 1);
4902118f387SNathan Whitehorn 
4912118f387SNathan Whitehorn 	if (newfs) {
4922118f387SNathan Whitehorn 		if (md->newfs != NULL) {
4932118f387SNathan Whitehorn 			free(md->newfs);
4942118f387SNathan Whitehorn 			md->newfs = NULL;
4952118f387SNathan Whitehorn 		}
4962118f387SNathan Whitehorn 
4972118f387SNathan Whitehorn 		if (strcmp(type, "freebsd-ufs") == 0) {
4982118f387SNathan Whitehorn 			md->newfs = malloc(255);
4992118f387SNathan Whitehorn 			sprintf(md->newfs, "newfs /dev/%s", name);
5002118f387SNathan Whitehorn 		}
5012118f387SNathan Whitehorn 	}
5022118f387SNathan Whitehorn 
5032118f387SNathan Whitehorn 	if (strcmp(type, "freebsd-swap") == 0)
5042118f387SNathan Whitehorn 		mountpoint = "none";
5052118f387SNathan Whitehorn 	if (strcmp(type, "freebsd-boot") == 0)
5062118f387SNathan Whitehorn 		md->bootcode = 1;
5072118f387SNathan Whitehorn 
5082118f387SNathan Whitehorn 	/* VTOC8 needs partcode in UFS partitions */
5092118f387SNathan Whitehorn 	if (strcmp(scheme, "VTOC8") == 0 && strcmp(type, "freebsd-ufs") == 0)
5102118f387SNathan Whitehorn 		md->bootcode = 1;
5112118f387SNathan Whitehorn 
5122118f387SNathan Whitehorn 	if (mountpoint == NULL || mountpoint[0] == '\0') {
5132118f387SNathan Whitehorn 		if (md->fstab != NULL) {
5142118f387SNathan Whitehorn 			free(md->fstab->fs_spec);
5152118f387SNathan Whitehorn 			free(md->fstab->fs_file);
5162118f387SNathan Whitehorn 			free(md->fstab->fs_vfstype);
5172118f387SNathan Whitehorn 			free(md->fstab->fs_mntops);
5182118f387SNathan Whitehorn 			free(md->fstab->fs_type);
5192118f387SNathan Whitehorn 			free(md->fstab);
5202118f387SNathan Whitehorn 			md->fstab = NULL;
5212118f387SNathan Whitehorn 		}
5222118f387SNathan Whitehorn 	} else {
5232118f387SNathan Whitehorn 		if (md->fstab == NULL) {
5242118f387SNathan Whitehorn 			md->fstab = malloc(sizeof(struct fstab));
5252118f387SNathan Whitehorn 		} else {
5262118f387SNathan Whitehorn 			free(md->fstab->fs_spec);
5272118f387SNathan Whitehorn 			free(md->fstab->fs_file);
5282118f387SNathan Whitehorn 			free(md->fstab->fs_vfstype);
5292118f387SNathan Whitehorn 			free(md->fstab->fs_mntops);
5302118f387SNathan Whitehorn 			free(md->fstab->fs_type);
5312118f387SNathan Whitehorn 		}
5322118f387SNathan Whitehorn 		md->fstab->fs_spec = malloc(strlen(name) + 6);
5332118f387SNathan Whitehorn 		sprintf(md->fstab->fs_spec, "/dev/%s", name);
5342118f387SNathan Whitehorn 		md->fstab->fs_file = strdup(mountpoint);
5352118f387SNathan Whitehorn 		/* Get VFS from text after freebsd-, if possible */
5362118f387SNathan Whitehorn 		if (strncmp("freebsd-", type, 8))
5372118f387SNathan Whitehorn 			md->fstab->fs_vfstype = strdup(&type[8]);
5382118f387SNathan Whitehorn 		else
5392118f387SNathan Whitehorn 			md->fstab->fs_vfstype = strdup(type); /* Guess */
5402118f387SNathan Whitehorn 		md->fstab->fs_vfstype = strdup(&type[8]);
5412118f387SNathan Whitehorn 		if (strcmp(type, "freebsd-swap") == 0) {
5422118f387SNathan Whitehorn 			md->fstab->fs_type = strdup(FSTAB_SW);
5432118f387SNathan Whitehorn 			md->fstab->fs_freq = 0;
5442118f387SNathan Whitehorn 			md->fstab->fs_passno = 0;
5452118f387SNathan Whitehorn 		} else {
5462118f387SNathan Whitehorn 			md->fstab->fs_type = strdup(FSTAB_RW);
5472118f387SNathan Whitehorn 			if (strcmp(mountpoint, "/") == 0) {
5482118f387SNathan Whitehorn 				md->fstab->fs_freq = 1;
5492118f387SNathan Whitehorn 				md->fstab->fs_passno = 1;
5502118f387SNathan Whitehorn 			} else {
5512118f387SNathan Whitehorn 				md->fstab->fs_freq = 2;
5522118f387SNathan Whitehorn 				md->fstab->fs_passno = 2;
5532118f387SNathan Whitehorn 			}
5542118f387SNathan Whitehorn 		}
5552118f387SNathan Whitehorn 		md->fstab->fs_mntops = strdup(md->fstab->fs_type);
5562118f387SNathan Whitehorn 	}
5572118f387SNathan Whitehorn }
5582118f387SNathan Whitehorn 
5592118f387SNathan Whitehorn static
5602118f387SNathan Whitehorn int part_compare(const void *xa, const void *xb)
5612118f387SNathan Whitehorn {
5622118f387SNathan Whitehorn 	struct gprovider **a = (struct gprovider **)xa;
5632118f387SNathan Whitehorn 	struct gprovider **b = (struct gprovider **)xb;
5642118f387SNathan Whitehorn 	intmax_t astart, bstart;
5652118f387SNathan Whitehorn 	struct gconfig *gc;
5662118f387SNathan Whitehorn 
5672118f387SNathan Whitehorn 	astart = bstart = 0;
5682118f387SNathan Whitehorn 	LIST_FOREACH(gc, &(*a)->lg_config, lg_config)
5692118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "start") == 0) {
5702118f387SNathan Whitehorn 			astart = strtoimax(gc->lg_val, NULL, 0);
5712118f387SNathan Whitehorn 			break;
5722118f387SNathan Whitehorn 		}
5732118f387SNathan Whitehorn 	LIST_FOREACH(gc, &(*b)->lg_config, lg_config)
5742118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "start") == 0) {
5752118f387SNathan Whitehorn 			bstart = strtoimax(gc->lg_val, NULL, 0);
5762118f387SNathan Whitehorn 			break;
5772118f387SNathan Whitehorn 		}
5782118f387SNathan Whitehorn 
5792118f387SNathan Whitehorn 	if (astart < bstart)
5802118f387SNathan Whitehorn 		return -1;
5812118f387SNathan Whitehorn 	else if (astart > bstart)
5822118f387SNathan Whitehorn 		return 1;
5832118f387SNathan Whitehorn 	else
5842118f387SNathan Whitehorn 		return 0;
5852118f387SNathan Whitehorn }
5862118f387SNathan Whitehorn 
5872118f387SNathan Whitehorn intmax_t
5882118f387SNathan Whitehorn gpart_max_free(struct ggeom *geom, intmax_t *npartstart)
5892118f387SNathan Whitehorn {
5902118f387SNathan Whitehorn 	struct gconfig *gc;
5912118f387SNathan Whitehorn 	struct gprovider *pp, **providers;
5922118f387SNathan Whitehorn 	intmax_t lastend;
5932118f387SNathan Whitehorn 	intmax_t start, end;
5942118f387SNathan Whitehorn 	intmax_t maxsize, maxstart;
5952118f387SNathan Whitehorn 	intmax_t partstart, partend;
5962118f387SNathan Whitehorn 	int i, nparts;
5972118f387SNathan Whitehorn 
5982118f387SNathan Whitehorn 	/* Now get the maximum free size and free start */
5992118f387SNathan Whitehorn 	start = end = 0;
6002118f387SNathan Whitehorn 	LIST_FOREACH(gc, &geom->lg_config, lg_config) {
6012118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "first") == 0)
6022118f387SNathan Whitehorn 			start = strtoimax(gc->lg_val, NULL, 0);
6032118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "last") == 0)
6042118f387SNathan Whitehorn 			end = strtoimax(gc->lg_val, NULL, 0);
6052118f387SNathan Whitehorn 	}
6062118f387SNathan Whitehorn 
6072118f387SNathan Whitehorn 	i = nparts = 0;
6082118f387SNathan Whitehorn 	LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
6092118f387SNathan Whitehorn 		nparts++;
6102118f387SNathan Whitehorn 	providers = calloc(nparts, sizeof(providers[0]));
6112118f387SNathan Whitehorn 	LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
6122118f387SNathan Whitehorn 		providers[i++] = pp;
6132118f387SNathan Whitehorn 	qsort(providers, nparts, sizeof(providers[0]), part_compare);
6142118f387SNathan Whitehorn 
6152118f387SNathan Whitehorn 	lastend = start - 1;
6162118f387SNathan Whitehorn 	maxsize = 0;
6172118f387SNathan Whitehorn 	for (i = 0; i < nparts; i++) {
6182118f387SNathan Whitehorn 		pp = providers[i];
6192118f387SNathan Whitehorn 
6202118f387SNathan Whitehorn 		LIST_FOREACH(gc, &pp->lg_config, lg_config) {
6212118f387SNathan Whitehorn 			if (strcmp(gc->lg_name, "start") == 0)
6222118f387SNathan Whitehorn 				partstart = strtoimax(gc->lg_val, NULL, 0);
6232118f387SNathan Whitehorn 			if (strcmp(gc->lg_name, "end") == 0)
6242118f387SNathan Whitehorn 				partend = strtoimax(gc->lg_val, NULL, 0);
6252118f387SNathan Whitehorn 		}
6262118f387SNathan Whitehorn 
6272118f387SNathan Whitehorn 		if (partstart - lastend > maxsize) {
6282118f387SNathan Whitehorn 			maxsize = partstart - lastend - 1;
6292118f387SNathan Whitehorn 			maxstart = lastend + 1;
6302118f387SNathan Whitehorn 		}
6312118f387SNathan Whitehorn 
6322118f387SNathan Whitehorn 		lastend = partend;
6332118f387SNathan Whitehorn 	}
6342118f387SNathan Whitehorn 
6352118f387SNathan Whitehorn 	if (end - lastend > maxsize) {
6362118f387SNathan Whitehorn 		maxsize = end - lastend - 1;
6372118f387SNathan Whitehorn 		maxstart = lastend + 1;
6382118f387SNathan Whitehorn 	}
6392118f387SNathan Whitehorn 
6402118f387SNathan Whitehorn 	pp = LIST_FIRST(&geom->lg_consumer)->lg_provider;
6412118f387SNathan Whitehorn 
6422118f387SNathan Whitehorn 	/* Compute beginning of new partition and maximum available space */
6432118f387SNathan Whitehorn 	if (pp->lg_stripesize > 0 &&
6442118f387SNathan Whitehorn 	    (maxstart*pp->lg_sectorsize % pp->lg_stripesize) != 0) {
6452118f387SNathan Whitehorn 		intmax_t offset = (pp->lg_stripesize -
6462118f387SNathan Whitehorn 		    ((maxstart*pp->lg_sectorsize) % pp->lg_stripesize)) /
6472118f387SNathan Whitehorn 		    pp->lg_sectorsize;
6482118f387SNathan Whitehorn 		maxstart += offset;
6492118f387SNathan Whitehorn 		maxsize -= offset;
6502118f387SNathan Whitehorn 	}
6512118f387SNathan Whitehorn 
6522118f387SNathan Whitehorn 	if (npartstart != NULL)
6532118f387SNathan Whitehorn 		*npartstart = maxstart;
6542118f387SNathan Whitehorn 
6552118f387SNathan Whitehorn 	return (maxsize);
6562118f387SNathan Whitehorn }
6572118f387SNathan Whitehorn 
6582118f387SNathan Whitehorn void
6592118f387SNathan Whitehorn gpart_create(struct gprovider *pp, char *default_type, char *default_size,
6602118f387SNathan Whitehorn      char *default_mountpoint, char **partname, int interactive)
6612118f387SNathan Whitehorn {
6622118f387SNathan Whitehorn 	struct gctl_req *r;
6632118f387SNathan Whitehorn 	struct gconfig *gc;
6642118f387SNathan Whitehorn 	struct gconsumer *cp;
6652118f387SNathan Whitehorn 	struct ggeom *geom;
6662118f387SNathan Whitehorn 	const char *errstr, *scheme;
6672118f387SNathan Whitehorn 	char sizestr[32], startstr[32], output[64];
6682118f387SNathan Whitehorn 	intmax_t maxsize, size, sector, firstfree, stripe;
6692118f387SNathan Whitehorn 	uint64_t bytes;
6702118f387SNathan Whitehorn 	int nitems, choice, junk;
6712118f387SNathan Whitehorn 	unsigned i;
6722118f387SNathan Whitehorn 
6732118f387SNathan Whitehorn 	DIALOG_FORMITEM items[] = {
6742118f387SNathan Whitehorn 		{0, "Type:", 5, 0, 0, FALSE, "freebsd-ufs", 11, 0, 12, 15, 0,
6752118f387SNathan Whitehorn 		    FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-swap)",
6762118f387SNathan Whitehorn 		    FALSE},
6772118f387SNathan Whitehorn 		{0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 15, 0,
6782118f387SNathan Whitehorn 		    FALSE, "Partition size. Append K, M, G for kilobytes, "
6792118f387SNathan Whitehorn 		    "megabytes or gigabytes.", FALSE},
6802118f387SNathan Whitehorn 		{0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0,
6812118f387SNathan Whitehorn 		    FALSE, "Path at which to mount partition (blank for "
6822118f387SNathan Whitehorn 		    "swap, / for root filesystem)", FALSE},
6832118f387SNathan Whitehorn 		{0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE,
6842118f387SNathan Whitehorn 		    "Partition name. Not all partition schemes support this.",
6852118f387SNathan Whitehorn 		    FALSE},
6862118f387SNathan Whitehorn 	};
6872118f387SNathan Whitehorn 
6882118f387SNathan Whitehorn 	if (partname != NULL)
6892118f387SNathan Whitehorn 		*partname = NULL;
6902118f387SNathan Whitehorn 
6912118f387SNathan Whitehorn 	/* Record sector and stripe sizes */
6922118f387SNathan Whitehorn 	sector = pp->lg_sectorsize;
6932118f387SNathan Whitehorn 	stripe = pp->lg_stripesize;
6942118f387SNathan Whitehorn 
6952118f387SNathan Whitehorn 	/*
6962118f387SNathan Whitehorn 	 * Find the PART geom we are manipulating. This may be a consumer of
6972118f387SNathan Whitehorn 	 * this provider, or its parent. Check the consumer case first.
6982118f387SNathan Whitehorn 	 */
6992118f387SNathan Whitehorn 	geom = NULL;
7002118f387SNathan Whitehorn 	LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
7012118f387SNathan Whitehorn 		if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
7022118f387SNathan Whitehorn 			geom = cp->lg_geom;
7032118f387SNathan Whitehorn 			break;
7042118f387SNathan Whitehorn 		}
7052118f387SNathan Whitehorn 
7062118f387SNathan Whitehorn 	if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
7072118f387SNathan Whitehorn 		geom = pp->lg_geom;
7082118f387SNathan Whitehorn 
7092118f387SNathan Whitehorn 	/* Now get the partition scheme */
7102118f387SNathan Whitehorn 	scheme = NULL;
7112118f387SNathan Whitehorn 	if (geom != NULL) {
7122118f387SNathan Whitehorn 		LIST_FOREACH(gc, &geom->lg_config, lg_config)
7132118f387SNathan Whitehorn 			if (strcmp(gc->lg_name, "scheme") == 0)
7142118f387SNathan Whitehorn 				scheme = gc->lg_val;
7152118f387SNathan Whitehorn 	}
7162118f387SNathan Whitehorn 
7172118f387SNathan Whitehorn 	if (geom == NULL || scheme == NULL || strcmp(scheme, "(none)") == 0) {
7182118f387SNathan Whitehorn 		if (gpart_partition(pp->lg_geom->lg_name, NULL) == 0)
7192118f387SNathan Whitehorn 			dialog_msgbox("",
7202118f387SNathan Whitehorn 			    "The partition table has been successfully created."
7212118f387SNathan Whitehorn 			    " Please press Create again to create partitions.",
7222118f387SNathan Whitehorn 			    0, 0, TRUE);
7232118f387SNathan Whitehorn 
7242118f387SNathan Whitehorn 		return;
7252118f387SNathan Whitehorn 	}
7262118f387SNathan Whitehorn 
7272118f387SNathan Whitehorn 	/*
7282118f387SNathan Whitehorn 	 * If we still don't have a geom, either the user has
7292118f387SNathan Whitehorn 	 * canceled partitioning or there has been an error which has already
7302118f387SNathan Whitehorn 	 * been displayed, so bail.
7312118f387SNathan Whitehorn 	 */
7322118f387SNathan Whitehorn 	if (geom == NULL)
7332118f387SNathan Whitehorn 		return;
7342118f387SNathan Whitehorn 
7352118f387SNathan Whitehorn 	maxsize = size = gpart_max_free(geom, &firstfree);
7362118f387SNathan Whitehorn 	if (size <= 0) {
7372118f387SNathan Whitehorn 		dialog_msgbox("Error", "No free space left on device.", 0, 0,
7382118f387SNathan Whitehorn 		    TRUE);
7392118f387SNathan Whitehorn 		return;
7402118f387SNathan Whitehorn 	}
7412118f387SNathan Whitehorn 
7422118f387SNathan Whitehorn 	humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE,
7432118f387SNathan Whitehorn 	    HN_NOSPACE | HN_DECIMAL);
7442118f387SNathan Whitehorn 	items[1].text = sizestr;
7452118f387SNathan Whitehorn 
7462118f387SNathan Whitehorn 	/* Special-case the MBR default type for nested partitions */
7472118f387SNathan Whitehorn 	if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "PC98") == 0)
7482118f387SNathan Whitehorn 		items[0].text = "freebsd";
7492118f387SNathan Whitehorn 
750*c67f41d0SNathan Whitehorn 	nitems = scheme_supports_labels(scheme) ? 4 : 3;
7512118f387SNathan Whitehorn 
7522118f387SNathan Whitehorn 	if (default_type != NULL)
7532118f387SNathan Whitehorn 		items[0].text = default_type;
7542118f387SNathan Whitehorn 	if (default_size != NULL)
7552118f387SNathan Whitehorn 		items[1].text = default_size;
7562118f387SNathan Whitehorn 	if (default_mountpoint != NULL)
7572118f387SNathan Whitehorn 		items[2].text = default_mountpoint;
7582118f387SNathan Whitehorn 
7592118f387SNathan Whitehorn addpartform:
7602118f387SNathan Whitehorn 	if (interactive) {
7612118f387SNathan Whitehorn 		choice = dlg_form("Add Partition", "", 0, 0, 0, nitems,
7622118f387SNathan Whitehorn 		    items, &junk);
7632118f387SNathan Whitehorn 		if (choice) /* Cancel pressed */
7642118f387SNathan Whitehorn 			return;
7652118f387SNathan Whitehorn 	}
7662118f387SNathan Whitehorn 
7672118f387SNathan Whitehorn 	size = maxsize;
7682118f387SNathan Whitehorn 	if (strlen(items[1].text) > 0) {
7692118f387SNathan Whitehorn 		if (expand_number(items[1].text, &bytes) != 0) {
7702118f387SNathan Whitehorn 			char error[512];
7712118f387SNathan Whitehorn 
7722118f387SNathan Whitehorn 			sprintf(error, "Invalid size: %s\n", strerror(errno));
7732118f387SNathan Whitehorn 			dialog_msgbox("Error", error, 0, 0, TRUE);
7742118f387SNathan Whitehorn 			goto addpartform;
7752118f387SNathan Whitehorn 		}
7762118f387SNathan Whitehorn 		size = MIN((intmax_t)(bytes/sector), maxsize);
7772118f387SNathan Whitehorn 	}
7782118f387SNathan Whitehorn 
7792118f387SNathan Whitehorn 	/* Check if the label has a / in it */
7802118f387SNathan Whitehorn 	if (strchr(items[3].text, '/') != NULL) {
7812118f387SNathan Whitehorn 		dialog_msgbox("Error", "Label contains a /, which is not an "
7822118f387SNathan Whitehorn 		    "allowed character.", 0, 0, TRUE);
7832118f387SNathan Whitehorn 		goto addpartform;
7842118f387SNathan Whitehorn 	}
7852118f387SNathan Whitehorn 
7862118f387SNathan Whitehorn 	/* Warn if no mountpoint set */
7872118f387SNathan Whitehorn 	if (strcmp(items[0].text, "freebsd-ufs") == 0 &&
7882118f387SNathan Whitehorn 	    items[2].text[0] != '/') {
7892118f387SNathan Whitehorn 		dialog_vars.defaultno = TRUE;
7902118f387SNathan Whitehorn 		choice = dialog_yesno("Warning",
7912118f387SNathan Whitehorn 		    "This partition does not have a valid mountpoint "
7922118f387SNathan Whitehorn 		    "(for the partition from which you intend to boot the "
7932118f387SNathan Whitehorn 		    "operating system, the mountpoint should be /). Are you "
7942118f387SNathan Whitehorn 		    "sure you want to continue?"
7952118f387SNathan Whitehorn 		, 0, 0);
7962118f387SNathan Whitehorn 		dialog_vars.defaultno = FALSE;
7972118f387SNathan Whitehorn 		if (choice == 1) /* cancel */
7982118f387SNathan Whitehorn 			goto addpartform;
7992118f387SNathan Whitehorn 	}
8002118f387SNathan Whitehorn 
8012118f387SNathan Whitehorn 	/* If this is the root partition, check that this scheme is bootable */
8022118f387SNathan Whitehorn 	if (strcmp(items[2].text, "/") == 0 && !is_scheme_bootable(scheme)) {
8032118f387SNathan Whitehorn 		char message[512];
8042118f387SNathan Whitehorn 		sprintf(message, "This partition scheme (%s) is not bootable "
8052118f387SNathan Whitehorn 		    "on this platform. Are you sure you want to proceed?",
8062118f387SNathan Whitehorn 		    scheme);
8072118f387SNathan Whitehorn 		dialog_vars.defaultno = TRUE;
8082118f387SNathan Whitehorn 		choice = dialog_yesno("Warning", message, 0, 0);
8092118f387SNathan Whitehorn 		dialog_vars.defaultno = FALSE;
8102118f387SNathan Whitehorn 		if (choice == 1) /* cancel */
8112118f387SNathan Whitehorn 			goto addpartform;
8122118f387SNathan Whitehorn 	}
8132118f387SNathan Whitehorn 
8142118f387SNathan Whitehorn 	/*
8152118f387SNathan Whitehorn 	 * If this is the root partition, and we need a boot partition, ask
8162118f387SNathan Whitehorn 	 * the user to add one.
8172118f387SNathan Whitehorn 	 */
8182118f387SNathan Whitehorn 	if (strcmp(items[2].text, "/") == 0 && bootpart_size(scheme) > 0) {
8192118f387SNathan Whitehorn 		if (interactive)
8202118f387SNathan Whitehorn 			choice = dialog_yesno("Boot Partition",
8212118f387SNathan Whitehorn 			    "This partition scheme requires a boot partition "
8222118f387SNathan Whitehorn 			    "for the disk to be bootable. Would you like to "
8232118f387SNathan Whitehorn 			    "make one now?", 0, 0);
8242118f387SNathan Whitehorn 		else
8252118f387SNathan Whitehorn 			choice = 0;
8262118f387SNathan Whitehorn 
8272118f387SNathan Whitehorn 		if (choice == 0) { /* yes */
8282118f387SNathan Whitehorn 			r = gctl_get_handle();
8292118f387SNathan Whitehorn 			gctl_ro_param(r, "class", -1, "PART");
8302118f387SNathan Whitehorn 			gctl_ro_param(r, "arg0", -1, geom->lg_name);
8312118f387SNathan Whitehorn 			gctl_ro_param(r, "flags", -1, GPART_FLAGS);
8322118f387SNathan Whitehorn 			gctl_ro_param(r, "verb", -1, "add");
8332118f387SNathan Whitehorn 			gctl_ro_param(r, "type", -1, "freebsd-boot");
8342118f387SNathan Whitehorn 			snprintf(sizestr, sizeof(sizestr), "%jd",
8352118f387SNathan Whitehorn 			    bootpart_size(scheme) / sector);
8362118f387SNathan Whitehorn 			gctl_ro_param(r, "size", -1, sizestr);
8372118f387SNathan Whitehorn 			snprintf(startstr, sizeof(startstr), "%jd", firstfree);
8382118f387SNathan Whitehorn 			gctl_ro_param(r, "start", -1, startstr);
8392118f387SNathan Whitehorn 			gctl_rw_param(r, "output", sizeof(output), output);
8402118f387SNathan Whitehorn 			errstr = gctl_issue(r);
8412118f387SNathan Whitehorn 			if (errstr != NULL && errstr[0] != '\0')
8422118f387SNathan Whitehorn 				gpart_show_error("Error", NULL, errstr);
8432118f387SNathan Whitehorn 			gctl_free(r);
8442118f387SNathan Whitehorn 
8452118f387SNathan Whitehorn 			get_part_metadata(strtok(output, " "), 1)->bootcode = 1;
8462118f387SNathan Whitehorn 
8472118f387SNathan Whitehorn 			/* Now adjust the part we are really adding forward */
8482118f387SNathan Whitehorn 			firstfree += bootpart_size(scheme) / sector;
8492118f387SNathan Whitehorn 			size -= (bootpart_size(scheme) + stripe)/sector;
8502118f387SNathan Whitehorn 			if (stripe > 0 && (firstfree*sector % stripe) != 0)
8512118f387SNathan Whitehorn 				firstfree += (stripe - ((firstfree*sector) %
8522118f387SNathan Whitehorn 				    stripe)) / sector;
8532118f387SNathan Whitehorn 		}
8542118f387SNathan Whitehorn 	}
8552118f387SNathan Whitehorn 
8562118f387SNathan Whitehorn 	r = gctl_get_handle();
8572118f387SNathan Whitehorn 	gctl_ro_param(r, "class", -1, "PART");
8582118f387SNathan Whitehorn 	gctl_ro_param(r, "arg0", -1, geom->lg_name);
8592118f387SNathan Whitehorn 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
8602118f387SNathan Whitehorn 	gctl_ro_param(r, "verb", -1, "add");
8612118f387SNathan Whitehorn 
8622118f387SNathan Whitehorn 	gctl_ro_param(r, "type", -1, items[0].text);
8632118f387SNathan Whitehorn 	snprintf(sizestr, sizeof(sizestr), "%jd", size);
8642118f387SNathan Whitehorn 	gctl_ro_param(r, "size", -1, sizestr);
8652118f387SNathan Whitehorn 	snprintf(startstr, sizeof(startstr), "%jd", firstfree);
8662118f387SNathan Whitehorn 	gctl_ro_param(r, "start", -1, startstr);
8672118f387SNathan Whitehorn 	if (items[3].text[0] != '\0')
8682118f387SNathan Whitehorn 		gctl_ro_param(r, "label", -1, items[3].text);
8692118f387SNathan Whitehorn 	gctl_rw_param(r, "output", sizeof(output), output);
8702118f387SNathan Whitehorn 
8712118f387SNathan Whitehorn 	errstr = gctl_issue(r);
8722118f387SNathan Whitehorn 	if (errstr != NULL && errstr[0] != '\0') {
8732118f387SNathan Whitehorn 		gpart_show_error("Error", NULL, errstr);
8742118f387SNathan Whitehorn 		gctl_free(r);
8752118f387SNathan Whitehorn 		goto addpartform;
8762118f387SNathan Whitehorn 	}
8772118f387SNathan Whitehorn 
8782118f387SNathan Whitehorn 	if (strcmp(items[0].text, "freebsd-boot") == 0)
8792118f387SNathan Whitehorn 		get_part_metadata(strtok(output, " "), 1)->bootcode = 1;
8802118f387SNathan Whitehorn 	else if (strcmp(items[0].text, "freebsd") == 0)
8812118f387SNathan Whitehorn 		gpart_partition(strtok(output, " "), "BSD");
8822118f387SNathan Whitehorn 	else
8832118f387SNathan Whitehorn 		set_default_part_metadata(strtok(output, " "), scheme,
8842118f387SNathan Whitehorn 		    items[0].text, items[2].text, 1);
8852118f387SNathan Whitehorn 
8862118f387SNathan Whitehorn 	for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++)
8872118f387SNathan Whitehorn 		if (items[i].text_free)
8882118f387SNathan Whitehorn 			free(items[i].text);
8892118f387SNathan Whitehorn 	gctl_free(r);
8902118f387SNathan Whitehorn 
8912118f387SNathan Whitehorn 	if (partname != NULL)
8922118f387SNathan Whitehorn 		*partname = strdup(strtok(output, " "));
8932118f387SNathan Whitehorn }
8942118f387SNathan Whitehorn 
8952118f387SNathan Whitehorn void
8962118f387SNathan Whitehorn gpart_delete(struct gprovider *pp)
8972118f387SNathan Whitehorn {
8982118f387SNathan Whitehorn 	struct gconfig *gc;
8992118f387SNathan Whitehorn 	struct ggeom *geom;
9002118f387SNathan Whitehorn 	struct gconsumer *cp;
9012118f387SNathan Whitehorn 	struct gctl_req *r;
9022118f387SNathan Whitehorn 	const char *errstr;
9032118f387SNathan Whitehorn 	intmax_t idx;
9042118f387SNathan Whitehorn 	int choice, is_partition;
9052118f387SNathan Whitehorn 
9062118f387SNathan Whitehorn 	/* Is it a partition? */
9072118f387SNathan Whitehorn 	is_partition = (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0);
9082118f387SNathan Whitehorn 
9092118f387SNathan Whitehorn 	/* Find out if this is the root of a gpart geom */
9102118f387SNathan Whitehorn 	geom = NULL;
9112118f387SNathan Whitehorn 	LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
9122118f387SNathan Whitehorn 		if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
9132118f387SNathan Whitehorn 			geom = cp->lg_geom;
9142118f387SNathan Whitehorn 			break;
9152118f387SNathan Whitehorn 		}
9162118f387SNathan Whitehorn 
9172118f387SNathan Whitehorn 	/* Destroy all consumers */
9182118f387SNathan Whitehorn 	if (geom != NULL) {
9192118f387SNathan Whitehorn 		if (is_partition) {
9202118f387SNathan Whitehorn 			char message[512];
9212118f387SNathan Whitehorn 			/*
9222118f387SNathan Whitehorn 			 * We have to actually really delete the sub-partition
9232118f387SNathan Whitehorn 			 * tree so that the consumers will go away and the
9242118f387SNathan Whitehorn 			 * partition can be deleted. Warn the user.
9252118f387SNathan Whitehorn 			 */
9262118f387SNathan Whitehorn 
9272118f387SNathan Whitehorn 			sprintf(message, "Deleting this partition (%s) "
9282118f387SNathan Whitehorn 			    "requires deleting all existing sub-partitions. "
9292118f387SNathan Whitehorn 			    "This will PERMANENTLY ERASE any data stored here "
9302118f387SNathan Whitehorn 			    "and CANNOT BE REVERTED. Are you sure you want to "
9312118f387SNathan Whitehorn 			    "proceed?", cp->lg_geom->lg_name);
9322118f387SNathan Whitehorn 			dialog_vars.defaultno = TRUE;
9332118f387SNathan Whitehorn 			choice = dialog_yesno("Warning", message, 0, 0);
9342118f387SNathan Whitehorn 			dialog_vars.defaultno = FALSE;
9352118f387SNathan Whitehorn 
9362118f387SNathan Whitehorn 			if (choice == 1) /* cancel */
9372118f387SNathan Whitehorn 				return;
9382118f387SNathan Whitehorn 		}
9392118f387SNathan Whitehorn 
9402118f387SNathan Whitehorn 		gpart_destroy(geom, is_partition);
9412118f387SNathan Whitehorn 	}
9422118f387SNathan Whitehorn 
9432118f387SNathan Whitehorn 	/*
9442118f387SNathan Whitehorn 	 * If this is not a partition, see if that is a problem, complain if
9452118f387SNathan Whitehorn 	 * necessary, and return always, since we need not do anything further,
9462118f387SNathan Whitehorn 	 * error or no.
9472118f387SNathan Whitehorn 	 */
9482118f387SNathan Whitehorn 	if (!is_partition) {
9492118f387SNathan Whitehorn 		if (geom == NULL)
9502118f387SNathan Whitehorn 			dialog_msgbox("Error",
9512118f387SNathan Whitehorn 			    "Only partitions can be deleted.", 0, 0, TRUE);
9522118f387SNathan Whitehorn 		return;
9532118f387SNathan Whitehorn 	}
9542118f387SNathan Whitehorn 
9552118f387SNathan Whitehorn 	r = gctl_get_handle();
9562118f387SNathan Whitehorn 	gctl_ro_param(r, "class", -1, pp->lg_geom->lg_class->lg_name);
9572118f387SNathan Whitehorn 	gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name);
9582118f387SNathan Whitehorn 	gctl_ro_param(r, "flags", -1, GPART_FLAGS);
9592118f387SNathan Whitehorn 	gctl_ro_param(r, "verb", -1, "delete");
9602118f387SNathan Whitehorn 
9612118f387SNathan Whitehorn 	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
9622118f387SNathan Whitehorn 		if (strcmp(gc->lg_name, "index") == 0) {
9632118f387SNathan Whitehorn 			idx = atoi(gc->lg_val);
9642118f387SNathan Whitehorn 			gctl_ro_param(r, "index", sizeof(idx), &idx);
9652118f387SNathan Whitehorn 			break;
9662118f387SNathan Whitehorn 		}
9672118f387SNathan Whitehorn 	}
9682118f387SNathan Whitehorn 
9692118f387SNathan Whitehorn 	errstr = gctl_issue(r);
9702118f387SNathan Whitehorn 	if (errstr != NULL && errstr[0] != '\0') {
9712118f387SNathan Whitehorn 		gpart_show_error("Error", NULL, errstr);
9722118f387SNathan Whitehorn 		gctl_free(r);
9732118f387SNathan Whitehorn 		return;
9742118f387SNathan Whitehorn 	}
9752118f387SNathan Whitehorn 
9762118f387SNathan Whitehorn 	gctl_free(r);
9772118f387SNathan Whitehorn 
9782118f387SNathan Whitehorn 	delete_part_metadata(pp->lg_name);
9792118f387SNathan Whitehorn }
9802118f387SNathan Whitehorn 
9812118f387SNathan Whitehorn void
9822118f387SNathan Whitehorn gpart_revert_all(struct gmesh *mesh)
9832118f387SNathan Whitehorn {
9842118f387SNathan Whitehorn 	struct gclass *classp;
9852118f387SNathan Whitehorn 	struct gconfig *gc;
9862118f387SNathan Whitehorn 	struct ggeom *gp;
9872118f387SNathan Whitehorn 	struct gctl_req *r;
9882118f387SNathan Whitehorn 	const char *errstr;
9892118f387SNathan Whitehorn 	const char *modified;
9902118f387SNathan Whitehorn 
9912118f387SNathan Whitehorn 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
9922118f387SNathan Whitehorn 		if (strcmp(classp->lg_name, "PART") == 0)
9932118f387SNathan Whitehorn 			break;
9942118f387SNathan Whitehorn 	}
9952118f387SNathan Whitehorn 
9962118f387SNathan Whitehorn 	if (strcmp(classp->lg_name, "PART") != 0) {
9972118f387SNathan Whitehorn 		dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
9982118f387SNathan Whitehorn 		return;
9992118f387SNathan Whitehorn 	}
10002118f387SNathan Whitehorn 
10012118f387SNathan Whitehorn 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
10022118f387SNathan Whitehorn 		modified = "true"; /* XXX: If we don't know (kernel too old),
10032118f387SNathan Whitehorn 				    * assume there are modifications. */
10042118f387SNathan Whitehorn 		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
10052118f387SNathan Whitehorn 			if (strcmp(gc->lg_name, "modified") == 0) {
10062118f387SNathan Whitehorn 				modified = gc->lg_val;
10072118f387SNathan Whitehorn 				break;
10082118f387SNathan Whitehorn 			}
10092118f387SNathan Whitehorn 		}
10102118f387SNathan Whitehorn 
10112118f387SNathan Whitehorn 		if (strcmp(modified, "false") == 0)
10122118f387SNathan Whitehorn 			continue;
10132118f387SNathan Whitehorn 
10142118f387SNathan Whitehorn 		r = gctl_get_handle();
10152118f387SNathan Whitehorn 		gctl_ro_param(r, "class", -1, "PART");
10162118f387SNathan Whitehorn 		gctl_ro_param(r, "arg0", -1, gp->lg_name);
10172118f387SNathan Whitehorn 		gctl_ro_param(r, "verb", -1, "undo");
10182118f387SNathan Whitehorn 
10192118f387SNathan Whitehorn 		errstr = gctl_issue(r);
10202118f387SNathan Whitehorn 		if (errstr != NULL && errstr[0] != '\0')
10212118f387SNathan Whitehorn 			gpart_show_error("Error", NULL, errstr);
10222118f387SNathan Whitehorn 		gctl_free(r);
10232118f387SNathan Whitehorn 	}
10242118f387SNathan Whitehorn }
10252118f387SNathan Whitehorn 
10262118f387SNathan Whitehorn void
10272118f387SNathan Whitehorn gpart_commit(struct gmesh *mesh)
10282118f387SNathan Whitehorn {
10292118f387SNathan Whitehorn 	struct partition_metadata *md;
10302118f387SNathan Whitehorn 	struct gclass *classp;
10312118f387SNathan Whitehorn 	struct ggeom *gp;
10322118f387SNathan Whitehorn 	struct gconfig *gc;
10332118f387SNathan Whitehorn 	struct gconsumer *cp;
10342118f387SNathan Whitehorn 	struct gprovider *pp;
10352118f387SNathan Whitehorn 	struct gctl_req *r;
10362118f387SNathan Whitehorn 	const char *errstr;
10372118f387SNathan Whitehorn 	const char *modified;
10382118f387SNathan Whitehorn 
10392118f387SNathan Whitehorn 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
10402118f387SNathan Whitehorn 		if (strcmp(classp->lg_name, "PART") == 0)
10412118f387SNathan Whitehorn 			break;
10422118f387SNathan Whitehorn 	}
10432118f387SNathan Whitehorn 
10442118f387SNathan Whitehorn 	if (strcmp(classp->lg_name, "PART") != 0) {
10452118f387SNathan Whitehorn 		dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
10462118f387SNathan Whitehorn 		return;
10472118f387SNathan Whitehorn 	}
10482118f387SNathan Whitehorn 
10492118f387SNathan Whitehorn 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
10502118f387SNathan Whitehorn 		modified = "true"; /* XXX: If we don't know (kernel too old),
10512118f387SNathan Whitehorn 				    * assume there are modifications. */
10522118f387SNathan Whitehorn 		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
10532118f387SNathan Whitehorn 			if (strcmp(gc->lg_name, "modified") == 0) {
10542118f387SNathan Whitehorn 				modified = gc->lg_val;
10552118f387SNathan Whitehorn 				break;
10562118f387SNathan Whitehorn 			}
10572118f387SNathan Whitehorn 		}
10582118f387SNathan Whitehorn 
10592118f387SNathan Whitehorn 		if (strcmp(modified, "false") == 0)
10602118f387SNathan Whitehorn 			continue;
10612118f387SNathan Whitehorn 
10622118f387SNathan Whitehorn 		/* Add bootcode if necessary, before the commit */
10632118f387SNathan Whitehorn 		md = get_part_metadata(gp->lg_name, 0);
10642118f387SNathan Whitehorn 		if (md != NULL && md->bootcode)
10652118f387SNathan Whitehorn 			gpart_bootcode(gp);
10662118f387SNathan Whitehorn 
10672118f387SNathan Whitehorn 		/* Now install partcode on its partitions, if necessary */
10682118f387SNathan Whitehorn 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
10692118f387SNathan Whitehorn 			md = get_part_metadata(pp->lg_name, 0);
10702118f387SNathan Whitehorn 			if (md == NULL || !md->bootcode)
10712118f387SNathan Whitehorn 				continue;
10722118f387SNathan Whitehorn 
10732118f387SNathan Whitehorn 			/* Mark this partition active if that's required */
10742118f387SNathan Whitehorn 			gpart_activate(pp);
10752118f387SNathan Whitehorn 
10762118f387SNathan Whitehorn 			/* Check if the partition has sub-partitions */
10772118f387SNathan Whitehorn 			LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
10782118f387SNathan Whitehorn 				if (strcmp(cp->lg_geom->lg_class->lg_name,
10792118f387SNathan Whitehorn 				    "PART") == 0)
10802118f387SNathan Whitehorn 					break;
10812118f387SNathan Whitehorn 
10822118f387SNathan Whitehorn 			if (cp == NULL) /* No sub-partitions */
10832118f387SNathan Whitehorn 				gpart_partcode(pp);
10842118f387SNathan Whitehorn 		}
10852118f387SNathan Whitehorn 
10862118f387SNathan Whitehorn 		r = gctl_get_handle();
10872118f387SNathan Whitehorn 		gctl_ro_param(r, "class", -1, "PART");
10882118f387SNathan Whitehorn 		gctl_ro_param(r, "arg0", -1, gp->lg_name);
10892118f387SNathan Whitehorn 		gctl_ro_param(r, "verb", -1, "commit");
10902118f387SNathan Whitehorn 
10912118f387SNathan Whitehorn 		errstr = gctl_issue(r);
10922118f387SNathan Whitehorn 		if (errstr != NULL && errstr[0] != '\0')
10932118f387SNathan Whitehorn 			gpart_show_error("Error", NULL, errstr);
10942118f387SNathan Whitehorn 		gctl_free(r);
10952118f387SNathan Whitehorn 	}
10962118f387SNathan Whitehorn }
10972118f387SNathan Whitehorn 
1098