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  * flow.c
36  * Workflow logic for installer.
37  * $Id: flow.c,v 1.67 2005/04/08 08:09:23 cpressey Exp $
38  */
39 
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <string.h>
45 
46 #ifdef ENABLE_NLS
47 #include <libintl.h>
48 #include <locale.h>
49 #include "libdfui/lang.h"
50 #define _(String) gettext (String)
51 extern int _nl_msg_cat_cntr;
52 #else
53 #define _(String) (String)
54 #endif
55 
56 #include "libaura/mem.h"
57 #include "libaura/dict.h"
58 #include "libaura/fspred.h"
59 
60 #include "libdfui/dfui.h"
61 #ifdef DEBUG
62 #include "libdfui/dump.h"
63 #endif
64 #include "libdfui/system.h"
65 
66 #include "libinstaller/commands.h"
67 #include "libinstaller/confed.h"
68 #include "libinstaller/diskutil.h"
69 #include "libinstaller/functions.h"
70 #include "libinstaller/uiutil.h"
71 
72 #include "flow.h"
73 #include "fn.h"
74 #include "pathnames.h"
75 
76 /*** GLOBALS ***/
77 
78 void (*state)(struct i_fn_args *) = NULL;
79 int do_reboot;
80 int use_hammer;		/* 0=UFS 1=HAMMER 2=HAMMER2 */
81 int use_uefi;
82 int during_install;
83 
84 /*** STATES ***/
85 
86 /*
87  * The installer works like a big state machine.  Each major form is
88  * a state.  When the user has filled out the form satisfactorily,
89  * and selects "OK", there is a transition to the next state, in a
90  * mostly-linear order towards the final, "successfully installed"
91  * state.  The user may also "Cancel", which generally causes a
92  * transition to the previous state (but may also take them back to
93  * the very first state in some cases.)
94  *
95  * Installer States:
96  * - Select localization	optional
97  * - Welcome to DragonFly	required
98  * - Begin Installation		required
99  * - Select Disk		required
100  * - Format Disk		optional	dd, fdisk
101  * - Select Partition		required	dd, disklabel
102  * - Create Subpartitions	required	disklabel, newfs
103  * - Install DragonFly		required	swapon, mkdir, mount, cpdup
104  * - Install Bootstrap		optional	boot0cfg
105  * - Reboot			optional	reboot
106  */
107 
108 #ifdef ENABLE_NLS
109 void
110 state_lang_menu(struct i_fn_args *a)
111 {
112 	struct dfui_form *f;
113 	struct dfui_response *r;
114 	int done = 0;
115 	char *id;
116 	int cancelled = 0;
117 
118 	while (!done) {
119 		f = dfui_form_create(
120 			"main_menu",
121 			_("Select Language"),
122 			_("Please select the language you wish you use."),
123 			"",
124 
125 			"p", "role", "menu",
126 
127 			"a", "default", "English",
128 			"English Standard Default", "",
129 			"a", "ru", "Russian",
130 			"Russian KOI8-R", "",
131 			NULL
132 		);
133 
134 		if (!dfui_be_present(a->c, f, &r))
135 			abort_backend();
136 
137 		id = aura_strdup(dfui_response_get_action_id(r));
138 
139 		if (strcmp(id, "default") == 0) {
140 			state = state_welcome;
141 			return;
142 		} else {
143 			state = state_welcome;
144 			done = 1;
145 		}
146 
147 		dfui_form_free(f);
148 		dfui_response_free(r);
149 	}
150 
151 	/* set keymap, scrnmap, fonts */
152 	if (!set_lang_syscons(id))
153 		return;
154 
155 	/* set envars */
156 	if (!set_lang_envars(id))
157 		return;
158 
159 	dfui_be_set_global_setting(a->c, "lang", id, &cancelled);
160 
161 	/* XXX if (!cancelled) ... ? */
162 
163 	/* let gettext know about changes */
164 	++_nl_msg_cat_cntr;
165 }
166 #endif
167 
168 /*
169  * state_welcome_livecd: the start state of the installer state machine,
170  * when run from the Live CD.  Briefly describe DragonFly to the user,
171  * and present them with a set of reasonable options of how to proceed.
172  */
173 void
174 state_welcome(struct i_fn_args *a)
175 {
176 	struct dfui_form *f;
177 	struct dfui_response *r;
178 	char msg_buf[2][1024];
179 
180 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
181 	    _("Welcome to %s"), OPERATING_SYSTEM_NAME);
182 
183 	snprintf(msg_buf[1], sizeof(msg_buf[1]),
184 	    _("Welcome to the %s Live CD."
185 	    "\n\n"
186 	    "%s is an efficient and elegant BSD "
187 	    "Unix-derived operating system.  For more information, see %s"
188 	    "\n\n"
189 	    "From this CD, you can boot into %s ``live'' "
190 	    "(without installing it) to evaluate it, to install it "
191 	    "manually, or to troubleshoot problems with an "
192 	    "existing installation, using either a command prompt "
193 	    "or menu-driven utilities."
194 	    "\n\n"
195 	    "Also, you can use this automated application to assist "
196 	    "you in installing %s on this computer and "
197 	    "configuring it once it is installed."
198 	    ""),
199 	    OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_URL,
200 	    OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME);
201 
202 	if ((a->flags & I_BOOTED_LIVECD) == 0) {
203 		state = state_welcome_system;
204 		return;
205 	}
206 
207 	f = dfui_form_create(
208 	    "welcome",
209 	    msg_buf[0],
210 
211 	    msg_buf[1],
212 
213 	    "",
214 
215 	    "p",	"special", 	"dfinstaller_welcome",
216 
217 	    NULL
218 	);
219 
220 	if (a->flags & I_UPGRADE_TOOGLE) {
221 		snprintf(msg_buf[0], sizeof(msg_buf[0]),
222 		    _("Upgrade a FreeBSD 4.X system to %s"),
223 		    OPERATING_SYSTEM_NAME);
224 		dfui_form_action_add(f, "upgrade",
225 		    dfui_info_new(_("Upgrade"),
226 		    msg_buf[0], ""));
227 	} else {
228 		snprintf(msg_buf[0], sizeof(msg_buf[0]),
229 		    _("Install %s"), OPERATING_SYSTEM_NAME);
230 		snprintf(msg_buf[1], sizeof(msg_buf[1]),
231 		    _("Install %s on a HDD or HDD partition on this computer"),
232 		    OPERATING_SYSTEM_NAME);
233 		dfui_form_action_add(f, "install",
234 		    dfui_info_new(msg_buf[0],
235 		    msg_buf[1], ""));
236 	}
237 
238 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
239 	    _("Configure a %s system once it has been installed on HDD"),
240 	    OPERATING_SYSTEM_NAME);
241 	dfui_form_action_add(f, "configure",
242 	    dfui_info_new(_("Configure an Installed System"),
243 	    msg_buf[0], ""));
244 
245 	dfui_form_action_add(f, "utilities",
246 	    dfui_info_new(_("Live CD Utilities"),
247 	    _("Utilities to work with disks, diagnostics, and the LiveCD Environment"), ""));
248 
249 	dfui_form_action_add(f, "exit",
250 	    dfui_info_new(_("Exit to Live CD"),
251 	    _("Exit this program to a login prompt with access to the LiveCD"), ""));
252 
253 	dfui_form_action_add(f, "reboot",
254 	    dfui_info_new(_("Reboot this Computer"),
255 	    _("Reboot this computer (e.g. to boot into a newly installed system)"), ""));
256 
257 	dfui_form_action_add(f, "configure_netboot",
258 	    dfui_info_new(_("Setup NetBoot Install Services"),
259 	    _("Setup machine as remote installation server"), ""));
260 
261 	if (!dfui_be_present(a->c, f, &r))
262 		abort_backend();
263 
264 	if (strcmp(dfui_response_get_action_id(r), "install") == 0) {
265 		state = state_begin_install;
266 	} else if (strcmp(dfui_response_get_action_id(r), "upgrade") == 0) {
267 		state = state_begin_upgrade;
268 	} else if (strcmp(dfui_response_get_action_id(r), "configure") == 0) {
269 		storage_set_selected_disk(a->s, NULL);
270 		storage_set_selected_slice(a->s, NULL);
271 		state = state_configure_menu;
272 	} else if (strcmp(dfui_response_get_action_id(r), "utilities") == 0) {
273 		state = state_utilities_menu;
274 	} else if (strcmp(dfui_response_get_action_id(r), "exit") == 0) {
275 		state = NULL;
276         } else if (strcmp(dfui_response_get_action_id(r), "configure_netboot") == 0) {
277                 state = state_setup_remote_installation_server;
278 	} else if (strcmp(dfui_response_get_action_id(r), "reboot") == 0) {
279 		state = state_reboot;
280 	}
281 
282 	dfui_form_free(f);
283 	dfui_response_free(r);
284 }
285 
286 /*
287  * state_welcome_system: the start state of the installer state machine,
288  * when run from the installed system.  Allow the user to configure the
289  * system.
290  */
291 void
292 state_welcome_system(struct i_fn_args *a)
293 {
294 	struct dfui_form *f;
295 	struct dfui_response *r;
296 	char msg_buf[2][1024];
297 
298 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
299 	    _("Configure this %s System"), OPERATING_SYSTEM_NAME);
300 
301 	snprintf(msg_buf[1], sizeof(msg_buf[1]),
302 	    _("Thank you for choosing %s."
303 	    "\n\n"
304 	    "For up-to-date news and information on %s, "
305 	    "make sure to check out"
306 	    "\n\n"
307 	    "%s"
308 	    "\n\n"
309 	    "You can use this automated application to assist "
310 	    "you in setting up this %s system."
311 	    ""),
312 	    OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME,
313 	    OPERATING_SYSTEM_URL, OPERATING_SYSTEM_NAME);
314 
315 
316 	f = dfui_form_create(
317 	    "welcome",
318 	    msg_buf[0],
319 
320 	    msg_buf[1],
321 
322 	    "",
323 
324 	    "p",	"special", 	"dfinstaller_welcome",
325 
326 	    NULL
327 	);
328 
329 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
330 	    _("Configure this %s system"), OPERATING_SYSTEM_NAME);
331 
332 	dfui_form_action_add(f, "environment",
333 	    dfui_info_new(_("Configure this System"),
334 	    msg_buf[0], ""));
335 
336 	dfui_form_action_add(f, "utilities",
337 	    dfui_info_new(_("Utilities"),
338 	    _("Utilities to work with and diagnose disks and other subsystems"), ""));
339 
340 	dfui_form_action_add(f, "exit",
341 	    dfui_info_new(_("Exit Installer"),
342 	    _("Exit this program and return to the system"), ""));
343 
344 	if (!dfui_be_present(a->c, f, &r))
345 		abort_backend();
346 
347 	if (strcmp(dfui_response_get_action_id(r), "environment") == 0) {
348 		state = state_environment_menu;
349 	} else if (strcmp(dfui_response_get_action_id(r), "utilities") == 0) {
350 		state = state_utilities_menu;
351 	} else if (strcmp(dfui_response_get_action_id(r), "exit") == 0) {
352 		state = NULL;
353 	} else if (strcmp(dfui_response_get_action_id(r), "reboot") == 0) {
354 		state = state_reboot;
355 	}
356 
357 	dfui_form_free(f);
358 	dfui_response_free(r);
359 }
360 
361 void
362 state_configure_menu(struct i_fn_args *a)
363 {
364 	struct dfui_form *f = NULL;
365 	struct dfui_response *r = NULL;
366 	struct commands *cmds;
367 	int done = 0;
368 	char msg_buf[2][1024];
369 
370 	if (storage_get_selected_disk(a->s) == NULL || storage_get_selected_slice(a->s) == NULL) {
371 		if (!survey_storage(a)) {
372 			inform(a->c, _("Errors occurred while probing "
373 			    "the system for its storage capabilities."));
374 		}
375 
376 		a->short_desc = _("Select the disk containing the installation.");
377 		a->cancel_desc = _("Return to Welcome Menu");
378 		fn_select_disk(a);
379 		if (!a->result || storage_get_selected_disk(a->s) == NULL) {
380 			state = state_welcome;
381 			return;
382 		}
383 
384 		a->short_desc = _("Select the primary partition containing the installation.");
385 		a->cancel_desc = _("Return to Welcome Menu");
386 		fn_select_slice(a);
387 
388 		if (!a->result || storage_get_selected_slice(a->s) == NULL) {
389 			state = state_welcome;
390 			return;
391 		}
392 	}
393 
394 	a->cfg_root = "mnt";
395 
396 	if (during_install == 0) {
397 		switch (dfui_be_present_dialog(a->c, _("Select file system"),
398 		    _("HAMMER2|HAMMER1|UFS|Return to Welcome Menu"),
399 		    _("Please select the file system installed on the disk.\n\n")))
400 		{
401 		case 1:
402 			/* HAMMER2 (first menu item is the default) */
403 			use_hammer = 2;
404 			break;
405 		case 2:
406 			/* HAMMER1 */
407 			use_hammer = 1;
408 			break;
409 		case 3:
410 			/* UFS */
411 			use_hammer = 0;
412 			break;
413 		case 4:
414 			state = state_welcome;
415 			return;
416 			/* NOTREACHED */
417 			break;
418 		default:
419 			abort_backend();
420 			break;
421 		}
422 	}
423 
424 	if (!mount_target_system(a)) {
425 		inform(a->c, _("Target system could not be mounted."));
426 		state = state_welcome;
427 		return;
428 	}
429 
430 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
431 	    _("The options on this menu allow you to configure a "
432 	    "%s system after it has already been "
433 	    "installed."), OPERATING_SYSTEM_NAME);
434 
435 	while (!done) {
436 		f = dfui_form_create(
437 		    "configure_menu",
438 		    _("Configure an Installed System"),
439 		    msg_buf[0],
440 		    "",
441 		    "p", "role", "menu",
442 
443 		    "a", "set_timezone",
444 		    _("Select timezone"),
445 		    _("Set the Time Zone of your physical location"), "",
446 		    "a", "set_datetime",
447 		    _("Set date and time"),
448 		    _("Set the Time and Date of your machine"), "",
449 
450 		    "a", "set_kbdmap",
451 		    _("Set keyboard map"),
452 		    _("Set what kind of keyboard layout you have"), "",
453 		    "a", "root_passwd",	_("Set root password"),
454 		    _("Set the password that the root (superuser) account will use"), "",
455 		    "a", "add_user", _("Add a user"),
456 		    _("Add a user to the system"), "",
457 		    "a", "assign_ip", _("Configure network interfaces"),
458 		    _("Set up network interfaces (NICs, ethernet, TCP/IP, etc)"), "",
459 		    "a", "assign_hostname_domain",
460 		    _("Configure hostname and domain"),
461 		    _("Configure the hostname and domain for this system"), "",
462 		    /*
463 		    "a", "select_services", "Select Services",
464 		    "Enable/Disable system services (servers, daemons, etc.)", "",
465 		    */
466 		    "a", "set_vidfont",
467 		    _("Set console font"),
468 		    _("Set how the characters on your video console look"), "",
469 		    "a", "set_scrnmap",
470 		    _("Set screen map"),
471 		    _("Set how characters are translated before console display"), "",
472 
473 		    "a", "cancel", _("Return to Welcome Menu"), "", "",
474 		    "p", "accelerator", "ESC",
475 
476 		    NULL
477 		);
478 
479 		if (!dfui_be_present(a->c, f, &r))
480 			abort_backend();
481 
482 		/* XXX set up a */
483 		a->cfg_root = "mnt/";
484 		if (strcmp(dfui_response_get_action_id(r), "root_passwd") == 0) {
485 			fn_root_passwd(a);
486 		} else if (strcmp(dfui_response_get_action_id(r), "add_user") == 0) {
487 			fn_add_user(a);
488 		} else if (strcmp(dfui_response_get_action_id(r), "assign_ip") == 0) {
489 			fn_assign_ip(a);
490 		} else if (strcmp(dfui_response_get_action_id(r), "assign_hostname_domain") == 0) {
491 			fn_assign_hostname_domain(a);
492 		} else if (strcmp(dfui_response_get_action_id(r), "select_services") == 0) {
493 			fn_select_services(a);
494 		} else if (strcmp(dfui_response_get_action_id(r), "set_kbdmap") == 0) {
495 			fn_set_kbdmap(a);
496 		} else if (strcmp(dfui_response_get_action_id(r), "set_vidfont") == 0) {
497 			fn_set_vidfont(a);
498 		} else if (strcmp(dfui_response_get_action_id(r), "set_scrnmap") == 0) {
499 			fn_set_scrnmap(a);
500 		} else if (strcmp(dfui_response_get_action_id(r), "set_timezone") == 0) {
501 			fn_set_timezone(a);
502 		} else if (strcmp(dfui_response_get_action_id(r), "set_datetime") == 0) {
503 			fn_assign_datetime(a);
504 		} else if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
505 			state = state_welcome;
506 			done = 1;
507 		}
508 
509 		dfui_form_free(f);
510 		dfui_response_free(r);
511 	}
512 
513 	/*
514 	 * Before unmounting the system, write out any changes to rc.conf.
515 	 */
516 	config_vars_write(rc_conf, CONFIG_TYPE_SH,
517 	    "%s%setc/rc.conf", a->os_root, a->cfg_root);
518 
519 	/*
520 	 * Clear out configuration variable table in memory.
521 	 */
522 	config_vars_free(rc_conf);
523 	rc_conf = config_vars_new();
524 
525 	/*
526 	 * Finally, unmount the system we mounted on /mnt and remove mappings.
527 	 */
528 	cmds = commands_new();
529 	unmount_all_under(a, cmds, "%smnt", a->os_root);
530 	commands_execute(a, cmds);
531 	commands_free(cmds);
532 
533 	if (remove_all_mappings(a) == NULL)
534 		inform(a->c, _("Warning: mappings could not be removed."));
535 }
536 
537 void
538 state_utilities_menu(struct i_fn_args *a)
539 {
540 	struct dfui_form *f;
541 	struct dfui_response *r;
542 
543 	if (!survey_storage(a)) {
544 		inform(a->c, _("Errors occurred while probing "
545 		    "the system for its storage capabilities."));
546 	}
547 
548 	f = dfui_form_create(
549 	    "utilities_menu",
550 	    _("Live CD Utilities Menu"),
551 	    _("On these submenus you will find utilities to help "
552 	    "you set up your Live CD environment, diagnose "
553 	    "and analyse this system, and work with "
554 	    "the devices attached to this computer."),
555 	    "",
556 	    "p", "role", "menu",
557 	    "a", "environment", _("LiveCD Environment"),
558 	    _("Configure the LiveCD Environment"), "",
559 	    "a", "diagnostics", _("System Diagnostics"),
560 	    _("Probe and display detailed information about this system"), "",
561 	    "a", "diskutil", _("Disk Utilities"),
562 	    _("Format and check hard drives and floppy disks"), "",
563 	    "a", "livecd", _("Exit to Live CD"),
564 	    _("Exit this program to a login prompt with access to the LiveCD"), "",
565 	    "a", "reboot",
566 	    _("Reboot this Computer"), "", "",
567 	    "a", "cancel",
568 	    _("Return to Welcome Menu"), "", "",
569 	    "p", "accelerator", "ESC",
570 	    NULL
571 	);
572 
573 	if (!dfui_be_present(a->c, f, &r))
574 		abort_backend();
575 
576 	if (strcmp(dfui_response_get_action_id(r), "environment") == 0)
577 		state = state_environment_menu;
578 	else if (strcmp(dfui_response_get_action_id(r), "diagnostics") == 0)
579 		state = state_diagnostics_menu;
580 	else if (strcmp(dfui_response_get_action_id(r), "diskutil") == 0)
581 		state = state_diskutil_menu;
582 	else if (strcmp(dfui_response_get_action_id(r), "livecd") == 0)
583 		state = NULL;
584 	else if (strcmp(dfui_response_get_action_id(r), "reboot") == 0)
585 		state = state_reboot;
586 	else if (strcmp(dfui_response_get_action_id(r), "cancel") == 0)
587 		state = state_welcome;
588 
589 	dfui_form_free(f);
590 	dfui_response_free(r);
591 }
592 
593 void
594 state_environment_menu(struct i_fn_args *a)
595 {
596 	struct dfui_form *f;
597 	struct dfui_response *r;
598 	int done = 0;
599 	char msg_buf[2][1024];
600 
601 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
602 	    _("On this menu you will find utilities to help you "
603 	    "set up your Live CD environment.\n\nNote "
604 	    "that these functions affect only the LiveCD "
605 	    "environment you are currently using, and they will "
606 	    "not affect any system that may be installed on "
607 	    "this computer UNLESS you subsequently choose to "
608 	    "install %s from this environment, in which "
609 	    "case they will be copied to the newly installed "
610 	    "system."), OPERATING_SYSTEM_NAME);
611 
612 	while (!done) {
613 		f = dfui_form_create(
614 		    "environment_menu",
615 		    _("Live CD Environment Menu"),
616 		    msg_buf[0],
617 		    "",
618 		    "p", "role", "menu",
619 
620 		    "a", "set_timezone",
621 		    _("Select timezone"),
622 		    _("Set the Time Zone of your physical location"), "",
623 		    "a", "set_datetime",
624 		    _("Set date and time"),
625 		    _("Set the Time and Date of your machine"), "",
626 
627 		    "a", "set_kbdmap",
628 		    _("Set keyboard map"),
629 		    _("Set what kind of keyboard layout you have"), "",
630 		    "a", "set_vidfont",
631 		    _("Set console font"),
632 		    _("Set how the characters on your video console look"), "",
633 		    "a", "set_scrnmap",
634 		    _("Set screen map"),
635 		    _("Set how characters are translated before console display"), "",
636 
637 		    "a", "assign_hostname_domain",
638 		    _("Configure hostname and domain"),
639 		    _("Configure the hostname and domain for this system"), "",
640 		    "a", "assign_ip",
641 		    _("Configure network interfaces"),
642 		    _("Set up network interfaces (NICs, ethernet, TCP/IP, etc)"), "",
643 
644 		    "a", "cancel",
645 		    _("Return to Utilities Menu"), "", "",
646 		    "p", "accelerator", "ESC",
647 
648 		    NULL
649 		);
650 
651 		if (!dfui_be_present(a->c, f, &r))
652 			abort_backend();
653 
654 		/* Set up a */
655 		a->cfg_root = "";
656 		if (strcmp(dfui_response_get_action_id(r), "set_kbdmap") == 0) {
657 			fn_set_kbdmap(a);
658 		} else if (strcmp(dfui_response_get_action_id(r), "set_vidfont") == 0) {
659 			fn_set_vidfont(a);
660 		} else if (strcmp(dfui_response_get_action_id(r), "set_scrnmap") == 0) {
661 			fn_set_scrnmap(a);
662 		} else if (strcmp(dfui_response_get_action_id(r), "assign_hostname_domain") == 0) {
663 			fn_assign_hostname_domain(a);
664 		} else if (strcmp(dfui_response_get_action_id(r), "assign_ip") == 0) {
665 			fn_assign_ip(a);
666 		} else if (strcmp(dfui_response_get_action_id(r), "set_timezone") == 0) {
667 			fn_set_timezone(a);
668 		} else if (strcmp(dfui_response_get_action_id(r), "set_datetime") == 0) {
669 			fn_assign_datetime(a);
670 		} else if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
671 			state = state_utilities_menu;
672 			done = 1;
673 		}
674 
675 		dfui_form_free(f);
676 		dfui_response_free(r);
677 	}
678 }
679 
680 void
681 state_diagnostics_menu(struct i_fn_args *a)
682 {
683 	struct dfui_form *f;
684 	struct dfui_action *k;
685 	struct dfui_response *r;
686 	int done = 0;
687 
688 	while (!done) {
689 		f = dfui_form_create(
690 		    "utilities_menu",
691 		    _("Live CD Diagnostics Menu"),
692 		    _("These functions can help you diagnose this system."),
693 		    "",
694 		    "p", "role", "menu",
695 
696 		    "a", "show_dmesg",
697 		    _("Display system startup messages"),
698 		    _("Display system startup messages (dmesg)"), "",
699 		    "a", "pciconf",
700 		    _("Display PCI devices"),
701 		    _("Display PCI devices (pciconf)"), "",
702 		    "a", "natacontrol",
703 		    _("Display ATA devices"),
704 		    _("Display ATA devices (natacontrol)"), "",
705 		    NULL
706 		);
707 
708 		k = dfui_form_action_add(f, "cancel",
709 		    dfui_info_new(_("Return to Utilities Menu"), "", ""));
710 		dfui_action_property_set(k, "accelerator", "ESC");
711 
712 		if (!dfui_be_present(a->c, f, &r))
713 			abort_backend();
714 
715 		/* XXX set up a */
716 		if (strcmp(dfui_response_get_action_id(r), "show_dmesg") == 0) {
717 			fn_show_dmesg(a);
718 		} else if (strcmp(dfui_response_get_action_id(r), "pciconf") == 0) {
719 			fn_show_pciconf(a);
720 		} else if (strcmp(dfui_response_get_action_id(r), "natacontrol") == 0) {
721 			fn_show_natacontrol(a);
722 		} else if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
723 			state = state_utilities_menu;
724 			done = 1;
725 		}
726 
727 		dfui_form_free(f);
728 		dfui_response_free(r);
729 	}
730 }
731 
732 void
733 state_diskutil_menu(struct i_fn_args *a)
734 {
735 	struct dfui_form *f;
736 	struct dfui_action *k;
737 	struct dfui_response *r;
738 	int done = 0;
739 
740 	while (!done) {
741 		f = dfui_form_create(
742 		    "utilities_menu",
743 		    _("Disk Utilities Menu"),
744 		    _("These functions let you manipulate the storage devices "
745 		    "attached to this computer."),
746 		    "",
747 
748 		    "p", "role", "menu",
749 
750 		    "a", "format_hdd",
751 		    _("Format a hard disk drive"), "", "",
752 		    "a", "wipe_start_of_disk",
753 		    _("Wipe out the start of a disk"), "", "",
754 		    "a", "wipe_start_of_slice",
755 		    _("Wipe out the start of a primary partition"), "", "",
756 		    "a", "install_bootblocks",
757 		    _("Install bootblocks on disks"), "", "",
758 		    "a", "format_msdos_floppy",
759 		    _("Format an MSDOS floppy"), "", "",
760 		    NULL
761 		);
762 
763 		if (is_file("%sboot/cdboot.flp.bz2", a->os_root)) {
764 			dfui_form_action_add(f, "create_cdboot_floppy",
765 			    dfui_info_new(_("Create a CDBoot floppy"),
766 			    "",
767 			    ""));
768 		}
769 
770 		k = dfui_form_action_add(f, "cancel",
771 		    dfui_info_new(_("Return to Utilities Menu"), "", ""));
772 		dfui_action_property_set(k, "accelerator", "ESC");
773 
774 		if (!dfui_be_present(a->c, f, &r))
775 			abort_backend();
776 
777 		/* XXX set up a */
778 		if (strcmp(dfui_response_get_action_id(r), "format_hdd") == 0) {
779 			storage_set_selected_disk(a->s, NULL);
780 			storage_set_selected_slice(a->s, NULL);
781 			if (use_uefi)
782 				fn_format_disk_uefi(a);
783 			else
784 				fn_format_disk_mbr(a);
785 		} else if (strcmp(dfui_response_get_action_id(r), "wipe_start_of_disk") == 0) {
786 			fn_wipe_start_of_disk(a);
787 		} else if (strcmp(dfui_response_get_action_id(r), "wipe_start_of_slice") == 0) {
788 			fn_wipe_start_of_slice(a);
789 		} else if (strcmp(dfui_response_get_action_id(r), "install_bootblocks") == 0) {
790 			a->short_desc = _("Select the disks on which "
791 			    "you wish to install bootblocks.");
792 			a->cancel_desc = _("Return to Utilities Menu");
793 			fn_install_bootblocks(a, NULL);
794 		} else if (strcmp(dfui_response_get_action_id(r), "format_msdos_floppy") == 0) {
795 			fn_format_msdos_floppy(a);
796 		} else if (strcmp(dfui_response_get_action_id(r), "create_cdboot_floppy") == 0) {
797 			fn_create_cdboot_floppy(a);
798 		} else if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
799 			state = state_utilities_menu;
800 			done = 1;
801 		}
802 
803 		dfui_form_free(f);
804 		dfui_response_free(r);
805 	}
806 }
807 
808 /** INSTALLER STATES **/
809 
810 /*
811  * state_begin_upgrade: Ask the user where the freebsd
812  * 4.X install is and make sure its safe to proceed.
813  *
814  */
815 void
816 state_begin_upgrade(struct i_fn_args *a)
817 {
818         //struct dfui_form *f = NULL;
819         //struct dfui_response *r = NULL;
820         //int done = 0;
821 
822         if (storage_get_selected_disk(a->s) == NULL || storage_get_selected_slice(a->s) == NULL) {
823 		if (!survey_storage(a)) {
824 			inform(a->c, _("Errors occurred while probing "
825 			    "the system for its storage capabilities."));
826 		}
827 
828                 a->short_desc = _("Select the disk containing the installation that you would like to upgrade.");
829                 a->cancel_desc = _("Return to Welcome Menu");
830                 fn_select_disk(a);
831                 if (!a->result || storage_get_selected_disk(a->s) == NULL) {
832                         state = state_welcome;
833                         return;
834                 }
835 
836                 a->short_desc = _("Select the primary partition containing the installation you would like to upgrade.");
837                 a->cancel_desc = _("Return to Welcome Menu");
838                 fn_select_slice(a);
839 
840                 if (!a->result || storage_get_selected_slice(a->s) == NULL) {
841                         state = state_welcome;
842                         return;
843                 }
844         }
845 
846         a->cfg_root = "mnt";
847         if (!mount_target_system(a)) {
848                 inform(a->c, _("Target system could not be mounted."));
849                 state = state_welcome;
850                 return;
851         }
852 }
853 
854 /*
855  * state_begin_install: Briefly describe the install process
856  * to the user, and let them proceed (or not.)
857  */
858 void
859 state_begin_install(struct i_fn_args *a)
860 {
861 	struct dfui_form *f;
862 	struct dfui_response *r;
863 	char msg_buf[3][1024];
864 
865 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
866 	    _("This application will install %s"
867 	    " on one of the hard disk drives attached to this computer. "
868 	    "It has been designed to make it easy to install "
869 	    "%s in the typical case. "
870 	    "If you have special requirements that are not addressed "
871 	    "by this installer, or if you have problems using it, you "
872 	    "are welcome to install %s manually. "
873 	    "To do so select Exit to Live CD, login as root, and follow "
874 	    "the instructions given in the file /README ."
875 	    "\n\n"
876 	    "NOTE! As with any installation process, YOU ARE "
877 	    "STRONGLY ENCOURAGED TO BACK UP ANY IMPORTANT DATA ON THIS "
878 	    "COMPUTER BEFORE PROCEEDING!"
879 	    ""),
880 	    OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME,
881 	    OPERATING_SYSTEM_NAME);
882 
883 	snprintf(msg_buf[1], sizeof(msg_buf[1]),
884 	    _("Some situations in which you might not wish to use this "
885 	    "installer are:\n\n"
886 	    "- you want to install %s onto a "
887 	    "logical/extended partition;\n"
888 	    "- you want to install %s "
889 	    "onto a ``dangerously dedicated'' disk; or\n"
890 	    "- you want full and utter control over the install process."
891 	    ""),
892 	    OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME);
893 
894 	snprintf(msg_buf[2], sizeof(msg_buf[2]),
895 	    _("Install %s"), OPERATING_SYSTEM_NAME);
896 
897 	f = dfui_form_create(
898 	    "begin_install",
899 	    _("Begin Installation"),
900 	    msg_buf[0],
901 
902 	    msg_buf[1],
903 	    "p", "special", "dfinstaller_begin_install",
904 	    "p", "minimum_width", "76",
905 
906 	    "a", "proceed", msg_buf[2],
907 	    "", "",
908 	    "a", "cancel", _("Return to Welcome Menu"),
909 	    "", "",
910 	    "p", "accelerator", "ESC",
911 	    "a", "livecd", _("Exit to Live CD"),
912 	    "", "",
913 	    NULL
914 	);
915 
916 	if (!dfui_be_present(a->c, f, &r))
917 		abort_backend();
918 
919 	if (strcmp(dfui_response_get_action_id(r), "proceed") == 0) {
920 		if (!survey_storage(a)) {
921 			inform(a->c, _("Errors occurred while probing "
922 			    "the system for its storage capabilities."));
923 		}
924 		state = state_ask_uefi;
925 	} else if (strcmp(dfui_response_get_action_id(r), "livecd") == 0) {
926 		state = NULL;
927 	} else if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
928 		state = state_welcome;
929 	}
930 
931 	dfui_form_free(f);
932 	dfui_response_free(r);
933 }
934 
935 /*
936  * state_ask_uefi: ask the user if they want a UEFI installation
937  */
938 void
939 state_ask_uefi(struct i_fn_args *a)
940 {
941 	use_uefi = 0;
942 
943 	switch (dfui_be_present_dialog(a->c, _("UEFI or legacy BIOS?"),
944 	    _("UEFI|Legacy BIOS|Return to Begin Installation"),
945 	    _("Do you wish to set up %s for a UEFI or legacy BIOS system?"),
946 	    OPERATING_SYSTEM_NAME))
947 	{
948 	case 1:
949 		/* UEFI */
950 		use_uefi = 1;
951 		break;
952 	case 2:
953 		/* MBR */
954 		break;
955 	case 3:
956 		state = state_begin_install;
957 		return;
958 		/* NOTREACHED */
959 		break;
960 	default:
961 		abort_backend();
962 		break;
963 	}
964 	state = state_select_disk;
965 }
966 
967 /*
968  * state_select_disk: ask the user on which physical disk they wish
969  * to install DragonFly.
970  */
971 void
972 state_select_disk(struct i_fn_args *a)
973 {
974 	struct disk *d;
975 	int num_disks = 0;
976 	char msg_buf[1][1024];
977 
978 	for (d = storage_disk_first(a->s); d != NULL; d = disk_next(d))
979 		num_disks++;
980 
981 	if (num_disks == 0) {
982 		inform(a->c, _("The installer could not find any disks suitable "
983 		    "for installation (IDE or SCSI) attached to this "
984 		    "computer.  If you wish to install %s"
985 		    " on an unorthodox storage device, you will have to "
986 		    "exit to a LiveCD command prompt and install it "
987 		    "manually, using the file /README as a guide."),
988 		    OPERATING_SYSTEM_NAME);
989 		state = state_welcome;
990 		return;
991 	}
992 
993 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
994 	    _("Select a disk on which to install %s"),
995 	    OPERATING_SYSTEM_NAME);
996 	a->short_desc = msg_buf[0];
997 	a->cancel_desc = _("Return to Begin Installation");
998 	fn_select_disk(a);
999 	if (!a->result || storage_get_selected_disk(a->s) == NULL) {
1000 		state = state_begin_install;
1001 	} else {
1002 #if 0
1003 		if (disk_get_capacity(storage_get_selected_disk(a->s)) < DISK_MIN) {
1004 			inform(a->c, _("WARNING: you should have a disk "
1005 			    "at least %dM in size, or "
1006 			    "you may encounter problems trying to "
1007 			    "install %s."), DISK_MIN, OPERATING_SYSTEM_NAME);
1008 		}
1009 #endif
1010 		state = state_format_disk;
1011 	}
1012 }
1013 
1014 void
1015 state_ask_fs(struct i_fn_args *a)
1016 {
1017 	use_hammer = 0;
1018 
1019 	switch (dfui_be_present_dialog(a->c, _("Select file system"),
1020 	    _("Use HAMMER2|Use HAMMER1|Use UFS|Return to Select Disk"),
1021 	    _("Please select the file system you want to use with %s.\n\n"
1022 	      "HAMMER2 is the recommended %s file system.  "
1023 	      "HAMMER1 is the previous %s file system.  "
1024 	      "UFS is the traditional BSD file system."),
1025 	    OPERATING_SYSTEM_NAME,
1026 	    OPERATING_SYSTEM_NAME,
1027 	    OPERATING_SYSTEM_NAME))
1028 	{
1029 	case 1:
1030 		/* HAMMER2 (first menu item is the default) */
1031 		use_hammer = 2;
1032 		break;
1033 	case 2:
1034 		/* HAMMER1 */
1035 		use_hammer = 1;
1036 		break;
1037 	case 3:
1038 		/* UFS */
1039 		break;
1040 	case 4:
1041 		state = state_select_disk;
1042 		return;
1043 		/* NOTREACHED */
1044 		break;
1045 	default:
1046 		abort_backend();
1047 		break;
1048 	}
1049 	state = state_create_subpartitions;
1050 }
1051 
1052 /*
1053  * state_format_disk: ask the user if they wish to format the disk they
1054  * selected.
1055  */
1056 void
1057 state_format_disk(struct i_fn_args *a)
1058 {
1059 
1060 	if (use_uefi) {
1061 		fn_format_disk_uefi(a);
1062 		if (a->result)
1063 			state = state_ask_fs;
1064 		else
1065 			state = state_select_disk;
1066 		return;
1067 	}
1068 
1069 	/* XXX Using part of the disk is only supported for MBR installs */
1070 	switch (dfui_be_present_dialog(a->c, _("How Much Disk?"),
1071 	    _("Use Entire Disk|Use Part of Disk|Return to Select Disk"),
1072 	    _("Select how much of this disk you want to use for %s.\n\n%s"),
1073 	    OPERATING_SYSTEM_NAME,
1074 	    disk_get_desc(storage_get_selected_disk(a->s)))) {
1075 	case 1:
1076 		/* Entire Disk */
1077 		if (measure_activated_swap_from_disk(a, storage_get_selected_disk(a->s)) > 0) {
1078 			if (swapoff_all(a) == NULL) {
1079 				inform(a->c, _("Warning: swap could not be turned off."));
1080 				state = state_select_disk;
1081 				return;
1082 			}
1083 		}
1084 
1085 		fn_format_disk_mbr(a);
1086 		if (a->result)
1087 			state = state_ask_fs;
1088 		else
1089 			state = state_format_disk;
1090 		break;
1091 	case 2:
1092 		/* Part of Disk */
1093 		state = state_select_slice;
1094 		break;
1095 	case 3:
1096 		/* Return */
1097 		state = state_select_disk;
1098 		break;
1099 	default:
1100 		abort_backend();
1101 		break;
1102 	}
1103 }
1104 
1105 /*
1106  * state_select_slice: ask the user which slice they wish to install
1107  * DragonFly on.  In order to avoid confusing them, refer to it as
1108  * a primary partition, but tell them what BSD has traditionally called
1109  * it, too.
1110  */
1111 void
1112 state_select_slice(struct i_fn_args *a)
1113 {
1114 	char msg_buf[1][1024];
1115 
1116 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
1117 	    _("Select the existing primary partition (also "
1118 	    "known as a `slice' in the BSD tradition) on "
1119 	    "which to install %s.\n\n"
1120 	    "Note that if you do not have any existing "
1121 	    "primary partitions on this disk, you must "
1122 	    "first create some. This installer does not "
1123 	    "currently have the ability to do this, so "
1124 	    "you will have to exit and run fdisk (in "
1125 	    "DOS or *BSD) or parted (in Linux) to do so."),
1126 	    OPERATING_SYSTEM_NAME);
1127 
1128 	a->short_desc = msg_buf[0];
1129 	a->cancel_desc = _("Return to Select Disk");
1130 	fn_select_slice(a);
1131 	if (!a->result || storage_get_selected_slice(a->s) == NULL) {
1132 		state = state_select_disk;
1133 	} else {
1134 		if (measure_activated_swap_from_slice(a, storage_get_selected_disk(a->s),
1135 		    storage_get_selected_slice(a->s)) > 0) {
1136 			if (swapoff_all(a) == NULL) {
1137 				inform(a->c, _("Warning: swap could not be turned off."));
1138 				state = state_select_slice;
1139 				return;
1140 			}
1141 		}
1142 
1143 		if (slice_get_capacity(storage_get_selected_slice(a->s)) < DISK_MIN) {
1144 			inform(a->c, _("WARNING: you should have a primary "
1145 			    "partition at least %dM in size, or "
1146 			    "you may encounter problems trying to "
1147 			    "install %s."), DISK_MIN, OPERATING_SYSTEM_NAME);
1148 		}
1149 
1150 		if (confirm_dangerous_action(a->c,
1151 		    _("WARNING!  ALL data in primary partition #%d,\n\n%s\n\non the "
1152 		    "disk\n\n%s\n\n will be IRREVOCABLY ERASED!\n\nAre you "
1153 		    "ABSOLUTELY SURE you wish to take this action?  This is "
1154 		    "your LAST CHANCE to cancel!"),
1155 		    slice_get_number(storage_get_selected_slice(a->s)),
1156 		    slice_get_desc(storage_get_selected_slice(a->s)),
1157 		    disk_get_desc(storage_get_selected_disk(a->s)))) {
1158 			if (!format_slice(a)) {
1159 				inform(a->c, _("Primary partition #%d was "
1160 				    "not correctly formatted, and may "
1161 				    "now be in an inconsistent state. "
1162 				    "We recommend re-formatting it "
1163 				    "before proceeding."),
1164 				    slice_get_number(storage_get_selected_slice(a->s)));
1165 			} else {
1166 				inform(a->c, _("Primary partition #%d was formatted."),
1167 				    slice_get_number(storage_get_selected_slice(a->s)));
1168 				state = state_ask_fs;
1169 			}
1170 		} else {
1171 			inform(a->c, _("Action cancelled - no primary partitions were formatted."));
1172 			state = state_select_slice;
1173 		}
1174 	}
1175 }
1176 
1177 /*
1178  * state_create_subpartitions: let the user specify what subpartitions they
1179  * want on the disk, how large each should be, and where it should be mounted.
1180  */
1181 void
1182 state_create_subpartitions(struct i_fn_args *a)
1183 {
1184 	struct commands *cmds;
1185 
1186 	if (measure_activated_swap_from_slice(a, storage_get_selected_disk(a->s),
1187 	    storage_get_selected_slice(a->s)) > 0) {
1188 		if (swapoff_all(a) == NULL) {
1189 			inform(a->c, _("Warning: swap could not be turned off."));
1190 			state = disk_get_formatted(storage_get_selected_disk(a->s)) ?
1191 			    state_select_disk : state_select_slice;
1192 			return;
1193 		}
1194 	}
1195 
1196 	cmds = commands_new();
1197 
1198 	/*
1199 	 * Auto-disklabel the slice.
1200 	 * NB: one cannot use "/dev/adXsY" here -
1201 	 * it must be in the form "adXsY".
1202 	 */
1203 	command_add(cmds, "%s%s -W %s",
1204 	    a->os_root, cmd_name(a, "DISKLABEL64"),
1205 	    slice_get_device_name(storage_get_selected_slice(a->s)));
1206 	command_add(cmds, "%s%s if=/dev/zero of=/dev/%s bs=32k count=16",
1207 	    a->os_root, cmd_name(a, "DD"),
1208 	    slice_get_device_name(storage_get_selected_slice(a->s)));
1209 	command_add(cmds, "%s%s -B -r -w %s",
1210 	    a->os_root, cmd_name(a, "DISKLABEL64"),
1211 	    slice_get_device_name(storage_get_selected_slice(a->s)));
1212 	commands_execute(a, cmds);
1213 	commands_free(cmds);
1214 
1215 	/*
1216 	 * Create subpartitions and filesystems
1217 	 */
1218 	switch(use_hammer) {
1219 	case 1:
1220 		fn_create_subpartitions_hammer(FS_HAMMER, a);
1221 		break;
1222 	case 2:
1223 		fn_create_subpartitions_hammer(FS_HAMMER2, a);
1224 		break;
1225 	default:
1226 		fn_create_subpartitions_ufs(a);
1227 		break;
1228 	}
1229 
1230 	if (a->result) {
1231 		state = state_install_os;
1232 	} else {
1233 		state = disk_get_formatted(storage_get_selected_disk(a->s)) ?
1234 		    state_select_disk : state_select_slice;
1235 	}
1236 }
1237 
1238 /*
1239  * state_install_os: actually put DragonFly on the disk.
1240  */
1241 void
1242 state_install_os(struct i_fn_args *a)
1243 {
1244 	struct dfui_form *f;
1245 	struct dfui_response *r;
1246 	char msg_buf[1][1024];
1247 
1248 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
1249 	    _("Everything is now ready to install the actual files which "
1250 	    "comprise the %s operating system "
1251 	    "on the selected partition of the selected disk.\n\n"
1252 	    "Note that this process will take quite a while to finish. "
1253 	    "You may wish to take a break now and come back to the "
1254 	    "computer in a short while."),
1255 	    OPERATING_SYSTEM_NAME);
1256 
1257 	f = dfui_form_create(
1258 	    "install_os",
1259 	    _("Install OS"),
1260 	    msg_buf[0],
1261 
1262 	    "",
1263 
1264 	    "p", "role", "confirm",
1265 	    "p", "special", "dfinstaller_install_os",
1266 
1267 	    "a", "ok", _("Begin Installing Files"), "", "",
1268 	    "a", "cancel", _("Return to Create Subpartitions"), "", "",
1269 	    "p", "accelerator", "ESC",
1270 
1271 	    NULL
1272 	);
1273 
1274 	if (!dfui_be_present(a->c, f, &r))
1275 		abort_backend();
1276 
1277 	if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1278 		state = state_create_subpartitions;
1279 	} else {
1280 		fn_install_os(a);
1281 		if (a->result) {
1282 			if (use_uefi)
1283 				state = state_finish_install;
1284 			else
1285 				state = state_install_bootstrap;
1286 		}
1287 	}
1288 
1289 	dfui_form_free(f);
1290 	dfui_response_free(r);
1291 }
1292 
1293 /*
1294  * state_install_bootstrap: put boot0 bootblocks on selected disks.
1295  */
1296 void
1297 state_install_bootstrap(struct i_fn_args *a)
1298 {
1299 	char msg_buf[1][1024];
1300 
1301 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
1302 	    _("You may now wish to install bootblocks on one or more disks. "
1303 	    "If you already have a boot manager installed, you can skip "
1304 	    "this step (but you may have to configure your boot manager "
1305 	    "separately.)  If you installed %s on a disk other "
1306 	    "than your first disk, you will need to put the bootblock "
1307 	    "on at least your first disk and the %s disk."),
1308 	    OPERATING_SYSTEM_NAME, OPERATING_SYSTEM_NAME);
1309 
1310 	a->short_desc = msg_buf[0];
1311 	a->cancel_desc = _("Skip this Step");
1312 	fn_install_bootblocks(a,
1313 	    disk_get_device_name(storage_get_selected_disk(a->s)));
1314 	state = state_finish_install;
1315 }
1316 
1317 /*
1318  * Finish up the install.
1319  */
1320 void
1321 state_finish_install(struct i_fn_args *a)
1322 {
1323 	char msg_buf[1][1024];
1324 	during_install = 1;
1325 
1326 	snprintf(msg_buf[0], sizeof(msg_buf[0]),
1327 	    "%s is Installed!",
1328 	    OPERATING_SYSTEM_NAME);
1329 
1330 	switch (dfui_be_present_dialog(a->c, msg_buf[0],
1331 	    _("Configure this System|Reboot|Return to Welcome Menu"),
1332 	    _("Congratulations!\n\n"
1333 	    "%s has successfully been installed on "
1334 	    "this computer. You may now proceed to configure "
1335 	    "the installation. Alternately, you may wish to "
1336 	    "reboot the computer and boot into the installed "
1337 	    "system to confirm that it works."),
1338 	    OPERATING_SYSTEM_NAME)) {
1339 	case 1:
1340 		state = state_configure_menu;
1341 		break;
1342 	case 2:
1343 		state = state_reboot;
1344 		break;
1345 	case 3:
1346 		state = state_welcome;
1347 		break;
1348 	default:
1349 		abort_backend();
1350 	}
1351 }
1352 
1353 /*
1354  * state_reboot: reboot the machine.
1355  */
1356 void
1357 state_reboot(struct i_fn_args *a)
1358 {
1359 	struct dfui_form *f;
1360 	struct dfui_response *r;
1361 
1362 	f = dfui_form_create(
1363 	    "reboot",
1364 	    _("Reboot"),
1365 	    _("This machine is about to be shut down. "
1366 	    "After the machine has reached its shutdown state, "
1367 	    "you may remove the CD from the CD-ROM drive tray "
1368 	    "and press Enter to reboot from the HDD."),
1369 
1370 	    "",
1371 
1372 	    "p", "role", "confirm",
1373 
1374 	    "a", "ok", _("Reboot"), "", "",
1375 	    "a", "cancel", _("Return to Welcome Menu"), "", "",
1376 	    "p", "accelerator", "ESC",
1377 	    NULL
1378 	);
1379 
1380 	if (!dfui_be_present(a->c, f, &r))
1381 		abort_backend();
1382 
1383 	if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1384 		state = state_welcome;
1385 	} else {
1386 		do_reboot = 1;
1387 		state = NULL;
1388 	}
1389 
1390 	dfui_form_free(f);
1391 	dfui_response_free(r);
1392 }
1393 
1394 /*
1395  *
1396  *  state_setup_remote_installation_server:
1397  *  Setup a remote boot installation environment where a machine
1398  *  can boot via DHCP/TFTP/NFS and have a running environment
1399  *  where the installer can setup the machine.
1400  *
1401  */
1402 void
1403 state_setup_remote_installation_server(struct i_fn_args *a)
1404 {
1405         FILE *p;
1406         struct commands *cmds;
1407         struct dfui_form *f;
1408 	struct dfui_action *k;
1409         struct dfui_response *r;
1410         char *word;
1411         char interface[256];
1412         char line[256];
1413 
1414         switch (dfui_be_present_dialog(a->c, _("Enable Netboot Installation Services?"),
1415             _("Enable NetBoot Installation Services|No thanks"),
1416             _("NetBoot Installation Services allows this machine to become "
1417             "a Installation Server that will allow the clients to boot over the network "
1418 	    "via PXE and start the Installation Environment."
1419 	    "\n\n*NOTE!*  This will assign the IP Address of 10.1.0.1/24 to the selected interface."
1420             "\n\nWould you like to provision this machine to serve up the LiveCD/Installer?"))) {
1421 		case 1:
1422 			/*
1423 			 * Get interface list.
1424 			 */
1425 			p = popen("/sbin/ifconfig -l", "r");
1426 			/* XXX it's possible (though extremely unlikely) this will fail. */
1427 			while (fgets(line, 255, p) != NULL)
1428 				line[strlen(line) - 1] = '\0';
1429 			pclose(p);
1430 
1431 			f = dfui_form_create(
1432 			    "assign_ip",
1433 			    _("Setup NetBoot Installation Environment"),
1434 			    _("Please select which interface you would like to configure:"),
1435 			    "",
1436 			    "p",        "role", "menu",
1437 			    NULL
1438 			);
1439 
1440 			/* Loop through array. */
1441 			word = strtok(line, " \t");
1442 			while (word != NULL) {
1443 				dfui_form_action_add(f, word,
1444 				    dfui_info_new(word, "", ""));
1445 				word = strtok(NULL, " ");
1446 			}
1447 
1448 			k = dfui_form_action_add(f, "cancel",
1449 			    dfui_info_new("Cancel", "", ""));
1450 			dfui_action_property_set(k, "accelerator", "ESC");
1451 
1452 			if (!dfui_be_present(a->c, f, &r))
1453 				abort_backend();
1454 
1455 			strlcpy(interface, dfui_response_get_action_id(r), 256);
1456 
1457 			if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1458 				dfui_form_free(f);
1459 				dfui_response_free(r);
1460 				return;
1461 			}
1462 
1463 			/*
1464 			 *
1465 			 * Issues the necessary commands to setup the remote boot environment
1466 			 *
1467 			 */
1468 			cmds = commands_new();
1469 			command_add(cmds, "%s%s %s 10.1.0.1 netmask 255.255.255.0",
1470 			    a->os_root, cmd_name(a, "IFCONFIG"), interface);
1471 			command_add(cmds, "%s%s -p %stftpdroot",
1472 			    a->os_root, cmd_name(a, "MKDIR"), a->tmp);
1473 			command_add(cmds, "%s%s %sboot/pxeboot %stftpdroot",
1474 			    a->os_root, cmd_name(a, "CP"), a->os_root, a->tmp);
1475 			command_add(cmds, "%s%s %s -ro -alldirs -maproot=root: -network 10.1.0.0 -mask 255.255.255.0 >> %setc/exports",
1476 			    a->os_root, cmd_name(a, "ECHO"), a->os_root, a->os_root);
1477 			command_add(cmds, "%s%s tftp dgram udp wait root %s%s tftpd -l -s %stftpdroot >> %setc/inetd.conf",
1478 			    a->os_root, cmd_name(a, "ECHO"),
1479 			    a->os_root, cmd_name(a, "TFTPD"),
1480 			    a->tmp, a->os_root);
1481 			command_add(cmds, "%s%s",
1482 			    a->os_root, cmd_name(a, "INETD"));
1483 			command_add(cmds, "%s%s %svar/db/dhcpd.leases",
1484 			    a->os_root, cmd_name(a, "TOUCH"), a->os_root);
1485 			command_add(cmds, "%s%s -cf /etc/dhcpd.conf >/dev/null 2>&1",
1486 			    a->os_root, cmd_name(a, "DHCPD"));
1487 			command_add(cmds, "%s%s >/dev/null 2>&1",
1488 			    a->os_root, cmd_name(a, "RPCBIND"));
1489 			command_add(cmds, "%s%s -ln >/dev/null 2>&1",
1490 			    a->os_root, cmd_name(a, "MOUNTD"));
1491 			command_add(cmds, "%s%s -u -t -n 6 >/dev/null 2>&1",
1492 			    a->os_root, cmd_name(a, "NFSD"));
1493 
1494 			if (commands_execute(a, cmds)) {
1495 				inform(a->c, _("NetBoot installation services are now started."));
1496 			} else {
1497 				inform(a->c, _("A failure occurred while provisioning the NetBoot environment.  Please check the logs."));
1498 			}
1499 
1500 			commands_free(cmds);
1501 			dfui_form_free(f);
1502 			dfui_response_free(r);
1503 
1504 			break;
1505 		case 2:
1506 
1507 			break;
1508 
1509 	}
1510 
1511 	state = state_welcome;
1512 
1513 }
1514 
1515 /*** MAIN ***/
1516 
1517 int
1518 flow(int transport, char *rendezvous, char *os_root,
1519      int flags __unused)
1520 {
1521 	struct i_fn_args *a;
1522 
1523 	rc_conf = config_vars_new();
1524 
1525 	if ((a = i_fn_args_new(os_root, DEFAULT_INSTALLER_TEMP,
1526 			       DEFAULT_CMDNAMES_FILE, transport,
1527 			       rendezvous)) == NULL) {
1528 		return(0);
1529 	}
1530 
1531 	/*
1532 	 * XXX We can't handle this yet.
1533 	 *
1534 	   a->flags |= I_BOOTED_LIVECD;
1535 	   a->flags |= I_UPGRADE_TOOGLE;
1536 	*/
1537 	a->flags |= I_BOOTED_LIVECD;
1538 
1539 	/*
1540 	 * Execute the state machine here.  The global function pointer
1541 	 * variable `state' points to the next state_* function to execute.
1542 	 * Before it exits, this function should set `state' to the next
1543 	 * state to make a transition to, or NULL to indicate that the
1544 	 * state machine is finished.
1545 	 */
1546 #ifdef ENABLE_NLS
1547 	state = state_lang_menu;
1548 #else
1549 	state = state_welcome;
1550 #endif
1551 	for (; state != NULL; )
1552 		state(a);
1553 
1554 	config_vars_free(rc_conf);
1555 
1556 	i_fn_args_free(a);
1557 
1558 	return(do_reboot);
1559 }
1560