1 /* 2 * Copyright (c)2004,2015 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.c 36 * Installer Function : Create Subpartitions. 37 * $Id: fn_subpart.c,v 1.50 2005/04/07 20:22:40 cpressey Exp $ 38 */ 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 44 #ifdef ENABLE_NLS 45 #include <libintl.h> 46 #define _(String) gettext (String) 47 #else 48 #define _(String) (String) 49 #endif 50 51 #include "libaura/mem.h" 52 #include "libaura/buffer.h" 53 #include "libaura/dict.h" 54 #include "libaura/fspred.h" 55 56 #include "libdfui/dfui.h" 57 #include "libdfui/dump.h" 58 #include "libdfui/system.h" 59 60 #include "libinstaller/commands.h" 61 #include "libinstaller/diskutil.h" 62 #include "libinstaller/functions.h" 63 #include "libinstaller/uiutil.h" 64 65 #include "fn.h" 66 #include "flow.h" 67 #include "pathnames.h" 68 69 #define MTPT_BOOT 0 70 #define MTPT_SWAP 1 71 #define MTPT_ROOT 2 72 #define MTPT_BUILD 3 73 74 static int create_subpartitions(struct i_fn_args *); 75 static long default_capacity(struct storage *, const char *); 76 static int check_capacity(struct i_fn_args *); 77 static int check_subpartition_selections(struct dfui_response *, struct i_fn_args *); 78 static void save_subpartition_selections(struct dfui_response *, struct i_fn_args *); 79 static void populate_create_subpartitions_form(struct dfui_form *, struct i_fn_args *); 80 static int warn_subpartition_selections(struct i_fn_args *); 81 static struct dfui_form *make_create_subpartitions_form(struct i_fn_args *); 82 static int show_create_subpartitions_form(struct dfui_form *, struct i_fn_args *); 83 84 static const char *def_mountpt[] = {"/boot", "swap", "/", "/build", NULL}; 85 static long min_capacity[] = { 128, 0, DISK_MIN - 128, BUILD_MIN }; 86 static int expert = 0; 87 88 /* 89 * Given a set of subpartitions-to-be in the selected slice, 90 * create them. 91 */ 92 static int 93 create_subpartitions(struct i_fn_args *a) 94 { 95 struct subpartition *sp; 96 struct commands *cmds; 97 int result = 0; 98 int num_partitions; 99 100 cmds = commands_new(); 101 if (!is_file("%sinstall.disklabel.%s", 102 a->tmp, 103 slice_get_device_name(storage_get_selected_slice(a->s)))) { 104 /* 105 * Get a copy of the 'virgin' disklabel. 106 * XXX It might make more sense for this to 107 * happen right after format_slice() instead. 108 */ 109 command_add(cmds, "%s%s -r %s >%sinstall.disklabel.%s", 110 a->os_root, cmd_name(a, "DISKLABEL64"), 111 slice_get_device_name(storage_get_selected_slice(a->s)), 112 a->tmp, 113 slice_get_device_name(storage_get_selected_slice(a->s))); 114 } 115 116 /* 117 * Weave together a new disklabel out the of the 'virgin' 118 * disklabel, and the user's subpartition choices. 119 */ 120 121 /* 122 * Take everything from the 'virgin' disklabel up until the 123 * '16 partitions' line. 124 */ 125 num_partitions = 16; 126 command_add(cmds, "%s%s '$2==\"partitions:\" || cut { cut = 1 } !cut { print $0 }' <%sinstall.disklabel.%s >%sinstall.disklabel", 127 a->os_root, cmd_name(a, "AWK"), 128 a->tmp, 129 slice_get_device_name(storage_get_selected_slice(a->s)), 130 a->tmp); 131 132 /* 133 * 16 partitions: 134 * # size offset fstype 135 * c: 16383969 0 unused # 7999.985MB 136 */ 137 138 command_add(cmds, "%s%s '%d partitions:' >>%sinstall.disklabel", 139 a->os_root, cmd_name(a, "ECHO"), num_partitions ,a->tmp); 140 command_add(cmds, "%s%s '%s' >>%sinstall.disklabel", 141 a->os_root, cmd_name(a, "ECHO"), 142 "# size offset fstype", 143 a->tmp); 144 145 #ifdef DEBUG 146 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 147 sp != NULL; sp = subpartition_next(sp)) { 148 command_add(cmds, "%s%s 'mountpoint: %s device: %s'", 149 a->os_root, cmd_name(a, "ECHO"), 150 subpartition_get_mountpoint(sp), 151 subpartition_get_device_name(sp)); 152 } 153 #endif 154 155 /* 156 * Write a line for each subpartition the user wants. 157 */ 158 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 159 sp != NULL; sp = subpartition_next(sp)) { 160 if (subpartition_is_tmpfsbacked(sp)) { 161 continue; 162 } 163 if (subpartition_is_swap(sp)) { 164 command_add(cmds, "%s%s ' %c:\t%s\t*\tswap' >>%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%s\t4.2BSD' >>%sinstall.disklabel", 171 a->os_root, cmd_name(a, "ECHO"), 172 subpartition_get_letter(sp), 173 capacity_to_string(subpartition_get_capacity(sp)), 174 subpartition_get_letter(sp) == 'a' ? "0" : "*", 175 a->tmp); 176 } 177 } 178 temp_file_add(a, "install.disklabel"); 179 180 /* 181 * Label the slice from the disklabel we just wove together. 182 */ 183 command_add(cmds, "%s%s -R -B -r %s %sinstall.disklabel", 184 a->os_root, cmd_name(a, "DISKLABEL64"), 185 slice_get_device_name(storage_get_selected_slice(a->s)), 186 a->tmp); 187 188 /* 189 * Create a snapshot of the disklabel we just created 190 * for debugging inspection in the log. 191 */ 192 command_add(cmds, "%s%s %s", 193 a->os_root, cmd_name(a, "DISKLABEL64"), 194 slice_get_device_name(storage_get_selected_slice(a->s))); 195 196 /* 197 * If encryption was specified, load dm(4). 198 */ 199 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 200 sp != NULL; sp = subpartition_next(sp)) { 201 if (subpartition_is_encrypted(sp)) { 202 fn_get_passphrase(a); 203 break; 204 } 205 } 206 207 /* 208 * Create filesystems on the newly-created subpartitions. 209 */ 210 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 211 sp != NULL; sp = subpartition_next(sp)) { 212 if (subpartition_is_swap(sp) || subpartition_is_tmpfsbacked(sp)) { 213 if (subpartition_is_swap(sp) && 214 subpartition_is_encrypted(sp)) { 215 command_add(cmds, 216 "%s%s -d /tmp/t1 luksFormat /dev/%s", 217 a->os_root, cmd_name(a, "CRYPTSETUP"), 218 subpartition_get_device_name(sp)); 219 command_add(cmds, 220 "%s%s -d /tmp/t1 luksOpen /dev/%s swap", 221 a->os_root, cmd_name(a, "CRYPTSETUP"), 222 subpartition_get_device_name(sp)); 223 } 224 continue; 225 } 226 227 if (subpartition_is_encrypted(sp)) { 228 command_add(cmds, 229 "%s%s -d /tmp/t1 luksFormat /dev/%s", 230 a->os_root, cmd_name(a, "CRYPTSETUP"), 231 subpartition_get_device_name(sp)); 232 command_add(cmds, 233 "%s%s -d /tmp/t1 luksOpen /dev/%s %s", 234 a->os_root, cmd_name(a, "CRYPTSETUP"), 235 subpartition_get_device_name(sp), 236 subpartition_get_mapper_name(sp, -1)); 237 command_add(cmds, "%s%s%s -b %ld -f %ld /dev/mapper/%s", 238 a->os_root, cmd_name(a, "NEWFS"), 239 subpartition_is_softupdated(sp) ? " -U" : "", 240 subpartition_get_bsize(sp), 241 subpartition_get_fsize(sp), 242 subpartition_get_mapper_name(sp, -1)); 243 } else { 244 command_add(cmds, "%s%s%s -b %ld -f %ld /dev/%s", 245 a->os_root, cmd_name(a, "NEWFS"), 246 subpartition_is_softupdated(sp) ? " -U" : "", 247 subpartition_get_bsize(sp), 248 subpartition_get_fsize(sp), 249 subpartition_get_device_name(sp)); 250 } 251 } 252 253 result = commands_execute(a, cmds); 254 commands_free(cmds); 255 return(result); 256 } 257 258 /* 259 * Return default capacity field filler. Return 0 for /build if drive 260 * space minus swap is < 40GB (causes installer to use PFS's on the root 261 * partition instead). 262 */ 263 static long 264 default_capacity(struct storage *s, const char *mtpt) 265 { 266 unsigned long boot, root, swap, build; 267 unsigned long capacity; 268 unsigned long mem; 269 270 capacity = slice_get_capacity(storage_get_selected_slice(s)); /* MB */ 271 mem = storage_get_memsize(s); 272 273 /* 274 * Slice capacity is at least 10G at this point. Calculate basic 275 * defaults. 276 */ 277 swap = 2 * mem; 278 if (swap > capacity / 10) /* max 1/10 capacity */ 279 swap = capacity / 10; 280 if (swap < SWAP_MIN) /* having a little is nice */ 281 swap = SWAP_MIN; 282 if (swap > SWAP_MAX) /* installer cap */ 283 swap = SWAP_MAX; 284 285 boot = 1024; 286 287 build = (capacity - swap - boot) / 4; 288 #if 0 289 /* 290 * No longer cap the size of /build, the assumption didn't hold 291 * well particularly with /var/crash being placed on /build now. 292 */ 293 if (build > BUILD_MAX) 294 build = BUILD_MAX; 295 #endif 296 297 for (;;) { 298 root = (capacity - swap - boot - build); 299 300 /* 301 * Adjust until the defaults look sane 302 * 303 * root should be at least twice as large as build 304 */ 305 if (build && root < build * 2) { 306 --build; 307 continue; 308 } 309 310 /* 311 * root should be at least 1/2 capacity 312 */ 313 if (build && root < capacity / 2) { 314 --build; 315 continue; 316 } 317 break; 318 } 319 320 /* 321 * Finalize. If build is too small do not supply a /build, 322 * and if swap is too small do not supply swap. Cascade the 323 * released space to swap and root. 324 */ 325 if (build < BUILD_MIN) { 326 if (swap < SWAP_MIN && build >= SWAP_MIN - swap) { 327 build -= SWAP_MIN - swap; 328 swap = SWAP_MIN; 329 } 330 if (swap < 2 * mem && build >= 2 * mem - swap) { 331 build -= 2 * mem - swap; 332 swap = 2 * mem; 333 } 334 root += build; 335 build = 0; 336 } 337 if (swap < SWAP_MIN) { 338 root += swap; 339 swap = 0; 340 } 341 342 if (build == 0) 343 root = -1; /* no /build, root is the last part */ 344 else 345 build = -1; /* last partition just use remaining space */ 346 347 if (strcmp(mtpt, "/boot") == 0) 348 return(boot); 349 else if (strcmp(mtpt, "/build") == 0) 350 return(build); 351 else if (strcmp(mtpt, "swap") == 0) 352 return(swap); 353 else if (strcmp(mtpt, "/") == 0) 354 return(root); 355 356 /* shouldn't ever happen */ 357 return(-1); 358 } 359 360 static int 361 check_capacity(struct i_fn_args *a) 362 { 363 struct subpartition *sp; 364 unsigned long total_capacity = 0; 365 int mtpt; 366 367 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 368 sp != NULL; sp = subpartition_next(sp)) { 369 long subpart_capacity = subpartition_get_capacity(sp); 370 const char *mountpt = subpartition_get_mountpoint(sp); 371 372 if (subpart_capacity == -1) 373 total_capacity++; 374 else 375 total_capacity += subpart_capacity; 376 for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) { 377 if (strcmp(mountpt, def_mountpt[mtpt]) == 0 && 378 subpart_capacity < min_capacity[mtpt] && 379 subpart_capacity != -1) { 380 inform(a->c, _("WARNING: The size (%ldM) specified for " 381 "the %s subpartition is too small. It " 382 "should be at least %ldM or you will " 383 "risk running out of space during " 384 "the installation."), 385 subpart_capacity, mountpt, 386 min_capacity[mtpt]); 387 } 388 } 389 } 390 391 if (total_capacity > slice_get_capacity(storage_get_selected_slice(a->s))) { 392 inform(a->c, _("The space allocated to all of your selected " 393 "subpartitions (%luM) exceeds the total " 394 "capacity of the selected primary partition " 395 "(%luM). Remove some subpartitions or choose " 396 "a smaller size for them and try again."), 397 total_capacity, slice_get_capacity(storage_get_selected_slice(a->s))); 398 return(0); 399 } 400 401 return(1); 402 } 403 404 static int 405 check_subpartition_selections(struct dfui_response *r, struct i_fn_args *a) 406 { 407 struct dfui_dataset *ds; 408 struct dfui_dataset *star_ds = NULL; 409 struct aura_dict *d; 410 const char *mountpoint, *capstring; 411 long capacity = 0; 412 int found_root = 0; 413 int valid = 1; 414 415 d = aura_dict_new(1, AURA_DICT_LIST); 416 417 if ((ds = dfui_response_dataset_get_first(r)) == NULL) { 418 inform(a->c, _("Please set up at least one subpartition.")); 419 valid = 0; 420 } 421 422 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL; 423 ds = dfui_dataset_get_next(ds)) { 424 #ifdef DEBUG 425 dfui_dataset_dump(ds); 426 #endif 427 mountpoint = dfui_dataset_get_value(ds, "mountpoint"); 428 capstring = dfui_dataset_get_value(ds, "capacity"); 429 430 if (expert) { 431 int tmpfsbacked; 432 433 tmpfsbacked = (strcmp(dfui_dataset_get_value(ds, "tmpfsbacked"), "Y") == 0); 434 if (tmpfsbacked && strcmp(mountpoint, "/") == 0) { 435 inform(a->c, _("/ cannot be TMPFS backed.")); 436 valid = 0; 437 } 438 } 439 440 if (aura_dict_exists(d, mountpoint, strlen(mountpoint) + 1)) { 441 inform(a->c, _("The same mount point cannot be specified " 442 "for two different subpartitions.")); 443 valid = 0; 444 } 445 446 if (strcmp(mountpoint, "/") == 0) 447 found_root = 1; 448 449 if (strcmp(capstring, "*") == 0) { 450 if (star_ds != NULL) { 451 inform(a->c, _("You cannot have more than one subpartition " 452 "with a '*' capacity (meaning 'use the remainder " 453 "of the primary partition'.)")); 454 valid = 0; 455 } else { 456 star_ds = ds; 457 } 458 } 459 460 if (!(!strcasecmp(mountpoint, "swap") || mountpoint[0] == '/')) { 461 inform(a->c, _("Mount point must be either 'swap', or it must " 462 "start with a '/'.")); 463 valid = 0; 464 } 465 466 if (strpbrk(mountpoint, " \\\"'`") != NULL) { 467 inform(a->c, _("Mount point may not contain the following " 468 "characters: blank space, backslash, or " 469 "single, double, or back quotes.")); 470 valid = 0; 471 } 472 473 if (strlen(capstring) == 0) { 474 inform(a->c, _("A capacity must be specified.")); 475 valid = 0; 476 } 477 478 if (!string_to_capacity(capstring, &capacity)) { 479 inform(a->c, _("Capacity must be either a '*' symbol " 480 "to indicate 'use the rest of the primary " 481 "partition', or it must be a series of decimal " 482 "digits ending with an 'M' (indicating " 483 "megabytes), a 'G' (indicating gigabytes) and " 484 "so on (up to 'E'.)")); 485 valid = 0; 486 } 487 488 /* 489 * Maybe remove this limit entirely? 490 */ 491 if ((strcasecmp(mountpoint, "swap") == 0) && 492 (capacity > SWAP_MAX)) { 493 inform(a->c, _("Swap capacity is limited to %dG."), 494 SWAP_MAX / 1024); 495 valid = 0; 496 } 497 498 /* 499 * If we made it through that obstacle course, all is well. 500 */ 501 502 if (valid) 503 aura_dict_store(d, mountpoint, strlen(mountpoint) + 1, "", 1); 504 } 505 506 if (!found_root) { 507 inform(a->c, _("You must include a / (root) subpartition.")); 508 valid = 0; 509 } 510 511 if (aura_dict_size(d) > 16) { 512 inform(a->c, _("You cannot have more than 16 subpartitions " 513 "on a single primary partition. Remove some " 514 "and try again.")); 515 valid = 0; 516 } 517 518 aura_dict_free(d); 519 520 return(valid); 521 } 522 523 static void 524 save_subpartition_selections(struct dfui_response *r, struct i_fn_args *a) 525 { 526 struct dfui_dataset *ds; 527 char tmpfsbacked; 528 const char *mountpoint, *capstring; 529 long capacity; 530 long bsize, fsize; 531 int softupdates; 532 int valid = 1; 533 534 subpartitions_free(storage_get_selected_slice(a->s)); 535 536 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL; 537 ds = dfui_dataset_get_next(ds)) { 538 mountpoint = dfui_dataset_get_value(ds, "mountpoint"); 539 capstring = dfui_dataset_get_value(ds, "capacity"); 540 541 if (expert) { 542 softupdates = 543 (strcmp(dfui_dataset_get_value(ds, "softupdates"), "Y") == 0); 544 fsize = atol(dfui_dataset_get_value(ds, "fsize")); 545 bsize = atol(dfui_dataset_get_value(ds, "bsize")); 546 tmpfsbacked = (strcmp(dfui_dataset_get_value(ds, "tmpfsbacked"), "Y") == 0); 547 } else { 548 softupdates = (strcmp(mountpoint, "/boot") == 0 ? 0 : 1); 549 tmpfsbacked = 0; 550 fsize = -1; 551 bsize = -1; 552 } 553 554 if (string_to_capacity(capstring, &capacity)) { 555 subpartition_new_ufs(storage_get_selected_slice(a->s), 556 mountpoint, capacity, 557 strcasecmp(dfui_dataset_get_value(ds, "encrypted"), "Y") == 0, 558 softupdates, fsize, bsize, tmpfsbacked); 559 } 560 } 561 } 562 563 static void 564 populate_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a) 565 { 566 struct subpartition *sp; 567 struct dfui_dataset *ds; 568 char temp[32]; 569 int mtpt; 570 long capacity; 571 572 if (slice_subpartition_first(storage_get_selected_slice(a->s)) != NULL) { 573 /* 574 * The user has already given us their subpartition 575 * preferences, so use them here. 576 */ 577 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s)); 578 sp != NULL; sp = subpartition_next(sp)) { 579 ds = dfui_dataset_new(); 580 dfui_dataset_celldata_add(ds, "mountpoint", 581 subpartition_get_mountpoint(sp)); 582 dfui_dataset_celldata_add(ds, "capacity", 583 capacity_to_string(subpartition_get_capacity(sp))); 584 dfui_dataset_celldata_add(ds, "encrypted", 585 subpartition_is_encrypted(sp) ? "Y" : "N"); 586 if (expert) { 587 dfui_dataset_celldata_add(ds, "softupdates", 588 subpartition_is_softupdated(sp) ? "Y" : "N"); 589 dfui_dataset_celldata_add(ds, "tmpfsbacked", 590 subpartition_is_tmpfsbacked(sp) ? "Y" : "N"); 591 snprintf(temp, 32, "%ld", subpartition_get_fsize(sp)); 592 dfui_dataset_celldata_add(ds, "fsize", 593 temp); 594 snprintf(temp, 32, "%ld", subpartition_get_bsize(sp)); 595 dfui_dataset_celldata_add(ds, "bsize", 596 temp); 597 } 598 dfui_form_dataset_add(f, ds); 599 } 600 } else { 601 /* 602 * Otherwise, populate the form with datasets representing 603 * reasonably-calculated defaults. The defaults are chosen 604 * based on the slice's total capacity and the machine's 605 * total physical memory (for swap.) 606 */ 607 for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) { 608 capacity = default_capacity(a->s, def_mountpt[mtpt]); 609 if (capacity == 0) 610 continue; 611 ds = dfui_dataset_new(); 612 dfui_dataset_celldata_add(ds, "mountpoint", 613 def_mountpt[mtpt]); 614 dfui_dataset_celldata_add(ds, "capacity", 615 capacity_to_string(capacity)); 616 dfui_dataset_celldata_add(ds, "encrypted", "N"); 617 if (expert) { 618 dfui_dataset_celldata_add(ds, "softupdates", 619 strcmp(def_mountpt[mtpt], "/boot") != 0 ? "Y" : "N"); 620 dfui_dataset_celldata_add(ds, "tmpfsbacked", 621 "N"); 622 dfui_dataset_celldata_add(ds, "fsize", 623 capacity < 1024 ? "1024" : "2048"); 624 dfui_dataset_celldata_add(ds, "bsize", 625 capacity < 1024 ? "8192" : "16384"); 626 } 627 dfui_form_dataset_add(f, ds); 628 } 629 } 630 } 631 632 static int 633 warn_subpartition_selections(struct i_fn_args *a) 634 { 635 int valid = 0; 636 637 /* Skip this check for disks <= 8GB */ 638 if (slice_get_capacity(storage_get_selected_slice(a->s)) <= 8192) 639 return 0; 640 641 valid = check_capacity(a); 642 643 return(!valid); 644 } 645 646 static struct dfui_form * 647 make_create_subpartitions_form(struct i_fn_args *a) 648 { 649 struct dfui_field *fi; 650 struct dfui_form *f; 651 char msg_buf[1][1024]; 652 653 snprintf(msg_buf[0], sizeof(msg_buf[0]), 654 _("Subpartitions further divide a primary partition for " 655 "use with %s. Some reasons you may want " 656 "a set of subpartitions are:\n\n" 657 "- you want to restrict how much data can be written " 658 "to certain parts of the primary partition, to quell " 659 "denial-of-service attacks; and\n" 660 "- you want to speed up access to data on the disk." 661 ""), OPERATING_SYSTEM_NAME); 662 663 f = dfui_form_create( 664 "create_subpartitions", 665 _("Create Subpartitions"), 666 _("Set up the subpartitions (also known as just `partitions' " 667 "in BSD tradition) you want to have on this primary " 668 "partition.\n\n" 669 "For Capacity, use 'M' to indicate megabytes, 'G' to " 670 "indicate gigabytes, and so on (up to 'E'.) A single '*' " 671 "indicates 'use the remaining space on the primary partition'."), 672 673 msg_buf[0], 674 675 "p", "special", "dfinstaller_create_subpartitions", 676 "p", "minimum_width","64", 677 678 "f", "mountpoint", _("Mountpoint"), "", "", 679 "f", "capacity", _("Capacity"), "", "", 680 681 "f", "encrypted", _("Encrypted"), "", "", 682 "p", "control", "checkbox", 683 684 "a", "ok", _("Accept and Create"), "", "", 685 "a", "cancel", 686 (disk_get_formatted(storage_get_selected_disk(a->s)) ? 687 _("Return to Select Disk") : 688 _("Return to Select Primary Partition")), "", "", 689 "p", "accelerator", "ESC", 690 691 NULL 692 ); 693 694 dfui_form_set_multiple(f, 1); 695 dfui_form_set_extensible(f, 1); 696 697 if (expert) { 698 fi = dfui_form_field_add(f, "softupdates", 699 dfui_info_new(_("Softupdates"), "", "")); 700 dfui_field_property_set(fi, "control", "checkbox"); 701 702 fi = dfui_form_field_add(f, "tmpfsbacked", 703 dfui_info_new(_("TMPFS"), "", "")); 704 dfui_field_property_set(fi, "control", "checkbox"); 705 706 fi = dfui_form_field_add(f, "fsize", 707 dfui_info_new(_("Frag Sz"), "", "")); 708 709 fi = dfui_form_field_add(f, "bsize", 710 dfui_info_new(_("Block Sz"), "", "")); 711 712 dfui_form_action_add(f, "switch", 713 dfui_info_new(_("Switch to Normal Mode"), "", "")); 714 } else { 715 dfui_form_action_add(f, "switch", 716 dfui_info_new(_("Switch to Expert Mode"), "", "")); 717 } 718 719 return(f); 720 } 721 722 /* 723 * Returns: 724 * -1 = the form should be redisplayed 725 * 0 = failure, function is over 726 * 1 = success, function is over 727 */ 728 static int 729 show_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a) 730 { 731 struct dfui_dataset *ds; 732 struct dfui_response *r; 733 734 for (;;) { 735 if (dfui_form_dataset_get_first(f) == NULL) 736 populate_create_subpartitions_form(f, a); 737 738 if (!dfui_be_present(a->c, f, &r)) 739 abort_backend(); 740 741 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) { 742 dfui_response_free(r); 743 return(0); 744 } else if (strcmp(dfui_response_get_action_id(r), "switch") == 0) { 745 if (check_subpartition_selections(r, a)) { 746 save_subpartition_selections(r, a); 747 expert = expert ? 0 : 1; 748 dfui_response_free(r); 749 return(-1); 750 } 751 } else { 752 if (check_subpartition_selections(r, a)) { 753 save_subpartition_selections(r, a); 754 if (!warn_subpartition_selections(a)) { 755 if (!create_subpartitions(a)) { 756 inform(a->c, _("The subpartitions you chose were " 757 "not correctly created, and the " 758 "primary partition may " 759 "now be in an inconsistent state. " 760 "We recommend re-formatting it " 761 "before proceeding.")); 762 dfui_response_free(r); 763 return(0); 764 } else { 765 dfui_response_free(r); 766 return(1); 767 } 768 } 769 } 770 } 771 772 dfui_form_datasets_free(f); 773 /* dfui_form_datasets_add_from_response(f, r); */ 774 for (ds = dfui_response_dataset_get_first(r); ds != NULL; 775 ds = dfui_dataset_get_next(ds)) { 776 dfui_form_dataset_add(f, dfui_dataset_dup(ds)); 777 } 778 } 779 } 780 781 void 782 fn_create_subpartitions_ufs(struct i_fn_args *a) 783 { 784 struct dfui_form *f; 785 unsigned long capacity; 786 int done = 0; 787 788 a->result = 0; 789 capacity = slice_get_capacity(storage_get_selected_slice(a->s)); 790 if (capacity < DISK_MIN) { 791 inform(a->c, _("The selected disk is smaller than the " 792 "required %dM for the UFS filesystem."), DISK_MIN); 793 return; 794 } 795 #if 0 796 if (capacity <= 8192) 797 def_mountpt[2] = NULL; /* XXX adjust each time in a session */ 798 #endif 799 while (!done) { 800 f = make_create_subpartitions_form(a); 801 switch (show_create_subpartitions_form(f, a)) { 802 case -1: 803 done = 0; 804 break; 805 case 0: 806 done = 1; 807 a->result = 0; 808 break; 809 case 1: 810 done = 1; 811 a->result = 1; 812 break; 813 } 814 dfui_form_free(f); 815 } 816 } 817