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