]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/sysinstall/config.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / usr.sbin / 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$
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 %s then they may NOT\n"
191                        "be found by this run!", ProgName);
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 static 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-fc");
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 configResolv(dialogMenuItem *ditem)
610 {
611     FILE *fp;
612     char *cp, *c6p, *dp, *hp;
613
614     cp = variable_get(VAR_NAMESERVER);
615     if (!cp || !*cp)
616         goto skip;
617     Mkdir("/etc");
618     fp = fopen("/etc/resolv.conf", "w");
619     if (!fp)
620         return DITEM_FAILURE;
621     if (variable_get(VAR_DOMAINNAME))
622         fprintf(fp, "domain\t%s\n", variable_get(VAR_DOMAINNAME));
623     fprintf(fp, "nameserver\t%s\n", cp);
624     fclose(fp);
625     if (isDebug())
626         msgDebug("Wrote out /etc/resolv.conf\n");
627
628 skip:
629     dp = variable_get(VAR_DOMAINNAME);
630     cp = variable_get(VAR_IPADDR);
631     c6p = variable_get(VAR_IPV6ADDR);
632     hp = variable_get(VAR_HOSTNAME);
633     /* Tack ourselves into /etc/hosts */
634     fp = fopen("/etc/hosts", "w");
635     if (!fp)
636         return DITEM_FAILURE;
637     /* Add an entry for localhost */
638     if (dp) {
639         fprintf(fp, "::1\t\t\tlocalhost localhost.%s\n", dp);
640         fprintf(fp, "127.0.0.1\t\tlocalhost localhost.%s\n", dp);
641     } else {
642         fprintf(fp, "::1\t\t\tlocalhost\n");
643         fprintf(fp, "127.0.0.1\t\tlocalhost\n");
644     }
645     /* Now the host entries, if applicable */
646     if (((cp && cp[0] != '0') || (c6p && c6p[0] != '0')) && hp) {
647         char cp2[255];
648
649         if (!index(hp, '.'))
650             cp2[0] = '\0';
651         else {
652             SAFE_STRCPY(cp2, hp);
653             *(index(cp2, '.')) = '\0';
654         }
655         if (c6p && c6p[0] != '0') {
656             fprintf(fp, "%s\t%s %s\n", c6p, hp, cp2);
657             fprintf(fp, "%s\t%s.\n", c6p, hp);
658         }
659         if (cp && cp[0] != '0') {
660             fprintf(fp, "%s\t\t%s %s\n", cp, hp, cp2);
661             fprintf(fp, "%s\t\t%s.\n", cp, hp);
662         }
663     }
664     fclose(fp);
665     if (isDebug())
666         msgDebug("Wrote out /etc/hosts\n");
667     return DITEM_SUCCESS;
668 }
669
670 int
671 configRouter(dialogMenuItem *self)
672 {
673     int ret;
674
675     ret = variable_get_value(VAR_ROUTER,
676                              "Please specify the router you wish to use.  Routed is\n"
677                              "provided with the stock system and gated is provided\n"
678                              "as an optional package which this installation system\n"
679                              "will attempt to load if you select gated.  Any other\n"
680                              "choice of routing daemon will be assumed to be something\n"
681                              "the user intends to install themselves before rebooting\n"
682                              "the system.  If you don't want any routing daemon, choose NO", 1)
683       ? DITEM_SUCCESS : DITEM_FAILURE;
684   
685     if (ret == DITEM_SUCCESS) {
686         char *cp = variable_get(VAR_ROUTER);
687     
688         if (cp && strcmp(cp, "NO")) {
689             variable_set2(VAR_ROUTER_ENABLE, "YES", 1);
690             if (!strcmp(cp, "gated")) {
691                 if (package_add("gated") != DITEM_SUCCESS) {
692                     msgConfirm("Unable to load gated package.  Falling back to no router.");
693                     variable_unset(VAR_ROUTER);
694                     variable_unset(VAR_ROUTERFLAGS);
695                     variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
696                     cp = NULL;
697                 }
698             }
699             if (cp) {
700                 /* Now get the flags, if they chose a router */
701                 ret = variable_get_value(VAR_ROUTERFLAGS, 
702                                          "Please Specify the routing daemon flags; if you're running routed\n"
703                                          "then -q is the right choice for nodes and -s for gateway hosts.\n", 1)
704                   ? DITEM_SUCCESS : DITEM_FAILURE;
705                 if (ret != DITEM_SUCCESS)
706                     variable_unset(VAR_ROUTERFLAGS);
707             }
708         }
709         else {
710             /* No router case */
711             variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
712             variable_unset(VAR_ROUTERFLAGS);
713             variable_unset(VAR_ROUTER);
714         }
715     }
716     else {
717         variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
718         variable_unset(VAR_ROUTERFLAGS);
719         variable_unset(VAR_ROUTER);
720     }
721     return ret;
722 }
723
724 /* Shared between us and index_initialize() */
725 extern PkgNode Top, Plist;
726
727 int
728 configPackages(dialogMenuItem *self)
729 {
730     int i, restoreflag = 0;
731     PkgNodePtr tmp;
732
733     /* Did we get an INDEX? */
734     i = index_initialize("packages/INDEX");
735     if (DITEM_STATUS(i) == DITEM_FAILURE)
736         return i;
737
738     while (1) {
739         int ret, pos, scroll;
740         int current, low, high;
741
742         /* Bring up the packages menu */
743         pos = scroll = 0;
744         index_menu(&Top, &Top, &Plist, &pos, &scroll);
745
746         if (Plist.kids && Plist.kids->name) {
747             /* Now show the packing list menu */
748             pos = scroll = 0;
749             ret = index_menu(&Plist, &Plist, NULL, &pos, &scroll);
750             if (ret & DITEM_LEAVE_MENU)
751                 break;
752             else if (DITEM_STATUS(ret) != DITEM_FAILURE) {
753                 dialog_clear();
754                 restoreflag = 1;
755                 if (have_volumes) {
756                     low = low_volume;
757                     high = high_volume;
758                 } else
759                     low = high = 0;
760                 for (current = low; current <= high; current++)
761                     for (tmp = Plist.kids; tmp && tmp->name; tmp = tmp->next)
762                         (void)index_extract(mediaDevice, &Top, tmp, FALSE, current);
763                 break;
764             }
765         }
766         else {
767             msgConfirm("No packages were selected for extraction.");
768             break;
769         }
770     }
771     tmp = Plist.kids;
772     while (tmp) {
773         PkgNodePtr tmp2 = tmp->next;
774            
775         safe_free(tmp);
776         tmp = tmp2;
777     }
778     index_init(NULL, &Plist);
779     return DITEM_SUCCESS | (restoreflag ? DITEM_RESTORE : 0);
780 }
781
782 /* Load pcnfsd package */
783 int
784 configPCNFSD(dialogMenuItem *self)
785 {
786     int ret;
787
788     ret = package_add("pcnfsd");
789     if (DITEM_STATUS(ret) == DITEM_SUCCESS) {
790         variable_set2(VAR_PCNFSD, "YES", 0);
791         variable_set2("mountd_flags", "-n", 1);
792     }
793     return ret;
794 }
795
796 int
797 configInetd(dialogMenuItem *self)
798 {
799     char cmd[256];
800
801     WINDOW *w = savescr();
802
803     if (msgYesNo("The Internet Super Server (inetd) allows a number of simple Internet\n"
804                  "services to be enabled, including finger, ftp, and telnetd.  Enabling\n"
805                  "these services may increase risk of security problems by increasing\n"
806                  "the exposure of your system.\n\n"
807                  "With this in mind, do you wish to enable inetd?\n")) {
808         variable_set2("inetd_enable", "NO", 1);
809     } else {
810         /* If inetd is enabled, we'll need an inetd.conf */
811         variable_set2("inetd_enable", "YES", 1);
812         if (!msgYesNo("inetd(8) relies on its configuration file, /etc/inetd.conf, to determine\n"
813                    "which of its Internet services will be available.  The default FreeBSD\n"
814                    "inetd.conf(5) leaves all services disabled by default, so they must be\n"
815                    "specifically enabled in the configuration file before they will\n"
816                    "function, even once inetd(8) is enabled.  Note that services for\n"
817                    "IPv6 must be separately enabled from IPv4 services.\n\n"
818                    "Select [Yes] now to invoke an editor on /etc/inetd.conf, or [No] to\n"
819                    "use the current settings.\n")) {
820             sprintf(cmd, "%s /etc/inetd.conf", variable_get(VAR_EDITOR));
821             dialog_clear();
822             systemExecute(cmd);
823         }
824     }
825     restorescr(w);
826     return DITEM_SUCCESS;
827 }
828
829 int
830 configNFSServer(dialogMenuItem *self)
831 {
832     char cmd[256];
833     int retval = 0;
834
835     /* If we're an NFS server, we need an exports file */
836     if (!file_readable("/etc/exports")) {
837         WINDOW *w = savescr();
838
839         if (file_readable("/etc/exports.disabled"))
840             vsystem("mv /etc/exports.disabled /etc/exports");
841         else {
842             dialog_clear_norefresh();
843             msgConfirm("Operating as an NFS server means that you must first configure\n"
844                        "an /etc/exports file to indicate which hosts are allowed certain\n"
845                        "kinds of access to your local file systems.\n"
846                        "Press [ENTER] now to invoke an editor on /etc/exports\n");
847             vsystem("echo '#The following examples export /usr to 3 machines named after ducks,' > /etc/exports");
848             vsystem("echo '#/usr/src and /usr/obj read-only to machines named after trouble makers,' >> /etc/exports");
849             vsystem("echo '#/home and all directories under it to machines named after dead rock stars' >> /etc/exports");
850             vsystem("echo '#and, /a to a network of privileged machines allowed to write on it as root.' >> /etc/exports");
851             vsystem("echo '#/usr                   huey louie dewie' >> /etc/exports");
852             vsystem("echo '#/usr/src /usr/obj -ro  calvin hobbes' >> /etc/exports");
853             vsystem("echo '#/home   -alldirs       janice jimmy frank' >> /etc/exports");
854             vsystem("echo '#/a      -maproot=0  -network 10.0.1.0 -mask 255.255.248.0' >> /etc/exports");
855             vsystem("echo '#' >> /etc/exports");
856             vsystem("echo '# You should replace these lines with your actual exported filesystems.' >> /etc/exports");
857             vsystem("echo \"# Note that BSD's export syntax is 'host-centric' vs. Sun's 'FS-centric' one.\" >> /etc/exports");
858             vsystem("echo >> /etc/exports");
859             sprintf(cmd, "%s /etc/exports", variable_get(VAR_EDITOR));
860             dialog_clear();
861             systemExecute(cmd);
862         }
863         variable_set2(VAR_NFS_SERVER, "YES", 1);
864         retval = configRpcBind(NULL);
865         restorescr(w);
866     }
867     else if (variable_get(VAR_NFS_SERVER)) { /* We want to turn it off again? */
868         vsystem("mv -f /etc/exports /etc/exports.disabled");
869         variable_unset(VAR_NFS_SERVER);
870     }
871     return DITEM_SUCCESS | retval;
872 }
873
874 /*
875  * Extend the standard dmenuToggleVariable() method to also check and set
876  * the rpcbind variable if needed.
877  */
878 int
879 configRpcBind(dialogMenuItem *self)
880 {
881     char *tmp, *tmp2;
882     int retval = 0;
883     int doupdate = 1;
884
885     if (self != NULL) {
886         retval = dmenuToggleVariable(self);
887         tmp = strdup(self->data);
888         if ((tmp2 = index(tmp, '=')) != NULL)
889             *tmp2 = '\0';
890         if (strcmp(variable_get(tmp), "YES") != 0)
891             doupdate = 0;
892         free(tmp);
893     }
894
895     if (doupdate && strcmp(variable_get(VAR_RPCBIND_ENABLE), "YES") != 0) {
896         variable_set2(VAR_RPCBIND_ENABLE, "YES", 1);
897         retval |= DITEM_REDRAW;
898     }
899
900    return retval;
901 }
902
903 int
904 configEtcTtys(dialogMenuItem *self)
905 {
906     char cmd[256];
907
908     WINDOW *w = savescr();
909
910     /* Simply prompt for confirmation, then edit away. */
911     if (msgYesNo("Configuration of system TTYs requires editing the /etc/ttys file.\n"
912                  "Typical configuration activities might include enabling getty(8)\n"
913                  "on the first serial port to allow login via serial console after\n"
914                  "reboot, or to enable xdm.  The default ttys file enables normal\n"
915                  "virtual consoles, and most sites will not need to perform manual\n"
916                  "configuration.\n\n"
917                  "To load /etc/ttys in the editor, select [Yes], otherwise, [No].")) {
918     } else {
919         configTtys();
920         sprintf(cmd, "%s /etc/ttys", variable_get(VAR_EDITOR));
921         dialog_clear();
922         systemExecute(cmd);
923     }
924
925     restorescr(w);
926     return DITEM_SUCCESS;
927 }
928
929 #ifdef __i386__
930 int
931 checkLoaderACPI(void)
932 {
933     char val[4];
934
935     if (kenv(KENV_GET, "loader.acpi_disabled_by_user", &val[0], 4) <= 0) {
936         return (0);
937     }
938
939     if (strtol(&val[0], NULL, 10) <= 0) {
940         return (0);
941     }
942
943     return (1);
944 }
945
946 int
947 configLoaderACPI(int disable)
948 {
949     FILE *ldconf;
950
951     ldconf = fopen("/boot/loader.conf", "a");
952     if (ldconf == NULL) {
953         msgConfirm("Unable to open /boot/loader.conf.  Please consult the\n"
954                   "FreeBSD Handbook for instructions on disabling ACPI");
955         return DITEM_FAILURE;
956     }
957
958     fprintf(ldconf, "# --- Generated by sysinstall ---\n");
959     fprintf(ldconf, "hint.acpi.0.disabled=%d\n", disable);
960     fclose(ldconf);
961
962     return DITEM_SUCCESS;
963
964 #endif
965
966 int
967 configMTAPostfix(dialogMenuItem *self)
968 {
969     int ret;
970     FILE *perconf;
971
972     if(setenv("POSTFIX_DEFAULT_MTA", "YES", 1) != 0)
973         msgError("Error setting the enviroment variable POSTFIX_DEFAULT_MTA: %s (%u)",
974                  strerror(errno), errno);
975
976     ret = package_add("postfix-2.4");
977     unsetenv("POSTFIX_DEFAULT_MTA");
978
979     if(DITEM_STATUS(ret) == DITEM_FAILURE) {
980         msgConfirm("An error occurred while adding the postfix package\n"
981                    "Please change installation media and try again.");
982         return ret;
983     }
984
985     variable_set2(VAR_SENDMAIL_ENABLE, "YES", 1);
986     variable_set2("sendmail_flags", "-bd", 1);
987     variable_set2("sendmail_outbound_enable", "NO", 1);
988     variable_set2("sendmail_submit_enable", "NO", 1);
989     variable_set2("sendmail_msp_queue_enable", "NO", 1);
990
991     perconf = fopen("/etc/periodic.conf", "a");
992     if (perconf == NULL) {
993         msgConfirm("Unable to open /etc/periodic.conf.\n"
994                    "The daily cleanup scripts might generate errors when\n"
995                    "trying to run some sendmail only cleanup scripts.\n"
996                    "Please consult the documentation for the postfix port on how to\n"
997                    "fix this.");
998
999         /* Not really a serious problem, so we return success */
1000         return DITEM_SUCCESS;
1001     }
1002
1003     fprintf(perconf, "# --- Generated by sysinstall ---\n");
1004     fprintf(perconf, "daily_clean_hoststat_enable=\"NO\"\n");
1005     fprintf(perconf, "daily_status_mail_rejects_enable=\"NO\"\n");
1006     fprintf(perconf, "daily_status_include_submit_mailq=\"NO\"\n");
1007     fprintf(perconf, "daily_submit_queuerun=\"NO\"\n");
1008     fclose(perconf);
1009
1010     msgConfirm("Postfix is now installed and enabled as the default MTA.\n"
1011                "Please check that the configuration works as expected.\n"
1012                "See the Postfix documentation for more information.\n"
1013                "The documentation can be found in /usr/local/share/doc/postfix/\n"
1014                "or on the Postfix website at http://www.postfix.org/.");
1015
1016     return DITEM_SUCCESS;
1017 }
1018
1019 int
1020 configMTAExim(dialogMenuItem *self)
1021 {
1022     int ret;
1023     FILE *perconf, *mailerconf, *newsyslogconf;
1024
1025     ret = package_add("exim");
1026
1027     if(DITEM_STATUS(ret) == DITEM_FAILURE) {
1028         msgConfirm("An error occurred while adding the exim package\n"
1029                    "Please change installation media and try again.");
1030         return ret;
1031     }
1032
1033     variable_set2(VAR_SENDMAIL_ENABLE, "NONE", 1);
1034     variable_set2("exim_enable", "YES", 1);
1035
1036     /* Update periodic.conf */
1037     perconf = fopen("/etc/periodic.conf", "a");
1038     if (perconf == NULL) {
1039         /* Not really a serious problem, so we do not abort */
1040         msgConfirm("Unable to open /etc/periodic.conf.\n"
1041                    "The daily cleanup scripts might generate errors when\n"
1042                    "trying to run some sendmail only cleanup scripts.\n"
1043                    "Please consult the documentation for the exim port on how to\n"
1044                    "fix this.");
1045     } else {
1046         fprintf(perconf, "# --- Generated by sysinstall ---\n");
1047         fprintf(perconf, "daily_clean_hoststat_enable=\"NO\"\n");
1048         fprintf(perconf, "daily_status_include_submit_mailq=\"NO\"\n");
1049         fprintf(perconf, "daily_status_mail_rejects_enable=\"NO\"\n");
1050         fprintf(perconf, "daily_submit_queuerun=\"NO\"\n");
1051         fclose(perconf);
1052     }
1053
1054     /* Update mailer.conf */
1055     vsystem("mv -f /etc/mail/mailer.conf /etc/mail/mailer.conf.old");
1056     mailerconf = fopen("/etc/mail/mailer.conf", "w");
1057     if (mailerconf == NULL) {
1058         /* Not really a serious problem, so we do not abort */
1059         msgConfirm("Unable to open /etc/mailer.conf.\n"
1060                    "Some programs which use the sendmail wrappers may not work.\n"
1061                    "Please consult the documentation for the exim port on how\n"
1062                    "to correct this.");
1063     } else {
1064         fprintf(mailerconf, "# --- Generated by sysinstall ---\n");
1065         fprintf(mailerconf, "# Execute exim instead of sendmail\n");
1066         fprintf(mailerconf, "#\n");
1067         fprintf(mailerconf, "sendmail   /usr/local/sbin/exim\n");
1068         fprintf(mailerconf, "send-mail  /usr/local/sbin/exim\n");
1069         fprintf(mailerconf, "mailq              /usr/local/sbin/exim\n");
1070         fprintf(mailerconf, "newaliases /usr/local/sbin/exim\n");
1071         fprintf(mailerconf, "hoststat   /usr/bin/true\n");
1072         fprintf(mailerconf, "purgestat  /usr/bin/true\n");
1073         fclose(mailerconf);
1074     }
1075
1076     /* Make newsyslog rotate exim logfiles */
1077     newsyslogconf = fopen("/etc/newsyslog.conf", "a");
1078     if (newsyslogconf == NULL) {
1079         /* Not really a serious problem, so we do not abort */
1080         msgConfirm("Unable to open /etc/newsyslog.conf.\n"
1081                    "The exim logfiles will not be rotated.\n"
1082                    "Please consult the documentation for the exim port on how to\n"
1083                    "rotate the logfiles.");
1084     } else {
1085         fprintf(newsyslogconf, "# --- Generated by sysinstall ---\n");
1086         fprintf(newsyslogconf, "/var/log/exim/mainlog   mailnull:mail   640  7     *    @T00  ZN\n");
1087         fprintf(newsyslogconf, "/var/log/exim/rejectlog mailnull:mail   640  7     *    @T00  ZN\n");
1088         fclose(newsyslogconf);
1089     }
1090
1091     msgConfirm("Exim is now installed and enabled as the default MTA.\n"
1092                "Please check that the configuration works as expected.\n"
1093                "See the Exim documentation for more information.\n"
1094                "The documentation can be found in /usr/local/share/doc/exim/\n"
1095                "or on the Exim website at http://www.exim.org/.");
1096
1097     return DITEM_SUCCESS;
1098 }