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);
47285769Sallanjudestatic void apply_workaround(struct gmesh *mesh);
48218799Snwhitehornstatic struct partedit_item *read_geom_mesh(struct gmesh *mesh, int *nitems);
49218799Snwhitehornstatic void add_geom_children(struct ggeom *gp, int recurse,
50218799Snwhitehorn    struct partedit_item **items, int *nitems);
51218799Snwhitehornstatic void init_fstab_metadata(void);
52218799Snwhitehornstatic void get_mount_points(struct partedit_item *items, int nitems);
53218799Snwhitehornstatic int validate_setup(void);
54218799Snwhitehorn
55225066Snwhitehornstatic void
56225066Snwhitehornsigint_handler(int sig)
57225066Snwhitehorn{
58225066Snwhitehorn	struct gmesh mesh;
59225066Snwhitehorn
60225066Snwhitehorn	/* Revert all changes and exit dialog-mode cleanly on SIGINT */
61225066Snwhitehorn	geom_gettree(&mesh);
62225066Snwhitehorn	gpart_revert_all(&mesh);
63225066Snwhitehorn	geom_deletetree(&mesh);
64225066Snwhitehorn
65225066Snwhitehorn	end_dialog();
66225066Snwhitehorn
67225066Snwhitehorn	exit(1);
68225066Snwhitehorn}
69225066Snwhitehorn
70218799Snwhitehornint
71225066Snwhitehornmain(int argc, const char **argv)
72225066Snwhitehorn{
73218799Snwhitehorn	struct partition_metadata *md;
74218799Snwhitehorn	const char *prompt;
75226739Snwhitehorn	struct partedit_item *items = NULL;
76218799Snwhitehorn	struct gmesh mesh;
77218799Snwhitehorn	int i, op, nitems, nscroll;
78218799Snwhitehorn	int error;
79218799Snwhitehorn
80244858Snwhitehorn	if (strcmp(basename(argv[0]), "sade") == 0)
81244858Snwhitehorn		sade_mode = 1;
82244858Snwhitehorn
83218799Snwhitehorn	TAILQ_INIT(&part_metadata);
84218799Snwhitehorn
85218799Snwhitehorn	init_fstab_metadata();
86218799Snwhitehorn
87218799Snwhitehorn	init_dialog(stdin, stdout);
88244858Snwhitehorn	if (!sade_mode)
89218799Snwhitehorn		dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
90218799Snwhitehorn	dialog_vars.item_help = TRUE;
91218799Snwhitehorn	nscroll = i = 0;
92218799Snwhitehorn
93225066Snwhitehorn	/* Revert changes on SIGINT */
94225066Snwhitehorn	signal(SIGINT, sigint_handler);
95225066Snwhitehorn
96218799Snwhitehorn	if (strcmp(basename(argv[0]), "autopart") == 0) { /* Guided */
97218799Snwhitehorn		prompt = "Please review the disk setup. When complete, press "
98225066Snwhitehorn		    "the Finish button.";
99273831Snwhitehorn		/* Experimental ZFS autopartition support */
100273831Snwhitehorn		if (argc > 1 && strcmp(argv[1], "zfs") == 0) {
101273831Snwhitehorn			part_wizard("zfs");
102273831Snwhitehorn		} else {
103273831Snwhitehorn			part_wizard("ufs");
104273831Snwhitehorn		}
105245700Snwhitehorn	} else if (strcmp(basename(argv[0]), "scriptedpart") == 0) {
106245796Snwhitehorn		error = scripted_editor(argc, argv);
107245700Snwhitehorn		prompt = NULL;
108245796Snwhitehorn		if (error != 0) {
109245796Snwhitehorn			end_dialog();
110245796Snwhitehorn			return (error);
111245796Snwhitehorn		}
112218799Snwhitehorn	} else {
113218799Snwhitehorn		prompt = "Create partitions for FreeBSD. No changes will be "
114225066Snwhitehorn		    "made until you select Finish.";
115218799Snwhitehorn	}
116218799Snwhitehorn
117218799Snwhitehorn	/* Show the part editor either immediately, or to confirm wizard */
118245700Snwhitehorn	while (prompt != NULL) {
119218799Snwhitehorn		dlg_clear();
120218799Snwhitehorn		dlg_put_backtitle();
121218799Snwhitehorn
122226739Snwhitehorn		error = geom_gettree(&mesh);
123226739Snwhitehorn		if (error == 0)
124226739Snwhitehorn			items = read_geom_mesh(&mesh, &nitems);
125226739Snwhitehorn		if (error || items == NULL) {
126226739Snwhitehorn			dialog_msgbox("Error", "No disks found. If you need to "
127226739Snwhitehorn			    "install a kernel driver, choose Shell at the "
128226739Snwhitehorn			    "installation menu.", 0, 0, TRUE);
129226739Snwhitehorn			break;
130226739Snwhitehorn		}
131226739Snwhitehorn
132226739Snwhitehorn		get_mount_points(items, nitems);
133226739Snwhitehorn
134218799Snwhitehorn		if (i >= nitems)
135218799Snwhitehorn			i = nitems - 1;
136218799Snwhitehorn		op = diskeditor_show("Partition Editor", prompt,
137218799Snwhitehorn		    items, nitems, &i, &nscroll);
138218799Snwhitehorn
139218799Snwhitehorn		switch (op) {
140218799Snwhitehorn		case 0: /* Create */
141218799Snwhitehorn			gpart_create((struct gprovider *)(items[i].cookie),
142218799Snwhitehorn			    NULL, NULL, NULL, NULL, 1);
143218799Snwhitehorn			break;
144218799Snwhitehorn		case 1: /* Delete */
145218799Snwhitehorn			gpart_delete((struct gprovider *)(items[i].cookie));
146218799Snwhitehorn			break;
147218799Snwhitehorn		case 2: /* Modify */
148218799Snwhitehorn			gpart_edit((struct gprovider *)(items[i].cookie));
149218799Snwhitehorn			break;
150218799Snwhitehorn		case 3: /* Revert */
151218799Snwhitehorn			gpart_revert_all(&mesh);
152218799Snwhitehorn			while ((md = TAILQ_FIRST(&part_metadata)) != NULL) {
153218799Snwhitehorn				if (md->fstab != NULL) {
154218799Snwhitehorn					free(md->fstab->fs_spec);
155218799Snwhitehorn					free(md->fstab->fs_file);
156218799Snwhitehorn					free(md->fstab->fs_vfstype);
157218799Snwhitehorn					free(md->fstab->fs_mntops);
158218799Snwhitehorn					free(md->fstab->fs_type);
159218799Snwhitehorn					free(md->fstab);
160218799Snwhitehorn				}
161218799Snwhitehorn				if (md->newfs != NULL)
162218799Snwhitehorn					free(md->newfs);
163218799Snwhitehorn				free(md->name);
164218799Snwhitehorn
165218799Snwhitehorn				TAILQ_REMOVE(&part_metadata, md, metadata);
166218799Snwhitehorn				free(md);
167218799Snwhitehorn			}
168218799Snwhitehorn			init_fstab_metadata();
169218799Snwhitehorn			break;
170218799Snwhitehorn		case 4: /* Auto */
171273831Snwhitehorn			part_wizard("ufs");
172218799Snwhitehorn			break;
173218799Snwhitehorn		}
174218799Snwhitehorn
175218799Snwhitehorn		error = 0;
176219391Snwhitehorn		if (op == 5) { /* Finished */
177225066Snwhitehorn			dialog_vars.ok_label = __DECONST(char *, "Commit");
178225066Snwhitehorn			dialog_vars.extra_label =
179225066Snwhitehorn			    __DECONST(char *, "Revert & Exit");
180218799Snwhitehorn			dialog_vars.extra_button = TRUE;
181225066Snwhitehorn			dialog_vars.cancel_label = __DECONST(char *, "Back");
182218799Snwhitehorn			op = dialog_yesno("Confirmation", "Your changes will "
183218799Snwhitehorn			    "now be written to disk. If you have chosen to "
184218799Snwhitehorn			    "overwrite existing data, it will be PERMANENTLY "
185225066Snwhitehorn			    "ERASED. Are you sure you want to commit your "
186225066Snwhitehorn			    "changes?", 0, 0);
187225066Snwhitehorn			dialog_vars.ok_label = NULL;
188218799Snwhitehorn			dialog_vars.extra_button = FALSE;
189225066Snwhitehorn			dialog_vars.cancel_label = NULL;
190218799Snwhitehorn
191219391Snwhitehorn			if (op == 0 && validate_setup()) { /* Save */
192218799Snwhitehorn				error = apply_changes(&mesh);
193285769Sallanjude				if (!error)
194285769Sallanjude					apply_workaround(&mesh);
195218799Snwhitehorn				break;
196225066Snwhitehorn			} else if (op == 3) { /* Quit */
197218799Snwhitehorn				gpart_revert_all(&mesh);
198218799Snwhitehorn				error =	-1;
199218799Snwhitehorn				break;
200218799Snwhitehorn			}
201218799Snwhitehorn		}
202218799Snwhitehorn
203218799Snwhitehorn		geom_deletetree(&mesh);
204218799Snwhitehorn		free(items);
205218799Snwhitehorn	}
206218799Snwhitehorn
207245700Snwhitehorn	if (prompt == NULL) {
208245700Snwhitehorn		error = geom_gettree(&mesh);
209245700Snwhitehorn		if (validate_setup()) {
210245700Snwhitehorn			error = apply_changes(&mesh);
211245700Snwhitehorn		} else {
212245700Snwhitehorn			gpart_revert_all(&mesh);
213245700Snwhitehorn			error = -1;
214245700Snwhitehorn		}
215245700Snwhitehorn	}
216218799Snwhitehorn
217218799Snwhitehorn	geom_deletetree(&mesh);
218218799Snwhitehorn	free(items);
219218799Snwhitehorn	end_dialog();
220218799Snwhitehorn
221218799Snwhitehorn	return (error);
222218799Snwhitehorn}
223218799Snwhitehorn
224218799Snwhitehornstruct partition_metadata *
225218799Snwhitehornget_part_metadata(const char *name, int create)
226218799Snwhitehorn{
227218799Snwhitehorn	struct partition_metadata *md;
228218799Snwhitehorn
229218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata)
230218799Snwhitehorn		if (md->name != NULL && strcmp(md->name, name) == 0)
231218799Snwhitehorn			break;
232218799Snwhitehorn
233218799Snwhitehorn	if (md == NULL && create) {
234218799Snwhitehorn		md = calloc(1, sizeof(*md));
235218799Snwhitehorn		md->name = strdup(name);
236218799Snwhitehorn		TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
237218799Snwhitehorn	}
238218799Snwhitehorn
239218799Snwhitehorn	return (md);
240218799Snwhitehorn}
241218799Snwhitehorn
242218799Snwhitehornvoid
243225066Snwhitehorndelete_part_metadata(const char *name)
244225066Snwhitehorn{
245218799Snwhitehorn	struct partition_metadata *md;
246218799Snwhitehorn
247218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
248218799Snwhitehorn		if (md->name != NULL && strcmp(md->name, name) == 0) {
249218799Snwhitehorn			if (md->fstab != NULL) {
250218799Snwhitehorn				free(md->fstab->fs_spec);
251218799Snwhitehorn				free(md->fstab->fs_file);
252218799Snwhitehorn				free(md->fstab->fs_vfstype);
253218799Snwhitehorn				free(md->fstab->fs_mntops);
254218799Snwhitehorn				free(md->fstab->fs_type);
255218799Snwhitehorn				free(md->fstab);
256218799Snwhitehorn			}
257218799Snwhitehorn			if (md->newfs != NULL)
258218799Snwhitehorn				free(md->newfs);
259218799Snwhitehorn			free(md->name);
260218799Snwhitehorn
261218799Snwhitehorn			TAILQ_REMOVE(&part_metadata, md, metadata);
262218799Snwhitehorn			free(md);
263218799Snwhitehorn			break;
264218799Snwhitehorn		}
265218799Snwhitehorn	}
266218799Snwhitehorn}
267218799Snwhitehorn
268218799Snwhitehornstatic int
269218799Snwhitehornvalidate_setup(void)
270218799Snwhitehorn{
271230309Snwhitehorn	struct partition_metadata *md, *root = NULL;
272230309Snwhitehorn	int cancel;
273218799Snwhitehorn
274218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
275218799Snwhitehorn		if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0)
276230309Snwhitehorn			root = md;
277218799Snwhitehorn
278218799Snwhitehorn		/* XXX: Check for duplicate mountpoints */
279218799Snwhitehorn	}
280218799Snwhitehorn
281230309Snwhitehorn	if (root == NULL) {
282218799Snwhitehorn		dialog_msgbox("Error", "No root partition was found. "
283218799Snwhitehorn		    "The root FreeBSD partition must have a mountpoint of '/'.",
284218799Snwhitehorn		0, 0, TRUE);
285218799Snwhitehorn		return (FALSE);
286218799Snwhitehorn	}
287218799Snwhitehorn
288230309Snwhitehorn	/*
289230309Snwhitehorn	 * Check for root partitions that we aren't formatting, which is
290230309Snwhitehorn	 * usually a mistake
291230309Snwhitehorn	 */
292244858Snwhitehorn	if (root->newfs == NULL && !sade_mode) {
293230309Snwhitehorn		dialog_vars.defaultno = TRUE;
294230309Snwhitehorn		cancel = dialog_yesno("Warning", "The chosen root partition "
295230309Snwhitehorn		    "has a preexisting filesystem. If it contains an existing "
296230309Snwhitehorn		    "FreeBSD system, please update it with freebsd-update "
297230309Snwhitehorn		    "instead of installing a new system on it. The partition "
298230309Snwhitehorn		    "can also be erased by pressing \"No\" and then deleting "
299230309Snwhitehorn		    "and recreating it. Are you sure you want to proceed?",
300230309Snwhitehorn		    0, 0);
301230309Snwhitehorn		dialog_vars.defaultno = FALSE;
302230309Snwhitehorn		if (cancel)
303230309Snwhitehorn			return (FALSE);
304230309Snwhitehorn	}
305230309Snwhitehorn
306218799Snwhitehorn	return (TRUE);
307218799Snwhitehorn}
308218799Snwhitehorn
309218799Snwhitehornstatic int
310218799Snwhitehornapply_changes(struct gmesh *mesh)
311218799Snwhitehorn{
312218799Snwhitehorn	struct partition_metadata *md;
313218799Snwhitehorn	char message[512];
314218799Snwhitehorn	int i, nitems, error;
315218799Snwhitehorn	const char **items;
316218799Snwhitehorn	const char *fstab_path;
317218799Snwhitehorn	FILE *fstab;
318218799Snwhitehorn
319218799Snwhitehorn	nitems = 1; /* Partition table changes */
320218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
321218799Snwhitehorn		if (md->newfs != NULL)
322218799Snwhitehorn			nitems++;
323218799Snwhitehorn	}
324218799Snwhitehorn	items = calloc(nitems * 2, sizeof(const char *));
325218799Snwhitehorn	items[0] = "Writing partition tables";
326218799Snwhitehorn	items[1] = "7"; /* In progress */
327218799Snwhitehorn	i = 1;
328218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
329218799Snwhitehorn		if (md->newfs != NULL) {
330218799Snwhitehorn			char *item;
331218799Snwhitehorn			item = malloc(255);
332218799Snwhitehorn			sprintf(item, "Initializing %s", md->name);
333218799Snwhitehorn			items[i*2] = item;
334218799Snwhitehorn			items[i*2 + 1] = "Pending";
335218799Snwhitehorn			i++;
336218799Snwhitehorn		}
337218799Snwhitehorn	}
338218799Snwhitehorn
339218799Snwhitehorn	i = 0;
340218799Snwhitehorn	dialog_mixedgauge("Initializing",
341218799Snwhitehorn	    "Initializing file systems. Please wait.", 0, 0, i*100/nitems,
342218799Snwhitehorn	    nitems, __DECONST(char **, items));
343218799Snwhitehorn	gpart_commit(mesh);
344218799Snwhitehorn	items[i*2 + 1] = "3";
345218799Snwhitehorn	i++;
346218799Snwhitehorn
347218799Snwhitehorn	if (getenv("BSDINSTALL_LOG") == NULL)
348218799Snwhitehorn		setenv("BSDINSTALL_LOG", "/dev/null", 1);
349218799Snwhitehorn
350218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
351218799Snwhitehorn		if (md->newfs != NULL) {
352218799Snwhitehorn			items[i*2 + 1] = "7"; /* In progress */
353218799Snwhitehorn			dialog_mixedgauge("Initializing",
354218799Snwhitehorn			    "Initializing file systems. Please wait.", 0, 0,
355218799Snwhitehorn			    i*100/nitems, nitems, __DECONST(char **, items));
356218799Snwhitehorn			sprintf(message, "(echo %s; %s) >>%s 2>>%s",
357218799Snwhitehorn			    md->newfs, md->newfs, getenv("BSDINSTALL_LOG"),
358218799Snwhitehorn			    getenv("BSDINSTALL_LOG"));
359218799Snwhitehorn			error = system(message);
360218799Snwhitehorn			items[i*2 + 1] = (error == 0) ? "3" : "1";
361218799Snwhitehorn			i++;
362218799Snwhitehorn		}
363218799Snwhitehorn	}
364218799Snwhitehorn	dialog_mixedgauge("Initializing",
365218799Snwhitehorn	    "Initializing file systems. Please wait.", 0, 0,
366218799Snwhitehorn	    i*100/nitems, nitems, __DECONST(char **, items));
367218799Snwhitehorn
368218799Snwhitehorn	for (i = 1; i < nitems; i++)
369218799Snwhitehorn		free(__DECONST(char *, items[i*2]));
370218799Snwhitehorn	free(items);
371218799Snwhitehorn
372218799Snwhitehorn	if (getenv("PATH_FSTAB") != NULL)
373218799Snwhitehorn		fstab_path = getenv("PATH_FSTAB");
374218799Snwhitehorn	else
375218799Snwhitehorn		fstab_path = "/etc/fstab";
376218799Snwhitehorn	fstab = fopen(fstab_path, "w+");
377218799Snwhitehorn	if (fstab == NULL) {
378218799Snwhitehorn		sprintf(message, "Cannot open fstab file %s for writing (%s)\n",
379218799Snwhitehorn		    getenv("PATH_FSTAB"), strerror(errno));
380218799Snwhitehorn		dialog_msgbox("Error", message, 0, 0, TRUE);
381218799Snwhitehorn		return (-1);
382218799Snwhitehorn	}
383218799Snwhitehorn	fprintf(fstab, "# Device\tMountpoint\tFStype\tOptions\tDump\tPass#\n");
384218799Snwhitehorn	TAILQ_FOREACH(md, &part_metadata, metadata) {
385218799Snwhitehorn		if (md->fstab != NULL)
386223832Skevlo			fprintf(fstab, "%s\t%s\t\t%s\t%s\t%d\t%d\n",
387218799Snwhitehorn			    md->fstab->fs_spec, md->fstab->fs_file,
388218799Snwhitehorn			    md->fstab->fs_vfstype, md->fstab->fs_mntops,
389218799Snwhitehorn			    md->fstab->fs_freq, md->fstab->fs_passno);
390218799Snwhitehorn	}
391218799Snwhitehorn	fclose(fstab);
392218799Snwhitehorn
393218799Snwhitehorn	return (0);
394218799Snwhitehorn}
395218799Snwhitehorn
396285769Sallanjudestatic void
397285769Sallanjudeapply_workaround(struct gmesh *mesh)
398285769Sallanjude{
399285769Sallanjude	struct gclass *classp;
400285769Sallanjude	struct ggeom *gp;
401285769Sallanjude	struct gconfig *gc;
402285769Sallanjude	const char *scheme = NULL, *modified = NULL;
403285769Sallanjude
404285769Sallanjude	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
405285769Sallanjude		if (strcmp(classp->lg_name, "PART") == 0)
406285769Sallanjude			break;
407285769Sallanjude	}
408285769Sallanjude
409285769Sallanjude	if (strcmp(classp->lg_name, "PART") != 0) {
410285769Sallanjude		dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
411285769Sallanjude		return;
412285769Sallanjude	}
413285769Sallanjude
414285769Sallanjude	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
415285769Sallanjude		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
416285769Sallanjude			if (strcmp(gc->lg_name, "scheme") == 0) {
417285769Sallanjude				scheme = gc->lg_val;
418285769Sallanjude			} else if (strcmp(gc->lg_name, "modified") == 0) {
419285769Sallanjude				modified = gc->lg_val;
420285769Sallanjude			}
421285769Sallanjude		}
422285769Sallanjude
423285769Sallanjude		if (scheme && strcmp(scheme, "GPT") == 0 &&
424285769Sallanjude		    modified && strcmp(modified, "true") == 0) {
425285769Sallanjude			if (getenv("WORKAROUND_LENOVO"))
426285769Sallanjude				gpart_set_root(gp->lg_name, "lenovofix");
427285769Sallanjude			if (getenv("WORKAROUND_GPTACTIVE"))
428285769Sallanjude				gpart_set_root(gp->lg_name, "active");
429285769Sallanjude		}
430285769Sallanjude	}
431285769Sallanjude}
432285769Sallanjude
433218799Snwhitehornstatic struct partedit_item *
434225066Snwhitehornread_geom_mesh(struct gmesh *mesh, int *nitems)
435225066Snwhitehorn{
436218799Snwhitehorn	struct gclass *classp;
437218799Snwhitehorn	struct ggeom *gp;
438218799Snwhitehorn	struct partedit_item *items;
439218799Snwhitehorn
440218799Snwhitehorn	*nitems = 0;
441218799Snwhitehorn	items = NULL;
442218799Snwhitehorn
443218799Snwhitehorn	/*
444218799Snwhitehorn	 * Build the device table. First add all disks (and CDs).
445218799Snwhitehorn	 */
446218799Snwhitehorn
447218799Snwhitehorn	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
448218799Snwhitehorn		if (strcmp(classp->lg_name, "DISK") != 0 &&
449225066Snwhitehorn		    strcmp(classp->lg_name, "MD") != 0)
450218799Snwhitehorn			continue;
451218799Snwhitehorn
452218799Snwhitehorn		/* Now recurse into all children */
453218799Snwhitehorn		LIST_FOREACH(gp, &classp->lg_geom, lg_geom)
454218799Snwhitehorn			add_geom_children(gp, 0, &items, nitems);
455218799Snwhitehorn	}
456218799Snwhitehorn
457218799Snwhitehorn	return (items);
458218799Snwhitehorn}
459218799Snwhitehorn
460218799Snwhitehornstatic void
461218799Snwhitehornadd_geom_children(struct ggeom *gp, int recurse, struct partedit_item **items,
462225066Snwhitehorn    int *nitems)
463225066Snwhitehorn{
464218799Snwhitehorn	struct gconsumer *cp;
465218799Snwhitehorn	struct gprovider *pp;
466218799Snwhitehorn	struct gconfig *gc;
467218799Snwhitehorn
468218799Snwhitehorn	if (strcmp(gp->lg_class->lg_name, "PART") == 0 &&
469218799Snwhitehorn	    !LIST_EMPTY(&gp->lg_config)) {
470218799Snwhitehorn		LIST_FOREACH(gc, &gp->lg_config, lg_config) {
471218799Snwhitehorn			if (strcmp(gc->lg_name, "scheme") == 0)
472218799Snwhitehorn				(*items)[*nitems-1].type = gc->lg_val;
473218799Snwhitehorn		}
474218799Snwhitehorn	}
475218799Snwhitehorn
476218799Snwhitehorn	if (LIST_EMPTY(&gp->lg_provider))
477218799Snwhitehorn		return;
478218799Snwhitehorn
479218799Snwhitehorn	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
480218799Snwhitehorn		if (strcmp(gp->lg_class->lg_name, "LABEL") == 0)
481218799Snwhitehorn			continue;
482218799Snwhitehorn
483218799Snwhitehorn		/* Skip WORM media */
484218799Snwhitehorn		if (strncmp(pp->lg_name, "cd", 2) == 0)
485218799Snwhitehorn			continue;
486218799Snwhitehorn
487218799Snwhitehorn		*items = realloc(*items,
488218799Snwhitehorn		    (*nitems+1)*sizeof(struct partedit_item));
489218799Snwhitehorn		(*items)[*nitems].indentation = recurse;
490218799Snwhitehorn		(*items)[*nitems].name = pp->lg_name;
491218799Snwhitehorn		(*items)[*nitems].size = pp->lg_mediasize;
492218799Snwhitehorn		(*items)[*nitems].mountpoint = NULL;
493218799Snwhitehorn		(*items)[*nitems].type = "";
494218799Snwhitehorn		(*items)[*nitems].cookie = pp;
495218799Snwhitehorn
496218799Snwhitehorn		LIST_FOREACH(gc, &pp->lg_config, lg_config) {
497218799Snwhitehorn			if (strcmp(gc->lg_name, "type") == 0)
498218799Snwhitehorn				(*items)[*nitems].type = gc->lg_val;
499218799Snwhitehorn		}
500218799Snwhitehorn
501218799Snwhitehorn		/* Skip swap-backed MD devices */
502218799Snwhitehorn		if (strcmp(gp->lg_class->lg_name, "MD") == 0 &&
503218799Snwhitehorn		    strcmp((*items)[*nitems].type, "swap") == 0)
504218799Snwhitehorn			continue;
505218799Snwhitehorn
506218799Snwhitehorn		(*nitems)++;
507218799Snwhitehorn
508218799Snwhitehorn		LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
509218799Snwhitehorn			add_geom_children(cp->lg_geom, recurse+1, items,
510218799Snwhitehorn			    nitems);
511218799Snwhitehorn
512218799Snwhitehorn		/* Only use first provider for acd */
513218799Snwhitehorn		if (strcmp(gp->lg_class->lg_name, "ACD") == 0)
514218799Snwhitehorn			break;
515218799Snwhitehorn	}
516218799Snwhitehorn}
517218799Snwhitehorn
518218799Snwhitehornstatic void
519218799Snwhitehorninit_fstab_metadata(void)
520218799Snwhitehorn{
521218799Snwhitehorn	struct fstab *fstab;
522218799Snwhitehorn	struct partition_metadata *md;
523218799Snwhitehorn
524218799Snwhitehorn	setfsent();
525218799Snwhitehorn	while ((fstab = getfsent()) != NULL) {
526218799Snwhitehorn		md = calloc(1, sizeof(struct partition_metadata));
527218799Snwhitehorn
528218799Snwhitehorn		md->name = NULL;
529218799Snwhitehorn		if (strncmp(fstab->fs_spec, "/dev/", 5) == 0)
530218799Snwhitehorn			md->name = strdup(&fstab->fs_spec[5]);
531218799Snwhitehorn
532218799Snwhitehorn		md->fstab = malloc(sizeof(struct fstab));
533218799Snwhitehorn		md->fstab->fs_spec = strdup(fstab->fs_spec);
534218799Snwhitehorn		md->fstab->fs_file = strdup(fstab->fs_file);
535218799Snwhitehorn		md->fstab->fs_vfstype = strdup(fstab->fs_vfstype);
536218799Snwhitehorn		md->fstab->fs_mntops = strdup(fstab->fs_mntops);
537218799Snwhitehorn		md->fstab->fs_type = strdup(fstab->fs_type);
538218799Snwhitehorn		md->fstab->fs_freq = fstab->fs_freq;
539218799Snwhitehorn		md->fstab->fs_passno = fstab->fs_passno;
540218799Snwhitehorn
541218799Snwhitehorn		md->newfs = NULL;
542218799Snwhitehorn
543218799Snwhitehorn		TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
544218799Snwhitehorn	}
545218799Snwhitehorn}
546218799Snwhitehorn
547218799Snwhitehornstatic void
548218799Snwhitehornget_mount_points(struct partedit_item *items, int nitems)
549218799Snwhitehorn{
550218799Snwhitehorn	struct partition_metadata *md;
551218799Snwhitehorn	int i;
552218799Snwhitehorn
553218799Snwhitehorn	for (i = 0; i < nitems; i++) {
554218799Snwhitehorn		TAILQ_FOREACH(md, &part_metadata, metadata) {
555218799Snwhitehorn			if (md->name != NULL && md->fstab != NULL &&
556218799Snwhitehorn			    strcmp(md->name, items[i].name) == 0) {
557218799Snwhitehorn				items[i].mountpoint = md->fstab->fs_file;
558218799Snwhitehorn				break;
559218799Snwhitehorn			}
560218799Snwhitehorn		}
561218799Snwhitehorn	}
562218799Snwhitehorn}
563