]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - release/sysinstall/config.c
This commit was generated by cvs2svn to compensate for changes in r34739,
[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.108 1998/03/10 17:24:03 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 (!strncmp(lines[i], "nameserver", 10) && !name_set) {
347             /* Only take the first nameserver setting - we're lame */
348             variable_set2(VAR_NAMESERVER, string_skipwhite(string_prune(lines[i] + 10)));
349             name_set = TRUE;
350         }
351         free(lines[i]);
352     }
353 }
354
355 /* Version of below for dispatch routines */
356 int
357 configRC(dialogMenuItem *unused)
358 {
359     configRC_conf("/etc/rc.conf");
360     return DITEM_SUCCESS;
361 }
362
363 /*
364  * This sucks in /etc/rc.conf, substitutes anything needing substitution, then
365  * writes it all back out.  It's pretty gross and needs re-writing at some point.
366  */
367 void
368 configRC_conf(char *config)
369 {
370     FILE *fp;
371     char *lines[MAX_LINES], *cp;
372     Variable *v;
373     int i, nlines, len;
374
375     nlines = readConfig(config, lines, MAX_LINES);
376     if (nlines == -1)
377         return;
378
379     /* Now do variable substitutions */
380     for (v = VarHead; v; v = v->next) {
381         for (i = 0; i < nlines; i++) {
382             /* Skip the comments & non-variable settings */
383             if (lines[i][0] == '#' || !(cp = index(lines[i], '=')))
384                 continue;
385             len = strlen(v->name);
386             if (!strncmp(lines[i], v->name, cp - lines[i]) && (cp - lines[i]) == len) {
387                 char *cp2, *comment = NULL;
388
389                 /* If trailing comment, try and preserve it */
390                 if ((index(lines[i], '#')) != NULL) {
391                     /* Find quotes */
392                     if ((cp2 = index(cp, '"')) || (cp2 = index(cp, '\047')))
393                         cp2 = index(cp2 + 1, *cp2);
394                     if (cp2 && strlen(cp2 + 1)) {
395                         comment = alloca(strlen(cp2));
396                         strcpy(comment, cp2 + 1);
397                     }
398                 }
399                 free(lines[i]);
400                 lines[i] = (char *)malloc(strlen(v->name) + strlen(v->value) + (comment ? strlen(comment) : 0) + 10);
401                 if (comment)
402                     sprintf(lines[i], "%s=\"%s\"%s", v->name, v->value, comment);
403                 else
404                     sprintf(lines[i], "%s=\"%s\"\n", v->name, v->value);
405             }
406         }
407     }
408
409     /* Now write it all back out again */
410     if (isDebug())
411         msgDebug("Writing configuration changes to %s file..", config);
412     if (Fake)
413         fp = fdopen(DebugFD, "w");
414     else {
415         (void)vsystem("cp %s %s.previous", config, config);
416         fp = fopen(config, "w");
417     }
418     for (i = 0; i < nlines; i++) {
419         fprintf(fp, lines[i]);
420         /* Stand by for bogus special case handling - we try to dump the interface specs here */
421         if (!strncmp(lines[i], VAR_INTERFACES, strlen(VAR_INTERFACES))) {
422             Device **devp;
423             int j, cnt;
424
425             devp = deviceFind(NULL, DEVICE_TYPE_NETWORK);
426             cnt = deviceCount(devp);
427             for (j = 0; j < cnt; j++) {
428                 char iname[255], toadd[512];
429                 int k, addit = TRUE;
430
431                 if (!strncmp(devp[j]->name, "ppp", 3) || !strncmp(devp[j]->name, "tun", 3))
432                     continue;
433
434                 snprintf(iname, 255, "%s%s", VAR_IFCONFIG, devp[j]->name);
435                 if ((cp = variable_get(iname))) {
436                     snprintf(toadd, sizeof toadd, "%s=\"%s\"\n", iname, cp);
437                     for (k = 0; k < nlines; k++) {
438                         if (!strcmp(lines[k], toadd)) {
439                             addit = FALSE;
440                             break;
441                         }
442                     }
443                     if (addit)
444                         fprintf(fp, toadd);
445                 }
446             }
447         }
448         free(lines[i]);
449     }
450     fclose(fp);
451 }
452
453 int
454 configSaver(dialogMenuItem *self)
455 {
456     variable_set((char *)self->data);
457     if (!variable_get(VAR_BLANKTIME))
458         variable_set2(VAR_BLANKTIME, "300");
459     return DITEM_SUCCESS;
460 }
461
462 int
463 configSaverTimeout(dialogMenuItem *self)
464 {
465     return (variable_get_value(VAR_BLANKTIME,
466             "Enter time-out period in seconds for screen saver") ?
467             DITEM_SUCCESS : DITEM_FAILURE) | DITEM_RESTORE;
468 }
469
470 int
471 configRegister(dialogMenuItem *self)
472 {
473     return DITEM_STATUS(registerOpenDialog()) | DITEM_RESTORE;
474 }
475
476 int
477 configNTP(dialogMenuItem *self)
478 {
479     int status;
480
481     status = variable_get_value(VAR_NTPDATE_FLAGS,
482                                 "Enter the name of an NTP server")
483              ? DITEM_SUCCESS : DITEM_FAILURE;
484     if (status == DITEM_SUCCESS) {
485         static char tmp[255];
486
487         snprintf(tmp, sizeof(tmp), "ntpdate_enable=YES,ntpdate_flags=%s",
488                  variable_get(VAR_NTPDATE_FLAGS));
489         self->data = tmp;
490         dmenuSetVariables(self);
491     }
492     return status | DITEM_RESTORE;
493 }
494
495 int
496 configUsers(dialogMenuItem *self)
497 {
498     dialog_clear_norefresh();
499     dmenuOpenSimple(&MenuUsermgmt, FALSE); 
500     dialog_clear();
501     return DITEM_SUCCESS | DITEM_RESTORE;
502 }
503
504 int
505 configXEnvironment(dialogMenuItem *self)
506 {
507     char *config, *execfile;
508     char *moused;
509
510     dialog_clear_norefresh();
511     if (!dmenuOpenSimple(&MenuXF86Config, FALSE))
512         return DITEM_FAILURE | DITEM_RESTORE;
513     if (file_readable("/var/run/ld.so.hints"))
514         systemExecute("/sbin/ldconfig -m /usr/lib /usr/X11R6/lib /usr/local/lib /usr/lib/compat");
515     else
516         systemExecute("/sbin/ldconfig /usr/lib /usr/X11R6/lib /usr/local/lib /usr/lib/compat");
517     config = variable_get(VAR_XF86_CONFIG);
518     if (!config)
519         return DITEM_FAILURE | DITEM_RESTORE;
520     execfile = string_concat("/usr/X11R6/bin/", config);
521     if (file_executable(execfile)) {
522         dialog_clear_norefresh();
523         moused = variable_get(VAR_MOUSED);
524         while (!moused || strcmp(moused, "YES")) {
525             if (msgYesNo("The X server may access the mouse in two ways: direct access\n"
526                          "or indirect access via the mouse daemon.  You have not\n"
527                          "configured the mouse daemon.  Would you like to configure it\n"
528                          "now?  If you intend to let the X server access the mouse\n"
529                          "directly, choose \"No\" at this time."))
530                 break;
531             dmenuOpenSimple(&MenuMouse, FALSE); 
532             dialog_clear();
533             moused = variable_get(VAR_MOUSED);
534         }
535         if (moused && !strcmp(moused, "YES"))
536             msgConfirm("You have configured and been running the mouse daemon.\n"
537                        "Choose \"/dev/sysmouse\" as the mouse port and \"SysMouse\" or\n"
538                        "\"MouseSystems\" as the mouse protocol in the X configuration\n"
539                        "utility.");
540         dialog_clear();
541         systemExecute(execfile);
542         return DITEM_SUCCESS | DITEM_RESTORE;
543     }
544     else {
545         dialog_clear_norefresh();
546         msgConfirm("XFree86 does not appear to be installed!  Please install\n"
547                    "The XFree86 distribution before attempting to configure it.");
548         return DITEM_FAILURE | DITEM_RESTORE;
549     }
550 }
551
552 void
553 configResolv(void)
554 {
555     FILE *fp;
556     char *cp, *dp, *hp;
557
558     cp = variable_get(VAR_NAMESERVER);
559     if (!cp || !*cp)
560         goto skip;
561     Mkdir("/etc");
562     fp = fopen("/etc/resolv.conf", "w");
563     if (!fp)
564         return;
565     if (variable_get(VAR_DOMAINNAME))
566         fprintf(fp, "domain\t%s\n", variable_get(VAR_DOMAINNAME));
567     fprintf(fp, "nameserver\t%s\n", cp);
568     fclose(fp);
569     if (isDebug())
570         msgDebug("Wrote out /etc/resolv.conf\n");
571
572 skip:
573     dp = variable_get(VAR_DOMAINNAME);
574     cp = variable_get(VAR_IPADDR);
575     hp = variable_get(VAR_HOSTNAME);
576     /* Tack ourselves into /etc/hosts */
577     fp = fopen("/etc/hosts", "w");
578     if (!fp)
579         return;
580     /* Add an entry for localhost */
581     fprintf(fp, "127.0.0.1\t\tlocalhost.%s localhost\n", dp ? dp : "my.domain");
582     /* Now the host entries, if applicable */
583     if (cp && cp[0] != '0' && hp) {
584         char cp2[255];
585
586         if (!index(hp, '.'))
587             cp2[0] = '\0';
588         else {
589             SAFE_STRCPY(cp2, hp);
590             *(index(cp2, '.')) = '\0';
591         }
592         fprintf(fp, "%s\t\t%s %s\n", cp, hp, cp2);
593         fprintf(fp, "%s\t\t%s.\n", cp, hp);
594     }
595     fclose(fp);
596     if (isDebug())
597         msgDebug("Wrote out /etc/hosts\n");
598 }
599
600 int
601 configRouter(dialogMenuItem *self)
602 {
603     int ret;
604
605     ret = variable_get_value(VAR_ROUTER,
606                              "Please specify the router you wish to use.  Routed is\n"
607                              "provided with the stock system and gated is provided\n"
608                              "as an optional package which this installation system\n"
609                              "will attempt to load if you select gated.  Any other\n"
610                              "choice of routing daemon will be assumed to be something\n"
611                              "the user intends to install themselves before rebooting\n"
612                              "the system.  If you don't want any routing daemon, choose NO")
613       ? DITEM_SUCCESS : DITEM_FAILURE;
614   
615     if (ret == DITEM_SUCCESS) {
616         char *cp = variable_get(VAR_ROUTER);
617     
618         if (cp && strcmp(cp, "NO")) {
619             variable_set2(VAR_ROUTER_ENABLE, "YES");
620             if (!strcmp(cp, "gated")) {
621                 if (package_add(variable_get(VAR_GATED_PKG)) != DITEM_SUCCESS) {
622                     msgConfirm("Unable to load gated package.  Falling back to no router.");
623                     variable_unset(VAR_ROUTER);
624                     variable_unset(VAR_ROUTERFLAGS);
625                     variable_set2(VAR_ROUTER_ENABLE, "NO");
626                     cp = NULL;
627                 }
628             }
629             if (cp) {
630                 /* Now get the flags, if they chose a router */
631                 ret = variable_get_value(VAR_ROUTERFLAGS, 
632                                          "Please Specify the routing daemon flags; if you're running routed\n"
633                                          "then -q is the right choice for nodes and -s for gateway hosts.\n")
634                   ? DITEM_SUCCESS : DITEM_FAILURE;
635                 if (ret != DITEM_SUCCESS)
636                     variable_unset(VAR_ROUTERFLAGS);
637             }
638         }
639         else {
640             /* No router case */
641             variable_set2(VAR_ROUTER_ENABLE, "NO");
642             variable_unset(VAR_ROUTERFLAGS);
643             variable_unset(VAR_ROUTER);
644         }
645     }
646     return ret | DITEM_RESTORE;
647 }
648
649 int
650 configPackages(dialogMenuItem *self)
651 {
652     static PkgNode top, plist;
653     static Boolean index_initted = FALSE;
654     PkgNodePtr tmp;
655     FILE *fp;
656
657     if (!mediaVerify())
658         return DITEM_FAILURE;
659
660     if (!mediaDevice->init(mediaDevice))
661         return DITEM_FAILURE;
662
663     if (!index_initted) {
664         msgNotify("Attempting to fetch packages/INDEX file from selected media.");
665         fp = mediaDevice->get(mediaDevice, "packages/INDEX", TRUE);
666         if (!fp) {
667             dialog_clear_norefresh();
668             msgConfirm("Unable to get packages/INDEX file from selected media.\n"
669                        "This may be because the packages collection is not available at\n"
670                        "on the distribution media you've chosen (most likely an FTP site\n"
671                        "without the packages collection mirrored).  Please verify media\n"
672                        "(or path to media) and try again.  If your local site does not\n"
673                        "carry the packages collection, then we recommend either a CD\n"
674                        "distribution or the master distribution on ftp.freebsd.org.");
675             mediaDevice->shutdown(mediaDevice);
676             return DITEM_FAILURE | DITEM_RESTORE;
677         }
678         msgNotify("Located INDEX, now reading package data from it...");
679         index_init(&top, &plist);
680         if (index_read(fp, &top)) {
681             msgConfirm("I/O or format error on packages/INDEX file.\n"
682                        "Please verify media (or path to media) and try again.");
683             fclose(fp);
684             return DITEM_FAILURE | DITEM_RESTORE;
685         }
686         fclose(fp);
687         index_sort(&top);
688         index_initted = TRUE;
689     }
690     while (1) {
691         int ret, pos, scroll;
692
693         /* Bring up the packages menu */
694         pos = scroll = 0;
695         index_menu(&top, &plist, &pos, &scroll);
696
697         if (plist.kids && plist.kids->name) {
698             /* Now show the packing list menu */
699             pos = scroll = 0;
700             ret = index_menu(&plist, NULL, &pos, &scroll);
701             if (ret & DITEM_LEAVE_MENU)
702                 break;
703             else if (DITEM_STATUS(ret) != DITEM_FAILURE) {
704                 index_extract(mediaDevice, &top, &plist);
705                 break;
706             }
707         }
708         else {
709             dialog_clear_norefresh();
710             msgConfirm("No packages were selected for extraction.");
711             break;
712         }
713     }
714     tmp = plist.kids;
715     while (tmp) {
716         PkgNodePtr tmp2 = tmp->next;
717            
718         safe_free(tmp);
719         tmp = tmp2;
720     }
721     index_init(NULL, &plist);
722     return DITEM_SUCCESS | DITEM_RESTORE;
723 }
724
725 #ifdef NETCON_EXTENTIONS
726 /* Load novell client/server package */
727 int
728 configNovell(dialogMenuItem *self)
729 {
730     int ret = DITEM_SUCCESS;
731
732     if (!RunningAsInit) {
733         msgConfirm("This package can only be installed in multi-user mode.");
734         return ret;
735     }
736     if (variable_get(VAR_NOVELL))
737         variable_unset(VAR_NOVELL);
738     else {
739         ret = package_add(PACKAGE_NETCON);
740         if (DITEM_STATUS(ret) == DITEM_SUCCESS)
741             variable_set2(VAR_NOVELL, "YES");
742     }
743     return ret | DITEM_RESTORE;
744 }
745 #endif
746
747 /* Load pcnfsd package */
748 int
749 configPCNFSD(dialogMenuItem *self)
750 {
751     int ret = DITEM_SUCCESS;
752
753     if (variable_get(VAR_PCNFSD))
754         variable_unset(VAR_PCNFSD);
755     else {
756         ret = package_add(variable_get(VAR_PCNFSD_PKG));
757         if (DITEM_STATUS(ret) == DITEM_SUCCESS) {
758             variable_set2(VAR_PCNFSD, "YES");
759             variable_set2("mountd_flags", "-n");
760         }
761     }
762     return ret;
763 }
764
765 int
766 configNFSServer(dialogMenuItem *self)
767 {
768     char cmd[256];
769
770     /* If we're an NFS server, we need an exports file */
771     if (!file_readable("/etc/exports")) {
772         WINDOW *w = savescr();
773
774         if (file_readable("/etc/exports.disabled"))
775             vsystem("mv /etc/exports.disabled /etc/exports");
776         else {
777             dialog_clear_norefresh();
778             msgConfirm("Operating as an NFS server means that you must first configure\n"
779                        "an /etc/exports file to indicate which hosts are allowed certain\n"
780                        "kinds of access to your local file systems.\n"
781                        "Press [ENTER] now to invoke an editor on /etc/exports\n");
782             vsystem("echo '#The following examples export /usr to 3 machines named after ducks,' > /etc/exports");
783             vsystem("echo '#/home and all directories under it to machines named after dead rock stars' >> /etc/exports");
784             vsystem("echo '#and, finally, /a to 2 privileged machines allowed to write on it as root.' >> /etc/exports");
785             vsystem("echo '#/usr                huey louie dewie' >> /etc/exports");
786             vsystem("echo '#/home   -alldirs    janice jimmy frank' >> /etc/exports");
787             vsystem("echo '#/a      -maproot=0  bill albert' >> /etc/exports");
788             vsystem("echo '#' >> /etc/exports");
789             vsystem("echo '# You should replace these lines with your actual exported filesystems.' >> /etc/exports");
790             vsystem("echo >> /etc/exports");
791             sprintf(cmd, "%s /etc/exports", variable_get(VAR_EDITOR));
792             dialog_clear();
793             systemExecute(cmd);
794             restorescr(w);
795         }
796         variable_set2(VAR_NFS_SERVER, "YES");
797     }
798     else if (variable_get(VAR_NFS_SERVER)) { /* We want to turn it off again? */
799         vsystem("mv -f /etc/exports /etc/exports.disabled");
800         variable_unset(VAR_NFS_SERVER);
801     }
802     return DITEM_SUCCESS;
803 }