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
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
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.
36 * Disk functions for installer.
37 * $Id: fn_disk.c,v 1.40 2005/03/13 01:53:58 cpressey Exp $
45 #define _(String) gettext (String)
47 #define _(String) (String)
50 #include "libaura/mem.h"
51 #include "libaura/fspred.h"
53 #include "libdfui/dfui.h"
54 #include "libdfui/system.h"
56 #include "libinstaller/commands.h"
57 #include "libinstaller/diskutil.h"
58 #include "libinstaller/functions.h"
59 #include "libinstaller/uiutil.h"
62 #include "pathnames.h"
64 /*** DISK-RELATED FUNCTIONS ***/
67 * Ask the user which physical disk they want.
68 * Changes ss->selected_disk if successful.
71 fn_select_disk(struct i_fn_args *a)
74 struct dfui_action *k;
75 struct dfui_response *r;
85 "p", "special", "dfinstaller_select_disk",
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), "", ""));
95 k = dfui_form_action_add(f, "cancel",
96 dfui_info_new(a->cancel_desc, "", ""));
97 dfui_action_property_set(k, "accelerator", "ESC");
99 if (!dfui_be_present(a->c, f, &r))
102 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
105 d = disk_find(a->s, dfui_response_get_action_id(r));
107 inform(a->c, _("Internal error - response from frontend "
108 "should be a valid device name."));
111 storage_set_selected_disk(a->s, d);
117 dfui_response_free(r);
121 * Ask the user which slice on a the selected disk they want.
122 * Changes ss->selected_slice.
125 fn_select_slice(struct i_fn_args *a)
128 struct dfui_action *k;
129 struct dfui_response *r;
133 f = dfui_form_create(
135 _("Select Primary Partition"),
140 "p", "special", "dfinstaller_select_slice",
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), "", ""));
152 k = dfui_form_action_add(f, "cancel",
153 dfui_info_new(a->cancel_desc, "", ""));
154 dfui_action_property_set(k, "accelerator", "ESC");
156 if (!dfui_be_present(a->c, f, &r))
159 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
162 s = slice_find(storage_get_selected_disk(a->s),
163 atoi(dfui_response_get_action_id(r)));
165 inform(a->c, _("Internal error - response from frontend "
166 "should be a valid slice number."));
169 storage_set_selected_slice(a->s, s);
175 dfui_response_free(r);
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.
184 fn_format_disk(struct i_fn_args *a)
186 struct commands *cmds;
187 char *selected_disk_string;
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");
193 if (!a->result || storage_get_selected_disk(a->s) == NULL) {
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();
207 * Create the device node if it does not exist.
209 command_add_ensure_dev(a, cmds,
210 disk_get_device_name(storage_get_selected_disk(a->s)));
213 * Currently you need to pass 'yes' to OpenBSD's fdisk to
214 * be able to do these.
216 #if !defined(__OpenBSD__)
217 command_add(cmds, "%s%s -I %s",
218 a->os_root, cmd_name(a, "FDISK"),
219 disk_get_raw_device_name(storage_get_selected_disk(a->s)));
220 command_add(cmds, "%s%s | %s%s -B %s",
221 a->os_root, cmd_name(a, "YES"),
222 a->os_root, cmd_name(a, "FDISK"),
223 disk_get_raw_device_name(storage_get_selected_disk(a->s)));
225 if (!commands_execute(a, cmds)) {
226 inform(a->c, _("The disk\n\n%s\n\nwas "
227 "not correctly formatted, and may "
228 "now be in an inconsistent state. "
229 "We recommend re-formatting it "
230 "before attempting to install "
232 disk_get_desc(storage_get_selected_disk(a->s)),
233 OPERATING_SYSTEM_NAME);
241 * Since one of the disks has now changed, we must
242 * refresh our view of them and re-select the disk
243 * since the selected_disk pointer will be invalidated.
245 selected_disk_string = aura_strdup(
246 disk_get_device_name(storage_get_selected_disk(a->s)));
247 if (!survey_storage(a)) {
248 inform(a->c, _("Errors occurred while probing "
249 "the system for its storage capabilities."));
251 storage_set_selected_disk(a->s, disk_find(a->s, selected_disk_string));
252 free(selected_disk_string);
255 * Note that we formatted this disk and that we want
256 * to use the first (and only) slice of it.
258 disk_set_formatted(storage_get_selected_disk(a->s), 1);
259 storage_set_selected_slice(a->s, disk_slice_first(storage_get_selected_disk(a->s)));
261 if (!format_slice(a)) {
262 inform(a->c, _("The sole primary partition of "
263 "the disk\n\n%s\n\nwas "
264 "not correctly formatted, and may "
265 "now be in an inconsistent state. "
266 "We recommend re-formatting the "
267 "disk before attempting to install "
269 disk_get_desc(storage_get_selected_disk(a->s)),
270 OPERATING_SYSTEM_NAME);
275 inform(a->c, _("The disk\n\n%s\n\nwas formatted."),
276 disk_get_desc(storage_get_selected_disk(a->s)));
279 inform(a->c, _("Action cancelled - no disks were formatted."));
285 * Wipes the start of the selected disk.
288 fn_wipe_start_of_disk(struct i_fn_args *a)
290 struct commands *cmds;
292 a->short_desc = _("If you are having problems formatting a disk, "
293 "it may be because of junk that has accumulated "
294 "in the boot block and the partition table. "
295 "A cure for this is to wipe out everything on "
296 "the first few sectors of the disk. However, this "
297 "is a rather drastic action to take, so it is not "
298 "recommended unless you are otherwise "
299 "encountering problems.");
300 a->cancel_desc = _("Return to Utilities Menu");
305 /* XXX check to make sure no slices on this disk are mounted first? */
306 if (storage_get_selected_disk(a->s) != NULL && confirm_dangerous_action(a->c,
307 _("WARNING! ALL data in ALL partitions on the disk\n\n"
308 "%s\n\nwill be IRREVOCABLY ERASED!\n\nAre you ABSOLUTELY "
309 "SURE you wish to take this action? This is your "
310 "LAST CHANCE to cancel!"), disk_get_desc(storage_get_selected_disk(a->s)))) {
311 cmds = commands_new();
313 "%s%s if=%sdev/zero of=%sdev/%s bs=32k count=16",
314 a->os_root, cmd_name(a, "DD"),
315 a->os_root, a->os_root,
316 disk_get_raw_device_name(storage_get_selected_disk(a->s)));
317 if (commands_execute(a, cmds)) {
318 inform(a->c, _("Start of disk was successfully wiped."));
320 inform(a->c, _("Some errors occurred. "
321 "Start of disk was not successfully wiped."));
328 * Wipes the start of the selected slice.
331 fn_wipe_start_of_slice(struct i_fn_args *a)
333 struct commands *cmds;
336 _("If you are having problems formatting a primary partition, "
337 "it may be because of junk that has accumulated in the "
338 "partition's `disklabel'. A cure for this is to wipe out "
339 "everything on the first few sectors of the primary partition. "
340 "However, this is a rather drastic action to take, so it is not "
341 "recommended unless you are otherwise encountering problems.");
342 a->cancel_desc = _("Return to Utilities Menu");
347 if (confirm_dangerous_action(a->c,
348 _("WARNING! ALL data in primary partition #%d,\n\n%s\n\non the "
349 "disk\n\n%s\n\n will be IRREVOCABLY ERASED!\n\nAre you "
350 "ABSOLUTELY SURE you wish to take this action? This is "
351 "your LAST CHANCE to cancel!"),
352 slice_get_number(storage_get_selected_slice(a->s)),
353 slice_get_desc(storage_get_selected_slice(a->s)),
354 disk_get_desc(storage_get_selected_disk(a->s)))) {
355 /* XXX check to make sure this slice is not mounted first */
356 cmds = commands_new();
357 command_add(cmds, "%s%s if=%sdev/zero of=%sdev/%s bs=32k count=16",
358 a->os_root, cmd_name(a, "DD"),
359 a->os_root, a->os_root,
360 slice_get_raw_device_name(storage_get_selected_slice(a->s)));
361 if (commands_execute(a, cmds)) {
362 inform(a->c, _("Start of primary partition was successfully wiped."));
364 inform(a->c, _("Some errors occurred. "
365 "Start of primary partition was not successfully wiped."));
372 ask_to_wipe_boot_sector(struct i_fn_args *a, struct commands *fcmds)
374 struct commands *cmds;
378 for (cmd = command_get_first(fcmds); cmd != NULL;
379 cmd = command_get_next(cmd)) {
380 disk = command_get_tag(cmd);
382 command_get_result(cmd) > 0 &&
383 command_get_result(cmd) < 256) {
384 switch (dfui_be_present_dialog(a->c,
385 _("Bootblock Install Failed"),
386 _("Re-Initialize Bootblock|Cancel"),
387 _("Warning: bootblocks were not successfully "
388 "installed on the disk `%s'. This may be "
389 "because the disk is new and not yet "
390 "formatted. If this is the case, it might "
391 "help to re-initialize the boot sector, "
392 "then try installing the bootblock again. "
393 "Note that this should not affect the "
394 "partition table of the disk."),
397 cmds = commands_new();
399 "%s%s | %s%s -B %sdev/%s",
400 a->os_root, cmd_name(a, "YES"),
401 a->os_root, cmd_name(a, "FDISK"),
403 if (commands_execute(a, cmds)) {
404 inform(a->c, _("Boot sector successfully initialized."));
406 inform(a->c, _("Some errors occurred. "
407 "Boot sector was not successfully initialized."));
419 fn_install_bootblocks(struct i_fn_args *a)
422 struct dfui_response *r;
423 struct dfui_dataset *ds;
425 struct commands *cmds;
427 char disk[64], boot0cfg[32], packet[32];
428 char msg_buf[1][1024];
430 snprintf(msg_buf[0], sizeof(msg_buf[0]),
431 "'Packet Mode' refers to using newer BIOS calls to boot "
432 "from a partition of the disk. It is generally not "
433 "required unless:\n\n"
434 "- your BIOS does not support legacy mode; or\n"
435 "- your %s primary partition resides on a "
436 "cylinder of the disk beyond cylinder 1024; or\n"
437 "- you just can't get it to boot without it.",
438 OPERATING_SYSTEM_NAME);
440 f = dfui_form_create(
442 _("Install Bootblock(s)"),
447 "p", "special", "dfinstaller_install_bootstrap",
449 "f", "disk", _("Disk Drive"),
450 _("The disk on which you wish to install a bootblock"), "",
451 "p", "editable", "false",
452 "f", "boot0cfg", _("Install Bootblock?"),
453 _("Install a bootblock on this disk"), "",
454 "p", "control", "checkbox",
455 "f", "packet", _("Packet Mode?"),
456 _("Select this to use 'packet mode' to boot the disk"), "",
457 "p", "control", "checkbox",
459 "a", "ok", _("Accept and Install Bootblocks"), "", "",
460 "a", "cancel", a->cancel_desc, "", "",
461 "p", "accelerator", "ESC",
466 dfui_form_set_multiple(f, 1);
468 for (d = storage_disk_first(a->s); d != NULL; d = disk_next(d)) {
469 ds = dfui_dataset_new();
470 /* XXX need to see how this is handled in OpenBSD/NetBSD */
471 dfui_dataset_celldata_add(ds, "disk", disk_get_raw_device_name(d));
472 dfui_dataset_celldata_add(ds, "boot0cfg", "Y");
473 dfui_dataset_celldata_add(ds, "packet", autopacket(d) == 1 ? "Y" : "N");
474 dfui_form_dataset_add(f, ds);
477 if (!dfui_be_present(a->c, f, &r))
481 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
482 cmds = commands_new();
484 for (ds = dfui_response_dataset_get_first(r); ds != NULL;
485 ds = dfui_dataset_get_next(ds)) {
486 strlcpy(disk, dfui_dataset_get_value(ds, "disk"), 64);
487 strlcpy(boot0cfg, dfui_dataset_get_value(ds, "boot0cfg"), 32);
488 strlcpy(packet, dfui_dataset_get_value(ds, "packet"), 32);
490 if (strcasecmp(boot0cfg, "Y") == 0) {
491 cmd = command_add(cmds, "%s%s -B %s %s",
492 a->os_root, cmd_name(a, "BOOT0CFG"),
493 strcasecmp(packet, "Y") == 0 ? "-o packet" : "",
495 command_set_failure_mode(cmd, COMMAND_FAILURE_WARN);
496 command_set_tag(cmd, disk);
497 cmd = command_add(cmds, "%s%s -v %s",
498 a->os_root, cmd_name(a, "BOOT0CFG"),
500 command_set_failure_mode(cmd, COMMAND_FAILURE_WARN);
501 command_set_tag(cmd, disk);
505 if (!commands_execute(a, cmds)) {
506 ask_to_wipe_boot_sector(a, cmds);
508 inform(a->c, _("Bootblocks were successfully installed!"));
515 dfui_response_free(r);
519 fn_format_msdos_floppy(struct i_fn_args *a)
521 struct commands *cmds;
523 switch (dfui_be_present_dialog(a->c, _("Format MSDOS Floppy"),
524 _("Format Floppy|Return to Utilities Menu"),
525 _("Please insert the floppy to be formatted "
526 "in unit 0 (``drive A:'')."))) {
528 cmds = commands_new();
529 command_add(cmds, "%s%s -y -f 1440 /dev/fd0",
530 a->os_root, cmd_name(a, "FDFORMAT"));
531 command_add(cmds, "%s%s -f 1440 fd0",
532 a->os_root, cmd_name(a, "NEWFS_MSDOS"));
533 if (commands_execute(a, cmds))
534 inform(a->c, _("Floppy successfully formatted!"));
536 inform(a->c, _("Floppy was not successfully formatted."));
546 fn_create_cdboot_floppy(struct i_fn_args *a)
548 struct commands *cmds;
549 char msg_buf[1][1024];
551 snprintf(msg_buf[0], sizeof(msg_buf[0]),
552 "%s cannot be installed from a floppy; "
553 "it must be installed from a booted CD-ROM. "
554 "However, many older systems do not support booting "
555 "from a CD-ROM. For these systems, a boot disk can be "
556 "created. This boot disk contains the Smart Boot "
557 "Manager program, which can boot a CD-ROM even "
558 "on systems with BIOSes which do not support booting "
559 "from the CD-ROM.\n\n"
560 "Smart Boot Manager is not a part of %s; "
561 "the Smart Boot Manager project can be found here:\n\n"
562 "http://btmgr.sourceforge.net/\n\n"
563 "To create a CDBoot floppy, insert a blank floppy "
564 "in unit 0 (``drive A:'') before proceeding."
566 OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME);
568 switch (dfui_be_present_dialog(a->c, _("Create CDBoot Floppy"),
569 _("Create CDBoot Floppy|Return to Utilities Menu"),
572 cmds = commands_new();
573 command_add(cmds, "%s%s -c %sboot/cdboot.flp.bz2 | "
574 "%s%s of=%sdev/fd0 bs=32k",
575 a->os_root, cmd_name(a, "BUNZIP2"),
577 a->os_root, cmd_name(a, "DD"),
579 if (commands_execute(a, cmds))
580 inform(a->c, _("CDBoot floppy successfully created!"));
582 inform(a->c, _("CDBoot floppy was not successfully created."));
592 fn_create_memtest86_floppy(struct i_fn_args *a)
594 struct commands *cmds;
596 switch (dfui_be_present_dialog(a->c, _("Create memtest86 Floppy"),
597 "Create memtest86 Floppy|Return to Utilities Menu",
598 "While this installer allows you to test memory "
599 "on-line, the fact that the installer and operating "
600 "system are already loaded means that the memory "
601 "test has certain limits. For a more thorough "
602 "memory test, you can create a floppy containing "
603 "the memtest86 program, which boots up independently "
604 "of any operating system, allowing it access to "
605 "almost the entire memory of the computer for testing.\n\n"
606 "memtest86 is not a part of %s; "
607 "the memtest86 project can be found here:\n\n"
608 "http://www.memtest86.com/\n\n"
609 "To create a memtest86 floppy, insert a blank floppy "
610 "in unit 0 (``drive A:'') before proceeding."
611 "", OPERATING_SYSTEM_NAME)) {
613 cmds = commands_new();
614 command_add(cmds, "%s%s -c %sboot/memtest86.flp.bz2 | "
615 "%s%s of=%sdev/fd0 bs=32k",
616 a->os_root, cmd_name(a, "BUNZIP2"),
618 a->os_root, cmd_name(a, "DD"),
620 if (commands_execute(a, cmds))
621 inform(a->c, _("memtest86 floppy successfully created!"));
623 inform(a->c, _("memtest86 floppy was not successfully created."));
632 /**** NON-fn_ FUNCTIONS ***/
635 format_slice(struct i_fn_args *a)
637 struct commands *cmds;
641 cmds = commands_new();
644 * Create the device node if it does not exist.
646 command_add_ensure_dev(a, cmds,
647 slice_get_device_name(storage_get_selected_slice(a->s)));
650 * The information in a->s NEEDS to be accurate here!
651 * Presumably we just did a survey_storage() recently.
652 * XXX should we do another one here anyway just to be paranoid?
656 * Set the slice's sysid to 165.
658 disk_get_geometry(storage_get_selected_disk(a->s), &cyl, &hd, &sec);
659 command_add(cmds, "%s%s 'g c%d h%d s%d' >%snew.fdisk",
660 a->os_root, cmd_name(a, "ECHO"),
663 command_add(cmds, "%s%s 'p %d %d %lu %lu' >>%snew.fdisk",
664 a->os_root, cmd_name(a, "ECHO"),
665 slice_get_number(storage_get_selected_slice(a->s)),
667 slice_get_start(storage_get_selected_slice(a->s)),
668 slice_get_size(storage_get_selected_slice(a->s)),
670 if (slice_get_flags(storage_get_selected_slice(a->s)) & 0x80) {
671 command_add(cmds, "%s%s 'a %d' >>%snew.fdisk",
672 a->os_root, cmd_name(a, "ECHO"),
673 slice_get_number(storage_get_selected_slice(a->s)),
677 command_add(cmds, "%s%s %snew.fdisk",
678 a->os_root, cmd_name(a, "CAT"), a->tmp);
679 temp_file_add(a, "new.fdisk");
682 * Execute the fdisk script.
684 command_add(cmds, "%s%s -v -f %snew.fdisk %s",
685 a->os_root, cmd_name(a, "FDISK"), a->tmp,
686 disk_get_raw_device_name(storage_get_selected_disk(a->s)));
689 * Auto-disklabel the slice.
690 * NB: one cannot use "/dev/adXsY" here -
691 * it must be in the form "adXsY".
693 command_add(cmds, "%s%s -B -r -w %s auto",
694 a->os_root, cmd_name(a, "DISKLABEL"),
695 slice_get_raw_device_name(storage_get_selected_slice(a->s)));
698 * If there is an old 'virgin' disklabel hanging around
699 * in the temp dir, get rid of it. This won't happen
700 * from a real CD, but might happen with '-o' installs.
702 command_add(cmds, "%s%s -f %sinstall.disklabel.%s",
703 a->os_root, cmd_name(a, "RM"),
705 slice_get_device_name(storage_get_selected_slice(a->s)));
707 result = commands_execute(a, cmds);
715 autopacket(struct disk *d) {
719 for (p = disk_slice_first(d); p != NULL; p = slice_next(p)) {
720 tcap += slice_get_capacity(p);