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