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