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