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