dhcpcd: update README.DRAGONFLY
[dragonfly.git] / usr.sbin / installer / dfuibe_installer / fn_configure.c
blob3db5d4a7086ae88a0f3c817e88d0b024fa813c20
1 /*
2 * Copyright (c)2004,2015 The DragonFly Project. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
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 $
42 #include <sys/stat.h>
43 #include <sys/types.h>
45 #include <ctype.h>
46 #include <dirent.h>
47 #include <fcntl.h>
48 #include <libgen.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <time.h>
54 #include <unistd.h>
56 #ifdef ENABLE_NLS
57 #include <libintl.h>
58 #define _(String) gettext (String)
59 #else
60 #define _(String) (String)
61 #endif
63 #include "libaura/mem.h"
64 #include "libaura/dict.h"
65 #include "libaura/fspred.h"
67 #include "libdfui/dfui.h"
68 #include "libdfui/system.h"
70 #include "libinstaller/commands.h"
71 #include "libinstaller/confed.h"
72 #include "libinstaller/diskutil.h"
73 #include "libinstaller/functions.h"
74 #include "libinstaller/uiutil.h"
76 #include "fn.h"
77 #include "flow.h"
78 #include "pathnames.h"
80 struct config_vars *rc_conf;
82 static const char *yes_to_y(const char *);
84 /** CONFIGURE FUNCTIONS **/
86 #define GECOS_NOT_ALLOWED ":,\\\""
87 #define FILENAME_NOT_ALLOWED ":;`~!#$^&*()={}[]\\|?<>'\" "
88 #define MEMBERSHIPS_NOT_ALLOWED ":;`~!@#$%^&*()+={}[]\\|/?<>'\" "
89 #define USERNAME_NOT_ALLOWED (MEMBERSHIPS_NOT_ALLOWED ",")
91 void
92 fn_add_user(struct i_fn_args *a)
94 struct dfui_dataset *ds, *new_ds;
95 struct dfui_form *f;
96 struct dfui_response *r;
97 struct commands *cmds;
98 struct command *cmd;
99 const char *username, *home, *passwd_1, *passwd_2, *gecos;
100 const char *shell, *uid, *group, *groups;
101 const char *passwd_env = "passwd";
102 int done = 0;
104 f = dfui_form_create(
105 "add_user",
106 _("Add user"),
107 _("Here you can add a user to an installed system.\n\n"
108 "You can leave the Home Directory, User ID, and Login Group "
109 "fields empty if you want these items to be automatically "
110 "allocated by the system."),
112 "f", "username", _("Username"),
113 _("Enter the username the user will log in as"), "",
114 "f", "gecos", _("Real Name"),
115 _("Enter the real name (or GECOS field) of this user"), "",
116 "f", "passwd_1", _("Password"),
117 _("Enter the user's password (will not be displayed)"), "",
118 "p", "obscured", "true",
119 "f", "passwd_2", _("Password (Again)"),
120 _("Re-enter the user's password to confirm"), "",
121 "p", "obscured", "true",
122 "f", "shell", _("Shell"),
123 _("Enter the full path to the user's shell program"), "",
124 "f", "home", _("Home Directory"),
125 _("Enter the full path to the user's home directory, or leave blank"), "",
126 "f", "uid", _("User ID"),
127 _("Enter this account's numeric user id, or leave blank"), "",
128 "f", "group", _("Login Group"),
129 _("Enter the primary group for this account, or leave blank"), "",
130 "f", "groups", _("Other Group Memberships"),
131 _("Enter a comma-separated list of other groups "
132 "that this user should belong to"), "",
133 "a", "ok", _("Accept and Add"), "", "",
134 "a", "cancel", _("Return to Configure Menu"), "", "",
135 "p", "accelerator", "ESC",
136 NULL
139 ds = dfui_dataset_new();
140 dfui_dataset_celldata_add(ds, "username", "");
141 dfui_dataset_celldata_add(ds, "gecos", "");
142 dfui_dataset_celldata_add(ds, "passwd_1", "");
143 dfui_dataset_celldata_add(ds, "passwd_2", "");
144 dfui_dataset_celldata_add(ds, "shell", "/bin/tcsh");
145 dfui_dataset_celldata_add(ds, "home", "");
146 dfui_dataset_celldata_add(ds, "uid", "");
147 dfui_dataset_celldata_add(ds, "group", "");
148 dfui_dataset_celldata_add(ds, "groups", "");
149 dfui_form_dataset_add(f, ds);
151 while (!done) {
152 if (!dfui_be_present(a->c, f, &r))
153 abort_backend();
155 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
156 done = 1;
157 dfui_response_free(r);
158 break;
161 new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r));
162 dfui_form_datasets_free(f);
163 dfui_form_dataset_add(f, new_ds);
165 /* Fetch form field values. */
167 username = dfui_dataset_get_value(new_ds, "username");
168 home = dfui_dataset_get_value(new_ds, "home");
169 gecos = dfui_dataset_get_value(new_ds, "gecos");
170 shell = dfui_dataset_get_value(new_ds, "shell");
171 passwd_1 = dfui_dataset_get_value(new_ds, "passwd_1");
172 passwd_2 = dfui_dataset_get_value(new_ds, "passwd_2");
173 uid = dfui_dataset_get_value(new_ds, "uid");
174 group = dfui_dataset_get_value(new_ds, "group");
175 groups = dfui_dataset_get_value(new_ds, "groups");
177 if (strlen(username) == 0) {
178 inform(a->c, _("You must enter a username."));
179 done = 0;
180 } else if (strcmp(passwd_1, passwd_2) != 0) {
181 inform(a->c, _("The passwords do not match."));
182 done = 0;
183 } else if (!assert_clean(a->c, _("Username"), username, USERNAME_NOT_ALLOWED) ||
184 !assert_clean(a->c, _("Real Name"), gecos, GECOS_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, USERNAME_NOT_ALLOWED) ||
188 !assert_clean(a->c, _("Login Group"), group, USERNAME_NOT_ALLOWED) ||
189 !assert_clean(a->c, _("Group Memberships"), groups, MEMBERSHIPS_NOT_ALLOWED)) {
190 done = 0;
191 } else if (setenv(passwd_env, passwd_1, 1) != 0) {
192 inform(a->c, _("setenv() failed."));
193 done = 0;
194 } else if (!is_program("%s%s", a->os_root, shell) &&
195 strcmp(shell, "/nonexistent") != 0) {
196 inform(a->c, _("Chosen shell does not exist on the system."));
197 done = 0;
198 } else {
199 cmds = commands_new();
201 command_add(cmds, "%s%s %smnt/ /%s useradd "
202 "'%s' %s%s %s%s -c \"%s\" %s%s -s %s %s%s %s",
203 a->os_root, cmd_name(a, "CHROOT"),
204 a->os_root, cmd_name(a, "PW"),
205 username,
206 strlen(uid) == 0 ? "" : "-u ", uid,
207 strlen(group) == 0 ? "" : "-g ", group,
208 gecos,
209 strlen(home) == 0 ? "" : "-d ", home,
210 shell,
211 strlen(groups) == 0 ? "" : "-G ", groups,
212 (strlen(home) == 0 || !is_dir("%s", home)) ?
213 "-m -k /usr/share/skel" : "");
215 cmd = command_add(cmds, "%s%s \"$%s\" | "
216 "%s%s %smnt/ /%s usermod '%s' -h 0",
217 a->os_root, cmd_name(a, "ECHO"),
218 passwd_env,
219 a->os_root, cmd_name(a, "CHROOT"),
220 a->os_root, cmd_name(a, "PW"),
221 username);
222 command_set_desc(cmd, _("Setting password..."));
224 if (commands_execute(a, cmds)) {
225 inform(a->c, _("User `%s' was added."), username);
226 done = 1;
227 } else {
228 inform(a->c, _("User was not successfully added."));
229 done = 0;
232 unsetenv(passwd_env);
233 commands_free(cmds);
236 dfui_response_free(r);
239 dfui_form_free(f);
242 void
243 fn_root_passwd(struct i_fn_args *a)
245 struct dfui_dataset *ds, *new_ds;
246 struct dfui_form *f;
247 struct dfui_response *r;
248 struct commands *cmds;
249 struct command *cmd;
250 const char *root_passwd_1, *root_passwd_2;
251 const char *passwd_env = "passwd";
252 int done = 0;
254 f = dfui_form_create(
255 "root_passwd",
256 _("Set Root Password"),
257 _("Here you can set the super-user (root) password."),
260 "f", "root_passwd_1", _("Root password"),
261 _("Enter the root password you would like to use"), "",
262 "p", "obscured", "true",
263 "f", "root_passwd_2", _("Root password again"),
264 _("Enter the root password again to confirm"), "",
265 "p", "obscured", "true",
267 "a", "ok", _("Accept and Set Password"), "", "",
268 "a", "cancel", _("Return to Configure Menu"), "", "",
269 "p", "accelerator", "ESC",
271 NULL
274 ds = dfui_dataset_new();
275 dfui_dataset_celldata_add(ds, "root_passwd_1", "");
276 dfui_dataset_celldata_add(ds, "root_passwd_2", "");
277 dfui_form_dataset_add(f, ds);
279 while (!done) {
280 if (!dfui_be_present(a->c, f, &r))
281 abort_backend();
283 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
284 done = 1;
285 dfui_response_free(r);
286 break;
289 new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r));
290 dfui_form_datasets_free(f);
291 dfui_form_dataset_add(f, new_ds);
293 root_passwd_1 = dfui_dataset_get_value(new_ds, "root_passwd_1");
294 root_passwd_2 = dfui_dataset_get_value(new_ds, "root_passwd_2");
296 if (strlen(root_passwd_1) == 0) {
297 inform(a->c, _("You must enter a password."));
298 done = 0;
299 } else if (strcmp(root_passwd_1, root_passwd_2) != 0) {
300 inform(a->c, _("The passwords do not match."));
301 done = 0;
302 } else if (setenv(passwd_env, root_passwd_1, 1) != 0) {
303 inform(a->c, _("setenv() failed."));
304 done = 0;
305 } else {
306 cmds = commands_new();
307 cmd = command_add(cmds, "%s%s \"$%s\" | "
308 "%s%s %smnt/ /%s usermod root -h 0",
309 a->os_root, cmd_name(a, "ECHO"),
310 passwd_env,
311 a->os_root, cmd_name(a, "CHROOT"),
312 a->os_root, cmd_name(a, "PW"));
313 command_set_desc(cmd, _("Setting password..."));
314 if (commands_execute(a, cmds)) {
315 inform(a->c, _("The root password has been changed."));
316 done = 1;
317 } else {
318 inform(a->c, _("An error occurred when "
319 "setting the root password."));
320 done = 0;
322 unsetenv(passwd_env);
323 commands_free(cmds);
326 dfui_response_free(r);
329 dfui_form_free(f);
332 void
333 fn_get_passphrase(struct i_fn_args *a, int confirm)
335 struct dfui_dataset *ds, *new_ds;
336 struct dfui_form *f;
337 struct dfui_response *r;
338 const char *passphrase_1, *passphrase_2;
339 int fd;
340 int done = 0;
342 if (confirm) {
343 f = dfui_form_create(
344 "crypt_passphrase",
345 _("Set Passphrase for Encryption"),
346 _("Please specify the passphrase to be used for the encrypted "
347 "filesystems.\n\n"
348 "Please note that in the LiveCD environment the keymap is "
349 "set to \"US ISO\". "
350 "If you prefer a different keymap for entering the passphrase "
351 "here, you will need to set it manually using kbdcontrol(1)."),
354 "f", "passphrase_1", _("Passphrase"),
355 _("Enter the passphrase you would like to use for encryption"), "",
356 "p", "obscured", "true",
357 "f", "passphrase_2", _("Passphrase again"),
358 _("Enter the passphrase again to confirm"), "",
359 "p", "obscured", "true",
361 "a", "ok", _("Accept and Set Passphrase"), "", "",
362 "p", "accelerator", "ESC",
364 NULL
366 } else {
367 f = dfui_form_create(
368 "crypt_passphrase",
369 _("Specify Decryption Passphrase"),
370 _("Please enter the passphrase to decrypt and mount the "
371 "filesystems.\n\n"
372 "Please note that in the LiveCD environment the keymap is "
373 "set to \"US ISO\". "
374 "If you prefer a different keymap for entering the passphrase "
375 "here, you will need to set it manually using kbdcontrol(1)."),
378 "f", "passphrase_1", _("Passphrase"),
379 _("Enter the passphrase"), "",
380 "p", "obscured", "true",
382 "a", "ok", _("OK"), "", "",
383 "p", "accelerator", "ESC",
385 NULL
389 ds = dfui_dataset_new();
390 dfui_dataset_celldata_add(ds, "passphrase_1", "");
391 if (confirm)
392 dfui_dataset_celldata_add(ds, "passphrase_2", "");
393 dfui_form_dataset_add(f, ds);
395 while (!done) {
396 if (!dfui_be_present(a->c, f, &r))
397 abort_backend();
399 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
400 new_ds = dfui_dataset_dup(dfui_response_dataset_get_first(r));
401 dfui_form_datasets_free(f);
402 dfui_form_dataset_add(f, new_ds);
405 * Fetch form field values.
408 passphrase_1 = dfui_dataset_get_value(new_ds, "passphrase_1");
409 passphrase_2 = passphrase_1;
410 if (confirm)
411 passphrase_2 = dfui_dataset_get_value(new_ds, "passphrase_2");
413 if (strlen(passphrase_1) == 0 && strlen(passphrase_2) == 0) {
414 done = 0;
415 } else if (strcmp(passphrase_1, passphrase_2) == 0) {
417 * Passphrases match, write it out.
419 fd = open("/tmp/t1", O_RDWR | O_CREAT | O_TRUNC,
420 S_IRUSR);
421 if (fd != -1) {
422 write(fd, passphrase_1, strlen(passphrase_1));
423 close(fd);
424 done = 1;
425 } else {
426 inform(a->c, _("write() error"));
427 done = 0;
429 } else {
431 * Passphrases don't match, tell the user,
432 * let them try again.
434 inform(a->c, _("The passphrases do not match."));
435 done = 0;
439 dfui_response_free(r);
442 dfui_form_free(f);
445 /** LIVECD UTILITIES FUNCTIONS **/
448 * String returned by this function must be deallocated by the caller.
450 char *
451 fn_select_file(const char *title, const char *desc, const char *help, const char *cancel,
452 const char *dir, const char *ext, const struct i_fn_args *a)
454 DIR *d;
455 struct dfui_form *f;
456 struct dfui_action *k;
457 struct dfui_response *r;
458 struct dirent *de;
459 char *s;
460 struct aura_dict *dict;
461 char *rk;
462 size_t rk_len;
464 f = dfui_form_create(
465 "select_file",
466 title, desc, help,
467 "p", "role", "menu",
468 NULL
471 dict = aura_dict_new(1, AURA_DICT_SORTED_LIST);
472 d = opendir(dir);
473 while ((de = readdir(d)) != NULL) {
474 if (strcmp(de->d_name, ".") == 0 ||
475 strcmp(de->d_name, "..") == 0 ||
476 strstr(de->d_name, ext) == NULL)
477 continue;
478 aura_dict_store(dict, de->d_name, strlen(de->d_name) + 1, "", 1);
480 closedir(d);
482 aura_dict_rewind(dict);
483 while (!aura_dict_eof(dict)) {
484 aura_dict_get_current_key(dict, (void **)&rk, &rk_len),
485 dfui_form_action_add(f, rk,
486 dfui_info_new(rk, "", ""));
487 aura_dict_next(dict);
489 aura_dict_free(dict);
491 k = dfui_form_action_add(f, "cancel",
492 dfui_info_new(cancel, "", ""));
493 dfui_action_property_set(k, "accelerator", "ESC");
495 if (!dfui_be_present(a->c, f, &r))
496 abort_backend();
498 s = aura_strdup(dfui_response_get_action_id(r));
500 dfui_form_free(f);
501 dfui_response_free(r);
503 return(s);
506 void
507 fn_set_kbdmap(struct i_fn_args *a)
509 struct commands *cmds;
510 char *s;
511 char filename[256], keymapname[256];
513 s = fn_select_file(_("Select Keyboard Map"),
514 _("Select a keyboard map appropriate to your keyboard layout."),
515 "", _("Return to Utilities Menu"), "/usr/share/syscons/keymaps",
516 ".kbd", a);
518 if (strcmp(s, "cancel") != 0) {
519 cmds = commands_new();
520 command_add(cmds, "%s%s -l "
521 "/usr/share/syscons/keymaps/%s < /dev/ttyv0",
522 a->os_root, cmd_name(a, "KBDCONTROL"),
524 if (commands_execute(a, cmds)) {
525 snprintf(filename, 256, "/usr/share/syscons/keymaps/%s", s);
526 snprintf(keymapname, 256, "%s", filename_noext(basename(filename)));
527 config_var_set(rc_conf, "keymap", keymapname);
528 } else {
529 inform(a->c, _("Keyboard map not successfully set."));
531 commands_free(cmds);
534 free(s);
537 void
538 fn_set_vidfont(struct i_fn_args *a)
540 struct commands *cmds;
541 char *s;
542 char filename[256], variable[256], fontname[256];
543 int by = 0;
546 s = fn_select_file(_("Select Console Font"),
547 _("Select a font appropriate to your video monitor and language."),
548 "", _("Return to Utilities Menu"), "/usr/share/syscons/fonts",
549 ".fnt", a);
551 if (strcmp(s, "cancel") != 0) {
552 cmds = commands_new();
553 command_add(cmds, "%s%s -f "
554 "/usr/share/syscons/fonts/%s < /dev/ttyv0",
555 a->os_root, cmd_name(a, "VIDCONTROL"),
557 if (commands_execute(a, cmds)) {
558 if (strstr(s, "8x16") != NULL)
559 by = 16;
560 else if (strstr(s, "8x14") != NULL)
561 by = 14;
562 else
563 by = 8;
565 snprintf(variable, 256, "font8x%d", by);
566 snprintf(filename, 256, "/usr/share/syscons/fonts/%s", s);
567 snprintf(fontname, 256, "%s", filename_noext(basename(filename)));
568 config_var_set(rc_conf, variable, fontname);
570 } else {
571 inform(a->c, _("Video font not successfully set."));
573 commands_free(cmds);
576 free(s);
579 void
580 fn_set_scrnmap(struct i_fn_args *a)
582 struct commands *cmds;
583 char *s;
584 char filename[256], scrnmapname[256];
586 s = fn_select_file(_("Select Screen Map"),
587 _("Select a mapping for translating characters as they appear "
588 "on your video console screen."),
589 "", _("Return to Utilities Menu"), "/usr/share/syscons/scrnmaps",
590 ".scm", a);
592 if (strcmp(s, "cancel") != 0) {
593 cmds = commands_new();
594 command_add(cmds, "%s%s -l "
595 "/usr/share/syscons/scrnmaps/%s < /dev/ttyv0",
596 a->os_root, cmd_name(a, "VIDCONTROL"),
598 if (commands_execute(a, cmds)) {
599 snprintf(filename, 256, "/usr/share/syscons/scrnmaps/%s", s);
600 snprintf(scrnmapname, 256, "%s", filename_noext(basename(filename)));
601 config_var_set(rc_conf, "scrnmap", scrnmapname);
602 } else {
603 inform(a->c, _("Video font not successfully set."));
605 commands_free(cmds);
607 free(s);
610 void
611 fn_set_timezone(struct i_fn_args *a)
613 struct commands *cmds;
614 char *s = NULL;
615 char current_path[256], selection[256], temp[256];
616 int found_file = 0;
617 int result;
619 result = dfui_be_present_dialog(a->c, _("Local or UTC (Greenwich Mean Time) clock"),
620 _("Yes|No"),
621 _("Is this machine's CMOS clock set to UTC?\n\n"
622 "If it is set to local time, or you don't know, please choose NO here!"));
623 if (result < 1)
624 abort_backend();
626 cmds = commands_new();
627 switch (result) {
628 case 1:
629 command_add(cmds, "%s%s -f %s%setc/wall_cmos_clock",
630 a->os_root, cmd_name(a, "RM"),
631 a->os_root, a->cfg_root);
632 break;
633 case 2:
634 command_add(cmds, "%s%s %s%setc/wall_cmos_clock",
635 a->os_root, cmd_name(a, "TOUCH"),
636 a->os_root, a->cfg_root);
637 break;
639 commands_execute(a, cmds);
641 snprintf(current_path, 256, "%s%susr/share/zoneinfo",
642 a->os_root, a->cfg_root);
643 while (!found_file) {
644 if (s != NULL)
645 free(s);
646 s = fn_select_file(_("Select Time Zone"),
647 _("Select a Time Zone appropriate to your physical location."),
648 "", _("Return to Utilities Menu"), current_path,
649 "", a);
650 if (is_dir("%s/%s", current_path, s)) {
651 snprintf(temp, 256, "%s/%s", current_path, s);
652 strlcpy(current_path, temp, 256);
653 } else {
654 if (is_file("%s/%s", current_path, s)) {
655 snprintf(selection, 256, "%s/%s", current_path, s);
656 found_file = 1;
658 if (strcmp(s, "cancel") == 0) {
659 strlcpy(selection, "cancel", 256);
660 found_file = 1;
664 free(s);
666 if (strcmp(selection, "cancel") != 0) {
667 command_add(cmds, "%s%s %s %s%setc/localtime",
668 a->os_root, cmd_name(a, "CP"),
669 selection,
670 a->os_root, a->cfg_root);
671 if (commands_execute(a, cmds)) {
672 inform(a->c, _("The Time Zone has been set to %s."), selection);
673 setenv("TZ", selection, 1);
674 tzset();
677 commands_free(cmds);
680 void
681 fn_assign_datetime(struct i_fn_args *a)
683 struct commands *cmds;
684 struct dfui_dataset *ds, *new_ds;
685 struct dfui_form *f;
686 struct dfui_response *r;
687 struct tm *tp;
688 char temp[256];
689 int year, month, dayofmonth, hour, minutes;
690 int valid = 1;
691 time_t now;
693 now = time(NULL);
694 tp = localtime(&now);
696 f = dfui_form_create(
697 "set_datetime",
698 _("Set Time/Date"),
699 _("Enter the date-time in your timezone."),
702 "f", "year", _("Enter year"),
703 _("Enter the current year (e.g. `2004')"), "",
704 "f", "month", _("Month"),
705 _("Enter the current month (e.g. `07')"), "",
706 "f", "dayofmonth", "dayofmonth",
707 _("Enter the current day of month (e.g. `30')"), "",
708 "f", "hour", "hour",
709 _("Enter the current hour (e.g. `07')"), "",
710 "f", "minutes", "minutes",
711 _("Enter the current minutes (e.g. `59')"), "",
713 "a", "ok", _("OK"), "", "",
714 "a", "cancel", _("Cancel"), "", "",
715 "p", "accelerator", "ESC",
717 NULL
720 ds = dfui_dataset_new();
721 snprintf(temp, 256, "%i", (tp->tm_year+1900));
722 dfui_dataset_celldata_add(ds, "year", temp);
723 snprintf(temp, 256, "%i", (tp->tm_mon+1));
724 dfui_dataset_celldata_add(ds, "month", temp);
725 snprintf(temp, 256, "%i", tp->tm_mday);
726 dfui_dataset_celldata_add(ds, "dayofmonth", temp);
727 snprintf(temp, 256, "%i", tp->tm_hour);
728 dfui_dataset_celldata_add(ds, "hour", temp);
729 snprintf(temp, 256, "%i", tp->tm_min);
730 dfui_dataset_celldata_add(ds, "minutes", temp);
731 dfui_form_dataset_add(f, ds);
733 if (!dfui_be_present(a->c, f, &r))
734 abort_backend();
736 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
737 new_ds = dfui_response_dataset_get_first(r);
739 if ((year = atoi(dfui_dataset_get_value(new_ds, "year"))) <= 0)
740 valid = 0;
741 month = atoi(dfui_dataset_get_value(new_ds, "month"));
742 if (month < 1 || month > 12)
743 valid = 0;
744 dayofmonth = atoi(dfui_dataset_get_value(new_ds, "dayofmonth"));
745 if (dayofmonth < 1 || dayofmonth > 31)
746 valid = 0;
747 hour = atoi(dfui_dataset_get_value(new_ds, "hour"));
748 if (hour < 0 || hour > 23)
749 valid = 0;
750 minutes = atoi(dfui_dataset_get_value(new_ds, "minutes"));
751 if (minutes < 0 || minutes > 59)
752 valid = 0;
754 if (valid) {
755 cmds = commands_new();
756 command_add(cmds, "%s%s -n %04d%02d%02d%02d%02d",
757 a->os_root, cmd_name(a, "DATE"),
758 year, month, dayofmonth, hour, minutes);
759 if (commands_execute(a, cmds)) {
760 inform(a->c, _("The date and time have been set."));
762 commands_free(cmds);
763 } else {
764 inform(a->c, _("Please enter numbers within acceptable ranges "
765 "for year, month, day of month, hour, and minute."));
770 void
771 fn_assign_hostname_domain(struct i_fn_args *a)
773 struct dfui_form *f;
774 struct dfui_response *r;
775 struct dfui_dataset *ds, *new_ds;
776 struct config_vars *resolv_conf;
777 const char *domain, *hostname;
778 char *fqdn;
780 f = dfui_form_create(
781 "set_hostname_domain",
782 _("Set Hostname/Domain"),
783 _("Please enter this machine's hostname and domain name."),
786 "f", "hostname", _("Hostname"),
787 _("Enter the Hostname (e.g. `machine')"), "",
788 "f", "domain", _("Domain"),
789 _("Enter the Domain Name (e.g. `network.lan')"), "",
791 "a", "ok", _("OK"), "", "",
792 "a", "cancel", _("Cancel"), "", "",
793 "p", "accelerator", "ESC",
795 NULL
798 ds = dfui_dataset_new();
799 dfui_dataset_celldata_add(ds, "hostname", "");
800 dfui_dataset_celldata_add(ds, "domain", "");
801 dfui_form_dataset_add(f, ds);
803 if (!dfui_be_present(a->c, f, &r))
804 abort_backend();
806 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
807 new_ds = dfui_response_dataset_get_first(r);
809 hostname = dfui_dataset_get_value(new_ds, "hostname");
810 domain = dfui_dataset_get_value(new_ds, "domain");
811 if (strlen(domain) == 0)
812 asprintf(&fqdn, "%s", hostname);
813 else
814 asprintf(&fqdn, "%s.%s", hostname, domain);
816 resolv_conf = config_vars_new();
818 config_var_set(rc_conf, "hostname", fqdn);
819 config_var_set(resolv_conf, "search", domain);
820 config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
821 "%s%setc/resolv.conf", a->os_root, a->cfg_root);
823 config_vars_free(resolv_conf);
825 free(fqdn);
828 dfui_form_free(f);
829 dfui_response_free(r);
832 void
833 fn_assign_ip(struct i_fn_args *a)
835 FILE *p;
836 struct commands *cmds;
837 struct command *cmd;
838 struct config_vars *resolv_conf;
839 struct dfui_dataset *ds, *new_ds;
840 struct dfui_form *f;
841 struct dfui_action *k;
842 struct dfui_response *r;
843 const char *domain, *hostname;
844 const char *interface_ip, *interface_netmask, *defaultrouter, *dns_resolver;
845 char *string, *string1;
846 char *word;
847 char interface[256];
848 char line[256];
849 int write_config = 0;
852 * Get interface list.
854 p = popen("/sbin/ifconfig -l", "r");
855 /* XXX it's possible (though extremely unlikely) this will fail. */
856 while (fgets(line, 255, p) != NULL)
857 line[strlen(line) - 1] = '\0';
859 pclose(p);
861 f = dfui_form_create(
862 "assign_ip",
863 _("Assign IP Address"),
864 _("Please select which interface you would like to configure:"),
866 "p", "role", "menu",
867 NULL
870 /* Loop through array. */
871 word = strtok(line, " \t");
872 while (word != NULL) {
873 dfui_form_action_add(f, word,
874 dfui_info_new(word, "", ""));
875 word = strtok(NULL, " ");
878 k = dfui_form_action_add(f, "cancel",
879 dfui_info_new("Cancel", "", ""));
880 dfui_action_property_set(k, "accelerator", "ESC");
882 if (!dfui_be_present(a->c, f, &r))
883 abort_backend();
885 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
886 dfui_form_free(f);
887 dfui_response_free(r);
888 return;
891 strlcpy(interface, dfui_response_get_action_id(r), 256);
893 resolv_conf = config_vars_new();
895 switch (dfui_be_present_dialog(a->c, _("Use DHCP?"),
896 _("Use DHCP|Configure Manually"),
897 _("DHCP allows the interface to automatically obtain "
898 "an IP address from a nearby DHCP server.\n\n"
899 "Would you like to enable DHCP for %s?"), interface)) {
900 case 1:
901 asprintf(&string, "ifconfig_%s", interface);
903 cmds = commands_new();
904 cmd = command_add(cmds, "%s%s dhclient",
905 a->os_root, cmd_name(a, "KILLALL"));
906 command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
907 command_add(cmds, "%s%s %s",
908 a->os_root, cmd_name(a, "DHCLIENT"),
909 interface);
910 if (commands_execute(a, cmds)) {
911 /* XXX sleep(3); */
912 show_ifconfig(a->c, interface);
913 write_config = 1;
914 } else {
915 switch (dfui_be_present_dialog(a->c, _("DHCP Failure"),
916 _("Yes|No"),
917 _("Warning: could not enable dhclient for %s.\n\n"
918 "Write the corresponding settings to rc.conf "
919 "anyway?"), interface)) {
920 case 1:
921 write_config = 1;
922 break;
923 case 2:
924 write_config = 0;
925 break;
926 default:
927 abort_backend();
930 commands_free(cmds);
931 config_var_set(rc_conf, string, "DHCP");
932 free(string);
933 break;
934 case 2:
935 dfui_form_free(f);
936 dfui_response_free(r);
937 f = dfui_form_create(
938 "assign_ip",
939 _("Assign IP Address"),
940 _("Configuring Interface:"),
943 "f", "interface_ip", _("IP Address"),
944 _("Enter the IP Address you would like to use"), "",
945 "f", "interface_netmask", _("Netmask"),
946 _("Enter the netmask of the IP address"), "",
947 "f", "defaultrouter", _("Default Router"),
948 _("Enter the IP address of the default router"), "",
949 "f", "dns_resolver", _("Primary DNS Server"),
950 _("Enter the IP address of primary DNS Server"), "",
951 "f", "hostname", _("Hostname"),
952 _("Enter the Hostname"), "",
953 "f", "domain", _("Domain"),
954 _("Enter the Domain Name"), "",
956 "a", "ok", _("Configure Interface"),
957 "", "",
958 "a", "cancel", _("Return to Utilities Menu"),
959 "", "",
960 "p", "accelerator", "ESC",
962 NULL
965 ds = dfui_dataset_new();
966 dfui_dataset_celldata_add(ds, "interface_netmask", "");
967 dfui_dataset_celldata_add(ds, "defaultrouter", "");
968 dfui_dataset_celldata_add(ds, "dns_resolver", "");
969 dfui_dataset_celldata_add(ds, "hostname", "");
970 dfui_dataset_celldata_add(ds, "domain", "");
971 dfui_dataset_celldata_add(ds, "interface_ip", "");
972 dfui_form_dataset_add(f, ds);
974 if (!dfui_be_present(a->c, f, &r))
975 abort_backend();
977 if (strcmp(dfui_response_get_action_id(r), "ok") == 0) {
978 new_ds = dfui_response_dataset_get_first(r);
980 interface_ip = dfui_dataset_get_value(
981 new_ds, "interface_ip");
982 interface_netmask = dfui_dataset_get_value(
983 new_ds, "interface_netmask");
984 defaultrouter = dfui_dataset_get_value(
985 new_ds, "defaultrouter");
986 dns_resolver = dfui_dataset_get_value(
987 new_ds, "dns_resolver");
988 hostname = dfui_dataset_get_value(
989 new_ds, "hostname");
990 domain = dfui_dataset_get_value(
991 new_ds, "domain");
993 asprintf(&string, "ifconfig_%s", interface);
994 asprintf(&string1, "inet %s netmask %s",
995 interface_ip, interface_netmask);
997 cmds = commands_new();
998 command_add(cmds, "%s%s %s %s netmask %s",
999 a->os_root, cmd_name(a, "IFCONFIG"),
1000 interface, interface_ip, interface_netmask);
1001 command_add(cmds, "%s%s add default %s",
1002 a->os_root, cmd_name(a, "ROUTE"),
1003 defaultrouter);
1005 if (commands_execute(a, cmds)) {
1006 /* XXX sleep(3); */
1007 show_ifconfig(a->c, interface);
1008 write_config = 1;
1009 } else {
1010 switch (dfui_be_present_dialog(a->c,
1011 _("ifconfig Failure"),
1012 _("Yes|No"),
1013 _("Warning: could not assign IP address "
1014 "or default gateway.\n\n"
1015 "Write the corresponding settings to "
1016 "rc.conf anyway?"))) {
1017 case 1:
1018 write_config = 1;
1019 break;
1020 case 2:
1021 write_config = 0;
1022 break;
1023 default:
1024 abort_backend();
1027 commands_free(cmds);
1029 config_var_set(rc_conf, string, string1);
1030 config_var_set(rc_conf, "defaultrouter", defaultrouter);
1032 free(string);
1033 free(string1);
1035 asprintf(&string, "%s.%s", hostname, domain);
1036 config_var_set(rc_conf, "hostname", string);
1037 free(string);
1039 config_var_set(resolv_conf, "search", domain);
1040 config_var_set(resolv_conf, "nameserver", dns_resolver);
1042 break;
1043 default:
1044 abort_backend();
1047 if (write_config) {
1049 * Save out changes to /etc/rc.conf and /etc/resolv.conf.
1051 config_vars_write(resolv_conf, CONFIG_TYPE_RESOLV,
1052 "%s%setc/resolv.conf", a->os_root, a->cfg_root);
1055 config_vars_free(resolv_conf);
1057 dfui_form_free(f);
1058 dfui_response_free(r);
1061 static const char *
1062 yes_to_y(const char *value)
1064 return(strcasecmp(value, "YES") == 0 ? "Y" : "N");
1067 void
1068 fn_select_services(struct i_fn_args *a)
1070 struct dfui_dataset *ds;
1071 struct dfui_form *f;
1072 struct dfui_response *r;
1074 if (!config_vars_read(a, rc_conf, CONFIG_TYPE_SH, "%s%setc/rc.conf",
1075 a->os_root, a->cfg_root)) {
1076 inform(a->c, _("Couldn't read %s%setc/rc.conf."),
1077 a->os_root, a->cfg_root);
1078 a->result = 0;
1079 return;
1082 f = dfui_form_create(
1083 "select_services",
1084 _("Select Services"),
1085 _("Please select which services you would like "
1086 "started at boot time."),
1089 "f", "syslogd", "syslogd",
1090 _("System Logging Daemon"), "",
1091 "p", "control", "checkbox",
1092 "f", "inetd", "inetd",
1093 _("Internet Super-Server"), "",
1094 "p", "control", "checkbox",
1095 "f", "named", "named",
1096 _("BIND Name Server"), "",
1097 "p", "control", "checkbox",
1098 "f", "ntpd", "ntpd",
1099 _("Network Time Protocol Daemon"), "",
1100 "p", "control", "checkbox",
1101 "f", "sshd", "sshd",
1102 _("Secure Shell Daemon"), "",
1103 "p", "control", "checkbox",
1105 "a", "ok", _("Enable/Disable Services"),
1106 "", "",
1107 "a", "cancel", _("Return to Utilities Menu"),
1108 "", "",
1109 "p", "accelerator", "ESC",
1111 NULL
1114 ds = dfui_dataset_new();
1115 dfui_dataset_celldata_add(ds, "syslogd",
1116 yes_to_y(config_var_get(rc_conf, "syslogd_enable")));
1117 dfui_dataset_celldata_add(ds, "inetd",
1118 yes_to_y(config_var_get(rc_conf, "inetd_enable")));
1119 dfui_dataset_celldata_add(ds, "named",
1120 yes_to_y(config_var_get(rc_conf, "named_enable")));
1121 dfui_dataset_celldata_add(ds, "ntpd",
1122 yes_to_y(config_var_get(rc_conf, "ntpd_enable")));
1123 dfui_dataset_celldata_add(ds, "sshd",
1124 yes_to_y(config_var_get(rc_conf, "sshd_enable")));
1125 dfui_form_dataset_add(f, ds);
1127 if (!dfui_be_present(a->c, f, &r))
1128 abort_backend();
1130 if (strcmp(dfui_response_get_action_id(r), "cancel") == 0) {
1131 dfui_form_free(f);
1132 dfui_response_free(r);
1133 return;
1136 dfui_form_free(f);
1137 dfui_response_free(r);
1140 /*** NON-fn_ FUNCTIONS ***/
1143 * Uses ss->selected_{disk,slice} as the target system.
1145 * XXX We now assume that the root mount has enough of the topology
1146 * to handle any configuration actions.
1149 mount_target_system(struct i_fn_args *a)
1151 FILE *crypttab, *fstab;
1152 struct commands *cmds;
1153 struct command *cmd;
1154 struct subpartition *a_subpart;
1155 struct subpartition *d_subpart;
1156 char name[256], device[256];
1157 char *filename, line[256];
1158 char *word;
1161 * Mount subpartitions from this installation if they are
1162 * not already mounted. Tricky, as we need to honour the
1163 * installation's loader.conf and fstab.
1165 cmds = commands_new();
1168 * First, unmount anything already mounted on /mnt.
1170 unmount_all_under(a, cmds, "%smnt", a->os_root);
1173 * Reset and clear out subpartitions so that system
1174 * can make a "dummy" subpart.
1176 subpartitions_free(storage_get_selected_slice(a->s));
1179 * Create a temporary dummy subpartition - that we
1180 * assume exists
1182 a_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s),
1183 "/dummy", 0, 0, 0, 0, 0, 0);
1184 subpartition_new_ufs(storage_get_selected_slice(a->s),
1185 "swap", 0, 0, 0, 0, 0, 0);
1186 d_subpart = subpartition_new_ufs(storage_get_selected_slice(a->s),
1187 "/dummy", 0, 0, 0, 0, 0, 0);
1190 * Mount the target's / and read its /etc/fstab.
1192 * XXX NEEDS TO BE REWRITTEN XXX
1195 command_add(cmds, "%s%s /dev/%s %sboot",
1196 a->os_root, cmd_name(a, "MOUNT"),
1197 subpartition_get_device_name(a_subpart),
1198 a->os_root);
1199 cmd = command_add(cmds,
1200 "%s%s -f %st2;"
1201 "%s%s \"^vfs\\.root\\.realroot=\" %sboot/loader.conf >%st2",
1202 a->os_root, cmd_name(a, "RM"), a->tmp,
1203 a->os_root, cmd_name(a, "GREP"),
1204 a->os_root, a->tmp);
1205 command_set_failure_mode(cmd, COMMAND_FAILURE_IGNORE);
1207 if (!commands_execute(a, cmds)) {
1208 commands_free(cmds);
1209 return(0);
1211 commands_free(cmds);
1212 cmds = commands_new();
1215 * XXX NEEDS TO BE REWRITTEN XXX
1218 struct stat sb = { .st_size = 0 };
1219 const char *fsname;
1220 const char *mountid;
1222 switch (use_hammer) {
1223 case 1:
1224 fsname = "hammer";
1225 mountid = "MOUNT_HAMMER";
1226 break;
1227 case 2:
1228 fsname = "hammer2";
1229 mountid = "MOUNT_HAMMER2";
1230 break;
1231 case 0:
1232 default:
1233 fsname = "ufs";
1234 mountid = "MOUNT";
1235 break;
1238 stat("/tmp/t2", &sb);
1239 if (sb.st_size > 0) {
1240 command_add(cmds, "%s%s %sboot",
1241 a->os_root, cmd_name(a, "UMOUNT"),
1242 a->os_root);
1243 fn_get_passphrase(a, 0);
1244 command_add(cmds,
1245 "%s%s -d /tmp/t1 luksOpen /dev/`%s%s \"^vfs\\.root\\.realroot=\" %st2 |"
1246 "%s%s -F%s: '{print $2;}' |"
1247 "%s%s -F: '{print $1;}'` %s",
1248 a->os_root, cmd_name(a, "CRYPTSETUP"),
1249 a->os_root, cmd_name(a, "GREP"),
1250 a->tmp,
1251 a->os_root, cmd_name(a, "AWK"),
1252 fsname,
1253 a->os_root, cmd_name(a, "AWK"),
1254 subpartition_get_mapper_name(d_subpart, -1));
1255 command_add(cmds,
1256 "%s%s %s %s%s",
1257 a->os_root,
1258 cmd_name(a, mountid),
1259 subpartition_get_mapper_name(d_subpart, 1),
1260 a->os_root, a->cfg_root);
1261 } else {
1262 command_add(cmds,
1263 "%s%s /dev/`%s%s \"^vfs\\.root\\.mountfrom\" %sboot/loader.conf |"
1264 "%s%s -F%s: '{print $2;}' |"
1265 "%s%s 's/\"//'` %s%s",
1266 a->os_root,
1267 cmd_name(a, mountid),
1268 a->os_root, cmd_name(a, "GREP"),
1269 a->os_root,
1270 a->os_root, cmd_name(a, "AWK"),
1271 fsname,
1272 a->os_root, cmd_name(a, "SED"),
1273 a->os_root, a->cfg_root);
1274 command_add(cmds, "%s%s %sboot",
1275 a->os_root, cmd_name(a, "UMOUNT"),
1276 a->os_root);
1279 if (!commands_execute(a, cmds)) {
1280 commands_free(cmds);
1281 unlink("/tmp/t1");
1282 return(0);
1284 commands_free(cmds);
1285 cmds = commands_new();
1288 * Get rid of the dummy subpartition.
1290 subpartitions_free(storage_get_selected_slice(a->s));
1293 * See if an /etc/crypttab exists.
1295 * Scan and open the related mappings (currently not used since
1296 * we removed the additional mounts from the fstab scan, but we
1297 * might put those back in at a future date so leave this in for
1298 * now).
1300 asprintf(&filename, "%s%s/etc/crypttab", a->os_root, a->cfg_root);
1301 crypttab = fopen(filename, "r");
1302 free(filename);
1303 if (crypttab != NULL) {
1304 while (fgets(line, 256, crypttab) != NULL) {
1306 * Parse the crypttab line.
1308 if (first_non_space_char_is(line, '#'))
1309 continue;
1310 if ((word = strtok(line, " \t")) == NULL)
1311 continue;
1312 strlcpy(name, word, 256);
1314 /* don't mount encrypted swap */
1315 if (strcmp(name, "swap") == 0)
1316 continue;
1317 /* encrypted root already mounted */
1318 if (strcmp(name, subpartition_get_mapper_name(d_subpart, -1)) == 0)
1319 continue;
1321 if ((word = strtok(NULL, " \t")) == NULL)
1322 continue;
1323 strlcpy(device, word, 256);
1325 command_add(cmds,
1326 "%s%s -d /tmp/t1 luksOpen %s %s",
1327 a->os_root, cmd_name(a, "CRYPTSETUP"),
1328 device, name);
1330 continue;
1332 fclose(crypttab);
1334 if (!commands_execute(a, cmds)) {
1335 commands_free(cmds);
1336 unlink("/tmp/t1");
1337 return(0);
1339 commands_free(cmds);
1340 unlink("/tmp/t1");
1343 * (current we do not mount the other partitions, everything needed
1344 * for system configuration should be on the already-mounted root).
1346 asprintf(&filename, "%s%s/etc/fstab", a->os_root, a->cfg_root);
1347 fstab = fopen(filename, "r");
1348 free(filename);
1349 if (fstab == NULL) {
1350 inform(a->c, _("Filesystem table on installed system could not be read."));
1351 cmds = commands_new();
1352 command_add(cmds, "%s%s %s%s",
1353 a->os_root, cmd_name(a, "UMOUNT"),
1354 a->os_root, a->cfg_root);
1355 if (!commands_execute(a, cmds)) {
1356 inform(a->c, _("Warning: Installed system was not properly unmounted."));
1358 commands_free(cmds);
1359 return(0);
1361 fclose(fstab);
1363 return 1;