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.form.value_without_ok = true; 643 conf.title = "Edit Partition"; 644 choice = bsddialog_form(&conf, "", 0, 0, 0, nitems, items); 645 646 if (choice == BSDDIALOG_CANCEL) 647 goto endedit; 648 649 /* If this is the root partition, check that this fs is bootable */ 650 if (strcmp(items[2].value, "/") == 0 && !is_fs_bootable(scheme, 651 items[0].value)) { 652 char message[512]; 653 sprintf(message, "This file system (%s) is not bootable " 654 "on this system. Are you sure you want to proceed?", 655 items[0].value); 656 conf.button.default_cancel = true; 657 conf.title = "Warning"; 658 choice = bsddialog_yesno(&conf, message, 0, 0); 659 conf.button.default_cancel = false; 660 if (choice == BSDDIALOG_CANCEL) 661 goto editpart; 662 } 663 664 /* Check if the label has a / in it */ 665 if (items[3].value != NULL && strchr(items[3].value, '/') != NULL) { 666 conf.title = "Error"; 667 bsddialog_msgbox(&conf, "Label contains a /, which is not an " 668 "allowed character.", 0, 0); 669 goto editpart; 670 } 671 672 r = gctl_get_handle(); 673 gctl_ro_param(r, "class", -1, "PART"); 674 gctl_ro_param(r, "arg0", -1, geom->lg_name); 675 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 676 gctl_ro_param(r, "verb", -1, "modify"); 677 gctl_ro_param(r, "index", sizeof(idx), &idx); 678 if (items[3].value != NULL && (hadlabel || items[3].value[0] != '\0')) 679 gctl_ro_param(r, "label", -1, items[3].value); 680 gctl_ro_param(r, "type", -1, items[0].value); 681 errstr = gctl_issue(r); 682 if (errstr != NULL && errstr[0] != '\0') { 683 gpart_show_error("Error", NULL, errstr); 684 gctl_free(r); 685 goto editpart; 686 } 687 gctl_free(r); 688 689 newfs_command(items[0].value, newfs, 1); 690 set_default_part_metadata(pp->lg_name, scheme, items[0].value, 691 items[2].value, (strcmp(oldtype, items[0].value) != 0) ? 692 newfs : NULL); 693 694 endedit: 695 if (strcmp(oldtype, items[0].value) != 0 && cp != NULL) 696 gpart_destroy(cp->lg_geom); 697 if (strcmp(oldtype, items[0].value) != 0 && strcmp(items[0].value, 698 "freebsd") == 0) 699 gpart_partition(pp->lg_name, "BSD"); 700 701 for (i = 0; i < nitems(items); i++) 702 if (items[i].value != NULL) 703 free(items[i].value); 704 } 705 706 void 707 set_default_part_metadata(const char *name, const char *scheme, 708 const char *type, const char *mountpoint, const char *newfs) 709 { 710 struct partition_metadata *md; 711 char *zpool_name = NULL; 712 const char *default_bootmount = NULL; 713 int i; 714 715 /* Set part metadata */ 716 md = get_part_metadata(name, 1); 717 718 if (newfs) { 719 if (md->newfs != NULL) { 720 free(md->newfs); 721 md->newfs = NULL; 722 } 723 724 if (newfs != NULL && newfs[0] != '\0') { 725 md->newfs = malloc(strlen(newfs) + strlen(" /dev/") + 726 strlen(mountpoint) + 5 + strlen(name) + 1); 727 if (strcmp("freebsd-zfs", type) == 0) { 728 zpool_name = strdup((strlen(mountpoint) == 1) ? 729 "root" : &mountpoint[1]); 730 for (i = 0; zpool_name[i] != 0; i++) 731 if (!isalnum(zpool_name[i])) 732 zpool_name[i] = '_'; 733 sprintf(md->newfs, "%s %s /dev/%s", newfs, 734 zpool_name, name); 735 } else { 736 sprintf(md->newfs, "%s /dev/%s", newfs, name); 737 } 738 } 739 } 740 741 if (strcmp(type, "freebsd-swap") == 0) 742 mountpoint = "none"; 743 if (strcmp(type, bootpart_type(scheme, &default_bootmount)) == 0) { 744 if (default_bootmount == NULL) 745 md->bootcode = 1; 746 else if (mountpoint == NULL || strlen(mountpoint) == 0) 747 mountpoint = default_bootmount; 748 } 749 750 if (mountpoint == NULL || mountpoint[0] == '\0') { 751 if (md->fstab != NULL) { 752 free(md->fstab->fs_spec); 753 free(md->fstab->fs_file); 754 free(md->fstab->fs_vfstype); 755 free(md->fstab->fs_mntops); 756 free(md->fstab->fs_type); 757 free(md->fstab); 758 md->fstab = NULL; 759 } 760 } else { 761 if (md->fstab == NULL) { 762 md->fstab = malloc(sizeof(struct fstab)); 763 } else { 764 free(md->fstab->fs_spec); 765 free(md->fstab->fs_file); 766 free(md->fstab->fs_vfstype); 767 free(md->fstab->fs_mntops); 768 free(md->fstab->fs_type); 769 } 770 if (strcmp("freebsd-zfs", type) == 0) { 771 md->fstab->fs_spec = strdup(zpool_name); 772 } else { 773 md->fstab->fs_spec = malloc(strlen(name) + 774 strlen("/dev/") + 1); 775 sprintf(md->fstab->fs_spec, "/dev/%s", name); 776 } 777 md->fstab->fs_file = strdup(mountpoint); 778 /* Get VFS from text after freebsd-, if possible */ 779 if (strncmp("freebsd-", type, 8) == 0) 780 md->fstab->fs_vfstype = strdup(&type[8]); 781 else if (strcmp("fat32", type) == 0 || strcmp("efi", type) == 0 782 || strcmp("ms-basic-data", type) == 0) 783 md->fstab->fs_vfstype = strdup("msdosfs"); 784 else 785 md->fstab->fs_vfstype = strdup(type); /* Guess */ 786 if (strcmp(type, "freebsd-swap") == 0) { 787 md->fstab->fs_type = strdup(FSTAB_SW); 788 md->fstab->fs_freq = 0; 789 md->fstab->fs_passno = 0; 790 } else if (strcmp(type, "freebsd-zfs") == 0) { 791 md->fstab->fs_type = strdup(FSTAB_RW); 792 md->fstab->fs_freq = 0; 793 md->fstab->fs_passno = 0; 794 } else { 795 md->fstab->fs_type = strdup(FSTAB_RW); 796 if (strcmp(mountpoint, "/") == 0) { 797 md->fstab->fs_freq = 1; 798 md->fstab->fs_passno = 1; 799 } else { 800 md->fstab->fs_freq = 2; 801 md->fstab->fs_passno = 2; 802 } 803 } 804 md->fstab->fs_mntops = strdup(md->fstab->fs_type); 805 } 806 807 if (zpool_name != NULL) 808 free(zpool_name); 809 } 810 811 static 812 int part_compare(const void *xa, const void *xb) 813 { 814 struct gprovider **a = (struct gprovider **)xa; 815 struct gprovider **b = (struct gprovider **)xb; 816 intmax_t astart, bstart; 817 struct gconfig *gc; 818 819 astart = bstart = 0; 820 LIST_FOREACH(gc, &(*a)->lg_config, lg_config) 821 if (strcmp(gc->lg_name, "start") == 0) { 822 astart = strtoimax(gc->lg_val, NULL, 0); 823 break; 824 } 825 LIST_FOREACH(gc, &(*b)->lg_config, lg_config) 826 if (strcmp(gc->lg_name, "start") == 0) { 827 bstart = strtoimax(gc->lg_val, NULL, 0); 828 break; 829 } 830 831 if (astart < bstart) 832 return -1; 833 else if (astart > bstart) 834 return 1; 835 else 836 return 0; 837 } 838 839 intmax_t 840 gpart_max_free(struct ggeom *geom, intmax_t *npartstart) 841 { 842 struct gconfig *gc; 843 struct gprovider *pp, **providers; 844 intmax_t sectorsize, stripesize, offset; 845 intmax_t lastend; 846 intmax_t start, end; 847 intmax_t maxsize, maxstart; 848 intmax_t partstart, partend; 849 int i, nparts; 850 851 /* Now get the maximum free size and free start */ 852 start = end = 0; 853 LIST_FOREACH(gc, &geom->lg_config, lg_config) { 854 if (strcmp(gc->lg_name, "first") == 0) 855 start = strtoimax(gc->lg_val, NULL, 0); 856 if (strcmp(gc->lg_name, "last") == 0) 857 end = strtoimax(gc->lg_val, NULL, 0); 858 } 859 860 i = nparts = 0; 861 LIST_FOREACH(pp, &geom->lg_provider, lg_provider) 862 nparts++; 863 providers = calloc(nparts, sizeof(providers[0])); 864 LIST_FOREACH(pp, &geom->lg_provider, lg_provider) 865 providers[i++] = pp; 866 qsort(providers, nparts, sizeof(providers[0]), part_compare); 867 868 lastend = start - 1; 869 maxsize = 0; 870 for (i = 0; i < nparts; i++) { 871 pp = providers[i]; 872 873 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 874 if (strcmp(gc->lg_name, "start") == 0) 875 partstart = strtoimax(gc->lg_val, NULL, 0); 876 if (strcmp(gc->lg_name, "end") == 0) 877 partend = strtoimax(gc->lg_val, NULL, 0); 878 } 879 880 if (partstart - lastend > maxsize) { 881 maxsize = partstart - lastend - 1; 882 maxstart = lastend + 1; 883 } 884 885 lastend = partend; 886 } 887 888 if (end - lastend > maxsize) { 889 maxsize = end - lastend; 890 maxstart = lastend + 1; 891 } 892 893 pp = LIST_FIRST(&geom->lg_consumer)->lg_provider; 894 895 /* 896 * Round the start and size of the largest available space up to 897 * the nearest multiple of the adjusted stripe size. 898 * 899 * The adjusted stripe size is the least common multiple of the 900 * actual stripe size, or the sector size if no stripe size was 901 * reported, and 4096. The reason for this is that contemporary 902 * disks often have 4096-byte physical sectors but report 512 903 * bytes instead for compatibility with older / broken operating 904 * systems and BIOSes. For the same reasons, virtualized storage 905 * may also report a 512-byte stripe size, or none at all. 906 */ 907 sectorsize = pp->lg_sectorsize; 908 if ((stripesize = pp->lg_stripesize) == 0) 909 stripesize = sectorsize; 910 while (stripesize % 4096 != 0) 911 stripesize *= 2; 912 if ((offset = maxstart * sectorsize % stripesize) != 0) { 913 offset = (stripesize - offset) / sectorsize; 914 maxstart += offset; 915 maxsize -= offset; 916 } 917 918 if (npartstart != NULL) 919 *npartstart = maxstart; 920 921 return (maxsize); 922 } 923 924 static size_t 925 add_boot_partition(struct ggeom *geom, struct gprovider *pp, 926 const char *scheme, int interactive) 927 { 928 struct gconfig *gc; 929 struct gprovider *ppi; 930 int choice; 931 struct bsddialog_conf conf; 932 933 /* Check for existing freebsd-boot partition */ 934 LIST_FOREACH(ppi, &geom->lg_provider, lg_provider) { 935 struct partition_metadata *md; 936 const char *bootmount = NULL; 937 938 LIST_FOREACH(gc, &ppi->lg_config, lg_config) 939 if (strcmp(gc->lg_name, "type") == 0) 940 break; 941 if (gc == NULL) 942 continue; 943 if (strcmp(gc->lg_val, bootpart_type(scheme, &bootmount)) != 0) 944 continue; 945 946 /* 947 * If the boot partition is not mountable and needs partcode, 948 * but doesn't have it, it doesn't satisfy our requirements. 949 */ 950 md = get_part_metadata(ppi->lg_name, 0); 951 if (bootmount == NULL && (md == NULL || !md->bootcode)) 952 continue; 953 954 /* If it is mountable, but mounted somewhere else, remount */ 955 if (bootmount != NULL && md != NULL && md->fstab != NULL 956 && strlen(md->fstab->fs_file) > 0 957 && strcmp(md->fstab->fs_file, bootmount) != 0) 958 continue; 959 960 /* If it is mountable, but mountpoint is not set, mount it */ 961 if (bootmount != NULL && md == NULL) 962 set_default_part_metadata(ppi->lg_name, scheme, 963 gc->lg_val, bootmount, NULL); 964 965 /* Looks good at this point, no added data needed */ 966 return (0); 967 } 968 969 if (interactive) { 970 bsddialog_initconf(&conf); 971 conf.title = "Boot Partition"; 972 choice = bsddialog_yesno(&conf, 973 "This partition scheme requires a boot partition " 974 "for the disk to be bootable. Would you like to " 975 "make one now?", 0, 0); 976 } else { 977 choice = BSDDIALOG_YES; 978 } 979 980 if (choice == BSDDIALOG_YES) { 981 struct partition_metadata *md; 982 const char *bootmount = NULL; 983 char *bootpartname = NULL; 984 char sizestr[7]; 985 986 humanize_number(sizestr, 7, 987 bootpart_size(scheme), "B", HN_AUTOSCALE, 988 HN_NOSPACE | HN_DECIMAL); 989 990 gpart_create(pp, bootpart_type(scheme, &bootmount), 991 sizestr, bootmount, &bootpartname, 0); 992 993 if (bootpartname == NULL) /* Error reported to user already */ 994 return 0; 995 996 /* If the part is not mountable, make sure newfs isn't set */ 997 if (bootmount == NULL) { 998 md = get_part_metadata(bootpartname, 0); 999 if (md != NULL && md->newfs != NULL) { 1000 free(md->newfs); 1001 md->newfs = NULL; 1002 } 1003 } 1004 1005 free(bootpartname); 1006 1007 return (bootpart_size(scheme)); 1008 } 1009 1010 return (0); 1011 } 1012 1013 void 1014 gpart_create(struct gprovider *pp, const char *default_type, 1015 const char *default_size, const char *default_mountpoint, 1016 char **partname, int interactive) 1017 { 1018 struct gctl_req *r; 1019 struct gconfig *gc; 1020 struct gconsumer *cp; 1021 struct ggeom *geom; 1022 const char *errstr, *scheme; 1023 char sizestr[32], startstr[32], output[64], *newpartname; 1024 char newfs[255], options_fstype[64]; 1025 intmax_t maxsize, size, sector, firstfree, stripe; 1026 uint64_t bytes; 1027 int nitems, choice, junk; 1028 unsigned i; 1029 bool init_allocated; 1030 struct bsddialog_conf conf; 1031 1032 struct bsddialog_formitem items[] = { 1033 {"Type:", 1, 1, "freebsd-ufs", 1, 12, 12, 15, NULL, 0, 1034 "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, " 1035 "freebsd-swap)"}, 1036 {"Size:", 2, 1, "", 2, 12, 12, 15, NULL, 0, 1037 "Partition size. Append K, M, G for kilobytes, " 1038 "megabytes or gigabytes."}, 1039 {"Mountpoint:", 3, 1, "", 3, 12, 12, 15, NULL, 0, 1040 "Path at which to mount partition (blank for " 1041 "swap, / for root filesystem)"}, 1042 {"Label:", 4, 1, "", 4, 12, 12, 15, NULL, 0, 1043 "Partition name. Not all partition schemes support this."}, 1044 }; 1045 1046 bsddialog_initconf(&conf); 1047 1048 if (partname != NULL) 1049 *partname = NULL; 1050 1051 /* Record sector and stripe sizes */ 1052 sector = pp->lg_sectorsize; 1053 stripe = pp->lg_stripesize; 1054 1055 /* 1056 * Find the PART geom we are manipulating. This may be a consumer of 1057 * this provider, or its parent. Check the consumer case first. 1058 */ 1059 geom = NULL; 1060 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 1061 if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 1062 geom = cp->lg_geom; 1063 break; 1064 } 1065 1066 if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0) 1067 geom = pp->lg_geom; 1068 1069 /* Now get the partition scheme */ 1070 scheme = NULL; 1071 if (geom != NULL) { 1072 LIST_FOREACH(gc, &geom->lg_config, lg_config) 1073 if (strcmp(gc->lg_name, "scheme") == 0) 1074 scheme = gc->lg_val; 1075 } 1076 1077 if (geom == NULL || scheme == NULL || strcmp(scheme, "(none)") == 0) { 1078 if (gpart_partition(pp->lg_name, NULL) == 0) { 1079 bsddialog_msgbox(&conf, 1080 "The partition table has been successfully created." 1081 " Please press Create again to create partitions.", 1082 0, 0); 1083 } 1084 1085 return; 1086 } 1087 1088 /* 1089 * If we still don't have a geom, either the user has 1090 * canceled partitioning or there has been an error which has already 1091 * been displayed, so bail. 1092 */ 1093 if (geom == NULL) 1094 return; 1095 1096 maxsize = size = gpart_max_free(geom, &firstfree); 1097 if (size <= 0) { 1098 conf .title = "Error"; 1099 bsddialog_msgbox(&conf, "No free space left on device.", 0, 0); 1100 return; 1101 } 1102 1103 humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE, 1104 HN_NOSPACE | HN_DECIMAL); 1105 items[1].init = sizestr; 1106 1107 /* Special-case the MBR default type for nested partitions */ 1108 if (strcmp(scheme, "MBR") == 0) { 1109 items[0].init = "freebsd"; 1110 items[0].bottomdesc = "Filesystem type (e.g. freebsd, fat32)"; 1111 } 1112 1113 nitems = scheme_supports_labels(scheme) ? 4 : 3; 1114 1115 if (default_type != NULL) 1116 items[0].init = (char *)default_type; 1117 if (default_size != NULL) 1118 items[1].init = (char *)default_size; 1119 if (default_mountpoint != NULL) 1120 items[2].init = (char *)default_mountpoint; 1121 1122 /* Default options */ 1123 strncpy(options_fstype, items[0].init, 1124 sizeof(options_fstype)); 1125 newfs_command(options_fstype, newfs, 1); 1126 1127 init_allocated = false; 1128 addpartform: 1129 if (interactive) { 1130 conf.button.with_extra = true; 1131 conf.button.extra_label = "Options"; 1132 conf.form.value_without_ok = true; 1133 conf.title = "Add Partition"; 1134 choice = bsddialog_form(&conf, "", 0, 0, 0, nitems, items); 1135 conf.button.with_extra = false; 1136 conf.button.extra_label = NULL; 1137 conf.form.value_without_ok = false; 1138 switch (choice) { 1139 case BSDDIALOG_OK: 1140 break; 1141 case BSDDIALOG_CANCEL: 1142 return; 1143 case BSDDIALOG_EXTRA: /* Options */ 1144 strncpy(options_fstype, items[0].value, 1145 sizeof(options_fstype)); 1146 newfs_command(options_fstype, newfs, 0); 1147 for (i = 0; i < nitems(items); i++) { 1148 if (init_allocated) 1149 free((char*)items[i].init); 1150 items[i].init = items[i].value; 1151 } 1152 init_allocated = true; 1153 goto addpartform; 1154 } 1155 } else { /* auto partitioning */ 1156 items[0].value = strdup(items[0].init); 1157 items[1].value = strdup(items[1].init); 1158 items[2].value = strdup(items[2].init); 1159 if (nitems > 3) 1160 items[3].value = strdup(items[3].init); 1161 } 1162 1163 /* 1164 * If the user changed the fs type after specifying options, undo 1165 * their choices in favor of the new filesystem's defaults. 1166 */ 1167 if (strcmp(options_fstype, items[0].value) != 0) { 1168 strncpy(options_fstype, items[0].value, sizeof(options_fstype)); 1169 newfs_command(options_fstype, newfs, 1); 1170 } 1171 1172 size = maxsize; 1173 if (strlen(items[1].value) > 0) { 1174 if (expand_number(items[1].value, &bytes) != 0) { 1175 char error[512]; 1176 1177 sprintf(error, "Invalid size: %s\n", strerror(errno)); 1178 conf.title = "Error"; 1179 bsddialog_msgbox(&conf, error, 0, 0); 1180 goto addpartform; 1181 } 1182 size = MIN((intmax_t)(bytes/sector), maxsize); 1183 } 1184 1185 /* Check if the label has a / in it */ 1186 if (items[3].value != NULL && strchr(items[3].value, '/') != NULL) { 1187 conf.title = "Error"; 1188 bsddialog_msgbox(&conf, "Label contains a /, which is not an " 1189 "allowed character.", 0, 0); 1190 goto addpartform; 1191 } 1192 1193 /* Warn if no mountpoint set */ 1194 if (strcmp(items[0].value, "freebsd-ufs") == 0 && 1195 items[2].value[0] != '/') { 1196 choice = 0; 1197 if (interactive) { 1198 conf.button.default_cancel = true; 1199 conf.title = "Warning"; 1200 choice = bsddialog_yesno(&conf, 1201 "This partition does not have a valid mountpoint " 1202 "(for the partition from which you intend to boot the " 1203 "operating system, the mountpoint should be /). Are you " 1204 "sure you want to continue?" 1205 , 0, 0); 1206 conf.button.default_cancel = false; 1207 } 1208 if (choice == BSDDIALOG_CANCEL) 1209 goto addpartform; 1210 } 1211 1212 /* 1213 * Error if this scheme needs nested partitions, this is one, and 1214 * a mountpoint was set. 1215 */ 1216 if (strcmp(items[0].value, "freebsd") == 0 && 1217 strlen(items[2].value) > 0) { 1218 conf.title = "Error"; 1219 bsddialog_msgbox(&conf, "Partitions of type \"freebsd\" are " 1220 "nested BSD-type partition schemes and cannot have " 1221 "mountpoints. After creating one, select it and press " 1222 "Create again to add the actual file systems.", 0, 0); 1223 goto addpartform; 1224 } 1225 1226 /* If this is the root partition, check that this scheme is bootable */ 1227 if (strcmp(items[2].value, "/") == 0 && !is_scheme_bootable(scheme)) { 1228 char message[512]; 1229 sprintf(message, "This partition scheme (%s) is not bootable " 1230 "on this platform. Are you sure you want to proceed?", 1231 scheme); 1232 conf.button.default_cancel = true; 1233 conf.title = "Warning"; 1234 choice = bsddialog_yesno(&conf, message, 0, 0); 1235 conf.button.default_cancel = false; 1236 if (choice == BSDDIALOG_CANCEL) 1237 goto addpartform; 1238 } 1239 1240 /* If this is the root partition, check that this fs is bootable */ 1241 if (strcmp(items[2].value, "/") == 0 && !is_fs_bootable(scheme, 1242 items[0].value)) { 1243 char message[512]; 1244 sprintf(message, "This file system (%s) is not bootable " 1245 "on this system. Are you sure you want to proceed?", 1246 items[0].value); 1247 conf.button.default_cancel = true; 1248 conf.title = "Warning"; 1249 choice = bsddialog_yesno(&conf, message, 0, 0); 1250 conf.button.default_cancel = false; 1251 if (choice == BSDDIALOG_CANCEL) 1252 goto addpartform; 1253 } 1254 1255 /* 1256 * If this is the root partition, and we need a boot partition, ask 1257 * the user to add one. 1258 */ 1259 1260 if ((strcmp(items[0].value, "freebsd") == 0 || 1261 strcmp(items[2].value, "/") == 0) && bootpart_size(scheme) > 0) { 1262 size_t bytes = add_boot_partition(geom, pp, scheme, 1263 interactive); 1264 1265 /* Now adjust the part we are really adding forward */ 1266 if (bytes > 0) { 1267 firstfree += bytes / sector; 1268 size -= (bytes + stripe)/sector; 1269 if (stripe > 0 && (firstfree*sector % stripe) != 0) 1270 firstfree += (stripe - ((firstfree*sector) % 1271 stripe)) / sector; 1272 } 1273 } 1274 1275 output[0] = '\0'; 1276 1277 r = gctl_get_handle(); 1278 gctl_ro_param(r, "class", -1, "PART"); 1279 gctl_ro_param(r, "arg0", -1, geom->lg_name); 1280 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1281 gctl_ro_param(r, "verb", -1, "add"); 1282 1283 gctl_ro_param(r, "type", -1, items[0].value); 1284 snprintf(sizestr, sizeof(sizestr), "%jd", size); 1285 gctl_ro_param(r, "size", -1, sizestr); 1286 snprintf(startstr, sizeof(startstr), "%jd", firstfree); 1287 gctl_ro_param(r, "start", -1, startstr); 1288 if (items[3].value != NULL && items[3].value[0] != '\0') 1289 gctl_ro_param(r, "label", -1, items[3].value); 1290 gctl_add_param(r, "output", sizeof(output), output, 1291 GCTL_PARAM_WR | GCTL_PARAM_ASCII); 1292 errstr = gctl_issue(r); 1293 if (errstr != NULL && errstr[0] != '\0') { 1294 gpart_show_error("Error", NULL, errstr); 1295 gctl_free(r); 1296 goto addpartform; 1297 } 1298 newpartname = strtok(output, " "); 1299 gctl_free(r); 1300 1301 /* 1302 * Try to destroy any geom that gpart picked up already here from 1303 * dirty blocks. 1304 */ 1305 r = gctl_get_handle(); 1306 gctl_ro_param(r, "class", -1, "PART"); 1307 gctl_ro_param(r, "arg0", -1, newpartname); 1308 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1309 junk = 1; 1310 gctl_ro_param(r, "force", sizeof(junk), &junk); 1311 gctl_ro_param(r, "verb", -1, "destroy"); 1312 gctl_issue(r); /* Error usually expected and non-fatal */ 1313 gctl_free(r); 1314 1315 1316 if (strcmp(items[0].value, "freebsd") == 0) 1317 gpart_partition(newpartname, "BSD"); 1318 else 1319 set_default_part_metadata(newpartname, scheme, 1320 items[0].value, items[2].value, newfs); 1321 1322 for (i = 0; i < nitems(items); i++) { 1323 if (items[i].value != NULL) { 1324 free(items[i].value); 1325 if (init_allocated && items[i].init != NULL) 1326 free((char*)items[i].init); 1327 } 1328 } 1329 1330 if (partname != NULL) 1331 *partname = strdup(newpartname); 1332 } 1333 1334 void 1335 gpart_delete(struct gprovider *pp) 1336 { 1337 struct gconfig *gc; 1338 struct ggeom *geom; 1339 struct gconsumer *cp; 1340 struct gctl_req *r; 1341 const char *errstr; 1342 intmax_t idx; 1343 int is_partition; 1344 struct bsddialog_conf conf; 1345 1346 /* Is it a partition? */ 1347 is_partition = (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0); 1348 1349 /* Find out if this is the root of a gpart geom */ 1350 geom = NULL; 1351 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 1352 if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) { 1353 geom = cp->lg_geom; 1354 break; 1355 } 1356 1357 /* If so, destroy all children */ 1358 if (geom != NULL) { 1359 gpart_destroy(geom); 1360 1361 /* If this is a partition, revert it, so it can be deleted */ 1362 if (is_partition) { 1363 r = gctl_get_handle(); 1364 gctl_ro_param(r, "class", -1, "PART"); 1365 gctl_ro_param(r, "arg0", -1, geom->lg_name); 1366 gctl_ro_param(r, "verb", -1, "undo"); 1367 gctl_issue(r); /* Ignore non-fatal errors */ 1368 gctl_free(r); 1369 } 1370 } 1371 1372 /* 1373 * If this is not a partition, see if that is a problem, complain if 1374 * necessary, and return always, since we need not do anything further, 1375 * error or no. 1376 */ 1377 if (!is_partition) { 1378 if (geom == NULL) { 1379 bsddialog_initconf(&conf); 1380 conf.title = "Error"; 1381 bsddialog_msgbox(&conf, 1382 "Only partitions can be deleted.", 0, 0); 1383 } 1384 return; 1385 } 1386 1387 r = gctl_get_handle(); 1388 gctl_ro_param(r, "class", -1, pp->lg_geom->lg_class->lg_name); 1389 gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name); 1390 gctl_ro_param(r, "flags", -1, GPART_FLAGS); 1391 gctl_ro_param(r, "verb", -1, "delete"); 1392 1393 LIST_FOREACH(gc, &pp->lg_config, lg_config) { 1394 if (strcmp(gc->lg_name, "index") == 0) { 1395 idx = atoi(gc->lg_val); 1396 gctl_ro_param(r, "index", sizeof(idx), &idx); 1397 break; 1398 } 1399 } 1400 1401 errstr = gctl_issue(r); 1402 if (errstr != NULL && errstr[0] != '\0') { 1403 gpart_show_error("Error", NULL, errstr); 1404 gctl_free(r); 1405 return; 1406 } 1407 1408 gctl_free(r); 1409 1410 delete_part_metadata(pp->lg_name); 1411 } 1412 1413 void 1414 gpart_revert_all(struct gmesh *mesh) 1415 { 1416 struct gclass *classp; 1417 struct gconfig *gc; 1418 struct ggeom *gp; 1419 struct gctl_req *r; 1420 const char *modified; 1421 struct bsddialog_conf conf; 1422 1423 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 1424 if (strcmp(classp->lg_name, "PART") == 0) 1425 break; 1426 } 1427 1428 if (strcmp(classp->lg_name, "PART") != 0) { 1429 bsddialog_initconf(&conf); 1430 conf.title = "Error"; 1431 bsddialog_msgbox(&conf, "gpart not found!", 0, 0); 1432 return; 1433 } 1434 1435 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1436 modified = "true"; /* XXX: If we don't know (kernel too old), 1437 * assume there are modifications. */ 1438 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 1439 if (strcmp(gc->lg_name, "modified") == 0) { 1440 modified = gc->lg_val; 1441 break; 1442 } 1443 } 1444 1445 if (strcmp(modified, "false") == 0) 1446 continue; 1447 1448 r = gctl_get_handle(); 1449 gctl_ro_param(r, "class", -1, "PART"); 1450 gctl_ro_param(r, "arg0", -1, gp->lg_name); 1451 gctl_ro_param(r, "verb", -1, "undo"); 1452 1453 gctl_issue(r); 1454 gctl_free(r); 1455 } 1456 } 1457 1458 void 1459 gpart_commit(struct gmesh *mesh) 1460 { 1461 struct partition_metadata *md; 1462 struct gclass *classp; 1463 struct ggeom *gp; 1464 struct gconfig *gc; 1465 struct gconsumer *cp; 1466 struct gprovider *pp; 1467 struct gctl_req *r; 1468 const char *errstr; 1469 const char *modified; 1470 const char *rootfs; 1471 struct bsddialog_conf conf; 1472 1473 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 1474 if (strcmp(classp->lg_name, "PART") == 0) 1475 break; 1476 } 1477 1478 /* Figure out what filesystem / uses */ 1479 rootfs = "ufs"; /* Assume ufs if nothing else present */ 1480 TAILQ_FOREACH(md, &part_metadata, metadata) { 1481 if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0) { 1482 rootfs = md->fstab->fs_vfstype; 1483 break; 1484 } 1485 } 1486 1487 if (strcmp(classp->lg_name, "PART") != 0) { 1488 bsddialog_initconf(&conf); 1489 conf.title = "Error"; 1490 bsddialog_msgbox(&conf, "gpart not found!", 0, 0); 1491 return; 1492 } 1493 1494 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1495 modified = "true"; /* XXX: If we don't know (kernel too old), 1496 * assume there are modifications. */ 1497 LIST_FOREACH(gc, &gp->lg_config, lg_config) { 1498 if (strcmp(gc->lg_name, "modified") == 0) { 1499 modified = gc->lg_val; 1500 break; 1501 } 1502 } 1503 1504 if (strcmp(modified, "false") == 0) 1505 continue; 1506 1507 /* Add bootcode if necessary, before the commit */ 1508 md = get_part_metadata(gp->lg_name, 0); 1509 if (md != NULL && md->bootcode) 1510 gpart_bootcode(gp); 1511 1512 /* Now install partcode on its partitions, if necessary */ 1513 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 1514 md = get_part_metadata(pp->lg_name, 0); 1515 if (md == NULL || !md->bootcode) 1516 continue; 1517 1518 /* Mark this partition active if that's required */ 1519 gpart_activate(pp); 1520 1521 /* Check if the partition has sub-partitions */ 1522 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers) 1523 if (strcmp(cp->lg_geom->lg_class->lg_name, 1524 "PART") == 0) 1525 break; 1526 1527 if (cp == NULL) /* No sub-partitions */ 1528 gpart_partcode(pp, rootfs); 1529 } 1530 1531 r = gctl_get_handle(); 1532 gctl_ro_param(r, "class", -1, "PART"); 1533 gctl_ro_param(r, "arg0", -1, gp->lg_name); 1534 gctl_ro_param(r, "verb", -1, "commit"); 1535 1536 errstr = gctl_issue(r); 1537 if (errstr != NULL && errstr[0] != '\0') 1538 gpart_show_error("Error", NULL, errstr); 1539 gctl_free(r); 1540 } 1541 } 1542 1543