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 GPART_FLAGS "x" /* Do not commit changes by default */ 412118f387SNathan Whitehorn 422118f387SNathan Whitehorn static void 432118f387SNathan Whitehorn gpart_show_error(const char *title, const char *explanation, const char *errstr) 442118f387SNathan Whitehorn { 452118f387SNathan Whitehorn char *errmsg; 462118f387SNathan Whitehorn char message[512]; 472118f387SNathan Whitehorn int error; 482118f387SNathan Whitehorn 492118f387SNathan Whitehorn if (explanation == NULL) 502118f387SNathan Whitehorn explanation = ""; 512118f387SNathan Whitehorn 522118f387SNathan Whitehorn error = strtol(errstr, &errmsg, 0); 532118f387SNathan Whitehorn if (errmsg != errstr) { 542118f387SNathan Whitehorn while (errmsg[0] == ' ') 552118f387SNathan Whitehorn errmsg++; 562118f387SNathan Whitehorn if (errmsg[0] != '\0') 572118f387SNathan Whitehorn sprintf(message, "%s%s. %s", explanation, 582118f387SNathan Whitehorn strerror(error), errmsg); 592118f387SNathan Whitehorn else 602118f387SNathan Whitehorn sprintf(message, "%s%s", explanation, strerror(error)); 612118f387SNathan Whitehorn } else { 622118f387SNathan Whitehorn sprintf(message, "%s%s", explanation, errmsg); 632118f387SNathan Whitehorn } 642118f387SNathan Whitehorn 652118f387SNathan Whitehorn dialog_msgbox(title, message, 0, 0, TRUE); 662118f387SNathan Whitehorn } 672118f387SNathan Whitehorn 68c67f41d0SNathan Whitehorn static int 69c67f41d0SNathan Whitehorn scheme_supports_labels(const char *scheme) 70c67f41d0SNathan Whitehorn { 71c67f41d0SNathan Whitehorn if (strcmp(scheme, "APM") == 0) 72c67f41d0SNathan Whitehorn return (1); 73c67f41d0SNathan Whitehorn if (strcmp(scheme, "GPT") == 0) 74c67f41d0SNathan Whitehorn return (1); 75c67f41d0SNathan Whitehorn if (strcmp(scheme, "PC98") == 0) 76c67f41d0SNathan Whitehorn return (1); 77c67f41d0SNathan Whitehorn 78c67f41d0SNathan Whitehorn return (0); 79c67f41d0SNathan Whitehorn } 80c67f41d0SNathan Whitehorn 8150de5d07SNathan Whitehorn static void 8250de5d07SNathan Whitehorn newfs_command(const char *fstype, char *command, int use_default) 8350de5d07SNathan Whitehorn { 8450de5d07SNathan Whitehorn if (strcmp(fstype, "freebsd-ufs") == 0) { 8550de5d07SNathan Whitehorn int i; 8650de5d07SNathan Whitehorn DIALOG_LISTITEM items[] = { 8750de5d07SNathan Whitehorn {"UFS1", "UFS Version 1", 8850de5d07SNathan Whitehorn "Use version 1 of the UFS file system instead " 8950de5d07SNathan Whitehorn "of version 2 (not recommended)", 0 }, 9050de5d07SNathan Whitehorn {"SU", "Softupdates", 9150de5d07SNathan Whitehorn "Enable softupdates (default)", 1 }, 9250de5d07SNathan Whitehorn {"SUJ", "Softupdates journaling", 9350de5d07SNathan Whitehorn "Enable file system journaling (default - " 9450de5d07SNathan Whitehorn "turn off for SSDs)", 1 }, 9550de5d07SNathan Whitehorn {"TRIM", "Enable SSD TRIM support", 9650de5d07SNathan Whitehorn "Enable TRIM support, useful on solid-state drives", 9750de5d07SNathan Whitehorn 0 }, 9850de5d07SNathan Whitehorn }; 9950de5d07SNathan Whitehorn 10050de5d07SNathan Whitehorn if (!use_default) { 10150de5d07SNathan Whitehorn int choice; 10250de5d07SNathan Whitehorn choice = dlg_checklist("UFS Options", "", 0, 0, 0, 10350de5d07SNathan Whitehorn sizeof(items)/sizeof(items[0]), items, NULL, 10450de5d07SNathan Whitehorn FLAG_CHECK, &i); 10550de5d07SNathan Whitehorn if (choice == 1) /* Cancel */ 10650de5d07SNathan Whitehorn return; 10750de5d07SNathan Whitehorn } 10850de5d07SNathan Whitehorn 10950de5d07SNathan Whitehorn strcpy(command, "newfs "); 11050de5d07SNathan Whitehorn for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) { 11150de5d07SNathan Whitehorn if (items[i].state == 0) 11250de5d07SNathan Whitehorn continue; 11350de5d07SNathan Whitehorn if (strcmp(items[i].name, "UFS1") == 0) 11450de5d07SNathan Whitehorn strcat(command, "-O1 "); 11550de5d07SNathan Whitehorn else if (strcmp(items[i].name, "SU") == 0) 11650de5d07SNathan Whitehorn strcat(command, "-U "); 11750de5d07SNathan Whitehorn else if (strcmp(items[i].name, "SUJ") == 0) 11850de5d07SNathan Whitehorn strcat(command, "-j "); 11950de5d07SNathan Whitehorn else if (strcmp(items[i].name, "TRIM") == 0) 12050de5d07SNathan Whitehorn strcat(command, "-t "); 12150de5d07SNathan Whitehorn } 12250de5d07SNathan Whitehorn } else if (strcmp(fstype, "fat32") == 0 || strcmp(fstype, "efi") == 0) { 12350de5d07SNathan Whitehorn int i; 12450de5d07SNathan Whitehorn DIALOG_LISTITEM items[] = { 12550de5d07SNathan Whitehorn {"FAT32", "FAT Type 32", 12650de5d07SNathan Whitehorn "Create a FAT32 filesystem (default)", 1 }, 12750de5d07SNathan Whitehorn {"FAT16", "FAT Type 16", 12850de5d07SNathan Whitehorn "Create a FAT16 filesystem", 0 }, 12950de5d07SNathan Whitehorn {"FAT12", "FAT Type 12", 13050de5d07SNathan Whitehorn "Create a FAT12 filesystem", 0 }, 13150de5d07SNathan Whitehorn }; 13250de5d07SNathan Whitehorn 13350de5d07SNathan Whitehorn if (!use_default) { 13450de5d07SNathan Whitehorn int choice; 13550de5d07SNathan Whitehorn choice = dlg_checklist("FAT Options", "", 0, 0, 0, 13650de5d07SNathan Whitehorn sizeof(items)/sizeof(items[0]), items, NULL, 13750de5d07SNathan Whitehorn FLAG_RADIO, &i); 13850de5d07SNathan Whitehorn if (choice == 1) /* Cancel */ 13950de5d07SNathan Whitehorn return; 14050de5d07SNathan Whitehorn } 14150de5d07SNathan Whitehorn 14250de5d07SNathan Whitehorn strcpy(command, "newfs_msdos "); 14350de5d07SNathan Whitehorn for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) { 14450de5d07SNathan Whitehorn if (items[i].state == 0) 14550de5d07SNathan Whitehorn continue; 14650de5d07SNathan Whitehorn if (strcmp(items[i].name, "FAT32") == 0) 14750de5d07SNathan Whitehorn strcat(command, "-F 32 "); 14850de5d07SNathan Whitehorn else if (strcmp(items[i].name, "FAT16") == 0) 14950de5d07SNathan Whitehorn strcat(command, "-F 16 "); 15050de5d07SNathan Whitehorn else if (strcmp(items[i].name, "SUJ") == 0) 15150de5d07SNathan Whitehorn strcat(command, "-F 12 "); 15250de5d07SNathan Whitehorn } 15350de5d07SNathan Whitehorn } else { 15450de5d07SNathan Whitehorn if (!use_default) 15550de5d07SNathan Whitehorn dialog_msgbox("Error", "No configurable options exist " 15650de5d07SNathan Whitehorn "for this filesystem.", 0, 0, TRUE); 15750de5d07SNathan Whitehorn command[0] = '\0'; 15850de5d07SNathan Whitehorn } 15950de5d07SNathan Whitehorn } 16050de5d07SNathan Whitehorn 1612118f387SNathan Whitehorn int 1622118f387SNathan Whitehorn gpart_partition(const char *lg_name, const char *scheme) 1632118f387SNathan Whitehorn { 1642118f387SNathan Whitehorn int cancel, choice; 1652118f387SNathan Whitehorn struct gctl_req *r; 1662118f387SNathan Whitehorn const char *errstr; 1672118f387SNathan Whitehorn 1682118f387SNathan Whitehorn DIALOG_LISTITEM items[] = { 1692118f387SNathan Whitehorn {"APM", "Apple Partition Map", 1702118f387SNathan Whitehorn "Bootable on PowerPC Apple Hardware", 0 }, 1712118f387SNathan Whitehorn {"BSD", "BSD Labels", 1722118f387SNathan Whitehorn "Bootable on most x86 systems", 0 }, 1732118f387SNathan Whitehorn {"GPT", "GUID Partition Table", 1742118f387SNathan Whitehorn "Bootable on most x86 systems", 0 }, 1752118f387SNathan Whitehorn {"MBR", "DOS Partitions", 1762118f387SNathan Whitehorn "Bootable on most x86 systems", 0 }, 1772118f387SNathan Whitehorn {"PC98", "NEC PC9801 Partition Table", 1782118f387SNathan Whitehorn "Bootable on NEC PC9801 systems", 0 }, 1792118f387SNathan Whitehorn {"VTOC8", "Sun VTOC8 Partition Table", 1802118f387SNathan Whitehorn "Bootable on Sun SPARC systems", 0 }, 1812118f387SNathan Whitehorn }; 1822118f387SNathan Whitehorn 1832118f387SNathan Whitehorn schememenu: 1842118f387SNathan Whitehorn if (scheme == NULL) { 1852118f387SNathan Whitehorn dialog_vars.default_item = __DECONST(char *, default_scheme()); 1862118f387SNathan Whitehorn cancel = dlg_menu("Partition Scheme", 1872118f387SNathan Whitehorn "Select a partition scheme for this volume:", 0, 0, 0, 1882118f387SNathan Whitehorn sizeof(items) / sizeof(items[0]), items, &choice, NULL); 1892118f387SNathan Whitehorn dialog_vars.default_item = NULL; 1902118f387SNathan Whitehorn 1912118f387SNathan Whitehorn if (cancel) 1922118f387SNathan Whitehorn return (-1); 1932118f387SNathan Whitehorn 1942118f387SNathan Whitehorn if (!is_scheme_bootable(items[choice].name)) { 1952118f387SNathan Whitehorn char message[512]; 1962118f387SNathan Whitehorn sprintf(message, "This partition scheme (%s) is not " 1972118f387SNathan Whitehorn "bootable on this platform. Are you sure you want " 1982118f387SNathan Whitehorn "to proceed?", items[choice].name); 1992118f387SNathan Whitehorn dialog_vars.defaultno = TRUE; 2002118f387SNathan Whitehorn cancel = dialog_yesno("Warning", message, 0, 0); 2012118f387SNathan Whitehorn dialog_vars.defaultno = FALSE; 2022118f387SNathan Whitehorn if (cancel) /* cancel */ 2032118f387SNathan Whitehorn goto schememenu; 2042118f387SNathan Whitehorn } 2052118f387SNathan Whitehorn 2062118f387SNathan Whitehorn scheme = items[choice].name; 2072118f387SNathan Whitehorn } 2082118f387SNathan Whitehorn 2092118f387SNathan Whitehorn r = gctl_get_handle(); 2102118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 2112118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, lg_name); 2122118f387SNathan Whitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 2132118f387SNathan Whitehorn gctl_ro_param(r, "scheme", -1, scheme); 2142118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "create"); 2152118f387SNathan Whitehorn 2162118f387SNathan Whitehorn errstr = gctl_issue(r); 2172118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') { 2182118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 2192118f387SNathan Whitehorn gctl_free(r); 2202118f387SNathan Whitehorn scheme = NULL; 2212118f387SNathan Whitehorn goto schememenu; 2222118f387SNathan Whitehorn } 2232118f387SNathan Whitehorn gctl_free(r); 2242118f387SNathan Whitehorn 2252118f387SNathan Whitehorn if (bootcode_path(scheme) != NULL) 2262118f387SNathan Whitehorn get_part_metadata(lg_name, 1)->bootcode = 1; 2272118f387SNathan Whitehorn return (0); 2282118f387SNathan Whitehorn } 2292118f387SNathan Whitehorn 2302118f387SNathan Whitehorn static void 2312118f387SNathan Whitehorn gpart_activate(struct gprovider *pp) 2322118f387SNathan Whitehorn { 2332118f387SNathan Whitehorn struct gconfig *gc; 2342118f387SNathan Whitehorn struct gctl_req *r; 2352118f387SNathan Whitehorn const char *errstr, *scheme; 2362118f387SNathan Whitehorn const char *attribute = NULL; 2372118f387SNathan Whitehorn intmax_t idx; 2382118f387SNathan Whitehorn 2392118f387SNathan Whitehorn /* 2402118f387SNathan Whitehorn * Some partition schemes need this partition to be marked 'active' 2412118f387SNathan Whitehorn * for it to be bootable. 2422118f387SNathan Whitehorn */ 2432118f387SNathan Whitehorn LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) { 2442118f387SNathan Whitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 2452118f387SNathan Whitehorn scheme = gc->lg_val; 2462118f387SNathan Whitehorn break; 2472118f387SNathan Whitehorn } 2482118f387SNathan Whitehorn } 2492118f387SNathan Whitehorn 2502118f387SNathan Whitehorn if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "EBR") == 0 || 2512118f387SNathan Whitehorn strcmp(scheme, "PC98") == 0) 2522118f387SNathan Whitehorn attribute = "active"; 2532118f387SNathan Whitehorn else 2542118f387SNathan Whitehorn return; 2552118f387SNathan Whitehorn 2562118f387SNathan Whitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 2572118f387SNathan Whitehorn if (strcmp(gc->lg_name, "index") == 0) { 2582118f387SNathan Whitehorn idx = atoi(gc->lg_val); 2592118f387SNathan Whitehorn break; 2602118f387SNathan Whitehorn } 2612118f387SNathan Whitehorn } 2622118f387SNathan Whitehorn 2632118f387SNathan Whitehorn r = gctl_get_handle(); 2642118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 2652118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name); 2662118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "set"); 2672118f387SNathan Whitehorn gctl_ro_param(r, "attrib", -1, attribute); 2682118f387SNathan Whitehorn gctl_ro_param(r, "index", sizeof(idx), &idx); 2692118f387SNathan Whitehorn 2702118f387SNathan Whitehorn errstr = gctl_issue(r); 2712118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') 2722118f387SNathan Whitehorn gpart_show_error("Error", "Error marking partition active:", 2732118f387SNathan Whitehorn errstr); 2742118f387SNathan Whitehorn gctl_free(r); 2752118f387SNathan Whitehorn } 2762118f387SNathan Whitehorn 2772118f387SNathan Whitehorn static void 2782118f387SNathan Whitehorn gpart_bootcode(struct ggeom *gp) 2792118f387SNathan Whitehorn { 2802118f387SNathan Whitehorn const char *bootcode; 2812118f387SNathan Whitehorn struct gconfig *gc; 2822118f387SNathan Whitehorn struct gctl_req *r; 2832118f387SNathan Whitehorn const char *errstr, *scheme; 2842118f387SNathan Whitehorn uint8_t *boot; 2852118f387SNathan Whitehorn size_t bootsize, bytes; 2862118f387SNathan Whitehorn int bootfd; 2872118f387SNathan Whitehorn 2882118f387SNathan Whitehorn /* 2892118f387SNathan Whitehorn * Write default bootcode to the newly partitioned disk, if that 2902118f387SNathan Whitehorn * applies on this platform. 2912118f387SNathan Whitehorn */ 2922118f387SNathan Whitehorn LIST_FOREACH(gc, &gp->lg_config, lg_config) { 2932118f387SNathan Whitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 2942118f387SNathan Whitehorn scheme = gc->lg_val; 2952118f387SNathan Whitehorn break; 2962118f387SNathan Whitehorn } 2972118f387SNathan Whitehorn } 2982118f387SNathan Whitehorn 2992118f387SNathan Whitehorn bootcode = bootcode_path(scheme); 3002118f387SNathan Whitehorn if (bootcode == NULL) 3012118f387SNathan Whitehorn return; 3022118f387SNathan Whitehorn 3032118f387SNathan Whitehorn bootfd = open(bootcode, O_RDONLY); 3042118f387SNathan Whitehorn if (bootfd <= 0) { 3052118f387SNathan Whitehorn dialog_msgbox("Bootcode Error", strerror(errno), 0, 0, 3062118f387SNathan Whitehorn TRUE); 3072118f387SNathan Whitehorn return; 3082118f387SNathan Whitehorn } 3092118f387SNathan Whitehorn 3102118f387SNathan Whitehorn bootsize = lseek(bootfd, 0, SEEK_END); 3112118f387SNathan Whitehorn boot = malloc(bootsize); 3122118f387SNathan Whitehorn lseek(bootfd, 0, SEEK_SET); 3132118f387SNathan Whitehorn bytes = 0; 3142118f387SNathan Whitehorn while (bytes < bootsize) 3152118f387SNathan Whitehorn bytes += read(bootfd, boot + bytes, bootsize - bytes); 3162118f387SNathan Whitehorn close(bootfd); 3172118f387SNathan Whitehorn 3182118f387SNathan Whitehorn r = gctl_get_handle(); 3192118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 3202118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, gp->lg_name); 3212118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "bootcode"); 3222118f387SNathan Whitehorn gctl_ro_param(r, "bootcode", bootsize, boot); 3232118f387SNathan Whitehorn 3242118f387SNathan Whitehorn errstr = gctl_issue(r); 3252118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') 3262118f387SNathan Whitehorn gpart_show_error("Bootcode Error", NULL, errstr); 3272118f387SNathan Whitehorn gctl_free(r); 3282118f387SNathan Whitehorn free(boot); 3292118f387SNathan Whitehorn } 3302118f387SNathan Whitehorn 3312118f387SNathan Whitehorn static void 3322118f387SNathan Whitehorn gpart_partcode(struct gprovider *pp) 3332118f387SNathan Whitehorn { 3342118f387SNathan Whitehorn struct gconfig *gc; 3352118f387SNathan Whitehorn const char *scheme; 3362118f387SNathan Whitehorn const char *indexstr; 3372118f387SNathan Whitehorn char message[255], command[255]; 3382118f387SNathan Whitehorn 3392118f387SNathan Whitehorn LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) { 3402118f387SNathan Whitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 3412118f387SNathan Whitehorn scheme = gc->lg_val; 3422118f387SNathan Whitehorn break; 3432118f387SNathan Whitehorn } 3442118f387SNathan Whitehorn } 3452118f387SNathan Whitehorn 3462118f387SNathan Whitehorn /* Make sure this partition scheme needs partcode on this platform */ 3472118f387SNathan Whitehorn if (partcode_path(scheme) == NULL) 3482118f387SNathan Whitehorn return; 3492118f387SNathan Whitehorn 3502118f387SNathan Whitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 3512118f387SNathan Whitehorn if (strcmp(gc->lg_name, "index") == 0) { 3522118f387SNathan Whitehorn indexstr = gc->lg_val; 3532118f387SNathan Whitehorn break; 3542118f387SNathan Whitehorn } 3552118f387SNathan Whitehorn } 3562118f387SNathan Whitehorn 3572118f387SNathan Whitehorn /* Shell out to gpart for partcode for now */ 3582118f387SNathan Whitehorn sprintf(command, "gpart bootcode -p %s -i %s %s", 3592118f387SNathan Whitehorn partcode_path(scheme), indexstr, pp->lg_geom->lg_name); 3602118f387SNathan Whitehorn if (system(command) != 0) { 3612118f387SNathan Whitehorn sprintf(message, "Error installing partcode on partition %s", 3622118f387SNathan Whitehorn pp->lg_name); 3632118f387SNathan Whitehorn dialog_msgbox("Error", message, 0, 0, TRUE); 3642118f387SNathan Whitehorn } 3652118f387SNathan Whitehorn } 3662118f387SNathan Whitehorn 3672118f387SNathan Whitehorn void 3682118f387SNathan Whitehorn gpart_destroy(struct ggeom *lg_geom, int force) 3692118f387SNathan Whitehorn { 3702118f387SNathan Whitehorn struct gprovider *pp; 3712118f387SNathan Whitehorn struct gctl_req *r; 3722118f387SNathan Whitehorn const char *errstr; 3732118f387SNathan Whitehorn 3742118f387SNathan Whitehorn /* Begin with the hosing: delete all partitions */ 3752118f387SNathan Whitehorn LIST_FOREACH(pp, &lg_geom->lg_provider, lg_provider) 3762118f387SNathan Whitehorn gpart_delete(pp); 3772118f387SNathan Whitehorn 3782118f387SNathan Whitehorn /* Now destroy the geom itself */ 3792118f387SNathan Whitehorn r = gctl_get_handle(); 3802118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 3812118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, lg_geom->lg_name); 3822118f387SNathan Whitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 3832118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "destroy"); 3842118f387SNathan Whitehorn errstr = gctl_issue(r); 3852118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') 3862118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 3872118f387SNathan Whitehorn gctl_free(r); 3882118f387SNathan Whitehorn 3892118f387SNathan Whitehorn /* If asked, commit the change */ 3902118f387SNathan Whitehorn if (force) { 3912118f387SNathan Whitehorn r = gctl_get_handle(); 3922118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 3932118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, lg_geom->lg_name); 3942118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "commit"); 3952118f387SNathan Whitehorn errstr = gctl_issue(r); 3962118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') 3972118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 3982118f387SNathan Whitehorn gctl_free(r); 3992118f387SNathan Whitehorn } 4002118f387SNathan Whitehorn 4012118f387SNathan Whitehorn /* And any metadata associated with the partition scheme itself */ 4022118f387SNathan Whitehorn delete_part_metadata(lg_geom->lg_name); 4032118f387SNathan Whitehorn } 4042118f387SNathan Whitehorn 4052118f387SNathan Whitehorn void 4062118f387SNathan Whitehorn gpart_edit(struct gprovider *pp) 4072118f387SNathan Whitehorn { 4082118f387SNathan Whitehorn struct gctl_req *r; 4092118f387SNathan Whitehorn struct gconfig *gc; 4102118f387SNathan Whitehorn struct gconsumer *cp; 4112118f387SNathan Whitehorn struct ggeom *geom; 4122118f387SNathan Whitehorn const char *errstr, *oldtype, *scheme; 4132118f387SNathan Whitehorn struct partition_metadata *md; 4142118f387SNathan Whitehorn char sizestr[32]; 41550de5d07SNathan Whitehorn char newfs[64]; 4162118f387SNathan Whitehorn intmax_t idx; 4172118f387SNathan Whitehorn int hadlabel, choice, junk, nitems; 4182118f387SNathan Whitehorn unsigned i; 4192118f387SNathan Whitehorn 4202118f387SNathan Whitehorn DIALOG_FORMITEM items[] = { 4212118f387SNathan Whitehorn {0, "Type:", 5, 0, 0, FALSE, "", 11, 0, 12, 15, 0, 4222118f387SNathan Whitehorn FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-swap)", 4232118f387SNathan Whitehorn FALSE}, 4242118f387SNathan Whitehorn {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 0, 0, 4252118f387SNathan Whitehorn FALSE, "Partition size. Append K, M, G for kilobytes, " 4262118f387SNathan Whitehorn "megabytes or gigabytes.", FALSE}, 4272118f387SNathan Whitehorn {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0, 4282118f387SNathan Whitehorn FALSE, "Path at which to mount this partition (leave blank " 4292118f387SNathan Whitehorn "for swap, set to / for root filesystem)", FALSE}, 4302118f387SNathan Whitehorn {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE, 4312118f387SNathan Whitehorn "Partition name. Not all partition schemes support this.", 4322118f387SNathan Whitehorn FALSE}, 4332118f387SNathan Whitehorn }; 4342118f387SNathan Whitehorn 4352118f387SNathan Whitehorn /* 4362118f387SNathan Whitehorn * Find the PART geom we are manipulating. This may be a consumer of 4372118f387SNathan Whitehorn * this provider, or its parent. Check the consumer case first. 4382118f387SNathan Whitehorn */ 4392118f387SNathan Whitehorn geom = NULL; 4402118f387SNathan Whitehorn LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 4412118f387SNathan Whitehorn if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 4422118f387SNathan Whitehorn char message[512]; 4432118f387SNathan Whitehorn /* 4442118f387SNathan Whitehorn * The PART object is a consumer, so the user wants to 4452118f387SNathan Whitehorn * edit the partition table. gpart doesn't really 4462118f387SNathan Whitehorn * support this, so we have to hose the whole table 4472118f387SNathan Whitehorn * first. 4482118f387SNathan Whitehorn */ 4492118f387SNathan Whitehorn 4502118f387SNathan Whitehorn sprintf(message, "Changing the partition scheme on " 4512118f387SNathan Whitehorn "this disk (%s) requires deleting all existing " 4522118f387SNathan Whitehorn "partitions on this drive. This will PERMANENTLY " 4532118f387SNathan Whitehorn "ERASE any data stored here. Are you sure you want " 4542118f387SNathan Whitehorn "to proceed?", cp->lg_geom->lg_name); 4552118f387SNathan Whitehorn dialog_vars.defaultno = TRUE; 4562118f387SNathan Whitehorn choice = dialog_yesno("Warning", message, 0, 0); 4572118f387SNathan Whitehorn dialog_vars.defaultno = FALSE; 4582118f387SNathan Whitehorn 4592118f387SNathan Whitehorn if (choice == 1) /* cancel */ 4602118f387SNathan Whitehorn return; 4612118f387SNathan Whitehorn 4622118f387SNathan Whitehorn /* Destroy the geom and all sub-partitions */ 4632118f387SNathan Whitehorn gpart_destroy(cp->lg_geom, 0); 4642118f387SNathan Whitehorn 4652118f387SNathan Whitehorn /* Now re-partition and return */ 4662118f387SNathan Whitehorn gpart_partition(cp->lg_geom->lg_name, NULL); 4672118f387SNathan Whitehorn return; 4682118f387SNathan Whitehorn } 4692118f387SNathan Whitehorn 4702118f387SNathan Whitehorn if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 4712118f387SNathan Whitehorn geom = pp->lg_geom; 4722118f387SNathan Whitehorn 4732118f387SNathan Whitehorn if (geom == NULL) { 4742118f387SNathan Whitehorn /* Disk not partitioned, so partition it */ 475bcc25b7eSNathan Whitehorn gpart_partition(pp->lg_name, NULL); 4762118f387SNathan Whitehorn return; 4772118f387SNathan Whitehorn } 4782118f387SNathan Whitehorn 4792118f387SNathan Whitehorn LIST_FOREACH(gc, &geom->lg_config, lg_config) { 4802118f387SNathan Whitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 4812118f387SNathan Whitehorn scheme = gc->lg_val; 4822118f387SNathan Whitehorn break; 4832118f387SNathan Whitehorn } 4842118f387SNathan Whitehorn } 4852118f387SNathan Whitehorn 486c67f41d0SNathan Whitehorn nitems = scheme_supports_labels(scheme) ? 4 : 3; 4872118f387SNathan Whitehorn 4882118f387SNathan Whitehorn /* Edit editable parameters of a partition */ 4892118f387SNathan Whitehorn hadlabel = 0; 4902118f387SNathan Whitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 4912118f387SNathan Whitehorn if (strcmp(gc->lg_name, "type") == 0) { 4922118f387SNathan Whitehorn oldtype = gc->lg_val; 4932118f387SNathan Whitehorn items[0].text = gc->lg_val; 4942118f387SNathan Whitehorn } 4952118f387SNathan Whitehorn if (strcmp(gc->lg_name, "label") == 0 && gc->lg_val != NULL) { 4962118f387SNathan Whitehorn hadlabel = 1; 4972118f387SNathan Whitehorn items[3].text = gc->lg_val; 4982118f387SNathan Whitehorn } 4992118f387SNathan Whitehorn if (strcmp(gc->lg_name, "index") == 0) 5002118f387SNathan Whitehorn idx = atoi(gc->lg_val); 5012118f387SNathan Whitehorn } 5022118f387SNathan Whitehorn 5032118f387SNathan Whitehorn TAILQ_FOREACH(md, &part_metadata, metadata) { 5042118f387SNathan Whitehorn if (md->name != NULL && strcmp(md->name, pp->lg_name) == 0) { 5052118f387SNathan Whitehorn if (md->fstab != NULL) 5062118f387SNathan Whitehorn items[2].text = md->fstab->fs_file; 5072118f387SNathan Whitehorn break; 5082118f387SNathan Whitehorn } 5092118f387SNathan Whitehorn } 5102118f387SNathan Whitehorn 5112118f387SNathan Whitehorn humanize_number(sizestr, 7, pp->lg_mediasize, "B", HN_AUTOSCALE, 5122118f387SNathan Whitehorn HN_NOSPACE | HN_DECIMAL); 5132118f387SNathan Whitehorn items[1].text = sizestr; 5142118f387SNathan Whitehorn 5152118f387SNathan Whitehorn editpart: 5162118f387SNathan Whitehorn choice = dlg_form("Edit Partition", "", 0, 0, 0, nitems, items, &junk); 5172118f387SNathan Whitehorn 5182118f387SNathan Whitehorn if (choice) /* Cancel pressed */ 5192118f387SNathan Whitehorn return; 5202118f387SNathan Whitehorn 5212118f387SNathan Whitehorn /* Check if the label has a / in it */ 5222118f387SNathan Whitehorn if (strchr(items[3].text, '/') != NULL) { 5232118f387SNathan Whitehorn dialog_msgbox("Error", "Label contains a /, which is not an " 5242118f387SNathan Whitehorn "allowed character.", 0, 0, TRUE); 5252118f387SNathan Whitehorn goto editpart; 5262118f387SNathan Whitehorn } 5272118f387SNathan Whitehorn 5282118f387SNathan Whitehorn r = gctl_get_handle(); 5292118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 5302118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, geom->lg_name); 5312118f387SNathan Whitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 5322118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "modify"); 5332118f387SNathan Whitehorn gctl_ro_param(r, "index", sizeof(idx), &idx); 5342118f387SNathan Whitehorn if (hadlabel || items[3].text[0] != '\0') 5352118f387SNathan Whitehorn gctl_ro_param(r, "label", -1, items[3].text); 5362118f387SNathan Whitehorn gctl_ro_param(r, "type", -1, items[0].text); 5372118f387SNathan Whitehorn errstr = gctl_issue(r); 5382118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') { 5392118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 5402118f387SNathan Whitehorn gctl_free(r); 5412118f387SNathan Whitehorn goto editpart; 5422118f387SNathan Whitehorn } 5432118f387SNathan Whitehorn gctl_free(r); 5442118f387SNathan Whitehorn 54550de5d07SNathan Whitehorn newfs_command(items[0].text, newfs, 1); 5462118f387SNathan Whitehorn set_default_part_metadata(pp->lg_name, scheme, items[0].text, 54750de5d07SNathan Whitehorn items[2].text, (strcmp(oldtype, items[0].text) != 0) ? 54850de5d07SNathan Whitehorn newfs : NULL); 5492118f387SNathan Whitehorn 5502118f387SNathan Whitehorn for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++) 5512118f387SNathan Whitehorn if (items[i].text_free) 5522118f387SNathan Whitehorn free(items[i].text); 5532118f387SNathan Whitehorn } 5542118f387SNathan Whitehorn 5552118f387SNathan Whitehorn void 5562118f387SNathan Whitehorn set_default_part_metadata(const char *name, const char *scheme, 55750de5d07SNathan Whitehorn const char *type, const char *mountpoint, const char *newfs) 5582118f387SNathan Whitehorn { 5592118f387SNathan Whitehorn struct partition_metadata *md; 5602118f387SNathan Whitehorn 5612118f387SNathan Whitehorn /* Set part metadata */ 5622118f387SNathan Whitehorn md = get_part_metadata(name, 1); 5632118f387SNathan Whitehorn 5642118f387SNathan Whitehorn if (newfs) { 5652118f387SNathan Whitehorn if (md->newfs != NULL) { 5662118f387SNathan Whitehorn free(md->newfs); 5672118f387SNathan Whitehorn md->newfs = NULL; 5682118f387SNathan Whitehorn } 5692118f387SNathan Whitehorn 57050de5d07SNathan Whitehorn if (newfs != NULL && newfs[0] != '\0') { 57150de5d07SNathan Whitehorn md->newfs = malloc(strlen(newfs) + strlen(" /dev/") + 57250de5d07SNathan Whitehorn strlen(name) + 1); 57350de5d07SNathan Whitehorn sprintf(md->newfs, "%s /dev/%s", newfs, name); 5742118f387SNathan Whitehorn } 5752118f387SNathan Whitehorn } 5762118f387SNathan Whitehorn 5772118f387SNathan Whitehorn if (strcmp(type, "freebsd-swap") == 0) 5782118f387SNathan Whitehorn mountpoint = "none"; 5792118f387SNathan Whitehorn if (strcmp(type, "freebsd-boot") == 0) 5802118f387SNathan Whitehorn md->bootcode = 1; 5812118f387SNathan Whitehorn 5822118f387SNathan Whitehorn /* VTOC8 needs partcode in UFS partitions */ 5832118f387SNathan Whitehorn if (strcmp(scheme, "VTOC8") == 0 && strcmp(type, "freebsd-ufs") == 0) 5842118f387SNathan Whitehorn md->bootcode = 1; 5852118f387SNathan Whitehorn 5862118f387SNathan Whitehorn if (mountpoint == NULL || mountpoint[0] == '\0') { 5872118f387SNathan Whitehorn if (md->fstab != NULL) { 5882118f387SNathan Whitehorn free(md->fstab->fs_spec); 5892118f387SNathan Whitehorn free(md->fstab->fs_file); 5902118f387SNathan Whitehorn free(md->fstab->fs_vfstype); 5912118f387SNathan Whitehorn free(md->fstab->fs_mntops); 5922118f387SNathan Whitehorn free(md->fstab->fs_type); 5932118f387SNathan Whitehorn free(md->fstab); 5942118f387SNathan Whitehorn md->fstab = NULL; 5952118f387SNathan Whitehorn } 5962118f387SNathan Whitehorn } else { 5972118f387SNathan Whitehorn if (md->fstab == NULL) { 5982118f387SNathan Whitehorn md->fstab = malloc(sizeof(struct fstab)); 5992118f387SNathan Whitehorn } else { 6002118f387SNathan Whitehorn free(md->fstab->fs_spec); 6012118f387SNathan Whitehorn free(md->fstab->fs_file); 6022118f387SNathan Whitehorn free(md->fstab->fs_vfstype); 6032118f387SNathan Whitehorn free(md->fstab->fs_mntops); 6042118f387SNathan Whitehorn free(md->fstab->fs_type); 6052118f387SNathan Whitehorn } 6062118f387SNathan Whitehorn md->fstab->fs_spec = malloc(strlen(name) + 6); 6072118f387SNathan Whitehorn sprintf(md->fstab->fs_spec, "/dev/%s", name); 6082118f387SNathan Whitehorn md->fstab->fs_file = strdup(mountpoint); 6092118f387SNathan Whitehorn /* Get VFS from text after freebsd-, if possible */ 61050de5d07SNathan Whitehorn if (strncmp("freebsd-", type, 8) == 0) 6112118f387SNathan Whitehorn md->fstab->fs_vfstype = strdup(&type[8]); 61250de5d07SNathan Whitehorn else if (strcmp("fat32", type) == 0 || strcmp("efi", type) == 0) 61350de5d07SNathan Whitehorn md->fstab->fs_vfstype = strdup("msdosfs"); 6142118f387SNathan Whitehorn else 6152118f387SNathan Whitehorn md->fstab->fs_vfstype = strdup(type); /* Guess */ 6162118f387SNathan Whitehorn if (strcmp(type, "freebsd-swap") == 0) { 6172118f387SNathan Whitehorn md->fstab->fs_type = strdup(FSTAB_SW); 6182118f387SNathan Whitehorn md->fstab->fs_freq = 0; 6192118f387SNathan Whitehorn md->fstab->fs_passno = 0; 6202118f387SNathan Whitehorn } else { 6212118f387SNathan Whitehorn md->fstab->fs_type = strdup(FSTAB_RW); 6222118f387SNathan Whitehorn if (strcmp(mountpoint, "/") == 0) { 6232118f387SNathan Whitehorn md->fstab->fs_freq = 1; 6242118f387SNathan Whitehorn md->fstab->fs_passno = 1; 6252118f387SNathan Whitehorn } else { 6262118f387SNathan Whitehorn md->fstab->fs_freq = 2; 6272118f387SNathan Whitehorn md->fstab->fs_passno = 2; 6282118f387SNathan Whitehorn } 6292118f387SNathan Whitehorn } 6302118f387SNathan Whitehorn md->fstab->fs_mntops = strdup(md->fstab->fs_type); 6312118f387SNathan Whitehorn } 6322118f387SNathan Whitehorn } 6332118f387SNathan Whitehorn 6342118f387SNathan Whitehorn static 6352118f387SNathan Whitehorn int part_compare(const void *xa, const void *xb) 6362118f387SNathan Whitehorn { 6372118f387SNathan Whitehorn struct gprovider **a = (struct gprovider **)xa; 6382118f387SNathan Whitehorn struct gprovider **b = (struct gprovider **)xb; 6392118f387SNathan Whitehorn intmax_t astart, bstart; 6402118f387SNathan Whitehorn struct gconfig *gc; 6412118f387SNathan Whitehorn 6422118f387SNathan Whitehorn astart = bstart = 0; 6432118f387SNathan Whitehorn LIST_FOREACH(gc, &(*a)->lg_config, lg_config) 6442118f387SNathan Whitehorn if (strcmp(gc->lg_name, "start") == 0) { 6452118f387SNathan Whitehorn astart = strtoimax(gc->lg_val, NULL, 0); 6462118f387SNathan Whitehorn break; 6472118f387SNathan Whitehorn } 6482118f387SNathan Whitehorn LIST_FOREACH(gc, &(*b)->lg_config, lg_config) 6492118f387SNathan Whitehorn if (strcmp(gc->lg_name, "start") == 0) { 6502118f387SNathan Whitehorn bstart = strtoimax(gc->lg_val, NULL, 0); 6512118f387SNathan Whitehorn break; 6522118f387SNathan Whitehorn } 6532118f387SNathan Whitehorn 6542118f387SNathan Whitehorn if (astart < bstart) 6552118f387SNathan Whitehorn return -1; 6562118f387SNathan Whitehorn else if (astart > bstart) 6572118f387SNathan Whitehorn return 1; 6582118f387SNathan Whitehorn else 6592118f387SNathan Whitehorn return 0; 6602118f387SNathan Whitehorn } 6612118f387SNathan Whitehorn 6622118f387SNathan Whitehorn intmax_t 6632118f387SNathan Whitehorn gpart_max_free(struct ggeom *geom, intmax_t *npartstart) 6642118f387SNathan Whitehorn { 6652118f387SNathan Whitehorn struct gconfig *gc; 6662118f387SNathan Whitehorn struct gprovider *pp, **providers; 6672118f387SNathan Whitehorn intmax_t lastend; 6682118f387SNathan Whitehorn intmax_t start, end; 6692118f387SNathan Whitehorn intmax_t maxsize, maxstart; 6702118f387SNathan Whitehorn intmax_t partstart, partend; 6712118f387SNathan Whitehorn int i, nparts; 6722118f387SNathan Whitehorn 6732118f387SNathan Whitehorn /* Now get the maximum free size and free start */ 6742118f387SNathan Whitehorn start = end = 0; 6752118f387SNathan Whitehorn LIST_FOREACH(gc, &geom->lg_config, lg_config) { 6762118f387SNathan Whitehorn if (strcmp(gc->lg_name, "first") == 0) 6772118f387SNathan Whitehorn start = strtoimax(gc->lg_val, NULL, 0); 6782118f387SNathan Whitehorn if (strcmp(gc->lg_name, "last") == 0) 6792118f387SNathan Whitehorn end = strtoimax(gc->lg_val, NULL, 0); 6802118f387SNathan Whitehorn } 6812118f387SNathan Whitehorn 6822118f387SNathan Whitehorn i = nparts = 0; 6832118f387SNathan Whitehorn LIST_FOREACH(pp, &geom->lg_provider, lg_provider) 6842118f387SNathan Whitehorn nparts++; 6852118f387SNathan Whitehorn providers = calloc(nparts, sizeof(providers[0])); 6862118f387SNathan Whitehorn LIST_FOREACH(pp, &geom->lg_provider, lg_provider) 6872118f387SNathan Whitehorn providers[i++] = pp; 6882118f387SNathan Whitehorn qsort(providers, nparts, sizeof(providers[0]), part_compare); 6892118f387SNathan Whitehorn 6902118f387SNathan Whitehorn lastend = start - 1; 6912118f387SNathan Whitehorn maxsize = 0; 6922118f387SNathan Whitehorn for (i = 0; i < nparts; i++) { 6932118f387SNathan Whitehorn pp = providers[i]; 6942118f387SNathan Whitehorn 6952118f387SNathan Whitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 6962118f387SNathan Whitehorn if (strcmp(gc->lg_name, "start") == 0) 6972118f387SNathan Whitehorn partstart = strtoimax(gc->lg_val, NULL, 0); 6982118f387SNathan Whitehorn if (strcmp(gc->lg_name, "end") == 0) 6992118f387SNathan Whitehorn partend = strtoimax(gc->lg_val, NULL, 0); 7002118f387SNathan Whitehorn } 7012118f387SNathan Whitehorn 7022118f387SNathan Whitehorn if (partstart - lastend > maxsize) { 7032118f387SNathan Whitehorn maxsize = partstart - lastend - 1; 7042118f387SNathan Whitehorn maxstart = lastend + 1; 7052118f387SNathan Whitehorn } 7062118f387SNathan Whitehorn 7072118f387SNathan Whitehorn lastend = partend; 7082118f387SNathan Whitehorn } 7092118f387SNathan Whitehorn 7102118f387SNathan Whitehorn if (end - lastend > maxsize) { 7112118f387SNathan Whitehorn maxsize = end - lastend - 1; 7122118f387SNathan Whitehorn maxstart = lastend + 1; 7132118f387SNathan Whitehorn } 7142118f387SNathan Whitehorn 7152118f387SNathan Whitehorn pp = LIST_FIRST(&geom->lg_consumer)->lg_provider; 7162118f387SNathan Whitehorn 7172118f387SNathan Whitehorn /* Compute beginning of new partition and maximum available space */ 7182118f387SNathan Whitehorn if (pp->lg_stripesize > 0 && 7192118f387SNathan Whitehorn (maxstart*pp->lg_sectorsize % pp->lg_stripesize) != 0) { 7202118f387SNathan Whitehorn intmax_t offset = (pp->lg_stripesize - 7212118f387SNathan Whitehorn ((maxstart*pp->lg_sectorsize) % pp->lg_stripesize)) / 7222118f387SNathan Whitehorn pp->lg_sectorsize; 7232118f387SNathan Whitehorn maxstart += offset; 7242118f387SNathan Whitehorn maxsize -= offset; 7252118f387SNathan Whitehorn } 7262118f387SNathan Whitehorn 7272118f387SNathan Whitehorn if (npartstart != NULL) 7282118f387SNathan Whitehorn *npartstart = maxstart; 7292118f387SNathan Whitehorn 7302118f387SNathan Whitehorn return (maxsize); 7312118f387SNathan Whitehorn } 7322118f387SNathan Whitehorn 7332118f387SNathan Whitehorn void 7342118f387SNathan Whitehorn gpart_create(struct gprovider *pp, char *default_type, char *default_size, 7352118f387SNathan Whitehorn char *default_mountpoint, char **partname, int interactive) 7362118f387SNathan Whitehorn { 7372118f387SNathan Whitehorn struct gctl_req *r; 7382118f387SNathan Whitehorn struct gconfig *gc; 7392118f387SNathan Whitehorn struct gconsumer *cp; 7402118f387SNathan Whitehorn struct ggeom *geom; 7412118f387SNathan Whitehorn const char *errstr, *scheme; 7422118f387SNathan Whitehorn char sizestr[32], startstr[32], output[64]; 74350de5d07SNathan Whitehorn char newfs[64], options_fstype[64]; 7442118f387SNathan Whitehorn intmax_t maxsize, size, sector, firstfree, stripe; 7452118f387SNathan Whitehorn uint64_t bytes; 7462118f387SNathan Whitehorn int nitems, choice, junk; 7472118f387SNathan Whitehorn unsigned i; 7482118f387SNathan Whitehorn 7492118f387SNathan Whitehorn DIALOG_FORMITEM items[] = { 7502118f387SNathan Whitehorn {0, "Type:", 5, 0, 0, FALSE, "freebsd-ufs", 11, 0, 12, 15, 0, 7512118f387SNathan Whitehorn FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-swap)", 7522118f387SNathan Whitehorn FALSE}, 7532118f387SNathan Whitehorn {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 15, 0, 7542118f387SNathan Whitehorn FALSE, "Partition size. Append K, M, G for kilobytes, " 7552118f387SNathan Whitehorn "megabytes or gigabytes.", FALSE}, 7562118f387SNathan Whitehorn {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0, 7572118f387SNathan Whitehorn FALSE, "Path at which to mount partition (blank for " 7582118f387SNathan Whitehorn "swap, / for root filesystem)", FALSE}, 7592118f387SNathan Whitehorn {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE, 7602118f387SNathan Whitehorn "Partition name. Not all partition schemes support this.", 7612118f387SNathan Whitehorn FALSE}, 7622118f387SNathan Whitehorn }; 7632118f387SNathan Whitehorn 7642118f387SNathan Whitehorn if (partname != NULL) 7652118f387SNathan Whitehorn *partname = NULL; 7662118f387SNathan Whitehorn 7672118f387SNathan Whitehorn /* Record sector and stripe sizes */ 7682118f387SNathan Whitehorn sector = pp->lg_sectorsize; 7692118f387SNathan Whitehorn stripe = pp->lg_stripesize; 7702118f387SNathan Whitehorn 7712118f387SNathan Whitehorn /* 7722118f387SNathan Whitehorn * Find the PART geom we are manipulating. This may be a consumer of 7732118f387SNathan Whitehorn * this provider, or its parent. Check the consumer case first. 7742118f387SNathan Whitehorn */ 7752118f387SNathan Whitehorn geom = NULL; 7762118f387SNathan Whitehorn LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 7772118f387SNathan Whitehorn if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 7782118f387SNathan Whitehorn geom = cp->lg_geom; 7792118f387SNathan Whitehorn break; 7802118f387SNathan Whitehorn } 7812118f387SNathan Whitehorn 7822118f387SNathan Whitehorn if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 7832118f387SNathan Whitehorn geom = pp->lg_geom; 7842118f387SNathan Whitehorn 7852118f387SNathan Whitehorn /* Now get the partition scheme */ 7862118f387SNathan Whitehorn scheme = NULL; 7872118f387SNathan Whitehorn if (geom != NULL) { 7882118f387SNathan Whitehorn LIST_FOREACH(gc, &geom->lg_config, lg_config) 7892118f387SNathan Whitehorn if (strcmp(gc->lg_name, "scheme") == 0) 7902118f387SNathan Whitehorn scheme = gc->lg_val; 7912118f387SNathan Whitehorn } 7922118f387SNathan Whitehorn 7932118f387SNathan Whitehorn if (geom == NULL || scheme == NULL || strcmp(scheme, "(none)") == 0) { 794bcc25b7eSNathan Whitehorn if (gpart_partition(pp->lg_name, NULL) == 0) 7952118f387SNathan Whitehorn dialog_msgbox("", 7962118f387SNathan Whitehorn "The partition table has been successfully created." 7972118f387SNathan Whitehorn " Please press Create again to create partitions.", 7982118f387SNathan Whitehorn 0, 0, TRUE); 7992118f387SNathan Whitehorn 8002118f387SNathan Whitehorn return; 8012118f387SNathan Whitehorn } 8022118f387SNathan Whitehorn 8032118f387SNathan Whitehorn /* 8042118f387SNathan Whitehorn * If we still don't have a geom, either the user has 8052118f387SNathan Whitehorn * canceled partitioning or there has been an error which has already 8062118f387SNathan Whitehorn * been displayed, so bail. 8072118f387SNathan Whitehorn */ 8082118f387SNathan Whitehorn if (geom == NULL) 8092118f387SNathan Whitehorn return; 8102118f387SNathan Whitehorn 8112118f387SNathan Whitehorn maxsize = size = gpart_max_free(geom, &firstfree); 8122118f387SNathan Whitehorn if (size <= 0) { 8132118f387SNathan Whitehorn dialog_msgbox("Error", "No free space left on device.", 0, 0, 8142118f387SNathan Whitehorn TRUE); 8152118f387SNathan Whitehorn return; 8162118f387SNathan Whitehorn } 8172118f387SNathan Whitehorn 8182118f387SNathan Whitehorn humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE, 8192118f387SNathan Whitehorn HN_NOSPACE | HN_DECIMAL); 8202118f387SNathan Whitehorn items[1].text = sizestr; 8212118f387SNathan Whitehorn 8222118f387SNathan Whitehorn /* Special-case the MBR default type for nested partitions */ 823bcc25b7eSNathan Whitehorn if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "PC98") == 0) { 8242118f387SNathan Whitehorn items[0].text = "freebsd"; 825bcc25b7eSNathan Whitehorn items[0].help = "Filesystem type (e.g. freebsd, fat32)"; 826bcc25b7eSNathan Whitehorn } 8272118f387SNathan Whitehorn 828c67f41d0SNathan Whitehorn nitems = scheme_supports_labels(scheme) ? 4 : 3; 8292118f387SNathan Whitehorn 8302118f387SNathan Whitehorn if (default_type != NULL) 8312118f387SNathan Whitehorn items[0].text = default_type; 8322118f387SNathan Whitehorn if (default_size != NULL) 8332118f387SNathan Whitehorn items[1].text = default_size; 8342118f387SNathan Whitehorn if (default_mountpoint != NULL) 8352118f387SNathan Whitehorn items[2].text = default_mountpoint; 8362118f387SNathan Whitehorn 83750de5d07SNathan Whitehorn /* Default options */ 83850de5d07SNathan Whitehorn strncpy(options_fstype, items[0].text, 83950de5d07SNathan Whitehorn sizeof(options_fstype)); 84050de5d07SNathan Whitehorn newfs_command(options_fstype, newfs, 1); 8412118f387SNathan Whitehorn addpartform: 8422118f387SNathan Whitehorn if (interactive) { 84350de5d07SNathan Whitehorn dialog_vars.extra_label = "Options"; 84450de5d07SNathan Whitehorn dialog_vars.extra_button = TRUE; 8452118f387SNathan Whitehorn choice = dlg_form("Add Partition", "", 0, 0, 0, nitems, 8462118f387SNathan Whitehorn items, &junk); 84750de5d07SNathan Whitehorn dialog_vars.extra_button = FALSE; 84850de5d07SNathan Whitehorn switch (choice) { 84950de5d07SNathan Whitehorn case 0: /* OK */ 85050de5d07SNathan Whitehorn break; 85150de5d07SNathan Whitehorn case 1: /* Cancel */ 8522118f387SNathan Whitehorn return; 85350de5d07SNathan Whitehorn case 3: /* Options */ 85450de5d07SNathan Whitehorn strncpy(options_fstype, items[0].text, 85550de5d07SNathan Whitehorn sizeof(options_fstype)); 85650de5d07SNathan Whitehorn newfs_command(options_fstype, newfs, 0); 85750de5d07SNathan Whitehorn goto addpartform; 85850de5d07SNathan Whitehorn } 85950de5d07SNathan Whitehorn } 86050de5d07SNathan Whitehorn 86150de5d07SNathan Whitehorn /* 86250de5d07SNathan Whitehorn * If the user changed the fs type after specifying options, undo 86350de5d07SNathan Whitehorn * their choices in favor of the new filesystem's defaults. 86450de5d07SNathan Whitehorn */ 8650d49c6d5SNathan Whitehorn if (strcmp(options_fstype, items[0].text) != 0) { 86650de5d07SNathan Whitehorn strncpy(options_fstype, items[0].text, sizeof(options_fstype)); 86750de5d07SNathan Whitehorn newfs_command(options_fstype, newfs, 1); 8682118f387SNathan Whitehorn } 8692118f387SNathan Whitehorn 8702118f387SNathan Whitehorn size = maxsize; 8712118f387SNathan Whitehorn if (strlen(items[1].text) > 0) { 8722118f387SNathan Whitehorn if (expand_number(items[1].text, &bytes) != 0) { 8732118f387SNathan Whitehorn char error[512]; 8742118f387SNathan Whitehorn 8752118f387SNathan Whitehorn sprintf(error, "Invalid size: %s\n", strerror(errno)); 8762118f387SNathan Whitehorn dialog_msgbox("Error", error, 0, 0, TRUE); 8772118f387SNathan Whitehorn goto addpartform; 8782118f387SNathan Whitehorn } 8792118f387SNathan Whitehorn size = MIN((intmax_t)(bytes/sector), maxsize); 8802118f387SNathan Whitehorn } 8812118f387SNathan Whitehorn 8822118f387SNathan Whitehorn /* Check if the label has a / in it */ 8832118f387SNathan Whitehorn if (strchr(items[3].text, '/') != NULL) { 8842118f387SNathan Whitehorn dialog_msgbox("Error", "Label contains a /, which is not an " 8852118f387SNathan Whitehorn "allowed character.", 0, 0, TRUE); 8862118f387SNathan Whitehorn goto addpartform; 8872118f387SNathan Whitehorn } 8882118f387SNathan Whitehorn 8892118f387SNathan Whitehorn /* Warn if no mountpoint set */ 8902118f387SNathan Whitehorn if (strcmp(items[0].text, "freebsd-ufs") == 0 && 8912118f387SNathan Whitehorn items[2].text[0] != '/') { 8922118f387SNathan Whitehorn dialog_vars.defaultno = TRUE; 8932118f387SNathan Whitehorn choice = dialog_yesno("Warning", 8942118f387SNathan Whitehorn "This partition does not have a valid mountpoint " 8952118f387SNathan Whitehorn "(for the partition from which you intend to boot the " 8962118f387SNathan Whitehorn "operating system, the mountpoint should be /). Are you " 8972118f387SNathan Whitehorn "sure you want to continue?" 8982118f387SNathan Whitehorn , 0, 0); 8992118f387SNathan Whitehorn dialog_vars.defaultno = FALSE; 9002118f387SNathan Whitehorn if (choice == 1) /* cancel */ 9012118f387SNathan Whitehorn goto addpartform; 9022118f387SNathan Whitehorn } 9032118f387SNathan Whitehorn 9042118f387SNathan Whitehorn /* If this is the root partition, check that this scheme is bootable */ 9052118f387SNathan Whitehorn if (strcmp(items[2].text, "/") == 0 && !is_scheme_bootable(scheme)) { 9062118f387SNathan Whitehorn char message[512]; 9072118f387SNathan Whitehorn sprintf(message, "This partition scheme (%s) is not bootable " 9082118f387SNathan Whitehorn "on this platform. Are you sure you want to proceed?", 9092118f387SNathan Whitehorn scheme); 9102118f387SNathan Whitehorn dialog_vars.defaultno = TRUE; 9112118f387SNathan Whitehorn choice = dialog_yesno("Warning", message, 0, 0); 9122118f387SNathan Whitehorn dialog_vars.defaultno = FALSE; 9132118f387SNathan Whitehorn if (choice == 1) /* cancel */ 9142118f387SNathan Whitehorn goto addpartform; 9152118f387SNathan Whitehorn } 9162118f387SNathan Whitehorn 9172118f387SNathan Whitehorn /* 9182118f387SNathan Whitehorn * If this is the root partition, and we need a boot partition, ask 9192118f387SNathan Whitehorn * the user to add one. 9202118f387SNathan Whitehorn */ 9212118f387SNathan Whitehorn if (strcmp(items[2].text, "/") == 0 && bootpart_size(scheme) > 0) { 9222118f387SNathan Whitehorn if (interactive) 9232118f387SNathan Whitehorn choice = dialog_yesno("Boot Partition", 9242118f387SNathan Whitehorn "This partition scheme requires a boot partition " 9252118f387SNathan Whitehorn "for the disk to be bootable. Would you like to " 9262118f387SNathan Whitehorn "make one now?", 0, 0); 9272118f387SNathan Whitehorn else 9282118f387SNathan Whitehorn choice = 0; 9292118f387SNathan Whitehorn 9302118f387SNathan Whitehorn if (choice == 0) { /* yes */ 9312118f387SNathan Whitehorn r = gctl_get_handle(); 9322118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 9332118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, geom->lg_name); 9342118f387SNathan Whitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 9352118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "add"); 9362118f387SNathan Whitehorn gctl_ro_param(r, "type", -1, "freebsd-boot"); 9372118f387SNathan Whitehorn snprintf(sizestr, sizeof(sizestr), "%jd", 9382118f387SNathan Whitehorn bootpart_size(scheme) / sector); 9392118f387SNathan Whitehorn gctl_ro_param(r, "size", -1, sizestr); 9402118f387SNathan Whitehorn snprintf(startstr, sizeof(startstr), "%jd", firstfree); 9412118f387SNathan Whitehorn gctl_ro_param(r, "start", -1, startstr); 9422118f387SNathan Whitehorn gctl_rw_param(r, "output", sizeof(output), output); 9432118f387SNathan Whitehorn errstr = gctl_issue(r); 9442118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') 9452118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 9462118f387SNathan Whitehorn gctl_free(r); 9472118f387SNathan Whitehorn 9482118f387SNathan Whitehorn get_part_metadata(strtok(output, " "), 1)->bootcode = 1; 9492118f387SNathan Whitehorn 9502118f387SNathan Whitehorn /* Now adjust the part we are really adding forward */ 9512118f387SNathan Whitehorn firstfree += bootpart_size(scheme) / sector; 9522118f387SNathan Whitehorn size -= (bootpart_size(scheme) + stripe)/sector; 9532118f387SNathan Whitehorn if (stripe > 0 && (firstfree*sector % stripe) != 0) 9542118f387SNathan Whitehorn firstfree += (stripe - ((firstfree*sector) % 9552118f387SNathan Whitehorn stripe)) / sector; 9562118f387SNathan Whitehorn } 9572118f387SNathan Whitehorn } 9582118f387SNathan Whitehorn 9592118f387SNathan Whitehorn r = gctl_get_handle(); 9602118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 9612118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, geom->lg_name); 9622118f387SNathan Whitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 9632118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "add"); 9642118f387SNathan Whitehorn 9652118f387SNathan Whitehorn gctl_ro_param(r, "type", -1, items[0].text); 9662118f387SNathan Whitehorn snprintf(sizestr, sizeof(sizestr), "%jd", size); 9672118f387SNathan Whitehorn gctl_ro_param(r, "size", -1, sizestr); 9682118f387SNathan Whitehorn snprintf(startstr, sizeof(startstr), "%jd", firstfree); 9692118f387SNathan Whitehorn gctl_ro_param(r, "start", -1, startstr); 9702118f387SNathan Whitehorn if (items[3].text[0] != '\0') 9712118f387SNathan Whitehorn gctl_ro_param(r, "label", -1, items[3].text); 9722118f387SNathan Whitehorn gctl_rw_param(r, "output", sizeof(output), output); 9732118f387SNathan Whitehorn 9742118f387SNathan Whitehorn errstr = gctl_issue(r); 9752118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') { 9762118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 9772118f387SNathan Whitehorn gctl_free(r); 9782118f387SNathan Whitehorn goto addpartform; 9792118f387SNathan Whitehorn } 9802118f387SNathan Whitehorn 9812118f387SNathan Whitehorn if (strcmp(items[0].text, "freebsd-boot") == 0) 9822118f387SNathan Whitehorn get_part_metadata(strtok(output, " "), 1)->bootcode = 1; 9832118f387SNathan Whitehorn else if (strcmp(items[0].text, "freebsd") == 0) 9842118f387SNathan Whitehorn gpart_partition(strtok(output, " "), "BSD"); 9852118f387SNathan Whitehorn else 9862118f387SNathan Whitehorn set_default_part_metadata(strtok(output, " "), scheme, 98750de5d07SNathan Whitehorn items[0].text, items[2].text, newfs); 9882118f387SNathan Whitehorn 9892118f387SNathan Whitehorn for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++) 9902118f387SNathan Whitehorn if (items[i].text_free) 9912118f387SNathan Whitehorn free(items[i].text); 9922118f387SNathan Whitehorn gctl_free(r); 9932118f387SNathan Whitehorn 9942118f387SNathan Whitehorn if (partname != NULL) 9952118f387SNathan Whitehorn *partname = strdup(strtok(output, " ")); 9962118f387SNathan Whitehorn } 9972118f387SNathan Whitehorn 9982118f387SNathan Whitehorn void 9992118f387SNathan Whitehorn gpart_delete(struct gprovider *pp) 10002118f387SNathan Whitehorn { 10012118f387SNathan Whitehorn struct gconfig *gc; 10022118f387SNathan Whitehorn struct ggeom *geom; 10032118f387SNathan Whitehorn struct gconsumer *cp; 10042118f387SNathan Whitehorn struct gctl_req *r; 10052118f387SNathan Whitehorn const char *errstr; 10062118f387SNathan Whitehorn intmax_t idx; 10072118f387SNathan Whitehorn int choice, is_partition; 10082118f387SNathan Whitehorn 10092118f387SNathan Whitehorn /* Is it a partition? */ 10102118f387SNathan Whitehorn is_partition = (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0); 10112118f387SNathan Whitehorn 10122118f387SNathan Whitehorn /* Find out if this is the root of a gpart geom */ 10132118f387SNathan Whitehorn geom = NULL; 10142118f387SNathan Whitehorn LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 10152118f387SNathan Whitehorn if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 10162118f387SNathan Whitehorn geom = cp->lg_geom; 10172118f387SNathan Whitehorn break; 10182118f387SNathan Whitehorn } 10192118f387SNathan Whitehorn 10202118f387SNathan Whitehorn /* Destroy all consumers */ 10212118f387SNathan Whitehorn if (geom != NULL) { 10222118f387SNathan Whitehorn if (is_partition) { 10232118f387SNathan Whitehorn char message[512]; 10242118f387SNathan Whitehorn /* 10252118f387SNathan Whitehorn * We have to actually really delete the sub-partition 10262118f387SNathan Whitehorn * tree so that the consumers will go away and the 10272118f387SNathan Whitehorn * partition can be deleted. Warn the user. 10282118f387SNathan Whitehorn */ 10292118f387SNathan Whitehorn 10302118f387SNathan Whitehorn sprintf(message, "Deleting this partition (%s) " 10312118f387SNathan Whitehorn "requires deleting all existing sub-partitions. " 10322118f387SNathan Whitehorn "This will PERMANENTLY ERASE any data stored here " 10332118f387SNathan Whitehorn "and CANNOT BE REVERTED. Are you sure you want to " 10342118f387SNathan Whitehorn "proceed?", cp->lg_geom->lg_name); 10352118f387SNathan Whitehorn dialog_vars.defaultno = TRUE; 10362118f387SNathan Whitehorn choice = dialog_yesno("Warning", message, 0, 0); 10372118f387SNathan Whitehorn dialog_vars.defaultno = FALSE; 10382118f387SNathan Whitehorn 10392118f387SNathan Whitehorn if (choice == 1) /* cancel */ 10402118f387SNathan Whitehorn return; 10412118f387SNathan Whitehorn } 10422118f387SNathan Whitehorn 10432118f387SNathan Whitehorn gpart_destroy(geom, is_partition); 10442118f387SNathan Whitehorn } 10452118f387SNathan Whitehorn 10462118f387SNathan Whitehorn /* 10472118f387SNathan Whitehorn * If this is not a partition, see if that is a problem, complain if 10482118f387SNathan Whitehorn * necessary, and return always, since we need not do anything further, 10492118f387SNathan Whitehorn * error or no. 10502118f387SNathan Whitehorn */ 10512118f387SNathan Whitehorn if (!is_partition) { 10522118f387SNathan Whitehorn if (geom == NULL) 10532118f387SNathan Whitehorn dialog_msgbox("Error", 10542118f387SNathan Whitehorn "Only partitions can be deleted.", 0, 0, TRUE); 10552118f387SNathan Whitehorn return; 10562118f387SNathan Whitehorn } 10572118f387SNathan Whitehorn 10582118f387SNathan Whitehorn r = gctl_get_handle(); 10592118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, pp->lg_geom->lg_class->lg_name); 10602118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name); 10612118f387SNathan Whitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 10622118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "delete"); 10632118f387SNathan Whitehorn 10642118f387SNathan Whitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 10652118f387SNathan Whitehorn if (strcmp(gc->lg_name, "index") == 0) { 10662118f387SNathan Whitehorn idx = atoi(gc->lg_val); 10672118f387SNathan Whitehorn gctl_ro_param(r, "index", sizeof(idx), &idx); 10682118f387SNathan Whitehorn break; 10692118f387SNathan Whitehorn } 10702118f387SNathan Whitehorn } 10712118f387SNathan Whitehorn 10722118f387SNathan Whitehorn errstr = gctl_issue(r); 10732118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') { 10742118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 10752118f387SNathan Whitehorn gctl_free(r); 10762118f387SNathan Whitehorn return; 10772118f387SNathan Whitehorn } 10782118f387SNathan Whitehorn 10792118f387SNathan Whitehorn gctl_free(r); 10802118f387SNathan Whitehorn 10812118f387SNathan Whitehorn delete_part_metadata(pp->lg_name); 10822118f387SNathan Whitehorn } 10832118f387SNathan Whitehorn 10842118f387SNathan Whitehorn void 10852118f387SNathan Whitehorn gpart_revert_all(struct gmesh *mesh) 10862118f387SNathan Whitehorn { 10872118f387SNathan Whitehorn struct gclass *classp; 10882118f387SNathan Whitehorn struct gconfig *gc; 10892118f387SNathan Whitehorn struct ggeom *gp; 10902118f387SNathan Whitehorn struct gctl_req *r; 10912118f387SNathan Whitehorn const char *errstr; 10922118f387SNathan Whitehorn const char *modified; 10932118f387SNathan Whitehorn 10942118f387SNathan Whitehorn LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 10952118f387SNathan Whitehorn if (strcmp(classp->lg_name, "PART") == 0) 10962118f387SNathan Whitehorn break; 10972118f387SNathan Whitehorn } 10982118f387SNathan Whitehorn 10992118f387SNathan Whitehorn if (strcmp(classp->lg_name, "PART") != 0) { 11002118f387SNathan Whitehorn dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE); 11012118f387SNathan Whitehorn return; 11022118f387SNathan Whitehorn } 11032118f387SNathan Whitehorn 11042118f387SNathan Whitehorn LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 11052118f387SNathan Whitehorn modified = "true"; /* XXX: If we don't know (kernel too old), 11062118f387SNathan Whitehorn * assume there are modifications. */ 11072118f387SNathan Whitehorn LIST_FOREACH(gc, &gp->lg_config, lg_config) { 11082118f387SNathan Whitehorn if (strcmp(gc->lg_name, "modified") == 0) { 11092118f387SNathan Whitehorn modified = gc->lg_val; 11102118f387SNathan Whitehorn break; 11112118f387SNathan Whitehorn } 11122118f387SNathan Whitehorn } 11132118f387SNathan Whitehorn 11142118f387SNathan Whitehorn if (strcmp(modified, "false") == 0) 11152118f387SNathan Whitehorn continue; 11162118f387SNathan Whitehorn 11172118f387SNathan Whitehorn r = gctl_get_handle(); 11182118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 11192118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, gp->lg_name); 11202118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "undo"); 11212118f387SNathan Whitehorn 11222118f387SNathan Whitehorn errstr = gctl_issue(r); 11232118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') 11242118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 11252118f387SNathan Whitehorn gctl_free(r); 11262118f387SNathan Whitehorn } 11272118f387SNathan Whitehorn } 11282118f387SNathan Whitehorn 11292118f387SNathan Whitehorn void 11302118f387SNathan Whitehorn gpart_commit(struct gmesh *mesh) 11312118f387SNathan Whitehorn { 11322118f387SNathan Whitehorn struct partition_metadata *md; 11332118f387SNathan Whitehorn struct gclass *classp; 11342118f387SNathan Whitehorn struct ggeom *gp; 11352118f387SNathan Whitehorn struct gconfig *gc; 11362118f387SNathan Whitehorn struct gconsumer *cp; 11372118f387SNathan Whitehorn struct gprovider *pp; 11382118f387SNathan Whitehorn struct gctl_req *r; 11392118f387SNathan Whitehorn const char *errstr; 11402118f387SNathan Whitehorn const char *modified; 11412118f387SNathan Whitehorn 11422118f387SNathan Whitehorn LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 11432118f387SNathan Whitehorn if (strcmp(classp->lg_name, "PART") == 0) 11442118f387SNathan Whitehorn break; 11452118f387SNathan Whitehorn } 11462118f387SNathan Whitehorn 11472118f387SNathan Whitehorn if (strcmp(classp->lg_name, "PART") != 0) { 11482118f387SNathan Whitehorn dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE); 11492118f387SNathan Whitehorn return; 11502118f387SNathan Whitehorn } 11512118f387SNathan Whitehorn 11522118f387SNathan Whitehorn LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 11532118f387SNathan Whitehorn modified = "true"; /* XXX: If we don't know (kernel too old), 11542118f387SNathan Whitehorn * assume there are modifications. */ 11552118f387SNathan Whitehorn LIST_FOREACH(gc, &gp->lg_config, lg_config) { 11562118f387SNathan Whitehorn if (strcmp(gc->lg_name, "modified") == 0) { 11572118f387SNathan Whitehorn modified = gc->lg_val; 11582118f387SNathan Whitehorn break; 11592118f387SNathan Whitehorn } 11602118f387SNathan Whitehorn } 11612118f387SNathan Whitehorn 11622118f387SNathan Whitehorn if (strcmp(modified, "false") == 0) 11632118f387SNathan Whitehorn continue; 11642118f387SNathan Whitehorn 11652118f387SNathan Whitehorn /* Add bootcode if necessary, before the commit */ 11662118f387SNathan Whitehorn md = get_part_metadata(gp->lg_name, 0); 11672118f387SNathan Whitehorn if (md != NULL && md->bootcode) 11682118f387SNathan Whitehorn gpart_bootcode(gp); 11692118f387SNathan Whitehorn 11702118f387SNathan Whitehorn /* Now install partcode on its partitions, if necessary */ 11712118f387SNathan Whitehorn LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 11722118f387SNathan Whitehorn md = get_part_metadata(pp->lg_name, 0); 11732118f387SNathan Whitehorn if (md == NULL || !md->bootcode) 11742118f387SNathan Whitehorn continue; 11752118f387SNathan Whitehorn 11762118f387SNathan Whitehorn /* Mark this partition active if that's required */ 11772118f387SNathan Whitehorn gpart_activate(pp); 11782118f387SNathan Whitehorn 11792118f387SNathan Whitehorn /* Check if the partition has sub-partitions */ 11802118f387SNathan Whitehorn LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 11812118f387SNathan Whitehorn if (strcmp(cp->lg_geom->lg_class->lg_name, 11822118f387SNathan Whitehorn "PART") == 0) 11832118f387SNathan Whitehorn break; 11842118f387SNathan Whitehorn 11852118f387SNathan Whitehorn if (cp == NULL) /* No sub-partitions */ 11862118f387SNathan Whitehorn gpart_partcode(pp); 11872118f387SNathan Whitehorn } 11882118f387SNathan Whitehorn 11892118f387SNathan Whitehorn r = gctl_get_handle(); 11902118f387SNathan Whitehorn gctl_ro_param(r, "class", -1, "PART"); 11912118f387SNathan Whitehorn gctl_ro_param(r, "arg0", -1, gp->lg_name); 11922118f387SNathan Whitehorn gctl_ro_param(r, "verb", -1, "commit"); 11932118f387SNathan Whitehorn 11942118f387SNathan Whitehorn errstr = gctl_issue(r); 11952118f387SNathan Whitehorn if (errstr != NULL && errstr[0] != '\0') 11962118f387SNathan Whitehorn gpart_show_error("Error", NULL, errstr); 11972118f387SNathan Whitehorn gctl_free(r); 11982118f387SNathan Whitehorn } 11992118f387SNathan Whitehorn } 12002118f387SNathan Whitehorn 1201