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