diff --git a/usr.sbin/bsdinstall/partedit/part_wizard.c b/usr.sbin/bsdinstall/partedit/part_wizard.c index a3c5cb43ec51..44d9a08b0c78 100644 --- a/usr.sbin/bsdinstall/partedit/part_wizard.c +++ b/usr.sbin/bsdinstall/partedit/part_wizard.c @@ -1,407 +1,407 @@ /*- * 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 "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; struct bsddialog_conf conf; bsddialog_initconf(&conf); if (fsreq != NULL) fstype = fsreq; else fstype = "ufs"; startwizard: error = geom_gettree(&mesh); if (error != 0) return (1); - bsddialog_backtitle(&conf, "FreeBSD Installer"); + bsddialog_backtitle(&conf, OSNAME " Installer"); disk = boot_disk_select(&mesh); if (disk == NULL) { geom_deletetree(&mesh); return (1); } bsddialog_clear(0); - bsddialog_backtitle(&conf, "FreeBSD Installer"); + bsddialog_backtitle(&conf, OSNAME " Installer"); schemeroot = wizard_partition(&mesh, disk); free(disk); geom_deletetree(&mesh); if (schemeroot == NULL) return (1); bsddialog_clear(0); - bsddialog_backtitle(&conf, "FreeBSD Installer"); + bsddialog_backtitle(&conf, OSNAME " Installer"); error = geom_gettree(&mesh); if (error != 0) { free(schemeroot); return (1); } error = wizard_makeparts(&mesh, schemeroot, fstype, 1); 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; struct bsddialog_menuitem *disks = NULL; const char *type, *desc; char diskdesc[512]; char *chosen; int i, button, fd, selected, n = 0; struct bsddialog_conf conf; bsddialog_initconf(&conf); 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; /* * Check if the disk is available to be opened for * write operations, it helps prevent the USB * stick used to boot from being listed as an option */ fd = g_open(pp->lg_name, 1); if (fd == -1) { continue; } g_close(fd); 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].prefix = ""; disks[n-1].on = false; disks[n-1].depth = 0; disks[n-1].desc = strdup(diskdesc); disks[n-1].bottomdesc = ""; } } } if (n > 1) { conf.title = "Partitioning"; button = bsddialog_menu(&conf, "Select the disk on which to install " OSNAME ".", 0, 0, 0, n, disks, &selected); chosen = (button == BSDDIALOG_OK) ? strdup(disks[selected].name) : NULL; } else if (n == 1) { chosen = strdup(disks[0].name); } else { chosen = NULL; } for (i = 0; i < n; i++) free((char*)disks[i].desc); 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; struct bsddialog_conf conf; bsddialog_initconf(&conf); 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: conf.button.ok_label = "Entire Disk"; conf.button.cancel_label = "Partition"; if (gpart != NULL) conf.button.default_cancel = true; snprintf(message, sizeof(message), "Would you like to use this entire " "disk (%s) for " OSNAME " or partition it to share it with other " "operating systems? Using the entire disk will erase any data " "currently stored there.", disk); conf.title = "Partition"; choice = bsddialog_yesno(&conf, message, 9, 45); conf.button.ok_label = NULL; conf.button.cancel_label = NULL; conf.button.default_cancel = false; if (choice == BSDDIALOG_NO && scheme != NULL && !is_scheme_bootable(scheme)) { char warning[512]; int subchoice; snprintf(warning, sizeof(warning), "The existing partition scheme on this " "disk (%s) is not bootable on this platform. To install " OSNAME ", it must be repartitioned. This will destroy all " "data on the disk. Are you sure you want to proceed?", scheme); conf.title = "Non-bootable Disk"; subchoice = bsddialog_yesno(&conf, warning, 0, 0); if (subchoice != BSDDIALOG_YES) 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 */ conf.title = "Confirmation"; choice = bsddialog_yesno(&conf, "This will erase " "the disk. Are you sure you want to proceed?", 0, 0); if (choice != BSDDIALOG_YES) 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; 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 error, retval; struct bsddialog_conf conf; 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); snprintf(message, sizeof(message), "There is not enough free space on %s to " "install " OSNAME " (%s free, %s required). Would you like " "to choose another disk or to open the partition editor?", disk, availablestr, neededstr); bsddialog_initconf(&conf); conf.button.ok_label = "Another Disk"; conf.button.cancel_label = "Editor"; conf.title = "Warning"; retval = bsddialog_yesno(&conf, message, 0, 0); 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); 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); 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 74606a2ef8f3..148cb74edc75 100644 --- a/usr.sbin/bsdinstall/partedit/partedit.c +++ b/usr.sbin/bsdinstall/partedit/partedit.c @@ -1,628 +1,628 @@ /*- * 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 #include "diskmenu.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 */ if (geom_gettree(&mesh) == 0) { gpart_revert_all(&mesh); geom_deletetree(&mesh); } bsddialog_end(); 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; int error; struct bsddialog_conf conf; progname = getprogname(); if (strcmp(progname, "sade") == 0) sade_mode = 1; TAILQ_INIT(&part_metadata); init_fstab_metadata(); if (bsddialog_init() == BSDDIALOG_ERROR) err(1, "%s", bsddialog_geterror()); bsddialog_initconf(&conf); if (!sade_mode) bsddialog_backtitle(&conf, OSNAME " Installer"); 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) { bsddialog_end(); return (error); } } else { prompt = "Create partitions for " OSNAME ", F1 for help.\n" "No changes will be made until you select Finish."; } /* Show the part editor either immediately, or to confirm wizard */ while (prompt != NULL) { bsddialog_clear(0); if (!sade_mode) - bsddialog_backtitle(&conf, "FreeBSD Installer"); + bsddialog_backtitle(&conf, OSNAME " Installer"); error = geom_gettree(&mesh); if (error == 0) items = read_geom_mesh(&mesh, &nitems); if (error || items == NULL) { conf.title = "Error"; bsddialog_msgbox(&conf, "No disks found. If you need " "to install a kernel driver, choose Shell at the " "installation menu.", 0, 0); break; } - + get_mount_points(items, nitems); if (i >= nitems) i = nitems - 1; op = diskmenu_show("Partition Editor", prompt, items, nitems, &i); switch (op) { case BUTTON_CREATE: gpart_create((struct gprovider *)(items[i].cookie), NULL, NULL, NULL, NULL, 1); break; case BUTTON_DELETE: gpart_delete((struct gprovider *)(items[i].cookie)); break; case BUTTON_MODIFY: gpart_edit((struct gprovider *)(items[i].cookie)); break; case BUTTON_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 BUTTON_AUTO: part_wizard("ufs"); break; } error = 0; if (op == BUTTON_FINISH) { conf.button.ok_label = "Commit"; conf.button.with_extra = true; conf.button.extra_label = "Revert & Exit"; conf.button.cancel_label = "Back"; conf.title = "Confirmation"; op = bsddialog_yesno(&conf, "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); conf.button.ok_label = NULL; conf.button.with_extra = false; conf.button.extra_label = NULL; conf.button.cancel_label = NULL; if (op == BSDDIALOG_OK && validate_setup()) { /* Save */ error = apply_changes(&mesh); if (!error) apply_workaround(&mesh); break; } else if (op == BSDDIALOG_EXTRA) { /* Quit */ gpart_revert_all(&mesh); error = -1; break; } } geom_deletetree(&mesh); free(items); } if (prompt == NULL) { error = geom_gettree(&mesh); if (error == 0) { if (validate_setup()) { error = apply_changes(&mesh); } else { gpart_revert_all(&mesh); error = -1; } geom_deletetree(&mesh); } } bsddialog_end(); 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 button; struct bsddialog_conf conf; TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0) root = md; /* XXX: Check for duplicate mountpoints */ } bsddialog_initconf(&conf); if (root == NULL) { conf.title = "Error"; bsddialog_msgbox(&conf, "No root partition was found. " "The root " OSNAME " partition must have a mountpoint " "of '/'.", 0, 0); return (false); } /* * Check for root partitions that we aren't formatting, which is * usually a mistake */ if (root->newfs == NULL && !sade_mode) { conf.button.default_cancel = true; conf.title = "Warning"; button = bsddialog_yesno(&conf, "The chosen root partition " "has a preexisting filesystem. If it contains an existing " OSNAME " 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); if (button == BSDDIALOG_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, *miniperc; const char **minilabel; const char *fstab_path; FILE *fstab; char *command; struct bsddialog_conf conf; nitems = 1; /* Partition table changes */ TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->newfs != NULL) nitems++; } minilabel = calloc(nitems, sizeof(const char *)); miniperc = calloc(nitems, sizeof(int)); minilabel[0] = "Writing partition tables"; miniperc[0] = BSDDIALOG_MG_INPROGRESS; i = 1; TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->newfs != NULL) { char *item; asprintf(&item, "Initializing %s", md->name); minilabel[i] = item; miniperc[i] = BSDDIALOG_MG_PENDING; i++; } } i = 0; bsddialog_initconf(&conf); conf.title = "Initializing"; bsddialog_mixedgauge(&conf, "Initializing file systems. Please wait.", 0, 0, i * 100 / nitems, nitems, minilabel, miniperc); gpart_commit(mesh); miniperc[i] = BSDDIALOG_MG_COMPLETED; i++; if (getenv("BSDINSTALL_LOG") == NULL) setenv("BSDINSTALL_LOG", "/dev/null", 1); TAILQ_FOREACH(md, &part_metadata, metadata) { if (md->newfs != NULL) { miniperc[i] = BSDDIALOG_MG_INPROGRESS; bsddialog_mixedgauge(&conf, "Initializing file systems. Please wait.", 0, 0, i * 100 / nitems, nitems, minilabel, miniperc); asprintf(&command, "(echo %s; %s) >>%s 2>>%s", md->newfs, md->newfs, getenv("BSDINSTALL_LOG"), getenv("BSDINSTALL_LOG")); error = system(command); free(command); miniperc[i] = (error == 0) ? BSDDIALOG_MG_COMPLETED : BSDDIALOG_MG_FAILED; i++; } } bsddialog_mixedgauge(&conf, "Initializing file systems. Please wait.", 0, 0, i * 100 / nitems, nitems, minilabel, miniperc); for (i = 1; i < nitems; i++) free(__DECONST(char *, minilabel[i])); free(minilabel); free(miniperc); /* 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) { snprintf(message, sizeof(message), "Cannot open fstab file %s for writing (%s)\n", getenv("PATH_FSTAB"), strerror(errno)); conf.title = "Error"; bsddialog_msgbox(&conf, message, 0, 0); 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; struct bsddialog_conf conf; LIST_FOREACH(classp, &mesh->lg_class, lg_class) { if (strcmp(classp->lg_name, "PART") == 0) break; } if (strcmp(classp->lg_name, "PART") != 0) { bsddialog_initconf(&conf); conf.title = "Error"; bsddialog_msgbox(&conf, "gpart not found!", 0, 0); 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/startbsdinstall b/usr.sbin/bsdinstall/startbsdinstall index 63239c969ac6..ab78c2941256 100644 --- a/usr.sbin/bsdinstall/startbsdinstall +++ b/usr.sbin/bsdinstall/startbsdinstall @@ -1,111 +1,114 @@ #!/bin/sh +BSDCFG_SHARE="/usr/share/bsdconfig" +. $BSDCFG_SHARE/common.subr || exit 1 + : ${BSDDIALOG_OK=0} : ${BSDDIALOG_CANCEL=1} : ${BSDDIALOG_HELP=2} : ${BSDDIALOG_EXTRA=3} : ${BSDDIALOG_ESC=5} : ${BSDDIALOG_ERROR=255} kbdcontrol -d >/dev/null 2>&1 if [ $? -eq 0 ]; then # Syscons: use xterm, start interesting things on other VTYs TERM=xterm # Don't send ESC on function-key 62/63 (left/right command key) kbdcontrol -f 62 '' > /dev/null 2>&1 kbdcontrol -f 63 '' > /dev/null 2>&1 if [ -z "$EXTERNAL_VTY_STARTED" ]; then # Init will clean these processes up if/when the system # goes multiuser touch /tmp/bsdinstall_log tail -f /tmp/bsdinstall_log > /dev/ttyv2 & /usr/libexec/getty autologin ttyv3 & EXTERNAL_VTY_STARTED=1 fi else # Serial or other console echo - echo "Welcome to FreeBSD!" + echo "Welcome to ${OSNAME}!" echo echo "Please choose the appropriate terminal type for your system." echo "Common console types are:" echo " ansi Standard ANSI terminal" echo " vt100 VT100 or compatible terminal" echo " xterm xterm terminal emulator (or compatible)" echo echo -n "Console type [vt100]: " read TERM TERM=${TERM:-vt100} fi export TERM # Query terminal size; useful for serial lines. resizewin -z if [ -f /etc/installerconfig ]; then if [ "$1" != "primary" ]; then - bsddialog --backtitle "FreeBSD Installer" --title "Installing" --msgbox "FreeBSD is being installed from a script; please use the primary console." 0 0 + bsddialog --backtitle "${OSNAME} Installer" --title "Installing" --msgbox "${OSNAME} is being installed from a script; please use the primary console." 0 0 . "$0" elif bsdinstall script /etc/installerconfig; then - bsddialog --backtitle "FreeBSD Installer" --title "Complete" --no-cancel --ok-label "Reboot" --pause "Installation of FreeBSD complete! Rebooting in 10 seconds" 10 30 10 + bsddialog --backtitle "${OSNAME} Installer" --title "Complete" --no-cancel --ok-label "Reboot" --pause "Installation of ${OSNAME} complete! Rebooting in 10 seconds" 10 30 10 reboot else - bsddialog --backtitle "FreeBSD Installer" --title "Error" --textbox /tmp/bsdinstall_log 0 0 + bsddialog --backtitle "${OSNAME} Installer" --title "Error" --textbox /tmp/bsdinstall_log 0 0 fi exit fi -bsddialog --backtitle "FreeBSD Installer" --title "Welcome" --extra-button --extra-label "Shell" --ok-label "Install" --cancel-label "Live System" --yesno "Welcome to FreeBSD! Would you like to begin an installation or use the live system?" 0 0 +bsddialog --backtitle "${OSNAME} Installer" --title "Welcome" --extra-button --extra-label "Shell" --ok-label "Install" --cancel-label "Live System" --yesno "Welcome to ${OSNAME}! Would you like to begin an installation or use the live system?" 0 0 case $? in $BSDDIALOG_OK) # Install # If not netbooting, have the installer configure the network dlv=`/sbin/sysctl -n vfs.nfs.diskless_valid 2> /dev/null` if [ ${dlv:=0} -eq 0 -a ! -f /etc/diskless ]; then BSDINSTALL_CONFIGCURRENT=yes; export BSDINSTALL_CONFIGCURRENT fi trap true SIGINT # Ignore cntrl-C here bsdinstall if [ $? -eq 0 ]; then - bsddialog --backtitle "FreeBSD Installer" --title "Complete" --ok-label "Reboot" --extra-button --extra-label "Shutdown" --cancel-label "Live System" --yesno "Installation of FreeBSD complete! Would you like to reboot into the installed system now?" 0 0 + bsddialog --backtitle "${OSNAME} Installer" --title "Complete" --ok-label "Reboot" --extra-button --extra-label "Shutdown" --cancel-label "Live System" --yesno "Installation of ${OSNAME} complete! Would you like to reboot into the installed system now?" 0 0 case $? in $BSDDIALOG_OK) # Reboot reboot ;; $BSDDIALOG_EXTRA) # Shutdown shutdown -p now # shutdown(8) daemonizes, with the actual signal to # init(8) happening in the child, but if we exit the # script then runconsoles will clean up its children # thinking we're trying to go multiuser (and if the # user has disabled multiple console support we'll # still start trying to go multi-user, which gives # confusing output on the console if the daemon is slow # to run). Thus we spin while the daemon runs. while true; do sleep 1 done ;; $BSDDIALOG_CANCEL) # Live System exit 0 ;; esac else . "$0" fi ;; $BSDDIALOG_CANCEL) # Live System exit 0 ;; $BSDDIALOG_EXTRA) # Shell clear echo "When finished, type 'exit' to return to the installer." /bin/sh . "$0" ;; esac