2 * Copyright (c) 2011 Nathan Whitehorn
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
40 #include "diskeditor.h"
43 struct pmetadata_head part_metadata;
45 static int apply_changes(struct gmesh *mesh);
46 static struct partedit_item *read_geom_mesh(struct gmesh *mesh, int *nitems);
47 static void add_geom_children(struct ggeom *gp, int recurse,
48 struct partedit_item **items, int *nitems);
49 static void init_fstab_metadata(void);
50 static void get_mount_points(struct partedit_item *items, int nitems);
51 static int validate_setup(void);
54 sigint_handler(int sig)
58 /* Revert all changes and exit dialog-mode cleanly on SIGINT */
60 gpart_revert_all(&mesh);
61 geom_deletetree(&mesh);
69 main(int argc, const char **argv)
71 struct partition_metadata *md;
73 struct partedit_item *items;
75 int i, op, nitems, nscroll;
78 TAILQ_INIT(&part_metadata);
80 init_fstab_metadata();
82 init_dialog(stdin, stdout);
83 if (strcmp(basename(argv[0]), "sade") != 0)
84 dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
85 dialog_vars.item_help = TRUE;
88 /* Revert changes on SIGINT */
89 signal(SIGINT, sigint_handler);
91 if (strcmp(basename(argv[0]), "autopart") == 0) { /* Guided */
92 prompt = "Please review the disk setup. When complete, press "
96 prompt = "Create partitions for FreeBSD. No changes will be "
97 "made until you select Finish.";
100 /* Show the part editor either immediately, or to confirm wizard */
102 error = geom_gettree(&mesh);
103 items = read_geom_mesh(&mesh, &nitems);
104 get_mount_points(items, nitems);
110 op = diskeditor_show("Partition Editor", prompt,
111 items, nitems, &i, &nscroll);
115 gpart_create((struct gprovider *)(items[i].cookie),
116 NULL, NULL, NULL, NULL, 1);
119 gpart_delete((struct gprovider *)(items[i].cookie));
122 gpart_edit((struct gprovider *)(items[i].cookie));
125 gpart_revert_all(&mesh);
126 while ((md = TAILQ_FIRST(&part_metadata)) != NULL) {
127 if (md->fstab != NULL) {
128 free(md->fstab->fs_spec);
129 free(md->fstab->fs_file);
130 free(md->fstab->fs_vfstype);
131 free(md->fstab->fs_mntops);
132 free(md->fstab->fs_type);
135 if (md->newfs != NULL)
139 TAILQ_REMOVE(&part_metadata, md, metadata);
142 init_fstab_metadata();
150 if (op == 5) { /* Finished */
151 dialog_vars.ok_label = __DECONST(char *, "Commit");
152 dialog_vars.extra_label =
153 __DECONST(char *, "Revert & Exit");
154 dialog_vars.extra_button = TRUE;
155 dialog_vars.cancel_label = __DECONST(char *, "Back");
156 op = dialog_yesno("Confirmation", "Your changes will "
157 "now be written to disk. If you have chosen to "
158 "overwrite existing data, it will be PERMANENTLY "
159 "ERASED. Are you sure you want to commit your "
161 dialog_vars.ok_label = NULL;
162 dialog_vars.extra_button = FALSE;
163 dialog_vars.cancel_label = NULL;
165 if (op == 0 && validate_setup()) { /* Save */
166 error = apply_changes(&mesh);
168 } else if (op == 3) { /* Quit */
169 gpart_revert_all(&mesh);
175 geom_deletetree(&mesh);
180 geom_deletetree(&mesh);
187 struct partition_metadata *
188 get_part_metadata(const char *name, int create)
190 struct partition_metadata *md;
192 TAILQ_FOREACH(md, &part_metadata, metadata)
193 if (md->name != NULL && strcmp(md->name, name) == 0)
196 if (md == NULL && create) {
197 md = calloc(1, sizeof(*md));
198 md->name = strdup(name);
199 TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
206 delete_part_metadata(const char *name)
208 struct partition_metadata *md;
210 TAILQ_FOREACH(md, &part_metadata, metadata) {
211 if (md->name != NULL && strcmp(md->name, name) == 0) {
212 if (md->fstab != NULL) {
213 free(md->fstab->fs_spec);
214 free(md->fstab->fs_file);
215 free(md->fstab->fs_vfstype);
216 free(md->fstab->fs_mntops);
217 free(md->fstab->fs_type);
220 if (md->newfs != NULL)
224 TAILQ_REMOVE(&part_metadata, md, metadata);
234 struct partition_metadata *md;
235 int root_found = FALSE;
237 TAILQ_FOREACH(md, &part_metadata, metadata) {
238 if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0)
241 /* XXX: Check for duplicate mountpoints */
245 dialog_msgbox("Error", "No root partition was found. "
246 "The root FreeBSD partition must have a mountpoint of '/'.",
255 apply_changes(struct gmesh *mesh)
257 struct partition_metadata *md;
259 int i, nitems, error;
261 const char *fstab_path;
264 nitems = 1; /* Partition table changes */
265 TAILQ_FOREACH(md, &part_metadata, metadata) {
266 if (md->newfs != NULL)
269 items = calloc(nitems * 2, sizeof(const char *));
270 items[0] = "Writing partition tables";
271 items[1] = "7"; /* In progress */
273 TAILQ_FOREACH(md, &part_metadata, metadata) {
274 if (md->newfs != NULL) {
277 sprintf(item, "Initializing %s", md->name);
279 items[i*2 + 1] = "Pending";
285 dialog_mixedgauge("Initializing",
286 "Initializing file systems. Please wait.", 0, 0, i*100/nitems,
287 nitems, __DECONST(char **, items));
289 items[i*2 + 1] = "3";
292 if (getenv("BSDINSTALL_LOG") == NULL)
293 setenv("BSDINSTALL_LOG", "/dev/null", 1);
295 TAILQ_FOREACH(md, &part_metadata, metadata) {
296 if (md->newfs != NULL) {
297 items[i*2 + 1] = "7"; /* In progress */
298 dialog_mixedgauge("Initializing",
299 "Initializing file systems. Please wait.", 0, 0,
300 i*100/nitems, nitems, __DECONST(char **, items));
301 sprintf(message, "(echo %s; %s) >>%s 2>>%s",
302 md->newfs, md->newfs, getenv("BSDINSTALL_LOG"),
303 getenv("BSDINSTALL_LOG"));
304 error = system(message);
305 items[i*2 + 1] = (error == 0) ? "3" : "1";
309 dialog_mixedgauge("Initializing",
310 "Initializing file systems. Please wait.", 0, 0,
311 i*100/nitems, nitems, __DECONST(char **, items));
313 for (i = 1; i < nitems; i++)
314 free(__DECONST(char *, items[i*2]));
317 if (getenv("PATH_FSTAB") != NULL)
318 fstab_path = getenv("PATH_FSTAB");
320 fstab_path = "/etc/fstab";
321 fstab = fopen(fstab_path, "w+");
323 sprintf(message, "Cannot open fstab file %s for writing (%s)\n",
324 getenv("PATH_FSTAB"), strerror(errno));
325 dialog_msgbox("Error", message, 0, 0, TRUE);
328 fprintf(fstab, "# Device\tMountpoint\tFStype\tOptions\tDump\tPass#\n");
329 TAILQ_FOREACH(md, &part_metadata, metadata) {
330 if (md->fstab != NULL)
331 fprintf(fstab, "%s\t%s\t\t%s\t%s\t%d\t%d\n",
332 md->fstab->fs_spec, md->fstab->fs_file,
333 md->fstab->fs_vfstype, md->fstab->fs_mntops,
334 md->fstab->fs_freq, md->fstab->fs_passno);
341 static struct partedit_item *
342 read_geom_mesh(struct gmesh *mesh, int *nitems)
344 struct gclass *classp;
346 struct partedit_item *items;
352 * Build the device table. First add all disks (and CDs).
355 LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
356 if (strcmp(classp->lg_name, "DISK") != 0 &&
357 strcmp(classp->lg_name, "MD") != 0)
360 /* Now recurse into all children */
361 LIST_FOREACH(gp, &classp->lg_geom, lg_geom)
362 add_geom_children(gp, 0, &items, nitems);
369 add_geom_children(struct ggeom *gp, int recurse, struct partedit_item **items,
372 struct gconsumer *cp;
373 struct gprovider *pp;
376 if (strcmp(gp->lg_class->lg_name, "PART") == 0 &&
377 !LIST_EMPTY(&gp->lg_config)) {
378 LIST_FOREACH(gc, &gp->lg_config, lg_config) {
379 if (strcmp(gc->lg_name, "scheme") == 0)
380 (*items)[*nitems-1].type = gc->lg_val;
384 if (LIST_EMPTY(&gp->lg_provider))
387 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
388 if (strcmp(gp->lg_class->lg_name, "LABEL") == 0)
391 /* Skip WORM media */
392 if (strncmp(pp->lg_name, "cd", 2) == 0)
395 *items = realloc(*items,
396 (*nitems+1)*sizeof(struct partedit_item));
397 (*items)[*nitems].indentation = recurse;
398 (*items)[*nitems].name = pp->lg_name;
399 (*items)[*nitems].size = pp->lg_mediasize;
400 (*items)[*nitems].mountpoint = NULL;
401 (*items)[*nitems].type = "";
402 (*items)[*nitems].cookie = pp;
404 LIST_FOREACH(gc, &pp->lg_config, lg_config) {
405 if (strcmp(gc->lg_name, "type") == 0)
406 (*items)[*nitems].type = gc->lg_val;
409 /* Skip swap-backed MD devices */
410 if (strcmp(gp->lg_class->lg_name, "MD") == 0 &&
411 strcmp((*items)[*nitems].type, "swap") == 0)
416 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
417 add_geom_children(cp->lg_geom, recurse+1, items,
420 /* Only use first provider for acd */
421 if (strcmp(gp->lg_class->lg_name, "ACD") == 0)
427 init_fstab_metadata(void)
430 struct partition_metadata *md;
433 while ((fstab = getfsent()) != NULL) {
434 md = calloc(1, sizeof(struct partition_metadata));
437 if (strncmp(fstab->fs_spec, "/dev/", 5) == 0)
438 md->name = strdup(&fstab->fs_spec[5]);
440 md->fstab = malloc(sizeof(struct fstab));
441 md->fstab->fs_spec = strdup(fstab->fs_spec);
442 md->fstab->fs_file = strdup(fstab->fs_file);
443 md->fstab->fs_vfstype = strdup(fstab->fs_vfstype);
444 md->fstab->fs_mntops = strdup(fstab->fs_mntops);
445 md->fstab->fs_type = strdup(fstab->fs_type);
446 md->fstab->fs_freq = fstab->fs_freq;
447 md->fstab->fs_passno = fstab->fs_passno;
451 TAILQ_INSERT_TAIL(&part_metadata, md, metadata);
456 get_mount_points(struct partedit_item *items, int nitems)
458 struct partition_metadata *md;
461 for (i = 0; i < nitems; i++) {
462 TAILQ_FOREACH(md, &part_metadata, metadata) {
463 if (md->name != NULL && md->fstab != NULL &&
464 strcmp(md->name, items[i].name) == 0) {
465 items[i].mountpoint = md->fstab->fs_file;