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