diff --git a/usr.sbin/bsdinstall/partedit/part_wizard.c b/usr.sbin/bsdinstall/partedit/part_wizard.c index 2380e4d1f1b8..db689fd223d7 100644 --- a/usr.sbin/bsdinstall/partedit/part_wizard.c +++ b/usr.sbin/bsdinstall/partedit/part_wizard.c @@ -1,364 +1,376 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2011 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "partedit.h" #define MIN_FREE_SPACE (1024*1024*1024) /* 1 GB */ #define SWAP_SIZE(available) MIN(available/20, 4*1024*1024*1024LL) static char *wizard_partition(struct gmesh *mesh, const char *disk); int part_wizard(const char *fsreq) { char *disk, *schemeroot; const char *fstype; struct gmesh mesh; int error; if (fsreq != NULL) fstype = fsreq; else fstype = "ufs"; startwizard: error = geom_gettree(&mesh); + if (error != 0) + return (1); dlg_put_backtitle(); - error = geom_gettree(&mesh); disk = boot_disk_select(&mesh); - if (disk == NULL) + if (disk == NULL) { + geom_deletetree(&mesh); return (1); + } dlg_clear(); dlg_put_backtitle(); schemeroot = wizard_partition(&mesh, disk); free(disk); + geom_deletetree(&mesh); if (schemeroot == NULL) return (1); - geom_deletetree(&mesh); dlg_clear(); dlg_put_backtitle(); error = geom_gettree(&mesh); + if (error != 0) { + free(schemeroot); + return (1); + } error = wizard_makeparts(&mesh, schemeroot, fstype, 1); - if (error) - goto startwizard; free(schemeroot); - geom_deletetree(&mesh); + if (error) + goto startwizard; return (0); } char * boot_disk_select(struct gmesh *mesh) { struct gclass *classp; struct gconfig *gc; struct ggeom *gp; struct gprovider *pp; DIALOG_LISTITEM *disks = NULL; const char *type, *desc; char diskdesc[512]; char *chosen; int i, err, selected, n = 0; LIST_FOREACH(classp, &mesh->lg_class, lg_class) { if (strcmp(classp->lg_name, "DISK") != 0 && strcmp(classp->lg_name, "RAID") != 0 && strcmp(classp->lg_name, "MD") != 0) continue; LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { if (LIST_EMPTY(&gp->lg_provider)) continue; LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { desc = type = NULL; LIST_FOREACH(gc, &pp->lg_config, lg_config) { if (strcmp(gc->lg_name, "type") == 0) type = gc->lg_val; if (strcmp(gc->lg_name, "descr") == 0) desc = gc->lg_val; } /* Skip swap-backed md and WORM devices */ if (strcmp(classp->lg_name, "MD") == 0 && type != NULL && strcmp(type, "swap") == 0) continue; if (strncmp(pp->lg_name, "cd", 2) == 0) continue; disks = realloc(disks, (++n)*sizeof(disks[0])); disks[n-1].name = pp->lg_name; humanize_number(diskdesc, 7, pp->lg_mediasize, "B", HN_AUTOSCALE, HN_DECIMAL); if (strncmp(pp->lg_name, "ad", 2) == 0) strcat(diskdesc, " ATA Hard Disk"); else if (strncmp(pp->lg_name, "md", 2) == 0) strcat(diskdesc, " Memory Disk"); else strcat(diskdesc, " Disk"); if (desc != NULL) snprintf(diskdesc, sizeof(diskdesc), "%s <%s>", diskdesc, desc); disks[n-1].text = strdup(diskdesc); disks[n-1].help = NULL; disks[n-1].state = 0; } } } if (n > 1) { err = dlg_menu("Partitioning", "Select the disk on which to install FreeBSD.", 0, 0, 0, n, disks, &selected, NULL); chosen = (err == 0) ? strdup(disks[selected].name) : NULL; } else if (n == 1) { chosen = strdup(disks[0].name); } else { chosen = NULL; } for (i = 0; i < n; i++) free(disks[i].text); return (chosen); } static struct gprovider * provider_for_name(struct gmesh *mesh, const char *name) { struct gclass *classp; struct gprovider *pp = NULL; struct ggeom *gp; LIST_FOREACH(classp, &mesh->lg_class, lg_class) { LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { if (LIST_EMPTY(&gp->lg_provider)) continue; LIST_FOREACH(pp, &gp->lg_provider, lg_provider) if (strcmp(pp->lg_name, name) == 0) break; if (pp != NULL) break; } if (pp != NULL) break; } return (pp); } static char * wizard_partition(struct gmesh *mesh, const char *disk) { struct gclass *classp; struct ggeom *gpart = NULL; struct gconfig *gc; char *retval = NULL; const char *scheme = NULL; char message[512]; int choice; LIST_FOREACH(classp, &mesh->lg_class, lg_class) if (strcmp(classp->lg_name, "PART") == 0) break; if (classp != NULL) { LIST_FOREACH(gpart, &classp->lg_geom, lg_geom) if (strcmp(gpart->lg_name, disk) == 0) break; } if (gpart != NULL) { LIST_FOREACH(gc, &gpart->lg_config, lg_config) { if (strcmp(gc->lg_name, "scheme") == 0) { scheme = gc->lg_val; break; } } } /* Treat uncommitted scheme deletions as no scheme */ if (scheme != NULL && strcmp(scheme, "(none)") == 0) scheme = NULL; query: dialog_vars.yes_label = "Entire Disk"; dialog_vars.no_label = "Partition"; if (gpart != NULL) dialog_vars.defaultno = TRUE; snprintf(message, sizeof(message), "Would you like to use this entire " "disk (%s) for FreeBSD or partition it to share it with other " "operating systems? Using the entire disk will erase any data " "currently stored there.", disk); choice = dialog_yesno("Partition", message, 0, 0); dialog_vars.yes_label = NULL; dialog_vars.no_label = NULL; dialog_vars.defaultno = FALSE; if (choice == 1 && scheme != NULL && !is_scheme_bootable(scheme)) { char warning[512]; int subchoice; sprintf(warning, "The existing partition scheme on this " "disk (%s) is not bootable on this platform. To install " "FreeBSD, it must be repartitioned. This will destroy all " "data on the disk. Are you sure you want to proceed?", scheme); subchoice = dialog_yesno("Non-bootable Disk", warning, 0, 0); if (subchoice != 0) goto query; gpart_destroy(gpart); scheme = choose_part_type(default_scheme()); if (scheme == NULL) return NULL; gpart_partition(disk, scheme); } if (scheme == NULL || choice == 0) { if (gpart != NULL && scheme != NULL) { /* Erase partitioned disk */ choice = dialog_yesno("Confirmation", "This will erase " "the disk. Are you sure you want to proceed?", 0, 0); if (choice != 0) goto query; gpart_destroy(gpart); } scheme = choose_part_type(default_scheme()); if (scheme == NULL) return NULL; gpart_partition(disk, scheme); } if (strcmp(scheme, "MBR") == 0) { struct gmesh submesh; - geom_gettree(&submesh); - gpart_create(provider_for_name(&submesh, disk), - "freebsd", NULL, NULL, &retval, - choice /* Non-interactive for "Entire Disk" */); - geom_deletetree(&submesh); + + if (geom_gettree(&submesh) == 0) { + gpart_create(provider_for_name(&submesh, disk), + "freebsd", NULL, NULL, &retval, + choice /* Non-interactive for "Entire Disk" */); + geom_deletetree(&submesh); + } } else { retval = strdup(disk); } return (retval); } int wizard_makeparts(struct gmesh *mesh, const char *disk, const char *fstype, int interactive) { struct gclass *classp; struct ggeom *gp; struct gprovider *pp; char *fsnames[] = {"freebsd-ufs", "freebsd-zfs"}; char *fsname; struct gmesh submesh; char swapsizestr[10], rootsizestr[10]; intmax_t swapsize, available; - int retval; + int error, retval; if (strcmp(fstype, "zfs") == 0) { fsname = fsnames[1]; } else { /* default to UFS */ fsname = fsnames[0]; } LIST_FOREACH(classp, &mesh->lg_class, lg_class) if (strcmp(classp->lg_name, "PART") == 0) break; LIST_FOREACH(gp, &classp->lg_geom, lg_geom) if (strcmp(gp->lg_name, disk) == 0) break; pp = provider_for_name(mesh, disk); available = gpart_max_free(gp, NULL)*pp->lg_sectorsize; if (interactive && available < MIN_FREE_SPACE) { char availablestr[10], neededstr[10], message[512]; humanize_number(availablestr, 7, available, "B", HN_AUTOSCALE, HN_DECIMAL); humanize_number(neededstr, 7, MIN_FREE_SPACE, "B", HN_AUTOSCALE, HN_DECIMAL); sprintf(message, "There is not enough free space on %s to " "install FreeBSD (%s free, %s required). Would you like " "to choose another disk or to open the partition editor?", disk, availablestr, neededstr); dialog_vars.yes_label = "Another Disk"; dialog_vars.no_label = "Editor"; retval = dialog_yesno("Warning", message, 0, 0); dialog_vars.yes_label = NULL; dialog_vars.no_label = NULL; return (!retval); /* Editor -> return 0 */ } swapsize = SWAP_SIZE(available); humanize_number(swapsizestr, 7, swapsize, "B", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); humanize_number(rootsizestr, 7, available - swapsize - 1024*1024, "B", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); - geom_gettree(&submesh); + error = geom_gettree(&submesh); + if (error != 0) + return (error); pp = provider_for_name(&submesh, disk); gpart_create(pp, fsname, rootsizestr, "/", NULL, 0); geom_deletetree(&submesh); - geom_gettree(&submesh); + error = geom_gettree(&submesh); + if (error != 0) + return (error); pp = provider_for_name(&submesh, disk); gpart_create(pp, "freebsd-swap", swapsizestr, NULL, NULL, 0); geom_deletetree(&submesh); return (0); } diff --git a/usr.sbin/bsdinstall/partedit/partedit.c b/usr.sbin/bsdinstall/partedit/partedit.c index 2ae71338d099..0f341cbaba12 100644 --- a/usr.sbin/bsdinstall/partedit/partedit.c +++ b/usr.sbin/bsdinstall/partedit/partedit.c @@ -1,604 +1,606 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2011 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include "diskeditor.h" #include "partedit.h" struct pmetadata_head part_metadata; static int sade_mode = 0; static int apply_changes(struct gmesh *mesh); static void apply_workaround(struct gmesh *mesh); static struct partedit_item *read_geom_mesh(struct gmesh *mesh, int *nitems); static void add_geom_children(struct ggeom *gp, int recurse, struct partedit_item **items, int *nitems); static void init_fstab_metadata(void); static void get_mount_points(struct partedit_item *items, int nitems); static int validate_setup(void); static void sigint_handler(int sig) { struct gmesh mesh; /* Revert all changes and exit dialog-mode cleanly on SIGINT */ - geom_gettree(&mesh); - gpart_revert_all(&mesh); - geom_deletetree(&mesh); + if (geom_gettree(&mesh) == 0) { + gpart_revert_all(&mesh); + geom_deletetree(&mesh); + } end_dialog(); exit(1); } int main(int argc, const char **argv) { struct partition_metadata *md; const char *progname, *prompt; struct partedit_item *items = NULL; struct gmesh mesh; int i, op, nitems, nscroll; int error; progname = getprogname(); if (strcmp(progname, "sade") == 0) sade_mode = 1; TAILQ_INIT(&part_metadata); init_fstab_metadata(); init_dialog(stdin, stdout); if (!sade_mode) dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); dialog_vars.item_help = TRUE; nscroll = i = 0; /* Revert changes on SIGINT */ signal(SIGINT, sigint_handler); if (strcmp(progname, "autopart") == 0) { /* Guided */ prompt = "Please review the disk setup. When complete, press " "the Finish button."; /* Experimental ZFS autopartition support */ if (argc > 1 && strcmp(argv[1], "zfs") == 0) { part_wizard("zfs"); } else { part_wizard("ufs"); } } else if (strcmp(progname, "scriptedpart") == 0) { error = scripted_editor(argc, argv); prompt = NULL; if (error != 0) { end_dialog(); return (error); } } else { prompt = "Create partitions for FreeBSD. No changes will be " "made until you select Finish."; } /* Show the part editor either immediately, or to confirm wizard */ while (prompt != NULL) { dlg_clear(); dlg_put_backtitle(); error = geom_gettree(&mesh); if (error == 0) items = read_geom_mesh(&mesh, &nitems); if (error || items == NULL) { dialog_msgbox("Error", "No disks found. If you need to " "install a kernel driver, choose Shell at the " "installation menu.", 0, 0, TRUE); break; } get_mount_points(items, nitems); if (i >= nitems) i = nitems - 1; op = diskeditor_show("Partition Editor", prompt, items, nitems, &i, &nscroll); switch (op) { case 0: /* Create */ gpart_create((struct gprovider *)(items[i].cookie), NULL, NULL, NULL, NULL, 1); break; case 1: /* Delete */ gpart_delete((struct gprovider *)(items[i].cookie)); break; case 2: /* Modify */ gpart_edit((struct gprovider *)(items[i].cookie)); break; case 3: /* Revert */ gpart_revert_all(&mesh); while ((md = TAILQ_FIRST(&part_metadata)) != NULL) { if (md->fstab != NULL) { free(md->fstab->fs_spec); free(md->fstab->fs_file); free(md->fstab->fs_vfstype); free(md->fstab->fs_mntops); free(md->fstab->fs_type); free(md->fstab); } if (md->newfs != NULL) free(md->newfs); free(md->name); TAILQ_REMOVE(&part_metadata, md, metadata); free(md); } init_fstab_metadata(); break; case 4: /* Auto */ part_wizard("ufs"); break; } error = 0; if (op == 5) { /* Finished */ dialog_vars.ok_label = __DECONST(char *, "Commit"); dialog_vars.extra_label = __DECONST(char *, "Revert & Exit"); dialog_vars.extra_button = TRUE; dialog_vars.cancel_label = __DECONST(char *, "Back"); op = dialog_yesno("Confirmation", "Your changes will " "now be written to disk. If you have chosen to " "overwrite existing data, it will be PERMANENTLY " "ERASED. Are you sure you want to commit your " "changes?", 0, 0); dialog_vars.ok_label = NULL; dialog_vars.extra_button = FALSE; dialog_vars.cancel_label = NULL; if (op == 0 && validate_setup()) { /* Save */ error = apply_changes(&mesh); if (!error) apply_workaround(&mesh); break; } else if (op == 3) { /* Quit */ gpart_revert_all(&mesh); error = -1; break; } } geom_deletetree(&mesh); free(items); } if (prompt == NULL) { error = geom_gettree(&mesh); - if (validate_setup()) { - error = apply_changes(&mesh); - } else { - gpart_revert_all(&mesh); - error = -1; + if (error != 0) { + if (validate_setup()) { + error = apply_changes(&mesh); + } else { + gpart_revert_all(&mesh); + error = -1; + } + geom_deletetree(&mesh); } } - geom_deletetree(&mesh); - free(items); end_dialog(); return (error); } struct partition_metadata * get_part_metadata(const char *name, int create) { struct partition_metadata *md; TAILQ_FOREACH(md, &part_metadata, metadata) if (md->name != NULL && strcmp(md->name, name) == 0) break; if (md == NULL && create) { md = calloc(1, sizeof(*md)); md->name = strdup(name); TAILQ_INSERT_TAIL(&part_metadata, md, metadata); } return (md); } void delete_part_metadata(const char *name) { struct partition_metadata *md; TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->name != NULL && strcmp(md->name, name) == 0) { if (md->fstab != NULL) { free(md->fstab->fs_spec); free(md->fstab->fs_file); free(md->fstab->fs_vfstype); free(md->fstab->fs_mntops); free(md->fstab->fs_type); free(md->fstab); } if (md->newfs != NULL) free(md->newfs); free(md->name); TAILQ_REMOVE(&part_metadata, md, metadata); free(md); break; } } } static int validate_setup(void) { struct partition_metadata *md, *root = NULL; int cancel; TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0) root = md; /* XXX: Check for duplicate mountpoints */ } if (root == NULL) { dialog_msgbox("Error", "No root partition was found. " "The root FreeBSD partition must have a mountpoint of '/'.", 0, 0, TRUE); return (FALSE); } /* * Check for root partitions that we aren't formatting, which is * usually a mistake */ if (root->newfs == NULL && !sade_mode) { dialog_vars.defaultno = TRUE; cancel = dialog_yesno("Warning", "The chosen root partition " "has a preexisting filesystem. If it contains an existing " "FreeBSD system, please update it with freebsd-update " "instead of installing a new system on it. The partition " "can also be erased by pressing \"No\" and then deleting " "and recreating it. Are you sure you want to proceed?", 0, 0); dialog_vars.defaultno = FALSE; if (cancel) return (FALSE); } return (TRUE); } static int mountpoint_sorter(const void *xa, const void *xb) { struct partition_metadata *a = *(struct partition_metadata **)xa; struct partition_metadata *b = *(struct partition_metadata **)xb; if (a->fstab == NULL && b->fstab == NULL) return 0; if (a->fstab == NULL) return 1; if (b->fstab == NULL) return -1; return strcmp(a->fstab->fs_file, b->fstab->fs_file); } static int apply_changes(struct gmesh *mesh) { struct partition_metadata *md; char message[512]; int i, nitems, error; const char **items; const char *fstab_path; FILE *fstab; nitems = 1; /* Partition table changes */ TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->newfs != NULL) nitems++; } items = calloc(nitems * 2, sizeof(const char *)); items[0] = "Writing partition tables"; items[1] = "7"; /* In progress */ i = 1; TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->newfs != NULL) { char *item; item = malloc(255); sprintf(item, "Initializing %s", md->name); items[i*2] = item; items[i*2 + 1] = "Pending"; i++; } } i = 0; dialog_mixedgauge("Initializing", "Initializing file systems. Please wait.", 0, 0, i*100/nitems, nitems, __DECONST(char **, items)); gpart_commit(mesh); items[i*2 + 1] = "3"; i++; if (getenv("BSDINSTALL_LOG") == NULL) setenv("BSDINSTALL_LOG", "/dev/null", 1); TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->newfs != NULL) { items[i*2 + 1] = "7"; /* In progress */ dialog_mixedgauge("Initializing", "Initializing file systems. Please wait.", 0, 0, i*100/nitems, nitems, __DECONST(char **, items)); sprintf(message, "(echo %s; %s) >>%s 2>>%s", md->newfs, md->newfs, getenv("BSDINSTALL_LOG"), getenv("BSDINSTALL_LOG")); error = system(message); items[i*2 + 1] = (error == 0) ? "3" : "1"; i++; } } dialog_mixedgauge("Initializing", "Initializing file systems. Please wait.", 0, 0, i*100/nitems, nitems, __DECONST(char **, items)); for (i = 1; i < nitems; i++) free(__DECONST(char *, items[i*2])); free(items); /* Sort filesystems for fstab so that mountpoints are ordered */ { struct partition_metadata **tobesorted; struct partition_metadata *tmp; int nparts = 0; TAILQ_FOREACH(md, &part_metadata, metadata) nparts++; tobesorted = malloc(sizeof(struct partition_metadata *)*nparts); nparts = 0; TAILQ_FOREACH_SAFE(md, &part_metadata, metadata, tmp) { tobesorted[nparts++] = md; TAILQ_REMOVE(&part_metadata, md, metadata); } qsort(tobesorted, nparts, sizeof(tobesorted[0]), mountpoint_sorter); /* Now re-add everything */ while (nparts-- > 0) TAILQ_INSERT_HEAD(&part_metadata, tobesorted[nparts], metadata); free(tobesorted); } if (getenv("PATH_FSTAB") != NULL) fstab_path = getenv("PATH_FSTAB"); else fstab_path = "/etc/fstab"; fstab = fopen(fstab_path, "w+"); if (fstab == NULL) { sprintf(message, "Cannot open fstab file %s for writing (%s)\n", getenv("PATH_FSTAB"), strerror(errno)); dialog_msgbox("Error", message, 0, 0, TRUE); return (-1); } fprintf(fstab, "# Device\tMountpoint\tFStype\tOptions\tDump\tPass#\n"); TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->fstab != NULL) fprintf(fstab, "%s\t%s\t\t%s\t%s\t%d\t%d\n", md->fstab->fs_spec, md->fstab->fs_file, md->fstab->fs_vfstype, md->fstab->fs_mntops, md->fstab->fs_freq, md->fstab->fs_passno); } fclose(fstab); return (0); } static void apply_workaround(struct gmesh *mesh) { struct gclass *classp; struct ggeom *gp; struct gconfig *gc; const char *scheme = NULL, *modified = NULL; LIST_FOREACH(classp, &mesh->lg_class, lg_class) { if (strcmp(classp->lg_name, "PART") == 0) break; } if (strcmp(classp->lg_name, "PART") != 0) { dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE); return; } LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { LIST_FOREACH(gc, &gp->lg_config, lg_config) { if (strcmp(gc->lg_name, "scheme") == 0) { scheme = gc->lg_val; } else if (strcmp(gc->lg_name, "modified") == 0) { modified = gc->lg_val; } } if (scheme && strcmp(scheme, "GPT") == 0 && modified && strcmp(modified, "true") == 0) { if (getenv("WORKAROUND_LENOVO")) gpart_set_root(gp->lg_name, "lenovofix"); if (getenv("WORKAROUND_GPTACTIVE")) gpart_set_root(gp->lg_name, "active"); } } } static struct partedit_item * read_geom_mesh(struct gmesh *mesh, int *nitems) { struct gclass *classp; struct ggeom *gp; struct partedit_item *items; *nitems = 0; items = NULL; /* * Build the device table. First add all disks (and CDs). */ LIST_FOREACH(classp, &mesh->lg_class, lg_class) { if (strcmp(classp->lg_name, "DISK") != 0 && strcmp(classp->lg_name, "MD") != 0) continue; /* Now recurse into all children */ LIST_FOREACH(gp, &classp->lg_geom, lg_geom) add_geom_children(gp, 0, &items, nitems); } return (items); } static void add_geom_children(struct ggeom *gp, int recurse, struct partedit_item **items, int *nitems) { struct gconsumer *cp; struct gprovider *pp; struct gconfig *gc; if (strcmp(gp->lg_class->lg_name, "PART") == 0 && !LIST_EMPTY(&gp->lg_config)) { LIST_FOREACH(gc, &gp->lg_config, lg_config) { if (strcmp(gc->lg_name, "scheme") == 0) (*items)[*nitems-1].type = gc->lg_val; } } if (LIST_EMPTY(&gp->lg_provider)) return; LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { if (strcmp(gp->lg_class->lg_name, "LABEL") == 0) continue; /* Skip WORM media */ if (strncmp(pp->lg_name, "cd", 2) == 0) continue; *items = realloc(*items, (*nitems+1)*sizeof(struct partedit_item)); (*items)[*nitems].indentation = recurse; (*items)[*nitems].name = pp->lg_name; (*items)[*nitems].size = pp->lg_mediasize; (*items)[*nitems].mountpoint = NULL; (*items)[*nitems].type = ""; (*items)[*nitems].cookie = pp; LIST_FOREACH(gc, &pp->lg_config, lg_config) { if (strcmp(gc->lg_name, "type") == 0) (*items)[*nitems].type = gc->lg_val; } /* Skip swap-backed MD devices */ if (strcmp(gp->lg_class->lg_name, "MD") == 0 && strcmp((*items)[*nitems].type, "swap") == 0) continue; (*nitems)++; LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) add_geom_children(cp->lg_geom, recurse+1, items, nitems); /* Only use first provider for acd */ if (strcmp(gp->lg_class->lg_name, "ACD") == 0) break; } } static void init_fstab_metadata(void) { struct fstab *fstab; struct partition_metadata *md; setfsent(); while ((fstab = getfsent()) != NULL) { md = calloc(1, sizeof(struct partition_metadata)); md->name = NULL; if (strncmp(fstab->fs_spec, "/dev/", 5) == 0) md->name = strdup(&fstab->fs_spec[5]); md->fstab = malloc(sizeof(struct fstab)); md->fstab->fs_spec = strdup(fstab->fs_spec); md->fstab->fs_file = strdup(fstab->fs_file); md->fstab->fs_vfstype = strdup(fstab->fs_vfstype); md->fstab->fs_mntops = strdup(fstab->fs_mntops); md->fstab->fs_type = strdup(fstab->fs_type); md->fstab->fs_freq = fstab->fs_freq; md->fstab->fs_passno = fstab->fs_passno; md->newfs = NULL; TAILQ_INSERT_TAIL(&part_metadata, md, metadata); } } static void get_mount_points(struct partedit_item *items, int nitems) { struct partition_metadata *md; int i; for (i = 0; i < nitems; i++) { TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->name != NULL && md->fstab != NULL && strcmp(md->name, items[i].name) == 0) { items[i].mountpoint = md->fstab->fs_file; break; } } } } diff --git a/usr.sbin/bsdinstall/partedit/scripted.c b/usr.sbin/bsdinstall/partedit/scripted.c index 69fba8f2cfa8..fdfdc2d10014 100644 --- a/usr.sbin/bsdinstall/partedit/scripted.c +++ b/usr.sbin/bsdinstall/partedit/scripted.c @@ -1,220 +1,234 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2013 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "partedit.h" static struct gprovider * provider_for_name(struct gmesh *mesh, const char *name) { struct gclass *classp; struct gprovider *pp = NULL; struct ggeom *gp; LIST_FOREACH(classp, &mesh->lg_class, lg_class) { LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { if (LIST_EMPTY(&gp->lg_provider)) continue; LIST_FOREACH(pp, &gp->lg_provider, lg_provider) if (strcmp(pp->lg_name, name) == 0) break; if (pp != NULL) break; } if (pp != NULL) break; } return (pp); } static int part_config(char *disk, const char *scheme, char *config) { char *partition, *ap, *size = NULL, *type = NULL, *mount = NULL; struct gclass *classp; struct gmesh mesh; struct ggeom *gpart = NULL; int error; if (scheme == NULL) scheme = default_scheme(); error = geom_gettree(&mesh); + if (error != 0) + return (-1); if (provider_for_name(&mesh, disk) == NULL) { fprintf(stderr, "GEOM provider %s not found\n", disk); geom_deletetree(&mesh); return (-1); } /* Remove any existing partitioning and create new scheme */ LIST_FOREACH(classp, &mesh.lg_class, lg_class) if (strcmp(classp->lg_name, "PART") == 0) break; if (classp != NULL) { LIST_FOREACH(gpart, &classp->lg_geom, lg_geom) if (strcmp(gpart->lg_name, disk) == 0) break; } if (gpart != NULL) gpart_destroy(gpart); gpart_partition(disk, scheme); if (strcmp(scheme, "MBR") == 0) { struct gmesh submesh; - geom_gettree(&submesh); - gpart_create(provider_for_name(&submesh, disk), - "freebsd", NULL, NULL, &disk, 0); - geom_deletetree(&submesh); + + if (geom_gettree(&submesh) == 0) { + gpart_create(provider_for_name(&submesh, disk), + "freebsd", NULL, NULL, &disk, 0); + geom_deletetree(&submesh); + } } else { - disk= strdup(disk); + disk = strdup(disk); } geom_deletetree(&mesh); error = geom_gettree(&mesh); + if (error != 0) { + free(disk); + return (-1); + } /* Create partitions */ if (config == NULL) { wizard_makeparts(&mesh, disk, "ufs", 0); goto finished; } while ((partition = strsep(&config, ",")) != NULL) { while ((ap = strsep(&partition, " \t\n")) != NULL) { if (*ap == '\0') continue; if (size == NULL) size = ap; else if (type == NULL) type = ap; else if (mount == NULL) mount = ap; } if (size == NULL) continue; if (strcmp(size, "auto") == 0) size = NULL; gpart_create(provider_for_name(&mesh, disk), type, size, mount, NULL, 0); geom_deletetree(&mesh); error = geom_gettree(&mesh); + if (error != 0) { + free(disk); + return (-1); + } size = type = mount = NULL; } finished: geom_deletetree(&mesh); free(disk); return (0); } -static -int parse_disk_config(char *input) +static int +parse_disk_config(char *input) { char *ap; char *disk = NULL, *scheme = NULL, *partconfig = NULL; while (input != NULL && *input != 0) { if (isspace(*input)) { input++; continue; } switch(*input) { case '{': input++; partconfig = strchr(input, '}'); if (partconfig == NULL) { fprintf(stderr, "Malformed partition setup " "string: %s\n", input); return (1); } *partconfig = '\0'; ap = partconfig+1; partconfig = input; input = ap; break; default: if (disk == NULL) disk = strsep(&input, " \t\n"); else if (scheme == NULL) scheme = strsep(&input, " \t\n"); else { fprintf(stderr, "Unknown directive: %s\n", strsep(&input, " \t\n")); return (1); } } } while (input != NULL && *input != 0); if (disk == NULL || strcmp(disk, "DEFAULT") == 0) { struct gmesh mesh; - geom_gettree(&mesh); - disk = boot_disk_select(&mesh); - geom_deletetree(&mesh); + + if (geom_gettree(&mesh) == 0) { + disk = boot_disk_select(&mesh); + geom_deletetree(&mesh); + } } return (part_config(disk, scheme, partconfig)); } int scripted_editor(int argc, const char **argv) { FILE *fp; char *input, *token; size_t len; int i, error = 0; fp = open_memstream(&input, &len); fputs(argv[1], fp); for (i = 2; i < argc; i++) { fprintf(fp, " %s", argv[i]); } fclose(fp); while ((token = strsep(&input, ";")) != NULL) { error = parse_disk_config(token); if (error != 0) { free(input); return (error); } } free(input); return (0); }