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 /dev/%s", 216 a->os_root, cmd_name(a, "CRYPTSETUP"), 217 subpartition_get_device_name(sp)); 218 command_add(cmds, 219 "%s%s -d /tmp/t1 luksOpen /dev/%s swap", 220 a->os_root, cmd_name(a, "CRYPTSETUP"), 221 subpartition_get_device_name(sp)); 222 } 223 continue; 224 } 225 226 if (strcmp(subpartition_get_mountpoint(sp), "/boot") == 0) { 227 command_add(cmds, "%s%s /dev/%s", 228 a->os_root, cmd_name(a, "NEWFS"), 229 subpartition_get_device_name(sp)); 230 } else { 231 if (subpartition_is_encrypted(sp)) { 232 command_add(cmds, 233 "%s%s -d /tmp/t1 luksFormat /dev/%s", 234 a->os_root, cmd_name(a, "CRYPTSETUP"), 235 subpartition_get_device_name(sp)); 236 command_add(cmds, 237 "%s%s -d /tmp/t1 luksOpen /dev/%s root", 238 a->os_root, cmd_name(a, "CRYPTSETUP"), 239 subpartition_get_device_name(sp)); 240 } 241 command_add(cmds, "%s%s -f -L ROOT /dev/%s", 242 a->os_root, cmd_name(a, "NEWFS_HAMMER"), 243 subpartition_is_encrypted(sp) ? 244 "mapper/root" : subpartition_get_device_name(sp)); 245 } 246 } 247 248 result = commands_execute(a, cmds); 249 commands_free(cmds); 250 return(result); 251 } 252 253 static long 254 default_capacity(struct storage *s, const char *mtpt) 255 { 256 unsigned long boot, root, swap; 257 unsigned long capacity; 258 unsigned long mem; 259 260 capacity = slice_get_capacity(storage_get_selected_slice(s)); 261 mem = storage_get_memsize(s); 262 263 /* 264 * Try to get 768M for /boot, but if space is tight go down to 128M 265 * in 128M steps. 266 * For swap, start with 2*mem but take less if space is tight 267 * (minimum is 384). 268 * Rest goes to / (which is at least 75% slice size). 269 */ 270 271 root = capacity / 4 * 3; 272 swap = 2 * mem; 273 if (swap > SWAP_MAX) 274 swap = SWAP_MAX; 275 boot = 768; 276 while (boot + root > capacity - 384) 277 boot -= 128; 278 if (boot + root + swap > capacity) 279 swap = capacity - boot - root; 280 281 if (capacity < DISK_MIN) 282 return(-1); 283 else if (strcmp(mtpt, "/boot") == 0) 284 return(boot); 285 else if (strcmp(mtpt, "swap") == 0) 286 return(swap); 287 else if (strcmp(mtpt, "/") == 0) 288 return(-1); 289 290 /* shouldn't ever happen */ 291 return(-1); 292 } 293 294 static int 295 check_capacity(struct i_fn_args *a) 296 { 297 struct subpartition *sp; 298 long min_capacity[] = {128, 0, DISK_MIN - 128, 0}; 299 unsigned long total_capacity = 0; 300 unsigned long remaining_capacity; 301 int mtpt, warn_smallpart = 0; 302 303 remaining_capacity = slice_get_capacity(storage_get_selected_slice(a->s)); 304 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 305 sp != NULL; sp = subpartition_next(sp)) { 306 if (subpartition_get_capacity(sp) != -1) 307 remaining_capacity -= subpartition_get_capacity(sp); 308 } 309 310 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 311 sp != NULL; sp = subpartition_next(sp)) { 312 long subpart_capacity = subpartition_get_capacity(sp); 313 const char *mountpt = subpartition_get_mountpoint(sp); 314 315 if (subpart_capacity == -1) 316 total_capacity++; 317 else 318 total_capacity += subpart_capacity; 319 for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) { 320 if (strcmp(mountpt, def_mountpt[mtpt]) == 0 && 321 subpart_capacity < min_capacity[mtpt] && 322 subpart_capacity != -1) { 323 inform(a->c, _("WARNING: The size (%ldM) specified for " 324 "the %s subpartition is too small. It " 325 "should be at least %ldM or you will " 326 "risk running out of space during " 327 "the installation."), 328 subpart_capacity, mountpt, 329 min_capacity[mtpt]); 330 } 331 } 332 if (strcmp(mountpt, "/boot") != 0 && 333 strcmp(mountpt, "swap") != 0) { 334 if ((subpart_capacity == -1 && remaining_capacity < HAMMER_MIN) || 335 (subpart_capacity != -1 && subpart_capacity < HAMMER_MIN)) 336 warn_smallpart++; 337 } 338 } 339 340 if (total_capacity > slice_get_capacity(storage_get_selected_slice(a->s))) { 341 inform(a->c, _("The space allocated to all of your selected " 342 "subpartitions (%luM) exceeds the total " 343 "capacity of the selected primary partition " 344 "(%luM). Remove some subpartitions or choose " 345 "a smaller size for them and try again."), 346 total_capacity, slice_get_capacity(storage_get_selected_slice(a->s))); 347 return(0); 348 } 349 350 if (warn_smallpart) 351 return (confirm_dangerous_action(a->c, 352 _("WARNING: HAMMER filesystems less than 50GB are " 353 "not recommended!\n" 354 "You may have to run 'hammer prune-everything' and " 355 "'hammer reblock'\n" 356 "quite often, even if using a nohistory mount.\n\n" 357 "NOTE: HAMMER filesystems smaller than 10GB are " 358 "unsupported. Use at your own risk."))); 359 360 return(1); 361 } 362 363 static int 364 check_subpartition_selections(struct dfui_response *r, struct i_fn_args *a) 365 { 366 struct dfui_dataset *ds; 367 struct dfui_dataset *star_ds = NULL; 368 struct aura_dict *d; 369 const char *mountpoint, *capstring; 370 long capacity = 0; 371 int found_root = 0; 372 int valid = 1; 373 374 d = aura_dict_new(1, AURA_DICT_LIST); 375 376 if ((ds = dfui_response_dataset_get_first(r)) == NULL) { 377 inform(a->c, _("Please set up at least one subpartition.")); 378 valid = 0; 379 } 380 381 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL; 382 ds = dfui_dataset_get_next(ds)) { 383 #ifdef DEBUG 384 dfui_dataset_dump(ds); 385 #endif 386 mountpoint = dfui_dataset_get_value(ds, "mountpoint"); 387 capstring = dfui_dataset_get_value(ds, "capacity"); 388 389 if (aura_dict_exists(d, mountpoint, strlen(mountpoint) + 1)) { 390 inform(a->c, _("The same mount point cannot be specified " 391 "for two different subpartitions.")); 392 valid = 0; 393 } 394 395 if (strcmp(mountpoint, "/") == 0) 396 found_root = 1; 397 398 if (strcmp(capstring, "*") == 0) { 399 if (star_ds != NULL) { 400 inform(a->c, _("You cannot have more than one subpartition " 401 "with a '*' capacity (meaning 'use the remainder " 402 "of the primary partition'.)")); 403 valid = 0; 404 } else { 405 star_ds = ds; 406 } 407 } 408 409 if (!(!strcasecmp(mountpoint, "swap") || mountpoint[0] == '/')) { 410 inform(a->c, _("Mount point must be either 'swap', or it must " 411 "start with a '/'.")); 412 valid = 0; 413 } 414 415 if (strpbrk(mountpoint, " \\\"'`") != NULL) { 416 inform(a->c, _("Mount point may not contain the following " 417 "characters: blank space, backslash, or " 418 "single, double, or back quotes.")); 419 valid = 0; 420 } 421 422 if (strlen(capstring) == 0) { 423 inform(a->c, _("A capacity must be specified.")); 424 valid = 0; 425 } 426 427 if (!string_to_capacity(capstring, &capacity)) { 428 inform(a->c, _("Capacity must be either a '*' symbol to indicate " 429 "'use the rest of the primary partition', or it " 430 "must be a series of decimal digits ending with a " 431 "'M' (indicating megabytes) or a 'G' (indicating " 432 "gigabytes.)")); 433 valid = 0; 434 } 435 436 /* 437 * Maybe remove this limit entirely? 438 */ 439 if ((strcasecmp(mountpoint, "swap") == 0) && 440 (capacity > SWAP_MAX)) { 441 inform(a->c, _("Swap capacity is limited to %dG."), 442 SWAP_MAX / 1024); 443 valid = 0; 444 } 445 446 /* 447 * If we made it through that obstacle course, all is well. 448 */ 449 450 if (valid) 451 aura_dict_store(d, mountpoint, strlen(mountpoint) + 1, "", 1); 452 } 453 454 if (!found_root) { 455 inform(a->c, _("You must include a / (root) subpartition.")); 456 valid = 0; 457 } 458 459 if (aura_dict_size(d) > 16) { 460 inform(a->c, _("You cannot have more than 16 subpartitions " 461 "on a single primary partition. Remove some " 462 "and try again.")); 463 valid = 0; 464 } 465 466 aura_dict_free(d); 467 468 return(valid); 469 } 470 471 static void 472 save_subpartition_selections(struct dfui_response *r, struct i_fn_args *a) 473 { 474 struct dfui_dataset *ds; 475 const char *mountpoint, *capstring; 476 long capacity; 477 int valid = 1; 478 479 subpartitions_free(storage_get_selected_slice(a->s)); 480 481 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL; 482 ds = dfui_dataset_get_next(ds)) { 483 mountpoint = dfui_dataset_get_value(ds, "mountpoint"); 484 capstring = dfui_dataset_get_value(ds, "capacity"); 485 486 if (string_to_capacity(capstring, &capacity)) { 487 subpartition_new_hammer(storage_get_selected_slice(a->s), 488 mountpoint, capacity, 489 strcasecmp(dfui_dataset_get_value(ds, "encrypted"), "Y") == 0); 490 } 491 } 492 } 493 494 static void 495 populate_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a) 496 { 497 struct subpartition *sp; 498 struct dfui_dataset *ds; 499 int i; 500 long capacity; 501 502 if (slice_subpartition_first(storage_get_selected_slice(a->s)) != NULL) { 503 /* 504 * The user has already given us their subpartition 505 * preferences, so use them here. 506 */ 507 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 508 sp != NULL; sp = subpartition_next(sp)) { 509 ds = dfui_dataset_new(); 510 dfui_dataset_celldata_add(ds, "mountpoint", 511 subpartition_get_mountpoint(sp)); 512 dfui_dataset_celldata_add(ds, "capacity", 513 capacity_to_string(subpartition_get_capacity(sp))); 514 dfui_dataset_celldata_add(ds, "encrypted", 515 subpartition_is_encrypted(sp) ? "Y" : "N"); 516 dfui_form_dataset_add(f, ds); 517 } 518 } else { 519 /* 520 * Otherwise, populate the form with datasets representing 521 * reasonably-calculated defaults. The defaults are chosen 522 * based on the slice's total capacity and the machine's 523 * total physical memory (for swap.) 524 */ 525 for (i = 0; def_mountpt[i] != NULL; i++) { 526 capacity = default_capacity(a->s, def_mountpt[i]); 527 ds = dfui_dataset_new(); 528 dfui_dataset_celldata_add(ds, "mountpoint", 529 def_mountpt[i]); 530 dfui_dataset_celldata_add(ds, "capacity", 531 capacity_to_string(capacity)); 532 dfui_dataset_celldata_add(ds, "encrypted", "N"); 533 dfui_form_dataset_add(f, ds); 534 } 535 } 536 } 537 538 static int 539 warn_subpartition_selections(struct i_fn_args *a) 540 { 541 int valid = 0; 542 543 if (subpartition_find(storage_get_selected_slice(a->s), "/boot") == NULL) { 544 inform(a->c, _("The /boot partition must not be omitted.")); 545 } else if (subpartition_find(storage_get_selected_slice(a->s), "/home") != NULL || 546 subpartition_find(storage_get_selected_slice(a->s), "/tmp") != NULL || 547 subpartition_find(storage_get_selected_slice(a->s), "/usr") != NULL || 548 subpartition_find(storage_get_selected_slice(a->s), "/usr/obj") != NULL || 549 subpartition_find(storage_get_selected_slice(a->s), "/var") != NULL || 550 subpartition_find(storage_get_selected_slice(a->s), "/var/crash") != NULL || 551 subpartition_find(storage_get_selected_slice(a->s), "/var/tmp") != NULL) { 552 inform(a->c, _("Pseudo filesystems will automatically be created " 553 "for /home, /tmp, /usr, /usr/obj, /var, /var/crash " 554 "and /var/tmp and must not be specified.")); 555 } else { 556 valid = check_capacity(a); 557 } 558 559 return(!valid); 560 } 561 562 static int 563 warn_encrypted_boot(struct i_fn_args *a) 564 { 565 int valid = 1; 566 567 struct subpartition *sp; 568 569 sp = subpartition_find(storage_get_selected_slice(a->s), "/boot"); 570 if (sp == NULL) 571 return(!valid); 572 573 if (subpartition_is_encrypted(sp)) { 574 switch (dfui_be_present_dialog(a->c, _("/boot cannot be encrypted"), 575 _("Leave /boot unencrypted|Return to Create Subpartitions"), 576 _("You have selected encryption for the /boot partition which " 577 "is not supported."))) { 578 case 1: 579 subpartition_clr_encrypted(sp); 580 valid = 1; 581 break; 582 case 2: 583 valid = 0; 584 break; 585 default: 586 abort_backend(); 587 } 588 } 589 590 return(!valid); 591 } 592 593 static struct dfui_form * 594 make_create_subpartitions_form(struct i_fn_args *a) 595 { 596 struct dfui_form *f; 597 char msg_buf[1][1024]; 598 599 snprintf(msg_buf[0], sizeof(msg_buf[0]), 600 _("Subpartitions further divide a primary partition for " 601 "use with %s. Some reasons you may want " 602 "a set of subpartitions are:\n\n" 603 "- you want to restrict how much data can be written " 604 "to certain parts of the primary partition, to quell " 605 "denial-of-service attacks; and\n" 606 "- you want to speed up access to data on the disk." 607 ""), OPERATING_SYSTEM_NAME); 608 609 f = dfui_form_create( 610 "create_subpartitions", 611 _("Create Subpartitions"), 612 _("Set up the subpartitions (also known as just `partitions' " 613 "in BSD tradition) you want to have on this primary " 614 "partition. In most cases you should be fine with " 615 "the default settings.\n\n" 616 "For Capacity, use 'M' to indicate megabytes, 'G' to " 617 "indicate gigabytes, or a single '*' to indicate " 618 "'use the remaining space on the primary partition'."), 619 620 msg_buf[0], 621 622 "p", "special", "dfinstaller_create_subpartitions", 623 "p", "minimum_width","64", 624 625 "f", "mountpoint", _("Mountpoint"), "", "", 626 "f", "capacity", _("Capacity"), "", "", 627 628 "f", "encrypted", _("Encrypted"), "", "", 629 "p", "control", "checkbox", 630 631 "a", "ok", _("Accept and Create"), "", "", 632 "a", "cancel", 633 (disk_get_formatted(storage_get_selected_disk(a->s)) ? 634 _("Return to Select Disk") : 635 _("Return to Select Primary Partition")), "", "", 636 "p", "accelerator", "ESC", 637 638 NULL 639 ); 640 641 dfui_form_set_multiple(f, 1); 642 dfui_form_set_extensible(f, 1); 643 /* 644 * Remove ATM until HAMMER installer support is better 645 * dfui_form_set_extensible(f, 1); 646 */ 647 #if 0 648 if (expert) { 649 fi = dfui_form_field_add(f, "softupdates", 650 dfui_info_new(_("Softupdates"), "", "")); 651 dfui_field_property_set(fi, "control", "checkbox"); 652 653 fi = dfui_form_field_add(f, "tmpfsbacked", 654 dfui_info_new(_("TMPFS"), "", "")); 655 dfui_field_property_set(fi, "control", "checkbox"); 656 657 fi = dfui_form_field_add(f, "fsize", 658 dfui_info_new(_("Frag Sz"), "", "")); 659 660 fi = dfui_form_field_add(f, "bsize", 661 dfui_info_new(_("Block Sz"), "", "")); 662 663 dfui_form_action_add(f, "switch", 664 dfui_info_new(_("Switch to Normal Mode"), "", "")); 665 } else { 666 dfui_form_action_add(f, "switch", 667 dfui_info_new(_("Switch to Expert Mode"), "", "")); 668 } 669 #endif 670 return(f); 671 } 672 673 /* 674 * Returns: 675 * -1 = the form should be redisplayed 676 * 0 = failure, function is over 677 * 1 = success, function is over 678 */ 679 static int 680 show_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a) 681 { 682 struct dfui_dataset *ds; 683 struct dfui_response *r; 684 685 for (;;) { 686 if (dfui_form_dataset_get_first(f) == NULL) 687 populate_create_subpartitions_form(f, a); 688 689 if (!dfui_be_present(a->c, f, &r)) 690 abort_backend(); 691 692 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { 693 dfui_response_free(r); 694 return(0); 695 } else if (strcmp(dfui_response_get_action_id(r), "switch") == 0) { 696 if (check_subpartition_selections(r, a)) { 697 save_subpartition_selections(r, a); 698 expert = expert ? 0 : 1; 699 dfui_response_free(r); 700 return(-1); 701 } 702 } else { 703 if (check_subpartition_selections(r, a)) { 704 save_subpartition_selections(r, a); 705 if (!warn_subpartition_selections(a) && 706 !warn_encrypted_boot(a)) { 707 if (!create_subpartitions(a)) { 708 inform(a->c, _("The subpartitions you chose were " 709 "not correctly created, and the " 710 "primary partition may " 711 "now be in an inconsistent state. " 712 "We recommend re-formatting it " 713 "before proceeding.")); 714 dfui_response_free(r); 715 return(0); 716 } else { 717 dfui_response_free(r); 718 return(1); 719 } 720 } 721 } 722 } 723 724 dfui_form_datasets_free(f); 725 /* dfui_form_datasets_add_from_response(f, r); */ 726 for (ds = dfui_response_dataset_get_first(r); ds != NULL; 727 ds = dfui_dataset_get_next(ds)) { 728 dfui_form_dataset_add(f, dfui_dataset_dup(ds)); 729 } 730 } 731 } 732 733 /* 734 * fn_create_subpartitions_hammer: let the user specify what subpartitions they 735 * want on the disk, how large each should be, and where it should be mounted. 736 */ 737 void 738 fn_create_subpartitions_hammer(struct i_fn_args *a) 739 { 740 struct dfui_form *f; 741 int done = 0; 742 743 a->result = 0; 744 while (!done) { 745 f = make_create_subpartitions_form(a); 746 switch (show_create_subpartitions_form(f, a)) { 747 case -1: 748 done = 0; 749 break; 750 case 0: 751 done = 1; 752 a->result = 0; 753 break; 754 case 1: 755 done = 1; 756 a->result = 1; 757 break; 758 } 759 dfui_form_free(f); 760 } 761 } 762