]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sysinstall/config.c
Add line edit and history support to ngctl(8) via editline(3).
[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 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-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 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.%s localhost\n", dp);
640         fprintf(fp, "127.0.0.1\t\tlocalhost.%s localhost\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
741         /* Bring up the packages menu */
742         pos = scroll = 0;
743         index_menu(&Top, &Top, &Plist, &pos, &scroll);
744
745         if (Plist.kids && Plist.kids->name) {
746             /* Now show the packing list menu */
747             pos = scroll = 0;
748             ret = index_menu(&Plist, &Plist, NULL, &pos, &scroll);
749             if (ret & DITEM_LEAVE_MENU)
750                 break;
751             else if (DITEM_STATUS(ret) != DITEM_FAILURE) {
752                 dialog_clear();
753                 restoreflag = 1;
754                 for (tmp = Plist.kids; tmp && tmp->name; tmp = tmp->next)
755                     (void)index_extract(mediaDevice, &Top, tmp, FALSE);
756                 break;
757             }
758         }
759         else {
760             msgConfirm("No packages were selected for extraction.");
761             break;
762         }
763     }
764     tmp = Plist.kids;
765     while (tmp) {
766         PkgNodePtr tmp2 = tmp->next;
767            
768         safe_free(tmp);
769         tmp = tmp2;
770     }
771     index_init(NULL, &Plist);
772     return DITEM_SUCCESS | (restoreflag ? DITEM_RESTORE : 0);
773 }
774
775 /* Load pcnfsd package */
776 int
777 configPCNFSD(dialogMenuItem *self)
778 {
779     int ret;
780
781     ret = package_add("pcnfsd");
782     if (DITEM_STATUS(ret) == DITEM_SUCCESS) {
783         variable_set2(VAR_PCNFSD, "YES", 0);
784         variable_set2("mountd_flags", "-n", 1);
785     }
786     return ret;
787 }
788
789 int
790 configInetd(dialogMenuItem *self)
791 {
792     char cmd[256];
793
794     WINDOW *w = savescr();
795
796     if (msgYesNo("The Internet Super Server (inetd) allows a number of simple Internet\n"
797                  "services to be enabled, including finger, ftp, and telnetd.  Enabling\n"
798                  "these services may increase risk of security problems by increasing\n"
799                  "the exposure of your system.\n\n"
800                  "With this in mind, do you wish to enable inetd?\n")) {
801         variable_set2("inetd_enable", "NO", 1);
802     } else {
803         /* If inetd is enabled, we'll need an inetd.conf */
804         variable_set2("inetd_enable", "YES", 1);
805         if (!msgYesNo("inetd(8) relies on its configuration file, /etc/inetd.conf, to determine\n"
806                    "which of its Internet services will be available.  The default FreeBSD\n"
807                    "inetd.conf(5) leaves all services disabled by default, so they must be\n"
808                    "specifically enabled in the configuration file before they will\n"
809                    "function, even once inetd(8) is enabled.  Note that services for\n"
810                    "IPv6 must be separately enabled from IPv4 services.\n\n"
811                    "Select [Yes] now to invoke an editor on /etc/inetd.conf, or [No] to\n"
812                    "use the current settings.\n")) {
813             sprintf(cmd, "%s /etc/inetd.conf", variable_get(VAR_EDITOR));
814             dialog_clear();
815             systemExecute(cmd);
816         }
817     }
818     restorescr(w);
819     return DITEM_SUCCESS;
820 }
821
822 int
823 configNFSServer(dialogMenuItem *self)
824 {
825     char cmd[256];
826     int retval = 0;
827
828     /* If we're an NFS server, we need an exports file */
829     if (!file_readable("/etc/exports")) {
830         WINDOW *w = savescr();
831
832         if (file_readable("/etc/exports.disabled"))
833             vsystem("mv /etc/exports.disabled /etc/exports");
834         else {
835             dialog_clear_norefresh();
836             msgConfirm("Operating as an NFS server means that you must first configure\n"
837                        "an /etc/exports file to indicate which hosts are allowed certain\n"
838                        "kinds of access to your local file systems.\n"
839                        "Press [ENTER] now to invoke an editor on /etc/exports\n");
840             vsystem("echo '#The following examples export /usr to 3 machines named after ducks,' > /etc/exports");
841             vsystem("echo '#/usr/src and /usr/ports read-only to machines named after trouble makers' >> /etc/exports");
842             vsystem("echo '#/home and all directories under it to machines named after dead rock stars' >> /etc/exports");
843             vsystem("echo '#and, /a to a network of privileged machines allowed to write on it as root.' >> /etc/exports");
844             vsystem("echo '#/usr                   huey louie dewie' >> /etc/exports");
845             vsystem("echo '#/usr/src /usr/obj -ro  calvin hobbes' >> /etc/exports");
846             vsystem("echo '#/home   -alldirs       janice jimmy frank' >> /etc/exports");
847             vsystem("echo '#/a      -maproot=0  -network 10.0.1.0 -mask 255.255.248.0' >> /etc/exports");
848             vsystem("echo '#' >> /etc/exports");
849             vsystem("echo '# You should replace these lines with your actual exported filesystems.' >> /etc/exports");
850             vsystem("echo \"# Note that BSD's export syntax is 'host-centric' vs. Sun's 'FS-centric' one.\" >> /etc/exports");
851             vsystem("echo >> /etc/exports");
852             sprintf(cmd, "%s /etc/exports", variable_get(VAR_EDITOR));
853             dialog_clear();
854             systemExecute(cmd);
855         }
856         variable_set2(VAR_NFS_SERVER, "YES", 1);
857         retval = configRpcBind(NULL);
858         restorescr(w);
859     }
860     else if (variable_get(VAR_NFS_SERVER)) { /* We want to turn it off again? */
861         vsystem("mv -f /etc/exports /etc/exports.disabled");
862         variable_unset(VAR_NFS_SERVER);
863     }
864     return DITEM_SUCCESS | retval;
865 }
866
867 /*
868  * Extend the standard dmenuToggleVariable() method to also check and set
869  * the rpcbind variable if needed.
870  */
871 int
872 configRpcBind(dialogMenuItem *self)
873 {
874     int retval = 0;
875     int doupdate = 1;
876
877     if (self != NULL) {
878         retval = dmenuToggleVariable(self);
879         if (strcmp(variable_get(self->data), "YES") != 0)
880             doupdate = 0;
881     }
882
883     if (doupdate && strcmp(variable_get(VAR_RPCBIND_ENABLE), "YES") != 0) {
884         variable_set2(VAR_RPCBIND_ENABLE, "YES", 1);
885         retval |= DITEM_REDRAW;
886     }
887
888    return retval;
889 }
890
891 int
892 configEtcTtys(dialogMenuItem *self)
893 {
894     char cmd[256];
895
896     WINDOW *w = savescr();
897
898     /* Simply prompt for confirmation, then edit away. */
899     if (msgYesNo("Configuration of system TTYs requires editing the /etc/ttys file.\n"
900                  "Typical configuration activities might include enabling getty(8)\n"
901                  "on the first serial port to allow login via serial console after\n"
902                  "reboot, or to enable xdm.  The default ttys file enables normal\n"
903                  "virtual consoles, and most sites will not need to perform manual\n"
904                  "configuration.\n\n"
905                  "To load /etc/ttys in the editor, select [Yes], otherwise, [No].")) {
906     } else {
907         configTtys();
908         sprintf(cmd, "%s /etc/ttys", variable_get(VAR_EDITOR));
909         dialog_clear();
910         systemExecute(cmd);
911     }
912
913     restorescr(w);
914     return DITEM_SUCCESS;
915 }
916
917 #ifdef __i386__
918 int
919 checkLoaderACPI(void)
920 {
921     char val[4];
922
923     if (kenv(KENV_GET, "loader.acpi_disabled_by_user", &val[0], 4) <= 0) {
924         return (0);
925     }
926
927     if (strtol(&val[0], NULL, 10) <= 0) {
928         return (0);
929     }
930
931     return (1);
932 }
933
934 int
935 configLoaderACPI(int disable)
936 {
937     FILE *ldconf;
938
939     ldconf = fopen("/boot/loader.conf", "a");
940     if (ldconf == NULL) {
941         msgConfirm("Unable to open /boot/loader.conf.  Please consult the\n"
942                   "FreeBSD Handbook for instructions on disabling ACPI");
943         return DITEM_FAILURE;
944     }
945
946     fprintf(ldconf, "# --- Generated by sysinstall ---\n");
947     fprintf(ldconf, "hint.acpi.0.disabled=%d\n", disable);
948     fclose(ldconf);
949
950     return DITEM_SUCCESS;
951
952 #endif
953
954 int
955 configMTAPostfix(dialogMenuItem *self)
956 {
957     int ret;
958     FILE *perconf;
959
960     if(setenv("POSTFIX_DEFAULT_MTA", "YES", 1) != 0)
961         msgError("Error setting the enviroment variable POSTFIX_DEFAULT_MTA: %s (%u)",
962                  strerror(errno), errno);
963
964     ret = package_add("postfix-2.2");
965     unsetenv("POSTFIX_DEFAULT_MTA");
966
967     if(DITEM_STATUS(ret) == DITEM_FAILURE) {
968         msgConfirm("An error occurred while adding the postfix package\n"
969                    "Please change installation media and try again.");
970         return ret;
971     }
972
973     variable_set2(VAR_SENDMAIL_ENABLE, "YES", 1);
974     variable_set2("sendmail_flags", "-bd", 1);
975     variable_set2("sendmail_outbound_enable", "NO", 1);
976     variable_set2("sendmail_submit_enable", "NO", 1);
977     variable_set2("sendmail_msp_queue_enable", "NO", 1);
978
979     perconf = fopen("/etc/periodic.conf", "a");
980     if (perconf == NULL) {
981         msgConfirm("Unable to open /etc/periodic.conf.\n"
982                    "The daily cleanup scripts might generate errors when\n"
983                    "trying to run some sendmail only cleanup scripts.\n"
984                    "Please consult the documentation for the postfix port on how to\n"
985                    "fix this.");
986
987         /* Not really a serious problem, so we return success */
988         return DITEM_SUCCESS;
989     }
990
991     fprintf(perconf, "# --- Generated by sysinstall ---\n");
992     fprintf(perconf, "daily_clean_hoststat_enable=\"NO\"\n");
993     fprintf(perconf, "daily_status_mail_rejects_enable=\"NO\"\n");
994     fprintf(perconf, "daily_status_include_submit_mailq=\"NO\"\n");
995     fprintf(perconf, "daily_submit_queuerun=\"NO\"\n");
996     fclose(perconf);
997
998     msgConfirm("Postfix is now installed and enabled as the default MTA.\n"
999                "Please check that the configuration works as expected.\n"
1000                "See the Postfix documentation for more information.\n"
1001                "The documentation can be found in /usr/local/share/doc/postfix/\n"
1002                "or on the Postfix website at http://www.postfix.org/.");
1003
1004     return DITEM_SUCCESS;
1005 }
1006
1007 int
1008 configMTAExim(dialogMenuItem *self)
1009 {
1010     int ret;
1011     FILE *perconf, *mailerconf, *newsyslogconf;
1012
1013     ret = package_add("exim");
1014
1015     if(DITEM_STATUS(ret) == DITEM_FAILURE) {
1016         msgConfirm("An error occurred while adding the exim package\n"
1017                    "Please change installation media and try again.");
1018         return ret;
1019     }
1020
1021     variable_set2(VAR_SENDMAIL_ENABLE, "NONE", 1);
1022     variable_set2("exim_enable", "YES", 1);
1023
1024     /* Update periodic.conf */
1025     perconf = fopen("/etc/periodic.conf", "a");
1026     if (perconf == NULL) {
1027         /* Not really a serious problem, so we do not abort */
1028         msgConfirm("Unable to open /etc/periodic.conf.\n"
1029                    "The daily cleanup scripts might generate errors when\n"
1030                    "trying to run some sendmail only cleanup scripts.\n"
1031                    "Please consult the documentation for the exim port on how to\n"
1032                    "fix this.");
1033     } else {
1034         fprintf(perconf, "# --- Generated by sysinstall ---\n");
1035         fprintf(perconf, "daily_clean_hoststat_enable=\"NO\"\n");
1036         fprintf(perconf, "daily_status_include_submit_mailq=\"NO\"\n");
1037         fprintf(perconf, "daily_status_mail_rejects_enable=\"NO\"\n");
1038         fprintf(perconf, "daily_submit_queuerun=\"NO\"\n");
1039         fclose(perconf);
1040     }
1041
1042     /* Update mailer.conf */
1043     vsystem("mv -f /etc/mail/mailer.conf /etc/mail/mailer.conf.old");
1044     mailerconf = fopen("/etc/mail/mailer.conf", "w");
1045     if (mailerconf == NULL) {
1046         /* Not really a serious problem, so we do not abort */
1047         msgConfirm("Unable to open /etc/mailer.conf.\n"
1048                    "Some programs which use the sendmail wrappers may not work.\n"
1049                    "Please consult the documentation for the exim port on how\n"
1050                    "to correct this.");
1051     } else {
1052         fprintf(mailerconf, "# --- Generated by sysinstall ---\n");
1053         fprintf(mailerconf, "# Execute exim instead of sendmail\n");
1054         fprintf(mailerconf, "#\n");
1055         fprintf(mailerconf, "sendmail   /usr/local/sbin/exim\n");
1056         fprintf(mailerconf, "send-mail  /usr/local/sbin/exim\n");
1057         fprintf(mailerconf, "mailq              /usr/local/sbin/exim\n");
1058         fprintf(mailerconf, "newaliases /usr/local/sbin/exim\n");
1059         fprintf(mailerconf, "hoststat   /usr/bin/true\n");
1060         fprintf(mailerconf, "purgestat  /usr/bin/true\n");
1061         fclose(mailerconf);
1062     }
1063
1064     /* Make newsyslog rotate exim logfiles */
1065     newsyslogconf = fopen("/etc/newsyslog.conf", "a");
1066     if (newsyslogconf == NULL) {
1067         /* Not really a serious problem, so we do not abort */
1068         msgConfirm("Unable to open /etc/newsyslog.conf.\n"
1069                    "The exim logfiles will not be rotated.\n"
1070                    "Please consult the documentation for the exim port on how to\n"
1071                    "rotate the logfiles.");
1072     } else {
1073         fprintf(newsyslogconf, "# --- Generated by sysinstall ---\n");
1074         fprintf(newsyslogconf, "/var/log/exim/mainlog   mailnull:mail   640  7     *    @T00  ZN\n");
1075         fprintf(newsyslogconf, "/var/log/exim/rejectlog mailnull:mail   640  7     *    @T00  ZN\n");
1076         fclose(newsyslogconf);
1077     }
1078
1079     msgConfirm("Exim is now installed and enabled as the default MTA.\n"
1080                "Please check that the configuration works as expected.\n"
1081                "See the Exim documentation for more information.\n"
1082                "The documentation can be found in /usr/local/share/doc/exim/\n"
1083                "or on the Exim website at http://www.exim.org/.");
1084
1085     return DITEM_SUCCESS;
1086 }