zic(8) & zdump(8): Raise WARNS to 2 and silence a warning.
[dragonfly.git] / usr.sbin / installer / dfuibe_installer / fn_subpart.c
blob93fa750d8e307af88d16f198b0d24a41ecfdd836
1 /*
2 * Copyright (c)2004 The DragonFly Project. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
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 $
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
44 #ifdef ENABLE_NLS
45 #include <libintl.h>
46 #define _(String) gettext (String)
47 #else
48 #define _(String) (String)
49 #endif
51 #include "libaura/mem.h"
52 #include "libaura/buffer.h"
53 #include "libaura/dict.h"
54 #include "libaura/fspred.h"
56 #include "libdfui/dfui.h"
57 #include "libdfui/dump.h"
58 #include "libdfui/system.h"
60 #include "libinstaller/commands.h"
61 #include "libinstaller/diskutil.h"
62 #include "libinstaller/functions.h"
63 #include "libinstaller/uiutil.h"
65 #include "fn.h"
66 #include "flow.h"
67 #include "pathnames.h"
69 static int create_subpartitions(struct i_fn_args *);
70 static long default_capacity(struct storage *, int);
71 static int check_capacity(struct i_fn_args *);
72 static int check_subpartition_selections(struct dfui_response *, struct i_fn_args *);
73 static void save_subpartition_selections(struct dfui_response *, struct i_fn_args *);
74 static void populate_create_subpartitions_form(struct dfui_form *, struct i_fn_args *);
75 static int warn_subpartition_selections(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 *);
79 static const char *def_mountpt[7] = {"/", "swap", "/var", "/tmp", "/usr", "/home", NULL};
80 static int expert = 0;
83 * Given a set of subpartitions-to-be in the selected slice,
84 * create them.
86 static int
87 create_subpartitions(struct i_fn_args *a)
89 struct subpartition *sp;
90 struct commands *cmds;
91 int result = 0;
92 int copied_original = 0;
93 int num_partitions;
95 cmds = commands_new();
96 if (!is_file("%sinstall.disklabel.%s",
97 a->tmp,
98 slice_get_device_name(storage_get_selected_slice(a->s)))) {
100 * Get a copy of the 'virgin' disklabel.
101 * XXX It might make more sense for this to
102 * happen right after format_slice() instead.
104 command_add(cmds, "%s%s -r %s >%sinstall.disklabel.%s",
105 a->os_root, cmd_name(a, "DISKLABEL"),
106 slice_get_device_name(storage_get_selected_slice(a->s)),
107 a->tmp,
108 slice_get_device_name(storage_get_selected_slice(a->s)));
112 * Weave together a new disklabel out the of the 'virgin'
113 * disklabel, and the user's subpartition choices.
117 * Take everything from the 'virgin' disklabel up until the
118 * '16 partitions' line.
120 num_partitions = 16;
121 command_add(cmds, "%s%s '$2==\"partitions:\" || cut { cut = 1 } !cut { print $0 }' <%sinstall.disklabel.%s >%sinstall.disklabel",
122 a->os_root, cmd_name(a, "AWK"),
123 a->tmp,
124 slice_get_device_name(storage_get_selected_slice(a->s)),
125 a->tmp);
128 * 16 partitions:
129 * # size offset fstype
130 * c: 16383969 0 unused # 7999.985MB
133 command_add(cmds, "%s%s '%d partitions:' >>%sinstall.disklabel",
134 a->os_root, cmd_name(a, "ECHO"), num_partitions ,a->tmp);
135 command_add(cmds, "%s%s '%s' >>%sinstall.disklabel",
136 a->os_root, cmd_name(a, "ECHO"),
137 "# size offset fstype",
138 a->tmp);
140 #ifdef DEBUG
141 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
142 sp != NULL; sp = subpartition_next(sp)) {
143 command_add(cmds, "%s%s 'mountpoint: %s device: %s'",
144 a->os_root, cmd_name(a, "ECHO"),
145 subpartition_get_mountpoint(sp),
146 subpartition_get_device_name(sp));
148 #endif
151 * Write a line for each subpartition the user wants.
153 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
154 sp != NULL; sp = subpartition_next(sp)) {
155 if (subpartition_is_mfsbacked(sp)) {
156 continue;
158 if (subpartition_get_letter(sp) > 'c' && !copied_original) {
160 * Copy the 'c' line from the 'virgin' disklabel.
162 command_add(cmds, "%s%s '^ c:' %sinstall.disklabel.%s >>%sinstall.disklabel",
163 a->os_root, cmd_name(a, "GREP"),
164 a->tmp,
165 slice_get_device_name(storage_get_selected_slice(a->s)),
166 a->tmp);
167 copied_original = 1;
169 if (subpartition_is_swap(sp)) {
170 command_add(cmds, "%s%s ' %c:\t%s\t*\tswap' >>%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 } else {
176 command_add(cmds, "%s%s ' %c:\t%s\t%s\t4.2BSD' >>%sinstall.disklabel",
177 a->os_root, cmd_name(a, "ECHO"),
178 subpartition_get_letter(sp),
179 capacity_to_string(subpartition_get_capacity(sp)),
180 subpartition_get_letter(sp) == 'a' ? "0" : "*",
181 a->tmp);
184 if (!copied_original) {
186 * Copy the 'c' line from the 'virgin' disklabel,
187 * if we haven't yet (less than 2 subpartitions.)
189 command_add(cmds, "%s%s '^ c:' %sinstall.disklabel.%s >>%sinstall.disklabel",
190 a->os_root, cmd_name(a, "GREP"),
191 a->tmp,
192 slice_get_device_name(storage_get_selected_slice(a->s)),
193 a->tmp);
195 temp_file_add(a, "install.disklabel");
198 * Label the slice from the disklabel we just wove together.
200 command_add(cmds, "%s%s -R -B -r %s %sinstall.disklabel",
201 a->os_root, cmd_name(a, "DISKLABEL"),
202 slice_get_device_name(storage_get_selected_slice(a->s)),
203 a->tmp);
206 * Create a snapshot of the disklabel we just created
207 * for debugging inspection in the log.
209 command_add(cmds, "%s%s %s",
210 a->os_root, cmd_name(a, "DISKLABEL"),
211 slice_get_device_name(storage_get_selected_slice(a->s)));
214 * Create filesystems on the newly-created subpartitions.
216 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
217 sp != NULL; sp = subpartition_next(sp)) {
218 if (subpartition_is_swap(sp) || subpartition_is_mfsbacked(sp))
219 continue;
222 * Ensure that all the needed device nodes exist.
224 command_add_ensure_dev(a, cmds,
225 disk_get_device_name(storage_get_selected_disk(a->s)));
226 command_add_ensure_dev(a, cmds,
227 slice_get_device_name(storage_get_selected_slice(a->s)));
228 command_add_ensure_dev(a, cmds,
229 subpartition_get_device_name(sp));
231 command_add(cmds, "%s%s%s -b %ld -f %ld %sdev/%s",
232 a->os_root, cmd_name(a, "NEWFS"),
233 subpartition_is_softupdated(sp) ? " -U" : "",
234 subpartition_get_bsize(sp),
235 subpartition_get_fsize(sp),
236 a->os_root,
237 subpartition_get_device_name(sp));
240 result = commands_execute(a, cmds);
241 commands_free(cmds);
242 return(result);
246 * +-------+------------+--------------+-----------------+-----------------+
247 * | Mtpt | Matt says | FreeBSD says | I got away with | A tiny system |
248 * +-------+------------+--------------+-----------------+-----------------+
249 * | / | 256M | 100M | 256M | 64M |
250 * | swap | 1G | 2 or 3 * mem | (4 * mem) 256M | (1 * mem) 64M |
251 * | /var | 256M | 50M | 256M | 12M |
252 * | /tmp | 256M | --- | 256M | --- |
253 * | /usr | [4G to] 8G | (>160M) rest | 5G | 160M |
254 * | /home | rest | --- | 3.5G | --- |
255 * +-------+------------+--------------+-----------------+-----------------+
256 * | total | 10G+ | ~430M+ | 9.5G | 300M |
257 * +-------+------------+--------------+-----------------+-----------------+
260 static long
261 default_capacity(struct storage *s, int mtpt)
263 unsigned long swap;
264 unsigned long capacity;
266 if (mtpt == MTPT_HOME)
267 return(-1);
269 capacity = slice_get_capacity(storage_get_selected_slice(s));
270 swap = 2 * storage_get_memsize(s);
271 if (storage_get_memsize(s) > (capacity / 2) || capacity < 4096)
272 swap = storage_get_memsize(s);
273 if (storage_get_memsize(s) > capacity)
274 swap = capacity / 2;
275 if (swap > 8192)
276 swap = 8192;
278 if (capacity < DISK_MIN) {
280 * For the purposes of this installer:
281 * can't be done. Sorry.
283 return(-1);
284 } else if (capacity < 523) {
285 switch (mtpt) {
286 case MTPT_ROOT: return(70);
287 case MTPT_SWAP: return(swap);
288 case MTPT_VAR: return(32);
289 case MTPT_TMP: return(32);
290 case MTPT_USR: return(174);
292 } else if (capacity < 1024) {
293 switch (mtpt) {
294 case MTPT_ROOT: return(96);
295 case MTPT_SWAP: return(swap);
296 case MTPT_VAR: return(64);
297 case MTPT_TMP: return(64);
298 case MTPT_USR: return(256);
300 } else if (capacity < 4096) {
301 switch (mtpt) {
302 case MTPT_ROOT: return(128);
303 case MTPT_SWAP: return(swap);
304 case MTPT_VAR: return(128);
305 case MTPT_TMP: return(128);
306 case MTPT_USR: return(512);
308 } else if (capacity < 10240) {
309 switch (mtpt) {
310 case MTPT_ROOT: return(256);
311 case MTPT_SWAP: return(swap);
312 case MTPT_VAR: return(256);
313 case MTPT_TMP: return(256);
314 case MTPT_USR: return(3072);
316 } else {
317 switch (mtpt) {
318 case MTPT_ROOT: return(256);
319 case MTPT_SWAP: return(swap);
320 case MTPT_VAR: return(256);
321 case MTPT_TMP: return(256);
322 case MTPT_USR: return(8192);
325 /* shouldn't ever happen */
326 return(-1);
329 static int
330 check_capacity(struct i_fn_args *a)
332 struct subpartition *sp;
333 unsigned long min_capacity[7] = {70, 0, 8, 0, 174, 0, 0};
334 unsigned long total_capacity = 0;
335 int mtpt;
337 if (subpartition_find(storage_get_selected_slice(a->s), "/usr") == NULL)
338 min_capacity[MTPT_ROOT] += min_capacity[MTPT_USR];
340 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
341 sp != NULL; sp = subpartition_next(sp)) {
342 if (subpartition_get_capacity(sp) == -1)
343 total_capacity++;
344 else
345 total_capacity += subpartition_get_capacity(sp);
346 for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) {
347 if (strcmp(subpartition_get_mountpoint(sp), def_mountpt[mtpt]) == 0 &&
348 min_capacity[mtpt] > 0 &&
349 subpartition_get_capacity(sp) < min_capacity[mtpt]) {
350 inform(a->c, _("WARNING: the %s subpartition should "
351 "be at least %dM in size or you will "
352 "risk running out of space during "
353 "the installation."),
354 subpartition_get_mountpoint(sp), min_capacity[mtpt]);
359 if (total_capacity > slice_get_capacity(storage_get_selected_slice(a->s))) {
360 inform(a->c, _("The space allocated to all of your selected "
361 "subpartitions (%dM) exceeds the total "
362 "capacity of the selected primary partition "
363 "(%dM). Remove some subpartitions or choose "
364 "a smaller size for them and try again."),
365 total_capacity, slice_get_capacity(storage_get_selected_slice(a->s)));
366 return(0);
369 return(1);
372 static int
373 check_subpartition_selections(struct dfui_response *r, struct i_fn_args *a)
375 struct dfui_dataset *ds;
376 struct dfui_dataset *star_ds = NULL;
377 struct aura_dict *d;
378 const char *mountpoint, *capstring;
379 long capacity = 0;
380 long bsize, fsize;
381 int found_root = 0;
382 int softupdates, mfsbacked;
383 int valid = 1;
385 d = aura_dict_new(1, AURA_DICT_LIST);
387 if ((ds = dfui_response_dataset_get_first(r)) == NULL) {
388 inform(a->c, _("Please set up at least one subpartition."));
389 valid = 0;
392 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL;
393 ds = dfui_dataset_get_next(ds)) {
394 #ifdef DEBUG
395 dfui_dataset_dump(ds);
396 #endif
397 mountpoint = dfui_dataset_get_value(ds, "mountpoint");
398 capstring = dfui_dataset_get_value(ds, "capacity");
400 if (expert) {
401 softupdates =
402 (strcmp(dfui_dataset_get_value(ds, "softupdates"), "Y") == 0);
403 fsize = atol(dfui_dataset_get_value(ds, "fsize"));
404 bsize = atol(dfui_dataset_get_value(ds, "bsize"));
405 mfsbacked = (strcmp(dfui_dataset_get_value(ds, "mfsbacked"), "Y") == 0);
406 } else {
407 softupdates = (strcmp(mountpoint, "/") == 0 ? 0 : 1);
408 mfsbacked = (strcmp(mountpoint, "/tmp") == 0 ? 0 : 1);
409 fsize = -1;
410 bsize = -1;
413 if (aura_dict_exists(d, mountpoint, strlen(mountpoint) + 1)) {
414 inform(a->c, _("The same mount point cannot be specified "
415 "for two different subpartitions."));
416 valid = 0;
419 if (strcmp(mountpoint, "/") == 0)
420 found_root = 1;
422 if (strcmp(capstring, "*") == 0) {
423 if (star_ds != NULL) {
424 inform(a->c, _("You cannot have more than one subpartition "
425 "with a '*' capacity (meaning 'use the remainder "
426 "of the primary partition'.)"));
427 valid = 0;
428 } else {
429 star_ds = ds;
433 if (!(!strcasecmp(mountpoint, "swap") || mountpoint[0] == '/')) {
434 inform(a->c, _("Mount point must be either 'swap', or it must "
435 "start with a '/'."));
436 valid = 0;
439 if (strpbrk(mountpoint, " \\\"'`") != NULL) {
440 inform(a->c, _("Mount point may not contain the following "
441 "characters: blank space, backslash, or "
442 "single, double, or back quotes."));
443 valid = 0;
446 if (strlen(capstring) == 0) {
447 inform(a->c, _("A capacity must be specified."));
448 valid = 0;
451 if (!string_to_capacity(capstring, &capacity)) {
452 inform(a->c, _("Capacity must be either a '*' symbol to indicate "
453 "'use the rest of the primary partition', or it "
454 "must be a series of decimal digits ending with a "
455 "'M' (indicating megabytes) or a 'G' (indicating "
456 "gigabytes.)"));
457 valid = 0;
460 if ((strcasecmp(mountpoint, "swap") == 0) && (capacity > 8192)) {
461 inform(a->c, _("Swap capacity is limited to 8G."));
462 valid = 0;
466 * If we made it through that obstacle course, all is well.
469 if (valid)
470 aura_dict_store(d, mountpoint, strlen(mountpoint) + 1, "", 1);
473 if (!found_root) {
474 inform(a->c, _("You must include a / (root) subpartition."));
475 valid = 0;
478 if (aura_dict_size(d) > 16) {
479 inform(a->c, _("You cannot have more than 16 subpartitions "
480 "on a single primary partition. Remove some "
481 "and try again."));
482 valid = 0;
485 aura_dict_free(d);
487 return(valid);
490 static void
491 save_subpartition_selections(struct dfui_response *r, struct i_fn_args *a)
493 struct dfui_dataset *ds;
494 char mfsbacked;
495 const char *mountpoint, *capstring;
496 long capacity;
497 long bsize, fsize;
498 int softupdates;
499 int valid = 1;
501 subpartitions_free(storage_get_selected_slice(a->s));
503 for (ds = dfui_response_dataset_get_first(r); valid && ds != NULL;
504 ds = dfui_dataset_get_next(ds)) {
505 mountpoint = dfui_dataset_get_value(ds, "mountpoint");
506 capstring = dfui_dataset_get_value(ds, "capacity");
508 if (expert) {
509 softupdates =
510 (strcmp(dfui_dataset_get_value(ds, "softupdates"), "Y") == 0);
511 fsize = atol(dfui_dataset_get_value(ds, "fsize"));
512 bsize = atol(dfui_dataset_get_value(ds, "bsize"));
513 mfsbacked = (strcmp(dfui_dataset_get_value(ds, "mfsbacked"), "Y") == 0);
514 } else {
515 softupdates = (strcmp(mountpoint, "/") == 0 ? 0 : 1);
516 mfsbacked = 0;
517 fsize = -1;
518 bsize = -1;
521 if (string_to_capacity(capstring, &capacity)) {
522 subpartition_new(storage_get_selected_slice(a->s), mountpoint, capacity,
523 softupdates, fsize, bsize, mfsbacked);
528 static void
529 populate_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a)
531 struct subpartition *sp;
532 struct dfui_dataset *ds;
533 char temp[32];
534 int mtpt;
535 long capacity;
537 if (slice_subpartition_first(storage_get_selected_slice(a->s)) != NULL) {
539 * The user has already given us their subpartition
540 * preferences, so use them here.
542 for (sp = slice_subpartition_first(storage_get_selected_slice(a->s));
543 sp != NULL; sp = subpartition_next(sp)) {
544 ds = dfui_dataset_new();
545 dfui_dataset_celldata_add(ds, "mountpoint",
546 subpartition_get_mountpoint(sp));
547 dfui_dataset_celldata_add(ds, "capacity",
548 capacity_to_string(subpartition_get_capacity(sp)));
549 if (expert) {
550 dfui_dataset_celldata_add(ds, "softupdates",
551 subpartition_is_softupdated(sp) ? "Y" : "N");
552 dfui_dataset_celldata_add(ds, "mfsbacked",
553 subpartition_is_mfsbacked(sp) ? "Y" : "N");
554 snprintf(temp, 32, "%ld", subpartition_get_fsize(sp));
555 dfui_dataset_celldata_add(ds, "fsize",
556 temp);
557 snprintf(temp, 32, "%ld", subpartition_get_bsize(sp));
558 dfui_dataset_celldata_add(ds, "bsize",
559 temp);
561 dfui_form_dataset_add(f, ds);
563 } else {
565 * Otherwise, populate the form with datasets representing
566 * reasonably-calculated defaults. The defaults are chosen
567 * based on the slice's total capacity and the machine's
568 * total physical memory (for swap.)
570 for (mtpt = 0; def_mountpt[mtpt] != NULL; mtpt++) {
571 capacity = default_capacity(a->s, mtpt);
572 ds = dfui_dataset_new();
573 dfui_dataset_celldata_add(ds, "mountpoint",
574 def_mountpt[mtpt]);
575 dfui_dataset_celldata_add(ds, "capacity",
576 capacity_to_string(capacity));
577 if (expert) {
578 dfui_dataset_celldata_add(ds, "softupdates",
579 strcmp(def_mountpt[mtpt], "/") != 0 ? "Y" : "N");
580 dfui_dataset_celldata_add(ds, "mfsbacked",
581 "N");
582 dfui_dataset_celldata_add(ds, "fsize",
583 capacity < 1024 ? "1024" : "2048");
584 dfui_dataset_celldata_add(ds, "bsize",
585 capacity < 1024 ? "8192" : "16384");
587 dfui_form_dataset_add(f, ds);
592 static int
593 warn_subpartition_selections(struct i_fn_args *a)
595 int valid = 0;
596 struct aura_buffer *omit, *consequences;
598 omit = aura_buffer_new(2048);
599 consequences = aura_buffer_new(2048);
601 valid = check_capacity(a);
602 if (subpartition_find(storage_get_selected_slice(a->s), "/var") == NULL) {
603 aura_buffer_cat(omit, "/var ");
604 aura_buffer_cat(consequences, _("/var will be a plain dir in /\n"));
606 if (subpartition_find(storage_get_selected_slice(a->s), "/usr") == NULL) {
607 aura_buffer_cat(omit, "/usr ");
608 aura_buffer_cat(consequences, _("/usr will be a plain dir in /\n"));
610 if (subpartition_find(storage_get_selected_slice(a->s), "/tmp") == NULL) {
611 aura_buffer_cat(omit, "/tmp ");
612 aura_buffer_cat(consequences, _("/tmp will be symlinked to /var/tmp\n"));
614 if (subpartition_find(storage_get_selected_slice(a->s), "/home") == NULL) {
615 aura_buffer_cat(omit, "/home ");
616 aura_buffer_cat(consequences, _("/home will be symlinked to /usr/home\n"));
619 if (valid && aura_buffer_len(omit) > 0) {
620 switch (dfui_be_present_dialog(a->c, _("Really omit?"),
621 _("Omit Subpartition(s)|Return to Create Subpartitions"),
622 _("You have elected to not have the following "
623 "subpartition(s):\n\n%s\n\n"
624 "The ramifications of these subpartition(s) being "
625 "missing will be:\n\n%s\n"
626 "Is this really what you want to do?"),
627 aura_buffer_buf(omit), aura_buffer_buf(consequences))) {
628 case 1:
629 valid = 1;
630 break;
631 case 2:
632 valid = 0;
633 break;
634 default:
635 abort_backend();
639 aura_buffer_free(omit);
640 aura_buffer_free(consequences);
642 return(!valid);
645 static struct dfui_form *
646 make_create_subpartitions_form(struct i_fn_args *a)
648 struct dfui_field *fi;
649 struct dfui_form *f;
650 char msg_buf[1][1024];
652 snprintf(msg_buf[0], sizeof(msg_buf[0]),
653 _("Subpartitions further divide a primary partition for "
654 "use with %s. Some reasons you may want "
655 "a set of subpartitions are:\n\n"
656 "- you want to restrict how much data can be written "
657 "to certain parts of the primary partition, to quell "
658 "denial-of-service attacks; and\n"
659 "- you want to speed up access to data on the disk."
660 ""), OPERATING_SYSTEM_NAME);
662 f = dfui_form_create(
663 "create_subpartitions",
664 _("Create Subpartitions"),
665 _("Set up the subpartitions (also known as just `partitions' "
666 "in BSD tradition) you want to have on this primary "
667 "partition.\n\n"
668 "For Capacity, use 'M' to indicate megabytes, 'G' to "
669 "indicate gigabytes, or a single '*' to indicate "
670 "'use the remaining space on the primary partition'."),
672 msg_buf[0],
674 "p", "special", "dfinstaller_create_subpartitions",
675 "p", "minimum_width","64",
677 "f", "mountpoint", _("Mountpoint"), "", "",
678 "f", "capacity", _("Capacity"), "", "",
680 "a", "ok", _("Accept and Create"), "", "",
681 "a", "cancel",
682 (disk_get_formatted(storage_get_selected_disk(a->s)) ?
683 _("Return to Select Disk") :
684 _("Return to Select Primary Partition")), "", "",
685 "p", "accelerator", "ESC",
687 NULL
690 dfui_form_set_multiple(f, 1);
691 dfui_form_set_extensible(f, 1);
693 if (expert) {
694 fi = dfui_form_field_add(f, "softupdates",
695 dfui_info_new(_("Softupdates"), "", ""));
696 dfui_field_property_set(fi, "control", "checkbox");
698 fi = dfui_form_field_add(f, "mfsbacked",
699 dfui_info_new(_("MFS"), "", ""));
700 dfui_field_property_set(fi, "control", "checkbox");
702 fi = dfui_form_field_add(f, "fsize",
703 dfui_info_new(_("Frag Sz"), "", ""));
705 fi = dfui_form_field_add(f, "bsize",
706 dfui_info_new(_("Block Sz"), "", ""));
708 dfui_form_action_add(f, "switch",
709 dfui_info_new(_("Switch to Normal Mode"), "", ""));
710 } else {
711 dfui_form_action_add(f, "switch",
712 dfui_info_new(_("Switch to Expert Mode"), "", ""));
715 return(f);
719 * Returns:
720 * -1 = the form should be redisplayed
721 * 0 = failure, function is over
722 * 1 = success, function is over
724 static int
725 show_create_subpartitions_form(struct dfui_form *f, struct i_fn_args *a)
727 struct dfui_dataset *ds;
728 struct dfui_response *r;
730 for (;;) {
731 if (dfui_form_dataset_get_first(f) == NULL)
732 populate_create_subpartitions_form(f, a);
734 if (!dfui_be_present(a->c, f, &r))
735 abort_backend();
737 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
738 dfui_response_free(r);
739 return(0);
740 } else if (strcmp(dfui_response_get_action_id(r), "switch") == 0) {
741 if (check_subpartition_selections(r, a)) {
742 save_subpartition_selections(r, a);
743 expert = expert ? 0 : 1;
744 dfui_response_free(r);
745 return(-1);
747 } else {
748 if (check_subpartition_selections(r, a)) {
749 save_subpartition_selections(r, a);
750 if (!warn_subpartition_selections(a)) {
751 if (!create_subpartitions(a)) {
752 inform(a->c, _("The subpartitions you chose were "
753 "not correctly created, and the "
754 "primary partition may "
755 "now be in an inconsistent state. "
756 "We recommend re-formatting it "
757 "before proceeding."));
758 dfui_response_free(r);
759 return(0);
760 } else {
761 dfui_response_free(r);
762 return(1);
768 dfui_form_datasets_free(f);
769 /* dfui_form_datasets_add_from_response(f, r); */
770 for (ds = dfui_response_dataset_get_first(r); ds != NULL;
771 ds = dfui_dataset_get_next(ds)) {
772 dfui_form_dataset_add(f, dfui_dataset_dup(ds));
778 * fn_create_subpartitions: let the user specify what subpartitions they
779 * want on the disk, how large each should be, and where it should be mounted.
781 void
782 fn_create_subpartitions(struct i_fn_args *a)
784 struct commands *cmds;
786 cmds = commands_new();
789 * Auto-disklabel the slice.
790 * NB: one cannot use "/dev/adXsY" here -
791 * it must be in the form "adXsY".
793 if (use_hammer == 1) {
794 command_add(cmds, "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
795 a->os_root, cmd_name(a, "DD"),
796 slice_get_raw_device_name(storage_get_selected_slice(a->s)));
797 command_add(cmds, "%s%s -B -r -w %s auto",
798 a->os_root, cmd_name(a, "DISKLABEL64"),
799 slice_get_raw_device_name(storage_get_selected_slice(a->s)));
800 commands_execute(a, cmds);
801 commands_free(cmds);
802 fn_create_subpartitions_hammer(a);
803 } else {
804 command_add(cmds, "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
805 a->os_root, cmd_name(a, "DD"),
806 slice_get_raw_device_name(storage_get_selected_slice(a->s)));
807 command_add(cmds, "%s%s -B -r -w %s auto",
808 a->os_root, cmd_name(a, "DISKLABEL"),
809 slice_get_raw_device_name(storage_get_selected_slice(a->s)));
810 commands_execute(a, cmds);
811 commands_free(cmds);
812 fn_create_subpartitions_ufs(a);
816 void
817 fn_create_subpartitions_ufs(struct i_fn_args *a)
819 struct dfui_form *f;
820 int done = 0;
822 a->result = 0;
823 while (!done) {
824 f = make_create_subpartitions_form(a);
825 switch (show_create_subpartitions_form(f, a)) {
826 case -1:
827 done = 0;
828 break;
829 case 0:
830 done = 1;
831 a->result = 0;
832 break;
833 case 1:
834 done = 1;
835 a->result = 1;
836 break;
838 dfui_form_free(f);