]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - release/sysinstall/config.c
Sync with rc.conf change for weak_mountd_authentication
[FreeBSD/FreeBSD.git] / release / 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  * $Id: config.c,v 1.101 1997/06/21 15:45:07 jkh Exp $
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
48 static Chunk *chunk_list[MAX_CHUNKS];
49 static int nchunks;
50 static int rootdev_is_od;
51
52 /* arg to sort */
53 static int
54 chunk_compare(Chunk *c1, Chunk *c2)
55 {
56     if (!c1 && !c2)
57         return 0;
58     else if (!c1 && c2)
59         return 1;
60     else if (c1 && !c2)
61         return -1;
62     else if (!c1->private_data && !c2->private_data)
63         return 0;
64     else if (c1->private_data && !c2->private_data)
65         return 1;
66     else if (!c1->private_data && c2->private_data)
67         return -1;
68     else
69         return strcmp(((PartInfo *)(c1->private_data))->mountpoint, ((PartInfo *)(c2->private_data))->mountpoint);
70 }
71
72 static void
73 chunk_sort(void)
74 {
75     int i, j;
76
77     for (i = 0; i < nchunks; i++) {
78         for (j = 0; j < nchunks; j++) {
79             if (chunk_compare(chunk_list[j], chunk_list[j + 1]) > 0) {
80                 Chunk *tmp = chunk_list[j];
81
82                 chunk_list[j] = chunk_list[j + 1];
83                 chunk_list[j + 1] = tmp;
84             }
85         }
86     }
87 }
88
89 static void
90 check_rootdev(Chunk **list, int n)
91 {
92         int i;
93         Chunk *c;
94
95         rootdev_is_od = 0;
96         for (i = 0; i < n; i++) {
97                 c = *list++;
98                 if (c->type == part && (c->flags & CHUNK_IS_ROOT)
99                     && strncmp(c->disk->name, "od", 2) == 0)
100                         rootdev_is_od = 1;
101         }
102 }
103
104 static char *
105 name_of(Chunk *c1)
106 {
107     static char rootname[32];
108
109     /* Our boot blocks can't deal with root partitions on slices - need the compatbility name */
110     if (c1->type == part && c1->flags & CHUNK_IS_ROOT) {
111         sprintf(rootname, "%sa", c1->disk->name);
112         return rootname;
113     }
114     else
115         return c1->name;
116 }
117
118 static char *
119 mount_point(Chunk *c1)
120 {
121     if (c1->type == part && c1->subtype == FS_SWAP)
122         return "none";
123     else if (c1->type == part || c1->type == fat)
124         return ((PartInfo *)c1->private_data)->mountpoint;
125     return "/bogus";
126 }
127
128 static char *
129 fstype(Chunk *c1)
130 {
131     if (c1->type == fat)
132         return "msdos";
133     else if (c1->type == part) {
134         if (c1->subtype != FS_SWAP)
135             return "ufs";
136         else
137             return "swap";
138     }
139     return "bogus";
140 }
141
142 static char *
143 fstype_short(Chunk *c1)
144 {
145     if (c1->type == part) {
146         if (c1->subtype != FS_SWAP) {
147             if (rootdev_is_od == 0 && strncmp(c1->name, "od", 2) == 0)
148                 return "rw,noauto";
149             else
150                 return "rw";
151         }
152         else
153             return "sw";
154     }
155     else if (c1->type == fat) {
156         if (strncmp(c1->name, "od", 2) == 0)
157             return "ro,noauto";
158         else
159             return "ro";
160     }
161     return "bog";
162 }
163
164 static int
165 seq_num(Chunk *c1)
166 {
167     if (c1->type == part && c1->subtype != FS_SWAP) {
168         if (rootdev_is_od == 0 && strncmp(c1->name, "od", 2) == 0)
169             return 0;
170         else
171             return 1;
172     }
173     return 0;
174 }
175
176 int
177 configFstab(void)
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             if (c1->type == freebsd) {
211                 for (c2 = c1->part; c2; c2 = c2->next) {
212                     if (c2->type == part && (c2->subtype == FS_SWAP || c2->private_data))
213                         chunk_list[nchunks++] = c2;
214                 }
215             }
216             else if (c1->type == fat && c1->private_data)
217                 chunk_list[nchunks++] = c1;
218         }
219     }
220     chunk_list[nchunks] = 0;
221     chunk_sort();
222
223     fstab = fopen("/etc/fstab", "w");
224     if (!fstab) {
225         msgConfirm("Unable to create a new /etc/fstab file!  Manual intervention\n"
226                    "will be required.");
227         return DITEM_FAILURE;
228     }
229
230     check_rootdev(chunk_list, nchunks);
231
232     /* Go for the burn */
233     msgDebug("Generating /etc/fstab file\n");
234     fprintf(fstab, "# Device\t\tMountpoint\tFStype\tOptions\t\tDump\tPass#\n");
235     for (i = 0; i < nchunks; i++)
236         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]),
237                 fstype(chunk_list[i]), fstype_short(chunk_list[i]), seq_num(chunk_list[i]), seq_num(chunk_list[i]));
238     Mkdir("/proc");
239     fprintf(fstab, "proc\t\t\t/proc\t\tprocfs\trw\t\t0\t0\n");
240
241     /* Now look for the CDROMs */
242     devs = deviceFind(NULL, DEVICE_TYPE_CDROM);
243     cnt = deviceCount(devs);
244
245     /* Write the first one out as /cdrom */
246     if (cnt) {
247         if (Mkdir("/cdrom")) {
248             msgConfirm("Unable to make mount point for: /cdrom");
249         }
250         else
251             fprintf(fstab, "/dev/%s\t\t/cdrom\t\tcd9660\tro,noauto\t0\t0\n", devs[0]->name);
252     }
253
254     /* Write the others out as /cdrom<n> */
255     for (i = 1; i < cnt; i++) {
256         char cdname[10];
257
258         sprintf(cdname, "/cdrom%d", i);
259         if (Mkdir(cdname)) {
260             msgConfirm("Unable to make mount point for: %s", cdname);
261         }
262         else
263             fprintf(fstab, "/dev/%s\t\t%s\tcd9660\tro,noauto\t0\t0\n", devs[i]->name, cdname);
264     }
265     fclose(fstab);
266     if (isDebug())
267         msgDebug("Wrote out /etc/fstab file\n");
268     return DITEM_SUCCESS;
269 }
270
271 /* Do the work of sucking in a config file.
272  * config is the filename to read in.
273  * lines is a fixed (max) sized array of char *.
274  * returns number of lines read.  line contents
275  * are malloc'd and must be freed by the caller.
276  */
277 int
278 readConfig(char *config, char **lines, int max)
279 {
280     FILE *fp;
281     char line[256];
282     int i, nlines;
283
284     fp = fopen(config, "r");
285     if (!fp)
286         return -1;
287
288     nlines = 0;
289     /* Read in the entire file */
290     for (i = 0; i < max; i++) {
291         if (!fgets(line, sizeof line, fp))
292             break;
293         lines[nlines++] = strdup(line);
294     }
295     fclose(fp);
296     if (isDebug())
297         msgDebug("readConfig: Read %d lines from %s.\n", nlines, config);
298     return nlines;
299 }
300
301 #define MAX_LINES  2000 /* Some big number we're not likely to ever reach - I'm being really lazy here, I know */
302
303 /* Load the environment from an rc.conf file */
304 void
305 configEnvironmentRC_conf(char *config)
306 {
307     char *lines[MAX_LINES], *cp, *cp2;
308     int i, nlines;
309
310     nlines = readConfig(config, lines, MAX_LINES);
311     if (nlines == -1)
312         return;
313
314     for (i = 0; i < nlines; i++) {
315         /* Skip the comments & non-variable settings */
316         if (lines[i][0] == '#' || !(cp = index(lines[i], '='))) {
317             free(lines[i]);
318             continue;
319         }
320         *cp++ = '\0';
321         /* Find quotes */
322         if ((cp2 = index(cp, '"')) || (cp2 = index(cp, '\047'))) {
323             cp = cp2 + 1;
324             cp2 = index(cp, *cp2);
325         }
326         /* If valid quotes, use it */
327         if (cp2) {
328             *cp2 = '\0';
329             if (strlen(cp))
330                 variable_set2(lines[i], cp);
331         }
332         free(lines[i]);
333     }
334 }
335
336 /* Load the environment from a resolv.conf file */
337 void
338 configEnvironmentResolv(char *config)
339 {
340     char *lines[MAX_LINES];
341     int i, nlines;
342
343     nlines = readConfig(config, lines, MAX_LINES);
344     if (nlines == -1)
345         return;
346     for (i = 0; i < nlines; i++) {
347         Boolean name_set = FALSE;
348
349         if (!strncmp(lines[i], "domain", 6))
350             variable_set2(VAR_DOMAINNAME, string_skipwhite(string_prune(lines[i] + 6)));
351         else if (!strncmp(lines[i], "nameserver", 10) && !name_set) {
352             /* Only take the first nameserver setting - we're lame */
353             variable_set2(VAR_NAMESERVER, string_skipwhite(string_prune(lines[i] + 10)));
354             name_set = TRUE;
355         }
356         free(lines[i]);
357     }
358 }
359
360 /* Version of below for dispatch routines */
361 int
362 configRC(dialogMenuItem *unused)
363 {
364     configRC_conf("/etc/rc.conf");
365     return DITEM_SUCCESS;
366 }
367
368 /*
369  * This sucks in /etc/rc.conf, substitutes anything needing substitution, then
370  * writes it all back out.  It's pretty gross and needs re-writing at some point.
371  */
372 void
373 configRC_conf(char *config)
374 {
375     FILE *fp;
376     char *lines[MAX_LINES], *cp;
377     Variable *v;
378     int i, nlines, len;
379
380     nlines = readConfig(config, lines, MAX_LINES);
381     if (nlines == -1)
382         return;
383
384     /* Now do variable substitutions */
385     for (v = VarHead; v; v = v->next) {
386         for (i = 0; i < nlines; i++) {
387             /* Skip the comments & non-variable settings */
388             if (lines[i][0] == '#' || !(cp = index(lines[i], '=')))
389                 continue;
390             len = strlen(v->name);
391             if (!strncmp(lines[i], v->name, cp - lines[i]) && (cp - lines[i]) == len) {
392                 char *cp2, *comment = NULL;
393
394                 /* If trailing comment, try and preserve it */
395                 if ((index(lines[i], '#')) != NULL) {
396                     /* Find quotes */
397                     if ((cp2 = index(cp, '"')) || (cp2 = index(cp, '\047')))
398                         cp2 = index(cp2 + 1, *cp2);
399                     if (cp2 && strlen(cp2 + 1)) {
400                         comment = alloca(strlen(cp2));
401                         strcpy(comment, cp2 + 1);
402                     }
403                 }
404                 free(lines[i]);
405                 lines[i] = (char *)malloc(strlen(v->name) + strlen(v->value) + (comment ? strlen(comment) : 0) + 10);
406                 if (comment)
407                     sprintf(lines[i], "%s=\"%s\"%s", v->name, v->value, comment);
408                 else
409                     sprintf(lines[i], "%s=\"%s\"\n", v->name, v->value);
410             }
411         }
412     }
413
414     /* Now write it all back out again */
415     if (isDebug())
416         msgDebug("Writing configuration changes to %s file..", config);
417     if (Fake)
418         fp = fdopen(DebugFD, "w");
419     else {
420         (void)vsystem("cp %s %s.previous", config, config);
421         fp = fopen(config, "w");
422     }
423     for (i = 0; i < nlines; i++) {
424         fprintf(fp, lines[i]);
425         /* Stand by for bogus special case handling - we try to dump the interface specs here */
426         if (!strncmp(lines[i], VAR_INTERFACES, strlen(VAR_INTERFACES))) {
427             Device **devp;
428             int j, cnt;
429
430             devp = deviceFind(NULL, DEVICE_TYPE_NETWORK);
431             cnt = deviceCount(devp);
432             for (j = 0; j < cnt; j++) {
433                 char iname[255], toadd[512];
434                 int k, addit = TRUE;
435
436                 if (!strncmp(devp[j]->name, "ppp", 3) || !strncmp(devp[j]->name, "tun", 3))
437                     continue;
438
439                 snprintf(iname, 255, "%s%s", VAR_IFCONFIG, devp[j]->name);
440                 if ((cp = variable_get(iname))) {
441                     snprintf(toadd, sizeof toadd, "%s=\"%s\"\n", iname, cp);
442                     for (k = 0; k < nlines; k++) {
443                         if (!strcmp(lines[k], toadd)) {
444                             addit = FALSE;
445                             break;
446                         }
447                     }
448                     if (addit)
449                         fprintf(fp, toadd);
450                 }
451             }
452         }
453         free(lines[i]);
454     }
455     fclose(fp);
456 }
457
458 int
459 configSaver(dialogMenuItem *self)
460 {
461     variable_set((char *)self->data);
462     if (!variable_get(VAR_BLANKTIME))
463         variable_set2(VAR_BLANKTIME, "300");
464     return DITEM_SUCCESS;
465 }
466
467 int
468 configSaverTimeout(dialogMenuItem *self)
469 {
470     return (variable_get_value(VAR_BLANKTIME, "Enter time-out period in seconds for screen saver") ?
471             DITEM_SUCCESS : DITEM_FAILURE) | DITEM_RESTORE;
472 }
473
474 int
475 configRegister(dialogMenuItem *self)
476 {
477     return DITEM_STATUS(registerOpenDialog()) | DITEM_RESTORE;
478 }
479
480 int
481 configNTP(dialogMenuItem *self)
482 {
483     int status;
484
485     status = variable_get_value("ntpdate_flags", "Enter the name of an NTP server") ? DITEM_SUCCESS : DITEM_FAILURE;
486     if (status == DITEM_SUCCESS) {
487         static char tmp[255];
488
489         snprintf(tmp, 255, "ntpdate_enable=YES,ntpdate_flags=%s", variable_get("ntpdate_flags"));
490         self->data = tmp;
491         dmenuSetVariables(self);
492     }
493     return status | DITEM_RESTORE;
494 }
495
496 int
497 configUsers(dialogMenuItem *self)
498 {
499     dialog_clear_norefresh();
500     dmenuOpenSimple(&MenuUsermgmt, FALSE); 
501     dialog_clear();
502     return DITEM_SUCCESS | DITEM_RESTORE;
503 }
504
505 int
506 configXEnvironment(dialogMenuItem *self)
507 {
508 #ifndef USE_XIG_ENVIRONMENT
509     char *config, *execfile;
510
511     dialog_clear_norefresh();
512     if (!dmenuOpenSimple(&MenuXF86Config, FALSE))
513         return DITEM_FAILURE | DITEM_RESTORE;
514     systemExecute("/sbin/ldconfig /usr/lib /usr/X11R6/lib /usr/local/lib /usr/lib/compat");
515     config = variable_get(VAR_XF86_CONFIG);
516     if (!config)
517         return DITEM_FAILURE | DITEM_RESTORE;
518     execfile = string_concat("/usr/X11R6/bin/", config);
519     if (file_executable(execfile)) {
520         dialog_clear_norefresh();
521         if (!file_readable("/dev/mouse") && !msgYesNo("Does this system have a mouse attached to it?"))
522             dmenuOpenSimple(&MenuMouse, FALSE); 
523         dialog_clear();
524         systemExecute(execfile);
525         return DITEM_SUCCESS | DITEM_RESTORE;
526     }
527     else {
528         dialog_clear_norefresh();
529         msgConfirm("XFree86 does not appear to be installed!  Please install\n"
530                    "The XFree86 distribution before attempting to configure it.");
531         return DITEM_FAILURE | DITEM_RESTORE;
532     }
533
534 #else   /* USE_XIG_ENVIRONMENT */
535     int i;
536
537     /* Make sure we're sane first */
538     if (!file_readable("/usr/X11R6/lib/X11/AcceleratedX/bin/Xinstall") ||
539         !file_readable("/usr/X11R6/lib/X11/AcceleratedX/bin/Xsetup")) {
540         dialog_clear_norefresh();
541         msgConfirm("Hmmm!  It looks like you elected not to install the AccelleratedX\n"
542                    "server package (or the installation failed somehow).  If this was\n"
543                    "an omission rather than an error, please go to the Distributions\n"
544                    "menu, select the Custom distribution options and then choose your X11\n"
545                    "distribution components from the XFree86 menu.  AccelX will be selected\n"
546                    "as the default server automatically.");
547         return DITEM_FAILURE | DITEM_RESTORE;
548     }
549
550     if (mediaDevice && mediaDevice->type != DEVICE_TYPE_CDROM) {
551         if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS || !mediaDevice || !mediaDevice->init(mediaDevice)) {
552             msgConfirm("I can't mount the CDE distribution from CDROM, sorry.\n"
553                        "Please make sure you have the 1st CD of your FreeBSD Desktop/Pro\n"
554                        "distribution in the drive before trying this operation.");
555             return DITEM_FAILURE | DITEM_RESTORE;
556         }
557     }
558
559     if (!directory_exists("/dist/CDE/")) {
560         msgConfirm("Hmmm!  I can't find the CDE distribution.  Please place the 1st CD of your\n"
561                    "FreeBSD Desktop/Pro distribution in the drive and try this operation again.");
562         return DITEM_FAILURE | DITEM_RESTORE;
563     }
564
565     /* Pre-extract base sets in kludge to work around chicken-and-egg problem with CDE and Xaccel */
566     if (directory_exists("/dist/CDE/") && !file_readable("/usr/X11R6/bin/xterm")) {
567         msgNotify("Installing bootstrap X11 tools from CDE distribution.");
568         systemExecute("tar xpf /dist/CDE/FreeBSD/packages/X11-RUN/archive -C /");
569         systemExecute("tar xpf /dist/CDE/FreeBSD/packages/X11-PRG/archive -C /");
570     }
571     systemExecute("/sbin/ldconfig /usr/lib /usr/X11R6/lib /usr/dt/lib /usr/local/lib /usr/lib/compat");
572
573     dialog_clear_norefresh();
574     msgNotify("Running AcceleratedX 3.1 installation procedure, please wait.");
575     if ((i = vsystem("/usr/X11R6/lib/X11/AcceleratedX/bin/Xinstall"))) {
576         dialog_clear_norefresh();
577         msgConfirm("Installation procedure failed, error code %d!  Please report\n"
578                    "error to Walnut Creek CDROM tech support (either send email\n"
579                    "to support@cdrom.com or call +1 510 603 1234).  Thank you!", i);
580         return DITEM_FAILURE | DITEM_RESTORE;
581     }
582     else {
583         dialog_clear();
584         systemExecute("/usr/X11R6/lib/X11/AcceleratedX/bin/Xsetup");
585     }
586     if (directory_exists("/dist/CDE")) {
587         dialog_clear_norefresh();
588         msgNotify("Running CDE installation - please wait (this may take awhile!).");
589         dialog_clear();
590         clear();
591         refresh();
592         i = systemExecute("(cd /dist/CDE; sh Install)");
593         dialog_clear();
594         if (i) {
595             msgConfirm("/dist/CDE/dtinstall script returned an error status!\n\n"
596                        "To try again, you should run this command manually after the system\n"
597                        "is up (and if your CDROM is mounted in the standard location, the path\n"
598                        "to it will actually be /cdrom/CDE/dtinstall when you run it later).\n");
599         }
600         else {
601             if (file_readable("/dist/CDE/post-install"))
602                 systemExecute("/dist/CDE/post-install");
603             /* Repair the damage done by the CDE installation */
604             msgNotify("Doing final adjustments to Xaccel distribution...");
605             systemExecute("/usr/X11R6/lib/X11/AcceleratedX/bin/Xinstall");
606         }
607     }
608     return DITEM_SUCCESS | DITEM_RESTORE;
609 #endif  /* USE_XIG_ENVIRONMENT */
610 }
611
612 void
613 configResolv(void)
614 {
615     FILE *fp;
616     char *cp, *dp, *hp;
617
618     cp = variable_get(VAR_NAMESERVER);
619     if (!cp || !*cp)
620         goto skip;
621     Mkdir("/etc");
622     fp = fopen("/etc/resolv.conf", "w");
623     if (!fp)
624         return;
625     if (variable_get(VAR_DOMAINNAME))
626         fprintf(fp, "domain\t%s\n", variable_get(VAR_DOMAINNAME));
627     fprintf(fp, "nameserver\t%s\n", cp);
628     fclose(fp);
629     if (isDebug())
630         msgDebug("Wrote out /etc/resolv.conf\n");
631
632 skip:
633     dp = variable_get(VAR_DOMAINNAME);
634     cp = variable_get(VAR_IPADDR);
635     hp = variable_get(VAR_HOSTNAME);
636     /* Tack ourselves into /etc/hosts */
637     fp = fopen("/etc/hosts", "w");
638     if (!fp)
639         return;
640     /* Add an entry for localhost */
641     fprintf(fp, "127.0.0.1\t\tlocalhost.%s localhost\n", dp ? dp : "my.domain");
642     /* Now the host entries, if applicable */
643     if (cp && cp[0] != '0' && hp) {
644         char cp2[255];
645
646         if (!index(hp, '.'))
647             cp2[0] = '\0';
648         else {
649             SAFE_STRCPY(cp2, hp);
650             *(index(cp2, '.')) = '\0';
651         }
652         fprintf(fp, "%s\t\t%s %s\n", cp, hp, cp2);
653         fprintf(fp, "%s\t\t%s.\n", cp, hp);
654     }
655     fclose(fp);
656     if (isDebug())
657         msgDebug("Wrote out /etc/hosts\n");
658 }
659
660 int
661 configRouter(dialogMenuItem *self)
662 {
663     int ret;
664
665     ret = variable_get_value(VAR_ROUTER,
666                              "Please specify the router you wish to use.  Routed is\n"
667                              "provided with the stock system and gated is provided\n"
668                              "as an optional package which this installation system\n"
669                              "will attempt to load if you select gated.  Any other\n"
670                              "choice of routing daemon will be assumed to be something\n"
671                              "the user intends to install themselves before rebooting\n"
672                              "the system.  If you don't want any routing daemon, choose NO")
673       ? DITEM_SUCCESS : DITEM_FAILURE;
674   
675     if (ret == DITEM_SUCCESS) {
676         char *cp = variable_get(VAR_ROUTER);
677     
678         if (cp && strcmp(cp, "NO")) {
679             variable_set2(VAR_ROUTER_ENABLE, "YES");
680             if (!strcmp(cp, "gated")) {
681                 if (package_add(variable_get(VAR_GATED_PKG)) != DITEM_SUCCESS) {
682                     msgConfirm("Unable to load gated package.  Falling back to no router.");
683                     variable_unset(VAR_ROUTER);
684                     variable_unset(VAR_ROUTERFLAGS);
685                     variable_set2(VAR_ROUTER_ENABLE, "NO");
686                     cp = NULL;
687                 }
688             }
689             if (cp) {
690                 /* Now get the flags, if they chose a router */
691                 ret = variable_get_value(VAR_ROUTERFLAGS, 
692                                          "Please Specify the routing daemon flags; if you're running routed\n"
693                                          "then -q is the right choice for nodes and -s for gateway hosts.\n")
694                   ? DITEM_SUCCESS : DITEM_FAILURE;
695                 if (ret != DITEM_SUCCESS)
696                     variable_unset(VAR_ROUTERFLAGS);
697             }
698         }
699         else {
700             /* No router case */
701             variable_set2(VAR_ROUTER_ENABLE, "NO");
702             variable_unset(VAR_ROUTERFLAGS);
703             variable_unset(VAR_ROUTER);
704         }
705     }
706     return ret | DITEM_RESTORE;
707 }
708
709 int
710 configPackages(dialogMenuItem *self)
711 {
712     static PkgNode top, plist;
713     static Boolean index_initted = FALSE;
714     PkgNodePtr tmp;
715     FILE *fp;
716
717     if (!mediaVerify())
718         return DITEM_FAILURE;
719
720     if (!mediaDevice->init(mediaDevice))
721         return DITEM_FAILURE;
722
723     if (!index_initted) {
724         msgNotify("Attempting to fetch packages/INDEX file from selected media.");
725         fp = mediaDevice->get(mediaDevice, "packages/INDEX", TRUE);
726         if (!fp) {
727             dialog_clear_norefresh();
728             msgConfirm("Unable to get packages/INDEX file from selected media.\n"
729                        "This may be because the packages collection is not available at\n"
730                        "on the distribution media you've chosen (most likely an FTP site\n"
731                        "without the packages collection mirrored).  Please verify media\n"
732                        "(or path to media) and try again.  If your local site does not\n"
733                        "carry the packages collection, then we recommend either a CD\n"
734                        "distribution or the master distribution on ftp.freebsd.org.");
735             mediaDevice->shutdown(mediaDevice);
736             return DITEM_FAILURE | DITEM_RESTORE;
737         }
738         msgNotify("Located INDEX, now reading package data from it...");
739         index_init(&top, &plist);
740         if (index_read(fp, &top)) {
741             msgConfirm("I/O or format error on packages/INDEX file.\n"
742                        "Please verify media (or path to media) and try again.");
743             fclose(fp);
744             return DITEM_FAILURE | DITEM_RESTORE;
745         }
746         fclose(fp);
747         index_sort(&top);
748         index_initted = TRUE;
749     }
750     while (1) {
751         int ret, pos, scroll;
752
753         /* Bring up the packages menu */
754         pos = scroll = 0;
755         index_menu(&top, &plist, &pos, &scroll);
756
757         if (plist.kids && plist.kids->name) {
758             /* Now show the packing list menu */
759             pos = scroll = 0;
760             ret = index_menu(&plist, NULL, &pos, &scroll);
761             if (ret & DITEM_LEAVE_MENU)
762                 break;
763             else if (DITEM_STATUS(ret) != DITEM_FAILURE) {
764                 index_extract(mediaDevice, &top, &plist);
765                 break;
766             }
767         }
768         else {
769             dialog_clear_norefresh();
770             msgConfirm("No packages were selected for extraction.");
771             break;
772         }
773     }
774     tmp = plist.kids;
775     while (tmp) {
776         PkgNodePtr tmp2 = tmp->next;
777            
778         safe_free(tmp);
779         tmp = tmp2;
780     }
781     index_init(NULL, &plist);
782     return DITEM_SUCCESS | DITEM_RESTORE;
783 }
784
785 #ifdef NETCON_EXTENTIONS
786 /* Load novell client/server package */
787 int
788 configNovell(dialogMenuItem *self)
789 {
790     int ret = DITEM_SUCCESS;
791
792     if (!RunningAsInit) {
793         msgConfirm("This package can only be installed in multi-user mode.");
794         return ret;
795     }
796     if (variable_get(VAR_NOVELL))
797         variable_unset(VAR_NOVELL);
798     else {
799         ret = package_add(PACKAGE_NETCON);
800         if (DITEM_STATUS(ret) == DITEM_SUCCESS)
801             variable_set2(VAR_NOVELL, "YES");
802     }
803     return ret | DITEM_RESTORE;
804 }
805 #endif
806
807 /* Load pcnfsd package */
808 int
809 configPCNFSD(dialogMenuItem *self)
810 {
811     int ret = DITEM_SUCCESS;
812
813     if (variable_get(VAR_PCNFSD))
814         variable_unset(VAR_PCNFSD);
815     else {
816         ret = package_add(variable_get(VAR_PCNFSD_PKG));
817         if (DITEM_STATUS(ret) == DITEM_SUCCESS) {
818             variable_set2(VAR_PCNFSD, "YES");
819             variable_set2("mountd_flags", "-n");
820         }
821     }
822     return ret;
823 }
824
825 int
826 configNFSServer(dialogMenuItem *self)
827 {
828     char cmd[256];
829
830     /* If we're an NFS server, we need an exports file */
831     if (!file_readable("/etc/exports")) {
832         WINDOW *w = savescr();
833
834         if (file_readable("/etc/exports.disabled"))
835             vsystem("mv /etc/exports.disabled /etc/exports");
836         else {
837             dialog_clear_norefresh();
838             msgConfirm("Operating as an NFS server means that you must first configure\n"
839                        "an /etc/exports file to indicate which hosts are allowed certain\n"
840                        "kinds of access to your local file systems.\n"
841                        "Press [ENTER] now to invoke an editor on /etc/exports\n");
842             vsystem("echo '#The following examples export /usr to 3 machines named after ducks,' > /etc/exports");
843             vsystem("echo '#/home and all directories under it to machines named after dead rock stars' >> /etc/exports");
844             vsystem("echo '#and, finally, /a to 2 privileged machines allowed to write on it as root.' >> /etc/exports");
845             vsystem("echo '#/usr                huey louie dewie' >> /etc/exports");
846             vsystem("echo '#/home   -alldirs    janice jimmy frank' >> /etc/exports");
847             vsystem("echo '#/a      -maproot=0  bill albert' >> /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 >> /etc/exports");
851             sprintf(cmd, "%s /etc/exports", variable_get(VAR_EDITOR));
852             dialog_clear();
853             systemExecute(cmd);
854             restorescr(w);
855         }
856         variable_set2(VAR_NFS_SERVER, "YES");
857     }
858     else if (variable_get(VAR_NFS_SERVER)) { /* We want to turn it off again? */
859         vsystem("mv -f /etc/exports /etc/exports.disabled");
860         variable_unset(VAR_NFS_SERVER);
861     }
862     return DITEM_SUCCESS;
863 }