Add HAMMER support to the installer
[dragonfly.git] / contrib / bsdinstaller-1.1.6 / src / backend / 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/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                 if (commands_execute(a, cmds)) {
978                         /* XXX sleep(3); */
979                         show_ifconfig(a->c, interface);
980                         write_config = 1;
981                 } else {
982                         switch (dfui_be_present_dialog(a->c, _("DHCP Failure"),
983                             _("Yes|No"),
984                             _("Warning: could not enable dhclient for %s.\n\n"
985                               "Write the corresponding settings to rc.conf "
986                               "anyway?"), interface)) {
987                         case 1:
988                                 write_config = 1;
989                                 break;
990                         case 2:
991                                 write_config = 0;
992                                 break;
993                         default:
994                                 abort_backend();
995                         }
996                 }
997                 commands_free(cmds);
998                 asprintf(&string, "ifconfig_%s", interface);
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 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 - for the benefit of ensure_dev et al.
1271          */
1272         
1273         a_subpart = subpartition_new(storage_get_selected_slice(a->s),
1274             "/dummy", 0, 0, 0, 0, 0);
1275
1276         /*
1277          * Ensure that the devices we'll be using exist.
1278          */
1279         command_add_ensure_dev(a, cmds,
1280             disk_get_device_name(storage_get_selected_disk(a->s)));
1281         command_add_ensure_dev(a, cmds,
1282             slice_get_device_name(storage_get_selected_slice(a->s)));
1283         command_add_ensure_dev(a, cmds,
1284             subpartition_get_device_name(a_subpart));
1285
1286         /*
1287          * Mount the target's / and read its /etc/fstab.
1288          */
1289         if (use_hammer == 0) {
1290                 command_add(cmds, "%s%s %sdev/%s %s%s",
1291                     a->os_root, cmd_name(a, "MOUNT"),
1292                     a->os_root,
1293                     subpartition_get_device_name(a_subpart),
1294                     a->os_root, a->cfg_root);
1295         } else {
1296                 command_add(cmds, "%s%s %sdev/%s %s%s",
1297                     a->os_root, cmd_name(a, "MOUNT_HAMMER"),
1298                     a->os_root,
1299                     subpartition_get_device_name(a_subpart),
1300                     a->os_root, a->cfg_root);
1301         }
1302         if (!commands_execute(a, cmds)) {
1303                 commands_free(cmds);
1304                 return(0);
1305         }
1306         commands_free(cmds);
1307
1308         /*
1309          * Get rid of the dummy subpartition.
1310          */
1311         subpartitions_free(storage_get_selected_slice(a->s));
1312
1313         asprintf(&filename, "%s%s/etc/fstab", a->os_root, a->cfg_root);
1314         fstab = fopen(filename, "r");
1315         free(filename);
1316         if (fstab == NULL) {
1317                 inform(a->c, _("Filesystem table on installed system could not be read."));
1318                 cmds = commands_new();
1319                 command_add(cmds, "%s%s %s%s",
1320                     a->os_root, cmd_name(a, "UMOUNT"),
1321                     a->os_root, a->cfg_root);
1322                 if (!commands_execute(a, cmds)) {
1323                         inform(a->c, _("Warning: Installed system was not properly unmounted."));
1324                 }
1325                 commands_free(cmds);
1326                 return(0);
1327         }
1328
1329         cmds = commands_new();
1330
1331         while (fgets(line, 256, fstab) != NULL) {
1332                 /*
1333                  * Parse the fstab line.
1334                  */
1335                 if (first_non_space_char_is(line, '#'))
1336                         continue;
1337                 if ((word = strtok(line, " \t")) == NULL)
1338                         continue;
1339                 strlcpy(device, word, 256);
1340                 if ((word = strtok(NULL, " \t")) == NULL)
1341                         continue;
1342                 strlcpy(mtpt, word, 256);
1343                 if ((word = strtok(NULL, " \t")) == NULL)
1344                         continue;
1345                 strlcpy(fstype, word, 256);
1346                 if ((word = strtok(NULL, " \t")) == NULL)
1347                         continue;
1348                 strlcpy(options, word, 256);
1349
1350                 /*
1351                  * Now, if the mountpoint has /usr, /var, /tmp, or /home
1352                  * as a prefix, mount it under a->cfg_root.
1353                  */
1354                 for (i = 0; try_mtpt[i] != NULL; i++) {
1355                         if (strstr(mtpt, try_mtpt[i]) == mtpt) {
1356                                 /*
1357                                  * Don't mount it if it's optional.
1358                                  */
1359                                 if (strstr(options, "noauto") != NULL)
1360                                         continue;
1361
1362                                 /*
1363                                  * Don't mount it if device doesn't start
1364                                  * with /dev/ and it isn't 'swap'.
1365                                  */
1366                                 if (strstr(device, "/dev/") == NULL &&
1367                                     strcmp(device, "swap") != 0)
1368                                         continue;
1369
1370                                 /*
1371                                  * If the device is 'swap', mount_mfs it instead.
1372                                  */
1373                                 if (strcmp(device, "swap") == 0) {
1374                                         cvtoptions = convert_swap_options(options);
1375                                         command_add(cmds,
1376                                             "%s%s %s swap %s%s%s",
1377                                             a->os_root, cmd_name(a, "MOUNT_MFS"),
1378                                             cvtoptions, a->os_root, a->cfg_root, mtpt);
1379                                         free(cvtoptions);
1380                                 } else {
1381                                         if (use_hammer == 0 ||
1382                                             (use_hammer == 1 && strcmp(mtpt, "/boot/") == 0)) {
1383                                                 command_add_ensure_dev(a, cmds, device);
1384                                                 command_add(cmds,
1385                                                     "%s%s -o %s %s%s %s%s%s",
1386                                                     a->os_root, cmd_name(a, "MOUNT"),
1387                                                     options,    /* XXX */
1388                                                     a->os_root, device, a->os_root,
1389                                                     a->cfg_root, mtpt);
1390                                         } else {
1391                                                 command_add_ensure_dev(a, cmds, device);
1392                                                 command_add(cmds,
1393                                                     "%s%s %s%s %s%s%s",
1394                                                     a->os_root, cmd_name(a, "MOUNT_HAMMER"),
1395                                                     a->os_root, device, a->os_root,
1396                                                     a->cfg_root, mtpt);
1397                                         }
1398                                 }
1399                         }
1400                 }
1401         }
1402         fclose(fstab);
1403
1404         if (!commands_execute(a, cmds)) {
1405                 commands_free(cmds);
1406                 return(0);
1407         }
1408         commands_free(cmds);
1409
1410         return(1);
1411 }