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