1218799Snwhitehorn/*- 2218799Snwhitehorn * Copyright (c) 2011 Nathan Whitehorn 3218799Snwhitehorn * All rights reserved. 4218799Snwhitehorn * 5218799Snwhitehorn * Redistribution and use in source and binary forms, with or without 6218799Snwhitehorn * modification, are permitted provided that the following conditions 7218799Snwhitehorn * are met: 8218799Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9218799Snwhitehorn * notice, this list of conditions and the following disclaimer. 10218799Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11218799Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12218799Snwhitehorn * documentation and/or other materials provided with the distribution. 13218799Snwhitehorn * 14218799Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15218799Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16218799Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17218799Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18218799Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19218799Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20218799Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21218799Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22218799Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23218799Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24218799Snwhitehorn * SUCH DAMAGE. 25218799Snwhitehorn * 26218799Snwhitehorn * $FreeBSD: releng/10.3/usr.sbin/bsdinstall/partedit/gpart_ops.c 285769 2015-07-21 21:12:28Z allanjude $ 27218799Snwhitehorn */ 28218799Snwhitehorn 29218799Snwhitehorn#include <sys/param.h> 30273831Snwhitehorn#include <sys/stat.h> 31218799Snwhitehorn#include <errno.h> 32218799Snwhitehorn#include <libutil.h> 33218799Snwhitehorn#include <inttypes.h> 34218799Snwhitehorn 35218799Snwhitehorn#include <libgeom.h> 36218799Snwhitehorn#include <dialog.h> 37218799Snwhitehorn#include <dlg_keys.h> 38218799Snwhitehorn 39218799Snwhitehorn#include "partedit.h" 40218799Snwhitehorn 41218799Snwhitehorn#define GPART_FLAGS "x" /* Do not commit changes by default */ 42218799Snwhitehorn 43218799Snwhitehornstatic void 44218799Snwhitehorngpart_show_error(const char *title, const char *explanation, const char *errstr) 45218799Snwhitehorn{ 46218799Snwhitehorn char *errmsg; 47218799Snwhitehorn char message[512]; 48218799Snwhitehorn int error; 49218799Snwhitehorn 50218799Snwhitehorn if (explanation == NULL) 51218799Snwhitehorn explanation = ""; 52218799Snwhitehorn 53218799Snwhitehorn error = strtol(errstr, &errmsg, 0); 54218799Snwhitehorn if (errmsg != errstr) { 55218799Snwhitehorn while (errmsg[0] == ' ') 56218799Snwhitehorn errmsg++; 57218799Snwhitehorn if (errmsg[0] != '\0') 58218799Snwhitehorn sprintf(message, "%s%s. %s", explanation, 59218799Snwhitehorn strerror(error), errmsg); 60218799Snwhitehorn else 61218799Snwhitehorn sprintf(message, "%s%s", explanation, strerror(error)); 62218799Snwhitehorn } else { 63218799Snwhitehorn sprintf(message, "%s%s", explanation, errmsg); 64218799Snwhitehorn } 65218799Snwhitehorn 66218799Snwhitehorn dialog_msgbox(title, message, 0, 0, TRUE); 67218799Snwhitehorn} 68218799Snwhitehorn 69218853Snwhitehornstatic int 70218853Snwhitehornscheme_supports_labels(const char *scheme) 71218853Snwhitehorn{ 72218853Snwhitehorn if (strcmp(scheme, "APM") == 0) 73218853Snwhitehorn return (1); 74218853Snwhitehorn if (strcmp(scheme, "GPT") == 0) 75218853Snwhitehorn return (1); 76218853Snwhitehorn if (strcmp(scheme, "PC98") == 0) 77218853Snwhitehorn return (1); 78218853Snwhitehorn 79218853Snwhitehorn return (0); 80218853Snwhitehorn} 81218853Snwhitehorn 82219892Snwhitehornstatic void 83219892Snwhitehornnewfs_command(const char *fstype, char *command, int use_default) 84219892Snwhitehorn{ 85219892Snwhitehorn if (strcmp(fstype, "freebsd-ufs") == 0) { 86219892Snwhitehorn int i; 87219892Snwhitehorn DIALOG_LISTITEM items[] = { 88219892Snwhitehorn {"UFS1", "UFS Version 1", 89219892Snwhitehorn "Use version 1 of the UFS file system instead " 90219892Snwhitehorn "of version 2 (not recommended)", 0 }, 91219892Snwhitehorn {"SU", "Softupdates", 92219892Snwhitehorn "Enable softupdates (default)", 1 }, 93219892Snwhitehorn {"SUJ", "Softupdates journaling", 94219892Snwhitehorn "Enable file system journaling (default - " 95219892Snwhitehorn "turn off for SSDs)", 1 }, 96219892Snwhitehorn {"TRIM", "Enable SSD TRIM support", 97219892Snwhitehorn "Enable TRIM support, useful on solid-state drives", 98219892Snwhitehorn 0 }, 99219892Snwhitehorn }; 100219892Snwhitehorn 101219892Snwhitehorn if (!use_default) { 102219892Snwhitehorn int choice; 103219892Snwhitehorn choice = dlg_checklist("UFS Options", "", 0, 0, 0, 104219892Snwhitehorn sizeof(items)/sizeof(items[0]), items, NULL, 105219892Snwhitehorn FLAG_CHECK, &i); 106219892Snwhitehorn if (choice == 1) /* Cancel */ 107219892Snwhitehorn return; 108219892Snwhitehorn } 109219892Snwhitehorn 110219892Snwhitehorn strcpy(command, "newfs "); 111219892Snwhitehorn for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) { 112219892Snwhitehorn if (items[i].state == 0) 113219892Snwhitehorn continue; 114219892Snwhitehorn if (strcmp(items[i].name, "UFS1") == 0) 115219892Snwhitehorn strcat(command, "-O1 "); 116219892Snwhitehorn else if (strcmp(items[i].name, "SU") == 0) 117219892Snwhitehorn strcat(command, "-U "); 118219892Snwhitehorn else if (strcmp(items[i].name, "SUJ") == 0) 119219892Snwhitehorn strcat(command, "-j "); 120219892Snwhitehorn else if (strcmp(items[i].name, "TRIM") == 0) 121219892Snwhitehorn strcat(command, "-t "); 122219892Snwhitehorn } 123273831Snwhitehorn } else if (strcmp(fstype, "freebsd-zfs") == 0) { 124273831Snwhitehorn int i; 125273831Snwhitehorn DIALOG_LISTITEM items[] = { 126273831Snwhitehorn {"fletcher4", "checksum algorithm: fletcher4", 127273831Snwhitehorn "Use fletcher4 for data integrity checking. " 128273831Snwhitehorn "(default)", 1 }, 129273831Snwhitehorn {"fletcher2", "checksum algorithm: fletcher2", 130273831Snwhitehorn "Use fletcher2 for data integrity checking. " 131273831Snwhitehorn "(not recommended)", 0 }, 132273831Snwhitehorn {"sha256", "checksum algorithm: sha256", 133273831Snwhitehorn "Use sha256 for data integrity checking. " 134273831Snwhitehorn "(not recommended)", 0 }, 135273831Snwhitehorn {"atime", "Update atimes for files", 136273831Snwhitehorn "Disable atime update", 0 }, 137273831Snwhitehorn }; 138273831Snwhitehorn 139273831Snwhitehorn if (!use_default) { 140273831Snwhitehorn int choice; 141273831Snwhitehorn choice = dlg_checklist("ZFS Options", "", 0, 0, 0, 142273831Snwhitehorn sizeof(items)/sizeof(items[0]), items, NULL, 143273831Snwhitehorn FLAG_CHECK, &i); 144273831Snwhitehorn if (choice == 1) /* Cancel */ 145273831Snwhitehorn return; 146273831Snwhitehorn } 147273831Snwhitehorn 148273831Snwhitehorn strcpy(command, "zpool create -f -m none "); 149273831Snwhitehorn if (getenv("BSDINSTALL_TMPBOOT") != NULL) { 150273831Snwhitehorn char zfsboot_path[MAXPATHLEN]; 151273831Snwhitehorn sprintf(zfsboot_path, "%s/zfs", 152273831Snwhitehorn getenv("BSDINSTALL_TMPBOOT")); 153273831Snwhitehorn mkdir(zfsboot_path, S_IRWXU | S_IRGRP | S_IXGRP | 154273831Snwhitehorn S_IROTH | S_IXOTH); 155273831Snwhitehorn sprintf(command, "%s -o cachefile=%s/zpool.cache ", 156273831Snwhitehorn command, zfsboot_path); 157273831Snwhitehorn } 158273831Snwhitehorn for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) { 159273831Snwhitehorn if (items[i].state == 0) 160273831Snwhitehorn continue; 161273831Snwhitehorn if (strcmp(items[i].name, "fletcher4") == 0) 162273831Snwhitehorn strcat(command, "-O checksum=fletcher4 "); 163273831Snwhitehorn else if (strcmp(items[i].name, "fletcher2") == 0) 164273831Snwhitehorn strcat(command, "-O checksum=fletcher2 "); 165273831Snwhitehorn else if (strcmp(items[i].name, "sha256") == 0) 166273831Snwhitehorn strcat(command, "-O checksum=sha256 "); 167273831Snwhitehorn else if (strcmp(items[i].name, "atime") == 0) 168273831Snwhitehorn strcat(command, "-O atime=off "); 169273831Snwhitehorn } 170219892Snwhitehorn } else if (strcmp(fstype, "fat32") == 0 || strcmp(fstype, "efi") == 0) { 171219892Snwhitehorn int i; 172219892Snwhitehorn DIALOG_LISTITEM items[] = { 173219892Snwhitehorn {"FAT32", "FAT Type 32", 174219892Snwhitehorn "Create a FAT32 filesystem (default)", 1 }, 175219892Snwhitehorn {"FAT16", "FAT Type 16", 176219892Snwhitehorn "Create a FAT16 filesystem", 0 }, 177219892Snwhitehorn {"FAT12", "FAT Type 12", 178219892Snwhitehorn "Create a FAT12 filesystem", 0 }, 179219892Snwhitehorn }; 180219892Snwhitehorn 181219892Snwhitehorn if (!use_default) { 182219892Snwhitehorn int choice; 183219892Snwhitehorn choice = dlg_checklist("FAT Options", "", 0, 0, 0, 184219892Snwhitehorn sizeof(items)/sizeof(items[0]), items, NULL, 185219892Snwhitehorn FLAG_RADIO, &i); 186219892Snwhitehorn if (choice == 1) /* Cancel */ 187219892Snwhitehorn return; 188219892Snwhitehorn } 189219892Snwhitehorn 190219892Snwhitehorn strcpy(command, "newfs_msdos "); 191219892Snwhitehorn for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) { 192219892Snwhitehorn if (items[i].state == 0) 193219892Snwhitehorn continue; 194219892Snwhitehorn if (strcmp(items[i].name, "FAT32") == 0) 195219892Snwhitehorn strcat(command, "-F 32 "); 196219892Snwhitehorn else if (strcmp(items[i].name, "FAT16") == 0) 197219892Snwhitehorn strcat(command, "-F 16 "); 198233904Snwhitehorn else if (strcmp(items[i].name, "FAT12") == 0) 199219892Snwhitehorn strcat(command, "-F 12 "); 200219892Snwhitehorn } 201219892Snwhitehorn } else { 202219892Snwhitehorn if (!use_default) 203219892Snwhitehorn dialog_msgbox("Error", "No configurable options exist " 204219892Snwhitehorn "for this filesystem.", 0, 0, TRUE); 205219892Snwhitehorn command[0] = '\0'; 206219892Snwhitehorn } 207219892Snwhitehorn} 208219892Snwhitehorn 209285769Sallanjudeconst char * 210285769Sallanjudechoose_part_type(const char *def_scheme) 211218799Snwhitehorn{ 212218799Snwhitehorn int cancel, choice; 213285769Sallanjude const char *scheme = NULL; 214218799Snwhitehorn 215218799Snwhitehorn DIALOG_LISTITEM items[] = { 216218799Snwhitehorn {"APM", "Apple Partition Map", 217218799Snwhitehorn "Bootable on PowerPC Apple Hardware", 0 }, 218218799Snwhitehorn {"BSD", "BSD Labels", 219218799Snwhitehorn "Bootable on most x86 systems", 0 }, 220218799Snwhitehorn {"GPT", "GUID Partition Table", 221218799Snwhitehorn "Bootable on most x86 systems", 0 }, 222218799Snwhitehorn {"MBR", "DOS Partitions", 223218799Snwhitehorn "Bootable on most x86 systems", 0 }, 224218799Snwhitehorn {"PC98", "NEC PC9801 Partition Table", 225218799Snwhitehorn "Bootable on NEC PC9801 systems", 0 }, 226218799Snwhitehorn {"VTOC8", "Sun VTOC8 Partition Table", 227218799Snwhitehorn "Bootable on Sun SPARC systems", 0 }, 228218799Snwhitehorn }; 229218799Snwhitehorn 230285769Sallanjudeparttypemenu: 231285769Sallanjude dialog_vars.default_item = __DECONST(char *, def_scheme); 232285769Sallanjude cancel = dlg_menu("Partition Scheme", 233285769Sallanjude "Select a partition scheme for this volume:", 0, 0, 0, 234285769Sallanjude sizeof(items) / sizeof(items[0]), items, &choice, NULL); 235285769Sallanjude dialog_vars.default_item = NULL; 236285769Sallanjude 237285769Sallanjude if (cancel) 238285769Sallanjude return NULL; 239285769Sallanjude 240285769Sallanjude if (!is_scheme_bootable(items[choice].name)) { 241285769Sallanjude char message[512]; 242285769Sallanjude sprintf(message, "This partition scheme (%s) is not " 243285769Sallanjude "bootable on this platform. Are you sure you want " 244285769Sallanjude "to proceed?", items[choice].name); 245285769Sallanjude dialog_vars.defaultno = TRUE; 246285769Sallanjude cancel = dialog_yesno("Warning", message, 0, 0); 247285769Sallanjude dialog_vars.defaultno = FALSE; 248285769Sallanjude if (cancel) /* cancel */ 249285769Sallanjude goto parttypemenu; 250285769Sallanjude } 251285769Sallanjude 252285769Sallanjude scheme = items[choice].name; 253285769Sallanjude 254285769Sallanjude return scheme; 255285769Sallanjude} 256285769Sallanjude 257285769Sallanjudeint 258285769Sallanjudegpart_partition(const char *lg_name, const char *scheme) 259285769Sallanjude{ 260285769Sallanjude int cancel; 261285769Sallanjude struct gctl_req *r; 262285769Sallanjude const char *errstr; 263285769Sallanjude 264218799Snwhitehornschememenu: 265218799Snwhitehorn if (scheme == NULL) { 266285769Sallanjude scheme = choose_part_type(default_scheme()); 267218799Snwhitehorn 268285769Sallanjude if (scheme == NULL) 269218799Snwhitehorn return (-1); 270218799Snwhitehorn 271285769Sallanjude if (!is_scheme_bootable(scheme)) { 272218799Snwhitehorn char message[512]; 273218799Snwhitehorn sprintf(message, "This partition scheme (%s) is not " 274218799Snwhitehorn "bootable on this platform. Are you sure you want " 275285769Sallanjude "to proceed?", scheme); 276218799Snwhitehorn dialog_vars.defaultno = TRUE; 277218799Snwhitehorn cancel = dialog_yesno("Warning", message, 0, 0); 278218799Snwhitehorn dialog_vars.defaultno = FALSE; 279285769Sallanjude if (cancel) { /* cancel */ 280285769Sallanjude /* Reset scheme so user can choose another */ 281285769Sallanjude scheme = NULL; 282218799Snwhitehorn goto schememenu; 283285769Sallanjude } 284218799Snwhitehorn } 285218799Snwhitehorn } 286218799Snwhitehorn 287218799Snwhitehorn r = gctl_get_handle(); 288218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 289218799Snwhitehorn gctl_ro_param(r, "arg0", -1, lg_name); 290218799Snwhitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 291218799Snwhitehorn gctl_ro_param(r, "scheme", -1, scheme); 292218799Snwhitehorn gctl_ro_param(r, "verb", -1, "create"); 293218799Snwhitehorn 294218799Snwhitehorn errstr = gctl_issue(r); 295218799Snwhitehorn if (errstr != NULL && errstr[0] != '\0') { 296218799Snwhitehorn gpart_show_error("Error", NULL, errstr); 297218799Snwhitehorn gctl_free(r); 298218799Snwhitehorn scheme = NULL; 299218799Snwhitehorn goto schememenu; 300218799Snwhitehorn } 301218799Snwhitehorn gctl_free(r); 302218799Snwhitehorn 303218799Snwhitehorn if (bootcode_path(scheme) != NULL) 304218799Snwhitehorn get_part_metadata(lg_name, 1)->bootcode = 1; 305218799Snwhitehorn return (0); 306218799Snwhitehorn} 307218799Snwhitehorn 308218799Snwhitehornstatic void 309218799Snwhitehorngpart_activate(struct gprovider *pp) 310218799Snwhitehorn{ 311218799Snwhitehorn struct gconfig *gc; 312218799Snwhitehorn struct gctl_req *r; 313218799Snwhitehorn const char *errstr, *scheme; 314218799Snwhitehorn const char *attribute = NULL; 315218799Snwhitehorn intmax_t idx; 316218799Snwhitehorn 317218799Snwhitehorn /* 318218799Snwhitehorn * Some partition schemes need this partition to be marked 'active' 319218799Snwhitehorn * for it to be bootable. 320218799Snwhitehorn */ 321218799Snwhitehorn LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) { 322218799Snwhitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 323218799Snwhitehorn scheme = gc->lg_val; 324218799Snwhitehorn break; 325218799Snwhitehorn } 326218799Snwhitehorn } 327218799Snwhitehorn 328218799Snwhitehorn if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "EBR") == 0 || 329218799Snwhitehorn strcmp(scheme, "PC98") == 0) 330218799Snwhitehorn attribute = "active"; 331218799Snwhitehorn else 332218799Snwhitehorn return; 333218799Snwhitehorn 334218799Snwhitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 335218799Snwhitehorn if (strcmp(gc->lg_name, "index") == 0) { 336218799Snwhitehorn idx = atoi(gc->lg_val); 337218799Snwhitehorn break; 338218799Snwhitehorn } 339218799Snwhitehorn } 340218799Snwhitehorn 341218799Snwhitehorn r = gctl_get_handle(); 342218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 343218799Snwhitehorn gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name); 344218799Snwhitehorn gctl_ro_param(r, "verb", -1, "set"); 345218799Snwhitehorn gctl_ro_param(r, "attrib", -1, attribute); 346218799Snwhitehorn gctl_ro_param(r, "index", sizeof(idx), &idx); 347218799Snwhitehorn 348218799Snwhitehorn errstr = gctl_issue(r); 349218799Snwhitehorn if (errstr != NULL && errstr[0] != '\0') 350218799Snwhitehorn gpart_show_error("Error", "Error marking partition active:", 351218799Snwhitehorn errstr); 352218799Snwhitehorn gctl_free(r); 353218799Snwhitehorn} 354218799Snwhitehorn 355285769Sallanjudevoid 356285769Sallanjudegpart_set_root(const char *lg_name, const char *attribute) 357285769Sallanjude{ 358285769Sallanjude struct gctl_req *r; 359285769Sallanjude const char *errstr; 360285769Sallanjude 361285769Sallanjude r = gctl_get_handle(); 362285769Sallanjude gctl_ro_param(r, "class", -1, "PART"); 363285769Sallanjude gctl_ro_param(r, "arg0", -1, lg_name); 364285769Sallanjude gctl_ro_param(r, "flags", -1, "C"); 365285769Sallanjude gctl_ro_param(r, "verb", -1, "set"); 366285769Sallanjude gctl_ro_param(r, "attrib", -1, attribute); 367285769Sallanjude 368285769Sallanjude errstr = gctl_issue(r); 369285769Sallanjude if (errstr != NULL && errstr[0] != '\0') 370285769Sallanjude gpart_show_error("Error", "Error setting parameter on disk:", 371285769Sallanjude errstr); 372285769Sallanjude gctl_free(r); 373285769Sallanjude} 374285769Sallanjude 375218799Snwhitehornstatic void 376218799Snwhitehorngpart_bootcode(struct ggeom *gp) 377218799Snwhitehorn{ 378218799Snwhitehorn const char *bootcode; 379218799Snwhitehorn struct gconfig *gc; 380218799Snwhitehorn struct gctl_req *r; 381218799Snwhitehorn const char *errstr, *scheme; 382218799Snwhitehorn uint8_t *boot; 383218799Snwhitehorn size_t bootsize, bytes; 384218799Snwhitehorn int bootfd; 385218799Snwhitehorn 386218799Snwhitehorn /* 387218799Snwhitehorn * Write default bootcode to the newly partitioned disk, if that 388218799Snwhitehorn * applies on this platform. 389218799Snwhitehorn */ 390218799Snwhitehorn LIST_FOREACH(gc, &gp->lg_config, lg_config) { 391218799Snwhitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 392218799Snwhitehorn scheme = gc->lg_val; 393218799Snwhitehorn break; 394218799Snwhitehorn } 395218799Snwhitehorn } 396218799Snwhitehorn 397218799Snwhitehorn bootcode = bootcode_path(scheme); 398218799Snwhitehorn if (bootcode == NULL) 399218799Snwhitehorn return; 400218799Snwhitehorn 401218799Snwhitehorn bootfd = open(bootcode, O_RDONLY); 402228048Skevlo if (bootfd < 0) { 403218799Snwhitehorn dialog_msgbox("Bootcode Error", strerror(errno), 0, 0, 404218799Snwhitehorn TRUE); 405218799Snwhitehorn return; 406218799Snwhitehorn } 407218799Snwhitehorn 408218799Snwhitehorn bootsize = lseek(bootfd, 0, SEEK_END); 409218799Snwhitehorn boot = malloc(bootsize); 410218799Snwhitehorn lseek(bootfd, 0, SEEK_SET); 411218799Snwhitehorn bytes = 0; 412218799Snwhitehorn while (bytes < bootsize) 413218799Snwhitehorn bytes += read(bootfd, boot + bytes, bootsize - bytes); 414218799Snwhitehorn close(bootfd); 415218799Snwhitehorn 416218799Snwhitehorn r = gctl_get_handle(); 417218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 418218799Snwhitehorn gctl_ro_param(r, "arg0", -1, gp->lg_name); 419218799Snwhitehorn gctl_ro_param(r, "verb", -1, "bootcode"); 420218799Snwhitehorn gctl_ro_param(r, "bootcode", bootsize, boot); 421218799Snwhitehorn 422218799Snwhitehorn errstr = gctl_issue(r); 423218799Snwhitehorn if (errstr != NULL && errstr[0] != '\0') 424218799Snwhitehorn gpart_show_error("Bootcode Error", NULL, errstr); 425218799Snwhitehorn gctl_free(r); 426218799Snwhitehorn free(boot); 427218799Snwhitehorn} 428218799Snwhitehorn 429218799Snwhitehornstatic void 430273831Snwhitehorngpart_partcode(struct gprovider *pp, const char *fstype) 431218799Snwhitehorn{ 432218799Snwhitehorn struct gconfig *gc; 433218799Snwhitehorn const char *scheme; 434218799Snwhitehorn const char *indexstr; 435218799Snwhitehorn char message[255], command[255]; 436218799Snwhitehorn 437218799Snwhitehorn LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) { 438218799Snwhitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 439218799Snwhitehorn scheme = gc->lg_val; 440218799Snwhitehorn break; 441218799Snwhitehorn } 442218799Snwhitehorn } 443218799Snwhitehorn 444218799Snwhitehorn /* Make sure this partition scheme needs partcode on this platform */ 445273831Snwhitehorn if (partcode_path(scheme, fstype) == NULL) 446218799Snwhitehorn return; 447218799Snwhitehorn 448218799Snwhitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 449218799Snwhitehorn if (strcmp(gc->lg_name, "index") == 0) { 450218799Snwhitehorn indexstr = gc->lg_val; 451218799Snwhitehorn break; 452218799Snwhitehorn } 453218799Snwhitehorn } 454218799Snwhitehorn 455218799Snwhitehorn /* Shell out to gpart for partcode for now */ 456218799Snwhitehorn sprintf(command, "gpart bootcode -p %s -i %s %s", 457273831Snwhitehorn partcode_path(scheme, fstype), indexstr, pp->lg_geom->lg_name); 458218799Snwhitehorn if (system(command) != 0) { 459218799Snwhitehorn sprintf(message, "Error installing partcode on partition %s", 460218799Snwhitehorn pp->lg_name); 461218799Snwhitehorn dialog_msgbox("Error", message, 0, 0, TRUE); 462218799Snwhitehorn } 463218799Snwhitehorn} 464218799Snwhitehorn 465218799Snwhitehornvoid 466226083Snwhitehorngpart_destroy(struct ggeom *lg_geom) 467218799Snwhitehorn{ 468226083Snwhitehorn struct gctl_req *r; 469218799Snwhitehorn struct gprovider *pp; 470218799Snwhitehorn const char *errstr; 471226083Snwhitehorn int force = 1; 472218799Snwhitehorn 473226083Snwhitehorn /* Delete all child metadata */ 474218799Snwhitehorn LIST_FOREACH(pp, &lg_geom->lg_provider, lg_provider) 475218799Snwhitehorn gpart_delete(pp); 476218799Snwhitehorn 477226083Snwhitehorn /* Revert any local changes to get this geom into a pristine state */ 478226083Snwhitehorn r = gctl_get_handle(); 479226083Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 480226083Snwhitehorn gctl_ro_param(r, "arg0", -1, lg_geom->lg_name); 481226083Snwhitehorn gctl_ro_param(r, "verb", -1, "undo"); 482226083Snwhitehorn gctl_issue(r); /* Ignore errors -- these are non-fatal */ 483226083Snwhitehorn gctl_free(r); 484226083Snwhitehorn 485218799Snwhitehorn /* Now destroy the geom itself */ 486218799Snwhitehorn r = gctl_get_handle(); 487218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 488218799Snwhitehorn gctl_ro_param(r, "arg0", -1, lg_geom->lg_name); 489218799Snwhitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 490226083Snwhitehorn gctl_ro_param(r, "force", sizeof(force), &force); 491218799Snwhitehorn gctl_ro_param(r, "verb", -1, "destroy"); 492218799Snwhitehorn errstr = gctl_issue(r); 493226666Snwhitehorn if (errstr != NULL && errstr[0] != '\0') { 494226666Snwhitehorn /* 495226666Snwhitehorn * Check if we reverted away the existence of the geom 496226666Snwhitehorn * altogether. Show all other errors to the user. 497226666Snwhitehorn */ 498226666Snwhitehorn if (strtol(errstr, NULL, 0) != EINVAL) 499226666Snwhitehorn gpart_show_error("Error", NULL, errstr); 500226666Snwhitehorn } 501218799Snwhitehorn gctl_free(r); 502218799Snwhitehorn 503218799Snwhitehorn /* And any metadata associated with the partition scheme itself */ 504218799Snwhitehorn delete_part_metadata(lg_geom->lg_name); 505218799Snwhitehorn} 506218799Snwhitehorn 507218799Snwhitehornvoid 508218799Snwhitehorngpart_edit(struct gprovider *pp) 509218799Snwhitehorn{ 510218799Snwhitehorn struct gctl_req *r; 511218799Snwhitehorn struct gconfig *gc; 512218799Snwhitehorn struct gconsumer *cp; 513218799Snwhitehorn struct ggeom *geom; 514218799Snwhitehorn const char *errstr, *oldtype, *scheme; 515218799Snwhitehorn struct partition_metadata *md; 516218799Snwhitehorn char sizestr[32]; 517273831Snwhitehorn char newfs[255]; 518218799Snwhitehorn intmax_t idx; 519218799Snwhitehorn int hadlabel, choice, junk, nitems; 520218799Snwhitehorn unsigned i; 521218799Snwhitehorn 522218799Snwhitehorn DIALOG_FORMITEM items[] = { 523218799Snwhitehorn {0, "Type:", 5, 0, 0, FALSE, "", 11, 0, 12, 15, 0, 524273831Snwhitehorn FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, " 525273831Snwhitehorn "freebsd-swap)", FALSE}, 526218799Snwhitehorn {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 0, 0, 527218799Snwhitehorn FALSE, "Partition size. Append K, M, G for kilobytes, " 528218799Snwhitehorn "megabytes or gigabytes.", FALSE}, 529218799Snwhitehorn {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0, 530218799Snwhitehorn FALSE, "Path at which to mount this partition (leave blank " 531218799Snwhitehorn "for swap, set to / for root filesystem)", FALSE}, 532218799Snwhitehorn {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE, 533218799Snwhitehorn "Partition name. Not all partition schemes support this.", 534218799Snwhitehorn FALSE}, 535218799Snwhitehorn }; 536218799Snwhitehorn 537218799Snwhitehorn /* 538218799Snwhitehorn * Find the PART geom we are manipulating. This may be a consumer of 539218799Snwhitehorn * this provider, or its parent. Check the consumer case first. 540218799Snwhitehorn */ 541218799Snwhitehorn geom = NULL; 542218799Snwhitehorn LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 543218799Snwhitehorn if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 544226083Snwhitehorn /* Check for zombie geoms, treating them as blank */ 545226083Snwhitehorn scheme = NULL; 546226083Snwhitehorn LIST_FOREACH(gc, &cp->lg_geom->lg_config, lg_config) { 547226083Snwhitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 548226083Snwhitehorn scheme = gc->lg_val; 549226083Snwhitehorn break; 550226083Snwhitehorn } 551226083Snwhitehorn } 552226083Snwhitehorn if (scheme == NULL || strcmp(scheme, "(none)") == 0) { 553226083Snwhitehorn gpart_partition(cp->lg_geom->lg_name, NULL); 554218799Snwhitehorn return; 555226083Snwhitehorn } 556218799Snwhitehorn 557226666Snwhitehorn /* If this is a nested partition, edit as usual */ 558226666Snwhitehorn if (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 559226666Snwhitehorn break; 560226666Snwhitehorn 561218799Snwhitehorn /* Destroy the geom and all sub-partitions */ 562226083Snwhitehorn gpart_destroy(cp->lg_geom); 563218799Snwhitehorn 564218799Snwhitehorn /* Now re-partition and return */ 565218799Snwhitehorn gpart_partition(cp->lg_geom->lg_name, NULL); 566218799Snwhitehorn return; 567218799Snwhitehorn } 568218799Snwhitehorn 569218799Snwhitehorn if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 570218799Snwhitehorn geom = pp->lg_geom; 571218799Snwhitehorn 572218799Snwhitehorn if (geom == NULL) { 573218799Snwhitehorn /* Disk not partitioned, so partition it */ 574225066Snwhitehorn gpart_partition(pp->lg_name, NULL); 575218799Snwhitehorn return; 576218799Snwhitehorn } 577218799Snwhitehorn 578218799Snwhitehorn LIST_FOREACH(gc, &geom->lg_config, lg_config) { 579218799Snwhitehorn if (strcmp(gc->lg_name, "scheme") == 0) { 580218799Snwhitehorn scheme = gc->lg_val; 581218799Snwhitehorn break; 582218799Snwhitehorn } 583218799Snwhitehorn } 584218799Snwhitehorn 585218853Snwhitehorn nitems = scheme_supports_labels(scheme) ? 4 : 3; 586218799Snwhitehorn 587218799Snwhitehorn /* Edit editable parameters of a partition */ 588218799Snwhitehorn hadlabel = 0; 589218799Snwhitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 590218799Snwhitehorn if (strcmp(gc->lg_name, "type") == 0) { 591218799Snwhitehorn oldtype = gc->lg_val; 592218799Snwhitehorn items[0].text = gc->lg_val; 593218799Snwhitehorn } 594218799Snwhitehorn if (strcmp(gc->lg_name, "label") == 0 && gc->lg_val != NULL) { 595218799Snwhitehorn hadlabel = 1; 596218799Snwhitehorn items[3].text = gc->lg_val; 597218799Snwhitehorn } 598218799Snwhitehorn if (strcmp(gc->lg_name, "index") == 0) 599218799Snwhitehorn idx = atoi(gc->lg_val); 600218799Snwhitehorn } 601218799Snwhitehorn 602218799Snwhitehorn TAILQ_FOREACH(md, &part_metadata, metadata) { 603218799Snwhitehorn if (md->name != NULL && strcmp(md->name, pp->lg_name) == 0) { 604218799Snwhitehorn if (md->fstab != NULL) 605218799Snwhitehorn items[2].text = md->fstab->fs_file; 606218799Snwhitehorn break; 607218799Snwhitehorn } 608218799Snwhitehorn } 609218799Snwhitehorn 610218799Snwhitehorn humanize_number(sizestr, 7, pp->lg_mediasize, "B", HN_AUTOSCALE, 611218799Snwhitehorn HN_NOSPACE | HN_DECIMAL); 612218799Snwhitehorn items[1].text = sizestr; 613218799Snwhitehorn 614218799Snwhitehorneditpart: 615218799Snwhitehorn choice = dlg_form("Edit Partition", "", 0, 0, 0, nitems, items, &junk); 616218799Snwhitehorn 617218799Snwhitehorn if (choice) /* Cancel pressed */ 618226666Snwhitehorn goto endedit; 619218799Snwhitehorn 620218799Snwhitehorn /* Check if the label has a / in it */ 621218799Snwhitehorn if (strchr(items[3].text, '/') != NULL) { 622218799Snwhitehorn dialog_msgbox("Error", "Label contains a /, which is not an " 623218799Snwhitehorn "allowed character.", 0, 0, TRUE); 624218799Snwhitehorn goto editpart; 625218799Snwhitehorn } 626218799Snwhitehorn 627218799Snwhitehorn r = gctl_get_handle(); 628218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 629218799Snwhitehorn gctl_ro_param(r, "arg0", -1, geom->lg_name); 630218799Snwhitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 631218799Snwhitehorn gctl_ro_param(r, "verb", -1, "modify"); 632218799Snwhitehorn gctl_ro_param(r, "index", sizeof(idx), &idx); 633218799Snwhitehorn if (hadlabel || items[3].text[0] != '\0') 634218799Snwhitehorn gctl_ro_param(r, "label", -1, items[3].text); 635218799Snwhitehorn gctl_ro_param(r, "type", -1, items[0].text); 636218799Snwhitehorn errstr = gctl_issue(r); 637218799Snwhitehorn if (errstr != NULL && errstr[0] != '\0') { 638218799Snwhitehorn gpart_show_error("Error", NULL, errstr); 639218799Snwhitehorn gctl_free(r); 640218799Snwhitehorn goto editpart; 641218799Snwhitehorn } 642218799Snwhitehorn gctl_free(r); 643218799Snwhitehorn 644219892Snwhitehorn newfs_command(items[0].text, newfs, 1); 645218799Snwhitehorn set_default_part_metadata(pp->lg_name, scheme, items[0].text, 646219892Snwhitehorn items[2].text, (strcmp(oldtype, items[0].text) != 0) ? 647219892Snwhitehorn newfs : NULL); 648218799Snwhitehorn 649226666Snwhitehornendedit: 650226666Snwhitehorn if (strcmp(oldtype, items[0].text) != 0 && cp != NULL) 651226666Snwhitehorn gpart_destroy(cp->lg_geom); 652226666Snwhitehorn if (strcmp(oldtype, items[0].text) != 0 && strcmp(items[0].text, 653226666Snwhitehorn "freebsd") == 0) 654226666Snwhitehorn gpart_partition(pp->lg_name, "BSD"); 655226666Snwhitehorn 656218799Snwhitehorn for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++) 657218799Snwhitehorn if (items[i].text_free) 658218799Snwhitehorn free(items[i].text); 659218799Snwhitehorn} 660218799Snwhitehorn 661218799Snwhitehornvoid 662218799Snwhitehornset_default_part_metadata(const char *name, const char *scheme, 663219892Snwhitehorn const char *type, const char *mountpoint, const char *newfs) 664218799Snwhitehorn{ 665218799Snwhitehorn struct partition_metadata *md; 666273831Snwhitehorn char *zpool_name = NULL; 667273831Snwhitehorn int i; 668218799Snwhitehorn 669218799Snwhitehorn /* Set part metadata */ 670218799Snwhitehorn md = get_part_metadata(name, 1); 671218799Snwhitehorn 672218799Snwhitehorn if (newfs) { 673218799Snwhitehorn if (md->newfs != NULL) { 674218799Snwhitehorn free(md->newfs); 675218799Snwhitehorn md->newfs = NULL; 676218799Snwhitehorn } 677218799Snwhitehorn 678219892Snwhitehorn if (newfs != NULL && newfs[0] != '\0') { 679219892Snwhitehorn md->newfs = malloc(strlen(newfs) + strlen(" /dev/") + 680273831Snwhitehorn strlen(mountpoint) + 5 + strlen(name) + 1); 681273831Snwhitehorn if (strcmp("freebsd-zfs", type) == 0) { 682273831Snwhitehorn zpool_name = strdup((strlen(mountpoint) == 1) ? 683273831Snwhitehorn "root" : &mountpoint[1]); 684273831Snwhitehorn for (i = 0; zpool_name[i] != 0; i++) 685273831Snwhitehorn if (!isalnum(zpool_name[i])) 686273831Snwhitehorn zpool_name[i] = '_'; 687273831Snwhitehorn sprintf(md->newfs, "%s %s /dev/%s", newfs, 688273831Snwhitehorn zpool_name, name); 689273831Snwhitehorn } else { 690273831Snwhitehorn sprintf(md->newfs, "%s /dev/%s", newfs, name); 691273831Snwhitehorn } 692218799Snwhitehorn } 693218799Snwhitehorn } 694218799Snwhitehorn 695218799Snwhitehorn if (strcmp(type, "freebsd-swap") == 0) 696218799Snwhitehorn mountpoint = "none"; 697271636Semaste if (strcmp(type, bootpart_type(scheme)) == 0) 698218799Snwhitehorn md->bootcode = 1; 699218799Snwhitehorn 700273831Snwhitehorn /* VTOC8 needs partcode at the start of partitions */ 701273831Snwhitehorn if (strcmp(scheme, "VTOC8") == 0 && (strcmp(type, "freebsd-ufs") == 0 702273831Snwhitehorn || strcmp(type, "freebsd-zfs") == 0)) 703218799Snwhitehorn md->bootcode = 1; 704218799Snwhitehorn 705218799Snwhitehorn if (mountpoint == NULL || mountpoint[0] == '\0') { 706218799Snwhitehorn if (md->fstab != NULL) { 707218799Snwhitehorn free(md->fstab->fs_spec); 708218799Snwhitehorn free(md->fstab->fs_file); 709218799Snwhitehorn free(md->fstab->fs_vfstype); 710218799Snwhitehorn free(md->fstab->fs_mntops); 711218799Snwhitehorn free(md->fstab->fs_type); 712218799Snwhitehorn free(md->fstab); 713218799Snwhitehorn md->fstab = NULL; 714218799Snwhitehorn } 715218799Snwhitehorn } else { 716218799Snwhitehorn if (md->fstab == NULL) { 717218799Snwhitehorn md->fstab = malloc(sizeof(struct fstab)); 718218799Snwhitehorn } else { 719218799Snwhitehorn free(md->fstab->fs_spec); 720218799Snwhitehorn free(md->fstab->fs_file); 721218799Snwhitehorn free(md->fstab->fs_vfstype); 722218799Snwhitehorn free(md->fstab->fs_mntops); 723218799Snwhitehorn free(md->fstab->fs_type); 724218799Snwhitehorn } 725273831Snwhitehorn if (strcmp("freebsd-zfs", type) == 0) { 726273831Snwhitehorn md->fstab->fs_spec = strdup(zpool_name); 727273831Snwhitehorn } else { 728273831Snwhitehorn md->fstab->fs_spec = malloc(strlen(name) + 729273831Snwhitehorn strlen("/dev/") + 1); 730273831Snwhitehorn sprintf(md->fstab->fs_spec, "/dev/%s", name); 731273831Snwhitehorn } 732218799Snwhitehorn md->fstab->fs_file = strdup(mountpoint); 733218799Snwhitehorn /* Get VFS from text after freebsd-, if possible */ 734219892Snwhitehorn if (strncmp("freebsd-", type, 8) == 0) 735218799Snwhitehorn md->fstab->fs_vfstype = strdup(&type[8]); 736219892Snwhitehorn else if (strcmp("fat32", type) == 0 || strcmp("efi", type) == 0) 737219892Snwhitehorn md->fstab->fs_vfstype = strdup("msdosfs"); 738218799Snwhitehorn else 739218799Snwhitehorn md->fstab->fs_vfstype = strdup(type); /* Guess */ 740218799Snwhitehorn if (strcmp(type, "freebsd-swap") == 0) { 741218799Snwhitehorn md->fstab->fs_type = strdup(FSTAB_SW); 742218799Snwhitehorn md->fstab->fs_freq = 0; 743218799Snwhitehorn md->fstab->fs_passno = 0; 744273831Snwhitehorn } else if (strcmp(type, "freebsd-zfs") == 0) { 745273831Snwhitehorn md->fstab->fs_type = strdup(FSTAB_RW); 746273831Snwhitehorn md->fstab->fs_freq = 0; 747273831Snwhitehorn md->fstab->fs_passno = 0; 748218799Snwhitehorn } else { 749218799Snwhitehorn md->fstab->fs_type = strdup(FSTAB_RW); 750218799Snwhitehorn if (strcmp(mountpoint, "/") == 0) { 751218799Snwhitehorn md->fstab->fs_freq = 1; 752218799Snwhitehorn md->fstab->fs_passno = 1; 753218799Snwhitehorn } else { 754218799Snwhitehorn md->fstab->fs_freq = 2; 755218799Snwhitehorn md->fstab->fs_passno = 2; 756218799Snwhitehorn } 757218799Snwhitehorn } 758218799Snwhitehorn md->fstab->fs_mntops = strdup(md->fstab->fs_type); 759218799Snwhitehorn } 760273831Snwhitehorn 761273831Snwhitehorn if (zpool_name != NULL) 762273831Snwhitehorn free(zpool_name); 763218799Snwhitehorn} 764218799Snwhitehorn 765218799Snwhitehornstatic 766218799Snwhitehornint part_compare(const void *xa, const void *xb) 767218799Snwhitehorn{ 768218799Snwhitehorn struct gprovider **a = (struct gprovider **)xa; 769218799Snwhitehorn struct gprovider **b = (struct gprovider **)xb; 770218799Snwhitehorn intmax_t astart, bstart; 771218799Snwhitehorn struct gconfig *gc; 772218799Snwhitehorn 773218799Snwhitehorn astart = bstart = 0; 774218799Snwhitehorn LIST_FOREACH(gc, &(*a)->lg_config, lg_config) 775218799Snwhitehorn if (strcmp(gc->lg_name, "start") == 0) { 776218799Snwhitehorn astart = strtoimax(gc->lg_val, NULL, 0); 777218799Snwhitehorn break; 778218799Snwhitehorn } 779218799Snwhitehorn LIST_FOREACH(gc, &(*b)->lg_config, lg_config) 780218799Snwhitehorn if (strcmp(gc->lg_name, "start") == 0) { 781218799Snwhitehorn bstart = strtoimax(gc->lg_val, NULL, 0); 782218799Snwhitehorn break; 783218799Snwhitehorn } 784218799Snwhitehorn 785218799Snwhitehorn if (astart < bstart) 786218799Snwhitehorn return -1; 787218799Snwhitehorn else if (astart > bstart) 788218799Snwhitehorn return 1; 789218799Snwhitehorn else 790218799Snwhitehorn return 0; 791218799Snwhitehorn} 792218799Snwhitehorn 793218799Snwhitehornintmax_t 794218799Snwhitehorngpart_max_free(struct ggeom *geom, intmax_t *npartstart) 795218799Snwhitehorn{ 796218799Snwhitehorn struct gconfig *gc; 797218799Snwhitehorn struct gprovider *pp, **providers; 798218799Snwhitehorn intmax_t lastend; 799218799Snwhitehorn intmax_t start, end; 800218799Snwhitehorn intmax_t maxsize, maxstart; 801218799Snwhitehorn intmax_t partstart, partend; 802218799Snwhitehorn int i, nparts; 803218799Snwhitehorn 804218799Snwhitehorn /* Now get the maximum free size and free start */ 805218799Snwhitehorn start = end = 0; 806218799Snwhitehorn LIST_FOREACH(gc, &geom->lg_config, lg_config) { 807218799Snwhitehorn if (strcmp(gc->lg_name, "first") == 0) 808218799Snwhitehorn start = strtoimax(gc->lg_val, NULL, 0); 809218799Snwhitehorn if (strcmp(gc->lg_name, "last") == 0) 810218799Snwhitehorn end = strtoimax(gc->lg_val, NULL, 0); 811218799Snwhitehorn } 812218799Snwhitehorn 813218799Snwhitehorn i = nparts = 0; 814218799Snwhitehorn LIST_FOREACH(pp, &geom->lg_provider, lg_provider) 815218799Snwhitehorn nparts++; 816218799Snwhitehorn providers = calloc(nparts, sizeof(providers[0])); 817218799Snwhitehorn LIST_FOREACH(pp, &geom->lg_provider, lg_provider) 818218799Snwhitehorn providers[i++] = pp; 819218799Snwhitehorn qsort(providers, nparts, sizeof(providers[0]), part_compare); 820218799Snwhitehorn 821218799Snwhitehorn lastend = start - 1; 822218799Snwhitehorn maxsize = 0; 823218799Snwhitehorn for (i = 0; i < nparts; i++) { 824218799Snwhitehorn pp = providers[i]; 825218799Snwhitehorn 826218799Snwhitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 827218799Snwhitehorn if (strcmp(gc->lg_name, "start") == 0) 828218799Snwhitehorn partstart = strtoimax(gc->lg_val, NULL, 0); 829218799Snwhitehorn if (strcmp(gc->lg_name, "end") == 0) 830218799Snwhitehorn partend = strtoimax(gc->lg_val, NULL, 0); 831218799Snwhitehorn } 832218799Snwhitehorn 833218799Snwhitehorn if (partstart - lastend > maxsize) { 834218799Snwhitehorn maxsize = partstart - lastend - 1; 835218799Snwhitehorn maxstart = lastend + 1; 836218799Snwhitehorn } 837218799Snwhitehorn 838218799Snwhitehorn lastend = partend; 839218799Snwhitehorn } 840218799Snwhitehorn 841218799Snwhitehorn if (end - lastend > maxsize) { 842218799Snwhitehorn maxsize = end - lastend - 1; 843218799Snwhitehorn maxstart = lastend + 1; 844218799Snwhitehorn } 845218799Snwhitehorn 846218799Snwhitehorn pp = LIST_FIRST(&geom->lg_consumer)->lg_provider; 847218799Snwhitehorn 848218799Snwhitehorn /* Compute beginning of new partition and maximum available space */ 849218799Snwhitehorn if (pp->lg_stripesize > 0 && 850218799Snwhitehorn (maxstart*pp->lg_sectorsize % pp->lg_stripesize) != 0) { 851218799Snwhitehorn intmax_t offset = (pp->lg_stripesize - 852218799Snwhitehorn ((maxstart*pp->lg_sectorsize) % pp->lg_stripesize)) / 853218799Snwhitehorn pp->lg_sectorsize; 854218799Snwhitehorn maxstart += offset; 855218799Snwhitehorn maxsize -= offset; 856218799Snwhitehorn } 857218799Snwhitehorn 858218799Snwhitehorn if (npartstart != NULL) 859218799Snwhitehorn *npartstart = maxstart; 860218799Snwhitehorn 861218799Snwhitehorn return (maxsize); 862218799Snwhitehorn} 863218799Snwhitehorn 864218799Snwhitehornvoid 865218799Snwhitehorngpart_create(struct gprovider *pp, char *default_type, char *default_size, 866218799Snwhitehorn char *default_mountpoint, char **partname, int interactive) 867218799Snwhitehorn{ 868218799Snwhitehorn struct gctl_req *r; 869218799Snwhitehorn struct gconfig *gc; 870218799Snwhitehorn struct gconsumer *cp; 871218799Snwhitehorn struct ggeom *geom; 872218799Snwhitehorn const char *errstr, *scheme; 873226161Snwhitehorn char sizestr[32], startstr[32], output[64], *newpartname; 874273831Snwhitehorn char newfs[255], options_fstype[64]; 875218799Snwhitehorn intmax_t maxsize, size, sector, firstfree, stripe; 876218799Snwhitehorn uint64_t bytes; 877218799Snwhitehorn int nitems, choice, junk; 878218799Snwhitehorn unsigned i; 879218799Snwhitehorn 880218799Snwhitehorn DIALOG_FORMITEM items[] = { 881218799Snwhitehorn {0, "Type:", 5, 0, 0, FALSE, "freebsd-ufs", 11, 0, 12, 15, 0, 882273831Snwhitehorn FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, " 883273831Snwhitehorn "freebsd-swap)", FALSE}, 884218799Snwhitehorn {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 15, 0, 885218799Snwhitehorn FALSE, "Partition size. Append K, M, G for kilobytes, " 886218799Snwhitehorn "megabytes or gigabytes.", FALSE}, 887218799Snwhitehorn {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0, 888218799Snwhitehorn FALSE, "Path at which to mount partition (blank for " 889218799Snwhitehorn "swap, / for root filesystem)", FALSE}, 890218799Snwhitehorn {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE, 891218799Snwhitehorn "Partition name. Not all partition schemes support this.", 892218799Snwhitehorn FALSE}, 893218799Snwhitehorn }; 894218799Snwhitehorn 895218799Snwhitehorn if (partname != NULL) 896218799Snwhitehorn *partname = NULL; 897218799Snwhitehorn 898218799Snwhitehorn /* Record sector and stripe sizes */ 899218799Snwhitehorn sector = pp->lg_sectorsize; 900218799Snwhitehorn stripe = pp->lg_stripesize; 901218799Snwhitehorn 902218799Snwhitehorn /* 903218799Snwhitehorn * Find the PART geom we are manipulating. This may be a consumer of 904218799Snwhitehorn * this provider, or its parent. Check the consumer case first. 905218799Snwhitehorn */ 906218799Snwhitehorn geom = NULL; 907218799Snwhitehorn LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 908218799Snwhitehorn if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 909218799Snwhitehorn geom = cp->lg_geom; 910218799Snwhitehorn break; 911218799Snwhitehorn } 912218799Snwhitehorn 913218799Snwhitehorn if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 914218799Snwhitehorn geom = pp->lg_geom; 915218799Snwhitehorn 916218799Snwhitehorn /* Now get the partition scheme */ 917218799Snwhitehorn scheme = NULL; 918218799Snwhitehorn if (geom != NULL) { 919218799Snwhitehorn LIST_FOREACH(gc, &geom->lg_config, lg_config) 920218799Snwhitehorn if (strcmp(gc->lg_name, "scheme") == 0) 921218799Snwhitehorn scheme = gc->lg_val; 922218799Snwhitehorn } 923218799Snwhitehorn 924218799Snwhitehorn if (geom == NULL || scheme == NULL || strcmp(scheme, "(none)") == 0) { 925225066Snwhitehorn if (gpart_partition(pp->lg_name, NULL) == 0) 926218799Snwhitehorn dialog_msgbox("", 927218799Snwhitehorn "The partition table has been successfully created." 928218799Snwhitehorn " Please press Create again to create partitions.", 929218799Snwhitehorn 0, 0, TRUE); 930218799Snwhitehorn 931218799Snwhitehorn return; 932218799Snwhitehorn } 933218799Snwhitehorn 934218799Snwhitehorn /* 935218799Snwhitehorn * If we still don't have a geom, either the user has 936218799Snwhitehorn * canceled partitioning or there has been an error which has already 937218799Snwhitehorn * been displayed, so bail. 938218799Snwhitehorn */ 939218799Snwhitehorn if (geom == NULL) 940218799Snwhitehorn return; 941218799Snwhitehorn 942218799Snwhitehorn maxsize = size = gpart_max_free(geom, &firstfree); 943218799Snwhitehorn if (size <= 0) { 944218799Snwhitehorn dialog_msgbox("Error", "No free space left on device.", 0, 0, 945218799Snwhitehorn TRUE); 946218799Snwhitehorn return; 947218799Snwhitehorn } 948218799Snwhitehorn 949218799Snwhitehorn humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE, 950218799Snwhitehorn HN_NOSPACE | HN_DECIMAL); 951218799Snwhitehorn items[1].text = sizestr; 952218799Snwhitehorn 953218799Snwhitehorn /* Special-case the MBR default type for nested partitions */ 954225066Snwhitehorn if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "PC98") == 0) { 955218799Snwhitehorn items[0].text = "freebsd"; 956225066Snwhitehorn items[0].help = "Filesystem type (e.g. freebsd, fat32)"; 957225066Snwhitehorn } 958218799Snwhitehorn 959218853Snwhitehorn nitems = scheme_supports_labels(scheme) ? 4 : 3; 960218799Snwhitehorn 961218799Snwhitehorn if (default_type != NULL) 962218799Snwhitehorn items[0].text = default_type; 963218799Snwhitehorn if (default_size != NULL) 964218799Snwhitehorn items[1].text = default_size; 965218799Snwhitehorn if (default_mountpoint != NULL) 966218799Snwhitehorn items[2].text = default_mountpoint; 967218799Snwhitehorn 968219892Snwhitehorn /* Default options */ 969219892Snwhitehorn strncpy(options_fstype, items[0].text, 970219892Snwhitehorn sizeof(options_fstype)); 971219892Snwhitehorn newfs_command(options_fstype, newfs, 1); 972218799Snwhitehornaddpartform: 973218799Snwhitehorn if (interactive) { 974219892Snwhitehorn dialog_vars.extra_label = "Options"; 975219892Snwhitehorn dialog_vars.extra_button = TRUE; 976218799Snwhitehorn choice = dlg_form("Add Partition", "", 0, 0, 0, nitems, 977218799Snwhitehorn items, &junk); 978219892Snwhitehorn dialog_vars.extra_button = FALSE; 979219892Snwhitehorn switch (choice) { 980219892Snwhitehorn case 0: /* OK */ 981219892Snwhitehorn break; 982219892Snwhitehorn case 1: /* Cancel */ 983218799Snwhitehorn return; 984219892Snwhitehorn case 3: /* Options */ 985219892Snwhitehorn strncpy(options_fstype, items[0].text, 986219892Snwhitehorn sizeof(options_fstype)); 987219892Snwhitehorn newfs_command(options_fstype, newfs, 0); 988219892Snwhitehorn goto addpartform; 989219892Snwhitehorn } 990218799Snwhitehorn } 991218799Snwhitehorn 992219892Snwhitehorn /* 993219892Snwhitehorn * If the user changed the fs type after specifying options, undo 994219892Snwhitehorn * their choices in favor of the new filesystem's defaults. 995219892Snwhitehorn */ 996225613Snwhitehorn if (strcmp(options_fstype, items[0].text) != 0) { 997219892Snwhitehorn strncpy(options_fstype, items[0].text, sizeof(options_fstype)); 998219892Snwhitehorn newfs_command(options_fstype, newfs, 1); 999219892Snwhitehorn } 1000219892Snwhitehorn 1001218799Snwhitehorn size = maxsize; 1002218799Snwhitehorn if (strlen(items[1].text) > 0) { 1003218799Snwhitehorn if (expand_number(items[1].text, &bytes) != 0) { 1004218799Snwhitehorn char error[512]; 1005218799Snwhitehorn 1006218799Snwhitehorn sprintf(error, "Invalid size: %s\n", strerror(errno)); 1007218799Snwhitehorn dialog_msgbox("Error", error, 0, 0, TRUE); 1008218799Snwhitehorn goto addpartform; 1009218799Snwhitehorn } 1010218799Snwhitehorn size = MIN((intmax_t)(bytes/sector), maxsize); 1011218799Snwhitehorn } 1012218799Snwhitehorn 1013218799Snwhitehorn /* Check if the label has a / in it */ 1014218799Snwhitehorn if (strchr(items[3].text, '/') != NULL) { 1015218799Snwhitehorn dialog_msgbox("Error", "Label contains a /, which is not an " 1016218799Snwhitehorn "allowed character.", 0, 0, TRUE); 1017218799Snwhitehorn goto addpartform; 1018218799Snwhitehorn } 1019218799Snwhitehorn 1020218799Snwhitehorn /* Warn if no mountpoint set */ 1021218799Snwhitehorn if (strcmp(items[0].text, "freebsd-ufs") == 0 && 1022218799Snwhitehorn items[2].text[0] != '/') { 1023218799Snwhitehorn dialog_vars.defaultno = TRUE; 1024218799Snwhitehorn choice = dialog_yesno("Warning", 1025218799Snwhitehorn "This partition does not have a valid mountpoint " 1026218799Snwhitehorn "(for the partition from which you intend to boot the " 1027218799Snwhitehorn "operating system, the mountpoint should be /). Are you " 1028218799Snwhitehorn "sure you want to continue?" 1029218799Snwhitehorn , 0, 0); 1030218799Snwhitehorn dialog_vars.defaultno = FALSE; 1031218799Snwhitehorn if (choice == 1) /* cancel */ 1032218799Snwhitehorn goto addpartform; 1033218799Snwhitehorn } 1034218799Snwhitehorn 1035226160Snwhitehorn /* 1036226160Snwhitehorn * Error if this scheme needs nested partitions, this is one, and 1037226160Snwhitehorn * a mountpoint was set. 1038226160Snwhitehorn */ 1039226160Snwhitehorn if (strcmp(items[0].text, "freebsd") == 0 && 1040226160Snwhitehorn strlen(items[2].text) > 0) { 1041226160Snwhitehorn dialog_msgbox("Error", "Partitions of type \"freebsd\" are " 1042226160Snwhitehorn "nested BSD-type partition schemes and cannot have " 1043226160Snwhitehorn "mountpoints. After creating one, select it and press " 1044226160Snwhitehorn "Create again to add the actual file systems.", 0, 0, TRUE); 1045226160Snwhitehorn goto addpartform; 1046226160Snwhitehorn } 1047226160Snwhitehorn 1048218799Snwhitehorn /* If this is the root partition, check that this scheme is bootable */ 1049218799Snwhitehorn if (strcmp(items[2].text, "/") == 0 && !is_scheme_bootable(scheme)) { 1050218799Snwhitehorn char message[512]; 1051218799Snwhitehorn sprintf(message, "This partition scheme (%s) is not bootable " 1052218799Snwhitehorn "on this platform. Are you sure you want to proceed?", 1053218799Snwhitehorn scheme); 1054218799Snwhitehorn dialog_vars.defaultno = TRUE; 1055218799Snwhitehorn choice = dialog_yesno("Warning", message, 0, 0); 1056218799Snwhitehorn dialog_vars.defaultno = FALSE; 1057218799Snwhitehorn if (choice == 1) /* cancel */ 1058218799Snwhitehorn goto addpartform; 1059218799Snwhitehorn } 1060218799Snwhitehorn 1061273831Snwhitehorn /* If this is the root partition, check that this fs is bootable */ 1062273831Snwhitehorn if (strcmp(items[2].text, "/") == 0 && !is_fs_bootable(scheme, 1063273831Snwhitehorn items[0].text)) { 1064273831Snwhitehorn char message[512]; 1065273831Snwhitehorn sprintf(message, "This file system (%s) is not bootable " 1066273831Snwhitehorn "on this system. Are you sure you want to proceed?", 1067273831Snwhitehorn items[0].text); 1068273831Snwhitehorn dialog_vars.defaultno = TRUE; 1069273831Snwhitehorn choice = dialog_yesno("Warning", message, 0, 0); 1070273831Snwhitehorn dialog_vars.defaultno = FALSE; 1071273831Snwhitehorn if (choice == 1) /* cancel */ 1072273831Snwhitehorn goto addpartform; 1073273831Snwhitehorn } 1074273831Snwhitehorn 1075218799Snwhitehorn /* 1076218799Snwhitehorn * If this is the root partition, and we need a boot partition, ask 1077218799Snwhitehorn * the user to add one. 1078218799Snwhitehorn */ 1079226160Snwhitehorn 1080226160Snwhitehorn /* Check for existing freebsd-boot partition */ 1081226160Snwhitehorn LIST_FOREACH(pp, &geom->lg_provider, lg_provider) { 1082226160Snwhitehorn struct partition_metadata *md; 1083226160Snwhitehorn md = get_part_metadata(pp->lg_name, 0); 1084226160Snwhitehorn if (md == NULL || !md->bootcode) 1085226160Snwhitehorn continue; 1086226160Snwhitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) 1087226160Snwhitehorn if (strcmp(gc->lg_name, "type") == 0) 1088226160Snwhitehorn break; 1089271636Semaste if (gc != NULL && strcmp(gc->lg_val, 1090271636Semaste bootpart_type(scheme)) == 0) 1091226160Snwhitehorn break; 1092226160Snwhitehorn } 1093226160Snwhitehorn 1094226160Snwhitehorn /* If there isn't one, and we need one, ask */ 1095255817Snwhitehorn if ((strcmp(items[0].text, "freebsd") == 0 || 1096255817Snwhitehorn strcmp(items[2].text, "/") == 0) && bootpart_size(scheme) > 0 && 1097226160Snwhitehorn pp == NULL) { 1098218799Snwhitehorn if (interactive) 1099218799Snwhitehorn choice = dialog_yesno("Boot Partition", 1100218799Snwhitehorn "This partition scheme requires a boot partition " 1101218799Snwhitehorn "for the disk to be bootable. Would you like to " 1102218799Snwhitehorn "make one now?", 0, 0); 1103218799Snwhitehorn else 1104218799Snwhitehorn choice = 0; 1105218799Snwhitehorn 1106218799Snwhitehorn if (choice == 0) { /* yes */ 1107218799Snwhitehorn r = gctl_get_handle(); 1108218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 1109218799Snwhitehorn gctl_ro_param(r, "arg0", -1, geom->lg_name); 1110218799Snwhitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1111218799Snwhitehorn gctl_ro_param(r, "verb", -1, "add"); 1112271636Semaste gctl_ro_param(r, "type", -1, bootpart_type(scheme)); 1113218799Snwhitehorn snprintf(sizestr, sizeof(sizestr), "%jd", 1114218799Snwhitehorn bootpart_size(scheme) / sector); 1115218799Snwhitehorn gctl_ro_param(r, "size", -1, sizestr); 1116218799Snwhitehorn snprintf(startstr, sizeof(startstr), "%jd", firstfree); 1117218799Snwhitehorn gctl_ro_param(r, "start", -1, startstr); 1118218799Snwhitehorn gctl_rw_param(r, "output", sizeof(output), output); 1119218799Snwhitehorn errstr = gctl_issue(r); 1120218799Snwhitehorn if (errstr != NULL && errstr[0] != '\0') 1121218799Snwhitehorn gpart_show_error("Error", NULL, errstr); 1122218799Snwhitehorn gctl_free(r); 1123218799Snwhitehorn 1124218799Snwhitehorn get_part_metadata(strtok(output, " "), 1)->bootcode = 1; 1125218799Snwhitehorn 1126218799Snwhitehorn /* Now adjust the part we are really adding forward */ 1127218799Snwhitehorn firstfree += bootpart_size(scheme) / sector; 1128218799Snwhitehorn size -= (bootpart_size(scheme) + stripe)/sector; 1129218799Snwhitehorn if (stripe > 0 && (firstfree*sector % stripe) != 0) 1130218799Snwhitehorn firstfree += (stripe - ((firstfree*sector) % 1131218799Snwhitehorn stripe)) / sector; 1132218799Snwhitehorn } 1133218799Snwhitehorn } 1134218799Snwhitehorn 1135218799Snwhitehorn r = gctl_get_handle(); 1136218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 1137218799Snwhitehorn gctl_ro_param(r, "arg0", -1, geom->lg_name); 1138218799Snwhitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1139218799Snwhitehorn gctl_ro_param(r, "verb", -1, "add"); 1140218799Snwhitehorn 1141218799Snwhitehorn gctl_ro_param(r, "type", -1, items[0].text); 1142218799Snwhitehorn snprintf(sizestr, sizeof(sizestr), "%jd", size); 1143218799Snwhitehorn gctl_ro_param(r, "size", -1, sizestr); 1144218799Snwhitehorn snprintf(startstr, sizeof(startstr), "%jd", firstfree); 1145218799Snwhitehorn gctl_ro_param(r, "start", -1, startstr); 1146218799Snwhitehorn if (items[3].text[0] != '\0') 1147218799Snwhitehorn gctl_ro_param(r, "label", -1, items[3].text); 1148218799Snwhitehorn gctl_rw_param(r, "output", sizeof(output), output); 1149218799Snwhitehorn errstr = gctl_issue(r); 1150218799Snwhitehorn if (errstr != NULL && errstr[0] != '\0') { 1151218799Snwhitehorn gpart_show_error("Error", NULL, errstr); 1152218799Snwhitehorn gctl_free(r); 1153218799Snwhitehorn goto addpartform; 1154218799Snwhitehorn } 1155226161Snwhitehorn newpartname = strtok(output, " "); 1156226161Snwhitehorn gctl_free(r); 1157218799Snwhitehorn 1158226161Snwhitehorn /* 1159226161Snwhitehorn * Try to destroy any geom that gpart picked up already here from 1160226161Snwhitehorn * dirty blocks. 1161226161Snwhitehorn */ 1162226161Snwhitehorn r = gctl_get_handle(); 1163226161Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 1164226161Snwhitehorn gctl_ro_param(r, "arg0", -1, newpartname); 1165226161Snwhitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1166226161Snwhitehorn junk = 1; 1167226161Snwhitehorn gctl_ro_param(r, "force", sizeof(junk), &junk); 1168226161Snwhitehorn gctl_ro_param(r, "verb", -1, "destroy"); 1169226161Snwhitehorn gctl_issue(r); /* Error usually expected and non-fatal */ 1170226161Snwhitehorn gctl_free(r); 1171226161Snwhitehorn 1172271636Semaste if (strcmp(items[0].text, bootpart_type(scheme)) == 0) 1173226161Snwhitehorn get_part_metadata(newpartname, 1)->bootcode = 1; 1174218799Snwhitehorn else if (strcmp(items[0].text, "freebsd") == 0) 1175226161Snwhitehorn gpart_partition(newpartname, "BSD"); 1176218799Snwhitehorn else 1177226161Snwhitehorn set_default_part_metadata(newpartname, scheme, 1178219892Snwhitehorn items[0].text, items[2].text, newfs); 1179218799Snwhitehorn 1180218799Snwhitehorn for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++) 1181218799Snwhitehorn if (items[i].text_free) 1182218799Snwhitehorn free(items[i].text); 1183218799Snwhitehorn 1184218799Snwhitehorn if (partname != NULL) 1185226161Snwhitehorn *partname = strdup(newpartname); 1186218799Snwhitehorn} 1187218799Snwhitehorn 1188218799Snwhitehornvoid 1189218799Snwhitehorngpart_delete(struct gprovider *pp) 1190218799Snwhitehorn{ 1191218799Snwhitehorn struct gconfig *gc; 1192218799Snwhitehorn struct ggeom *geom; 1193218799Snwhitehorn struct gconsumer *cp; 1194218799Snwhitehorn struct gctl_req *r; 1195218799Snwhitehorn const char *errstr; 1196218799Snwhitehorn intmax_t idx; 1197226083Snwhitehorn int is_partition; 1198218799Snwhitehorn 1199218799Snwhitehorn /* Is it a partition? */ 1200218799Snwhitehorn is_partition = (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0); 1201218799Snwhitehorn 1202218799Snwhitehorn /* Find out if this is the root of a gpart geom */ 1203218799Snwhitehorn geom = NULL; 1204218799Snwhitehorn LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 1205218799Snwhitehorn if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 1206218799Snwhitehorn geom = cp->lg_geom; 1207218799Snwhitehorn break; 1208218799Snwhitehorn } 1209218799Snwhitehorn 1210226083Snwhitehorn /* If so, destroy all children */ 1211218799Snwhitehorn if (geom != NULL) { 1212226083Snwhitehorn gpart_destroy(geom); 1213226083Snwhitehorn 1214226083Snwhitehorn /* If this is a partition, revert it, so it can be deleted */ 1215218799Snwhitehorn if (is_partition) { 1216226083Snwhitehorn r = gctl_get_handle(); 1217226083Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 1218226083Snwhitehorn gctl_ro_param(r, "arg0", -1, geom->lg_name); 1219226083Snwhitehorn gctl_ro_param(r, "verb", -1, "undo"); 1220226083Snwhitehorn gctl_issue(r); /* Ignore non-fatal errors */ 1221226083Snwhitehorn gctl_free(r); 1222218799Snwhitehorn } 1223226083Snwhitehorn } 1224218799Snwhitehorn 1225218799Snwhitehorn /* 1226218799Snwhitehorn * If this is not a partition, see if that is a problem, complain if 1227218799Snwhitehorn * necessary, and return always, since we need not do anything further, 1228218799Snwhitehorn * error or no. 1229218799Snwhitehorn */ 1230218799Snwhitehorn if (!is_partition) { 1231218799Snwhitehorn if (geom == NULL) 1232218799Snwhitehorn dialog_msgbox("Error", 1233218799Snwhitehorn "Only partitions can be deleted.", 0, 0, TRUE); 1234218799Snwhitehorn return; 1235218799Snwhitehorn } 1236218799Snwhitehorn 1237218799Snwhitehorn r = gctl_get_handle(); 1238218799Snwhitehorn gctl_ro_param(r, "class", -1, pp->lg_geom->lg_class->lg_name); 1239218799Snwhitehorn gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name); 1240218799Snwhitehorn gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1241218799Snwhitehorn gctl_ro_param(r, "verb", -1, "delete"); 1242218799Snwhitehorn 1243218799Snwhitehorn LIST_FOREACH(gc, &pp->lg_config, lg_config) { 1244218799Snwhitehorn if (strcmp(gc->lg_name, "index") == 0) { 1245218799Snwhitehorn idx = atoi(gc->lg_val); 1246218799Snwhitehorn gctl_ro_param(r, "index", sizeof(idx), &idx); 1247218799Snwhitehorn break; 1248218799Snwhitehorn } 1249218799Snwhitehorn } 1250218799Snwhitehorn 1251218799Snwhitehorn errstr = gctl_issue(r); 1252218799Snwhitehorn if (errstr != NULL && errstr[0] != '\0') { 1253218799Snwhitehorn gpart_show_error("Error", NULL, errstr); 1254218799Snwhitehorn gctl_free(r); 1255218799Snwhitehorn return; 1256218799Snwhitehorn } 1257218799Snwhitehorn 1258218799Snwhitehorn gctl_free(r); 1259218799Snwhitehorn 1260218799Snwhitehorn delete_part_metadata(pp->lg_name); 1261218799Snwhitehorn} 1262218799Snwhitehorn 1263218799Snwhitehornvoid 1264218799Snwhitehorngpart_revert_all(struct gmesh *mesh) 1265218799Snwhitehorn{ 1266218799Snwhitehorn struct gclass *classp; 1267218799Snwhitehorn struct gconfig *gc; 1268218799Snwhitehorn struct ggeom *gp; 1269218799Snwhitehorn struct gctl_req *r; 1270218799Snwhitehorn const char *modified; 1271218799Snwhitehorn 1272218799Snwhitehorn LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 1273218799Snwhitehorn if (strcmp(classp->lg_name, "PART") == 0) 1274218799Snwhitehorn break; 1275218799Snwhitehorn } 1276218799Snwhitehorn 1277218799Snwhitehorn if (strcmp(classp->lg_name, "PART") != 0) { 1278218799Snwhitehorn dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE); 1279218799Snwhitehorn return; 1280218799Snwhitehorn } 1281218799Snwhitehorn 1282218799Snwhitehorn LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1283218799Snwhitehorn modified = "true"; /* XXX: If we don't know (kernel too old), 1284218799Snwhitehorn * assume there are modifications. */ 1285218799Snwhitehorn LIST_FOREACH(gc, &gp->lg_config, lg_config) { 1286218799Snwhitehorn if (strcmp(gc->lg_name, "modified") == 0) { 1287218799Snwhitehorn modified = gc->lg_val; 1288218799Snwhitehorn break; 1289218799Snwhitehorn } 1290218799Snwhitehorn } 1291218799Snwhitehorn 1292218799Snwhitehorn if (strcmp(modified, "false") == 0) 1293218799Snwhitehorn continue; 1294218799Snwhitehorn 1295218799Snwhitehorn r = gctl_get_handle(); 1296218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 1297218799Snwhitehorn gctl_ro_param(r, "arg0", -1, gp->lg_name); 1298218799Snwhitehorn gctl_ro_param(r, "verb", -1, "undo"); 1299218799Snwhitehorn 1300226161Snwhitehorn gctl_issue(r); 1301218799Snwhitehorn gctl_free(r); 1302218799Snwhitehorn } 1303218799Snwhitehorn} 1304218799Snwhitehorn 1305218799Snwhitehornvoid 1306218799Snwhitehorngpart_commit(struct gmesh *mesh) 1307218799Snwhitehorn{ 1308218799Snwhitehorn struct partition_metadata *md; 1309218799Snwhitehorn struct gclass *classp; 1310218799Snwhitehorn struct ggeom *gp; 1311218799Snwhitehorn struct gconfig *gc; 1312218799Snwhitehorn struct gconsumer *cp; 1313218799Snwhitehorn struct gprovider *pp; 1314218799Snwhitehorn struct gctl_req *r; 1315218799Snwhitehorn const char *errstr; 1316218799Snwhitehorn const char *modified; 1317273831Snwhitehorn const char *rootfs; 1318218799Snwhitehorn 1319218799Snwhitehorn LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 1320218799Snwhitehorn if (strcmp(classp->lg_name, "PART") == 0) 1321218799Snwhitehorn break; 1322218799Snwhitehorn } 1323218799Snwhitehorn 1324273831Snwhitehorn /* Figure out what filesystem / uses */ 1325273831Snwhitehorn rootfs = "ufs"; /* Assume ufs if nothing else present */ 1326273831Snwhitehorn TAILQ_FOREACH(md, &part_metadata, metadata) { 1327273831Snwhitehorn if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0) { 1328273831Snwhitehorn rootfs = md->fstab->fs_vfstype; 1329273831Snwhitehorn break; 1330273831Snwhitehorn } 1331273831Snwhitehorn } 1332273831Snwhitehorn 1333218799Snwhitehorn if (strcmp(classp->lg_name, "PART") != 0) { 1334218799Snwhitehorn dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE); 1335218799Snwhitehorn return; 1336218799Snwhitehorn } 1337218799Snwhitehorn 1338218799Snwhitehorn LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1339218799Snwhitehorn modified = "true"; /* XXX: If we don't know (kernel too old), 1340218799Snwhitehorn * assume there are modifications. */ 1341218799Snwhitehorn LIST_FOREACH(gc, &gp->lg_config, lg_config) { 1342218799Snwhitehorn if (strcmp(gc->lg_name, "modified") == 0) { 1343218799Snwhitehorn modified = gc->lg_val; 1344218799Snwhitehorn break; 1345218799Snwhitehorn } 1346218799Snwhitehorn } 1347218799Snwhitehorn 1348218799Snwhitehorn if (strcmp(modified, "false") == 0) 1349218799Snwhitehorn continue; 1350218799Snwhitehorn 1351218799Snwhitehorn /* Add bootcode if necessary, before the commit */ 1352218799Snwhitehorn md = get_part_metadata(gp->lg_name, 0); 1353218799Snwhitehorn if (md != NULL && md->bootcode) 1354218799Snwhitehorn gpart_bootcode(gp); 1355218799Snwhitehorn 1356218799Snwhitehorn /* Now install partcode on its partitions, if necessary */ 1357218799Snwhitehorn LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1358218799Snwhitehorn md = get_part_metadata(pp->lg_name, 0); 1359218799Snwhitehorn if (md == NULL || !md->bootcode) 1360218799Snwhitehorn continue; 1361218799Snwhitehorn 1362218799Snwhitehorn /* Mark this partition active if that's required */ 1363218799Snwhitehorn gpart_activate(pp); 1364218799Snwhitehorn 1365218799Snwhitehorn /* Check if the partition has sub-partitions */ 1366218799Snwhitehorn LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 1367218799Snwhitehorn if (strcmp(cp->lg_geom->lg_class->lg_name, 1368218799Snwhitehorn "PART") == 0) 1369218799Snwhitehorn break; 1370218799Snwhitehorn 1371218799Snwhitehorn if (cp == NULL) /* No sub-partitions */ 1372273831Snwhitehorn gpart_partcode(pp, rootfs); 1373218799Snwhitehorn } 1374218799Snwhitehorn 1375218799Snwhitehorn r = gctl_get_handle(); 1376218799Snwhitehorn gctl_ro_param(r, "class", -1, "PART"); 1377218799Snwhitehorn gctl_ro_param(r, "arg0", -1, gp->lg_name); 1378218799Snwhitehorn gctl_ro_param(r, "verb", -1, "commit"); 1379218799Snwhitehorn 1380218799Snwhitehorn errstr = gctl_issue(r); 1381218799Snwhitehorn if (errstr != NULL && errstr[0] != '\0') 1382218799Snwhitehorn gpart_show_error("Error", NULL, errstr); 1383218799Snwhitehorn gctl_free(r); 1384218799Snwhitehorn } 1385218799Snwhitehorn} 1386218799Snwhitehorn 1387