1218799Snwhitehorn/*-
2218799Snwhitehorn * Copyright (c) 2011 Nathan Whitehorn
3218799Snwhitehorn * All rights reserved.
4218799Snwhitehorn *
5218799Snwhitehorn * Redistribution and use in source and binary forms, with or without
6218799Snwhitehorn * modification, are permitted provided that the following conditions
7218799Snwhitehorn * are met:
8218799Snwhitehorn * 1. Redistributions of source code must retain the above copyright
9218799Snwhitehorn *    notice, this list of conditions and the following disclaimer.
10218799Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
11218799Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
12218799Snwhitehorn *    documentation and/or other materials provided with the distribution.
13218799Snwhitehorn *
14218799Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15218799Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16218799Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17218799Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18218799Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19218799Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20218799Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21218799Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22218799Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23218799Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24218799Snwhitehorn * SUCH DAMAGE.
25218799Snwhitehorn *
26218799Snwhitehorn * $FreeBSD$
27218799Snwhitehorn */
28218799Snwhitehorn
29218799Snwhitehorn#include <sys/param.h>
30218799Snwhitehorn#include <libgen.h>
31218799Snwhitehorn#include <libutil.h>
32218799Snwhitehorn#include <inttypes.h>
33218799Snwhitehorn#include <errno.h>
34218799Snwhitehorn
35218799Snwhitehorn#include <fstab.h>
36218799Snwhitehorn#include <libgeom.h>
37218799Snwhitehorn#include <dialog.h>
38218799Snwhitehorn#include <dlg_keys.h>
39218799Snwhitehorn
40218799Snwhitehorn#include "diskeditor.h"
41218799Snwhitehorn#include "partedit.h"
42218799Snwhitehorn
43218799Snwhitehornstruct pmetadata_head part_metadata;
44244858Snwhitehornstatic int sade_mode = 0;
45218799Snwhitehorn
46218799Snwhitehornstatic int apply_changes(struct gmesh *mesh);
47218799Snwhitehornstatic struct partedit_item *read_geom_mesh(struct gmesh *mesh, int *nitems);
48218799Snwhitehornstatic void add_geom_children(struct ggeom *gp, int recurse,
49218799Snwhitehorn    struct partedit_item **items, int *nitems);
50218799Snwhitehornstatic void init_fstab_metadata(void);
51218799Snwhitehornstatic void get_mount_points(struct partedit_item *items, int nitems);
52218799Snwhitehornstatic int validate_setup(void);
53218799Snwhitehorn
54225066Snwhitehornstatic void
55225066Snwhitehornsigint_handler(int sig)
56225066Snwhitehorn{
57225066Snwhitehorn	struct gmesh mesh;
58225066Snwhitehorn
59225066Snwhitehorn	/* Revert all changes and exit dialog-mode cleanly on SIGINT */
60225066Snwhitehorn	geom_gettree(&mesh);
61225066Snwhitehorn	gpart_revert_all(&mesh);
62225066Snwhitehorn	geom_deletetree(&mesh);
63225066Snwhitehorn
64225066Snwhitehorn	end_dialog();
65225066Snwhitehorn
66225066Snwhitehorn	exit(1);
67225066Snwhitehorn}
68225066Snwhitehorn
69218799Snwhitehornint
70225066Snwhitehornmain(int argc, const char **argv)
71225066Snwhitehorn{
72218799Snwhitehorn	struct partition_metadata *md;
73218799Snwhitehorn	const char *prompt;
74226739Snwhitehorn	struct partedit_item *items = NULL;
75218799Snwhitehorn	struct gmesh mesh;
76218799Snwhitehorn	int i, op, nitems, nscroll;
77218799Snwhitehorn	int error;
78218799Snwhitehorn
79244858Snwhitehorn	if (strcmp(basename(argv[0]), "sade") == 0)
80244858Snwhitehorn		sade_mode = 1;
81244858Snwhitehorn
82218799Snwhitehorn	TAILQ_INIT(&part_metadata);
83218799Snwhitehorn
84218799Snwhitehorn	init_fstab_metadata();
85218799Snwhitehorn
86218799Snwhitehorn	init_dialog(stdin, stdout);
87244858Snwhitehorn	if (!sade_mode)
88218799Snwhitehorn		dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
89218799Snwhitehorn	dialog_vars.item_help = TRUE;
90218799Snwhitehorn	nscroll = i = 0;
91218799Snwhitehorn
92225066Snwhitehorn	/* Revert changes on SIGINT */
93225066Snwhitehorn	signal(SIGINT, sigint_handler);
94225066Snwhitehorn
95218799Snwhitehorn	if (strcmp(basename(argv[0]), "autopart") == 0) { /* Guided */
96218799Snwhitehorn		prompt = "Please review the disk setup. When complete, press "
97225066Snwhitehorn		    "the Finish button.";
98218799Snwhitehorn		part_wizard();
99245700Snwhitehorn	} else if (strcmp(basename(argv[0]), "scriptedpart") == 0) {
100245796Snwhitehorn		error = scripted_editor(argc, argv);
101245700Snwhitehorn		prompt = NULL;
102245796Snwhitehorn		if (error != 0) {
103245796Snwhitehorn			end_dialog();
104245796Snwhitehorn			return (error);
105245796Snwhitehorn		}
106218799Snwhitehorn	} else {
107218799Snwhitehorn		prompt = "Create partitions for FreeBSD. No changes will be "
108225066Snwhitehorn		    "made until you select Finish.";
109218799Snwhitehorn	}
110218799Snwhitehorn
111218799Snwhitehorn	/* Show the part editor either immediately, or to confirm wizard */
112245700Snwhitehorn	while (prompt != NULL) {
113218799Snwhitehorn		dlg_clear();
114218799Snwhitehorn		dlg_put_backtitle();
115218799Snwhitehorn
116226739Snwhitehorn		error = geom_gettree(&mesh);
117226739Snwhitehorn		if (error == 0)
118226739Snwhitehorn			items = read_geom_mesh(&mesh, &nitems);
119226739Snwhitehorn		if (error || items == NULL) {
120226739Snwhitehorn			dialog_msgbox("Error", "No disks found. If you need to "
121226739Snwhitehorn			    "install a kernel driver, choose Shell at the "
122226739Snwhitehorn			    "installation menu.", 0, 0, TRUE);
123226739Snwhitehorn			break;
124226739Snwhitehorn		}
125226739Snwhitehorn
126226739Snwhitehorn		get_mount_points(items, nitems);
127226739Snwhitehorn
128218799Snwhitehorn		if (i >= nitems)
129218799Snwhitehorn			i = nitems - 1;
130218799Snwhitehorn		op = diskeditor_show("Partition Editor", prompt,
131218799Snwhitehorn		    items, nitems, &i, &nscroll);
132218799Snwhitehorn
133218799Snwhitehorn		switch (op) {
134218799Snwhitehorn		case 0: /* Create */
135218799Snwhitehorn			gpart_create((struct gprovider *)(items[i].cookie),
136218799Snwhitehorn			    NULL, NULL, NULL, NULL, 1);
137218799Snwhitehorn			break;
138218799Snwhitehorn		case 1: /* Delete */
139218799Snwhitehorn			gpart_delete((struct gprovider *)(items[i].cookie));
140218799Snwhitehorn			break;
141218799Snwhitehorn		case 2: /* Modify */
142218799Snwhitehorn			gpart_edit((struct gprovider *)(items[i].cookie));
143218799Snwhitehorn			break;
144218799Snwhitehorn		case 3: /* Revert */
145218799Snwhitehorn			gpart_revert_all(&mesh);
146218799Snwhitehorn			while ((md = TAILQ_FIRST(&part_metadata)) != NULL) {
147218799Snwhitehorn				if (md->fstab != NULL) {
148218799Snwhitehorn					free(md->fstab->fs_spec);
149218799Snwhitehorn					free(md->fstab->fs_file);
150218799Snwhitehorn					free(md->fstab->fs_vfstype);
151218799Snwhitehorn					free(md->fstab->fs_mntops);
152218799Snwhitehorn					free(md->fstab->fs_type);
153218799Snwhitehorn					free(md->fstab);
154218799Snwhitehorn				}
155218799Snwhitehorn				if (md->newfs != NULL)
156218799Snwhitehorn					free(md->newfs);
157218799Snwhitehorn				free(md->name);
158218799Snwhitehorn
159218799Snwhitehorn				TAILQ_REMOVE(&part_metadata, md, metadata);
160218799Snwhitehorn				free(md);
161218799Snwhitehorn			}
162218799Snwhitehorn			init_fstab_metadata();
163218799Snwhitehorn			break;
164218799Snwhitehorn		case 4: /* Auto */
165218799Snwhitehorn			part_wizard();
166218799Snwhitehorn			break;
167218799Snwhitehorn		}
168218799Snwhitehorn
169218799Snwhitehorn		error = 0;
170219391Snwhitehorn		if (op == 5) { /* Finished */
171225066Snwhitehorn			dialog_vars.ok_label = __DECONST(char *, "Commit");
172225066Snwhitehorn			dialog_vars.extra_label =
173225066Snwhitehorn			    __DECONST(char *, "Revert & Exit");
174218799Snwhitehorn			dialog_vars.extra_button = TRUE;
175225066Snwhitehorn			dialog_vars.cancel_label = __DECONST(char *, "Back");
176218799Snwhitehorn			op = dialog_yesno("Confirmation", "Your changes will "
177218799Snwhitehorn			    "now be written to disk. If you have chosen to "
178218799Snwhitehorn			    "overwrite existing data, it will be PERMANENTLY "
179225066Snwhitehorn			    "ERASED. Are you sure you want to commit your "
180225066Snwhitehorn			    "changes?", 0, 0);
181225066Snwhitehorn			dialog_vars.ok_label = NULL;
182218799Snwhitehorn			dialog_vars.extra_button = FALSE;
183225066Snwhitehorn			dialog_vars.cancel_label = NULL;
184218799Snwhitehorn
185219391Snwhitehorn			if (op == 0 && validate_setup()) { /* Save */
186218799Snwhitehorn				error = apply_changes(&mesh);
187218799Snwhitehorn				break;
188225066Snwhitehorn			} else if (op == 3) { /* Quit */
189218799Snwhitehorn				gpart_revert_all(&mesh);
190218799Snwhitehorn				error =	-1;
191218799Snwhitehorn				break;
192218799Snwhitehorn			}
193218799Snwhitehorn		}
194218799Snwhitehorn
195218799Snwhitehorn		geom_deletetree(&mesh);
196218799Snwhitehorn		free(items);
197218799Snwhitehorn	}
198218799Snwhitehorn
199245700Snwhitehorn	if (prompt == NULL) {
200245700Snwhitehorn		error = geom_gettree(&mesh);
201245700Snwhitehorn		if (validate_setup()) {
202245700Snwhitehorn			error = apply_changes(&mesh);
203245700Snwhitehorn		} else {
204245700Snwhitehorn			gpart_revert_all(&mesh);
205245700Snwhitehorn			error = -1;
206245700Snwhitehorn		}
207245700Snwhitehorn	}
208218799Snwhitehorn
209218799Snwhitehorn	geom_deletetree(&mesh);
210218799Snwhitehorn	free(items);
211218799Snwhitehorn	end_dialog();
212218799Snwhitehorn
213218799Snwhitehorn	return (error);
214218799Snwhitehorn}
215218799Snwhitehorn
216218799Snwhitehornstruct partition_metadata *
217218799Snwhitehornget_part_metadata(const char *name, int create)
218218799Snwhitehorn{
219218799Snwhitehorn	struct partition_metadata *md;
220218799Snwhitehorn
221218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata)
222218799Snwhitehorn		if (md->name != NULL && strcmp(md->name, name) == 0)
223218799Snwhitehorn			break;
224218799Snwhitehorn
225218799Snwhitehorn	if (md == NULL && create) {
226218799Snwhitehorn		md = calloc(1, sizeof(*md));
227218799Snwhitehorn		md->name = strdup(name);
228218799Snwhitehorn		TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
229218799Snwhitehorn	}
230218799Snwhitehorn
231218799Snwhitehorn	return (md);
232218799Snwhitehorn}
233218799Snwhitehorn
234218799Snwhitehornvoid
235225066Snwhitehorndelete_part_metadata(const char *name)
236225066Snwhitehorn{
237218799Snwhitehorn	struct partition_metadata *md;
238218799Snwhitehorn
239218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
240218799Snwhitehorn		if (md->name != NULL && strcmp(md->name, name) == 0) {
241218799Snwhitehorn			if (md->fstab != NULL) {
242218799Snwhitehorn				free(md->fstab->fs_spec);
243218799Snwhitehorn				free(md->fstab->fs_file);
244218799Snwhitehorn				free(md->fstab->fs_vfstype);
245218799Snwhitehorn				free(md->fstab->fs_mntops);
246218799Snwhitehorn				free(md->fstab->fs_type);
247218799Snwhitehorn				free(md->fstab);
248218799Snwhitehorn			}
249218799Snwhitehorn			if (md->newfs != NULL)
250218799Snwhitehorn				free(md->newfs);
251218799Snwhitehorn			free(md->name);
252218799Snwhitehorn
253218799Snwhitehorn			TAILQ_REMOVE(&part_metadata, md, metadata);
254218799Snwhitehorn			free(md);
255218799Snwhitehorn			break;
256218799Snwhitehorn		}
257218799Snwhitehorn	}
258218799Snwhitehorn}
259218799Snwhitehorn
260218799Snwhitehornstatic int
261218799Snwhitehornvalidate_setup(void)
262218799Snwhitehorn{
263230309Snwhitehorn	struct partition_metadata *md, *root = NULL;
264230309Snwhitehorn	int cancel;
265218799Snwhitehorn
266218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
267218799Snwhitehorn		if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0)
268230309Snwhitehorn			root = md;
269218799Snwhitehorn
270218799Snwhitehorn		/* XXX: Check for duplicate mountpoints */
271218799Snwhitehorn	}
272218799Snwhitehorn
273230309Snwhitehorn	if (root == NULL) {
274218799Snwhitehorn		dialog_msgbox("Error", "No root partition was found. "
275218799Snwhitehorn		    "The root FreeBSD partition must have a mountpoint of '/'.",
276218799Snwhitehorn		0, 0, TRUE);
277218799Snwhitehorn		return (FALSE);
278218799Snwhitehorn	}
279218799Snwhitehorn
280230309Snwhitehorn	/*
281230309Snwhitehorn	 * Check for root partitions that we aren't formatting, which is
282230309Snwhitehorn	 * usually a mistake
283230309Snwhitehorn	 */
284244858Snwhitehorn	if (root->newfs == NULL && !sade_mode) {
285230309Snwhitehorn		dialog_vars.defaultno = TRUE;
286230309Snwhitehorn		cancel = dialog_yesno("Warning", "The chosen root partition "
287230309Snwhitehorn		    "has a preexisting filesystem. If it contains an existing "
288230309Snwhitehorn		    "FreeBSD system, please update it with freebsd-update "
289230309Snwhitehorn		    "instead of installing a new system on it. The partition "
290230309Snwhitehorn		    "can also be erased by pressing \"No\" and then deleting "
291230309Snwhitehorn		    "and recreating it. Are you sure you want to proceed?",
292230309Snwhitehorn		    0, 0);
293230309Snwhitehorn		dialog_vars.defaultno = FALSE;
294230309Snwhitehorn		if (cancel)
295230309Snwhitehorn			return (FALSE);
296230309Snwhitehorn	}
297230309Snwhitehorn
298218799Snwhitehorn	return (TRUE);
299218799Snwhitehorn}
300218799Snwhitehorn
301218799Snwhitehornstatic int
302218799Snwhitehornapply_changes(struct gmesh *mesh)
303218799Snwhitehorn{
304218799Snwhitehorn	struct partition_metadata *md;
305218799Snwhitehorn	char message[512];
306218799Snwhitehorn	int i, nitems, error;
307218799Snwhitehorn	const char **items;
308218799Snwhitehorn	const char *fstab_path;
309218799Snwhitehorn	FILE *fstab;
310218799Snwhitehorn
311218799Snwhitehorn	nitems = 1; /* Partition table changes */
312218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
313218799Snwhitehorn		if (md->newfs != NULL)
314218799Snwhitehorn			nitems++;
315218799Snwhitehorn	}
316218799Snwhitehorn	items = calloc(nitems * 2, sizeof(const char *));
317218799Snwhitehorn	items[0] = "Writing partition tables";
318218799Snwhitehorn	items[1] = "7"; /* In progress */
319218799Snwhitehorn	i = 1;
320218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
321218799Snwhitehorn		if (md->newfs != NULL) {
322218799Snwhitehorn			char *item;
323218799Snwhitehorn			item = malloc(255);
324218799Snwhitehorn			sprintf(item, "Initializing %s", md->name);
325218799Snwhitehorn			items[i*2] = item;
326218799Snwhitehorn			items[i*2 + 1] = "Pending";
327218799Snwhitehorn			i++;
328218799Snwhitehorn		}
329218799Snwhitehorn	}
330218799Snwhitehorn
331218799Snwhitehorn	i = 0;
332218799Snwhitehorn	dialog_mixedgauge("Initializing",
333218799Snwhitehorn	    "Initializing file systems. Please wait.", 0, 0, i*100/nitems,
334218799Snwhitehorn	    nitems, __DECONST(char **, items));
335218799Snwhitehorn	gpart_commit(mesh);
336218799Snwhitehorn	items[i*2 + 1] = "3";
337218799Snwhitehorn	i++;
338218799Snwhitehorn
339218799Snwhitehorn	if (getenv("BSDINSTALL_LOG") == NULL)
340218799Snwhitehorn		setenv("BSDINSTALL_LOG", "/dev/null", 1);
341218799Snwhitehorn
342218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
343218799Snwhitehorn		if (md->newfs != NULL) {
344218799Snwhitehorn			items[i*2 + 1] = "7"; /* In progress */
345218799Snwhitehorn			dialog_mixedgauge("Initializing",
346218799Snwhitehorn			    "Initializing file systems. Please wait.", 0, 0,
347218799Snwhitehorn			    i*100/nitems, nitems, __DECONST(char **, items));
348218799Snwhitehorn			sprintf(message, "(echo %s; %s) >>%s 2>>%s",
349218799Snwhitehorn			    md->newfs, md->newfs, getenv("BSDINSTALL_LOG"),
350218799Snwhitehorn			    getenv("BSDINSTALL_LOG"));
351218799Snwhitehorn			error = system(message);
352218799Snwhitehorn			items[i*2 + 1] = (error == 0) ? "3" : "1";
353218799Snwhitehorn			i++;
354218799Snwhitehorn		}
355218799Snwhitehorn	}
356218799Snwhitehorn	dialog_mixedgauge("Initializing",
357218799Snwhitehorn	    "Initializing file systems. Please wait.", 0, 0,
358218799Snwhitehorn	    i*100/nitems, nitems, __DECONST(char **, items));
359218799Snwhitehorn
360218799Snwhitehorn	for (i = 1; i < nitems; i++)
361218799Snwhitehorn		free(__DECONST(char *, items[i*2]));
362218799Snwhitehorn	free(items);
363218799Snwhitehorn
364218799Snwhitehorn	if (getenv("PATH_FSTAB") != NULL)
365218799Snwhitehorn		fstab_path = getenv("PATH_FSTAB");
366218799Snwhitehorn	else
367218799Snwhitehorn		fstab_path = "/etc/fstab";
368218799Snwhitehorn	fstab = fopen(fstab_path, "w+");
369218799Snwhitehorn	if (fstab == NULL) {
370218799Snwhitehorn		sprintf(message, "Cannot open fstab file %s for writing (%s)\n",
371218799Snwhitehorn		    getenv("PATH_FSTAB"), strerror(errno));
372218799Snwhitehorn		dialog_msgbox("Error", message, 0, 0, TRUE);
373218799Snwhitehorn		return (-1);
374218799Snwhitehorn	}
375218799Snwhitehorn	fprintf(fstab, "# Device\tMountpoint\tFStype\tOptions\tDump\tPass#\n");
376218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
377218799Snwhitehorn		if (md->fstab != NULL)
378223832Skevlo			fprintf(fstab, "%s\t%s\t\t%s\t%s\t%d\t%d\n",
379218799Snwhitehorn			    md->fstab->fs_spec, md->fstab->fs_file,
380218799Snwhitehorn			    md->fstab->fs_vfstype, md->fstab->fs_mntops,
381218799Snwhitehorn			    md->fstab->fs_freq, md->fstab->fs_passno);
382218799Snwhitehorn	}
383218799Snwhitehorn	fclose(fstab);
384218799Snwhitehorn
385218799Snwhitehorn	return (0);
386218799Snwhitehorn}
387218799Snwhitehorn
388218799Snwhitehornstatic struct partedit_item *
389225066Snwhitehornread_geom_mesh(struct gmesh *mesh, int *nitems)
390225066Snwhitehorn{
391218799Snwhitehorn	struct gclass *classp;
392218799Snwhitehorn	struct ggeom *gp;
393218799Snwhitehorn	struct partedit_item *items;
394218799Snwhitehorn
395218799Snwhitehorn	*nitems = 0;
396218799Snwhitehorn	items = NULL;
397218799Snwhitehorn
398218799Snwhitehorn	/*
399218799Snwhitehorn	 * Build the device table. First add all disks (and CDs).
400218799Snwhitehorn	 */
401218799Snwhitehorn
402218799Snwhitehorn	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
403218799Snwhitehorn		if (strcmp(classp->lg_name, "DISK") != 0 &&
404225066Snwhitehorn		    strcmp(classp->lg_name, "MD") != 0)
405218799Snwhitehorn			continue;
406218799Snwhitehorn
407218799Snwhitehorn		/* Now recurse into all children */
408218799Snwhitehorn		LIST_FOREACH(gp, &classp->lg_geom, lg_geom)
409218799Snwhitehorn			add_geom_children(gp, 0, &items, nitems);
410218799Snwhitehorn	}
411218799Snwhitehorn
412218799Snwhitehorn	return (items);
413218799Snwhitehorn}
414218799Snwhitehorn
415218799Snwhitehornstatic void
416218799Snwhitehornadd_geom_children(struct ggeom *gp, int recurse, struct partedit_item **items,
417225066Snwhitehorn    int *nitems)
418225066Snwhitehorn{
419218799Snwhitehorn	struct gconsumer *cp;
420218799Snwhitehorn	struct gprovider *pp;
421218799Snwhitehorn	struct gconfig *gc;
422218799Snwhitehorn
423218799Snwhitehorn	if (strcmp(gp->lg_class->lg_name, "PART") == 0 &&
424218799Snwhitehorn	    !LIST_EMPTY(&gp->lg_config)) {
425218799Snwhitehorn		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
426218799Snwhitehorn			if (strcmp(gc->lg_name, "scheme") == 0)
427218799Snwhitehorn				(*items)[*nitems-1].type = gc->lg_val;
428218799Snwhitehorn		}
429218799Snwhitehorn	}
430218799Snwhitehorn
431218799Snwhitehorn	if (LIST_EMPTY(&gp->lg_provider))
432218799Snwhitehorn		return;
433218799Snwhitehorn
434218799Snwhitehorn	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
435218799Snwhitehorn		if (strcmp(gp->lg_class->lg_name, "LABEL") == 0)
436218799Snwhitehorn			continue;
437218799Snwhitehorn
438218799Snwhitehorn		/* Skip WORM media */
439218799Snwhitehorn		if (strncmp(pp->lg_name, "cd", 2) == 0)
440218799Snwhitehorn			continue;
441218799Snwhitehorn
442218799Snwhitehorn		*items = realloc(*items,
443218799Snwhitehorn		    (*nitems+1)*sizeof(struct partedit_item));
444218799Snwhitehorn		(*items)[*nitems].indentation = recurse;
445218799Snwhitehorn		(*items)[*nitems].name = pp->lg_name;
446218799Snwhitehorn		(*items)[*nitems].size = pp->lg_mediasize;
447218799Snwhitehorn		(*items)[*nitems].mountpoint = NULL;
448218799Snwhitehorn		(*items)[*nitems].type = "";
449218799Snwhitehorn		(*items)[*nitems].cookie = pp;
450218799Snwhitehorn
451218799Snwhitehorn		LIST_FOREACH(gc, &pp->lg_config, lg_config) {
452218799Snwhitehorn			if (strcmp(gc->lg_name, "type") == 0)
453218799Snwhitehorn				(*items)[*nitems].type = gc->lg_val;
454218799Snwhitehorn		}
455218799Snwhitehorn
456218799Snwhitehorn		/* Skip swap-backed MD devices */
457218799Snwhitehorn		if (strcmp(gp->lg_class->lg_name, "MD") == 0 &&
458218799Snwhitehorn		    strcmp((*items)[*nitems].type, "swap") == 0)
459218799Snwhitehorn			continue;
460218799Snwhitehorn
461218799Snwhitehorn		(*nitems)++;
462218799Snwhitehorn
463218799Snwhitehorn		LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
464218799Snwhitehorn			add_geom_children(cp->lg_geom, recurse+1, items,
465218799Snwhitehorn			    nitems);
466218799Snwhitehorn
467218799Snwhitehorn		/* Only use first provider for acd */
468218799Snwhitehorn		if (strcmp(gp->lg_class->lg_name, "ACD") == 0)
469218799Snwhitehorn			break;
470218799Snwhitehorn	}
471218799Snwhitehorn}
472218799Snwhitehorn
473218799Snwhitehornstatic void
474218799Snwhitehorninit_fstab_metadata(void)
475218799Snwhitehorn{
476218799Snwhitehorn	struct fstab *fstab;
477218799Snwhitehorn	struct partition_metadata *md;
478218799Snwhitehorn
479218799Snwhitehorn	setfsent();
480218799Snwhitehorn	while ((fstab = getfsent()) != NULL) {
481218799Snwhitehorn		md = calloc(1, sizeof(struct partition_metadata));
482218799Snwhitehorn
483218799Snwhitehorn		md->name = NULL;
484218799Snwhitehorn		if (strncmp(fstab->fs_spec, "/dev/", 5) == 0)
485218799Snwhitehorn			md->name = strdup(&fstab->fs_spec[5]);
486218799Snwhitehorn
487218799Snwhitehorn		md->fstab = malloc(sizeof(struct fstab));
488218799Snwhitehorn		md->fstab->fs_spec = strdup(fstab->fs_spec);
489218799Snwhitehorn		md->fstab->fs_file = strdup(fstab->fs_file);
490218799Snwhitehorn		md->fstab->fs_vfstype = strdup(fstab->fs_vfstype);
491218799Snwhitehorn		md->fstab->fs_mntops = strdup(fstab->fs_mntops);
492218799Snwhitehorn		md->fstab->fs_type = strdup(fstab->fs_type);
493218799Snwhitehorn		md->fstab->fs_freq = fstab->fs_freq;
494218799Snwhitehorn		md->fstab->fs_passno = fstab->fs_passno;
495218799Snwhitehorn
496218799Snwhitehorn		md->newfs = NULL;
497218799Snwhitehorn
498218799Snwhitehorn		TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
499218799Snwhitehorn	}
500218799Snwhitehorn}
501218799Snwhitehorn
502218799Snwhitehornstatic void
503218799Snwhitehornget_mount_points(struct partedit_item *items, int nitems)
504218799Snwhitehorn{
505218799Snwhitehorn	struct partition_metadata *md;
506218799Snwhitehorn	int i;
507218799Snwhitehorn
508218799Snwhitehorn	for (i = 0; i < nitems; i++) {
509218799Snwhitehorn		TAILQ_FOREACH(md, &part_metadata, metadata) {
510218799Snwhitehorn			if (md->name != NULL && md->fstab != NULL &&
511218799Snwhitehorn			    strcmp(md->name, items[i].name) == 0) {
512218799Snwhitehorn				items[i].mountpoint = md->fstab->fs_file;
513218799Snwhitehorn				break;
514218799Snwhitehorn			}
515218799Snwhitehorn		}
516218799Snwhitehorn	}
517218799Snwhitehorn}
518