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 > 8192) 280 swap = 8192; 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."))); 363 364 return(1); 365 } 366 367 static int 368 check_subpartition_selections(struct dfui_response *r, struct i_fn_args *a) 369 { 370 struct dfui_dataset *ds; 371 struct dfui_dataset *star_ds = NULL; 372 struct aura_dict *d; 373 const char *mountpoint, *capstring; 374 long capacity = 0; 375 int found_root = 0; 376 int valid = 1; 377 378 d = aura_dict_new(1, AURA_DICT_LIST); 379 380 if ((ds = dfui_response_dataset_get_first(r)) == NULL) { 381 inform(a->c, _("Please set up at least one subpartition.")); 382 valid = 0; 383 } 384 385 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL; 386 ds = dfui_dataset_get_next(ds)) { 387 #ifdef DEBUG 388 dfui_dataset_dump(ds); 389 #endif 390 mountpoint = dfui_dataset_get_value(ds, "mountpoint"); 391 capstring = dfui_dataset_get_value(ds, "capacity"); 392 393 if (aura_dict_exists(d, mountpoint, strlen(mountpoint) + 1)) { 394 inform(a->c, _("The same mount point cannot be specified " 395 "for two different subpartitions.")); 396 valid = 0; 397 } 398 399 if (strcmp(mountpoint, "/") == 0) 400 found_root = 1; 401 402 if (strcmp(capstring, "*") == 0) { 403 if (star_ds != NULL) { 404 inform(a->c, _("You cannot have more than one subpartition " 405 "with a '*' capacity (meaning 'use the remainder " 406 "of the primary partition'.)")); 407 valid = 0; 408 } else { 409 star_ds = ds; 410 } 411 } 412 413 if (!(!strcasecmp(mountpoint, "swap") || mountpoint[0] == '/')) { 414 inform(a->c, _("Mount point must be either 'swap', or it must " 415 "start with a '/'.")); 416 valid = 0; 417 } 418 419 if (strpbrk(mountpoint, " \\\"'`") != NULL) { 420 inform(a->c, _("Mount point may not contain the following " 421 "characters: blank space, backslash, or " 422 "single, double, or back quotes.")); 423 valid = 0; 424 } 425 426 if (strlen(capstring) == 0) { 427 inform(a->c, _("A capacity must be specified.")); 428 valid = 0; 429 } 430 431 if (!string_to_capacity(capstring, &capacity)) { 432 inform(a->c, _("Capacity must be either a '*' symbol to indicate " 433 "'use the rest of the primary partition', or it " 434 "must be a series of decimal digits ending with a " 435 "'M' (indicating megabytes) or a 'G' (indicating " 436 "gigabytes.)")); 437 valid = 0; 438 } 439 440 if ((strcasecmp(mountpoint, "swap") == 0) && (capacity > 8192)) { 441 inform(a->c, _("Swap capacity is limited to 8G.")); 442 valid = 0; 443 } 444 445 /* 446 * If we made it through that obstacle course, all is well. 447 */ 448 449 if (valid) 450 aura_dict_store(d, mountpoint, strlen(mountpoint) + 1, "", 1); 451 } 452 453 if (!found_root) { 454 inform(a->c, _("You must include a / (root) subpartition.")); 455 valid = 0; 456 } 457 458 if (aura_dict_size(d) > 16) { 459 inform(a->c, _("You cannot have more than 16 subpartitions " 460 "on a single primary partition. Remove some " 461 "and try again.")); 462 valid = 0; 463 } 464 465 aura_dict_free(d); 466 467 return(valid); 468 } 469 470 static void 471 save_subpartition_selections(struct dfui_response *r, struct i_fn_args *a) 472 { 473 struct dfui_dataset *ds; 474 const char *mountpoint, *capstring; 475 long capacity; 476 int valid = 1; 477 478 subpartitions_free(storage_get_selected_slice(a->s)); 479 480 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL; 481 ds = dfui_dataset_get_next(ds)) { 482 mountpoint = dfui_dataset_get_value(ds, "mountpoint"); 483 capstring = dfui_dataset_get_value(ds, "capacity"); 484 485 if (string_to_capacity(capstring, &capacity)) { 486 subpartition_new_hammer(storage_get_selected_slice(a->s), 487 mountpoint, capacity, 488 strcasecmp(dfui_dataset_get_value(ds, "encrypted"), "Y") == 0); 489 } 490 } 491 } 492 493 static void 494 populate_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a) 495 { 496 struct subpartition *sp; 497 struct dfui_dataset *ds; 498 int i; 499 long capacity; 500 501 if (slice_subpartition_first(storage_get_selected_slice(a->s)) != NULL) { 502 /* 503 * The user has already given us their subpartition 504 * preferences, so use them here. 505 */ 506 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 507 sp != NULL; sp = subpartition_next(sp)) { 508 ds = dfui_dataset_new(); 509 dfui_dataset_celldata_add(ds, "mountpoint", 510 subpartition_get_mountpoint(sp)); 511 dfui_dataset_celldata_add(ds, "capacity", 512 capacity_to_string(subpartition_get_capacity(sp))); 513 dfui_dataset_celldata_add(ds, "encrypted", 514 subpartition_is_encrypted(sp) ? "Y" : "N"); 515 dfui_form_dataset_add(f, ds); 516 } 517 } else { 518 /* 519 * Otherwise, populate the form with datasets representing 520 * reasonably-calculated defaults. The defaults are chosen 521 * based on the slice's total capacity and the machine's 522 * total physical memory (for swap.) 523 */ 524 for (i = 0; def_mountpt[i] != NULL; i++) { 525 capacity = default_capacity(a->s, def_mountpt[i]); 526 ds = dfui_dataset_new(); 527 dfui_dataset_celldata_add(ds, "mountpoint", 528 def_mountpt[i]); 529 dfui_dataset_celldata_add(ds, "capacity", 530 capacity_to_string(capacity)); 531 dfui_dataset_celldata_add(ds, "encrypted", "N"); 532 dfui_form_dataset_add(f, ds); 533 } 534 } 535 } 536 537 static int 538 warn_subpartition_selections(struct i_fn_args *a) 539 { 540 int valid = 0; 541 542 if (subpartition_find(storage_get_selected_slice(a->s), "/boot") == NULL) { 543 inform(a->c, _("The /boot partition must not be omitted.")); 544 } else if (subpartition_find(storage_get_selected_slice(a->s), "/home") != NULL || 545 subpartition_find(storage_get_selected_slice(a->s), "/tmp") != NULL || 546 subpartition_find(storage_get_selected_slice(a->s), "/usr") != NULL || 547 subpartition_find(storage_get_selected_slice(a->s), "/usr/obj") != NULL || 548 subpartition_find(storage_get_selected_slice(a->s), "/var") != NULL || 549 subpartition_find(storage_get_selected_slice(a->s), "/var/crash") != NULL || 550 subpartition_find(storage_get_selected_slice(a->s), "/var/tmp") != NULL) { 551 inform(a->c, _("Pseudo filesystems will automatically be created " 552 "for /home, /tmp, /usr, /usr/obj, /var, /var/crash " 553 "and /var/tmp and must not be specified.")); 554 } else { 555 valid = check_capacity(a); 556 } 557 558 return(!valid); 559 } 560 561 static int 562 warn_encrypted_boot(struct i_fn_args *a) 563 { 564 int valid = 1; 565 566 struct subpartition *sp; 567 568 sp = subpartition_find(storage_get_selected_slice(a->s), "/boot"); 569 if (sp == NULL) 570 return(!valid); 571 572 if (subpartition_is_encrypted(sp)) { 573 switch (dfui_be_present_dialog(a->c, _("/boot cannot be encrypted"), 574 _("Leave /boot unencrypted|Return to Create Subpartitions"), 575 _("You have selected encryption for the /boot partition which " 576 "is not supported."))) { 577 case 1: 578 valid = 1; 579 break; 580 case 2: 581 valid = 0; 582 break; 583 default: 584 abort_backend(); 585 } 586 } 587 588 return(!valid); 589 } 590 591 static struct dfui_form * 592 make_create_subpartitions_form(struct i_fn_args *a) 593 { 594 struct dfui_form *f; 595 char msg_buf[1][1024]; 596 597 snprintf(msg_buf[0], sizeof(msg_buf[0]), 598 _("Subpartitions further divide a primary partition for " 599 "use with %s. Some reasons you may want " 600 "a set of subpartitions are:\n\n" 601 "- you want to restrict how much data can be written " 602 "to certain parts of the primary partition, to quell " 603 "denial-of-service attacks; and\n" 604 "- you want to speed up access to data on the disk." 605 ""), OPERATING_SYSTEM_NAME); 606 607 f = dfui_form_create( 608 "create_subpartitions", 609 _("Create Subpartitions"), 610 _("Set up the subpartitions (also known as just `partitions' " 611 "in BSD tradition) you want to have on this primary " 612 "partition. In most cases you should be fine with " 613 "the default settings.\n\n" 614 "For Capacity, use 'M' to indicate megabytes, 'G' to " 615 "indicate gigabytes, or a single '*' to indicate " 616 "'use the remaining space on the primary partition'."), 617 618 msg_buf[0], 619 620 "p", "special", "dfinstaller_create_subpartitions", 621 "p", "minimum_width","64", 622 623 "f", "mountpoint", _("Mountpoint"), "", "", 624 "f", "capacity", _("Capacity"), "", "", 625 626 "f", "encrypted", _("Encrypted"), "", "", 627 "p", "control", "checkbox", 628 629 "a", "ok", _("Accept and Create"), "", "", 630 "a", "cancel", 631 (disk_get_formatted(storage_get_selected_disk(a->s)) ? 632 _("Return to Select Disk") : 633 _("Return to Select Primary Partition")), "", "", 634 "p", "accelerator", "ESC", 635 636 NULL 637 ); 638 639 dfui_form_set_multiple(f, 1); 640 dfui_form_set_extensible(f, 1); 641 /* 642 * Remove ATM until HAMMER installer support is better 643 * dfui_form_set_extensible(f, 1); 644 */ 645 #if 0 646 if (expert) { 647 fi = dfui_form_field_add(f, "softupdates", 648 dfui_info_new(_("Softupdates"), "", "")); 649 dfui_field_property_set(fi, "control", "checkbox"); 650 651 fi = dfui_form_field_add(f, "tmpfsbacked", 652 dfui_info_new(_("TMPFS"), "", "")); 653 dfui_field_property_set(fi, "control", "checkbox"); 654 655 fi = dfui_form_field_add(f, "fsize", 656 dfui_info_new(_("Frag Sz"), "", "")); 657 658 fi = dfui_form_field_add(f, "bsize", 659 dfui_info_new(_("Block Sz"), "", "")); 660 661 dfui_form_action_add(f, "switch", 662 dfui_info_new(_("Switch to Normal Mode"), "", "")); 663 } else { 664 dfui_form_action_add(f, "switch", 665 dfui_info_new(_("Switch to Expert Mode"), "", "")); 666 } 667 #endif 668 return(f); 669 } 670 671 /* 672 * Returns: 673 * -1 = the form should be redisplayed 674 * 0 = failure, function is over 675 * 1 = success, function is over 676 */ 677 static int 678 show_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a) 679 { 680 struct dfui_dataset *ds; 681 struct dfui_response *r; 682 683 for (;;) { 684 if (dfui_form_dataset_get_first(f) == NULL) 685 populate_create_subpartitions_form(f, a); 686 687 if (!dfui_be_present(a->c, f, &r)) 688 abort_backend(); 689 690 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { 691 dfui_response_free(r); 692 return(0); 693 } else if (strcmp(dfui_response_get_action_id(r), "switch") == 0) { 694 if (check_subpartition_selections(r, a)) { 695 save_subpartition_selections(r, a); 696 expert = expert ? 0 : 1; 697 dfui_response_free(r); 698 return(-1); 699 } 700 } else { 701 if (check_subpartition_selections(r, a)) { 702 save_subpartition_selections(r, a); 703 if (!warn_subpartition_selections(a) && 704 !warn_encrypted_boot(a)) { 705 if (!create_subpartitions(a)) { 706 inform(a->c, _("The subpartitions you chose were " 707 "not correctly created, and the " 708 "primary partition may " 709 "now be in an inconsistent state. " 710 "We recommend re-formatting it " 711 "before proceeding.")); 712 dfui_response_free(r); 713 return(0); 714 } else { 715 dfui_response_free(r); 716 return(1); 717 } 718 } 719 } 720 } 721 722 dfui_form_datasets_free(f); 723 /* dfui_form_datasets_add_from_response(f, r); */ 724 for (ds = dfui_response_dataset_get_first(r); ds != NULL; 725 ds = dfui_dataset_get_next(ds)) { 726 dfui_form_dataset_add(f, dfui_dataset_dup(ds)); 727 } 728 } 729 } 730 731 /* 732 * fn_create_subpartitions_hammer: let the user specify what subpartitions they 733 * want on the disk, how large each should be, and where it should be mounted. 734 */ 735 void 736 fn_create_subpartitions_hammer(struct i_fn_args *a) 737 { 738 struct dfui_form *f; 739 int done = 0; 740 741 a->result = 0; 742 while (!done) { 743 f = make_create_subpartitions_form(a); 744 switch (show_create_subpartitions_form(f, a)) { 745 case -1: 746 done = 0; 747 break; 748 case 0: 749 done = 1; 750 a->result = 0; 751 break; 752 case 1: 753 done = 1; 754 a->result = 1; 755 break; 756 } 757 dfui_form_free(f); 758 } 759 } 760