]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/sysinstall/config.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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                 if (variable_get(VAR_KEEPRCCONF) != NULL)
433                     fprintf(rcSite, "%s", line);
434                 else
435                     fprintf(rcSite, "#REMOVED: %s", line);
436             }
437         }
438         fclose(rcOld);
439     } else if (write_header) {
440         fprintf(rcSite, "# This file now contains just the overrides from /etc/defaults/rc.conf.\n");
441         fprintf(rcSite, "# Please make all changes to this file, not to /etc/defaults/rc.conf.\n\n");
442         fprintf(rcSite, "# Enable network daemons for user convenience.\n");
443         if ((t_loc = time(NULL)) != -1 && (cp = ctime(&t_loc)))
444             fprintf(rcSite, "# Created: %s", cp);
445     }
446
447     /* Now do variable substitutions */
448     for (v = VarHead; v; v = v->next) {
449         if (v->dirty) {
450             if (!did_marker) {
451                 time(&tp);
452                 fprintf(rcSite, "# -- sysinstall generated deltas -- # "
453                     "%s", ctime(&tp));
454                 did_marker = 1;
455             }
456             fprintf(rcSite, "%s=\"%s\"\n", v->name, v->value);
457             v->dirty = 0;
458         }
459     }
460     fclose(rcSite);
461
462     if(do_merge) {
463         if(rename("/etc/rc.conf.new", "/etc/rc.conf") != 0) {
464             msgError("Error renaming temporary rc.conf: %s (%u)", strerror(errno), errno);
465             return;
466         }
467     }
468
469     /* Tidy up the resulting file if it's late enough in the installation
470         for sort and uniq to be available */
471     if (do_sort) {
472         (void)vsystem("sort /etc/rc.conf | uniq > /etc/rc.conf.new && mv /etc/rc.conf.new /etc/rc.conf");
473     }
474 }
475
476 int
477 configSaver(dialogMenuItem *self)
478 {
479     variable_set((char *)self->data, 1);
480     if (!variable_get(VAR_BLANKTIME))
481         variable_set2(VAR_BLANKTIME, "300", 1);
482     return DITEM_SUCCESS;
483 }
484
485 int
486 configSaverTimeout(dialogMenuItem *self)
487 {
488     return (variable_get_value(VAR_BLANKTIME,
489             "Enter time-out period in seconds for screen saver", 1) ?
490         DITEM_SUCCESS : DITEM_FAILURE);
491 }
492
493 int
494 configNTP(dialogMenuItem *self)
495 {
496     int status;
497
498     status = variable_get_value(VAR_NTPDATE_HOSTS,
499                                 "Enter the name of an NTP server", 1)
500              ? DITEM_SUCCESS : DITEM_FAILURE;
501     if (status == DITEM_SUCCESS) {
502         static char tmp[255];
503
504         snprintf(tmp, sizeof(tmp), "ntpdate_enable=YES,ntpdate_hosts=%s",
505                  variable_get(VAR_NTPDATE_HOSTS));
506         self->data = tmp;
507         dmenuSetVariables(self);
508     }
509     return status;
510 }
511
512 int
513 configCountry(dialogMenuItem *self)
514 {
515     int choice, scroll, curr, max;
516
517     WINDOW *w = savescr();
518
519     dialog_clear_norefresh();
520     dmenuSetDefaultItem(&MenuCountry, NULL, NULL,
521         VAR_COUNTRY "=" DEFAULT_COUNTRY, &choice, &scroll, &curr, &max);
522     dmenuOpen(&MenuCountry, &choice, &scroll, &curr, &max, FALSE);
523     restorescr(w);
524     return DITEM_SUCCESS;
525 }
526
527 int
528 configUsers(dialogMenuItem *self)
529 {
530     WINDOW *w = savescr();
531
532     dialog_clear_norefresh();
533     dmenuOpenSimple(&MenuUsermgmt, FALSE);
534     restorescr(w);
535     return DITEM_SUCCESS;
536 }
537
538 int
539 configSecurelevel(dialogMenuItem *self)
540 {
541     WINDOW *w = savescr();
542
543     dialog_clear_norefresh();
544     dmenuOpenSimple(&MenuSecurelevel, FALSE);
545     restorescr(w);
546     return DITEM_SUCCESS;
547 }
548
549 int
550 configSecurelevelDisabled(dialogMenuItem *self)
551 {
552
553     variable_set2("kern_securelevel_enable", "NO", 1);
554     return DITEM_SUCCESS;
555 }
556
557 int
558 configSecurelevelSecure(dialogMenuItem *self)
559 {
560
561     variable_set2("kern_securelevel_enable", "YES", 1);
562     variable_set2("kern_securelevel", "1", 1);
563     return DITEM_SUCCESS;
564 }
565
566 int
567 configSecurelevelHighlySecure(dialogMenuItem *self)
568 {
569
570     variable_set2("kern_securelevel_enable", "YES", 1);
571     variable_set2("kern_securelevel", "2", 1);
572     return DITEM_SUCCESS;
573 }
574
575 int
576 configSecurelevelNetworkSecure(dialogMenuItem *self)
577 {
578
579     variable_set2("kern_securelevel_enable", "YES", 1);
580     variable_set2("kern_securelevel", "3", 1);
581     return DITEM_SUCCESS;
582 }
583
584 int
585 configResolv(dialogMenuItem *ditem)
586 {
587     FILE *fp;
588     char *cp, *c6p, *dp, *hp;
589
590     cp = variable_get(VAR_NAMESERVER);
591     if (!cp || !*cp)
592         goto skip;
593     Mkdir("/etc");
594     fp = fopen("/etc/resolv.conf", "w");
595     if (!fp)
596         return DITEM_FAILURE;
597     if (variable_get(VAR_DOMAINNAME))
598         fprintf(fp, "domain\t%s\n", variable_get(VAR_DOMAINNAME));
599     fprintf(fp, "nameserver\t%s\n", cp);
600     fclose(fp);
601     if (isDebug())
602         msgDebug("Wrote out /etc/resolv.conf\n");
603
604 skip:
605     dp = variable_get(VAR_DOMAINNAME);
606     cp = variable_get(VAR_IPADDR);
607     c6p = variable_get(VAR_IPV6ADDR);
608     hp = variable_get(VAR_HOSTNAME);
609     /* Tack ourselves into /etc/hosts */
610     fp = fopen("/etc/hosts", "w");
611     if (!fp)
612         return DITEM_FAILURE;
613     /* Add an entry for localhost */
614     if (dp) {
615         fprintf(fp, "::1\t\t\tlocalhost localhost.%s\n", dp);
616         fprintf(fp, "127.0.0.1\t\tlocalhost localhost.%s\n", dp);
617     } else {
618         fprintf(fp, "::1\t\t\tlocalhost\n");
619         fprintf(fp, "127.0.0.1\t\tlocalhost\n");
620     }
621     /* Now the host entries, if applicable */
622     if (((cp && cp[0] != '0') || (c6p && c6p[0] != '0')) && hp) {
623         char cp2[255];
624
625         if (!index(hp, '.'))
626             cp2[0] = '\0';
627         else {
628             SAFE_STRCPY(cp2, hp);
629             *(index(cp2, '.')) = '\0';
630         }
631         if (c6p && c6p[0] != '0') {
632             fprintf(fp, "%s\t%s %s\n", c6p, hp, cp2);
633             fprintf(fp, "%s\t%s.\n", c6p, hp);
634         }
635         if (cp && cp[0] != '0') {
636             fprintf(fp, "%s\t\t%s %s\n", cp, hp, cp2);
637             fprintf(fp, "%s\t\t%s.\n", cp, hp);
638         }
639     }
640     fclose(fp);
641     if (isDebug())
642         msgDebug("Wrote out /etc/hosts\n");
643     return DITEM_SUCCESS;
644 }
645
646 int
647 configRouter(dialogMenuItem *self)
648 {
649     int ret;
650
651     ret = variable_get_value(VAR_ROUTER,
652                              "Please specify the router you wish to use.  Routed is\n"
653                              "provided with the stock system and gated is provided\n"
654                              "as an optional package which this installation system\n"
655                              "will attempt to load if you select gated.  Any other\n"
656                              "choice of routing daemon will be assumed to be something\n"
657                              "the user intends to install themselves before rebooting\n"
658                              "the system.  If you don't want any routing daemon, choose NO", 1)
659       ? DITEM_SUCCESS : DITEM_FAILURE;
660
661     if (ret == DITEM_SUCCESS) {
662         char *cp = variable_get(VAR_ROUTER);
663
664         if (cp && strcmp(cp, "NO")) {
665             variable_set2(VAR_ROUTER_ENABLE, "YES", 1);
666             if (!strcmp(cp, "gated")) {
667                 if (package_add("gated") != DITEM_SUCCESS) {
668                     msgConfirm("Unable to load gated package.  Falling back to no router.");
669                     variable_unset(VAR_ROUTER);
670                     variable_unset(VAR_ROUTERFLAGS);
671                     variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
672                     cp = NULL;
673                 }
674             }
675             if (cp) {
676                 /* Now get the flags, if they chose a router */
677                 ret = variable_get_value(VAR_ROUTERFLAGS,
678                                          "Please Specify the routing daemon flags; if you're running routed\n"
679                                          "then -q is the right choice for nodes and -s for gateway hosts.\n", 1)
680                   ? DITEM_SUCCESS : DITEM_FAILURE;
681                 if (ret != DITEM_SUCCESS)
682                     variable_unset(VAR_ROUTERFLAGS);
683             }
684         }
685         else {
686             /* No router case */
687             variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
688             variable_unset(VAR_ROUTERFLAGS);
689             variable_unset(VAR_ROUTER);
690         }
691     }
692     else {
693         variable_set2(VAR_ROUTER_ENABLE, "NO", 1);
694         variable_unset(VAR_ROUTERFLAGS);
695         variable_unset(VAR_ROUTER);
696     }
697     return ret;
698 }
699
700 /* Shared between us and index_initialize() */
701 extern PkgNode Top, Plist;
702
703 int
704 configPackages(dialogMenuItem *self)
705 {
706     int i, restoreflag = 0;
707     PkgNodePtr tmp;
708
709     /* Did we get an INDEX? */
710     i = index_initialize("packages/INDEX");
711     if (DITEM_STATUS(i) == DITEM_FAILURE)
712         return i;
713
714     while (1) {
715         int ret, pos, scroll;
716         int current, low, high;
717
718         /* Bring up the packages menu */
719         pos = scroll = 0;
720         index_menu(&Top, &Top, &Plist, &pos, &scroll);
721
722         if (Plist.kids && Plist.kids->name) {
723             /* Now show the packing list menu */
724             pos = scroll = 0;
725             ret = index_menu(&Plist, &Plist, NULL, &pos, &scroll);
726             if (ret & DITEM_LEAVE_MENU)
727                 break;
728             else if (DITEM_STATUS(ret) != DITEM_FAILURE) {
729                 dialog_clear();
730                 restoreflag = 1;
731                 if (have_volumes) {
732                     low = low_volume;
733                     high = high_volume;
734                 } else
735                     low = high = 0;
736                 for (current = low; current <= high; current++)
737                     for (tmp = Plist.kids; tmp && tmp->name; tmp = tmp->next)
738                         (void)index_extract(mediaDevice, &Top, tmp, FALSE, current);
739                 break;
740             }
741         }
742         else {
743             msgConfirm("No packages were selected for extraction.");
744             break;
745         }
746     }
747     tmp = Plist.kids;
748     while (tmp) {
749         PkgNodePtr tmp2 = tmp->next;
750
751         safe_free(tmp);
752         tmp = tmp2;
753     }
754     index_init(NULL, &Plist);
755     return DITEM_SUCCESS | (restoreflag ? DITEM_RESTORE : 0);
756 }
757
758 /* Load pcnfsd package */
759 int
760 configPCNFSD(dialogMenuItem *self)
761 {
762     int ret;
763
764     ret = package_add("pcnfsd");
765     if (DITEM_STATUS(ret) == DITEM_SUCCESS) {
766         variable_set2(VAR_PCNFSD, "YES", 0);
767         variable_set2("mountd_flags", "-n", 1);
768     }
769     return ret;
770 }
771
772 int
773 configInetd(dialogMenuItem *self)
774 {
775     char cmd[256];
776
777     WINDOW *w = savescr();
778
779     if (msgYesNo("The Internet Super Server (inetd) allows a number of simple Internet\n"
780                  "services to be enabled, including finger, ftp, and telnetd.  Enabling\n"
781                  "these services may increase risk of security problems by increasing\n"
782                  "the exposure of your system.\n\n"
783                  "With this in mind, do you wish to enable inetd?\n")) {
784         variable_set2("inetd_enable", "NO", 1);
785     } else {
786         /* If inetd is enabled, we'll need an inetd.conf */
787         variable_set2("inetd_enable", "YES", 1);
788         if (!msgYesNo("inetd(8) relies on its configuration file, /etc/inetd.conf, to determine\n"
789                    "which of its Internet services will be available.  The default FreeBSD\n"
790                    "inetd.conf(5) leaves all services disabled by default, so they must be\n"
791                    "specifically enabled in the configuration file before they will\n"
792                    "function, even once inetd(8) is enabled.  Note that services for\n"
793                    "IPv6 must be separately enabled from IPv4 services.\n\n"
794                    "Select [Yes] now to invoke an editor on /etc/inetd.conf, or [No] to\n"
795                    "use the current settings.\n")) {
796             sprintf(cmd, "%s /etc/inetd.conf", variable_get(VAR_EDITOR));
797             dialog_clear();
798             systemExecute(cmd);
799         }
800     }
801     restorescr(w);
802     return DITEM_SUCCESS;
803 }
804
805 int
806 configNFSServer(dialogMenuItem *self)
807 {
808     char cmd[256];
809     int retval = 0;
810
811     /* If we're an NFS server, we need an exports file */
812     if (!file_readable("/etc/exports")) {
813         WINDOW *w = savescr();
814
815         if (file_readable("/etc/exports.disabled"))
816             vsystem("mv /etc/exports.disabled /etc/exports");
817         else {
818             dialog_clear_norefresh();
819             msgConfirm("Operating as an NFS server means that you must first configure\n"
820                        "an /etc/exports file to indicate which hosts are allowed certain\n"
821                        "kinds of access to your local file systems.\n"
822                        "Press [ENTER] now to invoke an editor on /etc/exports\n");
823             vsystem("echo '#The following examples export /usr to 3 machines named after ducks,' > /etc/exports");
824             vsystem("echo '#/usr/src and /usr/obj read-only to machines named after trouble makers,' >> /etc/exports");
825             vsystem("echo '#/home and all directories under it to machines named after dead rock stars' >> /etc/exports");
826             vsystem("echo '#and, /a to a network of privileged machines allowed to write on it as root.' >> /etc/exports");
827             vsystem("echo '#/usr                   huey louie dewie' >> /etc/exports");
828             vsystem("echo '#/usr/src /usr/obj -ro  calvin hobbes' >> /etc/exports");
829             vsystem("echo '#/home   -alldirs       janis jimi frank' >> /etc/exports");
830             vsystem("echo '#/a      -maproot=0  -network 10.0.1.0 -mask 255.255.248.0' >> /etc/exports");
831             vsystem("echo '#' >> /etc/exports");
832             vsystem("echo '# You should replace these lines with your actual exported filesystems.' >> /etc/exports");
833             vsystem("echo \"# Note that BSD's export syntax is 'host-centric' vs. Sun's 'FS-centric' one.\" >> /etc/exports");
834             vsystem("echo >> /etc/exports");
835             sprintf(cmd, "%s /etc/exports", variable_get(VAR_EDITOR));
836             dialog_clear();
837             systemExecute(cmd);
838         }
839         variable_set2(VAR_NFS_SERVER, "YES", 1);
840         retval = configRpcBind(NULL);
841         restorescr(w);
842     }
843     else if (variable_get(VAR_NFS_SERVER)) { /* We want to turn it off again? */
844         vsystem("mv -f /etc/exports /etc/exports.disabled");
845         variable_unset(VAR_NFS_SERVER);
846     }
847     return DITEM_SUCCESS | retval;
848 }
849
850 /*
851  * Extend the standard dmenuToggleVariable() method to also check and set
852  * the rpcbind variable if needed.
853  */
854 int
855 configRpcBind(dialogMenuItem *self)
856 {
857     char *tmp, *tmp2;
858     int retval = 0;
859     int doupdate = 1;
860
861     if (self != NULL) {
862         retval = dmenuToggleVariable(self);
863         tmp = strdup(self->data);
864         if ((tmp2 = index(tmp, '=')) != NULL)
865             *tmp2 = '\0';
866         if (strcmp(variable_get(tmp), "YES") != 0)
867             doupdate = 0;
868         free(tmp);
869     }
870
871     if (doupdate && strcmp(variable_get(VAR_RPCBIND_ENABLE), "YES") != 0) {
872         variable_set2(VAR_RPCBIND_ENABLE, "YES", 1);
873         retval |= DITEM_REDRAW;
874     }
875
876    return retval;
877 }
878
879 int
880 configEtcTtys(dialogMenuItem *self)
881 {
882     char cmd[256];
883
884     WINDOW *w = savescr();
885
886     /* Simply prompt for confirmation, then edit away. */
887     if (msgYesNo("Configuration of system TTYs requires editing the /etc/ttys file.\n"
888                  "Typical configuration activities might include enabling getty(8)\n"
889                  "on the first serial port to allow login via serial console after\n"
890                  "reboot, or to enable xdm.  The default ttys file enables normal\n"
891                  "virtual consoles, and most sites will not need to perform manual\n"
892                  "configuration.\n\n"
893                  "To load /etc/ttys in the editor, select [Yes], otherwise, [No].")) {
894     } else {
895         configTtys();
896         sprintf(cmd, "%s /etc/ttys", variable_get(VAR_EDITOR));
897         dialog_clear();
898         systemExecute(cmd);
899     }
900
901     restorescr(w);
902     return DITEM_SUCCESS;
903 }
904
905 #ifdef __i386__
906 int
907 checkLoaderACPI(void)
908 {
909     char val[4];
910
911     if (kenv(KENV_GET, "loader.acpi_disabled_by_user", &val[0], 4) <= 0) {
912         return (0);
913     }
914
915     if (strtol(&val[0], NULL, 10) <= 0) {
916         return (0);
917     }
918
919     return (1);
920 }
921
922 int
923 configLoaderACPI(int disable)
924 {
925     FILE *ldconf;
926
927     ldconf = fopen("/boot/loader.conf", "a");
928     if (ldconf == NULL) {
929         msgConfirm("Unable to open /boot/loader.conf.  Please consult the\n"
930                   "FreeBSD Handbook for instructions on disabling ACPI");
931         return DITEM_FAILURE;
932     }
933
934     fprintf(ldconf, "# --- Generated by sysinstall ---\n");
935     fprintf(ldconf, "hint.acpi.0.disabled=%d\n", disable);
936     fclose(ldconf);
937
938     return DITEM_SUCCESS;
939 }
940 #endif
941
942 int
943 configMTAPostfix(dialogMenuItem *self)
944 {
945     int ret;
946     FILE *perconf;
947
948     if(setenv("POSTFIX_DEFAULT_MTA", "YES", 1) != 0)
949         msgError("Error setting the enviroment variable POSTFIX_DEFAULT_MTA: %s (%u)",
950                  strerror(errno), errno);
951
952     ret = package_add("postfix-2.4");
953     unsetenv("POSTFIX_DEFAULT_MTA");
954
955     if(DITEM_STATUS(ret) == DITEM_FAILURE) {
956         msgConfirm("An error occurred while adding the postfix package\n"
957                    "Please change installation media and try again.");
958         return ret;
959     }
960
961     variable_set2(VAR_SENDMAIL_ENABLE, "YES", 1);
962     variable_set2("sendmail_flags", "-bd", 1);
963     variable_set2("sendmail_outbound_enable", "NO", 1);
964     variable_set2("sendmail_submit_enable", "NO", 1);
965     variable_set2("sendmail_msp_queue_enable", "NO", 1);
966
967     perconf = fopen("/etc/periodic.conf", "a");
968     if (perconf == NULL) {
969         msgConfirm("Unable to open /etc/periodic.conf.\n"
970                    "The daily cleanup scripts might generate errors when\n"
971                    "trying to run some sendmail only cleanup scripts.\n"
972                    "Please consult the documentation for the postfix port on how to\n"
973                    "fix this.");
974
975         /* Not really a serious problem, so we return success */
976         return DITEM_SUCCESS;
977     }
978
979     fprintf(perconf, "# --- Generated by sysinstall ---\n");
980     fprintf(perconf, "daily_clean_hoststat_enable=\"NO\"\n");
981     fprintf(perconf, "daily_status_mail_rejects_enable=\"NO\"\n");
982     fprintf(perconf, "daily_status_include_submit_mailq=\"NO\"\n");
983     fprintf(perconf, "daily_submit_queuerun=\"NO\"\n");
984     fclose(perconf);
985
986     msgConfirm("Postfix is now installed and enabled as the default MTA.\n"
987                "Please check that the configuration works as expected.\n"
988                "See the Postfix documentation for more information.\n"
989                "The documentation can be found in /usr/local/share/doc/postfix/\n"
990                "or on the Postfix website at http://www.postfix.org/.");
991
992     return DITEM_SUCCESS;
993 }
994
995 int
996 configMTAExim(dialogMenuItem *self)
997 {
998     int ret;
999     FILE *perconf, *mailerconf, *newsyslogconf;
1000
1001     ret = package_add("exim");
1002
1003     if(DITEM_STATUS(ret) == DITEM_FAILURE) {
1004         msgConfirm("An error occurred while adding the exim package\n"
1005                    "Please change installation media and try again.");
1006         return ret;
1007     }
1008
1009     variable_set2(VAR_SENDMAIL_ENABLE, "NONE", 1);
1010     variable_set2("exim_enable", "YES", 1);
1011
1012     /* Update periodic.conf */
1013     perconf = fopen("/etc/periodic.conf", "a");
1014     if (perconf == NULL) {
1015         /* Not really a serious problem, so we do not abort */
1016         msgConfirm("Unable to open /etc/periodic.conf.\n"
1017                    "The daily cleanup scripts might generate errors when\n"
1018                    "trying to run some sendmail only cleanup scripts.\n"
1019                    "Please consult the documentation for the exim port on how to\n"
1020                    "fix this.");
1021     } else {
1022         fprintf(perconf, "# --- Generated by sysinstall ---\n");
1023         fprintf(perconf, "daily_clean_hoststat_enable=\"NO\"\n");
1024         fprintf(perconf, "daily_status_include_submit_mailq=\"NO\"\n");
1025         fprintf(perconf, "daily_status_mail_rejects_enable=\"NO\"\n");
1026         fprintf(perconf, "daily_submit_queuerun=\"NO\"\n");
1027         fclose(perconf);
1028     }
1029
1030     /* Update mailer.conf */
1031     vsystem("mv -f /etc/mail/mailer.conf /etc/mail/mailer.conf.old");
1032     mailerconf = fopen("/etc/mail/mailer.conf", "w");
1033     if (mailerconf == NULL) {
1034         /* Not really a serious problem, so we do not abort */
1035         msgConfirm("Unable to open /etc/mailer.conf.\n"
1036                    "Some programs which use the sendmail wrappers may not work.\n"
1037                    "Please consult the documentation for the exim port on how\n"
1038                    "to correct this.");
1039     } else {
1040         fprintf(mailerconf, "# --- Generated by sysinstall ---\n");
1041         fprintf(mailerconf, "# Execute exim instead of sendmail\n");
1042         fprintf(mailerconf, "#\n");
1043         fprintf(mailerconf, "sendmail   /usr/local/sbin/exim\n");
1044         fprintf(mailerconf, "send-mail  /usr/local/sbin/exim\n");
1045         fprintf(mailerconf, "mailq              /usr/local/sbin/exim\n");
1046         fprintf(mailerconf, "newaliases /usr/local/sbin/exim\n");
1047         fprintf(mailerconf, "hoststat   /usr/bin/true\n");
1048         fprintf(mailerconf, "purgestat  /usr/bin/true\n");
1049         fclose(mailerconf);
1050     }
1051
1052     /* Make newsyslog rotate exim logfiles */
1053     newsyslogconf = fopen("/etc/newsyslog.conf", "a");
1054     if (newsyslogconf == NULL) {
1055         /* Not really a serious problem, so we do not abort */
1056         msgConfirm("Unable to open /etc/newsyslog.conf.\n"
1057                    "The exim logfiles will not be rotated.\n"
1058                    "Please consult the documentation for the exim port on how to\n"
1059                    "rotate the logfiles.");
1060     } else {
1061         fprintf(newsyslogconf, "# --- Generated by sysinstall ---\n");
1062         fprintf(newsyslogconf, "/var/log/exim/mainlog   mailnull:mail   640  7     *    @T00  ZN\n");
1063         fprintf(newsyslogconf, "/var/log/exim/rejectlog mailnull:mail   640  7     *    @T00  ZN\n");
1064         fclose(newsyslogconf);
1065     }
1066
1067     msgConfirm("Exim is now installed and enabled as the default MTA.\n"
1068                "Please check that the configuration works as expected.\n"
1069                "See the Exim documentation for more information.\n"
1070                "The documentation can be found in /usr/local/share/doc/exim/\n"
1071                "or on the Exim website at http://www.exim.org/.");
1072
1073     return DITEM_SUCCESS;
1074 }