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