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