1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2011 Nathan Whitehorn 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/stat.h> 33 #include <errno.h> 34 #include <libutil.h> 35 #include <inttypes.h> 36 37 #include <libgeom.h> 38 #include <dialog.h> 39 #include <dlg_keys.h> 40 41 #include "partedit.h" 42 43 #define GPART_FLAGS "x" /* Do not commit changes by default */ 44 45 static void 46 gpart_show_error(const char *title, const char *explanation, const char *errstr) 47 { 48 char *errmsg; 49 char message[512]; 50 int error; 51 52 if (explanation == NULL) 53 explanation = ""; 54 55 error = strtol(errstr, &errmsg, 0); 56 if (errmsg != errstr) { 57 while (errmsg[0] == ' ') 58 errmsg++; 59 if (errmsg[0] != '\0') 60 sprintf(message, "%s%s. %s", explanation, 61 strerror(error), errmsg); 62 else 63 sprintf(message, "%s%s", explanation, strerror(error)); 64 } else { 65 sprintf(message, "%s%s", explanation, errmsg); 66 } 67 68 dialog_msgbox(title, message, 0, 0, TRUE); 69 } 70 71 static int 72 scheme_supports_labels(const char *scheme) 73 { 74 if (strcmp(scheme, "APM") == 0) 75 return (1); 76 if (strcmp(scheme, "GPT") == 0) 77 return (1); 78 79 return (0); 80 } 81 82 static void 83 newfs_command(const char *fstype, char *command, int use_default) 84 { 85 if (strcmp(fstype, "freebsd-ufs") == 0) { 86 int i; 87 DIALOG_LISTITEM items[] = { 88 {"UFS1", "UFS Version 1", 89 "Use version 1 of the UFS file system instead " 90 "of version 2 (not recommended)", 0 }, 91 {"SU", "Softupdates", 92 "Enable softupdates (default)", 1 }, 93 {"SUJ", "Softupdates journaling", 94 "Enable file system journaling (default - " 95 "turn off for SSDs)", 1 }, 96 {"TRIM", "Enable SSD TRIM support", 97 "Enable TRIM support, useful on solid-state drives", 98 0 }, 99 }; 100 101 if (!use_default) { 102 int choice; 103 choice = dlg_checklist("UFS Options", "", 0, 0, 0, 104 nitems(items), items, NULL, 105 FLAG_CHECK, &i); 106 if (choice == 1) /* Cancel */ 107 return; 108 } 109 110 strcpy(command, "newfs "); 111 for (i = 0; i < (int)nitems(items); i++) { 112 if (items[i].state == 0) 113 continue; 114 if (strcmp(items[i].name, "UFS1") == 0) 115 strcat(command, "-O1 "); 116 else if (strcmp(items[i].name, "SU") == 0) 117 strcat(command, "-U "); 118 else if (strcmp(items[i].name, "SUJ") == 0) 119 strcat(command, "-j "); 120 else if (strcmp(items[i].name, "TRIM") == 0) 121 strcat(command, "-t "); 122 } 123 } else if (strcmp(fstype, "freebsd-zfs") == 0) { 124 int i; 125 DIALOG_LISTITEM items[] = { 126 {"fletcher4", "checksum algorithm: fletcher4", 127 "Use fletcher4 for data integrity checking. " 128 "(default)", 1 }, 129 {"fletcher2", "checksum algorithm: fletcher2", 130 "Use fletcher2 for data integrity checking. " 131 "(not recommended)", 0 }, 132 {"sha256", "checksum algorithm: sha256", 133 "Use sha256 for data integrity checking. " 134 "(not recommended)", 0 }, 135 {"atime", "Update atimes for files", 136 "Disable atime update", 0 }, 137 }; 138 139 if (!use_default) { 140 int choice; 141 choice = dlg_checklist("ZFS Options", "", 0, 0, 0, 142 nitems(items), items, NULL, 143 FLAG_CHECK, &i); 144 if (choice == 1) /* Cancel */ 145 return; 146 } 147 148 strcpy(command, "zpool create -f -m none "); 149 if (getenv("BSDINSTALL_TMPBOOT") != NULL) { 150 char zfsboot_path[MAXPATHLEN]; 151 snprintf(zfsboot_path, sizeof(zfsboot_path), "%s/zfs", 152 getenv("BSDINSTALL_TMPBOOT")); 153 mkdir(zfsboot_path, S_IRWXU | S_IRGRP | S_IXGRP | 154 S_IROTH | S_IXOTH); 155 sprintf(command, "%s -o cachefile=%s/zpool.cache ", 156 command, zfsboot_path); 157 } 158 for (i = 0; i < (int)nitems(items); i++) { 159 if (items[i].state == 0) 160 continue; 161 if (strcmp(items[i].name, "fletcher4") == 0) 162 strcat(command, "-O checksum=fletcher4 "); 163 else if (strcmp(items[i].name, "fletcher2") == 0) 164 strcat(command, "-O checksum=fletcher2 "); 165 else if (strcmp(items[i].name, "sha256") == 0) 166 strcat(command, "-O checksum=sha256 "); 167 else if (strcmp(items[i].name, "atime") == 0) 168 strcat(command, "-O atime=off "); 169 } 170 } else if (strcmp(fstype, "fat32") == 0 || strcmp(fstype, "efi") == 0 || 171 strcmp(fstype, "ms-basic-data") == 0) { 172 int i; 173 DIALOG_LISTITEM items[] = { 174 {"FAT32", "FAT Type 32", 175 "Create a FAT32 filesystem (default)", 1 }, 176 {"FAT16", "FAT Type 16", 177 "Create a FAT16 filesystem", 0 }, 178 {"FAT12", "FAT Type 12", 179 "Create a FAT12 filesystem", 0 }, 180 }; 181 182 if (!use_default) { 183 int choice; 184 choice = dlg_checklist("FAT Options", "", 0, 0, 0, 185 nitems(items), items, NULL, 186 FLAG_RADIO, &i); 187 if (choice == 1) /* Cancel */ 188 return; 189 } 190 191 strcpy(command, "newfs_msdos "); 192 for (i = 0; i < (int)nitems(items); i++) { 193 if (items[i].state == 0) 194 continue; 195 if (strcmp(items[i].name, "FAT16") == 0) 196 strcat(command, "-F 16 "); 197 else if (strcmp(items[i].name, "FAT12") == 0) 198 strcat(command, "-F 12 "); 199 } 200 } else { 201 if (!use_default) 202 dialog_msgbox("Error", "No configurable options exist " 203 "for this filesystem.", 0, 0, TRUE); 204 command[0] = '\0'; 205 } 206 } 207 208 const char * 209 choose_part_type(const char *def_scheme) 210 { 211 int cancel, choice; 212 const char *scheme = NULL; 213 214 DIALOG_LISTITEM items[] = { 215 {"APM", "Apple Partition Map", 216 "Bootable on PowerPC Apple Hardware", 0 }, 217 {"BSD", "BSD Labels", 218 "Bootable on most x86 systems", 0 }, 219 {"GPT", "GUID Partition Table", 220 "Bootable on most x86 systems and EFI aware ARM64", 0 }, 221 {"MBR", "DOS Partitions", 222 "Bootable on most x86 systems", 0 }, 223 {"VTOC8", "Sun VTOC8 Partition Table", 224 "Bootable on Sun SPARC systems", 0 }, 225 }; 226 227 parttypemenu: 228 dialog_vars.default_item = __DECONST(char *, def_scheme); 229 cancel = dlg_menu("Partition Scheme", 230 "Select a partition scheme for this volume:", 0, 0, 0, 231 nitems(items), items, &choice, NULL); 232 dialog_vars.default_item = NULL; 233 234 if (cancel) 235 return NULL; 236 237 if (!is_scheme_bootable(items[choice].name)) { 238 char message[512]; 239 sprintf(message, "This partition scheme (%s) is not " 240 "bootable on this platform. Are you sure you want " 241 "to proceed?", items[choice].name); 242 dialog_vars.defaultno = TRUE; 243 cancel = dialog_yesno("Warning", message, 0, 0); 244 dialog_vars.defaultno = FALSE; 245 if (cancel) /* cancel */ 246 goto parttypemenu; 247 } 248 249 scheme = items[choice].name; 250 251 return scheme; 252 } 253 254 int 255 gpart_partition(const char *lg_name, const char *scheme) 256 { 257 int cancel; 258 struct gctl_req *r; 259 const char *errstr; 260 261 schememenu: 262 if (scheme == NULL) { 263 scheme = choose_part_type(default_scheme()); 264 265 if (scheme == NULL) 266 return (-1); 267 268 if (!is_scheme_bootable(scheme)) { 269 char message[512]; 270 sprintf(message, "This partition scheme (%s) is not " 271 "bootable on this platform. Are you sure you want " 272 "to proceed?", scheme); 273 dialog_vars.defaultno = TRUE; 274 cancel = dialog_yesno("Warning", message, 0, 0); 275 dialog_vars.defaultno = FALSE; 276 if (cancel) { /* cancel */ 277 /* Reset scheme so user can choose another */ 278 scheme = NULL; 279 goto schememenu; 280 } 281 } 282 } 283 284 r = gctl_get_handle(); 285 gctl_ro_param(r, "class", -1, "PART"); 286 gctl_ro_param(r, "arg0", -1, lg_name); 287 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 288 gctl_ro_param(r, "scheme", -1, scheme); 289 gctl_ro_param(r, "verb", -1, "create"); 290 291 errstr = gctl_issue(r); 292 if (errstr != NULL && errstr[0] != '\0') { 293 gpart_show_error("Error", NULL, errstr); 294 gctl_free(r); 295 scheme = NULL; 296 goto schememenu; 297 } 298 gctl_free(r); 299 300 if (bootcode_path(scheme) != NULL) 301 get_part_metadata(lg_name, 1)->bootcode = 1; 302 return (0); 303 } 304 305 static void 306 gpart_activate(struct gprovider *pp) 307 { 308 struct gconfig *gc; 309 struct gctl_req *r; 310 const char *errstr, *scheme; 311 const char *attribute = NULL; 312 intmax_t idx; 313 314 /* 315 * Some partition schemes need this partition to be marked 'active' 316 * for it to be bootable. 317 */ 318 LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) { 319 if (strcmp(gc->lg_name, "scheme") == 0) { 320 scheme = gc->lg_val; 321 break; 322 } 323 } 324 325 if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "EBR") == 0) 326 attribute = "active"; 327 else 328 return; 329 330 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 331 if (strcmp(gc->lg_name, "index") == 0) { 332 idx = atoi(gc->lg_val); 333 break; 334 } 335 } 336 337 r = gctl_get_handle(); 338 gctl_ro_param(r, "class", -1, "PART"); 339 gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name); 340 gctl_ro_param(r, "verb", -1, "set"); 341 gctl_ro_param(r, "attrib", -1, attribute); 342 gctl_ro_param(r, "index", sizeof(idx), &idx); 343 344 errstr = gctl_issue(r); 345 if (errstr != NULL && errstr[0] != '\0') 346 gpart_show_error("Error", "Error marking partition active:", 347 errstr); 348 gctl_free(r); 349 } 350 351 void 352 gpart_set_root(const char *lg_name, const char *attribute) 353 { 354 struct gctl_req *r; 355 const char *errstr; 356 357 r = gctl_get_handle(); 358 gctl_ro_param(r, "class", -1, "PART"); 359 gctl_ro_param(r, "arg0", -1, lg_name); 360 gctl_ro_param(r, "flags", -1, "C"); 361 gctl_ro_param(r, "verb", -1, "set"); 362 gctl_ro_param(r, "attrib", -1, attribute); 363 364 errstr = gctl_issue(r); 365 if (errstr != NULL && errstr[0] != '\0') 366 gpart_show_error("Error", "Error setting parameter on disk:", 367 errstr); 368 gctl_free(r); 369 } 370 371 static void 372 gpart_bootcode(struct ggeom *gp) 373 { 374 const char *bootcode; 375 struct gconfig *gc; 376 struct gctl_req *r; 377 const char *errstr, *scheme; 378 uint8_t *boot; 379 size_t bootsize, bytes; 380 int bootfd; 381 382 /* 383 * Write default bootcode to the newly partitioned disk, if that 384 * applies on this platform. 385 */ 386 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 387 if (strcmp(gc->lg_name, "scheme") == 0) { 388 scheme = gc->lg_val; 389 break; 390 } 391 } 392 393 bootcode = bootcode_path(scheme); 394 if (bootcode == NULL) 395 return; 396 397 bootfd = open(bootcode, O_RDONLY); 398 if (bootfd < 0) { 399 dialog_msgbox("Bootcode Error", strerror(errno), 0, 0, 400 TRUE); 401 return; 402 } 403 404 bootsize = lseek(bootfd, 0, SEEK_END); 405 boot = malloc(bootsize); 406 lseek(bootfd, 0, SEEK_SET); 407 bytes = 0; 408 while (bytes < bootsize) 409 bytes += read(bootfd, boot + bytes, bootsize - bytes); 410 close(bootfd); 411 412 r = gctl_get_handle(); 413 gctl_ro_param(r, "class", -1, "PART"); 414 gctl_ro_param(r, "arg0", -1, gp->lg_name); 415 gctl_ro_param(r, "verb", -1, "bootcode"); 416 gctl_ro_param(r, "bootcode", bootsize, boot); 417 418 errstr = gctl_issue(r); 419 if (errstr != NULL && errstr[0] != '\0') 420 gpart_show_error("Bootcode Error", NULL, errstr); 421 gctl_free(r); 422 free(boot); 423 } 424 425 static void 426 gpart_partcode(struct gprovider *pp, const char *fstype) 427 { 428 struct gconfig *gc; 429 const char *scheme; 430 const char *indexstr; 431 char message[255], command[255]; 432 433 LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) { 434 if (strcmp(gc->lg_name, "scheme") == 0) { 435 scheme = gc->lg_val; 436 break; 437 } 438 } 439 440 /* Make sure this partition scheme needs partcode on this platform */ 441 if (partcode_path(scheme, fstype) == NULL) 442 return; 443 444 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 445 if (strcmp(gc->lg_name, "index") == 0) { 446 indexstr = gc->lg_val; 447 break; 448 } 449 } 450 451 /* Shell out to gpart for partcode for now */ 452 sprintf(command, "gpart bootcode -p %s -i %s %s", 453 partcode_path(scheme, fstype), indexstr, pp->lg_geom->lg_name); 454 if (system(command) != 0) { 455 sprintf(message, "Error installing partcode on partition %s", 456 pp->lg_name); 457 dialog_msgbox("Error", message, 0, 0, TRUE); 458 } 459 } 460 461 void 462 gpart_destroy(struct ggeom *lg_geom) 463 { 464 struct gctl_req *r; 465 struct gprovider *pp; 466 const char *errstr; 467 int force = 1; 468 469 /* Delete all child metadata */ 470 LIST_FOREACH(pp, &lg_geom->lg_provider, lg_provider) 471 gpart_delete(pp); 472 473 /* Revert any local changes to get this geom into a pristine state */ 474 r = gctl_get_handle(); 475 gctl_ro_param(r, "class", -1, "PART"); 476 gctl_ro_param(r, "arg0", -1, lg_geom->lg_name); 477 gctl_ro_param(r, "verb", -1, "undo"); 478 gctl_issue(r); /* Ignore errors -- these are non-fatal */ 479 gctl_free(r); 480 481 /* Now destroy the geom itself */ 482 r = gctl_get_handle(); 483 gctl_ro_param(r, "class", -1, "PART"); 484 gctl_ro_param(r, "arg0", -1, lg_geom->lg_name); 485 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 486 gctl_ro_param(r, "force", sizeof(force), &force); 487 gctl_ro_param(r, "verb", -1, "destroy"); 488 errstr = gctl_issue(r); 489 if (errstr != NULL && errstr[0] != '\0') { 490 /* 491 * Check if we reverted away the existence of the geom 492 * altogether. Show all other errors to the user. 493 */ 494 if (strtol(errstr, NULL, 0) != EINVAL) 495 gpart_show_error("Error", NULL, errstr); 496 } 497 gctl_free(r); 498 499 /* And any metadata associated with the partition scheme itself */ 500 delete_part_metadata(lg_geom->lg_name); 501 } 502 503 void 504 gpart_edit(struct gprovider *pp) 505 { 506 struct gctl_req *r; 507 struct gconfig *gc; 508 struct gconsumer *cp; 509 struct ggeom *geom; 510 const char *errstr, *oldtype, *scheme; 511 struct partition_metadata *md; 512 char sizestr[32]; 513 char newfs[255]; 514 intmax_t idx; 515 int hadlabel, choice, junk, nitems; 516 unsigned i; 517 518 DIALOG_FORMITEM items[] = { 519 {0, "Type:", 5, 0, 0, FALSE, "", 11, 0, 12, 15, 0, 520 FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, " 521 "freebsd-swap)", FALSE}, 522 {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 0, 0, 523 FALSE, "Partition size. Append K, M, G for kilobytes, " 524 "megabytes or gigabytes.", FALSE}, 525 {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0, 526 FALSE, "Path at which to mount this partition (leave blank " 527 "for swap, set to / for root filesystem)", FALSE}, 528 {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE, 529 "Partition name. Not all partition schemes support this.", 530 FALSE}, 531 }; 532 533 /* 534 * Find the PART geom we are manipulating. This may be a consumer of 535 * this provider, or its parent. Check the consumer case first. 536 */ 537 geom = NULL; 538 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 539 if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 540 /* Check for zombie geoms, treating them as blank */ 541 scheme = NULL; 542 LIST_FOREACH(gc, &cp->lg_geom->lg_config, lg_config) { 543 if (strcmp(gc->lg_name, "scheme") == 0) { 544 scheme = gc->lg_val; 545 break; 546 } 547 } 548 if (scheme == NULL || strcmp(scheme, "(none)") == 0) { 549 gpart_partition(cp->lg_geom->lg_name, NULL); 550 return; 551 } 552 553 /* If this is a nested partition, edit as usual */ 554 if (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 555 break; 556 557 /* Destroy the geom and all sub-partitions */ 558 gpart_destroy(cp->lg_geom); 559 560 /* Now re-partition and return */ 561 gpart_partition(cp->lg_geom->lg_name, NULL); 562 return; 563 } 564 565 if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 566 geom = pp->lg_geom; 567 568 if (geom == NULL) { 569 /* Disk not partitioned, so partition it */ 570 gpart_partition(pp->lg_name, NULL); 571 return; 572 } 573 574 LIST_FOREACH(gc, &geom->lg_config, lg_config) { 575 if (strcmp(gc->lg_name, "scheme") == 0) { 576 scheme = gc->lg_val; 577 break; 578 } 579 } 580 581 nitems = scheme_supports_labels(scheme) ? 4 : 3; 582 583 /* Edit editable parameters of a partition */ 584 hadlabel = 0; 585 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 586 if (strcmp(gc->lg_name, "type") == 0) { 587 oldtype = gc->lg_val; 588 items[0].text = gc->lg_val; 589 } 590 if (strcmp(gc->lg_name, "label") == 0 && gc->lg_val != NULL) { 591 hadlabel = 1; 592 items[3].text = gc->lg_val; 593 } 594 if (strcmp(gc->lg_name, "index") == 0) 595 idx = atoi(gc->lg_val); 596 } 597 598 TAILQ_FOREACH(md, &part_metadata, metadata) { 599 if (md->name != NULL && strcmp(md->name, pp->lg_name) == 0) { 600 if (md->fstab != NULL) 601 items[2].text = md->fstab->fs_file; 602 break; 603 } 604 } 605 606 humanize_number(sizestr, 7, pp->lg_mediasize, "B", HN_AUTOSCALE, 607 HN_NOSPACE | HN_DECIMAL); 608 items[1].text = sizestr; 609 610 editpart: 611 choice = dlg_form("Edit Partition", "", 0, 0, 0, nitems, items, &junk); 612 613 if (choice) /* Cancel pressed */ 614 goto endedit; 615 616 /* If this is the root partition, check that this fs is bootable */ 617 if (strcmp(items[2].text, "/") == 0 && !is_fs_bootable(scheme, 618 items[0].text)) { 619 char message[512]; 620 sprintf(message, "This file system (%s) is not bootable " 621 "on this system. Are you sure you want to proceed?", 622 items[0].text); 623 dialog_vars.defaultno = TRUE; 624 choice = dialog_yesno("Warning", message, 0, 0); 625 dialog_vars.defaultno = FALSE; 626 if (choice == 1) /* cancel */ 627 goto editpart; 628 } 629 630 /* Check if the label has a / in it */ 631 if (strchr(items[3].text, '/') != NULL) { 632 dialog_msgbox("Error", "Label contains a /, which is not an " 633 "allowed character.", 0, 0, TRUE); 634 goto editpart; 635 } 636 637 r = gctl_get_handle(); 638 gctl_ro_param(r, "class", -1, "PART"); 639 gctl_ro_param(r, "arg0", -1, geom->lg_name); 640 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 641 gctl_ro_param(r, "verb", -1, "modify"); 642 gctl_ro_param(r, "index", sizeof(idx), &idx); 643 if (hadlabel || items[3].text[0] != '\0') 644 gctl_ro_param(r, "label", -1, items[3].text); 645 gctl_ro_param(r, "type", -1, items[0].text); 646 errstr = gctl_issue(r); 647 if (errstr != NULL && errstr[0] != '\0') { 648 gpart_show_error("Error", NULL, errstr); 649 gctl_free(r); 650 goto editpart; 651 } 652 gctl_free(r); 653 654 newfs_command(items[0].text, newfs, 1); 655 set_default_part_metadata(pp->lg_name, scheme, items[0].text, 656 items[2].text, (strcmp(oldtype, items[0].text) != 0) ? 657 newfs : NULL); 658 659 endedit: 660 if (strcmp(oldtype, items[0].text) != 0 && cp != NULL) 661 gpart_destroy(cp->lg_geom); 662 if (strcmp(oldtype, items[0].text) != 0 && strcmp(items[0].text, 663 "freebsd") == 0) 664 gpart_partition(pp->lg_name, "BSD"); 665 666 for (i = 0; i < nitems(items); i++) 667 if (items[i].text_free) 668 free(items[i].text); 669 } 670 671 void 672 set_default_part_metadata(const char *name, const char *scheme, 673 const char *type, const char *mountpoint, const char *newfs) 674 { 675 struct partition_metadata *md; 676 char *zpool_name = NULL; 677 const char *default_bootmount = NULL; 678 int i; 679 680 /* Set part metadata */ 681 md = get_part_metadata(name, 1); 682 683 if (newfs) { 684 if (md->newfs != NULL) { 685 free(md->newfs); 686 md->newfs = NULL; 687 } 688 689 if (newfs != NULL && newfs[0] != '\0') { 690 md->newfs = malloc(strlen(newfs) + strlen(" /dev/") + 691 strlen(mountpoint) + 5 + strlen(name) + 1); 692 if (strcmp("freebsd-zfs", type) == 0) { 693 zpool_name = strdup((strlen(mountpoint) == 1) ? 694 "root" : &mountpoint[1]); 695 for (i = 0; zpool_name[i] != 0; i++) 696 if (!isalnum(zpool_name[i])) 697 zpool_name[i] = '_'; 698 sprintf(md->newfs, "%s %s /dev/%s", newfs, 699 zpool_name, name); 700 } else { 701 sprintf(md->newfs, "%s /dev/%s", newfs, name); 702 } 703 } 704 } 705 706 if (strcmp(type, "freebsd-swap") == 0) 707 mountpoint = "none"; 708 if (strcmp(type, bootpart_type(scheme, &default_bootmount)) == 0) { 709 if (default_bootmount == NULL) 710 md->bootcode = 1; 711 else if (mountpoint == NULL || strlen(mountpoint) == 0) 712 mountpoint = default_bootmount; 713 } 714 715 /* VTOC8 needs partcode at the start of partitions */ 716 if (strcmp(scheme, "VTOC8") == 0 && (strcmp(type, "freebsd-ufs") == 0 717 || strcmp(type, "freebsd-zfs") == 0)) 718 md->bootcode = 1; 719 720 if (mountpoint == NULL || mountpoint[0] == '\0') { 721 if (md->fstab != NULL) { 722 free(md->fstab->fs_spec); 723 free(md->fstab->fs_file); 724 free(md->fstab->fs_vfstype); 725 free(md->fstab->fs_mntops); 726 free(md->fstab->fs_type); 727 free(md->fstab); 728 md->fstab = NULL; 729 } 730 } else { 731 if (md->fstab == NULL) { 732 md->fstab = malloc(sizeof(struct fstab)); 733 } else { 734 free(md->fstab->fs_spec); 735 free(md->fstab->fs_file); 736 free(md->fstab->fs_vfstype); 737 free(md->fstab->fs_mntops); 738 free(md->fstab->fs_type); 739 } 740 if (strcmp("freebsd-zfs", type) == 0) { 741 md->fstab->fs_spec = strdup(zpool_name); 742 } else { 743 md->fstab->fs_spec = malloc(strlen(name) + 744 strlen("/dev/") + 1); 745 sprintf(md->fstab->fs_spec, "/dev/%s", name); 746 } 747 md->fstab->fs_file = strdup(mountpoint); 748 /* Get VFS from text after freebsd-, if possible */ 749 if (strncmp("freebsd-", type, 8) == 0) 750 md->fstab->fs_vfstype = strdup(&type[8]); 751 else if (strcmp("fat32", type) == 0 || strcmp("efi", type) == 0 752 || strcmp("ms-basic-data", type) == 0) 753 md->fstab->fs_vfstype = strdup("msdosfs"); 754 else 755 md->fstab->fs_vfstype = strdup(type); /* Guess */ 756 if (strcmp(type, "freebsd-swap") == 0) { 757 md->fstab->fs_type = strdup(FSTAB_SW); 758 md->fstab->fs_freq = 0; 759 md->fstab->fs_passno = 0; 760 } else if (strcmp(type, "freebsd-zfs") == 0) { 761 md->fstab->fs_type = strdup(FSTAB_RW); 762 md->fstab->fs_freq = 0; 763 md->fstab->fs_passno = 0; 764 } else { 765 md->fstab->fs_type = strdup(FSTAB_RW); 766 if (strcmp(mountpoint, "/") == 0) { 767 md->fstab->fs_freq = 1; 768 md->fstab->fs_passno = 1; 769 } else { 770 md->fstab->fs_freq = 2; 771 md->fstab->fs_passno = 2; 772 } 773 } 774 md->fstab->fs_mntops = strdup(md->fstab->fs_type); 775 } 776 777 if (zpool_name != NULL) 778 free(zpool_name); 779 } 780 781 static 782 int part_compare(const void *xa, const void *xb) 783 { 784 struct gprovider **a = (struct gprovider **)xa; 785 struct gprovider **b = (struct gprovider **)xb; 786 intmax_t astart, bstart; 787 struct gconfig *gc; 788 789 astart = bstart = 0; 790 LIST_FOREACH(gc, &(*a)->lg_config, lg_config) 791 if (strcmp(gc->lg_name, "start") == 0) { 792 astart = strtoimax(gc->lg_val, NULL, 0); 793 break; 794 } 795 LIST_FOREACH(gc, &(*b)->lg_config, lg_config) 796 if (strcmp(gc->lg_name, "start") == 0) { 797 bstart = strtoimax(gc->lg_val, NULL, 0); 798 break; 799 } 800 801 if (astart < bstart) 802 return -1; 803 else if (astart > bstart) 804 return 1; 805 else 806 return 0; 807 } 808 809 intmax_t 810 gpart_max_free(struct ggeom *geom, intmax_t *npartstart) 811 { 812 struct gconfig *gc; 813 struct gprovider *pp, **providers; 814 intmax_t sectorsize, stripesize, offset; 815 intmax_t lastend; 816 intmax_t start, end; 817 intmax_t maxsize, maxstart; 818 intmax_t partstart, partend; 819 int i, nparts; 820 821 /* Now get the maximum free size and free start */ 822 start = end = 0; 823 LIST_FOREACH(gc, &geom->lg_config, lg_config) { 824 if (strcmp(gc->lg_name, "first") == 0) 825 start = strtoimax(gc->lg_val, NULL, 0); 826 if (strcmp(gc->lg_name, "last") == 0) 827 end = strtoimax(gc->lg_val, NULL, 0); 828 } 829 830 i = nparts = 0; 831 LIST_FOREACH(pp, &geom->lg_provider, lg_provider) 832 nparts++; 833 providers = calloc(nparts, sizeof(providers[0])); 834 LIST_FOREACH(pp, &geom->lg_provider, lg_provider) 835 providers[i++] = pp; 836 qsort(providers, nparts, sizeof(providers[0]), part_compare); 837 838 lastend = start - 1; 839 maxsize = 0; 840 for (i = 0; i < nparts; i++) { 841 pp = providers[i]; 842 843 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 844 if (strcmp(gc->lg_name, "start") == 0) 845 partstart = strtoimax(gc->lg_val, NULL, 0); 846 if (strcmp(gc->lg_name, "end") == 0) 847 partend = strtoimax(gc->lg_val, NULL, 0); 848 } 849 850 if (partstart - lastend > maxsize) { 851 maxsize = partstart - lastend - 1; 852 maxstart = lastend + 1; 853 } 854 855 lastend = partend; 856 } 857 858 if (end - lastend > maxsize) { 859 maxsize = end - lastend; 860 maxstart = lastend + 1; 861 } 862 863 pp = LIST_FIRST(&geom->lg_consumer)->lg_provider; 864 865 /* 866 * Round the start and size of the largest available space up to 867 * the nearest multiple of the adjusted stripe size. 868 * 869 * The adjusted stripe size is the least common multiple of the 870 * actual stripe size, or the sector size if no stripe size was 871 * reported, and 4096. The reason for this is that contemporary 872 * disks often have 4096-byte physical sectors but report 512 873 * bytes instead for compatibility with older / broken operating 874 * systems and BIOSes. For the same reasons, virtualized storage 875 * may also report a 512-byte stripe size, or none at all. 876 */ 877 sectorsize = pp->lg_sectorsize; 878 if ((stripesize = pp->lg_stripesize) == 0) 879 stripesize = sectorsize; 880 while (stripesize % 4096 != 0) 881 stripesize *= 2; 882 if ((offset = maxstart * sectorsize % stripesize) != 0) { 883 offset = (stripesize - offset) / sectorsize; 884 maxstart += offset; 885 maxsize -= offset; 886 } 887 888 if (npartstart != NULL) 889 *npartstart = maxstart; 890 891 return (maxsize); 892 } 893 894 static size_t 895 add_boot_partition(struct ggeom *geom, struct gprovider *pp, 896 const char *scheme, int interactive) 897 { 898 struct gconfig *gc; 899 struct gprovider *ppi; 900 int choice; 901 902 /* Check for existing freebsd-boot partition */ 903 LIST_FOREACH(ppi, &geom->lg_provider, lg_provider) { 904 struct partition_metadata *md; 905 const char *bootmount = NULL; 906 907 LIST_FOREACH(gc, &ppi->lg_config, lg_config) 908 if (strcmp(gc->lg_name, "type") == 0) 909 break; 910 if (gc == NULL) 911 continue; 912 if (strcmp(gc->lg_val, bootpart_type(scheme, &bootmount)) != 0) 913 continue; 914 915 /* 916 * If the boot partition is not mountable and needs partcode, 917 * but doesn't have it, it doesn't satisfy our requirements. 918 */ 919 md = get_part_metadata(ppi->lg_name, 0); 920 if (bootmount == NULL && (md == NULL || !md->bootcode)) 921 continue; 922 923 /* If it is mountable, but mounted somewhere else, remount */ 924 if (bootmount != NULL && md != NULL && md->fstab != NULL 925 && strlen(md->fstab->fs_file) > 0 926 && strcmp(md->fstab->fs_file, bootmount) != 0) 927 continue; 928 929 /* If it is mountable, but mountpoint is not set, mount it */ 930 if (bootmount != NULL && md == NULL) 931 set_default_part_metadata(ppi->lg_name, scheme, 932 gc->lg_val, bootmount, NULL); 933 934 /* Looks good at this point, no added data needed */ 935 return (0); 936 } 937 938 if (interactive) 939 choice = dialog_yesno("Boot Partition", 940 "This partition scheme requires a boot partition " 941 "for the disk to be bootable. Would you like to " 942 "make one now?", 0, 0); 943 else 944 choice = 0; 945 946 if (choice == 0) { /* yes */ 947 struct partition_metadata *md; 948 const char *bootmount = NULL; 949 char *bootpartname = NULL; 950 char sizestr[7]; 951 952 humanize_number(sizestr, 7, 953 bootpart_size(scheme), "B", HN_AUTOSCALE, 954 HN_NOSPACE | HN_DECIMAL); 955 956 gpart_create(pp, bootpart_type(scheme, &bootmount), 957 sizestr, bootmount, &bootpartname, 0); 958 959 if (bootpartname == NULL) /* Error reported to user already */ 960 return 0; 961 962 /* If the part is not mountable, make sure newfs isn't set */ 963 if (bootmount == NULL) { 964 md = get_part_metadata(bootpartname, 0); 965 if (md != NULL && md->newfs != NULL) { 966 free(md->newfs); 967 md->newfs = NULL; 968 } 969 } 970 971 free(bootpartname); 972 973 return (bootpart_size(scheme)); 974 } 975 976 return (0); 977 } 978 979 void 980 gpart_create(struct gprovider *pp, const char *default_type, 981 const char *default_size, const char *default_mountpoint, 982 char **partname, int interactive) 983 { 984 struct gctl_req *r; 985 struct gconfig *gc; 986 struct gconsumer *cp; 987 struct ggeom *geom; 988 const char *errstr, *scheme; 989 char sizestr[32], startstr[32], output[64], *newpartname; 990 char newfs[255], options_fstype[64]; 991 intmax_t maxsize, size, sector, firstfree, stripe; 992 uint64_t bytes; 993 int nitems, choice, junk; 994 unsigned i; 995 996 DIALOG_FORMITEM items[] = { 997 {0, "Type:", 5, 0, 0, FALSE, "freebsd-ufs", 11, 0, 12, 15, 0, 998 FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, " 999 "freebsd-swap)", FALSE}, 1000 {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 15, 0, 1001 FALSE, "Partition size. Append K, M, G for kilobytes, " 1002 "megabytes or gigabytes.", FALSE}, 1003 {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0, 1004 FALSE, "Path at which to mount partition (blank for " 1005 "swap, / for root filesystem)", FALSE}, 1006 {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE, 1007 "Partition name. Not all partition schemes support this.", 1008 FALSE}, 1009 }; 1010 1011 if (partname != NULL) 1012 *partname = NULL; 1013 1014 /* Record sector and stripe sizes */ 1015 sector = pp->lg_sectorsize; 1016 stripe = pp->lg_stripesize; 1017 1018 /* 1019 * Find the PART geom we are manipulating. This may be a consumer of 1020 * this provider, or its parent. Check the consumer case first. 1021 */ 1022 geom = NULL; 1023 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 1024 if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 1025 geom = cp->lg_geom; 1026 break; 1027 } 1028 1029 if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 1030 geom = pp->lg_geom; 1031 1032 /* Now get the partition scheme */ 1033 scheme = NULL; 1034 if (geom != NULL) { 1035 LIST_FOREACH(gc, &geom->lg_config, lg_config) 1036 if (strcmp(gc->lg_name, "scheme") == 0) 1037 scheme = gc->lg_val; 1038 } 1039 1040 if (geom == NULL || scheme == NULL || strcmp(scheme, "(none)") == 0) { 1041 if (gpart_partition(pp->lg_name, NULL) == 0) 1042 dialog_msgbox("", 1043 "The partition table has been successfully created." 1044 " Please press Create again to create partitions.", 1045 0, 0, TRUE); 1046 1047 return; 1048 } 1049 1050 /* 1051 * If we still don't have a geom, either the user has 1052 * canceled partitioning or there has been an error which has already 1053 * been displayed, so bail. 1054 */ 1055 if (geom == NULL) 1056 return; 1057 1058 maxsize = size = gpart_max_free(geom, &firstfree); 1059 if (size <= 0) { 1060 dialog_msgbox("Error", "No free space left on device.", 0, 0, 1061 TRUE); 1062 return; 1063 } 1064 1065 humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE, 1066 HN_NOSPACE | HN_DECIMAL); 1067 items[1].text = sizestr; 1068 1069 /* Special-case the MBR default type for nested partitions */ 1070 if (strcmp(scheme, "MBR") == 0) { 1071 items[0].text = "freebsd"; 1072 items[0].help = "Filesystem type (e.g. freebsd, fat32)"; 1073 } 1074 1075 nitems = scheme_supports_labels(scheme) ? 4 : 3; 1076 1077 if (default_type != NULL) 1078 items[0].text = (char *)default_type; 1079 if (default_size != NULL) 1080 items[1].text = (char *)default_size; 1081 if (default_mountpoint != NULL) 1082 items[2].text = (char *)default_mountpoint; 1083 1084 /* Default options */ 1085 strncpy(options_fstype, items[0].text, 1086 sizeof(options_fstype)); 1087 newfs_command(options_fstype, newfs, 1); 1088 addpartform: 1089 if (interactive) { 1090 dialog_vars.extra_label = "Options"; 1091 dialog_vars.extra_button = TRUE; 1092 choice = dlg_form("Add Partition", "", 0, 0, 0, nitems, 1093 items, &junk); 1094 dialog_vars.extra_button = FALSE; 1095 switch (choice) { 1096 case 0: /* OK */ 1097 break; 1098 case 1: /* Cancel */ 1099 return; 1100 case 3: /* Options */ 1101 strncpy(options_fstype, items[0].text, 1102 sizeof(options_fstype)); 1103 newfs_command(options_fstype, newfs, 0); 1104 goto addpartform; 1105 } 1106 } 1107 1108 /* 1109 * If the user changed the fs type after specifying options, undo 1110 * their choices in favor of the new filesystem's defaults. 1111 */ 1112 if (strcmp(options_fstype, items[0].text) != 0) { 1113 strncpy(options_fstype, items[0].text, sizeof(options_fstype)); 1114 newfs_command(options_fstype, newfs, 1); 1115 } 1116 1117 size = maxsize; 1118 if (strlen(items[1].text) > 0) { 1119 if (expand_number(items[1].text, &bytes) != 0) { 1120 char error[512]; 1121 1122 sprintf(error, "Invalid size: %s\n", strerror(errno)); 1123 dialog_msgbox("Error", error, 0, 0, TRUE); 1124 goto addpartform; 1125 } 1126 size = MIN((intmax_t)(bytes/sector), maxsize); 1127 } 1128 1129 /* Check if the label has a / in it */ 1130 if (strchr(items[3].text, '/') != NULL) { 1131 dialog_msgbox("Error", "Label contains a /, which is not an " 1132 "allowed character.", 0, 0, TRUE); 1133 goto addpartform; 1134 } 1135 1136 /* Warn if no mountpoint set */ 1137 if (strcmp(items[0].text, "freebsd-ufs") == 0 && 1138 items[2].text[0] != '/') { 1139 choice = 0; 1140 if (interactive) { 1141 dialog_vars.defaultno = TRUE; 1142 choice = dialog_yesno("Warning", 1143 "This partition does not have a valid mountpoint " 1144 "(for the partition from which you intend to boot the " 1145 "operating system, the mountpoint should be /). Are you " 1146 "sure you want to continue?" 1147 , 0, 0); 1148 dialog_vars.defaultno = FALSE; 1149 } 1150 if (choice == 1) /* cancel */ 1151 goto addpartform; 1152 } 1153 1154 /* 1155 * Error if this scheme needs nested partitions, this is one, and 1156 * a mountpoint was set. 1157 */ 1158 if (strcmp(items[0].text, "freebsd") == 0 && 1159 strlen(items[2].text) > 0) { 1160 dialog_msgbox("Error", "Partitions of type \"freebsd\" are " 1161 "nested BSD-type partition schemes and cannot have " 1162 "mountpoints. After creating one, select it and press " 1163 "Create again to add the actual file systems.", 0, 0, TRUE); 1164 goto addpartform; 1165 } 1166 1167 /* If this is the root partition, check that this scheme is bootable */ 1168 if (strcmp(items[2].text, "/") == 0 && !is_scheme_bootable(scheme)) { 1169 char message[512]; 1170 sprintf(message, "This partition scheme (%s) is not bootable " 1171 "on this platform. Are you sure you want to proceed?", 1172 scheme); 1173 dialog_vars.defaultno = TRUE; 1174 choice = dialog_yesno("Warning", message, 0, 0); 1175 dialog_vars.defaultno = FALSE; 1176 if (choice == 1) /* cancel */ 1177 goto addpartform; 1178 } 1179 1180 /* If this is the root partition, check that this fs is bootable */ 1181 if (strcmp(items[2].text, "/") == 0 && !is_fs_bootable(scheme, 1182 items[0].text)) { 1183 char message[512]; 1184 sprintf(message, "This file system (%s) is not bootable " 1185 "on this system. Are you sure you want to proceed?", 1186 items[0].text); 1187 dialog_vars.defaultno = TRUE; 1188 choice = dialog_yesno("Warning", message, 0, 0); 1189 dialog_vars.defaultno = FALSE; 1190 if (choice == 1) /* cancel */ 1191 goto addpartform; 1192 } 1193 1194 /* 1195 * If this is the root partition, and we need a boot partition, ask 1196 * the user to add one. 1197 */ 1198 1199 if ((strcmp(items[0].text, "freebsd") == 0 || 1200 strcmp(items[2].text, "/") == 0) && bootpart_size(scheme) > 0) { 1201 size_t bytes = add_boot_partition(geom, pp, scheme, 1202 interactive); 1203 1204 /* Now adjust the part we are really adding forward */ 1205 if (bytes > 0) { 1206 firstfree += bytes / sector; 1207 size -= (bytes + stripe)/sector; 1208 if (stripe > 0 && (firstfree*sector % stripe) != 0) 1209 firstfree += (stripe - ((firstfree*sector) % 1210 stripe)) / sector; 1211 } 1212 } 1213 1214 r = gctl_get_handle(); 1215 gctl_ro_param(r, "class", -1, "PART"); 1216 gctl_ro_param(r, "arg0", -1, geom->lg_name); 1217 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1218 gctl_ro_param(r, "verb", -1, "add"); 1219 1220 gctl_ro_param(r, "type", -1, items[0].text); 1221 snprintf(sizestr, sizeof(sizestr), "%jd", size); 1222 gctl_ro_param(r, "size", -1, sizestr); 1223 snprintf(startstr, sizeof(startstr), "%jd", firstfree); 1224 gctl_ro_param(r, "start", -1, startstr); 1225 if (items[3].text[0] != '\0') 1226 gctl_ro_param(r, "label", -1, items[3].text); 1227 gctl_rw_param(r, "output", sizeof(output), output); 1228 errstr = gctl_issue(r); 1229 if (errstr != NULL && errstr[0] != '\0') { 1230 gpart_show_error("Error", NULL, errstr); 1231 gctl_free(r); 1232 goto addpartform; 1233 } 1234 newpartname = strtok(output, " "); 1235 gctl_free(r); 1236 1237 /* 1238 * Try to destroy any geom that gpart picked up already here from 1239 * dirty blocks. 1240 */ 1241 r = gctl_get_handle(); 1242 gctl_ro_param(r, "class", -1, "PART"); 1243 gctl_ro_param(r, "arg0", -1, newpartname); 1244 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1245 junk = 1; 1246 gctl_ro_param(r, "force", sizeof(junk), &junk); 1247 gctl_ro_param(r, "verb", -1, "destroy"); 1248 gctl_issue(r); /* Error usually expected and non-fatal */ 1249 gctl_free(r); 1250 1251 1252 if (strcmp(items[0].text, "freebsd") == 0) 1253 gpart_partition(newpartname, "BSD"); 1254 else 1255 set_default_part_metadata(newpartname, scheme, 1256 items[0].text, items[2].text, newfs); 1257 1258 for (i = 0; i < nitems(items); i++) 1259 if (items[i].text_free) 1260 free(items[i].text); 1261 1262 if (partname != NULL) 1263 *partname = strdup(newpartname); 1264 } 1265 1266 void 1267 gpart_delete(struct gprovider *pp) 1268 { 1269 struct gconfig *gc; 1270 struct ggeom *geom; 1271 struct gconsumer *cp; 1272 struct gctl_req *r; 1273 const char *errstr; 1274 intmax_t idx; 1275 int is_partition; 1276 1277 /* Is it a partition? */ 1278 is_partition = (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0); 1279 1280 /* Find out if this is the root of a gpart geom */ 1281 geom = NULL; 1282 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 1283 if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 1284 geom = cp->lg_geom; 1285 break; 1286 } 1287 1288 /* If so, destroy all children */ 1289 if (geom != NULL) { 1290 gpart_destroy(geom); 1291 1292 /* If this is a partition, revert it, so it can be deleted */ 1293 if (is_partition) { 1294 r = gctl_get_handle(); 1295 gctl_ro_param(r, "class", -1, "PART"); 1296 gctl_ro_param(r, "arg0", -1, geom->lg_name); 1297 gctl_ro_param(r, "verb", -1, "undo"); 1298 gctl_issue(r); /* Ignore non-fatal errors */ 1299 gctl_free(r); 1300 } 1301 } 1302 1303 /* 1304 * If this is not a partition, see if that is a problem, complain if 1305 * necessary, and return always, since we need not do anything further, 1306 * error or no. 1307 */ 1308 if (!is_partition) { 1309 if (geom == NULL) 1310 dialog_msgbox("Error", 1311 "Only partitions can be deleted.", 0, 0, TRUE); 1312 return; 1313 } 1314 1315 r = gctl_get_handle(); 1316 gctl_ro_param(r, "class", -1, pp->lg_geom->lg_class->lg_name); 1317 gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name); 1318 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1319 gctl_ro_param(r, "verb", -1, "delete"); 1320 1321 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 1322 if (strcmp(gc->lg_name, "index") == 0) { 1323 idx = atoi(gc->lg_val); 1324 gctl_ro_param(r, "index", sizeof(idx), &idx); 1325 break; 1326 } 1327 } 1328 1329 errstr = gctl_issue(r); 1330 if (errstr != NULL && errstr[0] != '\0') { 1331 gpart_show_error("Error", NULL, errstr); 1332 gctl_free(r); 1333 return; 1334 } 1335 1336 gctl_free(r); 1337 1338 delete_part_metadata(pp->lg_name); 1339 } 1340 1341 void 1342 gpart_revert_all(struct gmesh *mesh) 1343 { 1344 struct gclass *classp; 1345 struct gconfig *gc; 1346 struct ggeom *gp; 1347 struct gctl_req *r; 1348 const char *modified; 1349 1350 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 1351 if (strcmp(classp->lg_name, "PART") == 0) 1352 break; 1353 } 1354 1355 if (strcmp(classp->lg_name, "PART") != 0) { 1356 dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE); 1357 return; 1358 } 1359 1360 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1361 modified = "true"; /* XXX: If we don't know (kernel too old), 1362 * assume there are modifications. */ 1363 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 1364 if (strcmp(gc->lg_name, "modified") == 0) { 1365 modified = gc->lg_val; 1366 break; 1367 } 1368 } 1369 1370 if (strcmp(modified, "false") == 0) 1371 continue; 1372 1373 r = gctl_get_handle(); 1374 gctl_ro_param(r, "class", -1, "PART"); 1375 gctl_ro_param(r, "arg0", -1, gp->lg_name); 1376 gctl_ro_param(r, "verb", -1, "undo"); 1377 1378 gctl_issue(r); 1379 gctl_free(r); 1380 } 1381 } 1382 1383 void 1384 gpart_commit(struct gmesh *mesh) 1385 { 1386 struct partition_metadata *md; 1387 struct gclass *classp; 1388 struct ggeom *gp; 1389 struct gconfig *gc; 1390 struct gconsumer *cp; 1391 struct gprovider *pp; 1392 struct gctl_req *r; 1393 const char *errstr; 1394 const char *modified; 1395 const char *rootfs; 1396 1397 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 1398 if (strcmp(classp->lg_name, "PART") == 0) 1399 break; 1400 } 1401 1402 /* Figure out what filesystem / uses */ 1403 rootfs = "ufs"; /* Assume ufs if nothing else present */ 1404 TAILQ_FOREACH(md, &part_metadata, metadata) { 1405 if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0) { 1406 rootfs = md->fstab->fs_vfstype; 1407 break; 1408 } 1409 } 1410 1411 if (strcmp(classp->lg_name, "PART") != 0) { 1412 dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE); 1413 return; 1414 } 1415 1416 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1417 modified = "true"; /* XXX: If we don't know (kernel too old), 1418 * assume there are modifications. */ 1419 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 1420 if (strcmp(gc->lg_name, "modified") == 0) { 1421 modified = gc->lg_val; 1422 break; 1423 } 1424 } 1425 1426 if (strcmp(modified, "false") == 0) 1427 continue; 1428 1429 /* Add bootcode if necessary, before the commit */ 1430 md = get_part_metadata(gp->lg_name, 0); 1431 if (md != NULL && md->bootcode) 1432 gpart_bootcode(gp); 1433 1434 /* Now install partcode on its partitions, if necessary */ 1435 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1436 md = get_part_metadata(pp->lg_name, 0); 1437 if (md == NULL || !md->bootcode) 1438 continue; 1439 1440 /* Mark this partition active if that's required */ 1441 gpart_activate(pp); 1442 1443 /* Check if the partition has sub-partitions */ 1444 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 1445 if (strcmp(cp->lg_geom->lg_class->lg_name, 1446 "PART") == 0) 1447 break; 1448 1449 if (cp == NULL) /* No sub-partitions */ 1450 gpart_partcode(pp, rootfs); 1451 } 1452 1453 r = gctl_get_handle(); 1454 gctl_ro_param(r, "class", -1, "PART"); 1455 gctl_ro_param(r, "arg0", -1, gp->lg_name); 1456 gctl_ro_param(r, "verb", -1, "commit"); 1457 1458 errstr = gctl_issue(r); 1459 if (errstr != NULL && errstr[0] != '\0') 1460 gpart_show_error("Error", NULL, errstr); 1461 gctl_free(r); 1462 } 1463 } 1464 1465