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