Merge from vendor branch LIBPCAP:
[dragonfly.git] / release / sysinstall / config.c
1 /*
2  * The new sysinstall program.
3  *
4  * This is probably the last program in the `sysinstall' line - the next
5  * generation being essentially a complete rewrite.
6  *
7  * $FreeBSD: src/release/sysinstall/config.c,v 1.156.2.32 2003/03/27 18:17:17 murray Exp $
8  * $DragonFly: src/release/sysinstall/Attic/config.c,v 1.2 2003/06/17 04:27:21 dillon Exp $
9  *
10  * Copyright (c) 1995
11  *      Jordan Hubbard.  All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer,
18  *    verbatim and that no modifications are made prior to this
19  *    point in the file.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  */
37
38 #include "sysinstall.h"
39 #include <sys/disklabel.h>
40 #include <sys/wait.h>
41 #include <sys/errno.h>
42 #include <sys/ioctl.h>
43 #include <sys/fcntl.h>
44 #include <sys/param.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <sys/mount.h>
48 #include <time.h>
49
50 static Chunk *chunk_list[MAX_CHUNKS];
51 static int nchunks;
52 static int rootdev_is_od;
53
54 /* arg to sort */
55 static int
56 chunk_compare(Chunk *c1, Chunk *c2)
57 {
58     if (!c1 && !c2)
59         return 0;
60     else if (!c1 && c2)
61         return 1;
62     else if (c1 && !c2)
63         return -1;
64     else if (!c1->private_data && !c2->private_data)
65         return 0;
66     else if (c1->private_data && !c2->private_data)
67         return 1;
68     else if (!c1->private_data && c2->private_data)
69         return -1;
70     else
71         return strcmp(((PartInfo *)(c1->private_data))->mountpoint, ((PartInfo *)(c2->private_data))->mountpoint);
72 }
73
74 static void
75 chunk_sort(void)
76 {
77     int i, j;
78
79     for (i = 0; i < nchunks; i++) {
80         for (j = 0; j < nchunks; j++) {
81             if (chunk_compare(chunk_list[j], chunk_list[j + 1]) > 0) {
82                 Chunk *tmp = chunk_list[j];
83
84                 chunk_list[j] = chunk_list[j + 1];
85                 chunk_list[j + 1] = tmp;
86             }
87         }
88     }
89 }
90
91 static void
92 check_rootdev(Chunk **list, int n)
93 {
94         int i;
95         Chunk *c;
96
97         rootdev_is_od = 0;
98         for (i = 0; i < n; i++) {
99                 c = *list++;
100                 if (c->type == part && (c->flags & CHUNK_IS_ROOT)
101                     && strncmp(c->disk->name, "od", 2) == 0)
102                         rootdev_is_od = 1;
103         }
104 }
105
106 static char *
107 name_of(Chunk *c1)
108 {
109     return c1->name;
110 }
111
112 static char *
113 mount_point(Chunk *c1)
114 {
115     if (c1->type == part && c1->subtype == FS_SWAP)
116         return "none";
117     else if (c1->type == part || c1->type == fat)
118         return ((PartInfo *)c1->private_data)->mountpoint;
119     return "/bogus";
120 }
121
122 static char *
123 fstype(Chunk *c1)
124 {
125     if (c1->type == fat)
126         return "msdos";
127     else if (c1->type == part) {
128         if (c1->subtype != FS_SWAP)
129             return "ufs";
130         else
131             return "swap";
132     }
133     return "bogus";
134 }
135
136 static char *
137 fstype_short(Chunk *c1)
138 {
139     if (c1->type == part) {
140         if (c1->subtype != FS_SWAP) {
141             if (rootdev_is_od == 0 && strncmp(c1->name, "od", 2) == 0)
142                 return "rw,noauto";
143             else
144                 return "rw";
145         }
146         else
147             return "sw";
148     }
149     else if (c1->type == fat) {
150         if (strncmp(c1->name, "od", 2) == 0)
151             return "ro,noauto";
152         else
153             return "ro";
154     }
155     return "bog";
156 }
157
158 static int
159 seq_num(Chunk *c1)
160 {
161     if (c1->type == part && c1->subtype != FS_SWAP) {
162         if (rootdev_is_od == 0 && strncmp(c1->name, "od", 2) == 0)
163             return 0;
164         else if (c1->flags & CHUNK_IS_ROOT)
165             return 1;
166         else
167             return 2;
168     }
169     return 0;
170 }
171
172 int
173 configFstab(dialogMenuItem *self)
174 {
175     Device **devs;
176     Disk *disk;
177     FILE *fstab;
178     int i, cnt;
179     Chunk *c1, *c2;
180
181     if (!RunningAsInit) {
182         if (file_readable("/etc/fstab"))
183             return DITEM_SUCCESS;
184         else {
185             msgConfirm("Attempting to rebuild your /etc/fstab file.  Warning: If you had\n"
186                        "any CD devices in use before running sysinstall then they may NOT\n"
187                        "be found by this run!");
188         }
189     }
190
191     devs = deviceFind(NULL, DEVICE_TYPE_DISK);
192     if (!devs) {
193         msgConfirm("No disks found!");
194         return DITEM_FAILURE;
195     }
196
197     /* Record all the chunks */
198     nchunks = 0;
199     for (i = 0; devs[i]; i++) {
200         if (!devs[i]->enabled)
201             continue;
202         disk = (Disk *)devs[i]->private;
203         if (!disk->chunks)
204             msgFatal("No chunk list found for %s!", disk->name);
205         for (c1 = disk->chunks->part; c1; c1 = c1->next) {
206             if (c1->type == freebsd) {
207                 for (c2 = c1->part; c2; c2 = c2->next) {
208                     if (c2->type == part && (c2->subtype == FS_SWAP || c2->private_data))
209                         chunk_list[nchunks++] = c2;
210                 }
211             }
212             else if (c1->type == fat && c1->private_data)
213                 chunk_list[nchunks++] = c1;
214         }
215     }
216     chunk_list[nchunks] = 0;
217     chunk_sort();
218     
219     fstab = fopen("/etc/fstab", "w");
220     if (!fstab) {
221         msgConfirm("Unable to create a new /etc/fstab file!  Manual intervention\n"
222                    "will be required.");
223         return DITEM_FAILURE;
224     }
225     
226     check_rootdev(chunk_list, nchunks);
227     
228     /* Go for the burn */
229     msgDebug("Generating /etc/fstab file\n");
230     fprintf(fstab, "# See the fstab(5) manual page for important information on automatic mounts\n");
231     fprintf(fstab, "# of network filesystems before modifying this file.\n");
232     fprintf(fstab, "#\n");
233     fprintf(fstab, "# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#\n");
234     for (i = 0; i < nchunks; i++)
235         fprintf(fstab, "/dev/%s\t\t%s\t\t%s\t%s\t\t%d\t%d\n", name_of(chunk_list[i]), mount_point(chunk_list[i]),
236                 fstype(chunk_list[i]), fstype_short(chunk_list[i]), seq_num(chunk_list[i]), seq_num(chunk_list[i]));
237     
238     /* Now look for the CDROMs */
239     devs = deviceFind(NULL, DEVICE_TYPE_CDROM);
240     cnt = deviceCount(devs);
241     
242     /* Write out the CDROM entries */
243     for (i = 0; i < cnt; i++) {
244         char cdname[10];
245         
246         sprintf(cdname, "/cdrom%s", i ? itoa(i) : "");
247         if (Mkdir(cdname))
248             msgConfirm("Unable to make mount point for: %s", cdname);
249         else
250             fprintf(fstab, "/dev/%s\t\t%s\t\tcd9660\tro,noauto\t0\t0\n", devs[i]->name, cdname);
251     }
252     
253     /* And finally, a /proc. */
254     fprintf(fstab, "proc\t\t\t/proc\t\tprocfs\trw\t\t0\t0\n");
255     Mkdir("/proc");
256
257     fclose(fstab);
258     if (isDebug())
259         msgDebug("Wrote out /etc/fstab file\n");
260     return DITEM_SUCCESS;
261 }
262
263 /* Do the work of sucking in a config file.
264  * config is the filename to read in.
265  * lines is a fixed (max) sized array of char*
266  * returns number of lines read.  line contents
267  * are malloc'd and must be freed by the caller.
268  */
269 int
270 readConfig(char *config, char **lines, int max)
271 {
272     FILE *fp;
273     char line[256];
274     int i, nlines;
275
276     fp = fopen(config, "r");
277     if (!fp)
278         return -1;
279
280     nlines = 0;
281     /* Read in the entire file */
282     for (i = 0; i < max; i++) {
283         if (!fgets(line, sizeof line, fp))
284             break;
285         lines[nlines++] = strdup(line);
286     }
287     fclose(fp);
288     if (isDebug())
289         msgDebug("readConfig: Read %d lines from %s.\n", nlines, config);
290     return nlines;
291 }
292
293 #define MAX_LINES  2000 /* Some big number we're not likely to ever reach - I'm being really lazy here, I know */
294
295 static void
296 readConfigFile(char *config, int marked)
297 {
298     char *lines[MAX_LINES], *cp, *cp2;
299     int i, nlines;
300
301     nlines = readConfig(config, lines, MAX_LINES);
302     if (nlines == -1)
303         return;
304
305     for (i = 0; i < nlines; i++) {
306         /* Skip the comments & non-variable settings */
307         if (lines[i][0] == '#' || !(cp = index(lines[i], '='))) {
308             free(lines[i]);
309             continue;
310         }
311         *cp++ = '\0';
312         /* Find quotes */
313         if ((cp2 = index(cp, '"')) || (cp2 = index(cp, '\047'))) {
314             cp = cp2 + 1;
315             cp2 = index(cp, *cp2);
316         }
317         /* If valid quotes, use it */
318         if (cp2) {
319             *cp2 = '\0';
320             /* If we have a legit value, set it */
321             if (strlen(cp))
322                 variable_set2(lines[i], cp, marked);
323         }
324         free(lines[i]);
325     }
326 }
327
328 /* Load the environment from rc.conf file(s) */
329 void
330 configEnvironmentRC_conf(void)
331 {
332     static struct {
333         char *fname;
334         int marked;
335     } configs[] = {
336         { "/etc/defaults/rc.conf", 0 },
337         { "/etc/rc.conf", 0 },
338         { "/etc/rc.conf.local", 0 },
339         { NULL, 0 },
340     };
341     int i;
342
343     for (i = 0; configs[i].fname; i++) {
344         if (file_readable(configs[i].fname))
345             readConfigFile(configs[i].fname, configs[i].marked);
346     }
347 }
348
349 /* Load the environment from a resolv.conf file */
350 void
351 configEnvironmentResolv(char *config)
352 {
353     char *lines[MAX_LINES];
354     int i, nlines;
355
356     nlines = readConfig(config, lines, MAX_LINES);
357     if (nlines == -1)
358         return;
359     for (i = 0; i < nlines; i++) {
360         Boolean name_set = variable_get(VAR_NAMESERVER) ? 1 : 0;
361
362         if (!strncmp(lines[i], "domain", 6) && !variable_get(VAR_DOMAINNAME))
363             variable_set2(VAR_DOMAINNAME, string_skipwhite(string_prune(lines[i] + 6)), 0);
364         else if (!name_set && !strncmp(lines[i], "nameserver", 10)) {
365             /* Only take the first nameserver setting - we're lame */
366             variable_set2(VAR_NAMESERVER, string_skipwhite(string_prune(lines[i] + 10)), 0);
367         }
368         free(lines[i]);
369     }
370 }
371
372 /* Version of below for dispatch routines */
373 int
374 configRC(dialogMenuItem *unused)
375 {
376     configRC_conf();
377     return DITEM_SUCCESS;
378 }
379
380 void
381 configRC_conf(void)
382 {
383     FILE *rcSite;
384     Variable *v;
385     int write_header;
386     time_t t_loc;
387     char *cp;
388     static int did_marker = 0;
389     time_t tp;
390
391     write_header = !file_readable("/etc/rc.conf");
392     rcSite = fopen("/etc/rc.conf", "a");
393     if (!rcSite)
394         return;
395     if (write_header) {
396         fprintf(rcSite, "# This file now contains just the overrides from /etc/defaults/rc.conf.\n");
397         fprintf(rcSite, "# Please make all changes to this file, not to /etc/defaults/rc.conf.\n\n");
398         fprintf(rcSite, "# Enable network daemons for user convenience.\n");
399         if ((t_loc = time(NULL)) != -1 && (cp = ctime(&t_loc)))
400             fprintf(rcSite, "# Created: %s", cp);
401     }
402
403     /* Now do variable substitutions */
404     for (v = VarHead; v; v = v->next) {
405         if (v->dirty) {
406             if (!did_marker) {
407                 time(&tp);
408                 fprintf(rcSite, "# -- sysinstall generated deltas -- # "
409                     "%s", ctime(&tp));
410                 did_marker = 1;
411             }
412             fprintf(rcSite, "%s=\"%s\"\n", v->name, v->value);
413             v->dirty = 0;
414         }
415     }
416     fclose(rcSite);
417     /* Tidy up the resulting file if it's late enough in the installation
418         for sort and uniq to be available */
419     if (RunningAsInit && file_readable("/usr/bin/sort") && file_readable("/usr/bin/uniq"))
420         (void)vsystem("sort /etc/rc.conf | uniq > /etc/rc.conf.new && mv /etc/rc.conf.new /etc/rc.conf");
421 }
422
423 int
424 configSaver(dialogMenuItem *self)
425 {
426     variable_set((char *)self->data, 1);
427     if (!variable_get(VAR_BLANKTIME))
428         variable_set2(VAR_BLANKTIME, "300", 1);
429     return DITEM_SUCCESS;
430 }
431
432 int
433 configSaverTimeout(dialogMenuItem *self)
434 {
435     return (variable_get_value(VAR_BLANKTIME,
436             "Enter time-out period in seconds for screen saver", 1) ?
437         DITEM_SUCCESS : DITEM_FAILURE);
438 }
439
440 int
441 configNTP(dialogMenuItem *self)
442 {
443     int status;
444
445     status = variable_get_value(VAR_NTPDATE_FLAGS,
446                                 "Enter the name of an NTP server", 1)
447              ? DITEM_SUCCESS : DITEM_FAILURE;
448     if (status == DITEM_SUCCESS) {
449         static char tmp[255];
450
451         snprintf(tmp, sizeof(tmp), "ntpdate_enable=YES,ntpdate_flags=%s",
452                  variable_get(VAR_NTPDATE_FLAGS));
453         self->data = tmp;
454         dmenuSetVariables(self);
455     }
456     return status;
457 }
458
459 int
460 configUsers(dialogMenuItem *self)
461 {
462     WINDOW *w = savescr();
463
464     dialog_clear_norefresh();
465     dmenuOpenSimple(&MenuUsermgmt, FALSE); 
466     restorescr(w);
467     return DITEM_SUCCESS;
468 }
469
470 int
471 configLinux(dialogMenuItem *self)
472 {
473     WINDOW *w = savescr();
474     int i;
475
476     dialog_clear_norefresh();
477     variable_set2(VAR_LINUX_ENABLE, "YES", 1);
478     Mkdir("/compat/linux");
479     msgNotify("Installing Linux compatibility library...");
480     i = package_add("linux_base");
481     restorescr(w);
482     return i;
483 }
484
485 int
486 configSecurityProfile(dialogMenuItem *self)
487 {
488     WINDOW *w = savescr();
489
490     dialog_clear_norefresh();
491     dmenuOpenSimple(&MenuSecurityProfile, FALSE); 
492     restorescr(w);
493     return DITEM_SUCCESS;
494 }
495
496 /* Use the most extreme security settings */
497 int
498 configSecurityExtreme(dialogMenuItem *self)
499 {
500     WINDOW *w = savescr();
501
502     variable_set2("nfs_server_enable", "NO", 1);
503     variable_set2("sendmail_enable", "NO", 1);
504     variable_set2("sshd_enable", "NO", 1);
505     variable_set2("kern_securelevel_enable", "YES", 1);
506     variable_set2("kern_securelevel", "2", 1);
507
508     if (self)
509         msgConfirm("Extreme security settings have been selected.\n\n"
510             "Sendmail, sshd, and NFS services have been disabled, and\n"
511             "securelevels have been enabled.\n"
512             "PLEASE NOTE that this still does not save you from having\n"
513             "to properly secure your system in other ways or exercise\n"
514             "due diligence in your administration, this simply picks\n"
515             "a more secure set of out-of-box defaults to start with.\n\n"
516             "To change any of these settings later, edit /etc/rc.conf");
517
518     restorescr(w);
519     return DITEM_SUCCESS;
520 }
521
522 int
523 configSecurityModerate(dialogMenuItem *self)
524 {
525     WINDOW *w = savescr();
526
527     variable_set2("nfs_reserved_port_only", "YES", 1);
528     variable_set2("sendmail_enable", "YES", 1);
529     variable_set2("sshd_enable", "YES", 1);
530     variable_set2("kern_securelevel_enable", "NO", 1);
531
532     if (self)
533         msgConfirm("Moderate security settings have been selected.\n\n"
534             "Sendmail and sshd have been enabled, securelevels are\n"
535             "disabled, and NFS server settings have been left intact.\n"
536             "PLEASE NOTE that this still does not save you from having\n"
537             "to properly secure your system in other ways or exercise\n"
538             "due diligence in your administration, this simply picks\n"
539             "a standard set of out-of-box defaults to start with.\n\n"
540             "To change any of these settings later, edit /etc/rc.conf");
541
542     restorescr(w);
543     return DITEM_SUCCESS;
544 }
545
546 static void
547 write_root_xprofile(char *str)
548 {
549     FILE *fp;
550     int len;
551     char **cp;
552     static char *flist[] = { /* take care of both xdm and startx */
553         "/root/.xinitrc",
554         "/root/.xsession",
555         "/usr/share/skel/dot.xinitrc",
556         "/usr/share/skel/dot.xsession",
557         NULL,
558     };
559
560     len = strlen(str);
561     for (cp = flist; *cp; cp++) {
562         fp = fopen(*cp, "w");
563         if (fp) {
564             fwrite(str, 1, len, fp);
565             fchmod(fileno(fp), 0755);
566             fclose(fp);
567         }
568     }
569 }
570
571 static int
572 gotit(char *fname)
573 {
574     char tmp[FILENAME_MAX];
575
576     snprintf(tmp, sizeof tmp, "/usr/X11R6/bin/%s", fname);
577     if (file_executable(tmp))
578         return TRUE;
579     snprintf(tmp, sizeof tmp, "/usr/local/bin/%s", fname);
580     return file_executable(tmp);
581 }
582
583 int
584 configXDesktop(dialogMenuItem *self)
585 {
586     char *desk;
587     int ret = DITEM_SUCCESS;
588     WINDOW *w = savescr();
589     
590     dialog_clear_norefresh();
591     if (!dmenuOpenSimple(&MenuXDesktops, FALSE) || !(desk = variable_get(VAR_DESKSTYLE))) {
592         restorescr(w);
593         return DITEM_FAILURE;
594     }
595     if (!strcmp(desk, "kde")) {
596         ret = package_add("kde");
597         if (DITEM_STATUS(ret) != DITEM_FAILURE && gotit("startkde"))
598             write_root_xprofile("exec startkde\n");
599     }
600     else if (!strcmp(desk, "gnome2")) {
601         ret = package_add("gnome2");
602         if (DITEM_STATUS(ret) != DITEM_FAILURE && gotit("gnome-session")) {
603             write_root_xprofile("exec gnome-session\n");
604         }
605     }
606     else if (!strcmp(desk, "afterstep")) {
607         ret = package_add("afterstep");
608         if (DITEM_STATUS(ret) != DITEM_FAILURE && gotit("afterstep"))
609             write_root_xprofile("exec afterstep\n");
610     }
611     else if (!strcmp(desk, "windowmaker")) {
612         ret = package_add("windowmaker");
613         if (DITEM_STATUS(ret) != DITEM_FAILURE && gotit("wmaker.inst")) {
614             write_root_xprofile("xterm &\n[ ! -d $HOME/GNUstep/Library/WindowMaker ] && /usr/X11R6/bin/wmaker.inst\nexec /usr/X11R6/bin/wmaker\n");
615         }
616     }
617     else if (!strcmp(desk, "fvwm2")) {
618         ret = package_add("fvwm");
619         if (DITEM_STATUS(ret) != DITEM_FAILURE && gotit("fvwm"))
620             write_root_xprofile("exec fvwm\n");
621     }
622     if (DITEM_STATUS(ret) == DITEM_FAILURE)
623         msgConfirm("An error occurred while adding the package(s) required\n"
624                    "by this desktop type.  Please change installation media\n"
625                    "and/or select a different, perhaps simpler, desktop\n"
626                    "environment and try again.");
627     restorescr(w);
628     return ret;
629 }
630
631 int
632 configXSetup(dialogMenuItem *self)
633 {
634     char *config, *execfile, *execcmd, *style, *tmp;
635     char *moused;
636     WINDOW *w = savescr();
637     
638     setenv("XWINHOME", "/usr/X11R6", 1);
639 tryagain:
640     variable_unset(VAR_DESKSTYLE);
641     variable_unset(VAR_XF86_CONFIG);
642     dialog_clear_norefresh();
643     if (!dmenuOpenSimple(&MenuXF86Config, FALSE)) {
644         restorescr(w);
645         return DITEM_FAILURE;
646     }
647     config = variable_get(VAR_XF86_CONFIG);
648     style = variable_get(VAR_DESKSTYLE);
649     if (!config) {
650         if (style)
651             goto config_desktop;
652         else {
653             restorescr(w);
654             return DITEM_FAILURE;
655         }
656     }
657
658     if (file_readable("/var/run/ld-elf.so.hints"))
659         vsystem("/sbin/ldconfig -m /usr/lib /usr/X11R6/lib /usr/local/lib /usr/lib/compat");
660     else
661         vsystem("/sbin/ldconfig /usr/lib /usr/X11R6/lib /usr/local/lib /usr/lib/compat");
662     if (file_readable("/var/run/ld.so.hints"))
663         vsystem("ldconfig -m -aout /usr/lib/aout /usr/lib/compat/aout /usr/local/lib/aout /usr/X11R6/lib/aout");
664     else
665         vsystem("ldconfig -aout /usr/lib/aout /usr/lib/compat/aout /usr/local/lib/aout /usr/X11R6/lib/aout");
666
667     vsystem("/sbin/ifconfig lo0 127.0.0.1");
668
669     /* 
670      * execcmd may have been passed in as a command name with
671      * arguments.  Therefore, before determining if it is suitable for
672      * execution, we must split off the filename component from the
673      * command line arguments.
674      */
675
676     execcmd = string_concat("/usr/X11R6/bin/", config);
677     execfile = strdup(execcmd);
678     if ((tmp = strchr(execfile, ' ')))
679             *tmp = '\0';
680     if (file_executable(execfile)) {
681         free(execfile);
682         moused = variable_get(VAR_MOUSED);
683         while (!moused || strcmp(moused, "YES")) {
684             if (msgYesNo("The X server may access the mouse in two ways: direct access\n"
685                          "or indirect access via the mouse daemon.  You have not\n"
686                          "configured the mouse daemon.  Would you like to configure it\n"
687                          "now?  If you intend to let the X server access the mouse\n"
688                          "directly, choose \"No\" at this time."))
689                 break;
690             dialog_clear_norefresh();
691             dmenuOpenSimple(&MenuMouse, FALSE); 
692             moused = variable_get(VAR_MOUSED);
693         }
694         if (moused && !strcmp(moused, "YES"))
695             msgConfirm("You have configured and are now running the mouse daemon.\n"
696                        "Choose \"/dev/sysmouse\" as the mouse port and \"SysMouse\" or\n"
697                        "\"MouseSystems\" as the mouse protocol in the X configuration\n"
698                        "utility.");
699         Mkdir("/etc/X11");      /* XXX:Remove this later after we are happy mtree will have created this for us. */
700         systemExecute(execcmd);
701         if (!file_readable("/etc/X11/XF86Config")) {
702             if (!msgYesNo("The XFree86 configuration process seems to have\nfailed.  Would you like to try again?"))
703                 goto tryagain;
704             else {
705                 restorescr(w);
706                 return DITEM_FAILURE;
707             }
708         }
709 config_desktop:
710         configXDesktop(self);
711         restorescr(w);
712         return DITEM_SUCCESS;
713     }
714     else {
715         free(execfile);
716         msgConfirm("The XFree86 setup utility you chose does not appear to be installed!\n"
717                    "Please install this before attempting to configure XFree86.");
718         restorescr(w);
719         return DITEM_FAILURE;
720     }
721 }
722
723 int
724 configResolv(dialogMenuItem *ditem)
725 {
726     FILE *fp;
727     char *cp, *c6p, *dp, *hp;
728
729     cp = variable_get(VAR_NAMESERVER);
730     if (!cp || !*cp)
731         goto skip;
732     Mkdir("/etc");
733     fp = fopen("/etc/resolv.conf", "w");
734     if (!fp)
735         return DITEM_FAILURE;
736     if (variable_get(VAR_DOMAINNAME))
737         fprintf(fp, "domain\t%s\n", variable_get(VAR_DOMAINNAME));
738     fprintf(fp, "nameserver\t%s\n", cp);
739     fclose(fp);
740     if (isDebug())
741         msgDebug("Wrote out /etc/resolv.conf\n");
742
743 skip:
744     dp = variable_get(VAR_DOMAINNAME);
745     cp = variable_get(VAR_IPADDR);
746     c6p = variable_get(VAR_IPV6ADDR);
747     hp = variable_get(VAR_HOSTNAME);
748     /* Tack ourselves into /etc/hosts */
749     fp = fopen("/etc/hosts", "w");
750     if (!fp)
751         return DITEM_FAILURE;
752     /* Add an entry for localhost */
753     if (!variable_cmp(VAR_IPV6_ENABLE, "YES")) {
754         if (dp)
755             fprintf(fp, "::1\t\t\tlocalhost.%s localhost\n", dp);
756         else
757             fprintf(fp, "::1\t\t\tlocalhost\n");
758     }
759     if (dp)
760         fprintf(fp, "127.0.0.1\t\tlocalhost.%s localhost\n", dp);
761     else
762         fprintf(fp, "127.0.0.1\t\tlocalhost\n");
763     /* Now the host entries, if applicable */
764     if (((cp && cp[0] != '0') || (c6p && c6p[0] != '0')) && hp) {
765         char cp2[255];
766
767         if (!index(hp, '.'))
768             cp2[0] = '\0';
769         else {
770             SAFE_STRCPY(cp2, hp);
771             *(index(cp2, '.')) = '\0';
772         }
773         if (c6p && c6p[0] != '0') {
774             fprintf(fp, "%s\t%s %s\n", c6p, hp, cp2);
775             fprintf(fp, "%s\t%s.\n", c6p, hp);
776         }
777         if (cp && cp[0] != '0') {
778             fprintf(fp, "%s\t\t%s %s\n", cp, hp, cp2);
779             fprintf(fp, "%s\t\t%s.\n", cp, hp);
780         }
781     }
782     fclose(fp);
783     if (isDebug())
784         msgDebug("Wrote out /etc/hosts\n");
785     return DITEM_SUCCESS;
786 }
787
788 int
789 configRouter(dialogMenuItem *self)
790 {
791     int ret;
792
793     ret = variable_get_value(VAR_ROUTER,
794                              "Please specify the router you wish to use.  Routed is\n"
795                              "provided with the stock system and gated is provided\n"
796                              "as an optional package which this installation system\n"
797                              "will attempt to load if you select gated.  Any other\n"
798                              "choice of routing daemon will be assumed to be something\n"
799                              "the user intends to install themselves before rebooting\n"
800                              "the system.  If you don't want any routing daemon, choose NO", 1)
801       ? DITEM_SUCCESS : DITEM_FAILURE;
802   
803     if (ret == DITEM_SUCCESS) {
804         char *cp = variable_get(VAR_ROUTER);
805     
806         if (cp && strcmp(cp, "NO")) {
807             variable_set2(VAR_ROUTER_ENABLE, "YES", 1);
808             if (!strcmp(cp, "gated")) {
809                 if (package_add("gated") != DITEM_SUCCESS) {
810                     msgConfirm("Unable to load gated package.  Falling back to no router.");
811                     variable_unset(VAR_ROUTER);
812                     variable_unset(VAR_ROUTERFLAGS);
813                     variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
814                     cp = NULL;
815                 }
816             }
817             if (cp) {
818                 /* Now get the flags, if they chose a router */
819                 ret = variable_get_value(VAR_ROUTERFLAGS, 
820                                          "Please Specify the routing daemon flags; if you're running routed\n"
821                                          "then -q is the right choice for nodes and -s for gateway hosts.\n", 1)
822                   ? DITEM_SUCCESS : DITEM_FAILURE;
823                 if (ret != DITEM_SUCCESS)
824                     variable_unset(VAR_ROUTERFLAGS);
825             }
826         }
827         else {
828             /* No router case */
829             variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
830             variable_unset(VAR_ROUTERFLAGS);
831             variable_unset(VAR_ROUTER);
832         }
833     }
834     else {
835         variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
836         variable_unset(VAR_ROUTERFLAGS);
837         variable_unset(VAR_ROUTER);
838     }
839     return ret;
840 }
841
842 /* Shared between us and index_initialize() */
843 extern PkgNode Top, Plist;
844
845 int
846 configPackages(dialogMenuItem *self)
847 {
848     int i, restoreflag = 0;
849     PkgNodePtr tmp;
850
851     /* Did we get an INDEX? */
852     i = index_initialize("packages/INDEX");
853     if (DITEM_STATUS(i) == DITEM_FAILURE)
854         return i;
855
856     while (1) {
857         int ret, pos, scroll;
858
859         /* Bring up the packages menu */
860         pos = scroll = 0;
861         index_menu(&Top, &Top, &Plist, &pos, &scroll);
862
863         if (Plist.kids && Plist.kids->name) {
864             /* Now show the packing list menu */
865             pos = scroll = 0;
866             ret = index_menu(&Plist, &Plist, NULL, &pos, &scroll);
867             if (ret & DITEM_LEAVE_MENU)
868                 break;
869             else if (DITEM_STATUS(ret) != DITEM_FAILURE) {
870                 dialog_clear();
871                 restoreflag = 1;
872                 for (tmp = Plist.kids; tmp && tmp->name; tmp = tmp->next)
873                     (void)index_extract(mediaDevice, &Top, tmp, FALSE);
874                 break;
875             }
876         }
877         else {
878             msgConfirm("No packages were selected for extraction.");
879             break;
880         }
881     }
882     tmp = Plist.kids;
883     while (tmp) {
884         PkgNodePtr tmp2 = tmp->next;
885            
886         safe_free(tmp);
887         tmp = tmp2;
888     }
889     index_init(NULL, &Plist);
890     return DITEM_SUCCESS | (restoreflag ? DITEM_RESTORE : 0);
891 }
892
893 /* Load pcnfsd package */
894 int
895 configPCNFSD(dialogMenuItem *self)
896 {
897     int ret;
898
899     ret = package_add("pcnfsd");
900     if (DITEM_STATUS(ret) == DITEM_SUCCESS) {
901         variable_set2(VAR_PCNFSD, "YES", 0);
902         variable_set2("mountd_flags", "-n", 1);
903     }
904     return ret;
905 }
906
907 int
908 configInetd(dialogMenuItem *self)
909 {
910     char cmd[256];
911
912     WINDOW *w = savescr();
913
914     if (msgYesNo("The Internet Super Server (inetd) allows a number of simple Internet\n"
915                  "services to be enabled, including finger, ftp, and telnetd.  Enabling\n"
916                  "these services may increase risk of security problems by increasing\n"
917                  "the exposure of your system.\n\n"
918                  "With this in mind, do you wish to enable inetd?\n")) {
919         variable_set2("inetd_enable", "NO", 1);
920     } else {
921         /* If inetd is enabled, we'll need an inetd.conf */
922
923         if (!msgYesNo("inetd(8) relies on its configuration file, /etc/inetd.conf, to determine\n"
924                    "which of its Internet services will be available.  The default FreeBSD\n"
925                    "inetd.conf(5) leaves all services disabled by default, so they must be\n"
926                    "specifically enabled in the configuration file before they will\n"
927                    "function, even once inetd(8) is enabled.  Note that services for\n"
928                    "IPv6 must be separately enabled from IPv4 services.\n\n"
929                    "Select [Yes] now to invoke an editor on /etc/inetd.conf, or [No] to\n"
930                    "use the current settings.\n")) {
931             sprintf(cmd, "%s /etc/inetd.conf", variable_get(VAR_EDITOR));
932             dialog_clear();
933             systemExecute(cmd);
934             variable_set2("inetd_enable", "YES", 1);
935         }
936     }
937     restorescr(w);
938     return DITEM_SUCCESS;
939 }
940
941 int
942 configNFSServer(dialogMenuItem *self)
943 {
944     char cmd[256];
945
946     /* If we're an NFS server, we need an exports file */
947     if (!file_readable("/etc/exports")) {
948         WINDOW *w = savescr();
949
950         if (file_readable("/etc/exports.disabled"))
951             vsystem("mv /etc/exports.disabled /etc/exports");
952         else {
953             dialog_clear_norefresh();
954             msgConfirm("Operating as an NFS server means that you must first configure\n"
955                        "an /etc/exports file to indicate which hosts are allowed certain\n"
956                        "kinds of access to your local file systems.\n"
957                        "Press [ENTER] now to invoke an editor on /etc/exports\n");
958             vsystem("echo '#The following examples export /usr to 3 machines named after ducks,' > /etc/exports");
959             vsystem("echo '#/home and all directories under it to machines named after dead rock stars' >> /etc/exports");
960             vsystem("echo '#and, finally, /a to 2 privileged machines allowed to write on it as root.' >> /etc/exports");
961             vsystem("echo '#/usr                huey louie dewie' >> /etc/exports");
962             vsystem("echo '#/home   -alldirs    janice jimmy frank' >> /etc/exports");
963             vsystem("echo '#/a      -maproot=0  bill albert' >> /etc/exports");
964             vsystem("echo '#' >> /etc/exports");
965             vsystem("echo '# You should replace these lines with your actual exported filesystems.' >> /etc/exports");
966             vsystem("echo >> /etc/exports");
967             sprintf(cmd, "%s /etc/exports", variable_get(VAR_EDITOR));
968             dialog_clear();
969             systemExecute(cmd);
970         }
971         variable_set2(VAR_NFS_SERVER, "YES", 1);
972         restorescr(w);
973     }
974     else if (variable_get(VAR_NFS_SERVER)) { /* We want to turn it off again? */
975         vsystem("mv -f /etc/exports /etc/exports.disabled");
976         variable_unset(VAR_NFS_SERVER);
977     }
978     return DITEM_SUCCESS;
979 }
980
981 int
982 configEtcTtys(dialogMenuItem *self)
983 {
984     char cmd[256];
985
986     WINDOW *w = savescr();
987
988     /* Simply prompt for confirmation, then edit away. */
989     if (msgYesNo("Configuration of system TTYs requires editing the /etc/ttys file.\n"
990                  "Typical configuration activities might include enabling getty(8)\n"
991                  "on the first serial port to allow login via serial console after\n"
992                  "reboot, or to enable xdm.  The default ttys file enables normal\n"
993                  "virtual consoles, and most sites will not need to perform manual\n"
994                  "configuration.\n\n"
995                  "To load /etc/ttys in the editor, select [Yes], otherwise, [No].")) {
996     } else {
997         sprintf(cmd, "%s /etc/ttys", variable_get(VAR_EDITOR));
998         dialog_clear();
999         systemExecute(cmd);
1000     }
1001
1002     restorescr(w);
1003     return DITEM_SUCCESS;
1004 }