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