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