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