1 /*
2  * Copyright (c)2004,2015 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  * fn_configure.c
36  * Configuration functions for installer.
37  * This includes both Configure the LiveCD Environment, and
38  * Configure an Installed System (there is considerable overlap.)
39  * $Id: fn_configure.c,v 1.82 2005/03/25 05:24:00 cpressey Exp $
40  */
41 
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 
45 #include <ctype.h>
46 #include <dirent.h>
47 #include <fcntl.h>
48 #include <libgen.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <time.h>
54 #include <unistd.h>
55 
56 #ifdef ENABLE_NLS
57 #include <libintl.h>
58 #define _(String) gettext (String)
59 #else
60 #define _(String) (String)
61 #endif
62 
63 #include "libaura/mem.h"
64 #include "libaura/dict.h"
65 #include "libaura/fspred.h"
66 
67 #include "libdfui/dfui.h"
68 #include "libdfui/system.h"
69 
70 #include "libinstaller/commands.h"
71 #include "libinstaller/confed.h"
72 #include "libinstaller/diskutil.h"
73 #include "libinstaller/functions.h"
74 #include "libinstaller/uiutil.h"
75 
76 #include "fn.h"
77 #include "flow.h"
78 #include "pathnames.h"
79 
80 struct config_vars	*rc_conf;
81 
82 static const char	*yes_to_y(const char *);
83 
84 /** CONFIGURE FUNCTIONS **/
85 
86 #define	GECOS_NOT_ALLOWED	":,\\\""
87 #define	FILENAME_NOT_ALLOWED	":;`~!#$^&*()={}[]\\|?<>'\" "
88 #define	MEMBERSHIPS_NOT_ALLOWED	":;`~!@#$%^&*()+={}[]\\|/?<>'\" "
89 #define	USERNAME_NOT_ALLOWED	(MEMBERSHIPS_NOT_ALLOWED ",")
90 
91 void
92 fn_add_user(struct i_fn_args *a)
93 {
94 	struct dfui_dataset *ds, *new_ds;
95 	struct dfui_form *f;
96 	struct dfui_response *r;
97 	struct commands *cmds;
98 	struct command *cmd;
99 	const char *username, *home, *passwd_1, *passwd_2, *gecos;
100 	const char *shell, *uid, *group, *groups;
101 	const char *passwd_env = "passwd";
102 	int done = 0;
103 
104 	f = dfui_form_create(
105 	    "add_user",
106 	    _("Add user"),
107 	    _("Here you can add a user to an installed system.\n\n"
108 	    "You can leave the Home Directory, User ID, and Login Group "
109 	    "fields empty if you want these items to be automatically "
110 	    "allocated by the system."),
111 	    "",
112 	    "f", "username", _("Username"),
113 	    _("Enter the username the user will log in as"), "",
114 	    "f", "gecos", _("Real Name"),
115 	    _("Enter the real name (or GECOS field) of this user"), "",
116 	    "f", "passwd_1", _("Password"),
117 	    _("Enter the user's password (will not be displayed)"), "",
118 	    "p", "obscured", "true",
119 	    "f", "passwd_2", _("Password (Again)"),
120 	    _("Re-enter the user's password to confirm"), "",
121 	    "p", "obscured", "true",
122 	    "f", "shell", _("Shell"),
123 	    _("Enter the full path to the user's shell program"), "",
124 	    "f", "home", _("Home Directory"),
125 	    _("Enter the full path to the user's home directory, or leave blank"), "",
126 	    "f", "uid", _("User ID"),
127 	    _("Enter this account's numeric user id, or leave blank"), "",
128 	    "f", "group", _("Login Group"),
129 	    _("Enter the primary group for this account, or leave blank"), "",
130 	    "f", "groups", _("Other Group Memberships"),
131 	    _("Enter a comma-separated list of other groups "
132 	    "that this user should belong to"), "",
133 	    "a", "ok", _("Accept and Add"), "", "",
134 	    "a", "cancel", _("Return to Configure Menu"), "", "",
135 	    "p", "accelerator", "ESC",
136 	    NULL
137 	);
138 
139 	ds = dfui_dataset_new();
140 	dfui_dataset_celldata_add(ds, "username", "");
141 	dfui_dataset_celldata_add(ds, "gecos", "");
142 	dfui_dataset_celldata_add(ds, "passwd_1", "");
143 	dfui_dataset_celldata_add(ds, "passwd_2", "");
144 	dfui_dataset_celldata_add(ds, "shell", "/bin/tcsh");
145 	dfui_dataset_celldata_add(ds, "home", "");
146 	dfui_dataset_celldata_add(ds, "uid", "");
147 	dfui_dataset_celldata_add(ds, "group", "");
148 	dfui_dataset_celldata_add(ds, "groups", "");
149 	dfui_form_dataset_add(f, ds);
150 
151 	while (!done) {
152 		if (!dfui_be_present(a->c, f, &r))
153 			abort_backend();
154 
155 		if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
156 			done = 1;
157 			dfui_response_free(r);
158 			break;
159 		}
160 
161 		new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r));
162 		dfui_form_datasets_free(f);
163 		dfui_form_dataset_add(f, new_ds);
164 
165 		/* Fetch form field values. */
166 
167 		username = dfui_dataset_get_value(new_ds, "username");
168 		home = dfui_dataset_get_value(new_ds, "home");
169 		gecos = dfui_dataset_get_value(new_ds, "gecos");
170 		shell = dfui_dataset_get_value(new_ds, "shell");
171 		passwd_1 = dfui_dataset_get_value(new_ds, "passwd_1");
172 		passwd_2 = dfui_dataset_get_value(new_ds, "passwd_2");
173 		uid = dfui_dataset_get_value(new_ds, "uid");
174 		group = dfui_dataset_get_value(new_ds, "group");
175 		groups = dfui_dataset_get_value(new_ds, "groups");
176 
177 		if (strlen(username) == 0) {
178 			inform(a->c, _("You must enter a username."));
179 			done = 0;
180 		} else if (strcmp(passwd_1, passwd_2) != 0) {
181 			inform(a->c, _("The passwords do not match."));
182 			done = 0;
183 		} else if (!assert_clean(a->c, _("Username"), username, USERNAME_NOT_ALLOWED) ||
184 		    !assert_clean(a->c, _("Real Name"), gecos, GECOS_NOT_ALLOWED) ||
185 		    !assert_clean(a->c, _("Shell"), shell, FILENAME_NOT_ALLOWED) ||
186 		    !assert_clean(a->c, _("Home Directory"), home, FILENAME_NOT_ALLOWED) ||
187 		    !assert_clean(a->c, _("User ID"), uid, USERNAME_NOT_ALLOWED) ||
188 		    !assert_clean(a->c, _("Login Group"), group, USERNAME_NOT_ALLOWED) ||
189 		    !assert_clean(a->c, _("Group Memberships"), groups, MEMBERSHIPS_NOT_ALLOWED)) {
190 			done = 0;
191 		} else if (setenv(passwd_env, passwd_1, 1) != 0) {
192 			inform(a->c, _("setenv() failed."));
193 			done = 0;
194 		} else if (!is_program("%s%s", a->os_root, shell) &&
195 		    strcmp(shell, "/nonexistent") != 0) {
196 			inform(a->c, _("Chosen shell does not exist on the system."));
197 			done = 0;
198 		} else {
199 			cmds = commands_new();
200 
201 			command_add(cmds, "%s%s %smnt/ /%s useradd "
202 			    "'%s' %s%s %s%s -c \"%s\" %s%s -s %s %s%s %s",
203 			    a->os_root, cmd_name(a, "CHROOT"),
204 			    a->os_root, cmd_name(a, "PW"),
205 			    username,
206 			    strlen(uid) == 0 ? "" : "-u ", uid,
207 			    strlen(group) == 0 ? "" : "-g ", group,
208 			    gecos,
209 			    strlen(home) == 0 ? "" : "-d ", home,
210 			    shell,
211 			    strlen(groups) == 0 ? "" : "-G ", groups,
212 			    (strlen(home) == 0 || !is_dir("%s", home)) ?
213 			    "-m -k /usr/share/skel" : "");
214 
215 			cmd = command_add(cmds, "%s%s \"$%s\" | "
216 			    "%s%s %smnt/ /%s usermod '%s' -h 0",
217 			    a->os_root, cmd_name(a, "ECHO"),
218 			    passwd_env,
219 			    a->os_root, cmd_name(a, "CHROOT"),
220 			    a->os_root, cmd_name(a, "PW"),
221 			    username);
222 			command_set_desc(cmd, _("Setting password..."));
223 
224 			if (commands_execute(a, cmds)) {
225 				inform(a->c, _("User `%s' was added."), username);
226 				done = 1;
227 			} else {
228 				inform(a->c, _("User was not successfully added."));
229 				done = 0;
230 			}
231 
232 			unsetenv(passwd_env);
233 			commands_free(cmds);
234 		}
235 
236 		dfui_response_free(r);
237 	}
238 
239 	dfui_form_free(f);
240 }
241 
242 void
243 fn_root_passwd(struct i_fn_args *a)
244 {
245 	struct dfui_dataset *ds, *new_ds;
246 	struct dfui_form *f;
247 	struct dfui_response *r;
248 	struct commands *cmds;
249 	struct command *cmd;
250 	const char *root_passwd_1, *root_passwd_2;
251 	const char *passwd_env = "passwd";
252 	int done = 0;
253 
254 	f = dfui_form_create(
255 	    "root_passwd",
256 	    _("Set Root Password"),
257 	    _("Here you can set the super-user (root) password."),
258 	    "",
259 
260 	    "f", "root_passwd_1", _("Root password"),
261 	    _("Enter the root password you would like to use"), "",
262 	    "p", "obscured", "true",
263 	    "f", "root_passwd_2", _("Root password again"),
264 	    _("Enter the root password again to confirm"), "",
265 	    "p", "obscured", "true",
266 
267 	    "a", "ok", _("Accept and Set Password"), "", "",
268 	    "a", "cancel", _("Return to Configure Menu"), "", "",
269 	    "p", "accelerator", "ESC",
270 
271 	    NULL
272 	);
273 
274 	ds = dfui_dataset_new();
275 	dfui_dataset_celldata_add(ds, "root_passwd_1", "");
276 	dfui_dataset_celldata_add(ds, "root_passwd_2", "");
277 	dfui_form_dataset_add(f, ds);
278 
279 	while (!done) {
280 		if (!dfui_be_present(a->c, f, &r))
281 			abort_backend();
282 
283 		if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
284 			done = 1;
285 			dfui_response_free(r);
286 			break;
287 		}
288 
289 		new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r));
290 		dfui_form_datasets_free(f);
291 		dfui_form_dataset_add(f, new_ds);
292 
293 		root_passwd_1 = dfui_dataset_get_value(new_ds, "root_passwd_1");
294 		root_passwd_2 = dfui_dataset_get_value(new_ds, "root_passwd_2");
295 
296 		if (strlen(root_passwd_1) == 0) {
297 			inform(a->c, _("You must enter a password."));
298 			done = 0;
299 		} else if (strcmp(root_passwd_1, root_passwd_2) != 0) {
300 			inform(a->c, _("The passwords do not match."));
301 			done = 0;
302 		} else if (setenv(passwd_env, root_passwd_1, 1) != 0) {
303 			inform(a->c, _("setenv() failed."));
304 			done = 0;
305 		} else {
306 			cmds = commands_new();
307 			cmd = command_add(cmds, "%s%s \"$%s\" | "
308 			    "%s%s %smnt/ /%s usermod root -h 0",
309 			    a->os_root, cmd_name(a, "ECHO"),
310 			    passwd_env,
311 			    a->os_root, cmd_name(a, "CHROOT"),
312 			    a->os_root, cmd_name(a, "PW"));
313 			command_set_desc(cmd, _("Setting password..."));
314 			if (commands_execute(a, cmds)) {
315 				inform(a->c, _("The root password has been changed."));
316 				done = 1;
317 			} else {
318 				inform(a->c, _("An error occurred when "
319 				    "setting the root password."));
320 				done = 0;
321 			}
322 			unsetenv(passwd_env);
323 			commands_free(cmds);
324 		}
325 
326 		dfui_response_free(r);
327 	}
328 
329 	dfui_form_free(f);
330 }
331 
332 void
333 fn_get_passphrase(struct i_fn_args *a)
334 {
335 	struct dfui_dataset *ds, *new_ds;
336 	struct dfui_form *f;
337 	struct dfui_response *r;
338 	const char *passphrase_1, *passphrase_2;
339 	int fd;
340 	int done = 0;
341 
342 	f = dfui_form_create(
343 	    "crypt_passphrase",
344 	    _("Set Passphrase For Encryption"),
345 	    _("Please specify the passphrase to be used for the encrypted "
346 	    "filesystems.\n\n"
347 	    "Please note that in the LiveCD environment the keymap is set to "
348 	    "\"US ISO\". "
349 	    "If you prefer a different keymap for entering the passphrase "
350 	    "here, you will need to set it manually using kbdcontrol(1)."),
351 	    "",
352 
353 	    "f", "passphrase_1", _("Passphrase"),
354 	    _("Enter the passphrase you would like to use for encryption"), "",
355 	    "p", "obscured", "true",
356 	    "f", "passphrase_2", _("Passphrase again"),
357 	    _("Enter the passphrase again to confirm"), "",
358 	    "p", "obscured", "true",
359 
360 	    "a", "ok", _("Accept and Set Passphrase"), "", "",
361 	    "p", "accelerator", "ESC",
362 
363 	    NULL
364 	);
365 
366 	ds = dfui_dataset_new();
367 	dfui_dataset_celldata_add(ds, "passphrase_1", "");
368 	dfui_dataset_celldata_add(ds, "passphrase_2", "");
369 	dfui_form_dataset_add(f, ds);
370 
371 	while (!done) {
372 		if (!dfui_be_present(a->c, f, &r))
373 			abort_backend();
374 
375 		if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
376 			new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r));
377 			dfui_form_datasets_free(f);
378 			dfui_form_dataset_add(f, new_ds);
379 
380 			/*
381 			 * Fetch form field values.
382 			 */
383 
384 			passphrase_1 = dfui_dataset_get_value(new_ds, "passphrase_1");
385 			passphrase_2 = dfui_dataset_get_value(new_ds, "passphrase_2");
386 
387 			if (strlen(passphrase_1) == 0 && strlen(passphrase_2) == 0) {
388 				done = 0;
389 			} else if (strcmp(passphrase_1, passphrase_2) == 0) {
390 				/*
391 				 * Passphrases match, write it out.
392 				 */
393 				fd = open("/tmp/t1", O_RDWR | O_CREAT | O_TRUNC,
394 				    S_IRUSR);
395 				if (fd != -1) {
396 					write(fd, passphrase_1, strlen(passphrase_1));
397 					close(fd);
398 					done = 1;
399 				} else {
400 					inform(a->c, _("write() error"));
401 					done = 0;
402 				}
403 			} else {
404 				/*
405 				 * Passphrases don't match, tell the user,
406 				 * let them try again.
407 				 */
408 				inform(a->c, _("The passphrases do not match."));
409 				done = 0;
410 			}
411 		}
412 
413 		dfui_response_free(r);
414 	}
415 
416 	dfui_form_free(f);
417 }
418 
419 /** LIVECD UTILITIES FUNCTIONS **/
420 
421 /*
422  * String returned by this function must be deallocated by the caller.
423  */
424 char *
425 fn_select_file(const char *title, const char *desc, const char *help, const char *cancel,
426 	       const char *dir, const char *ext, const struct i_fn_args *a)
427 {
428 	DIR *d;
429 	struct dfui_form *f;
430 	struct dfui_action *k;
431 	struct dfui_response *r;
432 	struct dirent *de;
433 	char *s;
434 	struct aura_dict *dict;
435 	char *rk;
436 	size_t rk_len;
437 
438 	f = dfui_form_create(
439 	    "select_file",
440 	    title, desc, help,
441 	    "p", "role", "menu",
442 	    NULL
443 	);
444 
445 	dict = aura_dict_new(1, AURA_DICT_SORTED_LIST);
446 	d = opendir(dir);
447 	while ((de = readdir(d)) != NULL) {
448 		if (strcmp(de->d_name, ".") == 0 ||
449 		    strcmp(de->d_name, "..") == 0 ||
450 		    strstr(de->d_name, ext) == NULL)
451 			continue;
452 		aura_dict_store(dict, de->d_name, strlen(de->d_name) + 1, "", 1);
453 	}
454 	closedir(d);
455 
456 	aura_dict_rewind(dict);
457 	while (!aura_dict_eof(dict)) {
458 		aura_dict_get_current_key(dict, (void **)&rk, &rk_len),
459 		dfui_form_action_add(f, rk,
460 		    dfui_info_new(rk, "", ""));
461 		aura_dict_next(dict);
462 	}
463 	aura_dict_free(dict);
464 
465 	k = dfui_form_action_add(f, "cancel",
466 	    dfui_info_new(cancel, "", ""));
467 	dfui_action_property_set(k, "accelerator", "ESC");
468 
469 	if (!dfui_be_present(a->c, f, &r))
470 		abort_backend();
471 
472 	s = aura_strdup(dfui_response_get_action_id(r));
473 
474 	dfui_form_free(f);
475 	dfui_response_free(r);
476 
477 	return(s);
478 }
479 
480 void
481 fn_set_kbdmap(struct i_fn_args *a)
482 {
483 	struct commands *cmds;
484 	char *s;
485 	char filename[256], keymapname[256];
486 
487 	s = fn_select_file(_("Select Keyboard Map"),
488 	    _("Select a keyboard map appropriate to your keyboard layout."),
489 	    "", _("Return to Utilities Menu"), "/usr/share/syscons/keymaps",
490 	    ".kbd", a);
491 
492 	if (strcmp(s, "cancel") != 0) {
493 		cmds = commands_new();
494 		command_add(cmds, "%s%s -l "
495 		    "/usr/share/syscons/keymaps/%s < /dev/ttyv0",
496 		    a->os_root, cmd_name(a, "KBDCONTROL"),
497 		    s);
498 		if (commands_execute(a, cmds)) {
499 			snprintf(filename, 256, "/usr/share/syscons/keymaps/%s", s);
500 			snprintf(keymapname, 256, "%s", filename_noext(basename(filename)));
501 			config_var_set(rc_conf, "keymap", keymapname);
502 		} else {
503 			inform(a->c, _("Keyboard map not successfully set."));
504 		}
505 		commands_free(cmds);
506 	}
507 
508 	free(s);
509 }
510 
511 void
512 fn_set_vidfont(struct i_fn_args *a)
513 {
514 	struct commands *cmds;
515 	char *s;
516 	char filename[256], variable[256], fontname[256];
517 	int by = 0;
518 
519 
520 	s = fn_select_file(_("Select Console Font"),
521 	    _("Select a font appropriate to your video monitor and language."),
522 	    "", _("Return to Utilities Menu"), "/usr/share/syscons/fonts",
523 	    ".fnt", a);
524 
525 	if (strcmp(s, "cancel") != 0) {
526 		cmds = commands_new();
527 		command_add(cmds, "%s%s -f "
528 		    "/usr/share/syscons/fonts/%s < /dev/ttyv0",
529 		    a->os_root, cmd_name(a, "VIDCONTROL"),
530 		    s);
531 		if (commands_execute(a, cmds)) {
532 			if (strstr(s, "8x16") != NULL)
533 				by = 16;
534 			else if (strstr(s, "8x14") != NULL)
535 				by = 14;
536 			else
537 				by = 8;
538 
539 			snprintf(variable, 256, "font8x%d", by);
540 			snprintf(filename, 256, "/usr/share/syscons/fonts/%s", s);
541 			snprintf(fontname, 256, "%s", filename_noext(basename(filename)));
542 			config_var_set(rc_conf, variable, fontname);
543 
544 		} else {
545 			inform(a->c, _("Video font not successfully set."));
546 		}
547 		commands_free(cmds);
548 	}
549 
550 	free(s);
551 }
552 
553 void
554 fn_set_scrnmap(struct i_fn_args *a)
555 {
556 	struct commands *cmds;
557 	char *s;
558 	char filename[256], scrnmapname[256];
559 
560 	s = fn_select_file(_("Select Screen Map"),
561 	    _("Select a mapping for translating characters as they appear "
562 	    "on your video console screen."),
563 	    "", _("Return to Utilities Menu"), "/usr/share/syscons/scrnmaps",
564 	    ".scm", a);
565 
566 	if (strcmp(s, "cancel") != 0) {
567 		cmds = commands_new();
568 		command_add(cmds, "%s%s -l "
569 		    "/usr/share/syscons/scrnmaps/%s < /dev/ttyv0",
570 		    a->os_root, cmd_name(a, "VIDCONTROL"),
571 		    s);
572 		if (commands_execute(a, cmds)) {
573 			snprintf(filename, 256, "/usr/share/syscons/scrnmaps/%s", s);
574 			snprintf(scrnmapname, 256, "%s", filename_noext(basename(filename)));
575 			config_var_set(rc_conf, "scrnmap", scrnmapname);
576 		} else {
577 			inform(a->c, _("Video font not successfully set."));
578 		}
579 		commands_free(cmds);
580 	}
581 	free(s);
582 }
583 
584 void
585 fn_set_timezone(struct i_fn_args *a)
586 {
587 	struct commands *cmds;
588 	char *s = NULL;
589 	char current_path[256], selection[256], temp[256];
590 	int found_file = 0;
591 	int result;
592 
593 	result = dfui_be_present_dialog(a->c, _("Local or UTC (Greenwich Mean Time) clock"),
594 	    _("Yes|No"),
595             _("Is this machine's CMOS clock set to UTC?\n\n"
596 	    "If it is set to local time, or you don't know, please choose NO here!"));
597 	if (result < 1)
598 		abort_backend();
599 
600 	cmds = commands_new();
601 	switch (result) {
602 		case 1:
603 			command_add(cmds, "%s%s -f %s%setc/wall_cmos_clock",
604 			    a->os_root, cmd_name(a, "RM"),
605 			    a->os_root, a->cfg_root);
606 			break;
607 		case 2:
608 			command_add(cmds, "%s%s %s%setc/wall_cmos_clock",
609 			    a->os_root, cmd_name(a, "TOUCH"),
610 			    a->os_root, a->cfg_root);
611 			break;
612 	}
613 	commands_execute(a, cmds);
614 
615 	snprintf(current_path, 256, "%s%susr/share/zoneinfo",
616 	    a->os_root, a->cfg_root);
617 	while (!found_file) {
618 		if (s != NULL)
619 			free(s);
620 		s = fn_select_file(_("Select Time Zone"),
621 		    _("Select a Time Zone appropriate to your physical location."),
622 		    "", _("Return to Utilities Menu"), current_path,
623 		    "", a);
624 		if (is_dir("%s/%s", current_path, s)) {
625 			snprintf(temp, 256, "%s/%s", current_path, s);
626 			strlcpy(current_path, temp, 256);
627 		} else {
628 			if (is_file("%s/%s", current_path, s)) {
629 				snprintf(selection, 256, "%s/%s", current_path, s);
630 				found_file = 1;
631 			}
632 			if (strcmp(s, "cancel") == 0) {
633 				strlcpy(selection, "cancel", 256);
634 				found_file = 1;
635 			}
636 		}
637 	}
638 	free(s);
639 
640 	if (strcmp(selection, "cancel") != 0) {
641 		command_add(cmds, "%s%s %s %s%setc/localtime",
642 		    a->os_root, cmd_name(a, "CP"),
643 		    selection,
644 		    a->os_root, a->cfg_root);
645 		if (commands_execute(a, cmds)) {
646 			inform(a->c, _("The Time Zone has been set to %s."), selection);
647 			setenv("TZ", selection, 1);
648 			tzset();
649 		}
650 	}
651 	commands_free(cmds);
652 }
653 
654 void
655 fn_assign_datetime(struct i_fn_args *a)
656 {
657 	struct commands *cmds;
658 	struct dfui_dataset *ds, *new_ds;
659 	struct dfui_form *f;
660 	struct dfui_response *r;
661 	struct tm *tp;
662 	char temp[256];
663 	int year, month, dayofmonth, hour, minutes;
664 	int valid = 1;
665 	time_t now;
666 
667 	now = time(NULL);
668 	tp = localtime(&now);
669 
670 	f = dfui_form_create(
671 	    "set_datetime",
672 	    _("Set Time/Date"),
673 	    _("Enter the date-time in your timezone."),
674 	    "",
675 
676 	    "f", "year", _("Enter year"),
677 	    _("Enter the current year (e.g. `2004')"), "",
678 	    "f", "month", _("Month"),
679 	    _("Enter the current month (e.g. `07')"), "",
680 	    "f", "dayofmonth", "dayofmonth",
681 	    _("Enter the current day of month (e.g. `30')"), "",
682 	    "f", "hour", "hour",
683 	    _("Enter the current hour (e.g. `07')"), "",
684 	    "f", "minutes", "minutes",
685 	    _("Enter the current minutes (e.g. `59')"), "",
686 
687 	    "a", "ok", _("OK"), "", "",
688 	    "a", "cancel", _("Cancel"), "", "",
689 	    "p", "accelerator", "ESC",
690 
691 	    NULL
692 	);
693 
694 	ds = dfui_dataset_new();
695 	snprintf(temp, 256, "%i", (tp->tm_year+1900));
696 	dfui_dataset_celldata_add(ds, "year", temp);
697 	snprintf(temp, 256, "%i", (tp->tm_mon+1));
698 	dfui_dataset_celldata_add(ds, "month", temp);
699 	snprintf(temp, 256, "%i", tp->tm_mday);
700 	dfui_dataset_celldata_add(ds, "dayofmonth", temp);
701 	snprintf(temp, 256, "%i", tp->tm_hour);
702 	dfui_dataset_celldata_add(ds, "hour", temp);
703 	snprintf(temp, 256, "%i", tp->tm_min);
704 	dfui_dataset_celldata_add(ds, "minutes", temp);
705 	dfui_form_dataset_add(f, ds);
706 
707 	if (!dfui_be_present(a->c, f, &r))
708 		abort_backend();
709 
710 	if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
711 		new_ds = dfui_response_dataset_get_first(r);
712 
713 		if ((year = atoi(dfui_dataset_get_value(new_ds, "year"))) <= 0)
714 			valid = 0;
715 		month = atoi(dfui_dataset_get_value(new_ds, "month"));
716 		if (month < 1 || month > 12)
717 			valid = 0;
718 		dayofmonth = atoi(dfui_dataset_get_value(new_ds, "dayofmonth"));
719 		if (dayofmonth < 1 || dayofmonth > 31)
720 			valid = 0;
721 		hour = atoi(dfui_dataset_get_value(new_ds, "hour"));
722 		if (hour < 0 || hour > 23)
723 			valid = 0;
724 		minutes = atoi(dfui_dataset_get_value(new_ds, "minutes"));
725 		if (minutes < 0 || minutes > 59)
726 			valid = 0;
727 
728 		if (valid) {
729 			cmds = commands_new();
730 			command_add(cmds, "%s%s -n %04d%02d%02d%02d%02d",
731 			    a->os_root, cmd_name(a, "DATE"),
732 			    year, month, dayofmonth, hour, minutes);
733 			if (commands_execute(a, cmds)) {
734 				inform(a->c, _("The date and time have been set."));
735 			}
736 			commands_free(cmds);
737 		} else {
738 			inform(a->c, _("Please enter numbers within acceptable ranges "
739 				"for year, month, day of month, hour, and minute."));
740 		}
741 	}
742 }
743 
744 void
745 fn_assign_hostname_domain(struct i_fn_args *a)
746 {
747 	struct dfui_form *f;
748 	struct dfui_response *r;
749 	struct dfui_dataset *ds, *new_ds;
750 	struct config_vars *resolv_conf;
751 	const char *domain, *hostname;
752 	char *fqdn;
753 
754 	f = dfui_form_create(
755 	    "set_hostname_domain",
756 	    _("Set Hostname/Domain"),
757 	    _("Please enter this machine's hostname and domain name."),
758 	    "",
759 
760 	    "f", "hostname", _("Hostname"),
761 	    _("Enter the Hostname (e.g. `machine')"), "",
762 	    "f", "domain", _("Domain"),
763 	    _("Enter the Domain Name (e.g. `network.lan')"), "",
764 
765 	    "a", "ok", _("OK"), "", "",
766 	    "a", "cancel", _("Cancel"), "", "",
767 	    "p", "accelerator", "ESC",
768 
769 	    NULL
770 	);
771 
772 	ds = dfui_dataset_new();
773 	dfui_dataset_celldata_add(ds, "hostname", "");
774 	dfui_dataset_celldata_add(ds, "domain", "");
775 	dfui_form_dataset_add(f, ds);
776 
777 	if (!dfui_be_present(a->c, f, &r))
778 		abort_backend();
779 
780 	if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
781 		new_ds = dfui_response_dataset_get_first(r);
782 
783 		hostname = dfui_dataset_get_value(new_ds, "hostname");
784 		domain = dfui_dataset_get_value(new_ds, "domain");
785 		if (strlen(domain) == 0)
786 			asprintf(&fqdn, "%s", hostname);
787 		else
788 			asprintf(&fqdn, "%s.%s", hostname, domain);
789 
790 		resolv_conf = config_vars_new();
791 
792 		config_var_set(rc_conf, "hostname", fqdn);
793 		config_var_set(resolv_conf, "search", domain);
794 		config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
795 		    "%s%setc/resolv.conf", a->os_root, a->cfg_root);
796 
797 		config_vars_free(resolv_conf);
798 
799 		free(fqdn);
800 	}
801 
802 	dfui_form_free(f);
803 	dfui_response_free(r);
804 }
805 
806 void
807 fn_assign_ip(struct i_fn_args *a)
808 {
809 	FILE *p;
810 	struct commands *cmds;
811 	struct command *cmd;
812 	struct config_vars *resolv_conf;
813 	struct dfui_dataset *ds, *new_ds;
814 	struct dfui_form *f;
815 	struct dfui_action *k;
816 	struct dfui_response *r;
817 	const char *domain, *hostname;
818 	const char *interface_ip, *interface_netmask, *defaultrouter, *dns_resolver;
819 	char *string, *string1;
820 	char *word;
821 	char interface[256];
822 	char line[256];
823 	int write_config = 0;
824 
825 	/*
826 	 * Get interface list.
827 	 */
828 	p = popen("/sbin/ifconfig -l", "r");
829 	/* XXX it's possible (though extremely unlikely) this will fail. */
830 	while (fgets(line, 255, p) != NULL)
831 		line[strlen(line) - 1] = '\0';
832 
833 	pclose(p);
834 
835 	f = dfui_form_create(
836 	    "assign_ip",
837 	    _("Assign IP Address"),
838 	    _("Please select which interface you would like to configure:"),
839 	    "",
840 	    "p",	"role", "menu",
841 	    NULL
842 	);
843 
844 	/* Loop through array. */
845 	word = strtok(line, " \t");
846 	while (word != NULL) {
847 		dfui_form_action_add(f, word,
848 		    dfui_info_new(word, "", ""));
849 		word = strtok(NULL, " ");
850 	}
851 
852 	k = dfui_form_action_add(f, "cancel",
853 	    dfui_info_new("Cancel", "", ""));
854 	dfui_action_property_set(k, "accelerator", "ESC");
855 
856 	if (!dfui_be_present(a->c, f, &r))
857 		abort_backend();
858 
859 	if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
860 		dfui_form_free(f);
861 		dfui_response_free(r);
862 		return;
863 	}
864 
865 	strlcpy(interface, dfui_response_get_action_id(r), 256);
866 
867 	resolv_conf = config_vars_new();
868 
869 	switch (dfui_be_present_dialog(a->c, _("Use DHCP?"),
870 	    _("Use DHCP|Configure Manually"),
871 	    _("DHCP allows the interface to automatically obtain "
872 	    "an IP address from a nearby DHCP server.\n\n"
873 	    "Would you like to enable DHCP for %s?"), interface)) {
874 	case 1:
875 		asprintf(&string, "ifconfig_%s", interface);
876 
877 		cmds = commands_new();
878 		cmd = command_add(cmds, "%s%s dhclient",
879 		    a->os_root, cmd_name(a, "KILLALL"));
880 		command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
881 		command_add(cmds, "%s%s %s",
882 		    a->os_root, cmd_name(a, "DHCLIENT"),
883 		    interface);
884 		if (commands_execute(a, cmds)) {
885 			/* XXX sleep(3); */
886 			show_ifconfig(a->c, interface);
887 			write_config = 1;
888 		} else {
889 			switch (dfui_be_present_dialog(a->c, _("DHCP Failure"),
890 			    _("Yes|No"),
891 			    _("Warning: could not enable dhclient for %s.\n\n"
892 			      "Write the corresponding settings to rc.conf "
893 			      "anyway?"), interface)) {
894 			case 1:
895 				write_config = 1;
896 				break;
897 			case 2:
898 				write_config = 0;
899 				break;
900 			default:
901 				abort_backend();
902 			}
903 		}
904 		commands_free(cmds);
905 		config_var_set(rc_conf, string, "DHCP");
906 		free(string);
907 		break;
908 	case 2:
909 		dfui_form_free(f);
910 		dfui_response_free(r);
911 		f = dfui_form_create(
912 		    "assign_ip",
913 		    _("Assign IP Address"),
914 		    _("Configuring Interface:"),
915 		    "",
916 
917 		    "f", "interface_ip", _("IP Address"),
918 		    _("Enter the IP Address you would like to use"), "",
919 		    "f", "interface_netmask",	_("Netmask"),
920 		    _("Enter the netmask of the IP address"), "",
921 		    "f", "defaultrouter", _("Default Router"),
922 		    _("Enter the IP address of the default router"), "",
923 		    "f", "dns_resolver", _("Primary DNS Server"),
924 		    _("Enter the IP address of primary DNS Server"), "",
925 		    "f", "hostname", _("Hostname"),
926 		    _("Enter the Hostname"), "",
927 		    "f", "domain", _("Domain"),
928 		    _("Enter the Domain Name"), "",
929 
930 		    "a", "ok", _("Configure Interface"),
931 		    "", "",
932 		    "a", "cancel", _("Return to Utilities Menu"),
933 		    "", "",
934 		    "p", "accelerator", "ESC",
935 
936 		    NULL
937 		);
938 
939 		ds = dfui_dataset_new();
940 		dfui_dataset_celldata_add(ds, "interface_netmask", "");
941 		dfui_dataset_celldata_add(ds, "defaultrouter", "");
942 		dfui_dataset_celldata_add(ds, "dns_resolver", "");
943 		dfui_dataset_celldata_add(ds, "hostname", "");
944 		dfui_dataset_celldata_add(ds, "domain", "");
945 		dfui_dataset_celldata_add(ds, "interface_ip", "");
946 		dfui_form_dataset_add(f, ds);
947 
948 		if (!dfui_be_present(a->c, f, &r))
949 			abort_backend();
950 
951 		if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
952 			new_ds = dfui_response_dataset_get_first(r);
953 
954 			interface_ip = dfui_dataset_get_value(
955 						new_ds, "interface_ip");
956 			interface_netmask = dfui_dataset_get_value(
957 						new_ds, "interface_netmask");
958 			defaultrouter = dfui_dataset_get_value(
959 						new_ds, "defaultrouter");
960 			dns_resolver = dfui_dataset_get_value(
961 						new_ds, "dns_resolver");
962 			hostname = dfui_dataset_get_value(
963 						new_ds, "hostname");
964 			domain = dfui_dataset_get_value(
965 						new_ds, "domain");
966 
967 			asprintf(&string, "ifconfig_%s", interface);
968 			asprintf(&string1, "inet %s netmask %s",
969 			    interface_ip, interface_netmask);
970 
971 			cmds = commands_new();
972 			command_add(cmds, "%s%s %s %s netmask %s",
973 			    a->os_root, cmd_name(a, "IFCONFIG"),
974 			    interface, interface_ip, interface_netmask);
975 			command_add(cmds, "%s%s add default %s",
976 			    a->os_root, cmd_name(a, "ROUTE"),
977 			    defaultrouter);
978 
979 			if (commands_execute(a, cmds)) {
980 				/* XXX sleep(3); */
981 				show_ifconfig(a->c, interface);
982 				write_config = 1;
983 			} else {
984 				switch (dfui_be_present_dialog(a->c,
985 				    _("ifconfig Failure"),
986 				    _("Yes|No"),
987 				    _("Warning: could not assign IP address "
988 				      "or default gateway.\n\n"
989 				      "Write the corresponding settings to "
990 				      "rc.conf anyway?"))) {
991 				case 1:
992 					write_config = 1;
993 					break;
994 				case 2:
995 					write_config = 0;
996 					break;
997 				default:
998 					abort_backend();
999 				}
1000 			}
1001 			commands_free(cmds);
1002 
1003 			config_var_set(rc_conf, string, string1);
1004 			config_var_set(rc_conf, "defaultrouter", defaultrouter);
1005 
1006 			free(string);
1007 			free(string1);
1008 
1009 			asprintf(&string, "%s.%s", hostname, domain);
1010 			config_var_set(rc_conf, "hostname", string);
1011 			free(string);
1012 
1013 			config_var_set(resolv_conf, "search", domain);
1014 			config_var_set(resolv_conf, "nameserver", dns_resolver);
1015 		}
1016 		break;
1017 	default:
1018 		abort_backend();
1019 	}
1020 
1021 	if (write_config) {
1022 		/*
1023 		 * Save out changes to /etc/rc.conf and /etc/resolv.conf.
1024 		 */
1025 		config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
1026 		    "%s%setc/resolv.conf", a->os_root, a->cfg_root);
1027 	}
1028 
1029 	config_vars_free(resolv_conf);
1030 
1031 	dfui_form_free(f);
1032 	dfui_response_free(r);
1033 }
1034 
1035 static const char *
1036 yes_to_y(const char *value)
1037 {
1038 	return(strcasecmp(value, "YES") == 0 ? "Y" : "N");
1039 }
1040 
1041 void
1042 fn_select_services(struct i_fn_args *a)
1043 {
1044 	struct dfui_dataset *ds;
1045 	struct dfui_form *f;
1046 	struct dfui_response *r;
1047 
1048 	if (!config_vars_read(a, rc_conf, CONFIG_TYPE_SH, "%s%setc/rc.conf",
1049 		a->os_root, a->cfg_root)) {
1050 		inform(a->c, _("Couldn't read %s%setc/rc.conf."),
1051 		    a->os_root, a->cfg_root);
1052 		a->result = 0;
1053 		return;
1054 	}
1055 
1056 	f = dfui_form_create(
1057 	    "select_services",
1058 	    _("Select Services"),
1059 	    _("Please select which services you would like "
1060 	      "started at boot time."),
1061 	    "",
1062 
1063 	    "f", "syslogd", "syslogd",
1064 		_("System Logging Daemon"), "",
1065 		"p", "control", "checkbox",
1066 	    "f", "inetd", "inetd",
1067 		_("Internet Super-Server"), "",
1068 		"p", "control", "checkbox",
1069 	    "f", "named", "named",
1070 		_("BIND Name Server"), "",
1071 		"p", "control", "checkbox",
1072 	    "f", "ntpd", "ntpd",
1073 		_("Network Time Protocol Daemon"), "",
1074 		"p", "control", "checkbox",
1075 	    "f", "sshd", "sshd",
1076 		_("Secure Shell Daemon"), "",
1077 		"p", "control", "checkbox",
1078 
1079 	    "a", "ok", _("Enable/Disable Services"),
1080 	        "", "",
1081 	    "a", "cancel", _("Return to Utilities Menu"),
1082 		"", "",
1083 	        "p", "accelerator", "ESC",
1084 
1085 	    NULL
1086 	);
1087 
1088 	ds = dfui_dataset_new();
1089 	dfui_dataset_celldata_add(ds, "syslogd",
1090 	    yes_to_y(config_var_get(rc_conf, "syslogd_enable")));
1091 	dfui_dataset_celldata_add(ds, "inetd",
1092 	    yes_to_y(config_var_get(rc_conf, "inetd_enable")));
1093 	dfui_dataset_celldata_add(ds, "named",
1094 	    yes_to_y(config_var_get(rc_conf, "named_enable")));
1095 	dfui_dataset_celldata_add(ds, "ntpd",
1096 	    yes_to_y(config_var_get(rc_conf, "ntpd_enable")));
1097 	dfui_dataset_celldata_add(ds, "sshd",
1098 	    yes_to_y(config_var_get(rc_conf, "sshd_enable")));
1099 	dfui_form_dataset_add(f, ds);
1100 
1101 	if (!dfui_be_present(a->c, f, &r))
1102 		abort_backend();
1103 
1104 	if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1105 		dfui_form_free(f);
1106 		dfui_response_free(r);
1107 		return;
1108 	}
1109 
1110 	dfui_form_free(f);
1111 	dfui_response_free(r);
1112 }
1113 
1114 /*** NON-fn_ FUNCTIONS ***/
1115 
1116 /*
1117  * Uses ss->selected_{disk,slice} as the target system.
1118  *
1119  * XXX We now assume that the root mount has enough of the topology
1120  *     to handle any configuration actions.
1121  */
1122 int
1123 mount_target_system(struct i_fn_args *a)
1124 {
1125 	FILE *crypttab, *fstab;
1126 	struct commands *cmds;
1127 	struct command *cmd;
1128 	struct subpartition *a_subpart;
1129 	struct subpartition *d_subpart;
1130 	char name[256], device[256];
1131 	char *filename, line[256];
1132 	char *word;
1133 
1134 	/*
1135 	 * Mount subpartitions from this installation if they are
1136 	 * not already mounted.  Tricky, as we need to honour the
1137 	 * installation's loader.conf and fstab.
1138 	 */
1139 	cmds = commands_new();
1140 
1141 	/*
1142 	 * First, unmount anything already mounted on /mnt.
1143 	 */
1144 	unmount_all_under(a, cmds, "%smnt", a->os_root);
1145 
1146 	/*
1147 	 * Reset and clear out subpartitions so that system
1148 	 * can make a "dummy" subpart.
1149 	 */
1150 	subpartitions_free(storage_get_selected_slice(a->s));
1151 
1152 	/*
1153 	 * Create a temporary dummy subpartition - that we
1154 	 * assume exists
1155 	 */
1156 	a_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s),
1157 					 "/dummy", 0, 0, 0, 0, 0, 0);
1158 	subpartition_new_ufs(storage_get_selected_slice(a->s),
1159 					 "swap", 0, 0, 0, 0, 0, 0);
1160 	d_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s),
1161 					 "/dummy", 0, 0, 0, 0, 0, 0);
1162 
1163 	/*
1164 	 * Mount the target's / and read its /etc/fstab.
1165 	 *
1166 	 * XXX NEEDS TO BE REWRITTEN XXX
1167 	 */
1168 	{
1169 		command_add(cmds, "%s%s /dev/%s %sboot",
1170 		    a->os_root, cmd_name(a, "MOUNT"),
1171 		    subpartition_get_device_name(a_subpart),
1172 		    a->os_root);
1173 		cmd = command_add(cmds,
1174 		    "%s%s -f %st2;"
1175 		    "%s%s \"^vfs\\.root\\.realroot=\" %sboot/loader.conf >%st2",
1176 		    a->os_root, cmd_name(a, "RM"), a->tmp,
1177 		    a->os_root, cmd_name(a, "GREP"),
1178 		    a->os_root, a->tmp);
1179 		command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
1180 	}
1181 	if (!commands_execute(a, cmds)) {
1182 		commands_free(cmds);
1183 		return(0);
1184 	}
1185 	commands_free(cmds);
1186 	cmds = commands_new();
1187 
1188 	/*
1189 	 * XXX NEEDS TO BE REWRITTEN XXX
1190 	 */
1191 	{
1192 		struct stat sb = { .st_size = 0 };
1193 		const char *fsname;
1194 		const char *mountid;
1195 
1196 		switch (use_hammer) {
1197 		case 1:
1198 			fsname = "hammer";
1199 			mountid = "MOUNT_HAMMER";
1200 			break;
1201 		case 2:
1202 			fsname = "hammer2";
1203 			mountid = "MOUNT_HAMMER2";
1204 			break;
1205 		case 0:
1206 		default:
1207 			fsname = "ufs";
1208 			mountid = "MOUNT";
1209 			break;
1210 		}
1211 
1212 		stat("/tmp/t2", &sb);
1213 		if (sb.st_size > 0) {
1214 			command_add(cmds, "%s%s %sboot",
1215 			    a->os_root, cmd_name(a, "UMOUNT"),
1216 			    a->os_root);
1217 			fn_get_passphrase(a);
1218 			command_add(cmds,
1219 			    "%s%s -d /tmp/t1 luksOpen /dev/`%s%s \"^vfs\\.root\\.realroot=\" %st2 |"
1220 			    "%s%s -F%s: '{print $2;}' |"
1221 			    "%s%s -F: '{print $1;}'` %s",
1222 			    a->os_root, cmd_name(a, "CRYPTSETUP"),
1223 			    a->os_root, cmd_name(a, "GREP"),
1224 			    a->tmp,
1225 			    a->os_root, cmd_name(a, "AWK"),
1226 			    fsname,
1227 			    a->os_root, cmd_name(a, "AWK"),
1228 			    subpartition_get_mapper_name(d_subpart, -1));
1229 			command_add(cmds,
1230 			    "%s%s %s %s%s",
1231 			    a->os_root,
1232 			    cmd_name(a, mountid),
1233 			    subpartition_get_mapper_name(d_subpart, 1),
1234 			    a->os_root, a->cfg_root);
1235 		} else {
1236 			command_add(cmds,
1237 			    "%s%s /dev/`%s%s \"^vfs\\.root\\.mountfrom\" %sboot/loader.conf |"
1238 			    "%s%s -F%s: '{print $2;}' |"
1239 			    "%s%s 's/\"//'` %s%s",
1240 			    a->os_root,
1241 			    cmd_name(a, mountid),
1242 			    a->os_root, cmd_name(a, "GREP"),
1243 			    a->os_root,
1244 			    a->os_root, cmd_name(a, "AWK"),
1245 			    fsname,
1246 			    a->os_root, cmd_name(a, "SED"),
1247 			    a->os_root, a->cfg_root);
1248 			command_add(cmds, "%s%s %sboot",
1249 			    a->os_root, cmd_name(a, "UMOUNT"),
1250 			    a->os_root);
1251 		}
1252 	}
1253 	if (!commands_execute(a, cmds)) {
1254 		commands_free(cmds);
1255 		return(0);
1256 	}
1257 	commands_free(cmds);
1258 	cmds = commands_new();
1259 
1260 	/*
1261 	 * Get rid of the dummy subpartition.
1262 	 */
1263 	subpartitions_free(storage_get_selected_slice(a->s));
1264 
1265 	/*
1266 	 * See if an /etc/crypttab exists.
1267 	 *
1268 	 * Scan and open the related mappings (currently not used since
1269 	 * we removed the additional mounts from the fstab scan, but we
1270 	 * might put those back in at a future date so leave this in for
1271 	 * now).
1272 	 */
1273 	asprintf(&filename, "%s%s/etc/crypttab", a->os_root, a->cfg_root);
1274 	crypttab = fopen(filename, "r");
1275 	free(filename);
1276 	if (crypttab != NULL) {
1277 		while (fgets(line, 256, crypttab) != NULL) {
1278 			/*
1279 			 * Parse the crypttab line.
1280 			 */
1281 			if (first_non_space_char_is(line, '#'))
1282 				continue;
1283 			if ((word = strtok(line, " \t")) == NULL)
1284 				continue;
1285 			strlcpy(name, word, 256);
1286 
1287 			/* don't mount encrypted swap */
1288 			if (strcmp(name, "swap") == 0)
1289 				continue;
1290 			/* encrypted root already mounted */
1291 			if (strcmp(name, subpartition_get_mapper_name(d_subpart, -1)) == 0)
1292 				continue;
1293 
1294 			if ((word = strtok(NULL, " \t")) == NULL)
1295 				continue;
1296 			strlcpy(device, word, 256);
1297 
1298 			command_add(cmds,
1299 			    "%s%s -d /tmp/t1 luksOpen %s %s",
1300 			    a->os_root, cmd_name(a, "CRYPTSETUP"),
1301 			    device, name);
1302 
1303 			continue;
1304 		}
1305 		fclose(crypttab);
1306 	}
1307 	if (!commands_execute(a, cmds)) {
1308 		commands_free(cmds);
1309 		return(0);
1310 	}
1311 	commands_free(cmds);
1312 
1313 	/*
1314 	 * (current we do not mount the other partitions, everything needed
1315 	 *  for system configuration should be on the already-mounted root).
1316 	 */
1317 	asprintf(&filename, "%s%s/etc/fstab", a->os_root, a->cfg_root);
1318 	fstab = fopen(filename, "r");
1319 	free(filename);
1320 	if (fstab == NULL) {
1321 		inform(a->c, _("Filesystem table on installed system could not be read."));
1322 		cmds = commands_new();
1323 		command_add(cmds, "%s%s %s%s",
1324 		    a->os_root, cmd_name(a, "UMOUNT"),
1325 		    a->os_root, a->cfg_root);
1326 		if (!commands_execute(a, cmds)) {
1327 			inform(a->c, _("Warning: Installed system was not properly unmounted."));
1328 		}
1329 		commands_free(cmds);
1330 		return(0);
1331 	}
1332 	fclose(fstab);
1333 
1334 	return 1;
1335 }
1336