1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * Neither the name of the DragonFly Project nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 * OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * fn_subpart_hammer.c 36 * Installer Function : Create HAMMER Subpartitions. 37 */ 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 #ifdef ENABLE_NLS 44 #include <libintl.h> 45 #define _(String) gettext (String) 46 #else 47 #define _(String) (String) 48 #endif 49 50 #include "libaura/mem.h" 51 #include "libaura/buffer.h" 52 #include "libaura/dict.h" 53 #include "libaura/fspred.h" 54 55 #include "libdfui/dfui.h" 56 #include "libdfui/dump.h" 57 #include "libdfui/system.h" 58 59 #include "libinstaller/commands.h" 60 #include "libinstaller/diskutil.h" 61 #include "libinstaller/functions.h" 62 #include "libinstaller/uiutil.h" 63 64 #include "fn.h" 65 #include "flow.h" 66 #include "pathnames.h" 67 68 static int create_subpartitions(struct i_fn_args *); 69 static long default_capacity(struct storage *, const char *); 70 static int check_capacity(struct i_fn_args *); 71 static int check_subpartition_selections(struct dfui_response *, struct i_fn_args *); 72 static void save_subpartition_selections(struct dfui_response *, struct i_fn_args *); 73 static void populate_create_subpartitions_form(struct dfui_form *, struct i_fn_args *); 74 static int warn_subpartition_selections(struct i_fn_args *); 75 static int warn_encrypted_boot(struct i_fn_args *); 76 static struct dfui_form *make_create_subpartitions_form(struct i_fn_args *); 77 static int show_create_subpartitions_form(struct dfui_form *, struct i_fn_args *); 78 79 static const char *def_mountpt[] = {"/boot", "swap", "/", NULL}; 80 static int expert = 0; 81 82 /* 83 * Given a set of subpartitions-to-be in the selected slice, 84 * create them. 85 */ 86 static int 87 create_subpartitions(struct i_fn_args *a) 88 { 89 struct subpartition *sp; 90 struct commands *cmds; 91 int result = 0; 92 int num_partitions; 93 94 cmds = commands_new(); 95 if (!is_file("%sinstall.disklabel.%s", 96 a->tmp, 97 slice_get_device_name(storage_get_selected_slice(a->s)))) { 98 /* 99 * Get a copy of the 'virgin' disklabel. 100 * XXX It might make more sense for this to 101 * happen right after format_slice() instead. 102 */ 103 command_add(cmds, "%s%s -r %s >%sinstall.disklabel.%s", 104 a->os_root, cmd_name(a, "DISKLABEL64"), 105 slice_get_device_name(storage_get_selected_slice(a->s)), 106 a->tmp, 107 slice_get_device_name(storage_get_selected_slice(a->s))); 108 } 109 110 /* 111 * Weave together a new disklabel out the of the 'virgin' 112 * disklabel, and the user's subpartition choices. 113 */ 114 115 /* 116 * Take everything from the 'virgin' disklabel up until the 117 * '16 partitions' line. 118 */ 119 num_partitions = 16; 120 command_add(cmds, "%s%s '$2==\"partitions:\" || cut { cut = 1 } !cut { print $0 }' <%sinstall.disklabel.%s >%sinstall.disklabel", 121 a->os_root, cmd_name(a, "AWK"), 122 a->tmp, 123 slice_get_device_name(storage_get_selected_slice(a->s)), 124 a->tmp); 125 126 /* 127 * 16 partitions: 128 * # size offset fstype 129 * c: 16383969 0 unused # 7999.985MB 130 */ 131 132 command_add(cmds, "%s%s '%d partitions:' >>%sinstall.disklabel", 133 a->os_root, cmd_name(a, "ECHO"), num_partitions ,a->tmp); 134 command_add(cmds, "%s%s '%s' >>%sinstall.disklabel", 135 a->os_root, cmd_name(a, "ECHO"), 136 "# size offset fstype", 137 a->tmp); 138 139 #ifdef DEBUG 140 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 141 sp != NULL; sp = subpartition_next(sp)) { 142 command_add(cmds, "%s%s 'mountpoint: %s device: %s'", 143 a->os_root, cmd_name(a, "ECHO"), 144 subpartition_get_mountpoint(sp), 145 subpartition_get_device_name(sp)); 146 } 147 #endif 148 149 /* 150 * Write a line for each subpartition the user wants. 151 */ 152 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 153 sp != NULL; sp = subpartition_next(sp)) { 154 if (subpartition_is_tmpfsbacked(sp)) { 155 continue; 156 } 157 if (subpartition_is_swap(sp)) { 158 command_add(cmds, "%s%s ' %c:\t%s\t*\tswap' >>%sinstall.disklabel", 159 a->os_root, cmd_name(a, "ECHO"), 160 subpartition_get_letter(sp), 161 capacity_to_string(subpartition_get_capacity(sp)), 162 a->tmp); 163 } else if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0) { 164 command_add(cmds, "%s%s ' %c:\t%s\t0\t4.2BSD' >>%sinstall.disklabel", 165 a->os_root, cmd_name(a, "ECHO"), 166 subpartition_get_letter(sp), 167 capacity_to_string(subpartition_get_capacity(sp)), 168 a->tmp); 169 } else { 170 command_add(cmds, "%s%s ' %c:\t%s\t*\tHAMMER' >>%sinstall.disklabel", 171 a->os_root, cmd_name(a, "ECHO"), 172 subpartition_get_letter(sp), 173 capacity_to_string(subpartition_get_capacity(sp)), 174 a->tmp); 175 } 176 } 177 temp_file_add(a, "install.disklabel"); 178 179 /* 180 * Label the slice from the disklabel we just wove together. 181 */ 182 command_add(cmds, "%s%s -R -B -r %s %sinstall.disklabel", 183 a->os_root, cmd_name(a, "DISKLABEL64"), 184 slice_get_device_name(storage_get_selected_slice(a->s)), 185 a->tmp); 186 187 /* 188 * Create a snapshot of the disklabel we just created 189 * for debugging inspection in the log. 190 */ 191 command_add(cmds, "%s%s %s", 192 a->os_root, cmd_name(a, "DISKLABEL64"), 193 slice_get_device_name(storage_get_selected_slice(a->s))); 194 195 /* 196 * If encryption was specified, load dm(4). 197 */ 198 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 199 sp != NULL; sp = subpartition_next(sp)) { 200 if (subpartition_is_encrypted(sp)) { 201 fn_get_passphrase(a); 202 break; 203 } 204 } 205 206 /* 207 * Create filesystems on the newly-created subpartitions. 208 */ 209 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 210 sp != NULL; sp = subpartition_next(sp)) { 211 if (subpartition_is_swap(sp) || subpartition_is_tmpfsbacked(sp)) { 212 if (subpartition_is_swap(sp) && 213 subpartition_is_encrypted(sp)) { 214 command_add(cmds, 215 "%s%s -d /tmp/t1 luksFormat %sdev/%s", 216 a->os_root, cmd_name(a, "CRYPTSETUP"), 217 a->os_root, 218 subpartition_get_device_name(sp)); 219 command_add(cmds, 220 "%s%s -d /tmp/t1 luksOpen %sdev/%s swap", 221 a->os_root, cmd_name(a, "CRYPTSETUP"), 222 a->os_root, 223 subpartition_get_device_name(sp)); 224 } 225 continue; 226 } 227 228 if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0) { 229 command_add(cmds, "%s%s %sdev/%s", 230 a->os_root, cmd_name(a, "NEWFS"), 231 a->os_root, 232 subpartition_get_device_name(sp)); 233 } else { 234 if (subpartition_is_encrypted(sp)) { 235 command_add(cmds, 236 "%s%s -d /tmp/t1 luksFormat %sdev/%s", 237 a->os_root, cmd_name(a, "CRYPTSETUP"), 238 a->os_root, 239 subpartition_get_device_name(sp)); 240 command_add(cmds, 241 "%s%s -d /tmp/t1 luksOpen %sdev/%s root", 242 a->os_root, cmd_name(a, "CRYPTSETUP"), 243 a->os_root, 244 subpartition_get_device_name(sp)); 245 } 246 command_add(cmds, "%s%s -f -L ROOT %sdev/%s", 247 a->os_root, cmd_name(a, "NEWFS_HAMMER"), 248 a->os_root, 249 subpartition_is_encrypted(sp) ? 250 "mapper/root" : subpartition_get_device_name(sp)); 251 } 252 } 253 254 result = commands_execute(a, cmds); 255 commands_free(cmds); 256 return(result); 257 } 258 259 static long 260 default_capacity(struct storage *s, const char *mtpt) 261 { 262 unsigned long boot, root, swap; 263 unsigned long capacity; 264 unsigned long mem; 265 266 capacity = slice_get_capacity(storage_get_selected_slice(s)); 267 mem = storage_get_memsize(s); 268 269 /* 270 * Try to get 768M for /boot, but if space is tight go down to 128M 271 * in 128M steps. 272 * For swap, start with 2*mem but take less if space is tight 273 * (minimum is 384). 274 * Rest goes to / (which is at least 75% slice size). 275 */ 276 277 root = capacity / 4 * 3; 278 swap = 2 * mem; 279 if (swap > SWAP_MAX) 280 swap = SWAP_MAX; 281 boot = 768; 282 while (boot + root > capacity - 384) 283 boot -= 128; 284 if (boot + root + swap > capacity) 285 swap = capacity - boot - root; 286 287 if (capacity < DISK_MIN) 288 return(-1); 289 else if (strcmp(mtpt, "/boot") == 0) 290 return(boot); 291 else if (strcmp(mtpt, "swap") == 0) 292 return(swap); 293 else if (strcmp(mtpt, "/") == 0) 294 return(-1); 295 296 /* shouldn't ever happen */ 297 return(-1); 298 } 299 300 static int 301 check_capacity(struct i_fn_args *a) 302 { 303 struct subpartition *sp; 304 long min_capacity[] = {128, 0, DISK_MIN - 128, 0}; 305 unsigned long total_capacity = 0; 306 unsigned long remaining_capacity; 307 int mtpt, warn_smallpart = 0; 308 309 remaining_capacity = slice_get_capacity(storage_get_selected_slice(a->s)); 310 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 311 sp != NULL; sp = subpartition_next(sp)) { 312 if (subpartition_get_capacity(sp) != -1) 313 remaining_capacity -= subpartition_get_capacity(sp); 314 } 315 316 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 317 sp != NULL; sp = subpartition_next(sp)) { 318 long subpart_capacity = subpartition_get_capacity(sp); 319 const char *mountpt = subpartition_get_mountpoint(sp); 320 321 if (subpart_capacity == -1) 322 total_capacity++; 323 else 324 total_capacity += subpart_capacity; 325 for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) { 326 if (strcmp(mountpt, def_mountpt[mtpt]) == 0 && 327 subpart_capacity < min_capacity[mtpt] && 328 subpart_capacity != -1) { 329 inform(a->c, _("WARNING: The size (%ldM) specified for " 330 "the %s subpartition is too small. It " 331 "should be at least %ldM or you will " 332 "risk running out of space during " 333 "the installation."), 334 subpart_capacity, mountpt, 335 min_capacity[mtpt]); 336 } 337 } 338 if (strcmp(mountpt, "/boot") != 0 && 339 strcmp(mountpt, "swap") != 0) { 340 if ((subpart_capacity == -1 && remaining_capacity < HAMMER_MIN) || 341 (subpart_capacity != -1 && subpart_capacity < HAMMER_MIN)) 342 warn_smallpart++; 343 } 344 } 345 346 if (total_capacity > slice_get_capacity(storage_get_selected_slice(a->s))) { 347 inform(a->c, _("The space allocated to all of your selected " 348 "subpartitions (%luM) exceeds the total " 349 "capacity of the selected primary partition " 350 "(%luM). Remove some subpartitions or choose " 351 "a smaller size for them and try again."), 352 total_capacity, slice_get_capacity(storage_get_selected_slice(a->s))); 353 return(0); 354 } 355 356 if (warn_smallpart) 357 return (confirm_dangerous_action(a->c, 358 _("WARNING: HAMMER filesystems less than 50GB are " 359 "not recommended!\n" 360 "You may have to run 'hammer prune-everything' and " 361 "'hammer reblock'\n" 362 "quite often, even if using a nohistory mount.\n\n" 363 "NOTE: HAMMER filesystems smaller than 10GB are " 364 "unsupported. Use at your own risk."))); 365 366 return(1); 367 } 368 369 static int 370 check_subpartition_selections(struct dfui_response *r, struct i_fn_args *a) 371 { 372 struct dfui_dataset *ds; 373 struct dfui_dataset *star_ds = NULL; 374 struct aura_dict *d; 375 const char *mountpoint, *capstring; 376 long capacity = 0; 377 int found_root = 0; 378 int valid = 1; 379 380 d = aura_dict_new(1, AURA_DICT_LIST); 381 382 if ((ds = dfui_response_dataset_get_first(r)) == NULL) { 383 inform(a->c, _("Please set up at least one subpartition.")); 384 valid = 0; 385 } 386 387 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL; 388 ds = dfui_dataset_get_next(ds)) { 389 #ifdef DEBUG 390 dfui_dataset_dump(ds); 391 #endif 392 mountpoint = dfui_dataset_get_value(ds, "mountpoint"); 393 capstring = dfui_dataset_get_value(ds, "capacity"); 394 395 if (aura_dict_exists(d, mountpoint, strlen(mountpoint) + 1)) { 396 inform(a->c, _("The same mount point cannot be specified " 397 "for two different subpartitions.")); 398 valid = 0; 399 } 400 401 if (strcmp(mountpoint, "/") == 0) 402 found_root = 1; 403 404 if (strcmp(capstring, "*") == 0) { 405 if (star_ds != NULL) { 406 inform(a->c, _("You cannot have more than one subpartition " 407 "with a '*' capacity (meaning 'use the remainder " 408 "of the primary partition'.)")); 409 valid = 0; 410 } else { 411 star_ds = ds; 412 } 413 } 414 415 if (!(!strcasecmp(mountpoint, "swap") || mountpoint[0] == '/')) { 416 inform(a->c, _("Mount point must be either 'swap', or it must " 417 "start with a '/'.")); 418 valid = 0; 419 } 420 421 if (strpbrk(mountpoint, " \\\"'`") != NULL) { 422 inform(a->c, _("Mount point may not contain the following " 423 "characters: blank space, backslash, or " 424 "single, double, or back quotes.")); 425 valid = 0; 426 } 427 428 if (strlen(capstring) == 0) { 429 inform(a->c, _("A capacity must be specified.")); 430 valid = 0; 431 } 432 433 if (!string_to_capacity(capstring, &capacity)) { 434 inform(a->c, _("Capacity must be either a '*' symbol to indicate " 435 "'use the rest of the primary partition', or it " 436 "must be a series of decimal digits ending with a " 437 "'M' (indicating megabytes) or a 'G' (indicating " 438 "gigabytes.)")); 439 valid = 0; 440 } 441 442 /* 443 * Maybe remove this limit entirely? 444 */ 445 if ((strcasecmp(mountpoint, "swap") == 0) && 446 (capacity > SWAP_MAX)) { 447 inform(a->c, _("Swap capacity is limited to %dG."), 448 SWAP_MAX / 1024); 449 valid = 0; 450 } 451 452 /* 453 * If we made it through that obstacle course, all is well. 454 */ 455 456 if (valid) 457 aura_dict_store(d, mountpoint, strlen(mountpoint) + 1, "", 1); 458 } 459 460 if (!found_root) { 461 inform(a->c, _("You must include a / (root) subpartition.")); 462 valid = 0; 463 } 464 465 if (aura_dict_size(d) > 16) { 466 inform(a->c, _("You cannot have more than 16 subpartitions " 467 "on a single primary partition. Remove some " 468 "and try again.")); 469 valid = 0; 470 } 471 472 aura_dict_free(d); 473 474 return(valid); 475 } 476 477 static void 478 save_subpartition_selections(struct dfui_response *r, struct i_fn_args *a) 479 { 480 struct dfui_dataset *ds; 481 const char *mountpoint, *capstring; 482 long capacity; 483 int valid = 1; 484 485 subpartitions_free(storage_get_selected_slice(a->s)); 486 487 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL; 488 ds = dfui_dataset_get_next(ds)) { 489 mountpoint = dfui_dataset_get_value(ds, "mountpoint"); 490 capstring = dfui_dataset_get_value(ds, "capacity"); 491 492 if (string_to_capacity(capstring, &capacity)) { 493 subpartition_new_hammer(storage_get_selected_slice(a->s), 494 mountpoint, capacity, 495 strcasecmp(dfui_dataset_get_value(ds, "encrypted"), "Y") == 0); 496 } 497 } 498 } 499 500 static void 501 populate_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a) 502 { 503 struct subpartition *sp; 504 struct dfui_dataset *ds; 505 int i; 506 long capacity; 507 508 if (slice_subpartition_first(storage_get_selected_slice(a->s)) != NULL) { 509 /* 510 * The user has already given us their subpartition 511 * preferences, so use them here. 512 */ 513 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 514 sp != NULL; sp = subpartition_next(sp)) { 515 ds = dfui_dataset_new(); 516 dfui_dataset_celldata_add(ds, "mountpoint", 517 subpartition_get_mountpoint(sp)); 518 dfui_dataset_celldata_add(ds, "capacity", 519 capacity_to_string(subpartition_get_capacity(sp))); 520 dfui_dataset_celldata_add(ds, "encrypted", 521 subpartition_is_encrypted(sp) ? "Y" : "N"); 522 dfui_form_dataset_add(f, ds); 523 } 524 } else { 525 /* 526 * Otherwise, populate the form with datasets representing 527 * reasonably-calculated defaults. The defaults are chosen 528 * based on the slice's total capacity and the machine's 529 * total physical memory (for swap.) 530 */ 531 for (i = 0; def_mountpt[i] != NULL; i++) { 532 capacity = default_capacity(a->s, def_mountpt[i]); 533 ds = dfui_dataset_new(); 534 dfui_dataset_celldata_add(ds, "mountpoint", 535 def_mountpt[i]); 536 dfui_dataset_celldata_add(ds, "capacity", 537 capacity_to_string(capacity)); 538 dfui_dataset_celldata_add(ds, "encrypted", "N"); 539 dfui_form_dataset_add(f, ds); 540 } 541 } 542 } 543 544 static int 545 warn_subpartition_selections(struct i_fn_args *a) 546 { 547 int valid = 0; 548 549 if (subpartition_find(storage_get_selected_slice(a->s), "/boot") == NULL) { 550 inform(a->c, _("The /boot partition must not be omitted.")); 551 } else if (subpartition_find(storage_get_selected_slice(a->s), "/home") != NULL || 552 subpartition_find(storage_get_selected_slice(a->s), "/tmp") != NULL || 553 subpartition_find(storage_get_selected_slice(a->s), "/usr") != NULL || 554 subpartition_find(storage_get_selected_slice(a->s), "/usr/obj") != NULL || 555 subpartition_find(storage_get_selected_slice(a->s), "/var") != NULL || 556 subpartition_find(storage_get_selected_slice(a->s), "/var/crash") != NULL || 557 subpartition_find(storage_get_selected_slice(a->s), "/var/tmp") != NULL) { 558 inform(a->c, _("Pseudo filesystems will automatically be created " 559 "for /home, /tmp, /usr, /usr/obj, /var, /var/crash " 560 "and /var/tmp and must not be specified.")); 561 } else { 562 valid = check_capacity(a); 563 } 564 565 return(!valid); 566 } 567 568 static int 569 warn_encrypted_boot(struct i_fn_args *a) 570 { 571 int valid = 1; 572 573 struct subpartition *sp; 574 575 sp = subpartition_find(storage_get_selected_slice(a->s), "/boot"); 576 if (sp == NULL) 577 return(!valid); 578 579 if (subpartition_is_encrypted(sp)) { 580 switch (dfui_be_present_dialog(a->c, _("/boot cannot be encrypted"), 581 _("Leave /boot unencrypted|Return to Create Subpartitions"), 582 _("You have selected encryption for the /boot partition which " 583 "is not supported."))) { 584 case 1: 585 subpartition_clr_encrypted(sp); 586 valid = 1; 587 break; 588 case 2: 589 valid = 0; 590 break; 591 default: 592 abort_backend(); 593 } 594 } 595 596 return(!valid); 597 } 598 599 static struct dfui_form * 600 make_create_subpartitions_form(struct i_fn_args *a) 601 { 602 struct dfui_form *f; 603 char msg_buf[1][1024]; 604 605 snprintf(msg_buf[0], sizeof(msg_buf[0]), 606 _("Subpartitions further divide a primary partition for " 607 "use with %s. Some reasons you may want " 608 "a set of subpartitions are:\n\n" 609 "- you want to restrict how much data can be written " 610 "to certain parts of the primary partition, to quell " 611 "denial-of-service attacks; and\n" 612 "- you want to speed up access to data on the disk." 613 ""), OPERATING_SYSTEM_NAME); 614 615 f = dfui_form_create( 616 "create_subpartitions", 617 _("Create Subpartitions"), 618 _("Set up the subpartitions (also known as just `partitions' " 619 "in BSD tradition) you want to have on this primary " 620 "partition. In most cases you should be fine with " 621 "the default settings.\n\n" 622 "For Capacity, use 'M' to indicate megabytes, 'G' to " 623 "indicate gigabytes, or a single '*' to indicate " 624 "'use the remaining space on the primary partition'."), 625 626 msg_buf[0], 627 628 "p", "special", "dfinstaller_create_subpartitions", 629 "p", "minimum_width","64", 630 631 "f", "mountpoint", _("Mountpoint"), "", "", 632 "f", "capacity", _("Capacity"), "", "", 633 634 "f", "encrypted", _("Encrypted"), "", "", 635 "p", "control", "checkbox", 636 637 "a", "ok", _("Accept and Create"), "", "", 638 "a", "cancel", 639 (disk_get_formatted(storage_get_selected_disk(a->s)) ? 640 _("Return to Select Disk") : 641 _("Return to Select Primary Partition")), "", "", 642 "p", "accelerator", "ESC", 643 644 NULL 645 ); 646 647 dfui_form_set_multiple(f, 1); 648 dfui_form_set_extensible(f, 1); 649 /* 650 * Remove ATM until HAMMER installer support is better 651 * dfui_form_set_extensible(f, 1); 652 */ 653 #if 0 654 if (expert) { 655 fi = dfui_form_field_add(f, "softupdates", 656 dfui_info_new(_("Softupdates"), "", "")); 657 dfui_field_property_set(fi, "control", "checkbox"); 658 659 fi = dfui_form_field_add(f, "tmpfsbacked", 660 dfui_info_new(_("TMPFS"), "", "")); 661 dfui_field_property_set(fi, "control", "checkbox"); 662 663 fi = dfui_form_field_add(f, "fsize", 664 dfui_info_new(_("Frag Sz"), "", "")); 665 666 fi = dfui_form_field_add(f, "bsize", 667 dfui_info_new(_("Block Sz"), "", "")); 668 669 dfui_form_action_add(f, "switch", 670 dfui_info_new(_("Switch to Normal Mode"), "", "")); 671 } else { 672 dfui_form_action_add(f, "switch", 673 dfui_info_new(_("Switch to Expert Mode"), "", "")); 674 } 675 #endif 676 return(f); 677 } 678 679 /* 680 * Returns: 681 * -1 = the form should be redisplayed 682 * 0 = failure, function is over 683 * 1 = success, function is over 684 */ 685 static int 686 show_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a) 687 { 688 struct dfui_dataset *ds; 689 struct dfui_response *r; 690 691 for (;;) { 692 if (dfui_form_dataset_get_first(f) == NULL) 693 populate_create_subpartitions_form(f, a); 694 695 if (!dfui_be_present(a->c, f, &r)) 696 abort_backend(); 697 698 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { 699 dfui_response_free(r); 700 return(0); 701 } else if (strcmp(dfui_response_get_action_id(r), "switch") == 0) { 702 if (check_subpartition_selections(r, a)) { 703 save_subpartition_selections(r, a); 704 expert = expert ? 0 : 1; 705 dfui_response_free(r); 706 return(-1); 707 } 708 } else { 709 if (check_subpartition_selections(r, a)) { 710 save_subpartition_selections(r, a); 711 if (!warn_subpartition_selections(a) && 712 !warn_encrypted_boot(a)) { 713 if (!create_subpartitions(a)) { 714 inform(a->c, _("The subpartitions you chose were " 715 "not correctly created, and the " 716 "primary partition may " 717 "now be in an inconsistent state. " 718 "We recommend re-formatting it " 719 "before proceeding.")); 720 dfui_response_free(r); 721 return(0); 722 } else { 723 dfui_response_free(r); 724 return(1); 725 } 726 } 727 } 728 } 729 730 dfui_form_datasets_free(f); 731 /* dfui_form_datasets_add_from_response(f, r); */ 732 for (ds = dfui_response_dataset_get_first(r); ds != NULL; 733 ds = dfui_dataset_get_next(ds)) { 734 dfui_form_dataset_add(f, dfui_dataset_dup(ds)); 735 } 736 } 737 } 738 739 /* 740 * fn_create_subpartitions_hammer: let the user specify what subpartitions they 741 * want on the disk, how large each should be, and where it should be mounted. 742 */ 743 void 744 fn_create_subpartitions_hammer(struct i_fn_args *a) 745 { 746 struct dfui_form *f; 747 int done = 0; 748 749 a->result = 0; 750 while (!done) { 751 f = make_create_subpartitions_form(a); 752 switch (show_create_subpartitions_form(f, a)) { 753 case -1: 754 done = 0; 755 break; 756 case 0: 757 done = 1; 758 a->result = 0; 759 break; 760 case 1: 761 done = 1; 762 a->result = 1; 763 break; 764 } 765 dfui_form_free(f); 766 } 767 } 768