nrelease - gui - Change window manager, cpdup additional directories
[dragonfly.git] / usr.sbin / installer / dfuibe_installer / fn_configure.c
1 /*
2  * Copyright (c)2004 The DragonFly Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  *   Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in
13  *   the documentation and/or other materials provided with the
14  *   distribution.
15  *
16  *   Neither the name of the DragonFly Project nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 /*
35  * fn_configure.c
36  * Configuration functions for installer.
37  * This includes both Configure the LiveCD Environment, and
38  * Configure an Installed System (there is considerable overlap.)
39  * $Id: fn_configure.c,v 1.82 2005/03/25 05:24:00 cpressey Exp $
40  */
41
42 #include <sys/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_tmpfs_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_install_packages(struct i_fn_args *a)
341 {
342         FILE *pipe;
343         struct commands *cmds;
344         struct dfui_celldata *cd;
345         struct dfui_dataset *ds;
346         struct dfui_field *fi;
347         struct dfui_form *f;
348         struct dfui_response *r;
349         char command[256];
350         char pkg_name[256];
351         char msg_buf[1][1024];
352         struct aura_dict *seen;
353
354         snprintf(msg_buf[0], sizeof(msg_buf[0]),
355             _("Select optional software packages that you want "
356             "installed on this system.  This form lists only the "
357             "software packages installed on the LiveCD; thousands "
358             "more are available via the internet once %s "
359             "is installed."),
360             OPERATING_SYSTEM_NAME);
361
362         f = dfui_form_create(
363             "install_packages",
364             _("Install Packages"),
365             msg_buf[0],
366             "",
367
368             "p", "special", "dfinstaller_install_packages",
369
370             NULL
371         );
372
373         ds = dfui_dataset_new();
374         snprintf(command, 256, "ls %svar/db/pkg", a->os_root);
375         if ((pipe = popen(command, "r")) != NULL) {
376                 while (fgets(pkg_name, 255, pipe) != NULL) {
377                         while (strlen(pkg_name) > 0 &&
378                                isspace(pkg_name[strlen(pkg_name) - 1])) {
379                                 pkg_name[strlen(pkg_name) - 1] = '\0';
380                         }
381                         fi = dfui_form_field_add(f, pkg_name,
382                             dfui_info_new(pkg_name, "", ""));
383                         dfui_field_property_set(fi, "control", "checkbox");
384                         dfui_dataset_celldata_add(ds,
385                             pkg_name, "Y");
386                 }
387                 pclose(pipe);
388         }
389         dfui_form_dataset_add(f, ds);
390
391         dfui_form_action_add(f, "ok",
392             dfui_info_new(_("Accept and Install"), "", ""));
393         dfui_form_action_add(f, "cancel",
394             dfui_info_new(_("Return to Configure Menu"), "", ""));
395
396         if (!dfui_be_present(a->c, f, &r))
397                 abort_backend();
398
399         if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
400                 cmds = commands_new();
401                 seen = aura_dict_new(23, AURA_DICT_HASH);
402
403                 cd = dfui_dataset_celldata_get_first(dfui_response_dataset_get_first(r));
404
405                 while (cd != NULL) {
406                         strlcpy(pkg_name, dfui_celldata_get_field_id(cd), 256);
407                         if (!strcasecmp(dfui_celldata_get_value(cd), "Y")) {
408                                 if (!pkg_copy(a, cmds, pkg_name, seen)) {
409                                         inform(a->c, _("Couldn't install package `%s'."), pkg_name);
410                                         break;
411                                 }
412                         }
413                         cd = dfui_celldata_get_next(cd);
414                 }
415
416                 if (!commands_execute(a, cmds)) {
417                         inform(a->c, _("Packages were not fully installed."));
418                 } else {
419                         inform(a->c, _("Packages were successfully installed!"));
420                 }
421
422                 aura_dict_free(seen);
423                 commands_free(cmds);
424         }
425
426         dfui_form_free(f);
427         dfui_response_free(r);
428 }
429
430 void
431 fn_remove_packages(struct i_fn_args *a)
432 {
433         FILE *pipe;
434         struct commands *cmds;
435         struct dfui_celldata *cd;
436         struct dfui_dataset *ds;
437         struct dfui_field *fi;
438         struct dfui_form *f;
439         struct dfui_response *r;
440         char command[256];
441         char pkg_name[256];
442         struct aura_dict *seen;
443
444         f = dfui_form_create(
445             "remove_packages",
446             _("Remove Packages"),
447             _("Select the installed software packages that you want "
448             "removed from this system."),
449             "",
450
451             "p", "special", "dfinstaller_remove_packages",
452
453             NULL
454         );
455
456         ds = dfui_dataset_new();
457         snprintf(command, 256, "ls %smnt/var/db/pkg", a->os_root);
458         if ((pipe = popen(command, "r")) != NULL) {
459                 while (fgets(pkg_name, 255, pipe)) {
460                         pkg_name[strlen(pkg_name) - 1] = '\0';
461                         fi = dfui_form_field_add(f, pkg_name,
462                             dfui_info_new(pkg_name, "", ""));
463                         dfui_field_property_set(fi, "control", "checkbox");
464                         dfui_dataset_celldata_add(ds,
465                             pkg_name, "N");
466                 }
467                 pclose(pipe);
468         }
469         dfui_form_dataset_add(f, ds);
470
471         dfui_form_action_add(f, "ok",
472             dfui_info_new(_("Accept and Remove"), "", ""));
473         dfui_form_action_add(f, "cancel",
474             dfui_info_new(_("Return to Configure Menu"), "", ""));
475
476         if (!dfui_be_present(a->c, f, &r))
477                 abort_backend();
478
479         if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
480                 cmds = commands_new();
481                 seen = aura_dict_new(23, AURA_DICT_HASH);
482
483                 cd = dfui_dataset_celldata_get_first(dfui_response_dataset_get_first(r));
484
485                 while (cd != NULL) {
486                         strlcpy(pkg_name, dfui_celldata_get_field_id(cd), 256);
487                         if (!strcasecmp(dfui_celldata_get_value(cd), "Y")) {
488                                 if (!pkg_remove(a, cmds, pkg_name, seen)) {
489                                         inform(a->c, _("Couldn't remove package `%s'."), pkg_name);
490                                         break;
491                                 }
492                         }
493                         cd = dfui_celldata_get_next(cd);
494                 }
495
496                 if (!commands_execute(a, cmds)) {
497                         inform(a->c, _("Packages were not fully removed."));
498                 } else {
499                         inform(a->c, _("Packages were successfully removed."));
500                 }
501
502                 aura_dict_free(seen);
503                 commands_free(cmds);
504         }
505
506         dfui_form_free(f);
507         dfui_response_free(r);
508 }
509
510 /** LIVECD UTILITIES FUNCTIONS **/
511
512 /*
513  * String returned by this function must be deallocated by the caller.
514  */
515 char *
516 fn_select_file(const char *title, const char *desc, const char *help, const char *cancel,
517                const char *dir, const char *ext, const struct i_fn_args *a)
518 {
519         DIR *d;
520         struct dfui_form *f;
521         struct dfui_action *k;
522         struct dfui_response *r;
523         struct dirent *de;
524         char *s;
525         struct aura_dict *dict;
526         char *rk;
527         size_t rk_len;
528
529         f = dfui_form_create(
530             "select_file",
531             title, desc, help,
532             "p", "role", "menu",
533             NULL
534         );
535
536         dict = aura_dict_new(1, AURA_DICT_SORTED_LIST);
537         d = opendir(dir);
538         while ((de = readdir(d)) != NULL) {
539                 if (strcmp(de->d_name, ".") == 0 ||
540                     strcmp(de->d_name, "..") == 0 ||
541                     strstr(de->d_name, ext) == NULL)
542                         continue;
543                 aura_dict_store(dict, de->d_name, strlen(de->d_name) + 1, "", 1);
544         }
545         closedir(d);
546
547         aura_dict_rewind(dict);
548         while (!aura_dict_eof(dict)) {
549                 aura_dict_get_current_key(dict, (void **)&rk, &rk_len),
550                 dfui_form_action_add(f, rk,
551                     dfui_info_new(rk, "", ""));
552                 aura_dict_next(dict);
553         }
554         aura_dict_free(dict);
555
556         k = dfui_form_action_add(f, "cancel",
557             dfui_info_new(cancel, "", ""));
558         dfui_action_property_set(k, "accelerator", "ESC");
559
560         if (!dfui_be_present(a->c, f, &r))
561                 abort_backend();
562
563         s = aura_strdup(dfui_response_get_action_id(r));
564
565         dfui_form_free(f);
566         dfui_response_free(r);
567
568         return(s);
569 }
570
571 void
572 fn_set_kbdmap(struct i_fn_args *a)
573 {
574         struct commands *cmds;
575         char *s;
576         char filename[256], keymapname[256];
577
578         s = fn_select_file(_("Select Keyboard Map"),
579             _("Select a keyboard map appropriate to your keyboard layout."),
580             "", _("Return to Utilities Menu"), "/usr/share/syscons/keymaps",
581             ".kbd", a);
582
583         if (strcmp(s, "cancel") != 0) {
584                 cmds = commands_new();
585                 command_add(cmds, "%s%s -l "
586                     "/usr/share/syscons/keymaps/%s < /dev/ttyv0",
587                     a->os_root, cmd_name(a, "KBDCONTROL"),
588                     s);
589                 if (commands_execute(a, cmds)) {
590                         snprintf(filename, 256, "/usr/share/syscons/keymaps/%s", s);
591                         snprintf(keymapname, 256, filename_noext(basename(filename)));
592                         config_var_set(rc_conf, "keymap", keymapname);
593                 } else {
594                         inform(a->c, _("Keyboard map not successfully set."));
595                 }
596                 commands_free(cmds);
597         }
598
599         free(s);
600 }
601
602 void
603 fn_set_vidfont(struct i_fn_args *a)
604 {
605         struct commands *cmds;
606         char *s;
607         char filename[256], variable[256], fontname[256];
608         int by = 0;
609
610
611         s = fn_select_file(_("Select Console Font"),
612             _("Select a font appropriate to your video monitor and language."),
613             "", _("Return to Utilities Menu"), "/usr/share/syscons/fonts",
614             ".fnt", a);
615
616         if (strcmp(s, "cancel") != 0) {
617                 cmds = commands_new();
618                 command_add(cmds, "%s%s -f "
619                     "/usr/share/syscons/fonts/%s < /dev/ttyv0",
620                     a->os_root, cmd_name(a, "VIDCONTROL"),
621                     s);
622                 if (commands_execute(a, cmds)) {
623                         if (strstr(s, "8x16") != NULL)
624                                 by = 16;
625                         else if (strstr(s, "8x14") != NULL)
626                                 by = 14;
627                         else
628                                 by = 8;
629
630                         snprintf(variable, 256, "font8x%d", by);
631                         snprintf(filename, 256, "/usr/share/syscons/fonts/%s", s);
632                         snprintf(fontname, 256, filename_noext(basename(filename)));
633                         config_var_set(rc_conf, variable, fontname);
634
635                 } else {
636                         inform(a->c, _("Video font not successfully set."));
637                 }
638                 commands_free(cmds);
639         }
640
641         free(s);
642 }
643
644 void
645 fn_set_scrnmap(struct i_fn_args *a)
646 {
647         struct commands *cmds;
648         char *s;
649         char filename[256], scrnmapname[256];
650
651         s = fn_select_file(_("Select Screen Map"),
652             _("Select a mapping for translating characters as they appear "
653             "on your video console screen."),
654             "", _("Return to Utilities Menu"), "/usr/share/syscons/scrnmaps",
655             ".scm", a);
656
657         if (strcmp(s, "cancel") != 0) {
658                 cmds = commands_new();
659                 command_add(cmds, "%s%s -l "
660                     "/usr/share/syscons/scrnmaps/%s < /dev/ttyv0",
661                     a->os_root, cmd_name(a, "VIDCONTROL"),
662                     s);
663                 if (commands_execute(a, cmds)) {
664                         snprintf(filename, 256, "/usr/share/syscons/scrnmaps/%s", s);
665                         snprintf(scrnmapname, 256, filename_noext(basename(filename)));
666                         config_var_set(rc_conf, "scrnmap", scrnmapname);
667                 } else {
668                         inform(a->c, _("Video font not successfully set."));
669                 }
670                 commands_free(cmds);
671         }
672         free(s);
673 }
674
675 void
676 fn_set_timezone(struct i_fn_args *a)
677 {
678         struct commands *cmds;
679         char *s = NULL;
680         char current_path[256], selection[256], temp[256];
681         int found_file = 0;
682
683         cmds = commands_new();
684
685         switch (dfui_be_present_dialog(a->c, _("Local or UTC (Greenwich Mean Time) clock"),
686             _("Yes|No"),
687             _("Is this machine's CMOS clock set to UTC?\n"),
688             _("If it is set to local time, or you don't know, please choose NO here!"))) {
689                 case 1:
690                         cmds = commands_new();
691                         command_add(cmds, "%s%s %s%setc/wall_cmos_clock",
692                             a->os_root, cmd_name(a, "TOUCH"),
693                             a->os_root, a->cfg_root);
694                         commands_execute(a, cmds);
695         }
696
697         snprintf(current_path, 256, "%s%susr/share/zoneinfo",
698             a->os_root, a->cfg_root);
699         while (!found_file) {
700                 if (s != NULL)
701                         free(s);
702                 s = fn_select_file(_("Select Time Zone"),
703                     _("Select a Time Zone appropriate to your physical location."),
704                     "", _("Return to Utilities Menu"), current_path,
705                     "", a);
706                 if (is_dir("%s/%s", current_path, s)) {
707                         snprintf(temp, 256, "%s/%s", current_path, s);
708                         strlcpy(current_path, temp, 256);
709                 } else {
710                         if (is_file("%s/%s", current_path, s)) {
711                                 snprintf(selection, 256, "%s/%s", current_path, s);
712                                 found_file = 1;
713                         }
714                         if (strcmp(s, "cancel") == 0) {
715                                 strlcpy(selection, "cancel", 256);
716                                 found_file = 1;
717                         }
718                 }
719         }
720         free(s);
721
722         if (strcmp(selection, "cancel") != 0) {
723                 command_add(cmds, "%s%s %s %s%setc/localtime",
724                     a->os_root, cmd_name(a, "CP"),
725                     selection,
726                     a->os_root, a->cfg_root);
727                 if (commands_execute(a, cmds))
728                         inform(a->c, _("The Time Zone has been set to %s."), selection);
729         }
730         commands_free(cmds);
731 }
732
733 void
734 fn_assign_datetime(struct i_fn_args *a)
735 {
736         struct commands *cmds;
737         struct dfui_dataset *ds, *new_ds;
738         struct dfui_form *f;
739         struct dfui_response *r;
740         struct tm *tp;
741         char temp[256];
742         int year, month, dayofmonth, hour, minutes;
743         int valid = 1;
744         time_t now;
745
746         now = time(NULL);
747         tp = localtime(&now);
748
749         f = dfui_form_create(
750             "set_datetime",
751             _("Set Time/Date"),
752             _("Enter the current time and date."),
753             "",
754
755             "f", "year", _("Enter year"),
756             _("Enter the current year (e.g. `2004')"), "",
757             "f", "month", _("Month"),
758             _("Enter the current month (e.g. `07')"), "",
759             "f", "dayofmonth", "dayofmonth",
760             _("Enter the current day of month (e.g. `30')"), "",
761             "f", "hour", "hour",
762             _("Enter the current hour (e.g. `07')"), "",
763             "f", "minutes", "minutes",
764             _("Enter the current minutes (e.g. `59')"), "",
765
766             "a", "ok", _("OK"), "", "",
767             "a", "cancel", _("Cancel"), "", "",
768             "p", "accelerator", "ESC",
769
770             NULL
771         );
772
773         ds = dfui_dataset_new();
774         snprintf(temp, 256, "%i", (tp->tm_year+1900));
775         dfui_dataset_celldata_add(ds, "year", temp);
776         snprintf(temp, 256, "%i", (tp->tm_mon+1));
777         dfui_dataset_celldata_add(ds, "month", temp);
778         snprintf(temp, 256, "%i", tp->tm_mday);
779         dfui_dataset_celldata_add(ds, "dayofmonth", temp);
780         snprintf(temp, 256, "%i", tp->tm_hour);
781         dfui_dataset_celldata_add(ds, "hour", temp);
782         snprintf(temp, 256, "%i", tp->tm_min);
783         dfui_dataset_celldata_add(ds, "minutes", temp);
784         dfui_form_dataset_add(f, ds);
785
786         if (!dfui_be_present(a->c, f, &r))
787                 abort_backend();
788
789         if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
790                 new_ds = dfui_response_dataset_get_first(r);
791
792                 if ((year = atoi(dfui_dataset_get_value(new_ds, "year"))) <= 0)
793                         valid = 0;
794                 month = atoi(dfui_dataset_get_value(new_ds, "month"));
795                 if (month < 1 || month > 12)
796                         valid = 0;
797                 dayofmonth = atoi(dfui_dataset_get_value(new_ds, "dayofmonth"));
798                 if (dayofmonth < 1 || dayofmonth > 31)
799                         valid = 0;
800                 hour = atoi(dfui_dataset_get_value(new_ds, "hour"));
801                 if (hour < 0 || hour > 23)
802                         valid = 0;
803                 minutes = atoi(dfui_dataset_get_value(new_ds, "minutes"));
804                 if (minutes < 0 || minutes > 59)
805                         valid = 0;
806
807                 if (valid) {
808                         cmds = commands_new();
809                         command_add(cmds, "%s%s -n %04d%02d%02d%02d%02d",
810                             a->os_root, cmd_name(a, "DATE"),
811                             year, month, dayofmonth, hour, minutes);
812                         if (commands_execute(a, cmds)) {
813                                 inform(a->c, _("The date and time have been set."));
814                         }
815                         commands_free(cmds);
816                 } else {
817                         inform(a->c, _("Please enter numbers within acceptable ranges "
818                                 "for year, month, day of month, hour, and minute."));
819                 }
820         }
821 }
822
823 void
824 fn_assign_hostname_domain(struct i_fn_args *a)
825 {
826         struct dfui_form *f;
827         struct dfui_response *r;
828         struct dfui_dataset *ds, *new_ds;
829         struct config_vars *resolv_conf;
830         const char *domain, *hostname;
831         char *fqdn;
832
833         f = dfui_form_create(
834             "set_hostname_domain",
835             _("Set Hostname/Domain"),
836             _("Please enter this machine's hostname and domain name."),
837             "",
838
839             "f", "hostname", _("Hostname"),
840             _("Enter the Hostname (e.g. `machine')"), "",
841             "f", "domain", _("Domain"),
842             _("Enter the Domain Name (e.g. `network.lan')"), "",
843
844             "a", "ok", _("OK"), "", "",
845             "a", "cancel", _("Cancel"), "", "",
846             "p", "accelerator", "ESC",
847
848             NULL
849         );
850
851         ds = dfui_dataset_new();
852         dfui_dataset_celldata_add(ds, "hostname", "");
853         dfui_dataset_celldata_add(ds, "domain", "");
854         dfui_form_dataset_add(f, ds);
855
856         if (!dfui_be_present(a->c, f, &r))
857                 abort_backend();
858
859         if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
860                 new_ds = dfui_response_dataset_get_first(r);
861
862                 hostname = dfui_dataset_get_value(new_ds, "hostname");
863                 domain = dfui_dataset_get_value(new_ds, "domain");
864                 if (strlen(domain) == 0)
865                         asprintf(&fqdn, "%s", hostname);
866                 else
867                         asprintf(&fqdn, "%s.%s", hostname, domain);
868
869                 resolv_conf = config_vars_new();
870
871                 config_var_set(rc_conf, "hostname", fqdn);
872                 config_var_set(resolv_conf, "search", domain);
873                 config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
874                     "%s%setc/resolv.conf", "/", a->cfg_root);
875
876                 config_vars_free(resolv_conf);
877
878                 free(fqdn);
879         }
880
881         dfui_form_free(f);
882         dfui_response_free(r);
883 }
884
885 void
886 fn_assign_ip(struct i_fn_args *a)
887 {
888         FILE *p;
889         struct commands *cmds;
890         struct command *cmd;
891         struct config_vars *resolv_conf;
892         struct dfui_dataset *ds, *new_ds;
893         struct dfui_form *f;
894         struct dfui_action *k;
895         struct dfui_response *r;
896         const char *domain, *hostname;
897         const char *interface_ip, *interface_netmask, *defaultrouter, *dns_resolver;
898         char *string, *string1;
899         char *word;
900         char interface[256];
901         char line[256];
902         int write_config = 0;
903
904         /*
905          * Get interface list.
906          */
907         p = popen("/sbin/ifconfig -l", "r");
908         /* XXX it's possible (though extremely unlikely) this will fail. */
909         while (fgets(line, 255, p) != NULL)
910                 line[strlen(line) - 1] = '\0';
911
912         pclose(p);
913
914         f = dfui_form_create(
915             "assign_ip",
916             _("Assign IP Address"),
917             _("Please select which interface you would like to configure:"),
918             "",
919             "p",        "role", "menu",
920             NULL
921         );
922
923         /* Loop through array. */
924         word = strtok(line, " \t");
925         while (word != NULL) {
926                 dfui_form_action_add(f, word,
927                     dfui_info_new(word, "", ""));
928                 word = strtok(NULL, " ");
929         }
930
931         k = dfui_form_action_add(f, "cancel",
932             dfui_info_new("Cancel", "", ""));
933         dfui_action_property_set(k, "accelerator", "ESC");
934
935         if (!dfui_be_present(a->c, f, &r))
936                 abort_backend();
937
938         if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
939                 dfui_form_free(f);
940                 dfui_response_free(r);
941                 return;
942         }
943
944         strlcpy(interface, dfui_response_get_action_id(r), 256);
945
946         resolv_conf = config_vars_new();
947
948         switch (dfui_be_present_dialog(a->c, _("Use DHCP?"),
949             _("Use DHCP|Configure Manually"),
950             _("DHCP allows the interface to automatically obtain "
951             "an IP address from a nearby DHCP server.\n\n"
952             "Would you like to enable DHCP for %s?"), interface)) {
953         case 1:
954                 asprintf(&string, "ifconfig_%s", interface);
955
956                 cmds = commands_new();
957                 cmd = command_add(cmds, "%s%s dhclient",
958                     a->os_root, cmd_name(a, "KILLALL"));
959                 command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
960                 command_add(cmds, "%s%s %s",
961                     a->os_root, cmd_name(a, "DHCLIENT"),
962                     interface);
963                 if (commands_execute(a, cmds)) {
964                         /* XXX sleep(3); */
965                         show_ifconfig(a->c, interface);
966                         write_config = 1;
967                 } else {
968                         switch (dfui_be_present_dialog(a->c, _("DHCP Failure"),
969                             _("Yes|No"),
970                             _("Warning: could not enable dhclient for %s.\n\n"
971                               "Write the corresponding settings to rc.conf "
972                               "anyway?"), interface)) {
973                         case 1:
974                                 write_config = 1;
975                                 break;
976                         case 2:
977                                 write_config = 0;
978                                 break;
979                         default:
980                                 abort_backend();
981                         }
982                 }
983                 commands_free(cmds);
984                 config_var_set(rc_conf, string, "DHCP");
985                 free(string);
986                 break;
987         case 2:
988                 dfui_form_free(f);
989                 dfui_response_free(r);
990                 f = dfui_form_create(
991                     "assign_ip",
992                     _("Assign IP Address"),
993                     _("Configuring Interface:"),
994                     "",
995
996                     "f", "interface_ip", _("IP Address"),
997                     _("Enter the IP Address you would like to use"), "",
998                     "f", "interface_netmask",   _("Netmask"),
999                     _("Enter the netmask of the IP address"), "",
1000                     "f", "defaultrouter", _("Default Router"),
1001                     _("Enter the IP address of the default router"), "",
1002                     "f", "dns_resolver", _("Primary DNS Server"),
1003                     _("Enter the IP address of primary DNS Server"), "",
1004                     "f", "hostname", _("Hostname"),
1005                     _("Enter the Hostname"), "",
1006                     "f", "domain", _("Domain"),
1007                     _("Enter the Domain Name"), "",
1008
1009                     "a", "ok", _("Configure Interface"),
1010                     "", "",
1011                     "a", "cancel", _("Return to Utilities Menu"),
1012                     "", "",
1013                     "p", "accelerator", "ESC",
1014
1015                     NULL
1016                 );
1017
1018                 ds = dfui_dataset_new();
1019                 dfui_dataset_celldata_add(ds, "interface_netmask", "");
1020                 dfui_dataset_celldata_add(ds, "defaultrouter", "");
1021                 dfui_dataset_celldata_add(ds, "dns_resolver", "");
1022                 dfui_dataset_celldata_add(ds, "hostname", "");
1023                 dfui_dataset_celldata_add(ds, "domain", "");
1024                 dfui_dataset_celldata_add(ds, "interface_ip", "");
1025                 dfui_form_dataset_add(f, ds);
1026
1027                 if (!dfui_be_present(a->c, f, &r))
1028                         abort_backend();
1029
1030                 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
1031                         new_ds = dfui_response_dataset_get_first(r);
1032
1033                         interface_ip = dfui_dataset_get_value(new_ds, "interface_ip");
1034                         interface_netmask = dfui_dataset_get_value(new_ds, "interface_netmask");
1035                         defaultrouter = dfui_dataset_get_value(new_ds, "defaultrouter");
1036                         dns_resolver = dfui_dataset_get_value(new_ds, "dns_resolver");
1037                         hostname = dfui_dataset_get_value(new_ds, "hostname");
1038                         domain = dfui_dataset_get_value(new_ds, "domain");
1039
1040                         asprintf(&string, "ifconfig_%s", interface);
1041                         asprintf(&string1, "inet %s netmask %s",
1042                             interface_ip, interface_netmask);
1043
1044                         cmds = commands_new();
1045                         command_add(cmds, "%s%s %s %s netmask %s",
1046                             a->os_root, cmd_name(a, "IFCONFIG"),
1047                             interface, interface_ip, interface_netmask);
1048                         command_add(cmds, "%s%s add default %s",
1049                             a->os_root, cmd_name(a, "ROUTE"),
1050                             defaultrouter);
1051
1052                         if (commands_execute(a, cmds)) {
1053                                 /* XXX sleep(3); */
1054                                 show_ifconfig(a->c, interface);
1055                                 write_config = 1;
1056                         } else {
1057                                 switch (dfui_be_present_dialog(a->c,
1058                                     _("ifconfig Failure"),
1059                                     _("Yes|No"),
1060                                     _("Warning: could not assign IP address "
1061                                       "or default gateway.\n\n"
1062                                       "Write the corresponding settings to "
1063                                       "rc.conf anyway?"))) {
1064                                 case 1:
1065                                         write_config = 1;
1066                                         break;
1067                                 case 2:
1068                                         write_config = 0;
1069                                         break;
1070                                 default:
1071                                         abort_backend();
1072                                 }
1073                         }
1074                         commands_free(cmds);
1075
1076                         config_var_set(rc_conf, string, string1);
1077                         config_var_set(rc_conf, "defaultrouter", defaultrouter);
1078
1079                         free(string);
1080                         free(string1);
1081
1082                         asprintf(&string, "%s.%s", hostname, domain);
1083                         config_var_set(rc_conf, "hostname", string);
1084                         free(string);
1085
1086                         config_var_set(resolv_conf, "search", domain);
1087                         config_var_set(resolv_conf, "nameserver", dns_resolver);
1088                 }
1089                 break;
1090         default:
1091                 abort_backend();
1092         }
1093
1094         if (write_config) {
1095                 /*
1096                  * Save out changes to /etc/rc.conf and /etc/resolv.conf.
1097                  */
1098                 config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
1099                     "%s%setc/resolv.conf", a->os_root, a->cfg_root);
1100         }
1101
1102         config_vars_free(resolv_conf);
1103
1104         dfui_form_free(f);
1105         dfui_response_free(r);
1106 }
1107
1108 static const char *
1109 yes_to_y(const char *value)
1110 {
1111         return(strcasecmp(value, "YES") == 0 ? "Y" : "N");
1112 }
1113
1114 void
1115 fn_select_services(struct i_fn_args *a)
1116 {
1117         struct dfui_dataset *ds;
1118         struct dfui_form *f;
1119         struct dfui_response *r;
1120
1121         if (!config_vars_read(a, rc_conf, CONFIG_TYPE_SH, "%setc/rc.conf", a->cfg_root)) {
1122                 inform(a->c, _("Couldn't read %s%setc/rc.conf."),
1123                     a->os_root, a->cfg_root);
1124                 a->result = 0;
1125                 return;
1126         }
1127
1128         f = dfui_form_create(
1129             "select_services",
1130             _("Select Services"),
1131             _("Please select which services you would like started at boot time."),
1132             "",
1133
1134             "f", "syslogd", "syslogd",
1135                 _("System Logging Daemon"), "",
1136                 "p", "control", "checkbox",
1137             "f", "inetd", "inetd",
1138                 _("Internet Super-Server"), "",
1139                 "p", "control", "checkbox",
1140             "f", "named", "named",
1141                 _("BIND Name Server"), "",
1142                 "p", "control", "checkbox",
1143             "f", "ntpd", "ntpd",
1144                 _("Network Time Protocol Daemon"), "",
1145                 "p", "control", "checkbox",
1146             "f", "sshd", "sshd",
1147                 _("Secure Shell Daemon"), "",
1148                 "p", "control", "checkbox",
1149
1150             "a", "ok", _("Enable/Disable Services"),
1151                 "", "",
1152             "a", "cancel", _("Return to Utilities Menu"),
1153                 "", "",
1154                 "p", "accelerator", "ESC",
1155
1156             NULL
1157         );
1158
1159         ds = dfui_dataset_new();
1160         dfui_dataset_celldata_add(ds, "syslogd",
1161             yes_to_y(config_var_get(rc_conf, "syslogd_enable")));
1162         dfui_dataset_celldata_add(ds, "inetd",
1163             yes_to_y(config_var_get(rc_conf, "inetd_enable")));
1164         dfui_dataset_celldata_add(ds, "named",
1165             yes_to_y(config_var_get(rc_conf, "named_enable")));
1166         dfui_dataset_celldata_add(ds, "ntpd",
1167             yes_to_y(config_var_get(rc_conf, "ntpd_enable")));
1168         dfui_dataset_celldata_add(ds, "sshd",
1169             yes_to_y(config_var_get(rc_conf, "sshd_enable")));
1170         dfui_form_dataset_add(f, ds);
1171
1172         if (!dfui_be_present(a->c, f, &r))
1173                 abort_backend();
1174
1175         if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1176                 dfui_form_free(f);
1177                 dfui_response_free(r);
1178                 return;
1179         }
1180
1181         dfui_form_free(f);
1182         dfui_response_free(r);
1183 }
1184
1185 /*** NON-fn_ FUNCTIONS ***/
1186
1187 /*
1188  * Caller is responsible for deallocation.
1189  */
1190 static char *
1191 convert_tmpfs_options(char *line)
1192 {
1193         char *result, *word;
1194         int i;
1195
1196         result = malloc(256);
1197         result[0] = '\0';
1198
1199         for (; (word = strsep(&line, ",")) != NULL; ) {
1200                 if (word[0] == '-') {
1201                         /*
1202                          * Don't bother trying to honour the -C
1203                          * option, since we can't copy files from
1204                          * the right place anyway.
1205                          */
1206                         if (strcmp(word, "-C") != 0) {
1207                                 for (i = 0; word[i] != '\0'; i++) {
1208                                         if (word[i] == '=')
1209                                                 word[i] = ' ';
1210                                 }
1211                                 strlcat(result, word, 256);
1212                                 strlcat(result, " ", 256);
1213                         }
1214                 }
1215         }
1216
1217         return(result);
1218 }
1219
1220 /*
1221  * Uses ss->selected_{disk,slice} as the target system.
1222  */
1223 int
1224 mount_target_system(struct i_fn_args *a)
1225 {
1226         FILE *fstab;
1227         struct commands *cmds;
1228         struct subpartition *a_subpart;
1229         char device[256], mtpt[256], fstype[256], options[256];
1230         char *filename, line[256];
1231         const char *try_mtpt[5]  = {"/var", "/tmp", "/usr", "/home", NULL};
1232         char *word, *cvtoptions;
1233         int i;
1234
1235         /*
1236          * Mount subpartitions from this installation if they are
1237          * not already mounted.  Tricky, as we need to honour the
1238          * installation's loader.conf and fstab.
1239          */
1240         cmds = commands_new();
1241
1242         /*
1243          * First, unmount anything already mounted on /mnt.
1244          */
1245         unmount_all_under(a, cmds, "%smnt", a->os_root);
1246
1247         /*
1248          * Reset and clear out subpartitions so that system
1249          * can make a "dummy" subpart.
1250          */
1251         subpartitions_free(storage_get_selected_slice(a->s));
1252
1253         /*
1254          * Create a temporary dummy subpartition - that we
1255          * assume exists
1256          */
1257
1258         a_subpart = subpartition_new(storage_get_selected_slice(a->s),
1259             "/dummy", 0, 0, 0, 0, 0);
1260
1261         /*
1262          * Mount the target's / and read its /etc/fstab.
1263          */
1264         if (use_hammer == 0) {
1265                 command_add(cmds, "%s%s %sdev/%s %s%s",
1266                     a->os_root, cmd_name(a, "MOUNT"),
1267                     a->os_root,
1268                     subpartition_get_device_name(a_subpart),
1269                     a->os_root, a->cfg_root);
1270         } else {
1271                 command_add(cmds, "%s%s %sdev/%s %sboot",
1272                     a->os_root, cmd_name(a, "MOUNT"),
1273                     a->os_root,
1274                     subpartition_get_device_name(a_subpart),
1275                     a->os_root, a->cfg_root);
1276                 command_add(cmds,
1277                     "%s%s %sdev/`%s%s \"^vfs\\.root\\.mountfrom\" %sboot/loader.conf |"
1278                     "%s%s -Fhammer: '{print $2;}' |"
1279                     "%s%s 's/\"//'` %s%s",
1280                     a->os_root, cmd_name(a, "MOUNT_HAMMER"),
1281                     a->os_root,
1282                     a->os_root, cmd_name(a, "GREP"),
1283                     a->os_root,
1284                     a->os_root, cmd_name(a, "AWK"),
1285                     a->os_root, cmd_name(a, "SED"),
1286                     a->os_root, a->cfg_root);
1287                 command_add(cmds, "%s%s %sboot",
1288                     a->os_root, cmd_name(a, "UMOUNT"),
1289                     a->os_root, a->cfg_root);
1290         }
1291         if (!commands_execute(a, cmds)) {
1292                 commands_free(cmds);
1293                 return(0);
1294         }
1295         commands_free(cmds);
1296
1297         /*
1298          * Get rid of the dummy subpartition.
1299          */
1300         subpartitions_free(storage_get_selected_slice(a->s));
1301
1302         asprintf(&filename, "%s%s/etc/fstab", a->os_root, a->cfg_root);
1303         fstab = fopen(filename, "r");
1304         free(filename);
1305         if (fstab == NULL) {
1306                 inform(a->c, _("Filesystem table on installed system could not be read."));
1307                 cmds = commands_new();
1308                 command_add(cmds, "%s%s %s%s",
1309                     a->os_root, cmd_name(a, "UMOUNT"),
1310                     a->os_root, a->cfg_root);
1311                 if (!commands_execute(a, cmds)) {
1312                         inform(a->c, _("Warning: Installed system was not properly unmounted."));
1313                 }
1314                 commands_free(cmds);
1315                 return(0);
1316         }
1317
1318         cmds = commands_new();
1319
1320         while (fgets(line, 256, fstab) != NULL) {
1321                 /*
1322                  * Parse the fstab line.
1323                  */
1324                 if (first_non_space_char_is(line, '#'))
1325                         continue;
1326                 if ((word = strtok(line, " \t")) == NULL)
1327                         continue;
1328                 strlcpy(device, word, 256);
1329                 if ((word = strtok(NULL, " \t")) == NULL)
1330                         continue;
1331                 strlcpy(mtpt, word, 256);
1332                 if ((word = strtok(NULL, " \t")) == NULL)
1333                         continue;
1334                 strlcpy(fstype, word, 256);
1335                 if ((word = strtok(NULL, " \t")) == NULL)
1336                         continue;
1337                 strlcpy(options, word, 256);
1338
1339                 /*
1340                  * Now, if the mountpoint has /usr, /var, /tmp, or /home
1341                  * as a prefix, mount it under a->cfg_root.
1342                  */
1343                 for (i = 0; try_mtpt[i] != NULL; i++) {
1344                         if (strstr(mtpt, try_mtpt[i]) == mtpt) {
1345                                 /*
1346                                  * Don't mount it if it's optional.
1347                                  */
1348                                 if (strstr(options, "noauto") != NULL)
1349                                         continue;
1350
1351                                 /*
1352                                  * Don't mount it if device doesn't start
1353                                  * with /dev/ or /pfs and it isn't 'tmpfs'.
1354                                  */
1355                                 if (strstr(device, "/dev/") != NULL &&
1356                                      strstr(device, "/pfs/") != NULL &&
1357                                      strcmp(device, "tmpfs") != 0)
1358                                         continue;
1359
1360                                 /*
1361                                  * If the device is 'tmpfs', mount_tmpfs it instead.
1362                                  */
1363                                 if (strcmp(device, "tmpfs") == 0) {
1364                                         cvtoptions = convert_tmpfs_options(options);
1365                                         command_add(cmds,
1366                                             "%s%s %s tmpfs %s%s%s",
1367                                             a->os_root, cmd_name(a, "MOUNT_TMPFS"),
1368                                             cvtoptions, a->os_root, a->cfg_root, mtpt);
1369                                         free(cvtoptions);
1370                                 } else {
1371                                         if (use_hammer == 0) {
1372                                                 command_add(cmds,
1373                                                     "%s%s -o %s %s%s %s%s%s",
1374                                                     a->os_root, cmd_name(a, "MOUNT"),
1375                                                     options,
1376                                                     a->os_root, device, a->os_root,
1377                                                     a->cfg_root, mtpt);
1378                                         } else {
1379                                                 command_add(cmds,
1380                                                     "%s%s -o %s %s%s%s %s%s%s",
1381                                                     a->os_root, cmd_name(a, "MOUNT_NULL"),
1382                                                     options,
1383                                                     a->os_root, a->cfg_root, device, a->os_root,
1384                                                     a->cfg_root, mtpt);
1385                                         }
1386                                 }
1387                         }
1388                 }
1389         }
1390         fclose(fstab);
1391
1392         if (!commands_execute(a, cmds)) {
1393                 commands_free(cmds);
1394                 return(0);
1395         }
1396         commands_free(cmds);
1397
1398         return(1);
1399 }