1 /*
2  * Copyright (c)2004 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_disk.c
36  * Disk functions for installer.
37  * $Id: fn_disk.c,v 1.40 2005/03/13 01:53:58 cpressey Exp $
38  */
39 
40 #include <sys/diskmbr.h>
41 
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <string.h>
45 
46 #ifdef ENABLE_NLS
47 #include <libintl.h>
48 #define _(String) gettext (String)
49 #else
50 #define _(String) (String)
51 #endif
52 
53 #include "libaura/mem.h"
54 #include "libaura/fspred.h"
55 
56 #include "libdfui/dfui.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 "pathnames.h"
66 
67 /*** DISK-RELATED FUNCTIONS ***/
68 
69 /*
70  * Ask the user which physical disk they want.
71  * Changes ss->selected_disk if successful.
72  */
73 void
74 fn_select_disk(struct i_fn_args *a)
75 {
76 	struct dfui_form *f;
77 	struct dfui_action *k;
78 	struct dfui_response *r;
79 	struct disk *d;
80 
81 	f = dfui_form_create(
82 	    "select_disk",
83 	    _("Select Disk"),
84 	    a->short_desc,
85 	    "",
86 
87 	    "p", "role",  "menu",
88 	    "p", "special", "dfinstaller_select_disk",
89 
90 	    NULL
91 	);
92 
93 	for (d = storage_disk_first(a->s); d != NULL; d = disk_next(d)) {
94 		dfui_form_action_add(f, disk_get_device_name(d),
95 		    dfui_info_new(disk_get_desc(d), "", ""));
96 	}
97 
98 	k = dfui_form_action_add(f, "cancel",
99 	    dfui_info_new(a->cancel_desc, "", ""));
100 	dfui_action_property_set(k, "accelerator", "ESC");
101 
102 	if (!dfui_be_present(a->c, f, &r))
103 		abort_backend();
104 
105 	if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
106 		a->result = 0;
107 	} else {
108 		d = disk_find(a->s, dfui_response_get_action_id(r));
109 		if (d == NULL) {
110 			inform(a->c, _("Internal error - response from frontend "
111 			    "should be a valid device name."));
112 			a->result = 0;
113 		} else {
114 			storage_set_selected_disk(a->s, d);
115 			a->result = 1;
116 		}
117 	}
118 
119 	dfui_form_free(f);
120 	dfui_response_free(r);
121 }
122 
123 /*
124  * Ask the user which slice on a the selected disk they want.
125  * Changes ss->selected_slice.
126  */
127 void
128 fn_select_slice(struct i_fn_args *a)
129 {
130 	struct dfui_form *f;
131 	struct dfui_action *k;
132 	struct dfui_response *r;
133 	struct slice *s;
134 	char string[16];
135 
136 	f = dfui_form_create(
137 	    "select_slice",
138 	    _("Select Primary Partition"),
139 	    a->short_desc,
140 	    "",
141 
142 	    "p", "role", "menu",
143 	    "p", "special", "dfinstaller_select_slice",
144 
145 	    NULL
146 	);
147 
148 	for (s = disk_slice_first(storage_get_selected_disk(a->s));
149 	     s != NULL; s = slice_next(s)) {
150 		snprintf(string, 16, "%d", slice_get_number(s));
151 		dfui_form_action_add(f, string,
152 		    dfui_info_new(slice_get_desc(s), "", ""));
153 	}
154 
155 	k = dfui_form_action_add(f, "cancel",
156 	    dfui_info_new(a->cancel_desc, "", ""));
157 	dfui_action_property_set(k, "accelerator", "ESC");
158 
159 	if (!dfui_be_present(a->c, f, &r))
160 		abort_backend();
161 
162 	if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
163 		a->result = 0;
164 	} else {
165 		s = slice_find(storage_get_selected_disk(a->s),
166 		    atoi(dfui_response_get_action_id(r)));
167 		if (s == NULL) {
168 			inform(a->c, _("Internal error - response from frontend "
169 			    "should be a valid slice number."));
170 			a->result = 0;
171 		} else {
172 			storage_set_selected_slice(a->s, s);
173 			a->result = 1;
174 		}
175 	}
176 
177 	dfui_form_free(f);
178 	dfui_response_free(r);
179 }
180 
181 /*
182  * If ss->selected_disk == NULL, user will be asked for which disk.
183  * Returns 1 if disk was formatted, 0 if it wasn't.
184  * If it was, ss->selected_disk and ss->selected_slice are set to it.
185  */
186 void
187 fn_format_disk_mbr(struct i_fn_args *a)
188 {
189 	struct commands *cmds;
190 	char *selected_disk_string;
191 
192 	if (storage_get_selected_disk(a->s) == NULL) {
193 		a->short_desc = _("Select a disk to format.");
194 		a->cancel_desc = _("Return to Utilities Menu");
195 		fn_select_disk(a);
196 		if (!a->result || storage_get_selected_disk(a->s) == NULL) {
197 			a->result = 0;
198 			return;
199 		}
200 	}
201 
202 	if (confirm_dangerous_action(a->c,
203 	    _("WARNING!  ALL data in ALL partitions on the disk\n\n"
204 	    "%s\n\nwill be IRREVOCABLY ERASED!\n\nAre you ABSOLUTELY "
205 	    "SURE you wish to take this action?  This is your "
206 	    "LAST CHANCE to cancel!"), disk_get_desc(storage_get_selected_disk(a->s)))) {
207 		cmds = commands_new();
208 
209 		command_add(cmds,
210 		    "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
211 		    a->os_root, cmd_name(a, "DD"),
212 		    disk_get_device_name(storage_get_selected_disk(a->s)));
213 		command_add(cmds, "%s%s -BI %s",
214 		    a->os_root, cmd_name(a, "FDISK"),
215 		    disk_get_device_name(storage_get_selected_disk(a->s)));
216 
217 		if (!commands_execute(a, cmds)) {
218 			inform(a->c, _("The disk\n\n%s\n\nwas "
219 			    "not correctly formatted, and may "
220 			    "now be in an inconsistent state. "
221 			    "We recommend re-formatting it "
222 			    "before attempting to install "
223 			    "%s on it."),
224 			    disk_get_desc(storage_get_selected_disk(a->s)),
225 			    OPERATING_SYSTEM_NAME);
226 			commands_free(cmds);
227 			a->result = 0;
228 			return;
229 		}
230 		commands_free(cmds);
231 
232 		/*
233 		 * Since one of the disks has now changed, we must
234 		 * refresh our view of them and re-select the disk
235 		 * since the selected_disk pointer will be invalidated.
236 		 */
237 		selected_disk_string = aura_strdup(
238 		    disk_get_device_name(storage_get_selected_disk(a->s)));
239 		if (!survey_storage(a)) {
240 			inform(a->c, _("Errors occurred while probing "
241 			    "the system for its storage capabilities."));
242 		}
243 		storage_set_selected_disk(a->s, disk_find(a->s, selected_disk_string));
244 		free(selected_disk_string);
245 
246 		/*
247 		 * Note that we formatted this disk and that we want
248 		 * to use the first (and only) slice of it.
249 		 */
250 		disk_set_formatted(storage_get_selected_disk(a->s), 1);
251 		storage_set_selected_slice(a->s, disk_slice_first(storage_get_selected_disk(a->s)));
252 
253 		if (!format_slice(a)) {
254 			inform(a->c, _("The sole primary partition of "
255 			    "the disk\n\n%s\n\nwas "
256 			    "not correctly formatted, and may "
257 			    "now be in an inconsistent state. "
258 			    "We recommend re-formatting the "
259 			    "disk before attempting to install "
260 			    "%s on it."),
261 			    disk_get_desc(storage_get_selected_disk(a->s)),
262 			    OPERATING_SYSTEM_NAME);
263 			a->result = 0;
264 			return;
265 		}
266 		inform(a->c, _("The disk\n\n%s\n\nwas formatted."),
267 		    disk_get_desc(storage_get_selected_disk(a->s)));
268 		a->result = 1;
269 	} else {
270 		inform(a->c, _("Action cancelled - no disks were formatted."));
271 		a->result = 0;
272 	}
273 }
274 
275 void
276 fn_format_disk_uefi(struct i_fn_args *a)
277 {
278 	struct commands *cmds;
279 	char *selected_disk_string;
280 
281 	if (storage_get_selected_disk(a->s) == NULL) {
282 		a->short_desc = _("Select a disk to format.");
283 		a->cancel_desc = _("Return to Utilities Menu");
284 		fn_select_disk(a);
285 		if (!a->result || storage_get_selected_disk(a->s) == NULL) {
286 			a->result = 0;
287 			return;
288 		}
289 	}
290 
291 	if (confirm_dangerous_action(a->c,
292 	    _("WARNING!  ALL data in ALL partitions on the disk\n\n"
293 	    "%s\n\nwill be IRREVOCABLY ERASED!\n\nAre you ABSOLUTELY "
294 	    "SURE you wish to take this action?  This is your "
295 	    "LAST CHANCE to cancel!"), disk_get_desc(storage_get_selected_disk(a->s)))) {
296 		cmds = commands_new();
297 
298 		command_add(cmds,
299 		    "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
300 		    a->os_root, cmd_name(a, "DD"),
301 		    disk_get_device_name(storage_get_selected_disk(a->s)));
302 		command_add(cmds, "%s%s destroy %s",
303 		    a->os_root, cmd_name(a, "GPT"),
304 		    disk_get_device_name(storage_get_selected_disk(a->s)));
305 		command_add(cmds, "%s%s create -f %s",
306 		    a->os_root, cmd_name(a, "GPT"),
307 		    disk_get_device_name(storage_get_selected_disk(a->s)));
308 		command_add(cmds, "%s%s add -i 0 -s 262144 -t efi %s",
309 		    a->os_root, cmd_name(a, "GPT"),
310 		    disk_get_device_name(storage_get_selected_disk(a->s)));
311 		command_add(cmds, "%s%s add -i 1 -t dragonfly %s",
312 		    a->os_root, cmd_name(a, "GPT"),
313 		    disk_get_device_name(storage_get_selected_disk(a->s)));
314 		command_add(cmds, "%s%s -F 32 -c 2 -L EFI -m 0xf8 %ss0",
315 		    a->os_root, cmd_name(a, "NEWFS_MSDOS"),
316 		    disk_get_device_name(storage_get_selected_disk(a->s)));
317 		command_add(cmds, "%s%s /dev/%ss0 %smnt",
318 		    a->os_root, cmd_name(a, "MOUNT_MSDOS"),
319 		    disk_get_device_name(storage_get_selected_disk(a->s)),
320 		    a->os_root);
321 		command_add(cmds, "%s%s -p %smnt/EFI/BOOT",
322 		    a->os_root, cmd_name(a, "MKDIR"), a->os_root);
323 		command_add(cmds,
324 		    "%s%s %s/boot/boot1.efi %smnt/EFI/BOOT/BOOTX64.EFI",
325 		    a->os_root, cmd_name(a, "CP"),
326 		    a->os_root, a->os_root);
327 		command_add(cmds, "%s%s %smnt",
328 		    a->os_root, cmd_name(a, "UMOUNT"), a->os_root);
329 
330 		if (!commands_execute(a, cmds)) {
331 			inform(a->c, _("The disk\n\n%s\n\nwas "
332 			    "not correctly formatted, and may "
333 			    "now be in an inconsistent state. "
334 			    "We recommend re-formatting it "
335 			    "before attempting to install "
336 			    "%s on it."),
337 			    disk_get_desc(storage_get_selected_disk(a->s)),
338 			    OPERATING_SYSTEM_NAME);
339 			commands_free(cmds);
340 			a->result = 0;
341 			return;
342 		}
343 		commands_free(cmds);
344 
345 		/*
346 		 * Since one of the disks has now changed, we must
347 		 * refresh our view of them and re-select the disk
348 		 * since the selected_disk pointer will be invalidated.
349 		 */
350 		selected_disk_string = aura_strdup(
351 		    disk_get_device_name(storage_get_selected_disk(a->s)));
352 		if (!survey_storage(a)) {
353 			inform(a->c, _("Errors occurred while probing "
354 			    "the system for its storage capabilities."));
355 		}
356 		storage_set_selected_disk(a->s,
357 		    disk_find(a->s, selected_disk_string));
358 		free(selected_disk_string);
359 
360 		/*
361 		 * Note that we formatted this disk and that we want
362 		 * to use the first (and only) slice of it.
363 		 */
364 		disk_set_formatted(storage_get_selected_disk(a->s), 1);
365 		storage_set_selected_slice(a->s,
366 		    disk_slice_first(storage_get_selected_disk(a->s)));
367 
368 		inform(a->c, _("The disk\n\n%s\n\nwas formatted."),
369 		    disk_get_desc(storage_get_selected_disk(a->s)));
370 		a->result = 1;
371 	} else {
372 		inform(a->c, _("Action cancelled - no disks were formatted."));
373 		a->result = 0;
374 	}
375 }
376 
377 /*
378  * Wipes the start of the selected disk.
379  */
380 void
381 fn_wipe_start_of_disk(struct i_fn_args *a)
382 {
383 	struct commands *cmds;
384 
385 	a->short_desc = _("If you are having problems formatting a disk, "
386 	    "it may be because of junk that has accumulated "
387 	    "in the boot block and the partition table. "
388 	    "A cure for this is to wipe out everything on "
389 	    "the first few sectors of the disk.  However, this "
390 	    "is a rather drastic action to take, so it is not "
391 	    "recommended unless you are otherwise "
392 	    "encountering problems.");
393 	a->cancel_desc = _("Return to Utilities Menu");
394 	fn_select_disk(a);
395 	if (!a->result)
396 		return;
397 
398 	/* XXX check to make sure no slices on this disk are mounted first? */
399 	if (storage_get_selected_disk(a->s) != NULL && confirm_dangerous_action(a->c,
400 	    _("WARNING!  ALL data in ALL partitions on the disk\n\n"
401 	    "%s\n\nwill be IRREVOCABLY ERASED!\n\nAre you ABSOLUTELY "
402 	    "SURE you wish to take this action?  This is your "
403 	    "LAST CHANCE to cancel!"), disk_get_desc(storage_get_selected_disk(a->s)))) {
404 		cmds = commands_new();
405 		command_add(cmds,
406 		    "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
407 		    a->os_root, cmd_name(a, "DD"),
408 		    disk_get_device_name(storage_get_selected_disk(a->s)));
409 		if (commands_execute(a, cmds)) {
410 			inform(a->c, _("Start of disk was successfully wiped."));
411 		} else {
412 			inform(a->c, _("Some errors occurred. "
413 			    "Start of disk was not successfully wiped."));
414 		}
415 		commands_free(cmds);
416 	}
417 }
418 
419 /*
420  * Wipes the start of the selected slice.
421  */
422 void
423 fn_wipe_start_of_slice(struct i_fn_args *a)
424 {
425 	struct commands *cmds;
426 
427 	a->short_desc =
428 	  _("If you are having problems formatting a primary partition, "
429 	    "it may be because of junk that has accumulated in the "
430 	    "partition's `disklabel'. A cure for this is to wipe out "
431 	    "everything on the first few sectors of the primary partition. "
432 	    "However, this is a rather drastic action to take, so it is not "
433 	    "recommended unless you are otherwise encountering problems.");
434 	a->cancel_desc = _("Return to Utilities Menu");
435 	fn_select_slice(a);
436 	if (!a->result)
437 		return;
438 
439 	if (confirm_dangerous_action(a->c,
440 	    _("WARNING!  ALL data in primary partition #%d,\n\n%s\n\non the "
441 	    "disk\n\n%s\n\n will be IRREVOCABLY ERASED!\n\nAre you "
442 	    "ABSOLUTELY SURE you wish to take this action?  This is "
443 	    "your LAST CHANCE to cancel!"),
444 	    slice_get_number(storage_get_selected_slice(a->s)),
445 	    slice_get_desc(storage_get_selected_slice(a->s)),
446 	    disk_get_desc(storage_get_selected_disk(a->s)))) {
447 		/* XXX check to make sure this slice is not mounted first */
448 		cmds = commands_new();
449 		command_add(cmds, "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
450 		    a->os_root, cmd_name(a, "DD"),
451 		    slice_get_device_name(storage_get_selected_slice(a->s)));
452 		if (commands_execute(a, cmds)) {
453 			inform(a->c, _("Start of primary partition was successfully wiped."));
454 		} else {
455 			inform(a->c, _("Some errors occurred. "
456 			    "Start of primary partition was not successfully wiped."));
457 		}
458 		commands_free(cmds);
459 	}
460 }
461 
462 static void
463 ask_to_wipe_boot_sector(struct i_fn_args *a, struct commands *fcmds)
464 {
465 	struct commands *cmds;
466 	struct command *cmd;
467 	char *disk;
468 
469 	for (cmd = command_get_first(fcmds); cmd != NULL;
470 	     cmd = command_get_next(cmd)) {
471 		disk = command_get_tag(cmd);
472 		if (disk != NULL &&
473 		    command_get_result(cmd) > 0 &&
474 		    command_get_result(cmd) < 256) {
475 			switch (dfui_be_present_dialog(a->c,
476 			    _("Bootblock Install Failed"),
477 			    _("Re-Initialize Bootblock|Cancel"),
478 			    _("Warning: bootblocks were not successfully "
479 			    "installed on the disk `%s'. This may be "
480 			    "because the disk is new and not yet "
481 			    "formatted. If this is the case, it might "
482 			    "help to re-initialize the boot sector, "
483 			    "then try installing the bootblock again. "
484 			    "Note that this should not affect the "
485 			    "partition table of the disk."),
486 			    disk)) {
487 			case 1:
488 				cmds = commands_new();
489 				command_add(cmds,
490 				    "%s%s | %s%s -B /dev/%s",
491 				    a->os_root, cmd_name(a, "YES"),
492 				    a->os_root, cmd_name(a, "FDISK"),
493 				    disk);
494 				if (commands_execute(a, cmds)) {
495 					inform(a->c, _("Boot sector successfully initialized."));
496 				} else {
497 					inform(a->c, _("Some errors occurred. "
498 					    "Boot sector was not successfully initialized."));
499 				}
500 				commands_free(cmds);
501 				break;
502 			default:
503 				break;
504 			}
505 		}
506 	}
507 }
508 
509 void
510 fn_install_bootblocks(struct i_fn_args *a, const char *device)
511 {
512 	struct dfui_form *f;
513 	struct dfui_response *r;
514 	struct dfui_dataset *ds;
515 	struct disk *d;
516 	struct commands *cmds;
517 	struct command *cmd;
518 	char disk[64], boot0cfg[32], packet[32];
519 	char msg_buf[1][1024];
520 
521 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
522 	    "'Packet Mode' refers to using newer BIOS calls to boot "
523 	    "from a partition of the disk.  It is generally not "
524 	    "required unless:\n\n"
525 	    "- your BIOS does not support legacy mode; or\n"
526 	    "- your %s primary partition resides on a "
527 	    "cylinder of the disk beyond cylinder 1024; or\n"
528 	    "- you just can't get it to boot without it.",
529 	    OPERATING_SYSTEM_NAME);
530 
531 	f = dfui_form_create(
532 	    "install_bootstrap",
533 	    _("Install Bootblock(s)"),
534 	    a->short_desc,
535 
536 	    msg_buf[0],
537 
538 	    "p", "special", "dfinstaller_install_bootstrap",
539 
540 	    "f", "disk", _("Disk Drive"),
541 	    _("The disk on which you wish to install a bootblock"), "",
542 	    "p", "editable", "false",
543 	    "f", "boot0cfg", _("Install Bootblock?"),
544 	    _("Install a bootblock on this disk"), "",
545 	    "p", "control", "checkbox",
546 	    "f", "packet", _("Packet Mode?"),
547 	    _("Select this to use 'packet mode' to boot the disk"), "",
548 	    "p", "control", "checkbox",
549 
550 	    "a", "ok", _("Accept and Install Bootblocks"), "", "",
551 	    "a", "cancel", a->cancel_desc, "", "",
552 	    "p", "accelerator", "ESC",
553 
554 	    NULL
555 	);
556 
557 	dfui_form_set_multiple(f, 1);
558 
559 	if (device != NULL) {
560 		ds = dfui_dataset_new();
561 		dfui_dataset_celldata_add(ds, "disk", device);
562 		dfui_dataset_celldata_add(ds, "boot0cfg", "Y");
563 		dfui_dataset_celldata_add(ds, "packet", "Y");
564 		dfui_form_dataset_add(f, ds);
565 	} else {
566 		for (d = storage_disk_first(a->s); d != NULL; d = disk_next(d)) {
567 			ds = dfui_dataset_new();
568 			dfui_dataset_celldata_add(ds, "disk",
569 			    disk_get_device_name(d));
570 			dfui_dataset_celldata_add(ds, "boot0cfg", "Y");
571 			dfui_dataset_celldata_add(ds, "packet", "Y");
572 			dfui_form_dataset_add(f, ds);
573 		}
574 	}
575 
576 	if (!dfui_be_present(a->c, f, &r))
577 		abort_backend();
578 
579 	a->result = 0;
580 	if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
581 		cmds = commands_new();
582 
583 		for (ds = dfui_response_dataset_get_first(r); ds != NULL;
584 		     ds = dfui_dataset_get_next(ds)) {
585 			strlcpy(disk, dfui_dataset_get_value(ds, "disk"), 64);
586 			strlcpy(boot0cfg, dfui_dataset_get_value(ds, "boot0cfg"), 32);
587 			strlcpy(packet, dfui_dataset_get_value(ds, "packet"), 32);
588 
589 			if (strcasecmp(boot0cfg, "Y") == 0) {
590 				cmd = command_add(cmds, "%s%s -B -o %spacket %s",
591 				    a->os_root, cmd_name(a, "BOOT0CFG"),
592 				    strcasecmp(packet, "Y") == 0 ? "" : "no",
593 				    disk);
594 				command_set_failure_mode(cmd, COMMAND_FAILURE_WARN);
595 				command_set_tag(cmd, "%s", disk);
596 				cmd = command_add(cmds, "%s%s -v %s",
597 				    a->os_root, cmd_name(a, "BOOT0CFG"),
598 				    disk);
599 				command_set_failure_mode(cmd, COMMAND_FAILURE_WARN);
600 				command_set_tag(cmd, "%s", disk);
601 			}
602 		}
603 
604 		if (!commands_execute(a, cmds)) {
605 			ask_to_wipe_boot_sector(a, cmds);
606 		} else {
607 			inform(a->c, _("Bootblocks were successfully installed!"));
608 			a->result = 1;
609 		}
610 		commands_free(cmds);
611 	}
612 
613 	dfui_form_free(f);
614 	dfui_response_free(r);
615 }
616 
617 void
618 fn_format_msdos_floppy(struct i_fn_args *a)
619 {
620 	struct commands *cmds;
621 
622 	switch (dfui_be_present_dialog(a->c, _("Format MSDOS Floppy"),
623 	    _("Format Floppy|Return to Utilities Menu"),
624 	    _("Please insert the floppy to be formatted "
625 	    "in unit 0 (``drive A:'')."))) {
626 	case 1:
627 		cmds = commands_new();
628 		command_add(cmds, "%s%s -y -f 1440 /dev/fd0",
629 		    a->os_root, cmd_name(a, "FDFORMAT"));
630 		command_add(cmds, "%s%s -f 1440 fd0",
631 		    a->os_root, cmd_name(a, "NEWFS_MSDOS"));
632 		if (commands_execute(a, cmds))
633 			inform(a->c, _("Floppy successfully formatted!"));
634 		else
635 			inform(a->c, _("Floppy was not successfully formatted."));
636 		break;
637 	case 2:
638 		return;
639 	default:
640 		abort_backend();
641 	}
642 }
643 
644 void
645 fn_create_cdboot_floppy(struct i_fn_args *a)
646 {
647 	struct commands *cmds;
648 	char msg_buf[1][1024];
649 
650 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
651 	    "%s cannot be installed from a floppy; "
652 	    "it must be installed from a booted CD-ROM. "
653 	    "However, many older systems do not support booting "
654 	    "from a CD-ROM. For these systems, a boot disk can be "
655 	    "created. This boot disk contains the Smart Boot "
656 	    "Manager program, which can boot a CD-ROM even "
657 	    "on systems with BIOSes which do not support booting "
658 	    "from the CD-ROM.\n\n"
659 	    "Smart Boot Manager is not a part of %s; "
660 	    "the Smart Boot Manager project can be found here:\n\n"
661 	    "http://btmgr.sourceforge.net/\n\n"
662 	    "To create a CDBoot floppy, insert a blank floppy "
663 	    "in unit 0 (``drive A:'') before proceeding."
664 	    "",
665 	    OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME);
666 
667 	switch (dfui_be_present_dialog(a->c, _("Create CDBoot Floppy"),
668 	    _("Create CDBoot Floppy|Return to Utilities Menu"),
669 	    "%s", msg_buf[0])) {
670 	case 1:
671 		cmds = commands_new();
672 		command_add(cmds, "%s%s -c %sboot/cdboot.flp.bz2 | "
673 		    "%s%s of=/dev/fd0 bs=32k",
674 		    a->os_root, cmd_name(a, "BUNZIP2"),
675 		    a->os_root,
676 		    a->os_root, cmd_name(a, "DD"));
677 		if (commands_execute(a, cmds))
678 			inform(a->c, _("CDBoot floppy successfully created!"));
679 		else
680 			inform(a->c, _("CDBoot floppy was not successfully created."));
681 		break;
682 	case 2:
683 		return;
684 	default:
685 		abort_backend();
686 	}
687 }
688 
689 /**** NON-fn_ FUNCTIONS ***/
690 
691 int
692 format_slice(struct i_fn_args *a)
693 {
694 	struct commands *cmds;
695 	struct command *cmd;
696 	int result;
697 	int cyl, hd, sec;
698 
699 	cmds = commands_new();
700 
701 	/*
702 	 * The information in a->s NEEDS to be accurate here!
703 	 * Presumably we just did a survey_storage() recently.
704 	 * XXX should we do another one here anyway just to be paranoid?
705 	 */
706 
707 	/*
708 	 * Make sure the survey did get disk info correctly or fail
709 	 */
710 	if ((storage_get_selected_disk(a->s) == NULL) ||
711 	    (storage_get_selected_slice(a->s) == NULL))
712 		return 0;
713 
714 	/*
715 	 * Set the slice's sysid to 108.
716 	 */
717 	disk_get_geometry(storage_get_selected_disk(a->s), &cyl, &hd, &sec);
718 	command_add(cmds, "%s%s 'g c%d h%d s%d' >%snew.fdisk",
719 	    a->os_root, cmd_name(a, "ECHO"),
720 	    cyl, hd, sec,
721 	    a->tmp);
722 	command_add(cmds, "%s%s 'p %d %d %lu %lu' >>%snew.fdisk",
723 	    a->os_root, cmd_name(a, "ECHO"),
724 	    slice_get_number(storage_get_selected_slice(a->s)),
725 	    DOSPTYP_DFLYBSD,
726 	    slice_get_start(storage_get_selected_slice(a->s)),
727 	    slice_get_size(storage_get_selected_slice(a->s)),
728 	    a->tmp);
729 	if (slice_get_flags(storage_get_selected_slice(a->s)) & 0x80) {
730 		command_add(cmds, "%s%s 'a %d' >>%snew.fdisk",
731 		    a->os_root, cmd_name(a, "ECHO"),
732 		    slice_get_number(storage_get_selected_slice(a->s)),
733 		    a->tmp);
734 	}
735 
736 	command_add(cmds, "%s%s %snew.fdisk",
737 	    a->os_root, cmd_name(a, "CAT"), a->tmp);
738 	temp_file_add(a, "new.fdisk");
739 
740 	/*
741 	 * Execute the fdisk script.
742 	 */
743 	cmd = command_add(cmds, "%s%s -v -f %snew.fdisk %s",
744 	    a->os_root, cmd_name(a, "FDISK"), a->tmp,
745 	    disk_get_device_name(storage_get_selected_disk(a->s)));
746 	if (slice_get_size(storage_get_selected_slice(a->s)) == 0xFFFFFFFFU)
747 		command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
748 
749 	/*
750 	 * If there is an old 'virgin' disklabel hanging around
751 	 * in the temp dir, get rid of it.  This won't happen
752 	 * from a real CD, but might happen with '-o' installs.
753 	 */
754 	command_add(cmds, "%s%s -f %sinstall.disklabel.%s",
755 	    a->os_root, cmd_name(a, "RM"),
756 	    a->tmp,
757 	    slice_get_device_name(storage_get_selected_slice(a->s)));
758 
759 	result = commands_execute(a, cmds);
760 
761 	commands_free(cmds);
762 
763 	return(result);
764 }
765