installer: Check the user-entered swap size against our actual limits, too.
[dragonfly.git] / usr.sbin / installer / dfuibe_installer / fn_subpart_hammer.c
CommitLineData
7eae318c
MS
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
68static int create_subpartitions(struct i_fn_args *);
e6847d54 69static long default_capacity(struct storage *, const char *);
7eae318c
MS
70static int check_capacity(struct i_fn_args *);
71static int check_subpartition_selections(struct dfui_response *, struct i_fn_args *);
72static void save_subpartition_selections(struct dfui_response *, struct i_fn_args *);
73static void populate_create_subpartitions_form(struct dfui_form *, struct i_fn_args *);
74static int warn_subpartition_selections(struct i_fn_args *);
88cfb1f7 75static int warn_encrypted_boot(struct i_fn_args *);
7eae318c
MS
76static struct dfui_form *make_create_subpartitions_form(struct i_fn_args *);
77static int show_create_subpartitions_form(struct dfui_form *, struct i_fn_args *);
78
e6847d54 79static const char *def_mountpt[] = {"/boot", "swap", "/", NULL};
7eae318c
MS
80static int expert = 0;
81
82/*
83 * Given a set of subpartitions-to-be in the selected slice,
84 * create them.
85 */
86static int
87create_subpartitions(struct i_fn_args *a)
88{
89 struct subpartition *sp;
90 struct commands *cmds;
91 int result = 0;
7eae318c
MS
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)) {
761cad2f 154 if (subpartition_is_tmpfsbacked(sp)) {
7eae318c
MS
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);
e6847d54
SW
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);
7eae318c 169 } else {
e6847d54 170 command_add(cmds, "%s%s ' %c:\t%s\t*\tHAMMER' >>%sinstall.disklabel",
7eae318c
MS
171 a->os_root, cmd_name(a, "ECHO"),
172 subpartition_get_letter(sp),
173 capacity_to_string(subpartition_get_capacity(sp)),
7eae318c
MS
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
88cfb1f7
SW
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
7eae318c
MS
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)) {
88cfb1f7
SW
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 }
7eae318c 225 continue;
88cfb1f7 226 }
7eae318c 227
e6847d54
SW
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 {
88cfb1f7
SW
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 }
e6847d54
SW
246 command_add(cmds, "%s%s -f -L ROOT %sdev/%s",
247 a->os_root, cmd_name(a, "NEWFS_HAMMER"),
248 a->os_root,
88cfb1f7
SW
249 subpartition_is_encrypted(sp) ?
250 "mapper/root" : subpartition_get_device_name(sp));
e6847d54 251 }
7eae318c
MS
252 }
253
254 result = commands_execute(a, cmds);
255 commands_free(cmds);
256 return(result);
257}
258
259static long
e6847d54 260default_capacity(struct storage *s, const char *mtpt)
7eae318c 261{
aaeebad4 262 unsigned long boot, root, swap;
7eae318c 263 unsigned long capacity;
6cd7259e
SW
264 unsigned long mem;
265
7eae318c 266 capacity = slice_get_capacity(storage_get_selected_slice(s));
6cd7259e 267 mem = storage_get_memsize(s);
aaeebad4
SW
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;
6cd7259e 278 swap = 2 * mem;
f76463ce
SW
279 if (swap > SWAP_MAX)
280 swap = SWAP_MAX;
aaeebad4
SW
281 boot = 768;
282 while (boot + root > capacity - 384)
283 boot -= 128;
284 if (boot + root + swap > capacity)
285 swap = capacity - boot - root;
7eae318c 286
aaeebad4 287 if (capacity < DISK_MIN)
7eae318c 288 return(-1);
aaeebad4
SW
289 else if (strcmp(mtpt, "/boot") == 0)
290 return(boot);
291 else if (strcmp(mtpt, "swap") == 0)
e6847d54 292 return(swap);
aaeebad4 293 else if (strcmp(mtpt, "/") == 0)
e6847d54 294 return(-1);
aaeebad4 295
7eae318c
MS
296 /* shouldn't ever happen */
297 return(-1);
298}
299
300static int
301check_capacity(struct i_fn_args *a)
302{
303 struct subpartition *sp;
a9879eb2 304 long min_capacity[] = {128, 0, DISK_MIN - 128, 0};
7eae318c 305 unsigned long total_capacity = 0;
aaeebad4
SW
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 }
7eae318c 315
7eae318c
MS
316 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
317 sp != NULL; sp = subpartition_next(sp)) {
a41800d7
SW
318 long subpart_capacity = subpartition_get_capacity(sp);
319 const char *mountpt = subpartition_get_mountpoint(sp);
320
321 if (subpart_capacity == -1)
7eae318c
MS
322 total_capacity++;
323 else
a41800d7 324 total_capacity += subpart_capacity;
7eae318c 325 for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) {
a41800d7
SW
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 "
7eae318c
MS
332 "risk running out of space during "
333 "the installation."),
a41800d7
SW
334 subpart_capacity, mountpt,
335 min_capacity[mtpt]);
7eae318c
MS
336 }
337 }
a41800d7
SW
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))
f3ba2c0c
SW
342 warn_smallpart++;
343 }
7eae318c
MS
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 "
59b733d3 348 "subpartitions (%luM) exceeds the total "
7eae318c 349 "capacity of the selected primary partition "
59b733d3 350 "(%luM). Remove some subpartitions or choose "
7eae318c
MS
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
aaeebad4
SW
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
7eae318c
MS
364 return(1);
365}
366
367static int
368check_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;
7eae318c
MS
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");
66764e14 392
7eae318c
MS
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
268b6264
MD
440 /*
441 * Maybe remove this limit entirely?
442 */
443 if ((strcasecmp(mountpoint, "swap") == 0) &&
ef48e483
SW
444 (capacity > SWAP_MAX)) {
445 inform(a->c, _("Swap capacity is limited to %dG."),
446 SWAP_MAX / 1024);
4b220078
SW
447 valid = 0;
448 }
449
7eae318c
MS
450 /*
451 * If we made it through that obstacle course, all is well.
452 */
453
454 if (valid)
455 aura_dict_store(d, mountpoint, strlen(mountpoint) + 1, "", 1);
456 }
457
458 if (!found_root) {
459 inform(a->c, _("You must include a / (root) subpartition."));
460 valid = 0;
461 }
462
463 if (aura_dict_size(d) > 16) {
464 inform(a->c, _("You cannot have more than 16 subpartitions "
465 "on a single primary partition. Remove some "
466 "and try again."));
467 valid = 0;
468 }
469
470 aura_dict_free(d);
471
472 return(valid);
473}
474
475static void
476save_subpartition_selections(struct dfui_response *r, struct i_fn_args *a)
477{
478 struct dfui_dataset *ds;
7eae318c
MS
479 const char *mountpoint, *capstring;
480 long capacity;
7eae318c
MS
481 int valid = 1;
482
483 subpartitions_free(storage_get_selected_slice(a->s));
484
485 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL;
486 ds = dfui_dataset_get_next(ds)) {
487 mountpoint = dfui_dataset_get_value(ds, "mountpoint");
488 capstring = dfui_dataset_get_value(ds, "capacity");
66764e14 489
7eae318c
MS
490 if (string_to_capacity(capstring, &capacity)) {
491 subpartition_new_hammer(storage_get_selected_slice(a->s),
88cfb1f7
SW
492 mountpoint, capacity,
493 strcasecmp(dfui_dataset_get_value(ds, "encrypted"), "Y") == 0);
7eae318c
MS
494 }
495 }
496}
497
498static void
499populate_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a)
500{
501 struct subpartition *sp;
502 struct dfui_dataset *ds;
e6847d54 503 int i;
7eae318c
MS
504 long capacity;
505
506 if (slice_subpartition_first(storage_get_selected_slice(a->s)) != NULL) {
507 /*
508 * The user has already given us their subpartition
509 * preferences, so use them here.
510 */
511 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
512 sp != NULL; sp = subpartition_next(sp)) {
513 ds = dfui_dataset_new();
514 dfui_dataset_celldata_add(ds, "mountpoint",
515 subpartition_get_mountpoint(sp));
516 dfui_dataset_celldata_add(ds, "capacity",
517 capacity_to_string(subpartition_get_capacity(sp)));
88cfb1f7
SW
518 dfui_dataset_celldata_add(ds, "encrypted",
519 subpartition_is_encrypted(sp) ? "Y" : "N");
7eae318c
MS
520 dfui_form_dataset_add(f, ds);
521 }
522 } else {
523 /*
524 * Otherwise, populate the form with datasets representing
525 * reasonably-calculated defaults. The defaults are chosen
526 * based on the slice's total capacity and the machine's
527 * total physical memory (for swap.)
528 */
e6847d54
SW
529 for (i = 0; def_mountpt[i] != NULL; i++) {
530 capacity = default_capacity(a->s, def_mountpt[i]);
7eae318c
MS
531 ds = dfui_dataset_new();
532 dfui_dataset_celldata_add(ds, "mountpoint",
e6847d54 533 def_mountpt[i]);
7eae318c
MS
534 dfui_dataset_celldata_add(ds, "capacity",
535 capacity_to_string(capacity));
88cfb1f7 536 dfui_dataset_celldata_add(ds, "encrypted", "N");
7eae318c
MS
537 dfui_form_dataset_add(f, ds);
538 }
539 }
540}
541
542static int
543warn_subpartition_selections(struct i_fn_args *a)
544{
545 int valid = 0;
7eae318c 546
e6847d54
SW
547 if (subpartition_find(storage_get_selected_slice(a->s), "/boot") == NULL) {
548 inform(a->c, _("The /boot partition must not be omitted."));
549 } else if (subpartition_find(storage_get_selected_slice(a->s), "/home") != NULL ||
550 subpartition_find(storage_get_selected_slice(a->s), "/tmp") != NULL ||
551 subpartition_find(storage_get_selected_slice(a->s), "/usr") != NULL ||
552 subpartition_find(storage_get_selected_slice(a->s), "/usr/obj") != NULL ||
553 subpartition_find(storage_get_selected_slice(a->s), "/var") != NULL ||
554 subpartition_find(storage_get_selected_slice(a->s), "/var/crash") != NULL ||
555 subpartition_find(storage_get_selected_slice(a->s), "/var/tmp") != NULL) {
556 inform(a->c, _("Pseudo filesystems will automatically be created "
557 "for /home, /tmp, /usr, /usr/obj, /var, /var/crash "
558 "and /var/tmp and must not be specified."));
559 } else {
560 valid = check_capacity(a);
561 }
7eae318c
MS
562
563 return(!valid);
564}
565
88cfb1f7
SW
566static int
567warn_encrypted_boot(struct i_fn_args *a)
568{
569 int valid = 1;
570
571 struct subpartition *sp;
572
573 sp = subpartition_find(storage_get_selected_slice(a->s), "/boot");
574 if (sp == NULL)
575 return(!valid);
576
577 if (subpartition_is_encrypted(sp)) {
578 switch (dfui_be_present_dialog(a->c, _("/boot cannot be encrypted"),
579 _("Leave /boot unencrypted|Return to Create Subpartitions"),
580 _("You have selected encryption for the /boot partition which "
581 "is not supported."))) {
582 case 1:
b8d2998c 583 subpartition_clr_encrypted(sp);
88cfb1f7
SW
584 valid = 1;
585 break;
586 case 2:
587 valid = 0;
588 break;
589 default:
590 abort_backend();
591 }
592 }
593
594 return(!valid);
595}
596
7eae318c
MS
597static struct dfui_form *
598make_create_subpartitions_form(struct i_fn_args *a)
599{
7eae318c
MS
600 struct dfui_form *f;
601 char msg_buf[1][1024];
602
603 snprintf(msg_buf[0], sizeof(msg_buf[0]),
604 _("Subpartitions further divide a primary partition for "
605 "use with %s. Some reasons you may want "
606 "a set of subpartitions are:\n\n"
607 "- you want to restrict how much data can be written "
608 "to certain parts of the primary partition, to quell "
609 "denial-of-service attacks; and\n"
610 "- you want to speed up access to data on the disk."
611 ""), OPERATING_SYSTEM_NAME);
612
613 f = dfui_form_create(
614 "create_subpartitions",
615 _("Create Subpartitions"),
616 _("Set up the subpartitions (also known as just `partitions' "
617 "in BSD tradition) you want to have on this primary "
e6847d54 618 "partition. In most cases you should be fine with "
d4ff6419 619 "the default settings.\n\n"
7eae318c
MS
620 "For Capacity, use 'M' to indicate megabytes, 'G' to "
621 "indicate gigabytes, or a single '*' to indicate "
622 "'use the remaining space on the primary partition'."),
623
624 msg_buf[0],
625
626 "p", "special", "dfinstaller_create_subpartitions",
627 "p", "minimum_width","64",
628
629 "f", "mountpoint", _("Mountpoint"), "", "",
630 "f", "capacity", _("Capacity"), "", "",
631
88cfb1f7
SW
632 "f", "encrypted", _("Encrypted"), "", "",
633 "p", "control", "checkbox",
634
7eae318c
MS
635 "a", "ok", _("Accept and Create"), "", "",
636 "a", "cancel",
637 (disk_get_formatted(storage_get_selected_disk(a->s)) ?
638 _("Return to Select Disk") :
639 _("Return to Select Primary Partition")), "", "",
640 "p", "accelerator", "ESC",
641
642 NULL
643 );
644
645 dfui_form_set_multiple(f, 1);
646 dfui_form_set_extensible(f, 1);
647 /*
648 * Remove ATM until HAMMER installer support is better
649 * dfui_form_set_extensible(f, 1);
650 */
651#if 0
652 if (expert) {
653 fi = dfui_form_field_add(f, "softupdates",
654 dfui_info_new(_("Softupdates"), "", ""));
655 dfui_field_property_set(fi, "control", "checkbox");
656
761cad2f
SW
657 fi = dfui_form_field_add(f, "tmpfsbacked",
658 dfui_info_new(_("TMPFS"), "", ""));
7eae318c
MS
659 dfui_field_property_set(fi, "control", "checkbox");
660
661 fi = dfui_form_field_add(f, "fsize",
662 dfui_info_new(_("Frag Sz"), "", ""));
663
664 fi = dfui_form_field_add(f, "bsize",
665 dfui_info_new(_("Block Sz"), "", ""));
666
667 dfui_form_action_add(f, "switch",
668 dfui_info_new(_("Switch to Normal Mode"), "", ""));
669 } else {
670 dfui_form_action_add(f, "switch",
671 dfui_info_new(_("Switch to Expert Mode"), "", ""));
672 }
673#endif
674 return(f);
675}
676
677/*
678 * Returns:
679 * -1 = the form should be redisplayed
680 * 0 = failure, function is over
681 * 1 = success, function is over
682 */
683static int
684show_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a)
685{
686 struct dfui_dataset *ds;
687 struct dfui_response *r;
688
689 for (;;) {
690 if (dfui_form_dataset_get_first(f) == NULL)
691 populate_create_subpartitions_form(f, a);
692
693 if (!dfui_be_present(a->c, f, &r))
694 abort_backend();
695
696 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
697 dfui_response_free(r);
698 return(0);
699 } else if (strcmp(dfui_response_get_action_id(r), "switch") == 0) {
700 if (check_subpartition_selections(r, a)) {
701 save_subpartition_selections(r, a);
702 expert = expert ? 0 : 1;
703 dfui_response_free(r);
704 return(-1);
705 }
706 } else {
707 if (check_subpartition_selections(r, a)) {
708 save_subpartition_selections(r, a);
88cfb1f7
SW
709 if (!warn_subpartition_selections(a) &&
710 !warn_encrypted_boot(a)) {
7eae318c
MS
711 if (!create_subpartitions(a)) {
712 inform(a->c, _("The subpartitions you chose were "
713 "not correctly created, and the "
714 "primary partition may "
715 "now be in an inconsistent state. "
716 "We recommend re-formatting it "
717 "before proceeding."));
718 dfui_response_free(r);
719 return(0);
720 } else {
721 dfui_response_free(r);
722 return(1);
723 }
724 }
725 }
726 }
727
728 dfui_form_datasets_free(f);
729 /* dfui_form_datasets_add_from_response(f, r); */
730 for (ds = dfui_response_dataset_get_first(r); ds != NULL;
731 ds = dfui_dataset_get_next(ds)) {
732 dfui_form_dataset_add(f, dfui_dataset_dup(ds));
733 }
734 }
735}
736
737/*
738 * fn_create_subpartitions_hammer: let the user specify what subpartitions they
739 * want on the disk, how large each should be, and where it should be mounted.
740 */
741void
742fn_create_subpartitions_hammer(struct i_fn_args *a)
743{
744 struct dfui_form *f;
745 int done = 0;
746
747 a->result = 0;
748 while (!done) {
749 f = make_create_subpartitions_form(a);
750 switch (show_create_subpartitions_form(f, a)) {
751 case -1:
752 done = 0;
753 break;
754 case 0:
755 done = 1;
756 a->result = 0;
757 break;
758 case 1:
759 done = 1;
760 a->result = 1;
761 break;
762 }
763 dfui_form_free(f);
764 }
765}