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, int confirm)
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 	if (confirm) {
343 		f = dfui_form_create(
344 		    "crypt_passphrase",
345 		    _("Set Passphrase for Encryption"),
346 		    _("Please specify the passphrase to be used for the encrypted "
347 			"filesystems.\n\n"
348 			"Please note that in the LiveCD environment the keymap is "
349 			"set to \"US ISO\". "
350 			"If you prefer a different keymap for entering the passphrase "
351 			"here, you will need to set it manually using kbdcontrol(1)."),
352 		    "",
353 
354 		    "f", "passphrase_1", _("Passphrase"),
355 		    _("Enter the passphrase you would like to use for encryption"), "",
356 		    "p", "obscured", "true",
357 		    "f", "passphrase_2", _("Passphrase again"),
358 		    _("Enter the passphrase again to confirm"), "",
359 		    "p", "obscured", "true",
360 
361 		    "a", "ok", _("Accept and Set Passphrase"), "", "",
362 		    "p", "accelerator", "ESC",
363 
364 		    NULL
365 		);
366 	} else {
367 		f = dfui_form_create(
368 		    "crypt_passphrase",
369 		    _("Specify Decryption Passphrase"),
370 		    _("Please enter the passphrase to decrypt and mount the "
371 			"filesystems.\n\n"
372 			"Please note that in the LiveCD environment the keymap is "
373 			"set to \"US ISO\". "
374 			"If you prefer a different keymap for entering the passphrase "
375 			"here, you will need to set it manually using kbdcontrol(1)."),
376 		    "",
377 
378 		    "f", "passphrase_1", _("Passphrase"),
379 		    _("Enter the passphrase"), "",
380 		    "p", "obscured", "true",
381 
382 		    "a", "ok", _("OK"), "", "",
383 		    "p", "accelerator", "ESC",
384 
385 		    NULL
386 		);
387 	}
388 
389 	ds = dfui_dataset_new();
390 	dfui_dataset_celldata_add(ds, "passphrase_1", "");
391 	if (confirm)
392 		dfui_dataset_celldata_add(ds, "passphrase_2", "");
393 	dfui_form_dataset_add(f, ds);
394 
395 	while (!done) {
396 		if (!dfui_be_present(a->c, f, &r))
397 			abort_backend();
398 
399 		if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
400 			new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r));
401 			dfui_form_datasets_free(f);
402 			dfui_form_dataset_add(f, new_ds);
403 
404 			/*
405 			 * Fetch form field values.
406 			 */
407 
408 			passphrase_1 = dfui_dataset_get_value(new_ds, "passphrase_1");
409 			passphrase_2 = passphrase_1;
410 			if (confirm)
411 				passphrase_2 = dfui_dataset_get_value(new_ds, "passphrase_2");
412 
413 			if (strlen(passphrase_1) == 0 && strlen(passphrase_2) == 0) {
414 				done = 0;
415 			} else if (strcmp(passphrase_1, passphrase_2) == 0) {
416 				/*
417 				 * Passphrases match, write it out.
418 				 */
419 				fd = open("/tmp/t1", O_RDWR | O_CREAT | O_TRUNC,
420 				    S_IRUSR);
421 				if (fd != -1) {
422 					write(fd, passphrase_1, strlen(passphrase_1));
423 					close(fd);
424 					done = 1;
425 				} else {
426 					inform(a->c, _("write() error"));
427 					done = 0;
428 				}
429 			} else {
430 				/*
431 				 * Passphrases don't match, tell the user,
432 				 * let them try again.
433 				 */
434 				inform(a->c, _("The passphrases do not match."));
435 				done = 0;
436 			}
437 		}
438 
439 		dfui_response_free(r);
440 	}
441 
442 	dfui_form_free(f);
443 }
444 
445 /** LIVECD UTILITIES FUNCTIONS **/
446 
447 /*
448  * String returned by this function must be deallocated by the caller.
449  */
450 char *
451 fn_select_file(const char *title, const char *desc, const char *help, const char *cancel,
452 	       const char *dir, const char *ext, const struct i_fn_args *a)
453 {
454 	DIR *d;
455 	struct dfui_form *f;
456 	struct dfui_action *k;
457 	struct dfui_response *r;
458 	struct dirent *de;
459 	char *s;
460 	struct aura_dict *dict;
461 	char *rk;
462 	size_t rk_len;
463 
464 	f = dfui_form_create(
465 	    "select_file",
466 	    title, desc, help,
467 	    "p", "role", "menu",
468 	    NULL
469 	);
470 
471 	dict = aura_dict_new(1, AURA_DICT_SORTED_LIST);
472 	d = opendir(dir);
473 	while ((de = readdir(d)) != NULL) {
474 		if (strcmp(de->d_name, ".") == 0 ||
475 		    strcmp(de->d_name, "..") == 0 ||
476 		    strstr(de->d_name, ext) == NULL)
477 			continue;
478 		aura_dict_store(dict, de->d_name, strlen(de->d_name) + 1, "", 1);
479 	}
480 	closedir(d);
481 
482 	aura_dict_rewind(dict);
483 	while (!aura_dict_eof(dict)) {
484 		aura_dict_get_current_key(dict, (void **)&rk, &rk_len),
485 		dfui_form_action_add(f, rk,
486 		    dfui_info_new(rk, "", ""));
487 		aura_dict_next(dict);
488 	}
489 	aura_dict_free(dict);
490 
491 	k = dfui_form_action_add(f, "cancel",
492 	    dfui_info_new(cancel, "", ""));
493 	dfui_action_property_set(k, "accelerator", "ESC");
494 
495 	if (!dfui_be_present(a->c, f, &r))
496 		abort_backend();
497 
498 	s = aura_strdup(dfui_response_get_action_id(r));
499 
500 	dfui_form_free(f);
501 	dfui_response_free(r);
502 
503 	return(s);
504 }
505 
506 void
507 fn_set_kbdmap(struct i_fn_args *a)
508 {
509 	struct commands *cmds;
510 	char *s;
511 	char filename[256], keymapname[256];
512 
513 	s = fn_select_file(_("Select Keyboard Map"),
514 	    _("Select a keyboard map appropriate to your keyboard layout."),
515 	    "", _("Return to Utilities Menu"), "/usr/share/syscons/keymaps",
516 	    ".kbd", a);
517 
518 	if (strcmp(s, "cancel") != 0) {
519 		cmds = commands_new();
520 		command_add(cmds, "%s%s -l "
521 		    "/usr/share/syscons/keymaps/%s < /dev/ttyv0",
522 		    a->os_root, cmd_name(a, "KBDCONTROL"),
523 		    s);
524 		if (commands_execute(a, cmds)) {
525 			snprintf(filename, 256, "/usr/share/syscons/keymaps/%s", s);
526 			snprintf(keymapname, 256, "%s", filename_noext(basename(filename)));
527 			config_var_set(rc_conf, "keymap", keymapname);
528 		} else {
529 			inform(a->c, _("Keyboard map not successfully set."));
530 		}
531 		commands_free(cmds);
532 	}
533 
534 	free(s);
535 }
536 
537 void
538 fn_set_vidfont(struct i_fn_args *a)
539 {
540 	struct commands *cmds;
541 	char *s;
542 	char filename[256], variable[256], fontname[256];
543 	int by = 0;
544 
545 
546 	s = fn_select_file(_("Select Console Font"),
547 	    _("Select a font appropriate to your video monitor and language."),
548 	    "", _("Return to Utilities Menu"), "/usr/share/syscons/fonts",
549 	    ".fnt", a);
550 
551 	if (strcmp(s, "cancel") != 0) {
552 		cmds = commands_new();
553 		command_add(cmds, "%s%s -f "
554 		    "/usr/share/syscons/fonts/%s < /dev/ttyv0",
555 		    a->os_root, cmd_name(a, "VIDCONTROL"),
556 		    s);
557 		if (commands_execute(a, cmds)) {
558 			if (strstr(s, "8x16") != NULL)
559 				by = 16;
560 			else if (strstr(s, "8x14") != NULL)
561 				by = 14;
562 			else
563 				by = 8;
564 
565 			snprintf(variable, 256, "font8x%d", by);
566 			snprintf(filename, 256, "/usr/share/syscons/fonts/%s", s);
567 			snprintf(fontname, 256, "%s", filename_noext(basename(filename)));
568 			config_var_set(rc_conf, variable, fontname);
569 
570 		} else {
571 			inform(a->c, _("Video font not successfully set."));
572 		}
573 		commands_free(cmds);
574 	}
575 
576 	free(s);
577 }
578 
579 void
580 fn_set_scrnmap(struct i_fn_args *a)
581 {
582 	struct commands *cmds;
583 	char *s;
584 	char filename[256], scrnmapname[256];
585 
586 	s = fn_select_file(_("Select Screen Map"),
587 	    _("Select a mapping for translating characters as they appear "
588 	    "on your video console screen."),
589 	    "", _("Return to Utilities Menu"), "/usr/share/syscons/scrnmaps",
590 	    ".scm", a);
591 
592 	if (strcmp(s, "cancel") != 0) {
593 		cmds = commands_new();
594 		command_add(cmds, "%s%s -l "
595 		    "/usr/share/syscons/scrnmaps/%s < /dev/ttyv0",
596 		    a->os_root, cmd_name(a, "VIDCONTROL"),
597 		    s);
598 		if (commands_execute(a, cmds)) {
599 			snprintf(filename, 256, "/usr/share/syscons/scrnmaps/%s", s);
600 			snprintf(scrnmapname, 256, "%s", filename_noext(basename(filename)));
601 			config_var_set(rc_conf, "scrnmap", scrnmapname);
602 		} else {
603 			inform(a->c, _("Video font not successfully set."));
604 		}
605 		commands_free(cmds);
606 	}
607 	free(s);
608 }
609 
610 void
611 fn_set_timezone(struct i_fn_args *a)
612 {
613 	struct commands *cmds;
614 	char *s = NULL;
615 	char current_path[256], selection[256], temp[256];
616 	int found_file = 0;
617 	int result;
618 
619 	result = dfui_be_present_dialog(a->c, _("Local or UTC (Greenwich Mean Time) clock"),
620 	    _("Yes|No"),
621             _("Is this machine's CMOS clock set to UTC?\n\n"
622 	    "If it is set to local time, or you don't know, please choose NO here!"));
623 	if (result < 1)
624 		abort_backend();
625 
626 	cmds = commands_new();
627 	switch (result) {
628 		case 1:
629 			command_add(cmds, "%s%s -f %s%setc/wall_cmos_clock",
630 			    a->os_root, cmd_name(a, "RM"),
631 			    a->os_root, a->cfg_root);
632 			break;
633 		case 2:
634 			command_add(cmds, "%s%s %s%setc/wall_cmos_clock",
635 			    a->os_root, cmd_name(a, "TOUCH"),
636 			    a->os_root, a->cfg_root);
637 			break;
638 	}
639 	commands_execute(a, cmds);
640 
641 	snprintf(current_path, 256, "%s%susr/share/zoneinfo",
642 	    a->os_root, a->cfg_root);
643 	while (!found_file) {
644 		if (s != NULL)
645 			free(s);
646 		s = fn_select_file(_("Select Time Zone"),
647 		    _("Select a Time Zone appropriate to your physical location."),
648 		    "", _("Return to Utilities Menu"), current_path,
649 		    "", a);
650 		if (is_dir("%s/%s", current_path, s)) {
651 			snprintf(temp, 256, "%s/%s", current_path, s);
652 			strlcpy(current_path, temp, 256);
653 		} else {
654 			if (is_file("%s/%s", current_path, s)) {
655 				snprintf(selection, 256, "%s/%s", current_path, s);
656 				found_file = 1;
657 			}
658 			if (strcmp(s, "cancel") == 0) {
659 				strlcpy(selection, "cancel", 256);
660 				found_file = 1;
661 			}
662 		}
663 	}
664 	free(s);
665 
666 	if (strcmp(selection, "cancel") != 0) {
667 		command_add(cmds, "%s%s %s %s%setc/localtime",
668 		    a->os_root, cmd_name(a, "CP"),
669 		    selection,
670 		    a->os_root, a->cfg_root);
671 		if (commands_execute(a, cmds)) {
672 			inform(a->c, _("The Time Zone has been set to %s."), selection);
673 			setenv("TZ", selection, 1);
674 			tzset();
675 		}
676 	}
677 	commands_free(cmds);
678 }
679 
680 void
681 fn_assign_datetime(struct i_fn_args *a)
682 {
683 	struct commands *cmds;
684 	struct dfui_dataset *ds, *new_ds;
685 	struct dfui_form *f;
686 	struct dfui_response *r;
687 	struct tm *tp;
688 	char temp[256];
689 	int year, month, dayofmonth, hour, minutes;
690 	int valid = 1;
691 	time_t now;
692 
693 	now = time(NULL);
694 	tp = localtime(&now);
695 
696 	f = dfui_form_create(
697 	    "set_datetime",
698 	    _("Set Time/Date"),
699 	    _("Enter the date-time in your timezone."),
700 	    "",
701 
702 	    "f", "year", _("Enter year"),
703 	    _("Enter the current year (e.g. `2004')"), "",
704 	    "f", "month", _("Month"),
705 	    _("Enter the current month (e.g. `07')"), "",
706 	    "f", "dayofmonth", "dayofmonth",
707 	    _("Enter the current day of month (e.g. `30')"), "",
708 	    "f", "hour", "hour",
709 	    _("Enter the current hour (e.g. `07')"), "",
710 	    "f", "minutes", "minutes",
711 	    _("Enter the current minutes (e.g. `59')"), "",
712 
713 	    "a", "ok", _("OK"), "", "",
714 	    "a", "cancel", _("Cancel"), "", "",
715 	    "p", "accelerator", "ESC",
716 
717 	    NULL
718 	);
719 
720 	ds = dfui_dataset_new();
721 	snprintf(temp, 256, "%i", (tp->tm_year+1900));
722 	dfui_dataset_celldata_add(ds, "year", temp);
723 	snprintf(temp, 256, "%i", (tp->tm_mon+1));
724 	dfui_dataset_celldata_add(ds, "month", temp);
725 	snprintf(temp, 256, "%i", tp->tm_mday);
726 	dfui_dataset_celldata_add(ds, "dayofmonth", temp);
727 	snprintf(temp, 256, "%i", tp->tm_hour);
728 	dfui_dataset_celldata_add(ds, "hour", temp);
729 	snprintf(temp, 256, "%i", tp->tm_min);
730 	dfui_dataset_celldata_add(ds, "minutes", temp);
731 	dfui_form_dataset_add(f, ds);
732 
733 	if (!dfui_be_present(a->c, f, &r))
734 		abort_backend();
735 
736 	if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
737 		new_ds = dfui_response_dataset_get_first(r);
738 
739 		if ((year = atoi(dfui_dataset_get_value(new_ds, "year"))) <= 0)
740 			valid = 0;
741 		month = atoi(dfui_dataset_get_value(new_ds, "month"));
742 		if (month < 1 || month > 12)
743 			valid = 0;
744 		dayofmonth = atoi(dfui_dataset_get_value(new_ds, "dayofmonth"));
745 		if (dayofmonth < 1 || dayofmonth > 31)
746 			valid = 0;
747 		hour = atoi(dfui_dataset_get_value(new_ds, "hour"));
748 		if (hour < 0 || hour > 23)
749 			valid = 0;
750 		minutes = atoi(dfui_dataset_get_value(new_ds, "minutes"));
751 		if (minutes < 0 || minutes > 59)
752 			valid = 0;
753 
754 		if (valid) {
755 			cmds = commands_new();
756 			command_add(cmds, "%s%s -n %04d%02d%02d%02d%02d",
757 			    a->os_root, cmd_name(a, "DATE"),
758 			    year, month, dayofmonth, hour, minutes);
759 			if (commands_execute(a, cmds)) {
760 				inform(a->c, _("The date and time have been set."));
761 			}
762 			commands_free(cmds);
763 		} else {
764 			inform(a->c, _("Please enter numbers within acceptable ranges "
765 				"for year, month, day of month, hour, and minute."));
766 		}
767 	}
768 }
769 
770 void
771 fn_assign_hostname_domain(struct i_fn_args *a)
772 {
773 	struct dfui_form *f;
774 	struct dfui_response *r;
775 	struct dfui_dataset *ds, *new_ds;
776 	struct config_vars *resolv_conf;
777 	const char *domain, *hostname;
778 	char *fqdn;
779 
780 	f = dfui_form_create(
781 	    "set_hostname_domain",
782 	    _("Set Hostname/Domain"),
783 	    _("Please enter this machine's hostname and domain name."),
784 	    "",
785 
786 	    "f", "hostname", _("Hostname"),
787 	    _("Enter the Hostname (e.g. `machine')"), "",
788 	    "f", "domain", _("Domain"),
789 	    _("Enter the Domain Name (e.g. `network.lan')"), "",
790 
791 	    "a", "ok", _("OK"), "", "",
792 	    "a", "cancel", _("Cancel"), "", "",
793 	    "p", "accelerator", "ESC",
794 
795 	    NULL
796 	);
797 
798 	ds = dfui_dataset_new();
799 	dfui_dataset_celldata_add(ds, "hostname", "");
800 	dfui_dataset_celldata_add(ds, "domain", "");
801 	dfui_form_dataset_add(f, ds);
802 
803 	if (!dfui_be_present(a->c, f, &r))
804 		abort_backend();
805 
806 	if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
807 		new_ds = dfui_response_dataset_get_first(r);
808 
809 		hostname = dfui_dataset_get_value(new_ds, "hostname");
810 		domain = dfui_dataset_get_value(new_ds, "domain");
811 		if (strlen(domain) == 0)
812 			asprintf(&fqdn, "%s", hostname);
813 		else
814 			asprintf(&fqdn, "%s.%s", hostname, domain);
815 
816 		resolv_conf = config_vars_new();
817 
818 		config_var_set(rc_conf, "hostname", fqdn);
819 		config_var_set(resolv_conf, "search", domain);
820 		config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
821 		    "%s%setc/resolv.conf", a->os_root, a->cfg_root);
822 
823 		config_vars_free(resolv_conf);
824 
825 		free(fqdn);
826 	}
827 
828 	dfui_form_free(f);
829 	dfui_response_free(r);
830 }
831 
832 void
833 fn_assign_ip(struct i_fn_args *a)
834 {
835 	FILE *p;
836 	struct commands *cmds;
837 	struct command *cmd;
838 	struct config_vars *resolv_conf;
839 	struct dfui_dataset *ds, *new_ds;
840 	struct dfui_form *f;
841 	struct dfui_action *k;
842 	struct dfui_response *r;
843 	const char *domain, *hostname;
844 	const char *interface_ip, *interface_netmask, *defaultrouter, *dns_resolver;
845 	char *string, *string1;
846 	char *word;
847 	char interface[256];
848 	char line[256];
849 	int write_config = 0;
850 
851 	/*
852 	 * Get interface list.
853 	 */
854 	p = popen("/sbin/ifconfig -l", "r");
855 	/* XXX it's possible (though extremely unlikely) this will fail. */
856 	while (fgets(line, 255, p) != NULL)
857 		line[strlen(line) - 1] = '\0';
858 
859 	pclose(p);
860 
861 	f = dfui_form_create(
862 	    "assign_ip",
863 	    _("Assign IP Address"),
864 	    _("Please select which interface you would like to configure:"),
865 	    "",
866 	    "p",	"role", "menu",
867 	    NULL
868 	);
869 
870 	/* Loop through array. */
871 	word = strtok(line, " \t");
872 	while (word != NULL) {
873 		dfui_form_action_add(f, word,
874 		    dfui_info_new(word, "", ""));
875 		word = strtok(NULL, " ");
876 	}
877 
878 	k = dfui_form_action_add(f, "cancel",
879 	    dfui_info_new("Cancel", "", ""));
880 	dfui_action_property_set(k, "accelerator", "ESC");
881 
882 	if (!dfui_be_present(a->c, f, &r))
883 		abort_backend();
884 
885 	if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
886 		dfui_form_free(f);
887 		dfui_response_free(r);
888 		return;
889 	}
890 
891 	strlcpy(interface, dfui_response_get_action_id(r), 256);
892 
893 	resolv_conf = config_vars_new();
894 
895 	switch (dfui_be_present_dialog(a->c, _("Use DHCP?"),
896 	    _("Use DHCP|Configure Manually"),
897 	    _("DHCP allows the interface to automatically obtain "
898 	    "an IP address from a nearby DHCP server.\n\n"
899 	    "Would you like to enable DHCP for %s?"), interface)) {
900 	case 1:
901 		asprintf(&string, "ifconfig_%s", interface);
902 
903 		cmds = commands_new();
904 		cmd = command_add(cmds, "%s%s dhclient",
905 		    a->os_root, cmd_name(a, "KILLALL"));
906 		command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
907 		command_add(cmds, "%s%s %s",
908 		    a->os_root, cmd_name(a, "DHCLIENT"),
909 		    interface);
910 		if (commands_execute(a, cmds)) {
911 			/* XXX sleep(3); */
912 			show_ifconfig(a->c, interface);
913 			write_config = 1;
914 		} else {
915 			switch (dfui_be_present_dialog(a->c, _("DHCP Failure"),
916 			    _("Yes|No"),
917 			    _("Warning: could not enable dhclient for %s.\n\n"
918 			      "Write the corresponding settings to rc.conf "
919 			      "anyway?"), interface)) {
920 			case 1:
921 				write_config = 1;
922 				break;
923 			case 2:
924 				write_config = 0;
925 				break;
926 			default:
927 				abort_backend();
928 			}
929 		}
930 		commands_free(cmds);
931 		config_var_set(rc_conf, string, "DHCP");
932 		free(string);
933 		break;
934 	case 2:
935 		dfui_form_free(f);
936 		dfui_response_free(r);
937 		f = dfui_form_create(
938 		    "assign_ip",
939 		    _("Assign IP Address"),
940 		    _("Configuring Interface:"),
941 		    "",
942 
943 		    "f", "interface_ip", _("IP Address"),
944 		    _("Enter the IP Address you would like to use"), "",
945 		    "f", "interface_netmask",	_("Netmask"),
946 		    _("Enter the netmask of the IP address"), "",
947 		    "f", "defaultrouter", _("Default Router"),
948 		    _("Enter the IP address of the default router"), "",
949 		    "f", "dns_resolver", _("Primary DNS Server"),
950 		    _("Enter the IP address of primary DNS Server"), "",
951 		    "f", "hostname", _("Hostname"),
952 		    _("Enter the Hostname"), "",
953 		    "f", "domain", _("Domain"),
954 		    _("Enter the Domain Name"), "",
955 
956 		    "a", "ok", _("Configure Interface"),
957 		    "", "",
958 		    "a", "cancel", _("Return to Utilities Menu"),
959 		    "", "",
960 		    "p", "accelerator", "ESC",
961 
962 		    NULL
963 		);
964 
965 		ds = dfui_dataset_new();
966 		dfui_dataset_celldata_add(ds, "interface_netmask", "");
967 		dfui_dataset_celldata_add(ds, "defaultrouter", "");
968 		dfui_dataset_celldata_add(ds, "dns_resolver", "");
969 		dfui_dataset_celldata_add(ds, "hostname", "");
970 		dfui_dataset_celldata_add(ds, "domain", "");
971 		dfui_dataset_celldata_add(ds, "interface_ip", "");
972 		dfui_form_dataset_add(f, ds);
973 
974 		if (!dfui_be_present(a->c, f, &r))
975 			abort_backend();
976 
977 		if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
978 			new_ds = dfui_response_dataset_get_first(r);
979 
980 			interface_ip = dfui_dataset_get_value(
981 						new_ds, "interface_ip");
982 			interface_netmask = dfui_dataset_get_value(
983 						new_ds, "interface_netmask");
984 			defaultrouter = dfui_dataset_get_value(
985 						new_ds, "defaultrouter");
986 			dns_resolver = dfui_dataset_get_value(
987 						new_ds, "dns_resolver");
988 			hostname = dfui_dataset_get_value(
989 						new_ds, "hostname");
990 			domain = dfui_dataset_get_value(
991 						new_ds, "domain");
992 
993 			asprintf(&string, "ifconfig_%s", interface);
994 			asprintf(&string1, "inet %s netmask %s",
995 			    interface_ip, interface_netmask);
996 
997 			cmds = commands_new();
998 			command_add(cmds, "%s%s %s %s netmask %s",
999 			    a->os_root, cmd_name(a, "IFCONFIG"),
1000 			    interface, interface_ip, interface_netmask);
1001 			command_add(cmds, "%s%s add default %s",
1002 			    a->os_root, cmd_name(a, "ROUTE"),
1003 			    defaultrouter);
1004 
1005 			if (commands_execute(a, cmds)) {
1006 				/* XXX sleep(3); */
1007 				show_ifconfig(a->c, interface);
1008 				write_config = 1;
1009 			} else {
1010 				switch (dfui_be_present_dialog(a->c,
1011 				    _("ifconfig Failure"),
1012 				    _("Yes|No"),
1013 				    _("Warning: could not assign IP address "
1014 				      "or default gateway.\n\n"
1015 				      "Write the corresponding settings to "
1016 				      "rc.conf anyway?"))) {
1017 				case 1:
1018 					write_config = 1;
1019 					break;
1020 				case 2:
1021 					write_config = 0;
1022 					break;
1023 				default:
1024 					abort_backend();
1025 				}
1026 			}
1027 			commands_free(cmds);
1028 
1029 			config_var_set(rc_conf, string, string1);
1030 			config_var_set(rc_conf, "defaultrouter", defaultrouter);
1031 
1032 			free(string);
1033 			free(string1);
1034 
1035 			asprintf(&string, "%s.%s", hostname, domain);
1036 			config_var_set(rc_conf, "hostname", string);
1037 			free(string);
1038 
1039 			config_var_set(resolv_conf, "search", domain);
1040 			config_var_set(resolv_conf, "nameserver", dns_resolver);
1041 		}
1042 		break;
1043 	default:
1044 		abort_backend();
1045 	}
1046 
1047 	if (write_config) {
1048 		/*
1049 		 * Save out changes to /etc/rc.conf and /etc/resolv.conf.
1050 		 */
1051 		config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
1052 		    "%s%setc/resolv.conf", a->os_root, a->cfg_root);
1053 	}
1054 
1055 	config_vars_free(resolv_conf);
1056 
1057 	dfui_form_free(f);
1058 	dfui_response_free(r);
1059 }
1060 
1061 static const char *
1062 yes_to_y(const char *value)
1063 {
1064 	return(strcasecmp(value, "YES") == 0 ? "Y" : "N");
1065 }
1066 
1067 void
1068 fn_select_services(struct i_fn_args *a)
1069 {
1070 	struct dfui_dataset *ds;
1071 	struct dfui_form *f;
1072 	struct dfui_response *r;
1073 
1074 	if (!config_vars_read(a, rc_conf, CONFIG_TYPE_SH, "%s%setc/rc.conf",
1075 		a->os_root, a->cfg_root)) {
1076 		inform(a->c, _("Couldn't read %s%setc/rc.conf."),
1077 		    a->os_root, a->cfg_root);
1078 		a->result = 0;
1079 		return;
1080 	}
1081 
1082 	f = dfui_form_create(
1083 	    "select_services",
1084 	    _("Select Services"),
1085 	    _("Please select which services you would like "
1086 	      "started at boot time."),
1087 	    "",
1088 
1089 	    "f", "syslogd", "syslogd",
1090 		_("System Logging Daemon"), "",
1091 		"p", "control", "checkbox",
1092 	    "f", "inetd", "inetd",
1093 		_("Internet Super-Server"), "",
1094 		"p", "control", "checkbox",
1095 	    "f", "named", "named",
1096 		_("BIND Name Server"), "",
1097 		"p", "control", "checkbox",
1098 	    "f", "ntpd", "ntpd",
1099 		_("Network Time Protocol Daemon"), "",
1100 		"p", "control", "checkbox",
1101 	    "f", "sshd", "sshd",
1102 		_("Secure Shell Daemon"), "",
1103 		"p", "control", "checkbox",
1104 
1105 	    "a", "ok", _("Enable/Disable Services"),
1106 	        "", "",
1107 	    "a", "cancel", _("Return to Utilities Menu"),
1108 		"", "",
1109 	        "p", "accelerator", "ESC",
1110 
1111 	    NULL
1112 	);
1113 
1114 	ds = dfui_dataset_new();
1115 	dfui_dataset_celldata_add(ds, "syslogd",
1116 	    yes_to_y(config_var_get(rc_conf, "syslogd_enable")));
1117 	dfui_dataset_celldata_add(ds, "inetd",
1118 	    yes_to_y(config_var_get(rc_conf, "inetd_enable")));
1119 	dfui_dataset_celldata_add(ds, "named",
1120 	    yes_to_y(config_var_get(rc_conf, "named_enable")));
1121 	dfui_dataset_celldata_add(ds, "ntpd",
1122 	    yes_to_y(config_var_get(rc_conf, "ntpd_enable")));
1123 	dfui_dataset_celldata_add(ds, "sshd",
1124 	    yes_to_y(config_var_get(rc_conf, "sshd_enable")));
1125 	dfui_form_dataset_add(f, ds);
1126 
1127 	if (!dfui_be_present(a->c, f, &r))
1128 		abort_backend();
1129 
1130 	if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1131 		dfui_form_free(f);
1132 		dfui_response_free(r);
1133 		return;
1134 	}
1135 
1136 	dfui_form_free(f);
1137 	dfui_response_free(r);
1138 }
1139 
1140 /*** NON-fn_ FUNCTIONS ***/
1141 
1142 /*
1143  * Uses ss->selected_{disk,slice} as the target system.
1144  *
1145  * XXX We now assume that the root mount has enough of the topology
1146  *     to handle any configuration actions.
1147  */
1148 int
1149 mount_target_system(struct i_fn_args *a)
1150 {
1151 	FILE *crypttab, *fstab;
1152 	struct commands *cmds;
1153 	struct command *cmd;
1154 	struct subpartition *a_subpart;
1155 	struct subpartition *d_subpart;
1156 	char name[256], device[256];
1157 	char *filename, line[256];
1158 	char *word;
1159 
1160 	/*
1161 	 * Mount subpartitions from this installation if they are
1162 	 * not already mounted.  Tricky, as we need to honour the
1163 	 * installation's loader.conf and fstab.
1164 	 */
1165 	cmds = commands_new();
1166 
1167 	/*
1168 	 * First, unmount anything already mounted on /mnt.
1169 	 */
1170 	unmount_all_under(a, cmds, "%smnt", a->os_root);
1171 
1172 	/*
1173 	 * Reset and clear out subpartitions so that system
1174 	 * can make a "dummy" subpart.
1175 	 */
1176 	subpartitions_free(storage_get_selected_slice(a->s));
1177 
1178 	/*
1179 	 * Create a temporary dummy subpartition - that we
1180 	 * assume exists
1181 	 */
1182 	a_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s),
1183 					 "/dummy", 0, 0, 0, 0, 0, 0);
1184 	subpartition_new_ufs(storage_get_selected_slice(a->s),
1185 					 "swap", 0, 0, 0, 0, 0, 0);
1186 	d_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s),
1187 					 "/dummy", 0, 0, 0, 0, 0, 0);
1188 
1189 	/*
1190 	 * Mount the target's / and read its /etc/fstab.
1191 	 *
1192 	 * XXX NEEDS TO BE REWRITTEN XXX
1193 	 */
1194 	{
1195 		command_add(cmds, "%s%s /dev/%s %sboot",
1196 		    a->os_root, cmd_name(a, "MOUNT"),
1197 		    subpartition_get_device_name(a_subpart),
1198 		    a->os_root);
1199 		cmd = command_add(cmds,
1200 		    "%s%s -f %st2;"
1201 		    "%s%s \"^vfs\\.root\\.realroot=\" %sboot/loader.conf >%st2",
1202 		    a->os_root, cmd_name(a, "RM"), a->tmp,
1203 		    a->os_root, cmd_name(a, "GREP"),
1204 		    a->os_root, a->tmp);
1205 		command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
1206 	}
1207 	if (!commands_execute(a, cmds)) {
1208 		commands_free(cmds);
1209 		return(0);
1210 	}
1211 	commands_free(cmds);
1212 	cmds = commands_new();
1213 
1214 	/*
1215 	 * XXX NEEDS TO BE REWRITTEN XXX
1216 	 */
1217 	{
1218 		struct stat sb = { .st_size = 0 };
1219 		const char *fsname;
1220 		const char *mountid;
1221 
1222 		switch (use_hammer) {
1223 		case 1:
1224 			fsname = "hammer";
1225 			mountid = "MOUNT_HAMMER";
1226 			break;
1227 		case 2:
1228 			fsname = "hammer2";
1229 			mountid = "MOUNT_HAMMER2";
1230 			break;
1231 		case 0:
1232 		default:
1233 			fsname = "ufs";
1234 			mountid = "MOUNT";
1235 			break;
1236 		}
1237 
1238 		stat("/tmp/t2", &sb);
1239 		if (sb.st_size > 0) {
1240 			command_add(cmds, "%s%s %sboot",
1241 			    a->os_root, cmd_name(a, "UMOUNT"),
1242 			    a->os_root);
1243 			fn_get_passphrase(a, 0);
1244 			command_add(cmds,
1245 			    "%s%s -d /tmp/t1 luksOpen /dev/`%s%s \"^vfs\\.root\\.realroot=\" %st2 |"
1246 			    "%s%s -F%s: '{print $2;}' |"
1247 			    "%s%s -F: '{print $1;}'` %s",
1248 			    a->os_root, cmd_name(a, "CRYPTSETUP"),
1249 			    a->os_root, cmd_name(a, "GREP"),
1250 			    a->tmp,
1251 			    a->os_root, cmd_name(a, "AWK"),
1252 			    fsname,
1253 			    a->os_root, cmd_name(a, "AWK"),
1254 			    subpartition_get_mapper_name(d_subpart, -1));
1255 			command_add(cmds,
1256 			    "%s%s %s %s%s",
1257 			    a->os_root,
1258 			    cmd_name(a, mountid),
1259 			    subpartition_get_mapper_name(d_subpart, 1),
1260 			    a->os_root, a->cfg_root);
1261 		} else {
1262 			command_add(cmds,
1263 			    "%s%s /dev/`%s%s \"^vfs\\.root\\.mountfrom\" %sboot/loader.conf |"
1264 			    "%s%s -F%s: '{print $2;}' |"
1265 			    "%s%s 's/\"//'` %s%s",
1266 			    a->os_root,
1267 			    cmd_name(a, mountid),
1268 			    a->os_root, cmd_name(a, "GREP"),
1269 			    a->os_root,
1270 			    a->os_root, cmd_name(a, "AWK"),
1271 			    fsname,
1272 			    a->os_root, cmd_name(a, "SED"),
1273 			    a->os_root, a->cfg_root);
1274 			command_add(cmds, "%s%s %sboot",
1275 			    a->os_root, cmd_name(a, "UMOUNT"),
1276 			    a->os_root);
1277 		}
1278 	}
1279 	if (!commands_execute(a, cmds)) {
1280 		commands_free(cmds);
1281 		unlink("/tmp/t1");
1282 		return(0);
1283 	}
1284 	commands_free(cmds);
1285 	cmds = commands_new();
1286 
1287 	/*
1288 	 * Get rid of the dummy subpartition.
1289 	 */
1290 	subpartitions_free(storage_get_selected_slice(a->s));
1291 
1292 	/*
1293 	 * See if an /etc/crypttab exists.
1294 	 *
1295 	 * Scan and open the related mappings (currently not used since
1296 	 * we removed the additional mounts from the fstab scan, but we
1297 	 * might put those back in at a future date so leave this in for
1298 	 * now).
1299 	 */
1300 	asprintf(&filename, "%s%s/etc/crypttab", a->os_root, a->cfg_root);
1301 	crypttab = fopen(filename, "r");
1302 	free(filename);
1303 	if (crypttab != NULL) {
1304 		while (fgets(line, 256, crypttab) != NULL) {
1305 			/*
1306 			 * Parse the crypttab line.
1307 			 */
1308 			if (first_non_space_char_is(line, '#'))
1309 				continue;
1310 			if ((word = strtok(line, " \t")) == NULL)
1311 				continue;
1312 			strlcpy(name, word, 256);
1313 
1314 			/* don't mount encrypted swap */
1315 			if (strcmp(name, "swap") == 0)
1316 				continue;
1317 			/* encrypted root already mounted */
1318 			if (strcmp(name, subpartition_get_mapper_name(d_subpart, -1)) == 0)
1319 				continue;
1320 
1321 			if ((word = strtok(NULL, " \t")) == NULL)
1322 				continue;
1323 			strlcpy(device, word, 256);
1324 
1325 			command_add(cmds,
1326 			    "%s%s -d /tmp/t1 luksOpen %s %s",
1327 			    a->os_root, cmd_name(a, "CRYPTSETUP"),
1328 			    device, name);
1329 
1330 			continue;
1331 		}
1332 		fclose(crypttab);
1333 	}
1334 	if (!commands_execute(a, cmds)) {
1335 		commands_free(cmds);
1336 		unlink("/tmp/t1");
1337 		return(0);
1338 	}
1339 	commands_free(cmds);
1340 	unlink("/tmp/t1");
1341 
1342 	/*
1343 	 * (current we do not mount the other partitions, everything needed
1344 	 *  for system configuration should be on the already-mounted root).
1345 	 */
1346 	asprintf(&filename, "%s%s/etc/fstab", a->os_root, a->cfg_root);
1347 	fstab = fopen(filename, "r");
1348 	free(filename);
1349 	if (fstab == NULL) {
1350 		inform(a->c, _("Filesystem table on installed system could not be read."));
1351 		cmds = commands_new();
1352 		command_add(cmds, "%s%s %s%s",
1353 		    a->os_root, cmd_name(a, "UMOUNT"),
1354 		    a->os_root, a->cfg_root);
1355 		if (!commands_execute(a, cmds)) {
1356 			inform(a->c, _("Warning: Installed system was not properly unmounted."));
1357 		}
1358 		commands_free(cmds);
1359 		return(0);
1360 	}
1361 	fclose(fstab);
1362 
1363 	return 1;
1364 }
1365