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