Merge branch 'vendor/DHCPCD'
[dragonfly.git] / usr.sbin / installer / dfuibe_installer / fn_disk.c
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 108.
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             108,
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 }