installer: Clarity language when asking the user for time-date info.
[dragonfly.git] / usr.sbin / installer / dfuibe_installer / fn_configure.c
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(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, 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, 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, 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         }
829         commands_free(cmds);
830 }
831
832 void
833 fn_assign_datetime(struct i_fn_args *a)
834 {
835         struct commands *cmds;
836         struct dfui_dataset *ds, *new_ds;
837         struct dfui_form *f;
838         struct dfui_response *r;
839         struct tm *tp;
840         char temp[256];
841         int year, month, dayofmonth, hour, minutes;
842         int valid = 1;
843         time_t now;
844
845         now = time(NULL);
846         tp = localtime(&now);
847
848         f = dfui_form_create(
849             "set_datetime",
850             _("Set Time/Date"),
851             _("Enter the date-time in your timezone."),
852             "",
853
854             "f", "year", _("Enter year"),
855             _("Enter the current year (e.g. `2004')"), "",
856             "f", "month", _("Month"),
857             _("Enter the current month (e.g. `07')"), "",
858             "f", "dayofmonth", "dayofmonth",
859             _("Enter the current day of month (e.g. `30')"), "",
860             "f", "hour", "hour",
861             _("Enter the current hour (e.g. `07')"), "",
862             "f", "minutes", "minutes",
863             _("Enter the current minutes (e.g. `59')"), "",
864
865             "a", "ok", _("OK"), "", "",
866             "a", "cancel", _("Cancel"), "", "",
867             "p", "accelerator", "ESC",
868
869             NULL
870         );
871
872         ds = dfui_dataset_new();
873         snprintf(temp, 256, "%i", (tp->tm_year+1900));
874         dfui_dataset_celldata_add(ds, "year", temp);
875         snprintf(temp, 256, "%i", (tp->tm_mon+1));
876         dfui_dataset_celldata_add(ds, "month", temp);
877         snprintf(temp, 256, "%i", tp->tm_mday);
878         dfui_dataset_celldata_add(ds, "dayofmonth", temp);
879         snprintf(temp, 256, "%i", tp->tm_hour);
880         dfui_dataset_celldata_add(ds, "hour", temp);
881         snprintf(temp, 256, "%i", tp->tm_min);
882         dfui_dataset_celldata_add(ds, "minutes", temp);
883         dfui_form_dataset_add(f, ds);
884
885         if (!dfui_be_present(a->c, f, &r))
886                 abort_backend();
887
888         if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
889                 new_ds = dfui_response_dataset_get_first(r);
890
891                 if ((year = atoi(dfui_dataset_get_value(new_ds, "year"))) <= 0)
892                         valid = 0;
893                 month = atoi(dfui_dataset_get_value(new_ds, "month"));
894                 if (month < 1 || month > 12)
895                         valid = 0;
896                 dayofmonth = atoi(dfui_dataset_get_value(new_ds, "dayofmonth"));
897                 if (dayofmonth < 1 || dayofmonth > 31)
898                         valid = 0;
899                 hour = atoi(dfui_dataset_get_value(new_ds, "hour"));
900                 if (hour < 0 || hour > 23)
901                         valid = 0;
902                 minutes = atoi(dfui_dataset_get_value(new_ds, "minutes"));
903                 if (minutes < 0 || minutes > 59)
904                         valid = 0;
905
906                 if (valid) {
907                         cmds = commands_new();
908                         command_add(cmds, "%s%s -n %04d%02d%02d%02d%02d",
909                             a->os_root, cmd_name(a, "DATE"),
910                             year, month, dayofmonth, hour, minutes);
911                         if (commands_execute(a, cmds)) {
912                                 inform(a->c, _("The date and time have been set."));
913                         }
914                         commands_free(cmds);
915                 } else {
916                         inform(a->c, _("Please enter numbers within acceptable ranges "
917                                 "for year, month, day of month, hour, and minute."));
918                 }
919         }
920 }
921
922 void
923 fn_assign_hostname_domain(struct i_fn_args *a)
924 {
925         struct dfui_form *f;
926         struct dfui_response *r;
927         struct dfui_dataset *ds, *new_ds;
928         struct config_vars *resolv_conf;
929         const char *domain, *hostname;
930         char *fqdn;
931
932         f = dfui_form_create(
933             "set_hostname_domain",
934             _("Set Hostname/Domain"),
935             _("Please enter this machine's hostname and domain name."),
936             "",
937
938             "f", "hostname", _("Hostname"),
939             _("Enter the Hostname (e.g. `machine')"), "",
940             "f", "domain", _("Domain"),
941             _("Enter the Domain Name (e.g. `network.lan')"), "",
942
943             "a", "ok", _("OK"), "", "",
944             "a", "cancel", _("Cancel"), "", "",
945             "p", "accelerator", "ESC",
946
947             NULL
948         );
949
950         ds = dfui_dataset_new();
951         dfui_dataset_celldata_add(ds, "hostname", "");
952         dfui_dataset_celldata_add(ds, "domain", "");
953         dfui_form_dataset_add(f, ds);
954
955         if (!dfui_be_present(a->c, f, &r))
956                 abort_backend();
957
958         if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
959                 new_ds = dfui_response_dataset_get_first(r);
960
961                 hostname = dfui_dataset_get_value(new_ds, "hostname");
962                 domain = dfui_dataset_get_value(new_ds, "domain");
963                 if (strlen(domain) == 0)
964                         asprintf(&fqdn, "%s", hostname);
965                 else
966                         asprintf(&fqdn, "%s.%s", hostname, domain);
967
968                 resolv_conf = config_vars_new();
969
970                 config_var_set(rc_conf, "hostname", fqdn);
971                 config_var_set(resolv_conf, "search", domain);
972                 config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
973                     "%s%setc/resolv.conf", a->os_root, a->cfg_root);
974
975                 config_vars_free(resolv_conf);
976
977                 free(fqdn);
978         }
979
980         dfui_form_free(f);
981         dfui_response_free(r);
982 }
983
984 void
985 fn_assign_ip(struct i_fn_args *a)
986 {
987         FILE *p;
988         struct commands *cmds;
989         struct command *cmd;
990         struct config_vars *resolv_conf;
991         struct dfui_dataset *ds, *new_ds;
992         struct dfui_form *f;
993         struct dfui_action *k;
994         struct dfui_response *r;
995         const char *domain, *hostname;
996         const char *interface_ip, *interface_netmask, *defaultrouter, *dns_resolver;
997         char *string, *string1;
998         char *word;
999         char interface[256];
1000         char line[256];
1001         int write_config = 0;
1002
1003         /*
1004          * Get interface list.
1005          */
1006         p = popen("/sbin/ifconfig -l", "r");
1007         /* XXX it's possible (though extremely unlikely) this will fail. */
1008         while (fgets(line, 255, p) != NULL)
1009                 line[strlen(line) - 1] = '\0';
1010
1011         pclose(p);
1012
1013         f = dfui_form_create(
1014             "assign_ip",
1015             _("Assign IP Address"),
1016             _("Please select which interface you would like to configure:"),
1017             "",
1018             "p",        "role", "menu",
1019             NULL
1020         );
1021
1022         /* Loop through array. */
1023         word = strtok(line, " \t");
1024         while (word != NULL) {
1025                 dfui_form_action_add(f, word,
1026                     dfui_info_new(word, "", ""));
1027                 word = strtok(NULL, " ");
1028         }
1029
1030         k = dfui_form_action_add(f, "cancel",
1031             dfui_info_new("Cancel", "", ""));
1032         dfui_action_property_set(k, "accelerator", "ESC");
1033
1034         if (!dfui_be_present(a->c, f, &r))
1035                 abort_backend();
1036
1037         if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1038                 dfui_form_free(f);
1039                 dfui_response_free(r);
1040                 return;
1041         }
1042
1043         strlcpy(interface, dfui_response_get_action_id(r), 256);
1044
1045         resolv_conf = config_vars_new();
1046
1047         switch (dfui_be_present_dialog(a->c, _("Use DHCP?"),
1048             _("Use DHCP|Configure Manually"),
1049             _("DHCP allows the interface to automatically obtain "
1050             "an IP address from a nearby DHCP server.\n\n"
1051             "Would you like to enable DHCP for %s?"), interface)) {
1052         case 1:
1053                 asprintf(&string, "ifconfig_%s", interface);
1054
1055                 cmds = commands_new();
1056                 cmd = command_add(cmds, "%s%s dhclient",
1057                     a->os_root, cmd_name(a, "KILLALL"));
1058                 command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
1059                 command_add(cmds, "%s%s %s",
1060                     a->os_root, cmd_name(a, "DHCLIENT"),
1061                     interface);
1062                 if (commands_execute(a, cmds)) {
1063                         /* XXX sleep(3); */
1064                         show_ifconfig(a->c, interface);
1065                         write_config = 1;
1066                 } else {
1067                         switch (dfui_be_present_dialog(a->c, _("DHCP Failure"),
1068                             _("Yes|No"),
1069                             _("Warning: could not enable dhclient for %s.\n\n"
1070                               "Write the corresponding settings to rc.conf "
1071                               "anyway?"), interface)) {
1072                         case 1:
1073                                 write_config = 1;
1074                                 break;
1075                         case 2:
1076                                 write_config = 0;
1077                                 break;
1078                         default:
1079                                 abort_backend();
1080                         }
1081                 }
1082                 commands_free(cmds);
1083                 config_var_set(rc_conf, string, "DHCP");
1084                 free(string);
1085                 break;
1086         case 2:
1087                 dfui_form_free(f);
1088                 dfui_response_free(r);
1089                 f = dfui_form_create(
1090                     "assign_ip",
1091                     _("Assign IP Address"),
1092                     _("Configuring Interface:"),
1093                     "",
1094
1095                     "f", "interface_ip", _("IP Address"),
1096                     _("Enter the IP Address you would like to use"), "",
1097                     "f", "interface_netmask",   _("Netmask"),
1098                     _("Enter the netmask of the IP address"), "",
1099                     "f", "defaultrouter", _("Default Router"),
1100                     _("Enter the IP address of the default router"), "",
1101                     "f", "dns_resolver", _("Primary DNS Server"),
1102                     _("Enter the IP address of primary DNS Server"), "",
1103                     "f", "hostname", _("Hostname"),
1104                     _("Enter the Hostname"), "",
1105                     "f", "domain", _("Domain"),
1106                     _("Enter the Domain Name"), "",
1107
1108                     "a", "ok", _("Configure Interface"),
1109                     "", "",
1110                     "a", "cancel", _("Return to Utilities Menu"),
1111                     "", "",
1112                     "p", "accelerator", "ESC",
1113
1114                     NULL
1115                 );
1116
1117                 ds = dfui_dataset_new();
1118                 dfui_dataset_celldata_add(ds, "interface_netmask", "");
1119                 dfui_dataset_celldata_add(ds, "defaultrouter", "");
1120                 dfui_dataset_celldata_add(ds, "dns_resolver", "");
1121                 dfui_dataset_celldata_add(ds, "hostname", "");
1122                 dfui_dataset_celldata_add(ds, "domain", "");
1123                 dfui_dataset_celldata_add(ds, "interface_ip", "");
1124                 dfui_form_dataset_add(f, ds);
1125
1126                 if (!dfui_be_present(a->c, f, &r))
1127                         abort_backend();
1128
1129                 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
1130                         new_ds = dfui_response_dataset_get_first(r);
1131
1132                         interface_ip = dfui_dataset_get_value(new_ds, "interface_ip");
1133                         interface_netmask = dfui_dataset_get_value(new_ds, "interface_netmask");
1134                         defaultrouter = dfui_dataset_get_value(new_ds, "defaultrouter");
1135                         dns_resolver = dfui_dataset_get_value(new_ds, "dns_resolver");
1136                         hostname = dfui_dataset_get_value(new_ds, "hostname");
1137                         domain = dfui_dataset_get_value(new_ds, "domain");
1138
1139                         asprintf(&string, "ifconfig_%s", interface);
1140                         asprintf(&string1, "inet %s netmask %s",
1141                             interface_ip, interface_netmask);
1142
1143                         cmds = commands_new();
1144                         command_add(cmds, "%s%s %s %s netmask %s",
1145                             a->os_root, cmd_name(a, "IFCONFIG"),
1146                             interface, interface_ip, interface_netmask);
1147                         command_add(cmds, "%s%s add default %s",
1148                             a->os_root, cmd_name(a, "ROUTE"),
1149                             defaultrouter);
1150
1151                         if (commands_execute(a, cmds)) {
1152                                 /* XXX sleep(3); */
1153                                 show_ifconfig(a->c, interface);
1154                                 write_config = 1;
1155                         } else {
1156                                 switch (dfui_be_present_dialog(a->c,
1157                                     _("ifconfig Failure"),
1158                                     _("Yes|No"),
1159                                     _("Warning: could not assign IP address "
1160                                       "or default gateway.\n\n"
1161                                       "Write the corresponding settings to "
1162                                       "rc.conf anyway?"))) {
1163                                 case 1:
1164                                         write_config = 1;
1165                                         break;
1166                                 case 2:
1167                                         write_config = 0;
1168                                         break;
1169                                 default:
1170                                         abort_backend();
1171                                 }
1172                         }
1173                         commands_free(cmds);
1174
1175                         config_var_set(rc_conf, string, string1);
1176                         config_var_set(rc_conf, "defaultrouter", defaultrouter);
1177
1178                         free(string);
1179                         free(string1);
1180
1181                         asprintf(&string, "%s.%s", hostname, domain);
1182                         config_var_set(rc_conf, "hostname", string);
1183                         free(string);
1184
1185                         config_var_set(resolv_conf, "search", domain);
1186                         config_var_set(resolv_conf, "nameserver", dns_resolver);
1187                 }
1188                 break;
1189         default:
1190                 abort_backend();
1191         }
1192
1193         if (write_config) {
1194                 /*
1195                  * Save out changes to /etc/rc.conf and /etc/resolv.conf.
1196                  */
1197                 config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
1198                     "%s%setc/resolv.conf", a->os_root, a->cfg_root);
1199         }
1200
1201         config_vars_free(resolv_conf);
1202
1203         dfui_form_free(f);
1204         dfui_response_free(r);
1205 }
1206
1207 static const char *
1208 yes_to_y(const char *value)
1209 {
1210         return(strcasecmp(value, "YES") == 0 ? "Y" : "N");
1211 }
1212
1213 void
1214 fn_select_services(struct i_fn_args *a)
1215 {
1216         struct dfui_dataset *ds;
1217         struct dfui_form *f;
1218         struct dfui_response *r;
1219
1220         if (!config_vars_read(a, rc_conf, CONFIG_TYPE_SH, "%s%setc/rc.conf",
1221                 a->os_root, a->cfg_root)) {
1222                 inform(a->c, _("Couldn't read %s%setc/rc.conf."),
1223                     a->os_root, a->cfg_root);
1224                 a->result = 0;
1225                 return;
1226         }
1227
1228         f = dfui_form_create(
1229             "select_services",
1230             _("Select Services"),
1231             _("Please select which services you would like started at boot time."),
1232             "",
1233
1234             "f", "syslogd", "syslogd",
1235                 _("System Logging Daemon"), "",
1236                 "p", "control", "checkbox",
1237             "f", "inetd", "inetd",
1238                 _("Internet Super-Server"), "",
1239                 "p", "control", "checkbox",
1240             "f", "named", "named",
1241                 _("BIND Name Server"), "",
1242                 "p", "control", "checkbox",
1243             "f", "ntpd", "ntpd",
1244                 _("Network Time Protocol Daemon"), "",
1245                 "p", "control", "checkbox",
1246             "f", "sshd", "sshd",
1247                 _("Secure Shell Daemon"), "",
1248                 "p", "control", "checkbox",
1249
1250             "a", "ok", _("Enable/Disable Services"),
1251                 "", "",
1252             "a", "cancel", _("Return to Utilities Menu"),
1253                 "", "",
1254                 "p", "accelerator", "ESC",
1255
1256             NULL
1257         );
1258
1259         ds = dfui_dataset_new();
1260         dfui_dataset_celldata_add(ds, "syslogd",
1261             yes_to_y(config_var_get(rc_conf, "syslogd_enable")));
1262         dfui_dataset_celldata_add(ds, "inetd",
1263             yes_to_y(config_var_get(rc_conf, "inetd_enable")));
1264         dfui_dataset_celldata_add(ds, "named",
1265             yes_to_y(config_var_get(rc_conf, "named_enable")));
1266         dfui_dataset_celldata_add(ds, "ntpd",
1267             yes_to_y(config_var_get(rc_conf, "ntpd_enable")));
1268         dfui_dataset_celldata_add(ds, "sshd",
1269             yes_to_y(config_var_get(rc_conf, "sshd_enable")));
1270         dfui_form_dataset_add(f, ds);
1271
1272         if (!dfui_be_present(a->c, f, &r))
1273                 abort_backend();
1274
1275         if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1276                 dfui_form_free(f);
1277                 dfui_response_free(r);
1278                 return;
1279         }
1280
1281         dfui_form_free(f);
1282         dfui_response_free(r);
1283 }
1284
1285 /*** NON-fn_ FUNCTIONS ***/
1286
1287 /*
1288  * Caller is responsible for deallocation.
1289  */
1290 static char *
1291 convert_tmpfs_options(char *line)
1292 {
1293         char *result, *word;
1294         int i;
1295
1296         result = malloc(256);
1297         result[0] = '\0';
1298
1299         for (; (word = strsep(&line, ",")) != NULL; ) {
1300                 if (word[0] == '-') {
1301                         /*
1302                          * Don't bother trying to honour the -C
1303                          * option, since we can't copy files from
1304                          * the right place anyway.
1305                          */
1306                         if (strcmp(word, "-C") != 0) {
1307                                 for (i = 0; word[i] != '\0'; i++) {
1308                                         if (word[i] == '=')
1309                                                 word[i] = ' ';
1310                                 }
1311                                 strlcat(result, word, 256);
1312                                 strlcat(result, " ", 256);
1313                         }
1314                 }
1315         }
1316
1317         return(result);
1318 }
1319
1320 /*
1321  * Uses ss->selected_{disk,slice} as the target system.
1322  */
1323 int
1324 mount_target_system(struct i_fn_args *a)
1325 {
1326         FILE *crypttab, *fstab;
1327         struct commands *cmds;
1328         struct command *cmd;
1329         struct subpartition *a_subpart;
1330         char name[256], device[256], mtpt[256], fstype[256], options[256];
1331         char *filename, line[256];
1332         const char *try_mtpt[5]  = {"/var", "/tmp", "/usr", "/home", NULL};
1333         char *word, *cvtoptions;
1334         int i;
1335
1336         /*
1337          * Mount subpartitions from this installation if they are
1338          * not already mounted.  Tricky, as we need to honour the
1339          * installation's loader.conf and fstab.
1340          */
1341         cmds = commands_new();
1342
1343         /*
1344          * First, unmount anything already mounted on /mnt.
1345          */
1346         unmount_all_under(a, cmds, "%smnt", a->os_root);
1347
1348         /*
1349          * Reset and clear out subpartitions so that system
1350          * can make a "dummy" subpart.
1351          */
1352         subpartitions_free(storage_get_selected_slice(a->s));
1353
1354         /*
1355          * Create a temporary dummy subpartition - that we
1356          * assume exists
1357          */
1358
1359         a_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s),
1360             "/dummy", 0, 0, 0, 0, 0, 0);
1361
1362         /*
1363          * Mount the target's / and read its /etc/fstab.
1364          */
1365         if (use_hammer == 0) {
1366                 command_add(cmds, "%s%s %sdev/%s %s%s",
1367                     a->os_root, cmd_name(a, "MOUNT"),
1368                     a->os_root,
1369                     subpartition_get_device_name(a_subpart),
1370                     a->os_root, a->cfg_root);
1371                 cmd = command_add(cmds,
1372                     "%s%s -f %st2;"
1373                     "%s%s \"^[^#]\" %s%s/etc/crypttab >%st2",
1374                     a->os_root, cmd_name(a, "RM"), a->tmp,
1375                     a->os_root, cmd_name(a, "GREP"),
1376                     a->os_root, a->cfg_root, a->tmp);
1377                 command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
1378         } else {
1379                 command_add(cmds, "%s%s %sdev/%s %sboot",
1380                     a->os_root, cmd_name(a, "MOUNT"),
1381                     a->os_root,
1382                     subpartition_get_device_name(a_subpart),
1383                     a->os_root);
1384                 cmd = command_add(cmds,
1385                     "%s%s -f %st2;"
1386                     "%s%s \"^vfs\\.root\\.realroot=\" %sboot/loader.conf >%st2",
1387                     a->os_root, cmd_name(a, "RM"), a->tmp,
1388                     a->os_root, cmd_name(a, "GREP"),
1389                     a->os_root, a->tmp);
1390                 command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
1391         }
1392         if (!commands_execute(a, cmds)) {
1393                 commands_free(cmds);
1394                 return(0);
1395         }
1396         commands_free(cmds);
1397         cmds = commands_new();
1398
1399         if (use_hammer) {
1400                 struct stat sb = { .st_size = 0 };
1401                 stat("/tmp/t2", &sb);
1402                 if (sb.st_size > 0) {
1403                         command_add(cmds, "%s%s %sboot",
1404                             a->os_root, cmd_name(a, "UMOUNT"),
1405                             a->os_root);
1406                         fn_get_passphrase(a);
1407                         command_add(cmds,
1408                             "%s%s -d /tmp/t1 luksOpen %sdev/`%s%s \"^vfs\\.root\\.realroot=\" %st2 |"
1409                             "%s%s -Fhammer: '{print $2;}' |"
1410                             "%s%s -F: '{print $1;}'` root",
1411                             a->os_root, cmd_name(a, "CRYPTSETUP"),
1412                             a->os_root,
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 %sdev/mapper/root %s%s",
1419                             a->os_root, cmd_name(a, "MOUNT_HAMMER"),
1420                             a->os_root,
1421                             a->os_root, a->cfg_root);
1422                 } else {
1423                         command_add(cmds,
1424                             "%s%s %sdev/`%s%s \"^vfs\\.root\\.mountfrom\" %sboot/loader.conf |"
1425                             "%s%s -Fhammer: '{print $2;}' |"
1426                             "%s%s 's/\"//'` %s%s",
1427                             a->os_root, cmd_name(a, "MOUNT_HAMMER"),
1428                             a->os_root,
1429                             a->os_root, cmd_name(a, "GREP"),
1430                             a->os_root,
1431                             a->os_root, cmd_name(a, "AWK"),
1432                             a->os_root, cmd_name(a, "SED"),
1433                             a->os_root, a->cfg_root);
1434                         command_add(cmds, "%s%s %sboot",
1435                             a->os_root, cmd_name(a, "UMOUNT"),
1436                             a->os_root);
1437                 }
1438         }
1439         if (!commands_execute(a, cmds)) {
1440                 commands_free(cmds);
1441                 return(0);
1442         }
1443         commands_free(cmds);
1444         cmds = commands_new();
1445
1446         /*
1447          * Get rid of the dummy subpartition.
1448          */
1449         subpartitions_free(storage_get_selected_slice(a->s));
1450
1451         /*
1452          * See if an /etc/crypttab exists.
1453          */
1454         asprintf(&filename, "%s%s/etc/crypttab", a->os_root, a->cfg_root);
1455         crypttab = fopen(filename, "r");
1456         free(filename);
1457         if (crypttab != NULL) {
1458                 if (!use_hammer)
1459                         fn_get_passphrase(a);
1460                 while (fgets(line, 256, crypttab) != NULL) {
1461                         /*
1462                          * Parse the crypttab line.
1463                          */
1464                         if (first_non_space_char_is(line, '#'))
1465                                 continue;
1466                         if ((word = strtok(line, " \t")) == NULL)
1467                                 continue;
1468                         strlcpy(name, word, 256);
1469                         if (strcmp(name, "swap") == 0)
1470                                 continue;
1471                         if ((word = strtok(NULL, " \t")) == NULL)
1472                                 continue;
1473                         strlcpy(device, word, 256);
1474
1475                         command_add(cmds,
1476                             "%s%s -d /tmp/t1 luksOpen %s %s",
1477                             a->os_root, cmd_name(a, "CRYPTSETUP"),
1478                             device, name);
1479
1480                         continue;
1481                 }
1482                 fclose(crypttab);
1483         }
1484         if (!commands_execute(a, cmds)) {
1485                 commands_free(cmds);
1486                 return(0);
1487         }
1488         commands_free(cmds);
1489
1490         asprintf(&filename, "%s%s/etc/fstab", a->os_root, a->cfg_root);
1491         fstab = fopen(filename, "r");
1492         free(filename);
1493         if (fstab == NULL) {
1494                 inform(a->c, _("Filesystem table on installed system could not be read."));
1495                 cmds = commands_new();
1496                 command_add(cmds, "%s%s %s%s",
1497                     a->os_root, cmd_name(a, "UMOUNT"),
1498                     a->os_root, a->cfg_root);
1499                 if (!commands_execute(a, cmds)) {
1500                         inform(a->c, _("Warning: Installed system was not properly unmounted."));
1501                 }
1502                 commands_free(cmds);
1503                 return(0);
1504         }
1505
1506         cmds = commands_new();
1507
1508         while (fgets(line, 256, fstab) != NULL) {
1509                 /*
1510                  * Parse the fstab line.
1511                  */
1512                 if (first_non_space_char_is(line, '#'))
1513                         continue;
1514                 if ((word = strtok(line, " \t")) == NULL)
1515                         continue;
1516                 strlcpy(device, word, 256);
1517                 if ((word = strtok(NULL, " \t")) == NULL)
1518                         continue;
1519                 strlcpy(mtpt, word, 256);
1520                 if ((word = strtok(NULL, " \t")) == NULL)
1521                         continue;
1522                 strlcpy(fstype, word, 256);
1523                 if ((word = strtok(NULL, " \t")) == NULL)
1524                         continue;
1525                 strlcpy(options, word, 256);
1526
1527                 /*
1528                  * Now, if the mountpoint has /usr, /var, /tmp, or /home
1529                  * as a prefix, mount it under a->cfg_root.
1530                  */
1531                 for (i = 0; try_mtpt[i] != NULL; i++) {
1532                         if (strstr(mtpt, try_mtpt[i]) == mtpt) {
1533                                 /*
1534                                  * Don't mount it if it's optional.
1535                                  */
1536                                 if (strstr(options, "noauto") != NULL)
1537                                         continue;
1538
1539                                 /*
1540                                  * Don't mount it if device doesn't start
1541                                  * with /dev/ or /pfs and it isn't 'tmpfs'.
1542                                  */
1543                                 if (strstr(device, "/dev/") != NULL &&
1544                                      strstr(device, "/pfs/") != NULL &&
1545                                      strcmp(device, "tmpfs") != 0)
1546                                         continue;
1547
1548                                 /*
1549                                  * If the device is 'tmpfs', mount_tmpfs it instead.
1550                                  */
1551                                 if (strcmp(device, "tmpfs") == 0) {
1552                                         cvtoptions = convert_tmpfs_options(options);
1553                                         command_add(cmds,
1554                                             "%s%s %s tmpfs %s%s%s",
1555                                             a->os_root, cmd_name(a, "MOUNT_TMPFS"),
1556                                             cvtoptions, a->os_root, a->cfg_root, mtpt);
1557                                         free(cvtoptions);
1558                                 } else {
1559                                         if (use_hammer == 0) {
1560                                                 command_add(cmds,
1561                                                     "%s%s -o %s %s%s %s%s%s",
1562                                                     a->os_root, cmd_name(a, "MOUNT"),
1563                                                     options,
1564                                                     a->os_root, device, a->os_root,
1565                                                     a->cfg_root, mtpt);
1566                                         } else {
1567                                                 command_add(cmds,
1568                                                     "%s%s -o %s %s%s%s %s%s%s",
1569                                                     a->os_root, cmd_name(a, "MOUNT_NULL"),
1570                                                     options,
1571                                                     a->os_root, a->cfg_root, device,
1572                                                     a->os_root, a->cfg_root, mtpt);
1573                                         }
1574                                 }
1575                         }
1576                 }
1577         }
1578         fclose(fstab);
1579
1580         if (!commands_execute(a, cmds)) {
1581                 commands_free(cmds);
1582                 return(0);
1583         }
1584         commands_free(cmds);
1585
1586         return(1);
1587 }