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