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