]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sade/config.c
G/C some cruft.
[FreeBSD/FreeBSD.git] / usr.sbin / sade / 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$
8  *
9  * Copyright (c) 1995
10  *      Jordan Hubbard.  All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer,
17  *    verbatim and that no modifications are made prior to this
18  *    point in the file.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  */
36
37 #include "sysinstall.h"
38 #include <sys/disklabel.h>
39 #include <sys/wait.h>
40 #include <sys/errno.h>
41 #include <sys/ioctl.h>
42 #include <sys/fcntl.h>
43 #include <sys/param.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 #include <sys/mount.h>
47 #include <libdisk.h>
48 #include <time.h>
49 #include <kenv.h>
50
51 static Chunk *chunk_list[MAX_CHUNKS];
52 static int nchunks;
53 static int rootdev_is_od;
54
55 /* arg to sort */
56 static int
57 chunk_compare(Chunk *c1, Chunk *c2)
58 {
59     if (!c1 && !c2)
60         return 0;
61     else if (!c1 && c2)
62         return 1;
63     else if (c1 && !c2)
64         return -1;
65     else if (!c1->private_data && !c2->private_data)
66         return 0;
67     else if (c1->private_data && !c2->private_data)
68         return 1;
69     else if (!c1->private_data && c2->private_data)
70         return -1;
71     else
72         return strcmp(((PartInfo *)(c1->private_data))->mountpoint, ((PartInfo *)(c2->private_data))->mountpoint);
73 }
74
75 static void
76 chunk_sort(void)
77 {
78     int i, j;
79
80     for (i = 0; i < nchunks; i++) {
81         for (j = 0; j < nchunks; j++) {
82             if (chunk_compare(chunk_list[j], chunk_list[j + 1]) > 0) {
83                 Chunk *tmp = chunk_list[j];
84
85                 chunk_list[j] = chunk_list[j + 1];
86                 chunk_list[j + 1] = tmp;
87             }
88         }
89     }
90 }
91
92 static void
93 check_rootdev(Chunk **list, int n)
94 {
95         int i;
96         Chunk *c;
97
98         rootdev_is_od = 0;
99         for (i = 0; i < n; i++) {
100                 c = *list++;
101                 if (c->type == part && (c->flags & CHUNK_IS_ROOT)
102                     && strncmp(c->disk->name, "od", 2) == 0)
103                         rootdev_is_od = 1;
104         }
105 }
106
107 static char *
108 name_of(Chunk *c1)
109 {
110     return c1->name;
111 }
112
113 static char *
114 mount_point(Chunk *c1)
115 {
116     if (c1->type == part && c1->subtype == FS_SWAP)
117         return "none";
118     else if (c1->type == part || c1->type == fat || c1->type == efi)
119         return ((PartInfo *)c1->private_data)->mountpoint;
120     return "/bogus";
121 }
122
123 static char *
124 fstype(Chunk *c1)
125 {
126     if (c1->type == fat || c1->type == efi)
127         return "msdosfs";
128     else if (c1->type == part) {
129         if (c1->subtype != FS_SWAP)
130             return "ufs";
131         else
132             return "swap";
133     }
134     return "bogus";
135 }
136
137 static char *
138 fstype_short(Chunk *c1)
139 {
140     if (c1->type == part) {
141         if (c1->subtype != FS_SWAP) {
142             if (rootdev_is_od == 0 && strncmp(c1->name, "od", 2) == 0)
143                 return "rw,noauto";
144             else
145                 return "rw";
146         }
147         else
148             return "sw";
149     }
150     else if (c1->type == fat) {
151         if (strncmp(c1->name, "od", 2) == 0)
152             return "ro,noauto";
153         else
154             return "ro";
155     }
156     else if (c1->type == efi)
157         return "rw";
158
159     return "bog";
160 }
161
162 static int
163 seq_num(Chunk *c1)
164 {
165     if (c1->type == part && c1->subtype != FS_SWAP) {
166         if (rootdev_is_od == 0 && strncmp(c1->name, "od", 2) == 0)
167             return 0;
168         else if (c1->flags & CHUNK_IS_ROOT)
169             return 1;
170         else
171             return 2;
172     }
173     return 0;
174 }
175
176 int
177 configFstab(dialogMenuItem *self)
178 {
179     Device **devs;
180     Disk *disk;
181     FILE *fstab;
182     int i, cnt;
183     Chunk *c1, *c2;
184
185     if (!RunningAsInit) {
186         if (file_readable("/etc/fstab"))
187             return DITEM_SUCCESS;
188         else {
189             msgConfirm("Attempting to rebuild your /etc/fstab file.  Warning: If you had\n"
190                        "any CD devices in use before running sysinstall then they may NOT\n"
191                        "be found by this run!");
192         }
193     }
194
195     devs = deviceFind(NULL, DEVICE_TYPE_DISK);
196     if (!devs) {
197         msgConfirm("No disks found!");
198         return DITEM_FAILURE;
199     }
200
201     /* Record all the chunks */
202     nchunks = 0;
203     for (i = 0; devs[i]; i++) {
204         if (!devs[i]->enabled)
205             continue;
206         disk = (Disk *)devs[i]->private;
207         if (!disk->chunks)
208             msgFatal("No chunk list found for %s!", disk->name);
209         for (c1 = disk->chunks->part; c1; c1 = c1->next) {
210 #ifdef __powerpc__
211             if (c1->type == apple) {
212 #else
213             if (c1->type == freebsd) {
214 #endif
215                 for (c2 = c1->part; c2; c2 = c2->next) {
216                     if (c2->type == part && (c2->subtype == FS_SWAP || c2->private_data))
217                         chunk_list[nchunks++] = c2;
218                 }
219             }
220             else if (((c1->type == fat || c1->type == efi || c1->type == part) &&
221                     c1->private_data) || (c1->type == part && c1->subtype == FS_SWAP))
222                 chunk_list[nchunks++] = c1;
223         }
224     }
225     chunk_list[nchunks] = 0;
226     chunk_sort();
227     
228     fstab = fopen("/etc/fstab", "w");
229     if (!fstab) {
230         msgConfirm("Unable to create a new /etc/fstab file!  Manual intervention\n"
231                    "will be required.");
232         return DITEM_FAILURE;
233     }
234     
235     check_rootdev(chunk_list, nchunks);
236     
237     /* Go for the burn */
238     msgDebug("Generating /etc/fstab file\n");
239     fprintf(fstab, "# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#\n");
240     for (i = 0; i < nchunks; i++)
241         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]),
242                 fstype(chunk_list[i]), fstype_short(chunk_list[i]), seq_num(chunk_list[i]), seq_num(chunk_list[i]));
243     
244     /* Now look for the CDROMs */
245     devs = deviceFind(NULL, DEVICE_TYPE_CDROM);
246     cnt = deviceCount(devs);
247     
248     /* Write out the CDROM entries */
249     for (i = 0; i < cnt; i++) {
250         char cdname[10];
251         
252         sprintf(cdname, "/cdrom%s", i ? itoa(i) : "");
253         if (Mkdir(cdname))
254             msgConfirm("Unable to make mount point for: %s", cdname);
255         else
256             fprintf(fstab, "/dev/%s\t\t%s\t\tcd9660\tro,noauto\t0\t0\n", devs[i]->name, cdname);
257     }
258     
259     fclose(fstab);
260     if (isDebug())
261         msgDebug("Wrote out /etc/fstab file\n");
262     return DITEM_SUCCESS;
263 }
264
265 /* Do the work of sucking in a config file.
266  * config is the filename to read in.
267  * lines is a fixed (max) sized array of char*
268  * returns number of lines read.  line contents
269  * are malloc'd and must be freed by the caller.
270  */
271 int
272 readConfig(char *config, char **lines, int max)
273 {
274     FILE *fp;
275     char line[256];
276     int i, nlines;
277
278     fp = fopen(config, "r");
279     if (!fp)
280         return -1;
281
282     nlines = 0;
283     /* Read in the entire file */
284     for (i = 0; i < max; i++) {
285         if (!fgets(line, sizeof line, fp))
286             break;
287         lines[nlines++] = strdup(line);
288     }
289     fclose(fp);
290     if (isDebug())
291         msgDebug("readConfig: Read %d lines from %s.\n", nlines, config);
292     return nlines;
293 }
294
295 #define MAX_LINES  2000 /* Some big number we're not likely to ever reach - I'm being really lazy here, I know */
296
297 static void
298 readConfigFile(char *config, int marked)
299 {
300     char *lines[MAX_LINES], *cp, *cp2;
301     int i, nlines;
302
303     nlines = readConfig(config, lines, MAX_LINES);
304     if (nlines == -1)
305         return;
306
307     for (i = 0; i < nlines; i++) {
308         /* Skip the comments & non-variable settings */
309         if (lines[i][0] == '#' || !(cp = index(lines[i], '='))) {
310             free(lines[i]);
311             continue;
312         }
313         *cp++ = '\0';
314         /* Find quotes */
315         if ((cp2 = index(cp, '"')) || (cp2 = index(cp, '\047'))) {
316             cp = cp2 + 1;
317             cp2 = index(cp, *cp2);
318         }
319         /* If valid quotes, use it */
320         if (cp2) {
321             *cp2 = '\0';
322             /* If we have a legit value, set it */
323             if (strlen(cp))
324                 variable_set2(lines[i], cp, marked);
325         }
326         free(lines[i]);
327     }
328 }
329
330 /* Load the environment from rc.conf file(s) */
331 void
332 configEnvironmentRC_conf(void)
333 {
334     static struct {
335         char *fname;
336         int marked;
337     } configs[] = {
338         { "/etc/defaults/rc.conf", 0 },
339         { "/etc/rc.conf", 0 },
340         { "/etc/rc.conf.local", 0 },
341         { NULL, 0 },
342     };
343     int i;
344
345     for (i = 0; configs[i].fname; i++) {
346         if (file_readable(configs[i].fname))
347             readConfigFile(configs[i].fname, configs[i].marked);
348     }
349 }
350
351 /* Load the environment from a resolv.conf file */
352 void
353 configEnvironmentResolv(char *config)
354 {
355     char *lines[MAX_LINES];
356     int i, nlines;
357
358     nlines = readConfig(config, lines, MAX_LINES);
359     if (nlines == -1)
360         return;
361     for (i = 0; i < nlines; i++) {
362         Boolean name_set = variable_get(VAR_NAMESERVER) ? 1 : 0;
363
364         if (!strncmp(lines[i], "domain", 6) && !variable_get(VAR_DOMAINNAME))
365             variable_set2(VAR_DOMAINNAME, string_skipwhite(string_prune(lines[i] + 6)), 0);
366         else if (!name_set && !strncmp(lines[i], "nameserver", 10)) {
367             /* Only take the first nameserver setting - we're lame */
368             variable_set2(VAR_NAMESERVER, string_skipwhite(string_prune(lines[i] + 10)), 0);
369         }
370         free(lines[i]);
371     }
372 }
373
374 /* Version of below for dispatch routines */
375 int
376 configRC(dialogMenuItem *unused)
377 {
378     configRC_conf();
379     return DITEM_SUCCESS;
380 }
381
382 /*
383  * Write out rc.conf
384  *
385  * rc.conf is sorted if running as init and the needed utilities are
386  * present
387  *
388  * If rc.conf is sorted, all variables in rc.conf which conflict with
389  * the variables in the environment are removed from the original
390  * rc.conf
391  */
392 void
393 configRC_conf(void)
394 {
395     char line[256];
396     FILE *rcSite, *rcOld;
397     Variable *v;
398     int write_header;
399     time_t t_loc;
400     char *cp;
401     static int did_marker = 0;
402     int do_sort;
403     int do_merge;
404     time_t tp;
405
406     configTtys();
407     write_header = !file_readable("/etc/rc.conf");
408     do_sort = RunningAsInit && file_readable("/usr/bin/sort") &&
409         file_readable("/usr/bin/uniq");
410     do_merge = do_sort && file_readable("/etc/rc.conf");
411
412     if(do_merge) {
413         rcSite = fopen("/etc/rc.conf.new", "w");
414     } else
415         rcSite = fopen("/etc/rc.conf", "a");
416     if (rcSite == NULL) {
417         msgError("Error opening new rc.conf for writing: %s (%u)", strerror(errno), errno);
418         return;
419     }
420
421     if (do_merge) {
422         /* "Copy" the old rc.conf */
423         rcOld = fopen("/etc/rc.conf", "r");
424         if(!rcOld) {
425             msgError("Error opening rc.conf for reading: %s (%u)", strerror(errno), errno);
426             return;
427         }
428         while(fgets(line, sizeof(line), rcOld)) {
429             if(line[0] == '#' || variable_check2(line) != 0)
430                 fprintf(rcSite, "%s", line);
431             else
432                 fprintf(rcSite, "#REMOVED: %s", line);
433         }
434         fclose(rcOld);
435     } else if (write_header) {
436         fprintf(rcSite, "# This file now contains just the overrides from /etc/defaults/rc.conf.\n");
437         fprintf(rcSite, "# Please make all changes to this file, not to /etc/defaults/rc.conf.\n\n");
438         fprintf(rcSite, "# Enable network daemons for user convenience.\n");
439         if ((t_loc = time(NULL)) != -1 && (cp = ctime(&t_loc)))
440             fprintf(rcSite, "# Created: %s", cp);
441     }
442
443     /* Now do variable substitutions */
444     for (v = VarHead; v; v = v->next) {
445         if (v->dirty) {
446             if (!did_marker) {
447                 time(&tp);
448                 fprintf(rcSite, "# -- sysinstall generated deltas -- # "
449                     "%s", ctime(&tp));
450                 did_marker = 1;
451             }
452             fprintf(rcSite, "%s=\"%s\"\n", v->name, v->value);
453             v->dirty = 0;
454         }
455     }
456     fclose(rcSite);
457
458     if(do_merge) {
459         if(rename("/etc/rc.conf.new", "/etc/rc.conf") != 0) {
460             msgError("Error renaming temporary rc.conf: %s (%u)", strerror(errno), errno);
461             return;
462         }
463     }
464
465     /* Tidy up the resulting file if it's late enough in the installation
466         for sort and uniq to be available */
467     if (do_sort) {
468         (void)vsystem("sort /etc/rc.conf | uniq > /etc/rc.conf.new && mv /etc/rc.conf.new /etc/rc.conf");
469     }
470 }
471
472 int
473 configSaver(dialogMenuItem *self)
474 {
475     variable_set((char *)self->data, 1);
476     if (!variable_get(VAR_BLANKTIME))
477         variable_set2(VAR_BLANKTIME, "300", 1);
478     return DITEM_SUCCESS;
479 }
480
481 int
482 configSaverTimeout(dialogMenuItem *self)
483 {
484     return (variable_get_value(VAR_BLANKTIME,
485             "Enter time-out period in seconds for screen saver", 1) ?
486         DITEM_SUCCESS : DITEM_FAILURE);
487 }
488
489 int
490 configNTP(dialogMenuItem *self)
491 {
492     int status;
493
494     status = variable_get_value(VAR_NTPDATE_FLAGS,
495                                 "Enter the name of an NTP server", 1)
496              ? DITEM_SUCCESS : DITEM_FAILURE;
497     if (status == DITEM_SUCCESS) {
498         static char tmp[255];
499
500         snprintf(tmp, sizeof(tmp), "ntpdate_enable=YES,ntpdate_flags=%s",
501                  variable_get(VAR_NTPDATE_FLAGS));
502         self->data = tmp;
503         dmenuSetVariables(self);
504     }
505     return status;
506 }
507
508 int
509 configCountry(dialogMenuItem *self)
510 {
511     int choice, scroll, curr, max;
512
513     WINDOW *w = savescr();
514
515     dialog_clear_norefresh();
516     dmenuSetDefaultItem(&MenuCountry, NULL, NULL,
517         VAR_COUNTRY "=" DEFAULT_COUNTRY, &choice, &scroll, &curr, &max);
518     dmenuOpen(&MenuCountry, &choice, &scroll, &curr, &max, FALSE);
519     restorescr(w);
520     return DITEM_SUCCESS;
521 }
522
523 int
524 configUsers(dialogMenuItem *self)
525 {
526     WINDOW *w = savescr();
527
528     dialog_clear_norefresh();
529     dmenuOpenSimple(&MenuUsermgmt, FALSE); 
530     restorescr(w);
531     return DITEM_SUCCESS;
532 }
533
534 #ifdef WITH_LINUX
535 int
536 configLinux(dialogMenuItem *self)
537 {
538     WINDOW *w = savescr();
539     int i;
540
541     dialog_clear_norefresh();
542     variable_set2(VAR_LINUX_ENABLE, "YES", 1);
543     Mkdir("/compat/linux");
544     msgNotify("Installing Linux compatibility library...");
545     i = package_add("linux_base-8");
546     restorescr(w);
547     return i;
548 }
549 #endif
550
551 #ifdef __alpha__
552 int
553 configOSF1(dialogMenuItem *self)
554 {
555
556     variable_set2(VAR_OSF1_ENABLE, "YES", 1);
557     Mkdir("/compat/osf1");
558     return DITEM_SUCCESS;
559 }
560 #endif
561
562 int
563 configSecurelevel(dialogMenuItem *self)
564 {
565     WINDOW *w = savescr();
566
567     dialog_clear_norefresh();
568     dmenuOpenSimple(&MenuSecurelevel, FALSE);
569     restorescr(w);
570     return DITEM_SUCCESS;
571 }
572
573 int
574 configSecurelevelDisabled(dialogMenuItem *self)
575 {
576
577     variable_set2("kern_securelevel_enable", "NO", 1);
578     return DITEM_SUCCESS;
579 }
580
581 int
582 configSecurelevelSecure(dialogMenuItem *self)
583 {
584
585     variable_set2("kern_securelevel_enable", "YES", 1);
586     variable_set2("kern_securelevel", "1", 1);
587     return DITEM_SUCCESS;
588 }
589
590 int
591 configSecurelevelHighlySecure(dialogMenuItem *self)
592 {
593
594     variable_set2("kern_securelevel_enable", "YES", 1);
595     variable_set2("kern_securelevel", "2", 1);
596     return DITEM_SUCCESS;
597 }
598
599 int
600 configSecurelevelNetworkSecure(dialogMenuItem *self)
601 {
602
603     variable_set2("kern_securelevel_enable", "YES", 1);
604     variable_set2("kern_securelevel", "3", 1);
605     return DITEM_SUCCESS;
606 }
607
608 int
609 configSecurity(dialogMenuItem *self)
610 {
611     WINDOW *w = savescr();
612
613     dialog_clear_norefresh();
614     dmenuOpenSimple(&MenuSecurity, FALSE);
615     restorescr(w);
616     return DITEM_SUCCESS;
617 }
618
619 int
620 configResolv(dialogMenuItem *ditem)
621 {
622     FILE *fp;
623     char *cp, *c6p, *dp, *hp;
624
625     cp = variable_get(VAR_NAMESERVER);
626     if (!cp || !*cp)
627         goto skip;
628     Mkdir("/etc");
629     fp = fopen("/etc/resolv.conf", "w");
630     if (!fp)
631         return DITEM_FAILURE;
632     if (variable_get(VAR_DOMAINNAME))
633         fprintf(fp, "domain\t%s\n", variable_get(VAR_DOMAINNAME));
634     fprintf(fp, "nameserver\t%s\n", cp);
635     fclose(fp);
636     if (isDebug())
637         msgDebug("Wrote out /etc/resolv.conf\n");
638
639 skip:
640     dp = variable_get(VAR_DOMAINNAME);
641     cp = variable_get(VAR_IPADDR);
642     c6p = variable_get(VAR_IPV6ADDR);
643     hp = variable_get(VAR_HOSTNAME);
644     /* Tack ourselves into /etc/hosts */
645     fp = fopen("/etc/hosts", "w");
646     if (!fp)
647         return DITEM_FAILURE;
648     /* Add an entry for localhost */
649     if (dp) {
650         fprintf(fp, "::1\t\t\tlocalhost.%s localhost\n", dp);
651         fprintf(fp, "127.0.0.1\t\tlocalhost.%s localhost\n", dp);
652     } else {
653         fprintf(fp, "::1\t\t\tlocalhost\n");
654         fprintf(fp, "127.0.0.1\t\tlocalhost\n");
655     }
656     /* Now the host entries, if applicable */
657     if (((cp && cp[0] != '0') || (c6p && c6p[0] != '0')) && hp) {
658         char cp2[255];
659
660         if (!index(hp, '.'))
661             cp2[0] = '\0';
662         else {
663             SAFE_STRCPY(cp2, hp);
664             *(index(cp2, '.')) = '\0';
665         }
666         if (c6p && c6p[0] != '0') {
667             fprintf(fp, "%s\t%s %s\n", c6p, hp, cp2);
668             fprintf(fp, "%s\t%s.\n", c6p, hp);
669         }
670         if (cp && cp[0] != '0') {
671             fprintf(fp, "%s\t\t%s %s\n", cp, hp, cp2);
672             fprintf(fp, "%s\t\t%s.\n", cp, hp);
673         }
674     }
675     fclose(fp);
676     if (isDebug())
677         msgDebug("Wrote out /etc/hosts\n");
678     return DITEM_SUCCESS;
679 }
680
681 int
682 configRouter(dialogMenuItem *self)
683 {
684     int ret;
685
686     ret = variable_get_value(VAR_ROUTER,
687                              "Please specify the router you wish to use.  Routed is\n"
688                              "provided with the stock system and gated is provided\n"
689                              "as an optional package which this installation system\n"
690                              "will attempt to load if you select gated.  Any other\n"
691                              "choice of routing daemon will be assumed to be something\n"
692                              "the user intends to install themselves before rebooting\n"
693                              "the system.  If you don't want any routing daemon, choose NO", 1)
694       ? DITEM_SUCCESS : DITEM_FAILURE;
695   
696     if (ret == DITEM_SUCCESS) {
697         char *cp = variable_get(VAR_ROUTER);
698     
699         if (cp && strcmp(cp, "NO")) {
700             variable_set2(VAR_ROUTER_ENABLE, "YES", 1);
701             if (!strcmp(cp, "gated")) {
702                 if (package_add("gated") != DITEM_SUCCESS) {
703                     msgConfirm("Unable to load gated package.  Falling back to no router.");
704                     variable_unset(VAR_ROUTER);
705                     variable_unset(VAR_ROUTERFLAGS);
706                     variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
707                     cp = NULL;
708                 }
709             }
710             if (cp) {
711                 /* Now get the flags, if they chose a router */
712                 ret = variable_get_value(VAR_ROUTERFLAGS, 
713                                          "Please Specify the routing daemon flags; if you're running routed\n"
714                                          "then -q is the right choice for nodes and -s for gateway hosts.\n", 1)
715                   ? DITEM_SUCCESS : DITEM_FAILURE;
716                 if (ret != DITEM_SUCCESS)
717                     variable_unset(VAR_ROUTERFLAGS);
718             }
719         }
720         else {
721             /* No router case */
722             variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
723             variable_unset(VAR_ROUTERFLAGS);
724             variable_unset(VAR_ROUTER);
725         }
726     }
727     else {
728         variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
729         variable_unset(VAR_ROUTERFLAGS);
730         variable_unset(VAR_ROUTER);
731     }
732     return ret;
733 }
734
735 /* Shared between us and index_initialize() */
736 extern PkgNode Top, Plist;
737
738 int
739 configPackages(dialogMenuItem *self)
740 {
741     int i, restoreflag = 0;
742     PkgNodePtr tmp;
743
744     /* Did we get an INDEX? */
745     i = index_initialize("packages/INDEX");
746     if (DITEM_STATUS(i) == DITEM_FAILURE)
747         return i;
748
749     while (1) {
750         int ret, pos, scroll;
751
752         /* Bring up the packages menu */
753         pos = scroll = 0;
754         index_menu(&Top, &Top, &Plist, &pos, &scroll);
755
756         if (Plist.kids && Plist.kids->name) {
757             /* Now show the packing list menu */
758             pos = scroll = 0;
759             ret = index_menu(&Plist, &Plist, NULL, &pos, &scroll);
760             if (ret & DITEM_LEAVE_MENU)
761                 break;
762             else if (DITEM_STATUS(ret) != DITEM_FAILURE) {
763                 dialog_clear();
764                 restoreflag = 1;
765                 for (tmp = Plist.kids; tmp && tmp->name; tmp = tmp->next)
766                     (void)index_extract(mediaDevice, &Top, tmp, FALSE);
767                 break;
768             }
769         }
770         else {
771             msgConfirm("No packages were selected for extraction.");
772             break;
773         }
774     }
775     tmp = Plist.kids;
776     while (tmp) {
777         PkgNodePtr tmp2 = tmp->next;
778            
779         safe_free(tmp);
780         tmp = tmp2;
781     }
782     index_init(NULL, &Plist);
783     return DITEM_SUCCESS | (restoreflag ? DITEM_RESTORE : 0);
784 }
785
786 /* Load pcnfsd package */
787 int
788 configPCNFSD(dialogMenuItem *self)
789 {
790     int ret;
791
792     ret = package_add("pcnfsd");
793     if (DITEM_STATUS(ret) == DITEM_SUCCESS) {
794         variable_set2(VAR_PCNFSD, "YES", 0);
795         variable_set2("mountd_flags", "-n", 1);
796     }
797     return ret;
798 }
799
800 int
801 configInetd(dialogMenuItem *self)
802 {
803     char cmd[256];
804
805     WINDOW *w = savescr();
806
807     if (msgYesNo("The Internet Super Server (inetd) allows a number of simple Internet\n"
808                  "services to be enabled, including finger, ftp, and telnetd.  Enabling\n"
809                  "these services may increase risk of security problems by increasing\n"
810                  "the exposure of your system.\n\n"
811                  "With this in mind, do you wish to enable inetd?\n")) {
812         variable_set2("inetd_enable", "NO", 1);
813     } else {
814         /* If inetd is enabled, we'll need an inetd.conf */
815         variable_set2("inetd_enable", "YES", 1);
816         if (!msgYesNo("inetd(8) relies on its configuration file, /etc/inetd.conf, to determine\n"
817                    "which of its Internet services will be available.  The default FreeBSD\n"
818                    "inetd.conf(5) leaves all services disabled by default, so they must be\n"
819                    "specifically enabled in the configuration file before they will\n"
820                    "function, even once inetd(8) is enabled.  Note that services for\n"
821                    "IPv6 must be separately enabled from IPv4 services.\n\n"
822                    "Select [Yes] now to invoke an editor on /etc/inetd.conf, or [No] to\n"
823                    "use the current settings.\n")) {
824             sprintf(cmd, "%s /etc/inetd.conf", variable_get(VAR_EDITOR));
825             dialog_clear();
826             systemExecute(cmd);
827         }
828     }
829     restorescr(w);
830     return DITEM_SUCCESS;
831 }
832
833 int
834 configNFSServer(dialogMenuItem *self)
835 {
836     char cmd[256];
837     int retval = 0;
838
839     /* If we're an NFS server, we need an exports file */
840     if (!file_readable("/etc/exports")) {
841         WINDOW *w = savescr();
842
843         if (file_readable("/etc/exports.disabled"))
844             vsystem("mv /etc/exports.disabled /etc/exports");
845         else {
846             dialog_clear_norefresh();
847             msgConfirm("Operating as an NFS server means that you must first configure\n"
848                        "an /etc/exports file to indicate which hosts are allowed certain\n"
849                        "kinds of access to your local file systems.\n"
850                        "Press [ENTER] now to invoke an editor on /etc/exports\n");
851             vsystem("echo '#The following examples export /usr to 3 machines named after ducks,' > /etc/exports");
852             vsystem("echo '#/usr/src and /usr/ports read-only to machines named after trouble makers' >> /etc/exports");
853             vsystem("echo '#/home and all directories under it to machines named after dead rock stars' >> /etc/exports");
854             vsystem("echo '#and, /a to a network of privileged machines allowed to write on it as root.' >> /etc/exports");
855             vsystem("echo '#/usr                   huey louie dewie' >> /etc/exports");
856             vsystem("echo '#/usr/src /usr/obj -ro  calvin hobbes' >> /etc/exports");
857             vsystem("echo '#/home   -alldirs       janice jimmy frank' >> /etc/exports");
858             vsystem("echo '#/a      -maproot=0  -network 10.0.1.0 -mask 255.255.248.0' >> /etc/exports");
859             vsystem("echo '#' >> /etc/exports");
860             vsystem("echo '# You should replace these lines with your actual exported filesystems.' >> /etc/exports");
861             vsystem("echo \"# Note that BSD's export syntax is 'host-centric' vs. Sun's 'FS-centric' one.\" >> /etc/exports");
862             vsystem("echo >> /etc/exports");
863             sprintf(cmd, "%s /etc/exports", variable_get(VAR_EDITOR));
864             dialog_clear();
865             systemExecute(cmd);
866         }
867         variable_set2(VAR_NFS_SERVER, "YES", 1);
868         retval = configRpcBind(NULL);
869         restorescr(w);
870     }
871     else if (variable_get(VAR_NFS_SERVER)) { /* We want to turn it off again? */
872         vsystem("mv -f /etc/exports /etc/exports.disabled");
873         variable_unset(VAR_NFS_SERVER);
874     }
875     return DITEM_SUCCESS | retval;
876 }
877
878 /*
879  * Extend the standard dmenuToggleVariable() method to also check and set
880  * the rpcbind variable if needed.
881  */
882 int
883 configRpcBind(dialogMenuItem *self)
884 {
885     int retval = 0;
886     int doupdate = 1;
887
888     if (self != NULL) {
889         retval = dmenuToggleVariable(self);
890         if (strcmp(variable_get(self->data), "YES") != 0)
891             doupdate = 0;
892     }
893
894     if (doupdate && strcmp(variable_get(VAR_RPCBIND_ENABLE), "YES") != 0) {
895         variable_set2(VAR_RPCBIND_ENABLE, "YES", 1);
896         retval |= DITEM_REDRAW;
897     }
898
899    return retval;
900 }
901
902 int
903 configEtcTtys(dialogMenuItem *self)
904 {
905     char cmd[256];
906
907     WINDOW *w = savescr();
908
909     /* Simply prompt for confirmation, then edit away. */
910     if (msgYesNo("Configuration of system TTYs requires editing the /etc/ttys file.\n"
911                  "Typical configuration activities might include enabling getty(8)\n"
912                  "on the first serial port to allow login via serial console after\n"
913                  "reboot, or to enable xdm.  The default ttys file enables normal\n"
914                  "virtual consoles, and most sites will not need to perform manual\n"
915                  "configuration.\n\n"
916                  "To load /etc/ttys in the editor, select [Yes], otherwise, [No].")) {
917     } else {
918         configTtys();
919         sprintf(cmd, "%s /etc/ttys", variable_get(VAR_EDITOR));
920         dialog_clear();
921         systemExecute(cmd);
922     }
923
924     restorescr(w);
925     return DITEM_SUCCESS;
926 }
927
928 #ifdef __i386__
929 int
930 checkLoaderACPI(void)
931 {
932     char val[4];
933
934     if (kenv(KENV_GET, "loader.acpi_disabled_by_user", &val[0], 4) <= 0) {
935         return (0);
936     }
937
938     if (strtol(&val[0], NULL, 10) <= 0) {
939         return (0);
940     }
941
942     return (1);
943 }
944
945 int
946 configLoaderACPI(int disable)
947 {
948     FILE *ldconf;
949
950     ldconf = fopen("/boot/loader.conf", "a");
951     if (ldconf == NULL) {
952         msgConfirm("Unable to open /boot/loader.conf.  Please consult the\n"
953                   "FreeBSD Handbook for instructions on disabling ACPI");
954         return DITEM_FAILURE;
955     }
956
957     fprintf(ldconf, "# --- Generated by sysinstall ---\n");
958     fprintf(ldconf, "hint.acpi.0.disabled=%d\n", disable);
959     fclose(ldconf);
960
961     return DITEM_SUCCESS;
962
963 #endif
964
965 int
966 configMTAPostfix(dialogMenuItem *self)
967 {
968     int ret;
969     FILE *perconf;
970
971     if(setenv("POSTFIX_DEFAULT_MTA", "YES", 1) != 0)
972         msgError("Error setting the enviroment variable POSTFIX_DEFAULT_MTA: %s (%u)",
973                  strerror(errno), errno);
974
975     ret = package_add("postfix-2.2");
976     unsetenv("POSTFIX_DEFAULT_MTA");
977
978     if(DITEM_STATUS(ret) == DITEM_FAILURE) {
979         msgConfirm("An error occurred while adding the postfix package\n"
980                    "Please change installation media and try again.");
981         return ret;
982     }
983
984     variable_set2(VAR_SENDMAIL_ENABLE, "YES", 1);
985     variable_set2("sendmail_flags", "-bd", 1);
986     variable_set2("sendmail_outbound_enable", "NO", 1);
987     variable_set2("sendmail_submit_enable", "NO", 1);
988     variable_set2("sendmail_msp_queue_enable", "NO", 1);
989
990     perconf = fopen("/etc/periodic.conf", "a");
991     if (perconf == NULL) {
992         msgConfirm("Unable to open /etc/periodic.conf.\n"
993                    "The daily cleanup scripts might generate errors when\n"
994                    "trying to run some sendmail only cleanup scripts.\n"
995                    "Please consult the documentation for the postfix port on how to\n"
996                    "fix this.");
997
998         /* Not really a serious problem, so we return success */
999         return DITEM_SUCCESS;
1000     }
1001
1002     fprintf(perconf, "# --- Generated by sysinstall ---\n");
1003     fprintf(perconf, "daily_clean_hoststat_enable=\"NO\"\n");
1004     fprintf(perconf, "daily_status_mail_rejects_enable=\"NO\"\n");
1005     fprintf(perconf, "daily_status_include_submit_mailq=\"NO\"\n");
1006     fprintf(perconf, "daily_submit_queuerun=\"NO\"\n");
1007     fclose(perconf);
1008
1009     msgConfirm("Postfix is now installed and enabled as the default MTA.\n"
1010                "Please check that the configuration works as expected.\n"
1011                "See the Postfix documentation for more information.\n"
1012                "The documentation can be found in /usr/local/share/doc/postfix/\n"
1013                "or on the Postfix website at http://www.postfix.org/.");
1014
1015     return DITEM_SUCCESS;
1016 }
1017
1018 int
1019 configMTAExim(dialogMenuItem *self)
1020 {
1021     int ret;
1022     FILE *perconf, *mailerconf, *newsyslogconf;
1023
1024     ret = package_add("exim");
1025
1026     if(DITEM_STATUS(ret) == DITEM_FAILURE) {
1027         msgConfirm("An error occurred while adding the exim package\n"
1028                    "Please change installation media and try again.");
1029         return ret;
1030     }
1031
1032     variable_set2(VAR_SENDMAIL_ENABLE, "NONE", 1);
1033     variable_set2("exim_enable", "YES", 1);
1034
1035     /* Update periodic.conf */
1036     perconf = fopen("/etc/periodic.conf", "a");
1037     if (perconf == NULL) {
1038         /* Not really a serious problem, so we do not abort */
1039         msgConfirm("Unable to open /etc/periodic.conf.\n"
1040                    "The daily cleanup scripts might generate errors when\n"
1041                    "trying to run some sendmail only cleanup scripts.\n"
1042                    "Please consult the documentation for the exim port on how to\n"
1043                    "fix this.");
1044     } else {
1045         fprintf(perconf, "# --- Generated by sysinstall ---\n");
1046         fprintf(perconf, "daily_clean_hoststat_enable=\"NO\"\n");
1047         fprintf(perconf, "daily_status_include_submit_mailq=\"NO\"\n");
1048         fprintf(perconf, "daily_status_mail_rejects_enable=\"NO\"\n");
1049         fprintf(perconf, "daily_submit_queuerun=\"NO\"\n");
1050         fclose(perconf);
1051     }
1052
1053     /* Update mailer.conf */
1054     vsystem("mv -f /etc/mail/mailer.conf /etc/mail/mailer.conf.old");
1055     mailerconf = fopen("/etc/mail/mailer.conf", "w");
1056     if (mailerconf == NULL) {
1057         /* Not really a serious problem, so we do not abort */
1058         msgConfirm("Unable to open /etc/mailer.conf.\n"
1059                    "Some programs which use the sendmail wrappers may not work.\n"
1060                    "Please consult the documentation for the exim port on how\n"
1061                    "to correct this.");
1062     } else {
1063         fprintf(mailerconf, "# --- Generated by sysinstall ---\n");
1064         fprintf(mailerconf, "# Execute exim instead of sendmail\n");
1065         fprintf(mailerconf, "#\n");
1066         fprintf(mailerconf, "sendmail   /usr/local/sbin/exim\n");
1067         fprintf(mailerconf, "send-mail  /usr/local/sbin/exim\n");
1068         fprintf(mailerconf, "mailq              /usr/local/sbin/exim\n");
1069         fprintf(mailerconf, "newaliases /usr/local/sbin/exim\n");
1070         fprintf(mailerconf, "hoststat   /usr/bin/true\n");
1071         fprintf(mailerconf, "purgestat  /usr/bin/true\n");
1072         fclose(mailerconf);
1073     }
1074
1075     /* Make newsyslog rotate exim logfiles */
1076     newsyslogconf = fopen("/etc/newsyslog.conf", "a");
1077     if (newsyslogconf == NULL) {
1078         /* Not really a serious problem, so we do not abort */
1079         msgConfirm("Unable to open /etc/newsyslog.conf.\n"
1080                    "The exim logfiles will not be rotated.\n"
1081                    "Please consult the documentation for the exim port on how to\n"
1082                    "rotate the logfiles.");
1083     } else {
1084         fprintf(newsyslogconf, "# --- Generated by sysinstall ---\n");
1085         fprintf(newsyslogconf, "/var/log/exim/mainlog   mailnull:mail   640  7     *    @T00  ZN\n");
1086         fprintf(newsyslogconf, "/var/log/exim/rejectlog mailnull:mail   640  7     *    @T00  ZN\n");
1087         fclose(newsyslogconf);
1088     }
1089
1090     msgConfirm("Exim is now installed and enabled as the default MTA.\n"
1091                "Please check that the configuration works as expected.\n"
1092                "See the Exim documentation for more information.\n"
1093                "The documentation can be found in /usr/local/share/doc/exim/\n"
1094                "or on the Exim website at http://www.exim.org/.");
1095
1096     return DITEM_SUCCESS;
1097 }