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