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