12118f387SNathan Whitehorn /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
42118f387SNathan Whitehorn  * Copyright (c) 2011 Nathan Whitehorn
52118f387SNathan Whitehorn  * All rights reserved.
62118f387SNathan Whitehorn  *
72118f387SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
82118f387SNathan Whitehorn  * modification, are permitted provided that the following conditions
92118f387SNathan Whitehorn  * are met:
102118f387SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
112118f387SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
122118f387SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
132118f387SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
142118f387SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
152118f387SNathan Whitehorn  *
162118f387SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172118f387SNathan Whitehorn  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182118f387SNathan Whitehorn  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192118f387SNathan Whitehorn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202118f387SNathan Whitehorn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212118f387SNathan Whitehorn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222118f387SNathan Whitehorn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232118f387SNathan Whitehorn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242118f387SNathan Whitehorn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252118f387SNathan Whitehorn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262118f387SNathan Whitehorn  * SUCH DAMAGE.
272118f387SNathan Whitehorn  */
282118f387SNathan Whitehorn 
292118f387SNathan Whitehorn #include <sys/param.h>
302118f387SNathan Whitehorn 
3150e24496SAlfonso S. Siciliano #include <bsddialog.h>
32a107ddbbSRebecca Cran #include <err.h>
334e7e2cadSEd Schouten #include <errno.h>
344e7e2cadSEd Schouten #include <fstab.h>
354e7e2cadSEd Schouten #include <inttypes.h>
364e7e2cadSEd Schouten #include <libgeom.h>
374e7e2cadSEd Schouten #include <libutil.h>
3850e24496SAlfonso S. Siciliano #include <stdio.h>
394e7e2cadSEd Schouten #include <stdlib.h>
4050e24496SAlfonso S. Siciliano #include <string.h>
41a107ddbbSRebecca Cran #include <sysexits.h>
422118f387SNathan Whitehorn 
4350e24496SAlfonso S. Siciliano #include "diskmenu.h"
442118f387SNathan Whitehorn #include "partedit.h"
452118f387SNathan Whitehorn 
462118f387SNathan Whitehorn struct pmetadata_head part_metadata;
474f5fcf8dSNathan Whitehorn static int sade_mode = 0;
482118f387SNathan Whitehorn 
492118f387SNathan Whitehorn static int apply_changes(struct gmesh *mesh);
507059fa6fSAllan Jude static void apply_workaround(struct gmesh *mesh);
512118f387SNathan Whitehorn static struct partedit_item *read_geom_mesh(struct gmesh *mesh, int *nitems);
522118f387SNathan Whitehorn static void add_geom_children(struct ggeom *gp, int recurse,
532118f387SNathan Whitehorn     struct partedit_item **items, int *nitems);
542118f387SNathan Whitehorn static void init_fstab_metadata(void);
552118f387SNathan Whitehorn static void get_mount_points(struct partedit_item *items, int nitems);
562118f387SNathan Whitehorn static int validate_setup(void);
572118f387SNathan Whitehorn 
58bcc25b7eSNathan Whitehorn static void
sigint_handler(int sig)59bcc25b7eSNathan Whitehorn sigint_handler(int sig)
60bcc25b7eSNathan Whitehorn {
61bcc25b7eSNathan Whitehorn 	struct gmesh mesh;
62bcc25b7eSNathan Whitehorn 
63bcc25b7eSNathan Whitehorn 	/* Revert all changes and exit dialog-mode cleanly on SIGINT */
6423099099SJohn Baldwin 	if (geom_gettree(&mesh) == 0) {
65bcc25b7eSNathan Whitehorn 		gpart_revert_all(&mesh);
66bcc25b7eSNathan Whitehorn 		geom_deletetree(&mesh);
6723099099SJohn Baldwin 	}
68bcc25b7eSNathan Whitehorn 
6950e24496SAlfonso S. Siciliano 	bsddialog_end();
70bcc25b7eSNathan Whitehorn 
71bcc25b7eSNathan Whitehorn 	exit(1);
72bcc25b7eSNathan Whitehorn }
73bcc25b7eSNathan Whitehorn 
742118f387SNathan Whitehorn int
main(int argc,const char ** argv)75bcc25b7eSNathan Whitehorn main(int argc, const char **argv)
76bcc25b7eSNathan Whitehorn {
772118f387SNathan Whitehorn 	struct partition_metadata *md;
78b07b7aecSRyan Moeller 	const char *progname, *prompt;
7907d76626SNathan Whitehorn 	struct partedit_item *items = NULL;
802118f387SNathan Whitehorn 	struct gmesh mesh;
8150e24496SAlfonso S. Siciliano 	int i, op, nitems;
822118f387SNathan Whitehorn 	int error;
8350e24496SAlfonso S. Siciliano 	struct bsddialog_conf conf;
842118f387SNathan Whitehorn 
854e7e2cadSEd Schouten 	progname = getprogname();
864e7e2cadSEd Schouten 	if (strcmp(progname, "sade") == 0)
874f5fcf8dSNathan Whitehorn 		sade_mode = 1;
884f5fcf8dSNathan Whitehorn 
892118f387SNathan Whitehorn 	TAILQ_INIT(&part_metadata);
902118f387SNathan Whitehorn 
912118f387SNathan Whitehorn 	init_fstab_metadata();
922118f387SNathan Whitehorn 
9350e24496SAlfonso S. Siciliano 	if (bsddialog_init() == BSDDIALOG_ERROR)
9450e24496SAlfonso S. Siciliano 		err(1, "%s", bsddialog_geterror());
9550e24496SAlfonso S. Siciliano 	bsddialog_initconf(&conf);
964f5fcf8dSNathan Whitehorn 	if (!sade_mode)
97147585b4SBrad Davis 		bsddialog_backtitle(&conf, OSNAME " Installer");
9850e24496SAlfonso S. Siciliano 	i = 0;
992118f387SNathan Whitehorn 
100bcc25b7eSNathan Whitehorn 	/* Revert changes on SIGINT */
101bcc25b7eSNathan Whitehorn 	signal(SIGINT, sigint_handler);
102bcc25b7eSNathan Whitehorn 
1034e7e2cadSEd Schouten 	if (strcmp(progname, "autopart") == 0) { /* Guided */
1042118f387SNathan Whitehorn 		prompt = "Please review the disk setup. When complete, press "
105bcc25b7eSNathan Whitehorn 		    "the Finish button.";
1066e15678aSNathan Whitehorn 		/* Experimental ZFS autopartition support */
1076e15678aSNathan Whitehorn 		if (argc > 1 && strcmp(argv[1], "zfs") == 0) {
1086e15678aSNathan Whitehorn 			part_wizard("zfs");
1096e15678aSNathan Whitehorn 		} else {
1106e15678aSNathan Whitehorn 			part_wizard("ufs");
1116e15678aSNathan Whitehorn 		}
1124e7e2cadSEd Schouten 	} else if (strcmp(progname, "scriptedpart") == 0) {
113f0ddc92dSNathan Whitehorn 		error = scripted_editor(argc, argv);
1145eca7e06SNathan Whitehorn 		prompt = NULL;
115f0ddc92dSNathan Whitehorn 		if (error != 0) {
11650e24496SAlfonso S. Siciliano 			bsddialog_end();
117f0ddc92dSNathan Whitehorn 			return (error);
118f0ddc92dSNathan Whitehorn 		}
1192118f387SNathan Whitehorn 	} else {
120147585b4SBrad Davis 		prompt = "Create partitions for " OSNAME ", F1 for help.\n"
12150e24496SAlfonso S. Siciliano 		    "No changes will be made until you select Finish.";
1222118f387SNathan Whitehorn 	}
1232118f387SNathan Whitehorn 
1242118f387SNathan Whitehorn 	/* Show the part editor either immediately, or to confirm wizard */
1255eca7e06SNathan Whitehorn 	while (prompt != NULL) {
12661ba55bcSBaptiste Daroussin 		bsddialog_clear(0);
12750e24496SAlfonso S. Siciliano 		if (!sade_mode)
128cd724c25SMariusz Zaborski 			bsddialog_backtitle(&conf, OSNAME " Installer");
1292118f387SNathan Whitehorn 
13007d76626SNathan Whitehorn 		error = geom_gettree(&mesh);
13107d76626SNathan Whitehorn 		if (error == 0)
13207d76626SNathan Whitehorn 			items = read_geom_mesh(&mesh, &nitems);
13307d76626SNathan Whitehorn 		if (error || items == NULL) {
13450e24496SAlfonso S. Siciliano 			conf.title = "Error";
13550e24496SAlfonso S. Siciliano 			bsddialog_msgbox(&conf, "No disks found. If you need "
13650e24496SAlfonso S. Siciliano 			    "to install a kernel driver, choose Shell at the "
13750e24496SAlfonso S. Siciliano 			    "installation menu.", 0, 0);
13807d76626SNathan Whitehorn 			break;
13907d76626SNathan Whitehorn 		}
14007d76626SNathan Whitehorn 
14107d76626SNathan Whitehorn 		get_mount_points(items, nitems);
14207d76626SNathan Whitehorn 
1432118f387SNathan Whitehorn 		if (i >= nitems)
1442118f387SNathan Whitehorn 			i = nitems - 1;
14550e24496SAlfonso S. Siciliano 		op = diskmenu_show("Partition Editor", prompt, items, nitems,
14650e24496SAlfonso S. Siciliano 		    &i);
1472118f387SNathan Whitehorn 
1482118f387SNathan Whitehorn 		switch (op) {
14950e24496SAlfonso S. Siciliano 		case BUTTON_CREATE:
1502118f387SNathan Whitehorn 			gpart_create((struct gprovider *)(items[i].cookie),
1512118f387SNathan Whitehorn 			    NULL, NULL, NULL, NULL, 1);
1522118f387SNathan Whitehorn 			break;
15350e24496SAlfonso S. Siciliano 		case BUTTON_DELETE:
1542118f387SNathan Whitehorn 			gpart_delete((struct gprovider *)(items[i].cookie));
1552118f387SNathan Whitehorn 			break;
15650e24496SAlfonso S. Siciliano 		case BUTTON_MODIFY:
1572118f387SNathan Whitehorn 			gpart_edit((struct gprovider *)(items[i].cookie));
1582118f387SNathan Whitehorn 			break;
15950e24496SAlfonso S. Siciliano 		case BUTTON_REVERT:
1602118f387SNathan Whitehorn 			gpart_revert_all(&mesh);
1612118f387SNathan Whitehorn 			while ((md = TAILQ_FIRST(&part_metadata)) != NULL) {
1622118f387SNathan Whitehorn 				if (md->fstab != NULL) {
1632118f387SNathan Whitehorn 					free(md->fstab->fs_spec);
1642118f387SNathan Whitehorn 					free(md->fstab->fs_file);
1652118f387SNathan Whitehorn 					free(md->fstab->fs_vfstype);
1662118f387SNathan Whitehorn 					free(md->fstab->fs_mntops);
1672118f387SNathan Whitehorn 					free(md->fstab->fs_type);
1682118f387SNathan Whitehorn 					free(md->fstab);
1692118f387SNathan Whitehorn 				}
1702118f387SNathan Whitehorn 				if (md->newfs != NULL)
1712118f387SNathan Whitehorn 					free(md->newfs);
1722118f387SNathan Whitehorn 				free(md->name);
1732118f387SNathan Whitehorn 
1742118f387SNathan Whitehorn 				TAILQ_REMOVE(&part_metadata, md, metadata);
1752118f387SNathan Whitehorn 				free(md);
1762118f387SNathan Whitehorn 			}
1772118f387SNathan Whitehorn 			init_fstab_metadata();
1782118f387SNathan Whitehorn 			break;
17950e24496SAlfonso S. Siciliano 		case BUTTON_AUTO:
1806e15678aSNathan Whitehorn 			part_wizard("ufs");
1812118f387SNathan Whitehorn 			break;
1822118f387SNathan Whitehorn 		}
1832118f387SNathan Whitehorn 
1842118f387SNathan Whitehorn 		error = 0;
18550e24496SAlfonso S. Siciliano 		if (op == BUTTON_FINISH) {
18650e24496SAlfonso S. Siciliano 			conf.button.ok_label = "Commit";
18750e24496SAlfonso S. Siciliano 			conf.button.with_extra = true;
18850e24496SAlfonso S. Siciliano 			conf.button.extra_label = "Revert & Exit";
18950e24496SAlfonso S. Siciliano 			conf.button.cancel_label = "Back";
19050e24496SAlfonso S. Siciliano 			conf.title = "Confirmation";
19150e24496SAlfonso S. Siciliano 			op = bsddialog_yesno(&conf, "Your changes will now be "
19250e24496SAlfonso S. Siciliano 			    "written to disk. If you have chosen to overwrite "
19350e24496SAlfonso S. Siciliano 			    "existing data, it will be PERMANENTLY ERASED. Are "
19450e24496SAlfonso S. Siciliano 			    "you sure you want to commit your changes?", 0, 0);
19550e24496SAlfonso S. Siciliano 			conf.button.ok_label = NULL;
19650e24496SAlfonso S. Siciliano 			conf.button.with_extra = false;
19750e24496SAlfonso S. Siciliano 			conf.button.extra_label = NULL;
19850e24496SAlfonso S. Siciliano 			conf.button.cancel_label = NULL;
1992118f387SNathan Whitehorn 
20050e24496SAlfonso S. Siciliano 			if (op == BSDDIALOG_OK && validate_setup()) { /* Save */
2012118f387SNathan Whitehorn 				error = apply_changes(&mesh);
2027059fa6fSAllan Jude 				if (!error)
2037059fa6fSAllan Jude 					apply_workaround(&mesh);
2042118f387SNathan Whitehorn 				break;
20550e24496SAlfonso S. Siciliano 			} else if (op == BSDDIALOG_EXTRA) { /* Quit */
2062118f387SNathan Whitehorn 				gpart_revert_all(&mesh);
2072118f387SNathan Whitehorn 				error =	-1;
2082118f387SNathan Whitehorn 				break;
2092118f387SNathan Whitehorn 			}
2102118f387SNathan Whitehorn 		}
2112118f387SNathan Whitehorn 
2122118f387SNathan Whitehorn 		geom_deletetree(&mesh);
2132118f387SNathan Whitehorn 		free(items);
2142118f387SNathan Whitehorn 	}
2152118f387SNathan Whitehorn 
2165eca7e06SNathan Whitehorn 	if (prompt == NULL) {
2175eca7e06SNathan Whitehorn 		error = geom_gettree(&mesh);
2185307bbccSJohn Baldwin 		if (error == 0) {
2195eca7e06SNathan Whitehorn 			if (validate_setup()) {
2205eca7e06SNathan Whitehorn 				error = apply_changes(&mesh);
2215eca7e06SNathan Whitehorn 			} else {
2225eca7e06SNathan Whitehorn 				gpart_revert_all(&mesh);
2235eca7e06SNathan Whitehorn 				error = -1;
2245eca7e06SNathan Whitehorn 			}
22523099099SJohn Baldwin 			geom_deletetree(&mesh);
22623099099SJohn Baldwin 		}
2275eca7e06SNathan Whitehorn 	}
2282118f387SNathan Whitehorn 
22950e24496SAlfonso S. Siciliano 	bsddialog_end();
2302118f387SNathan Whitehorn 
2312118f387SNathan Whitehorn 	return (error);
2322118f387SNathan Whitehorn }
2332118f387SNathan Whitehorn 
2342118f387SNathan Whitehorn struct partition_metadata *
get_part_metadata(const char * name,int create)2352118f387SNathan Whitehorn get_part_metadata(const char *name, int create)
2362118f387SNathan Whitehorn {
2372118f387SNathan Whitehorn 	struct partition_metadata *md;
2382118f387SNathan Whitehorn 
2392118f387SNathan Whitehorn 	TAILQ_FOREACH(md, &part_metadata, metadata)
2402118f387SNathan Whitehorn 		if (md->name != NULL && strcmp(md->name, name) == 0)
2412118f387SNathan Whitehorn 			break;
2422118f387SNathan Whitehorn 
2432118f387SNathan Whitehorn 	if (md == NULL && create) {
2442118f387SNathan Whitehorn 		md = calloc(1, sizeof(*md));
2452118f387SNathan Whitehorn 		md->name = strdup(name);
2462118f387SNathan Whitehorn 		TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
2472118f387SNathan Whitehorn 	}
2482118f387SNathan Whitehorn 
2492118f387SNathan Whitehorn 	return (md);
2502118f387SNathan Whitehorn }
2512118f387SNathan Whitehorn 
2522118f387SNathan Whitehorn void
delete_part_metadata(const char * name)253bcc25b7eSNathan Whitehorn delete_part_metadata(const char *name)
254bcc25b7eSNathan Whitehorn {
2552118f387SNathan Whitehorn 	struct partition_metadata *md;
2562118f387SNathan Whitehorn 
2572118f387SNathan Whitehorn 	TAILQ_FOREACH(md, &part_metadata, metadata) {
2582118f387SNathan Whitehorn 		if (md->name != NULL && strcmp(md->name, name) == 0) {
2592118f387SNathan Whitehorn 			if (md->fstab != NULL) {
2602118f387SNathan Whitehorn 				free(md->fstab->fs_spec);
2612118f387SNathan Whitehorn 				free(md->fstab->fs_file);
2622118f387SNathan Whitehorn 				free(md->fstab->fs_vfstype);
2632118f387SNathan Whitehorn 				free(md->fstab->fs_mntops);
2642118f387SNathan Whitehorn 				free(md->fstab->fs_type);
2652118f387SNathan Whitehorn 				free(md->fstab);
2662118f387SNathan Whitehorn 			}
2672118f387SNathan Whitehorn 			if (md->newfs != NULL)
2682118f387SNathan Whitehorn 				free(md->newfs);
2692118f387SNathan Whitehorn 			free(md->name);
2702118f387SNathan Whitehorn 
2712118f387SNathan Whitehorn 			TAILQ_REMOVE(&part_metadata, md, metadata);
2722118f387SNathan Whitehorn 			free(md);
2732118f387SNathan Whitehorn 			break;
2742118f387SNathan Whitehorn 		}
2752118f387SNathan Whitehorn 	}
2762118f387SNathan Whitehorn }
2772118f387SNathan Whitehorn 
2782118f387SNathan Whitehorn static int
validate_setup(void)2792118f387SNathan Whitehorn validate_setup(void)
2802118f387SNathan Whitehorn {
2816fe359f2SNathan Whitehorn 	struct partition_metadata *md, *root = NULL;
28250e24496SAlfonso S. Siciliano 	int button;
28350e24496SAlfonso S. Siciliano 	struct bsddialog_conf conf;
2842118f387SNathan Whitehorn 
2852118f387SNathan Whitehorn 	TAILQ_FOREACH(md, &part_metadata, metadata) {
2862118f387SNathan Whitehorn 		if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0)
2876fe359f2SNathan Whitehorn 			root = md;
2882118f387SNathan Whitehorn 
2892118f387SNathan Whitehorn 		/* XXX: Check for duplicate mountpoints */
2902118f387SNathan Whitehorn 	}
2912118f387SNathan Whitehorn 
29250e24496SAlfonso S. Siciliano 	bsddialog_initconf(&conf);
29350e24496SAlfonso S. Siciliano 
2946fe359f2SNathan Whitehorn 	if (root == NULL) {
29550e24496SAlfonso S. Siciliano 		conf.title = "Error";
29650e24496SAlfonso S. Siciliano 		bsddialog_msgbox(&conf, "No root partition was found. "
297147585b4SBrad Davis 		    "The root " OSNAME " partition must have a mountpoint "
29850e24496SAlfonso S. Siciliano 		    "of '/'.", 0, 0);
29950e24496SAlfonso S. Siciliano 		return (false);
3002118f387SNathan Whitehorn 	}
3012118f387SNathan Whitehorn 
3026fe359f2SNathan Whitehorn 	/*
3036fe359f2SNathan Whitehorn 	 * Check for root partitions that we aren't formatting, which is
3046fe359f2SNathan Whitehorn 	 * usually a mistake
3056fe359f2SNathan Whitehorn 	 */
3064f5fcf8dSNathan Whitehorn 	if (root->newfs == NULL && !sade_mode) {
30750e24496SAlfonso S. Siciliano 		conf.button.default_cancel = true;
30850e24496SAlfonso S. Siciliano 		conf.title = "Warning";
30950e24496SAlfonso S. Siciliano 		button = bsddialog_yesno(&conf, "The chosen root partition "
3106fe359f2SNathan Whitehorn 		    "has a preexisting filesystem. If it contains an existing "
311147585b4SBrad Davis 		    OSNAME " system, please update it with freebsd-update "
3126fe359f2SNathan Whitehorn 		    "instead of installing a new system on it. The partition "
3136fe359f2SNathan Whitehorn 		    "can also be erased by pressing \"No\" and then deleting "
3146fe359f2SNathan Whitehorn 		    "and recreating it. Are you sure you want to proceed?",
3156fe359f2SNathan Whitehorn 		    0, 0);
31650e24496SAlfonso S. Siciliano 		if (button == BSDDIALOG_CANCEL)
31750e24496SAlfonso S. Siciliano 			return (false);
3186fe359f2SNathan Whitehorn 	}
3196fe359f2SNathan Whitehorn 
32050e24496SAlfonso S. Siciliano 	return (true);
3212118f387SNathan Whitehorn }
3222118f387SNathan Whitehorn 
3232118f387SNathan Whitehorn static int
mountpoint_sorter(const void * xa,const void * xb)324c2f16c59SNathan Whitehorn mountpoint_sorter(const void *xa, const void *xb)
325c2f16c59SNathan Whitehorn {
326c2f16c59SNathan Whitehorn 	struct partition_metadata *a = *(struct partition_metadata **)xa;
327c2f16c59SNathan Whitehorn 	struct partition_metadata *b = *(struct partition_metadata **)xb;
328c2f16c59SNathan Whitehorn 
329c2f16c59SNathan Whitehorn 	if (a->fstab == NULL && b->fstab == NULL)
330c2f16c59SNathan Whitehorn 		return 0;
331c2f16c59SNathan Whitehorn 	if (a->fstab == NULL)
332c2f16c59SNathan Whitehorn 		return 1;
333c2f16c59SNathan Whitehorn 	if (b->fstab == NULL)
334c2f16c59SNathan Whitehorn 		return -1;
335c2f16c59SNathan Whitehorn 
336c2f16c59SNathan Whitehorn 	return strcmp(a->fstab->fs_file, b->fstab->fs_file);
337c2f16c59SNathan Whitehorn }
338c2f16c59SNathan Whitehorn 
339c2f16c59SNathan Whitehorn static int
apply_changes(struct gmesh * mesh)3402118f387SNathan Whitehorn apply_changes(struct gmesh *mesh)
3412118f387SNathan Whitehorn {
3422118f387SNathan Whitehorn 	struct partition_metadata *md;
3432118f387SNathan Whitehorn 	char message[512];
34450e24496SAlfonso S. Siciliano 	int i, nitems, error, *miniperc;
34550e24496SAlfonso S. Siciliano 	const char **minilabel;
3462118f387SNathan Whitehorn 	const char *fstab_path;
3472118f387SNathan Whitehorn 	FILE *fstab;
348a8676bf3SJohn Baldwin 	char *command;
34950e24496SAlfonso S. Siciliano 	struct bsddialog_conf conf;
3502118f387SNathan Whitehorn 
3512118f387SNathan Whitehorn 	nitems = 1; /* Partition table changes */
3522118f387SNathan Whitehorn 	TAILQ_FOREACH(md, &part_metadata, metadata) {
3532118f387SNathan Whitehorn 		if (md->newfs != NULL)
3542118f387SNathan Whitehorn 			nitems++;
3552118f387SNathan Whitehorn 	}
35650e24496SAlfonso S. Siciliano 	minilabel = calloc(nitems, sizeof(const char *));
35750e24496SAlfonso S. Siciliano 	miniperc  = calloc(nitems, sizeof(int));
35850e24496SAlfonso S. Siciliano 	minilabel[0] = "Writing partition tables";
35950e24496SAlfonso S. Siciliano 	miniperc[0]  = BSDDIALOG_MG_INPROGRESS;
3602118f387SNathan Whitehorn 	i = 1;
3612118f387SNathan Whitehorn 	TAILQ_FOREACH(md, &part_metadata, metadata) {
3622118f387SNathan Whitehorn 		if (md->newfs != NULL) {
3632118f387SNathan Whitehorn 			char *item;
36451749e05SJohn Baldwin 
36551749e05SJohn Baldwin 			asprintf(&item, "Initializing %s", md->name);
36650e24496SAlfonso S. Siciliano 			minilabel[i] = item;
36750e24496SAlfonso S. Siciliano 			miniperc[i]  = BSDDIALOG_MG_PENDING;
3682118f387SNathan Whitehorn 			i++;
3692118f387SNathan Whitehorn 		}
3702118f387SNathan Whitehorn 	}
3712118f387SNathan Whitehorn 
3722118f387SNathan Whitehorn 	i = 0;
37350e24496SAlfonso S. Siciliano 	bsddialog_initconf(&conf);
37450e24496SAlfonso S. Siciliano 	conf.title = "Initializing";
37550e24496SAlfonso S. Siciliano 	bsddialog_mixedgauge(&conf,
3762118f387SNathan Whitehorn 	    "Initializing file systems. Please wait.", 0, 0, i * 100 / nitems,
37750e24496SAlfonso S. Siciliano 	    nitems, minilabel, miniperc);
3782118f387SNathan Whitehorn 	gpart_commit(mesh);
37950e24496SAlfonso S. Siciliano 	miniperc[i] = BSDDIALOG_MG_COMPLETED;
3802118f387SNathan Whitehorn 	i++;
3812118f387SNathan Whitehorn 
3822118f387SNathan Whitehorn 	if (getenv("BSDINSTALL_LOG") == NULL)
3832118f387SNathan Whitehorn 		setenv("BSDINSTALL_LOG", "/dev/null", 1);
3842118f387SNathan Whitehorn 
3852118f387SNathan Whitehorn 	TAILQ_FOREACH(md, &part_metadata, metadata) {
3862118f387SNathan Whitehorn 		if (md->newfs != NULL) {
38750e24496SAlfonso S. Siciliano 			miniperc[i] = BSDDIALOG_MG_INPROGRESS;
38850e24496SAlfonso S. Siciliano 			bsddialog_mixedgauge(&conf,
3892118f387SNathan Whitehorn 			    "Initializing file systems. Please wait.", 0, 0,
39050e24496SAlfonso S. Siciliano 			    i * 100 / nitems, nitems, minilabel, miniperc);
391a8676bf3SJohn Baldwin 			asprintf(&command, "(echo %s; %s) >>%s 2>>%s",
3922118f387SNathan Whitehorn 			    md->newfs, md->newfs, getenv("BSDINSTALL_LOG"),
3932118f387SNathan Whitehorn 			    getenv("BSDINSTALL_LOG"));
394a8676bf3SJohn Baldwin 			error = system(command);
395a8676bf3SJohn Baldwin 			free(command);
39650e24496SAlfonso S. Siciliano 			miniperc[i] = (error == 0) ?
39750e24496SAlfonso S. Siciliano 			    BSDDIALOG_MG_COMPLETED : BSDDIALOG_MG_FAILED;
3982118f387SNathan Whitehorn 			i++;
3992118f387SNathan Whitehorn 		}
4002118f387SNathan Whitehorn 	}
40150e24496SAlfonso S. Siciliano 	bsddialog_mixedgauge(&conf, "Initializing file systems. Please wait.",
40250e24496SAlfonso S. Siciliano 	    0, 0, i * 100 / nitems, nitems, minilabel, miniperc);
4032118f387SNathan Whitehorn 
4042118f387SNathan Whitehorn 	for (i = 1; i < nitems; i++)
40550e24496SAlfonso S. Siciliano 		free(__DECONST(char *, minilabel[i]));
40650e24496SAlfonso S. Siciliano 
40750e24496SAlfonso S. Siciliano 	free(minilabel);
40850e24496SAlfonso S. Siciliano 	free(miniperc);
4092118f387SNathan Whitehorn 
410c2f16c59SNathan Whitehorn 	/* Sort filesystems for fstab so that mountpoints are ordered */
411c2f16c59SNathan Whitehorn 	{
412c2f16c59SNathan Whitehorn 		struct partition_metadata **tobesorted;
413c2f16c59SNathan Whitehorn 		struct partition_metadata *tmp;
414c2f16c59SNathan Whitehorn 		int nparts = 0;
415c2f16c59SNathan Whitehorn 		TAILQ_FOREACH(md, &part_metadata, metadata)
416c2f16c59SNathan Whitehorn 			nparts++;
417c2f16c59SNathan Whitehorn 		tobesorted = malloc(sizeof(struct partition_metadata *)*nparts);
418c2f16c59SNathan Whitehorn 		nparts = 0;
419c2f16c59SNathan Whitehorn 		TAILQ_FOREACH_SAFE(md, &part_metadata, metadata, tmp) {
420c2f16c59SNathan Whitehorn 			tobesorted[nparts++] = md;
421c2f16c59SNathan Whitehorn 			TAILQ_REMOVE(&part_metadata, md, metadata);
422c2f16c59SNathan Whitehorn 		}
423c2f16c59SNathan Whitehorn 		qsort(tobesorted, nparts, sizeof(tobesorted[0]),
424c2f16c59SNathan Whitehorn 		    mountpoint_sorter);
425c2f16c59SNathan Whitehorn 
426c2f16c59SNathan Whitehorn 		/* Now re-add everything */
427c2f16c59SNathan Whitehorn 		while (nparts-- > 0)
428c2f16c59SNathan Whitehorn 			TAILQ_INSERT_HEAD(&part_metadata,
429c2f16c59SNathan Whitehorn 			    tobesorted[nparts], metadata);
430c2f16c59SNathan Whitehorn 		free(tobesorted);
431c2f16c59SNathan Whitehorn 	}
432c2f16c59SNathan Whitehorn 
4332118f387SNathan Whitehorn 	if (getenv("PATH_FSTAB") != NULL)
4342118f387SNathan Whitehorn 		fstab_path = getenv("PATH_FSTAB");
4352118f387SNathan Whitehorn 	else
4362118f387SNathan Whitehorn 		fstab_path = "/etc/fstab";
4372118f387SNathan Whitehorn 	fstab = fopen(fstab_path, "w+");
4382118f387SNathan Whitehorn 	if (fstab == NULL) {
4396e8bf240SJohn Baldwin 		snprintf(message, sizeof(message),
4406e8bf240SJohn Baldwin 		    "Cannot open fstab file %s for writing (%s)\n",
4412118f387SNathan Whitehorn 		    getenv("PATH_FSTAB"), strerror(errno));
44250e24496SAlfonso S. Siciliano 		conf.title = "Error";
44350e24496SAlfonso S. Siciliano 		bsddialog_msgbox(&conf, message, 0, 0);
4442118f387SNathan Whitehorn 		return (-1);
4452118f387SNathan Whitehorn 	}
4462118f387SNathan Whitehorn 	fprintf(fstab, "# Device\tMountpoint\tFStype\tOptions\tDump\tPass#\n");
4472118f387SNathan Whitehorn 	TAILQ_FOREACH(md, &part_metadata, metadata) {
4482118f387SNathan Whitehorn 		if (md->fstab != NULL)
44926092385SKevin Lo 			fprintf(fstab, "%s\t%s\t\t%s\t%s\t%d\t%d\n",
4502118f387SNathan Whitehorn 			    md->fstab->fs_spec, md->fstab->fs_file,
4512118f387SNathan Whitehorn 			    md->fstab->fs_vfstype, md->fstab->fs_mntops,
4522118f387SNathan Whitehorn 			    md->fstab->fs_freq, md->fstab->fs_passno);
4532118f387SNathan Whitehorn 	}
4542118f387SNathan Whitehorn 	fclose(fstab);
4552118f387SNathan Whitehorn 
4562118f387SNathan Whitehorn 	return (0);
4572118f387SNathan Whitehorn }
4582118f387SNathan Whitehorn 
4597059fa6fSAllan Jude static void
apply_workaround(struct gmesh * mesh)4607059fa6fSAllan Jude apply_workaround(struct gmesh *mesh)
4617059fa6fSAllan Jude {
4627059fa6fSAllan Jude 	struct gclass *classp;
4637059fa6fSAllan Jude 	struct ggeom *gp;
4647059fa6fSAllan Jude 	struct gconfig *gc;
4657059fa6fSAllan Jude 	const char *scheme = NULL, *modified = NULL;
46650e24496SAlfonso S. Siciliano 	struct bsddialog_conf conf;
4677059fa6fSAllan Jude 
4687059fa6fSAllan Jude 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
4697059fa6fSAllan Jude 		if (strcmp(classp->lg_name, "PART") == 0)
4707059fa6fSAllan Jude 			break;
4717059fa6fSAllan Jude 	}
4727059fa6fSAllan Jude 
4737059fa6fSAllan Jude 	if (strcmp(classp->lg_name, "PART") != 0) {
47450e24496SAlfonso S. Siciliano 		bsddialog_initconf(&conf);
47550e24496SAlfonso S. Siciliano 		conf.title = "Error";
47650e24496SAlfonso S. Siciliano 		bsddialog_msgbox(&conf, "gpart not found!", 0, 0);
4777059fa6fSAllan Jude 		return;
4787059fa6fSAllan Jude 	}
4797059fa6fSAllan Jude 
4807059fa6fSAllan Jude 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
4817059fa6fSAllan Jude 		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
4827059fa6fSAllan Jude 			if (strcmp(gc->lg_name, "scheme") == 0) {
4837059fa6fSAllan Jude 				scheme = gc->lg_val;
4847059fa6fSAllan Jude 			} else if (strcmp(gc->lg_name, "modified") == 0) {
4857059fa6fSAllan Jude 				modified = gc->lg_val;
4867059fa6fSAllan Jude 			}
4877059fa6fSAllan Jude 		}
4887059fa6fSAllan Jude 
4897059fa6fSAllan Jude 		if (scheme && strcmp(scheme, "GPT") == 0 &&
4907059fa6fSAllan Jude 		    modified && strcmp(modified, "true") == 0) {
4917059fa6fSAllan Jude 			if (getenv("WORKAROUND_LENOVO"))
4927059fa6fSAllan Jude 				gpart_set_root(gp->lg_name, "lenovofix");
4937059fa6fSAllan Jude 			if (getenv("WORKAROUND_GPTACTIVE"))
4947059fa6fSAllan Jude 				gpart_set_root(gp->lg_name, "active");
4957059fa6fSAllan Jude 		}
4967059fa6fSAllan Jude 	}
4977059fa6fSAllan Jude }
4987059fa6fSAllan Jude 
4992118f387SNathan Whitehorn static struct partedit_item *
read_geom_mesh(struct gmesh * mesh,int * nitems)500bcc25b7eSNathan Whitehorn read_geom_mesh(struct gmesh *mesh, int *nitems)
501bcc25b7eSNathan Whitehorn {
5022118f387SNathan Whitehorn 	struct gclass *classp;
5032118f387SNathan Whitehorn 	struct ggeom *gp;
5042118f387SNathan Whitehorn 	struct partedit_item *items;
5052118f387SNathan Whitehorn 
5062118f387SNathan Whitehorn 	*nitems = 0;
5072118f387SNathan Whitehorn 	items = NULL;
5082118f387SNathan Whitehorn 
5092118f387SNathan Whitehorn 	/*
5102118f387SNathan Whitehorn 	 * Build the device table. First add all disks (and CDs).
5112118f387SNathan Whitehorn 	 */
5122118f387SNathan Whitehorn 
5132118f387SNathan Whitehorn 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
5142118f387SNathan Whitehorn 		if (strcmp(classp->lg_name, "DISK") != 0 &&
5152118f387SNathan Whitehorn 		    strcmp(classp->lg_name, "MD") != 0)
5162118f387SNathan Whitehorn 			continue;
5172118f387SNathan Whitehorn 
5182118f387SNathan Whitehorn 		/* Now recurse into all children */
5192118f387SNathan Whitehorn 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom)
5202118f387SNathan Whitehorn 			add_geom_children(gp, 0, &items, nitems);
5212118f387SNathan Whitehorn 	}
5222118f387SNathan Whitehorn 
5232118f387SNathan Whitehorn 	return (items);
5242118f387SNathan Whitehorn }
5252118f387SNathan Whitehorn 
5262118f387SNathan Whitehorn static void
add_geom_children(struct ggeom * gp,int recurse,struct partedit_item ** items,int * nitems)5272118f387SNathan Whitehorn add_geom_children(struct ggeom *gp, int recurse, struct partedit_item **items,
528bcc25b7eSNathan Whitehorn     int *nitems)
529bcc25b7eSNathan Whitehorn {
5302118f387SNathan Whitehorn 	struct gconsumer *cp;
5312118f387SNathan Whitehorn 	struct gprovider *pp;
5322118f387SNathan Whitehorn 	struct gconfig *gc;
5332118f387SNathan Whitehorn 
5342118f387SNathan Whitehorn 	if (strcmp(gp->lg_class->lg_name, "PART") == 0 &&
5352118f387SNathan Whitehorn 	    !LIST_EMPTY(&gp->lg_config)) {
5362118f387SNathan Whitehorn 		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
5372118f387SNathan Whitehorn 			if (strcmp(gc->lg_name, "scheme") == 0)
5382118f387SNathan Whitehorn 				(*items)[*nitems-1].type = gc->lg_val;
5392118f387SNathan Whitehorn 		}
5402118f387SNathan Whitehorn 	}
5412118f387SNathan Whitehorn 
5422118f387SNathan Whitehorn 	if (LIST_EMPTY(&gp->lg_provider))
5432118f387SNathan Whitehorn 		return;
5442118f387SNathan Whitehorn 
5452118f387SNathan Whitehorn 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
5462118f387SNathan Whitehorn 		if (strcmp(gp->lg_class->lg_name, "LABEL") == 0)
5472118f387SNathan Whitehorn 			continue;
5482118f387SNathan Whitehorn 
5492118f387SNathan Whitehorn 		/* Skip WORM media */
5502118f387SNathan Whitehorn 		if (strncmp(pp->lg_name, "cd", 2) == 0)
5512118f387SNathan Whitehorn 			continue;
5522118f387SNathan Whitehorn 
5532118f387SNathan Whitehorn 		*items = realloc(*items,
5542118f387SNathan Whitehorn 		    (*nitems+1)*sizeof(struct partedit_item));
5552118f387SNathan Whitehorn 		(*items)[*nitems].indentation = recurse;
5562118f387SNathan Whitehorn 		(*items)[*nitems].name = pp->lg_name;
5572118f387SNathan Whitehorn 		(*items)[*nitems].size = pp->lg_mediasize;
5582118f387SNathan Whitehorn 		(*items)[*nitems].mountpoint = NULL;
5592118f387SNathan Whitehorn 		(*items)[*nitems].type = "";
5602118f387SNathan Whitehorn 		(*items)[*nitems].cookie = pp;
5612118f387SNathan Whitehorn 
5622118f387SNathan Whitehorn 		LIST_FOREACH(gc, &pp->lg_config, lg_config) {
5632118f387SNathan Whitehorn 			if (strcmp(gc->lg_name, "type") == 0)
5642118f387SNathan Whitehorn 				(*items)[*nitems].type = gc->lg_val;
5652118f387SNathan Whitehorn 		}
5662118f387SNathan Whitehorn 
5672118f387SNathan Whitehorn 		/* Skip swap-backed MD devices */
5682118f387SNathan Whitehorn 		if (strcmp(gp->lg_class->lg_name, "MD") == 0 &&
5692118f387SNathan Whitehorn 		    strcmp((*items)[*nitems].type, "swap") == 0)
5702118f387SNathan Whitehorn 			continue;
5712118f387SNathan Whitehorn 
5722118f387SNathan Whitehorn 		(*nitems)++;
5732118f387SNathan Whitehorn 
5742118f387SNathan Whitehorn 		LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
5752118f387SNathan Whitehorn 			add_geom_children(cp->lg_geom, recurse+1, items,
5762118f387SNathan Whitehorn 			    nitems);
5772118f387SNathan Whitehorn 
5782118f387SNathan Whitehorn 		/* Only use first provider for acd */
5792118f387SNathan Whitehorn 		if (strcmp(gp->lg_class->lg_name, "ACD") == 0)
5802118f387SNathan Whitehorn 			break;
5812118f387SNathan Whitehorn 	}
5822118f387SNathan Whitehorn }
5832118f387SNathan Whitehorn 
5842118f387SNathan Whitehorn static void
init_fstab_metadata(void)5852118f387SNathan Whitehorn init_fstab_metadata(void)
5862118f387SNathan Whitehorn {
5872118f387SNathan Whitehorn 	struct fstab *fstab;
5882118f387SNathan Whitehorn 	struct partition_metadata *md;
5892118f387SNathan Whitehorn 
5902118f387SNathan Whitehorn 	setfsent();
5912118f387SNathan Whitehorn 	while ((fstab = getfsent()) != NULL) {
5922118f387SNathan Whitehorn 		md = calloc(1, sizeof(struct partition_metadata));
5932118f387SNathan Whitehorn 
5942118f387SNathan Whitehorn 		md->name = NULL;
5952118f387SNathan Whitehorn 		if (strncmp(fstab->fs_spec, "/dev/", 5) == 0)
5962118f387SNathan Whitehorn 			md->name = strdup(&fstab->fs_spec[5]);
5972118f387SNathan Whitehorn 
5982118f387SNathan Whitehorn 		md->fstab = malloc(sizeof(struct fstab));
5992118f387SNathan Whitehorn 		md->fstab->fs_spec = strdup(fstab->fs_spec);
6002118f387SNathan Whitehorn 		md->fstab->fs_file = strdup(fstab->fs_file);
6012118f387SNathan Whitehorn 		md->fstab->fs_vfstype = strdup(fstab->fs_vfstype);
6022118f387SNathan Whitehorn 		md->fstab->fs_mntops = strdup(fstab->fs_mntops);
6032118f387SNathan Whitehorn 		md->fstab->fs_type = strdup(fstab->fs_type);
6042118f387SNathan Whitehorn 		md->fstab->fs_freq = fstab->fs_freq;
6052118f387SNathan Whitehorn 		md->fstab->fs_passno = fstab->fs_passno;
6062118f387SNathan Whitehorn 
6072118f387SNathan Whitehorn 		md->newfs = NULL;
6082118f387SNathan Whitehorn 
6092118f387SNathan Whitehorn 		TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
6102118f387SNathan Whitehorn 	}
6112118f387SNathan Whitehorn }
6122118f387SNathan Whitehorn 
6132118f387SNathan Whitehorn static void
get_mount_points(struct partedit_item * items,int nitems)6142118f387SNathan Whitehorn get_mount_points(struct partedit_item *items, int nitems)
6152118f387SNathan Whitehorn {
6162118f387SNathan Whitehorn 	struct partition_metadata *md;
6172118f387SNathan Whitehorn 	int i;
6182118f387SNathan Whitehorn 
6192118f387SNathan Whitehorn 	for (i = 0; i < nitems; i++) {
6202118f387SNathan Whitehorn 		TAILQ_FOREACH(md, &part_metadata, metadata) {
6212118f387SNathan Whitehorn 			if (md->name != NULL && md->fstab != NULL &&
6222118f387SNathan Whitehorn 			    strcmp(md->name, items[i].name) == 0) {
6232118f387SNathan Whitehorn 				items[i].mountpoint = md->fstab->fs_file;
6242118f387SNathan Whitehorn 				break;
6252118f387SNathan Whitehorn 			}
6262118f387SNathan Whitehorn 		}
6272118f387SNathan Whitehorn 	}
6282118f387SNathan Whitehorn }
629