12118f387SNathan Whitehorn /*- 22118f387SNathan Whitehorn * Copyright (c) 2011 Nathan Whitehorn 32118f387SNathan Whitehorn * All rights reserved. 42118f387SNathan Whitehorn * 52118f387SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 62118f387SNathan Whitehorn * modification, are permitted provided that the following conditions 72118f387SNathan Whitehorn * are met: 82118f387SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 92118f387SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 102118f387SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 112118f387SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 122118f387SNathan Whitehorn * documentation and/or other materials provided with the distribution. 132118f387SNathan Whitehorn * 142118f387SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152118f387SNathan Whitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162118f387SNathan Whitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172118f387SNathan Whitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182118f387SNathan Whitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192118f387SNathan Whitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202118f387SNathan Whitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212118f387SNathan Whitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222118f387SNathan Whitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232118f387SNathan Whitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242118f387SNathan Whitehorn * SUCH DAMAGE. 252118f387SNathan Whitehorn * 262118f387SNathan Whitehorn * $FreeBSD$ 272118f387SNathan Whitehorn */ 282118f387SNathan Whitehorn 292118f387SNathan Whitehorn #include <sys/param.h> 302118f387SNathan Whitehorn #include <errno.h> 312118f387SNathan Whitehorn #include <libutil.h> 322118f387SNathan Whitehorn #include <inttypes.h> 332118f387SNathan Whitehorn 342118f387SNathan Whitehorn #include <libgeom.h> 352118f387SNathan Whitehorn #include <dialog.h> 362118f387SNathan Whitehorn #include <dlg_keys.h> 372118f387SNathan Whitehorn 382118f387SNathan Whitehorn #include "partedit.h" 392118f387SNathan Whitehorn 402118f387SNathan Whitehorn #define MIN_FREE_SPACE (1024*1024*1024) /* 1 GB */ 412118f387SNathan Whitehorn #define SWAP_SIZE(available) MIN(available/20, 4*1024*1024*1024LL) 422118f387SNathan Whitehorn 432118f387SNathan Whitehorn static char *boot_disk(struct gmesh *mesh); 442118f387SNathan Whitehorn static char *wizard_partition(struct gmesh *mesh, const char *disk); 452118f387SNathan Whitehorn static int wizard_makeparts(struct gmesh *mesh, const char *disk); 462118f387SNathan Whitehorn 472118f387SNathan Whitehorn int 482118f387SNathan Whitehorn part_wizard(void) { 492118f387SNathan Whitehorn int error; 502118f387SNathan Whitehorn struct gmesh mesh; 512118f387SNathan Whitehorn char *disk, *schemeroot; 522118f387SNathan Whitehorn 532118f387SNathan Whitehorn startwizard: 542118f387SNathan Whitehorn error = geom_gettree(&mesh); 552118f387SNathan Whitehorn 562118f387SNathan Whitehorn dlg_put_backtitle(); 572118f387SNathan Whitehorn error = geom_gettree(&mesh); 582118f387SNathan Whitehorn disk = boot_disk(&mesh); 592118f387SNathan Whitehorn if (disk == NULL) 602118f387SNathan Whitehorn return (1); 612118f387SNathan Whitehorn 622118f387SNathan Whitehorn dlg_clear(); 632118f387SNathan Whitehorn dlg_put_backtitle(); 642118f387SNathan Whitehorn schemeroot = wizard_partition(&mesh, disk); 652118f387SNathan Whitehorn free(disk); 662118f387SNathan Whitehorn if (schemeroot == NULL) 672118f387SNathan Whitehorn return (1); 682118f387SNathan Whitehorn 692118f387SNathan Whitehorn geom_deletetree(&mesh); 702118f387SNathan Whitehorn dlg_clear(); 712118f387SNathan Whitehorn dlg_put_backtitle(); 722118f387SNathan Whitehorn error = geom_gettree(&mesh); 732118f387SNathan Whitehorn 742118f387SNathan Whitehorn error = wizard_makeparts(&mesh, schemeroot); 752118f387SNathan Whitehorn if (error) 762118f387SNathan Whitehorn goto startwizard; 772118f387SNathan Whitehorn free(schemeroot); 782118f387SNathan Whitehorn 792118f387SNathan Whitehorn geom_deletetree(&mesh); 802118f387SNathan Whitehorn 812118f387SNathan Whitehorn return (0); 822118f387SNathan Whitehorn } 832118f387SNathan Whitehorn 842118f387SNathan Whitehorn static char * 852118f387SNathan Whitehorn boot_disk(struct gmesh *mesh) 862118f387SNathan Whitehorn { 872118f387SNathan Whitehorn struct gclass *classp; 882118f387SNathan Whitehorn struct gconfig *gc; 892118f387SNathan Whitehorn struct ggeom *gp; 902118f387SNathan Whitehorn struct gprovider *pp; 912118f387SNathan Whitehorn DIALOG_LISTITEM *disks = NULL; 929636f84bSNathan Whitehorn const char *type, *desc; 932118f387SNathan Whitehorn char diskdesc[512]; 942118f387SNathan Whitehorn char *chosen; 952118f387SNathan Whitehorn int i, err, selected, n = 0; 962118f387SNathan Whitehorn 972118f387SNathan Whitehorn LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 982118f387SNathan Whitehorn if (strcmp(classp->lg_name, "DISK") != 0 && 99bcc25b7eSNathan Whitehorn strcmp(classp->lg_name, "RAID") != 0 && 1002118f387SNathan Whitehorn strcmp(classp->lg_name, "MD") != 0) 1012118f387SNathan Whitehorn continue; 1022118f387SNathan Whitehorn 1032118f387SNathan Whitehorn LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1042118f387SNathan Whitehorn if (LIST_EMPTY(&gp->lg_provider)) 1052118f387SNathan Whitehorn continue; 1062118f387SNathan Whitehorn 1072118f387SNathan Whitehorn LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1089636f84bSNathan Whitehorn desc = type = NULL; 1099636f84bSNathan Whitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 1102118f387SNathan Whitehorn if (strcmp(gc->lg_name, "type") == 0) 1112118f387SNathan Whitehorn type = gc->lg_val; 1129636f84bSNathan Whitehorn if (strcmp(gc->lg_name, "descr") == 0) 1139636f84bSNathan Whitehorn desc = gc->lg_val; 1149636f84bSNathan Whitehorn } 1152118f387SNathan Whitehorn 1169636f84bSNathan Whitehorn /* Skip swap-backed md and WORM devices */ 1172118f387SNathan Whitehorn if (strcmp(classp->lg_name, "MD") == 0 && 1182118f387SNathan Whitehorn type != NULL && strcmp(type, "swap") == 0) 1192118f387SNathan Whitehorn continue; 1209636f84bSNathan Whitehorn if (strncmp(pp->lg_name, "cd", 2) == 0) 1219636f84bSNathan Whitehorn continue; 1222118f387SNathan Whitehorn 1232118f387SNathan Whitehorn disks = realloc(disks, (++n)*sizeof(disks[0])); 1242118f387SNathan Whitehorn disks[n-1].name = pp->lg_name; 1252118f387SNathan Whitehorn humanize_number(diskdesc, 7, pp->lg_mediasize, 1262118f387SNathan Whitehorn "B", HN_AUTOSCALE, HN_DECIMAL); 1272118f387SNathan Whitehorn if (strncmp(pp->lg_name, "ad", 2) == 0) 1282118f387SNathan Whitehorn strcat(diskdesc, " ATA Hard Disk"); 1292118f387SNathan Whitehorn else if (strncmp(pp->lg_name, "md", 2) == 0) 1302118f387SNathan Whitehorn strcat(diskdesc, " Memory Disk"); 1319636f84bSNathan Whitehorn else 1329636f84bSNathan Whitehorn strcat(diskdesc, " Disk"); 1339636f84bSNathan Whitehorn 1349636f84bSNathan Whitehorn if (desc != NULL) 1359636f84bSNathan Whitehorn snprintf(diskdesc, sizeof(diskdesc), 1369636f84bSNathan Whitehorn "%s <%s>", diskdesc, desc); 1379636f84bSNathan Whitehorn 1382118f387SNathan Whitehorn disks[n-1].text = strdup(diskdesc); 1392118f387SNathan Whitehorn disks[n-1].help = NULL; 1402118f387SNathan Whitehorn disks[n-1].state = 0; 1412118f387SNathan Whitehorn } 1422118f387SNathan Whitehorn } 1432118f387SNathan Whitehorn } 1442118f387SNathan Whitehorn 1452118f387SNathan Whitehorn if (n > 1) { 1462118f387SNathan Whitehorn err = dlg_menu("Partitioning", 1472118f387SNathan Whitehorn "Select the disk on which to install FreeBSD.", 0, 0, 0, 1482118f387SNathan Whitehorn n, disks, &selected, NULL); 1492118f387SNathan Whitehorn 1502118f387SNathan Whitehorn chosen = (err == 0) ? strdup(disks[selected].name) : NULL; 1512118f387SNathan Whitehorn } else if (n == 1) { 1522118f387SNathan Whitehorn chosen = strdup(disks[0].name); 1532118f387SNathan Whitehorn } else { 1542118f387SNathan Whitehorn chosen = NULL; 1552118f387SNathan Whitehorn } 1562118f387SNathan Whitehorn 1572118f387SNathan Whitehorn for (i = 0; i < n; i++) 1582118f387SNathan Whitehorn free(disks[i].text); 1592118f387SNathan Whitehorn 1602118f387SNathan Whitehorn return (chosen); 1612118f387SNathan Whitehorn } 1622118f387SNathan Whitehorn 1632118f387SNathan Whitehorn static struct gprovider * 1642118f387SNathan Whitehorn provider_for_name(struct gmesh *mesh, const char *name) 1652118f387SNathan Whitehorn { 1662118f387SNathan Whitehorn struct gclass *classp; 1672118f387SNathan Whitehorn struct gprovider *pp = NULL; 1682118f387SNathan Whitehorn struct ggeom *gp; 1692118f387SNathan Whitehorn 1702118f387SNathan Whitehorn LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 1712118f387SNathan Whitehorn if (strcmp(classp->lg_name, "DISK") != 0 && 1722118f387SNathan Whitehorn strcmp(classp->lg_name, "PART") != 0 && 173bcc25b7eSNathan Whitehorn strcmp(classp->lg_name, "RAID") != 0 && 1742118f387SNathan Whitehorn strcmp(classp->lg_name, "MD") != 0) 1752118f387SNathan Whitehorn continue; 1762118f387SNathan Whitehorn 1772118f387SNathan Whitehorn LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1782118f387SNathan Whitehorn if (LIST_EMPTY(&gp->lg_provider)) 1792118f387SNathan Whitehorn continue; 1802118f387SNathan Whitehorn 1812118f387SNathan Whitehorn LIST_FOREACH(pp, &gp->lg_provider, lg_provider) 1822118f387SNathan Whitehorn if (strcmp(pp->lg_name, name) == 0) 1832118f387SNathan Whitehorn break; 1842118f387SNathan Whitehorn 1852118f387SNathan Whitehorn if (pp != NULL) break; 1862118f387SNathan Whitehorn } 1872118f387SNathan Whitehorn 1882118f387SNathan Whitehorn if (pp != NULL) break; 1892118f387SNathan Whitehorn } 1902118f387SNathan Whitehorn 1912118f387SNathan Whitehorn return (pp); 1922118f387SNathan Whitehorn } 1932118f387SNathan Whitehorn 1942118f387SNathan Whitehorn static char * 1952118f387SNathan Whitehorn wizard_partition(struct gmesh *mesh, const char *disk) 1962118f387SNathan Whitehorn { 1972118f387SNathan Whitehorn struct gclass *classp; 1982118f387SNathan Whitehorn struct ggeom *gpart = NULL; 1992118f387SNathan Whitehorn struct gconfig *gc; 2002118f387SNathan Whitehorn char message[512]; 2012118f387SNathan Whitehorn const char *scheme = NULL; 2022118f387SNathan Whitehorn char *retval = NULL; 2032118f387SNathan Whitehorn int choice; 2042118f387SNathan Whitehorn 2052118f387SNathan Whitehorn LIST_FOREACH(classp, &mesh->lg_class, lg_class) 2062118f387SNathan Whitehorn if (strcmp(classp->lg_name, "PART") == 0) 2072118f387SNathan Whitehorn break; 2082118f387SNathan Whitehorn 2092118f387SNathan Whitehorn if (classp != NULL) { 2102118f387SNathan Whitehorn LIST_FOREACH(gpart, &classp->lg_geom, lg_geom) 2112118f387SNathan Whitehorn if (strcmp(gpart->lg_name, disk) == 0) 2122118f387SNathan Whitehorn break; 2132118f387SNathan Whitehorn } 2142118f387SNathan Whitehorn 2152118f387SNathan Whitehorn if (gpart != NULL) { 2162118f387SNathan Whitehorn LIST_FOREACH(gc, &gpart->lg_config, lg_config) { 2172118f387SNathan Whitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 2182118f387SNathan Whitehorn scheme = gc->lg_val; 2192118f387SNathan Whitehorn break; 2202118f387SNathan Whitehorn } 2212118f387SNathan Whitehorn } 2222118f387SNathan Whitehorn } 2232118f387SNathan Whitehorn 224da42677dSNathan Whitehorn /* Treat uncommitted scheme deletions as no scheme */ 225da42677dSNathan Whitehorn if (scheme != NULL && strcmp(scheme, "(none)") == 0) 226da42677dSNathan Whitehorn scheme = NULL; 227da42677dSNathan Whitehorn 2282118f387SNathan Whitehorn query: 2292118f387SNathan Whitehorn dialog_vars.yes_label = "Entire Disk"; 2302118f387SNathan Whitehorn dialog_vars.no_label = "Partition"; 2312118f387SNathan Whitehorn if (gpart != NULL) 2322118f387SNathan Whitehorn dialog_vars.defaultno = TRUE; 2332118f387SNathan Whitehorn 2342118f387SNathan Whitehorn snprintf(message, sizeof(message), "Would you like to use this entire " 2352118f387SNathan Whitehorn "disk (%s) for FreeBSD or partition it to share it with other " 2362118f387SNathan Whitehorn "operating systems? Using the entire disk will erase any data " 2372118f387SNathan Whitehorn "currently stored there.", disk); 2382118f387SNathan Whitehorn choice = dialog_yesno("Partition", message, 0, 0); 2392118f387SNathan Whitehorn 2402118f387SNathan Whitehorn dialog_vars.yes_label = NULL; 2412118f387SNathan Whitehorn dialog_vars.no_label = NULL; 2422118f387SNathan Whitehorn dialog_vars.defaultno = FALSE; 2432118f387SNathan Whitehorn 2442118f387SNathan Whitehorn if (choice == 1 && scheme != NULL && !is_scheme_bootable(scheme)) { 2452118f387SNathan Whitehorn char warning[512]; 2462118f387SNathan Whitehorn int subchoice; 2472118f387SNathan Whitehorn 2482118f387SNathan Whitehorn sprintf(warning, "The existing partition scheme on this " 2492118f387SNathan Whitehorn "disk (%s) is not bootable on this platform. To install " 2502118f387SNathan Whitehorn "FreeBSD, it must be repartitioned. This will destroy all " 2512118f387SNathan Whitehorn "data on the disk. Are you sure you want to proceed?", 2522118f387SNathan Whitehorn scheme); 2532118f387SNathan Whitehorn subchoice = dialog_yesno("Non-bootable Disk", warning, 0, 0); 2542118f387SNathan Whitehorn if (subchoice != 0) 2552118f387SNathan Whitehorn goto query; 2562118f387SNathan Whitehorn 257*f36a5e0fSNathan Whitehorn gpart_destroy(gpart); 2582118f387SNathan Whitehorn gpart_partition(disk, default_scheme()); 2592118f387SNathan Whitehorn scheme = default_scheme(); 2602118f387SNathan Whitehorn } 2612118f387SNathan Whitehorn 262da42677dSNathan Whitehorn if (scheme == NULL || choice == 0) { 263da42677dSNathan Whitehorn if (gpart != NULL && scheme != NULL) { 264da42677dSNathan Whitehorn /* Erase partitioned disk */ 2652118f387SNathan Whitehorn choice = dialog_yesno("Confirmation", "This will erase " 2662118f387SNathan Whitehorn "the disk. Are you sure you want to proceed?", 0, 0); 2672118f387SNathan Whitehorn if (choice != 0) 2682118f387SNathan Whitehorn goto query; 2692118f387SNathan Whitehorn 270*f36a5e0fSNathan Whitehorn gpart_destroy(gpart); 2712118f387SNathan Whitehorn } 2722118f387SNathan Whitehorn 2732118f387SNathan Whitehorn gpart_partition(disk, default_scheme()); 2742118f387SNathan Whitehorn scheme = default_scheme(); 2752118f387SNathan Whitehorn } 2762118f387SNathan Whitehorn 2772118f387SNathan Whitehorn if (strcmp(scheme, "PC98") == 0 || strcmp(scheme, "MBR") == 0) { 2782118f387SNathan Whitehorn struct gmesh submesh; 2792118f387SNathan Whitehorn geom_gettree(&submesh); 2802118f387SNathan Whitehorn gpart_create(provider_for_name(&submesh, disk), 2812118f387SNathan Whitehorn "freebsd", NULL, NULL, &retval, 2822118f387SNathan Whitehorn choice /* Non-interactive for "Entire Disk" */); 2832118f387SNathan Whitehorn geom_deletetree(&submesh); 2842118f387SNathan Whitehorn } else { 2852118f387SNathan Whitehorn retval = strdup(disk); 2862118f387SNathan Whitehorn } 2872118f387SNathan Whitehorn 2882118f387SNathan Whitehorn return (retval); 2892118f387SNathan Whitehorn } 2902118f387SNathan Whitehorn 2912118f387SNathan Whitehorn static int 2922118f387SNathan Whitehorn wizard_makeparts(struct gmesh *mesh, const char *disk) 2932118f387SNathan Whitehorn { 2942118f387SNathan Whitehorn struct gmesh submesh; 2952118f387SNathan Whitehorn struct gclass *classp; 2962118f387SNathan Whitehorn struct ggeom *gp; 2972118f387SNathan Whitehorn struct gconfig *gc; 2982118f387SNathan Whitehorn const char *scheme; 2992118f387SNathan Whitehorn struct gprovider *pp; 3002118f387SNathan Whitehorn intmax_t swapsize, available; 3012118f387SNathan Whitehorn char swapsizestr[10], rootsizestr[10]; 3022118f387SNathan Whitehorn int retval; 3032118f387SNathan Whitehorn 3042118f387SNathan Whitehorn LIST_FOREACH(classp, &mesh->lg_class, lg_class) 3052118f387SNathan Whitehorn if (strcmp(classp->lg_name, "PART") == 0) 3062118f387SNathan Whitehorn break; 3072118f387SNathan Whitehorn 3082118f387SNathan Whitehorn LIST_FOREACH(gp, &classp->lg_geom, lg_geom) 3092118f387SNathan Whitehorn if (strcmp(gp->lg_name, disk) == 0) 3102118f387SNathan Whitehorn break; 3112118f387SNathan Whitehorn 3122118f387SNathan Whitehorn LIST_FOREACH(gc, &gp->lg_config, lg_config) 3132118f387SNathan Whitehorn if (strcmp(gc->lg_name, "scheme") == 0) 3142118f387SNathan Whitehorn scheme = gc->lg_val; 3152118f387SNathan Whitehorn 3162118f387SNathan Whitehorn pp = provider_for_name(mesh, disk); 3172118f387SNathan Whitehorn 3182118f387SNathan Whitehorn available = gpart_max_free(gp, NULL)*pp->lg_sectorsize; 3192118f387SNathan Whitehorn if (available < MIN_FREE_SPACE) { 3202118f387SNathan Whitehorn char availablestr[10], neededstr[10], message[512]; 3212118f387SNathan Whitehorn humanize_number(availablestr, 7, available, "B", HN_AUTOSCALE, 3222118f387SNathan Whitehorn HN_DECIMAL); 3232118f387SNathan Whitehorn humanize_number(neededstr, 7, MIN_FREE_SPACE, "B", HN_AUTOSCALE, 3242118f387SNathan Whitehorn HN_DECIMAL); 3252118f387SNathan Whitehorn sprintf(message, "There is not enough free space on %s to " 3262118f387SNathan Whitehorn "install FreeBSD (%s free, %s required). Would you like " 3272118f387SNathan Whitehorn "to choose another disk or to open the partition editor?", 3282118f387SNathan Whitehorn disk, availablestr, neededstr); 3292118f387SNathan Whitehorn 3302118f387SNathan Whitehorn dialog_vars.yes_label = "Another Disk"; 3312118f387SNathan Whitehorn dialog_vars.no_label = "Editor"; 3322118f387SNathan Whitehorn retval = dialog_yesno("Warning", message, 0, 0); 3332118f387SNathan Whitehorn dialog_vars.yes_label = NULL; 3342118f387SNathan Whitehorn dialog_vars.no_label = NULL; 3352118f387SNathan Whitehorn 3362118f387SNathan Whitehorn return (!retval); /* Editor -> return 0 */ 3372118f387SNathan Whitehorn } 3382118f387SNathan Whitehorn 3392118f387SNathan Whitehorn swapsize = SWAP_SIZE(available); 3402118f387SNathan Whitehorn humanize_number(swapsizestr, 7, swapsize, "B", HN_AUTOSCALE, 3412118f387SNathan Whitehorn HN_NOSPACE | HN_DECIMAL); 3422118f387SNathan Whitehorn humanize_number(rootsizestr, 7, available - swapsize - 1024*1024, 3432118f387SNathan Whitehorn "B", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); 3442118f387SNathan Whitehorn 3452118f387SNathan Whitehorn geom_gettree(&submesh); 3462118f387SNathan Whitehorn pp = provider_for_name(&submesh, disk); 3472118f387SNathan Whitehorn gpart_create(pp, "freebsd-ufs", rootsizestr, "/", NULL, 0); 3482118f387SNathan Whitehorn geom_deletetree(&submesh); 3492118f387SNathan Whitehorn 3502118f387SNathan Whitehorn geom_gettree(&submesh); 3512118f387SNathan Whitehorn pp = provider_for_name(&submesh, disk); 3522118f387SNathan Whitehorn gpart_create(pp, "freebsd-swap", swapsizestr, NULL, NULL, 0); 3532118f387SNathan Whitehorn geom_deletetree(&submesh); 3542118f387SNathan Whitehorn 3552118f387SNathan Whitehorn return (0); 3562118f387SNathan Whitehorn } 3572118f387SNathan Whitehorn 358