]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - release/sysinstall/config.c
This commit was generated by cvs2svn to compensate for changes in r34461,
[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.106 1998/03/09 08:39:46 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 (strlen(cp))
324                 variable_set2(lines[i], cp);
325         }
326         free(lines[i]);
327     }
328 }
329
330 /* Load the environment from a resolv.conf file */
331 void
332 configEnvironmentResolv(char *config)
333 {
334     char *lines[MAX_LINES];
335     int i, nlines;
336
337     nlines = readConfig(config, lines, MAX_LINES);
338     if (nlines == -1)
339         return;
340     for (i = 0; i < nlines; i++) {
341         Boolean name_set = FALSE;
342
343         if (!strncmp(lines[i], "domain", 6))
344             variable_set2(VAR_DOMAINNAME, string_skipwhite(string_prune(lines[i] + 6)));
345         else if (!strncmp(lines[i], "nameserver", 10) && !name_set) {
346             /* Only take the first nameserver setting - we're lame */
347             variable_set2(VAR_NAMESERVER, string_skipwhite(string_prune(lines[i] + 10)));
348             name_set = TRUE;
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     systemExecute("/sbin/ldconfig /usr/lib /usr/X11R6/lib /usr/local/lib /usr/lib/compat");
513     config = variable_get(VAR_XF86_CONFIG);
514     if (!config)
515         return DITEM_FAILURE | DITEM_RESTORE;
516     execfile = string_concat("/usr/X11R6/bin/", config);
517     if (file_executable(execfile)) {
518         dialog_clear_norefresh();
519         moused = variable_get(VAR_MOUSED);
520         while (!moused || strcmp(moused, "YES")) {
521             if (msgYesNo("The X server may access the mouse in two ways: direct access\n"
522                          "or indirect access via the mouse daemon.  You have not\n"
523                          "configured the mouse daemon.  Would you like to configure it\n"
524                          "now?  If you intend to let the X server access the mouse\n"
525                          "directly, choose \"No\" at this time."))
526                 break;
527             dmenuOpenSimple(&MenuMouse, FALSE); 
528             dialog_clear();
529             moused = variable_get(VAR_MOUSED);
530         }
531         if (moused && !strcmp(moused, "YES"))
532             msgConfirm("You have configured and been running the mouse daemon.\n"
533                        "Choose \"/dev/sysmouse\" as the mouse port and \"SysMouse\" or\n"
534                        "\"MouseSystems\" as the mouse protocol in the X configuration\n"
535                        "utility.");
536         dialog_clear();
537         systemExecute(execfile);
538         return DITEM_SUCCESS | DITEM_RESTORE;
539     }
540     else {
541         dialog_clear_norefresh();
542         msgConfirm("XFree86 does not appear to be installed!  Please install\n"
543                    "The XFree86 distribution before attempting to configure it.");
544         return DITEM_FAILURE | DITEM_RESTORE;
545     }
546 }
547
548 void
549 configResolv(void)
550 {
551     FILE *fp;
552     char *cp, *dp, *hp;
553
554     cp = variable_get(VAR_NAMESERVER);
555     if (!cp || !*cp)
556         goto skip;
557     Mkdir("/etc");
558     fp = fopen("/etc/resolv.conf", "w");
559     if (!fp)
560         return;
561     if (variable_get(VAR_DOMAINNAME))
562         fprintf(fp, "domain\t%s\n", variable_get(VAR_DOMAINNAME));
563     fprintf(fp, "nameserver\t%s\n", cp);
564     fclose(fp);
565     if (isDebug())
566         msgDebug("Wrote out /etc/resolv.conf\n");
567
568 skip:
569     dp = variable_get(VAR_DOMAINNAME);
570     cp = variable_get(VAR_IPADDR);
571     hp = variable_get(VAR_HOSTNAME);
572     /* Tack ourselves into /etc/hosts */
573     fp = fopen("/etc/hosts", "w");
574     if (!fp)
575         return;
576     /* Add an entry for localhost */
577     fprintf(fp, "127.0.0.1\t\tlocalhost.%s localhost\n", dp ? dp : "my.domain");
578     /* Now the host entries, if applicable */
579     if (cp && cp[0] != '0' && hp) {
580         char cp2[255];
581
582         if (!index(hp, '.'))
583             cp2[0] = '\0';
584         else {
585             SAFE_STRCPY(cp2, hp);
586             *(index(cp2, '.')) = '\0';
587         }
588         fprintf(fp, "%s\t\t%s %s\n", cp, hp, cp2);
589         fprintf(fp, "%s\t\t%s.\n", cp, hp);
590     }
591     fclose(fp);
592     if (isDebug())
593         msgDebug("Wrote out /etc/hosts\n");
594 }
595
596 int
597 configRouter(dialogMenuItem *self)
598 {
599     int ret;
600
601     ret = variable_get_value(VAR_ROUTER,
602                              "Please specify the router you wish to use.  Routed is\n"
603                              "provided with the stock system and gated is provided\n"
604                              "as an optional package which this installation system\n"
605                              "will attempt to load if you select gated.  Any other\n"
606                              "choice of routing daemon will be assumed to be something\n"
607                              "the user intends to install themselves before rebooting\n"
608                              "the system.  If you don't want any routing daemon, choose NO")
609       ? DITEM_SUCCESS : DITEM_FAILURE;
610   
611     if (ret == DITEM_SUCCESS) {
612         char *cp = variable_get(VAR_ROUTER);
613     
614         if (cp && strcmp(cp, "NO")) {
615             variable_set2(VAR_ROUTER_ENABLE, "YES");
616             if (!strcmp(cp, "gated")) {
617                 if (package_add(variable_get(VAR_GATED_PKG)) != DITEM_SUCCESS) {
618                     msgConfirm("Unable to load gated package.  Falling back to no router.");
619                     variable_unset(VAR_ROUTER);
620                     variable_unset(VAR_ROUTERFLAGS);
621                     variable_set2(VAR_ROUTER_ENABLE, "NO");
622                     cp = NULL;
623                 }
624             }
625             if (cp) {
626                 /* Now get the flags, if they chose a router */
627                 ret = variable_get_value(VAR_ROUTERFLAGS, 
628                                          "Please Specify the routing daemon flags; if you're running routed\n"
629                                          "then -q is the right choice for nodes and -s for gateway hosts.\n")
630                   ? DITEM_SUCCESS : DITEM_FAILURE;
631                 if (ret != DITEM_SUCCESS)
632                     variable_unset(VAR_ROUTERFLAGS);
633             }
634         }
635         else {
636             /* No router case */
637             variable_set2(VAR_ROUTER_ENABLE, "NO");
638             variable_unset(VAR_ROUTERFLAGS);
639             variable_unset(VAR_ROUTER);
640         }
641     }
642     return ret | DITEM_RESTORE;
643 }
644
645 int
646 configPackages(dialogMenuItem *self)
647 {
648     static PkgNode top, plist;
649     static Boolean index_initted = FALSE;
650     PkgNodePtr tmp;
651     FILE *fp;
652
653     if (!mediaVerify())
654         return DITEM_FAILURE;
655
656     if (!mediaDevice->init(mediaDevice))
657         return DITEM_FAILURE;
658
659     if (!index_initted) {
660         msgNotify("Attempting to fetch packages/INDEX file from selected media.");
661         fp = mediaDevice->get(mediaDevice, "packages/INDEX", TRUE);
662         if (!fp) {
663             dialog_clear_norefresh();
664             msgConfirm("Unable to get packages/INDEX file from selected media.\n"
665                        "This may be because the packages collection is not available at\n"
666                        "on the distribution media you've chosen (most likely an FTP site\n"
667                        "without the packages collection mirrored).  Please verify media\n"
668                        "(or path to media) and try again.  If your local site does not\n"
669                        "carry the packages collection, then we recommend either a CD\n"
670                        "distribution or the master distribution on ftp.freebsd.org.");
671             mediaDevice->shutdown(mediaDevice);
672             return DITEM_FAILURE | DITEM_RESTORE;
673         }
674         msgNotify("Located INDEX, now reading package data from it...");
675         index_init(&top, &plist);
676         if (index_read(fp, &top)) {
677             msgConfirm("I/O or format error on packages/INDEX file.\n"
678                        "Please verify media (or path to media) and try again.");
679             fclose(fp);
680             return DITEM_FAILURE | DITEM_RESTORE;
681         }
682         fclose(fp);
683         index_sort(&top);
684         index_initted = TRUE;
685     }
686     while (1) {
687         int ret, pos, scroll;
688
689         /* Bring up the packages menu */
690         pos = scroll = 0;
691         index_menu(&top, &plist, &pos, &scroll);
692
693         if (plist.kids && plist.kids->name) {
694             /* Now show the packing list menu */
695             pos = scroll = 0;
696             ret = index_menu(&plist, NULL, &pos, &scroll);
697             if (ret & DITEM_LEAVE_MENU)
698                 break;
699             else if (DITEM_STATUS(ret) != DITEM_FAILURE) {
700                 index_extract(mediaDevice, &top, &plist);
701                 break;
702             }
703         }
704         else {
705             dialog_clear_norefresh();
706             msgConfirm("No packages were selected for extraction.");
707             break;
708         }
709     }
710     tmp = plist.kids;
711     while (tmp) {
712         PkgNodePtr tmp2 = tmp->next;
713            
714         safe_free(tmp);
715         tmp = tmp2;
716     }
717     index_init(NULL, &plist);
718     return DITEM_SUCCESS | DITEM_RESTORE;
719 }
720
721 #ifdef NETCON_EXTENTIONS
722 /* Load novell client/server package */
723 int
724 configNovell(dialogMenuItem *self)
725 {
726     int ret = DITEM_SUCCESS;
727
728     if (!RunningAsInit) {
729         msgConfirm("This package can only be installed in multi-user mode.");
730         return ret;
731     }
732     if (variable_get(VAR_NOVELL))
733         variable_unset(VAR_NOVELL);
734     else {
735         ret = package_add(PACKAGE_NETCON);
736         if (DITEM_STATUS(ret) == DITEM_SUCCESS)
737             variable_set2(VAR_NOVELL, "YES");
738     }
739     return ret | DITEM_RESTORE;
740 }
741 #endif
742
743 /* Load pcnfsd package */
744 int
745 configPCNFSD(dialogMenuItem *self)
746 {
747     int ret = DITEM_SUCCESS;
748
749     if (variable_get(VAR_PCNFSD))
750         variable_unset(VAR_PCNFSD);
751     else {
752         ret = package_add(variable_get(VAR_PCNFSD_PKG));
753         if (DITEM_STATUS(ret) == DITEM_SUCCESS) {
754             variable_set2(VAR_PCNFSD, "YES");
755             variable_set2("mountd_flags", "-n");
756         }
757     }
758     return ret;
759 }
760
761 int
762 configNFSServer(dialogMenuItem *self)
763 {
764     char cmd[256];
765
766     /* If we're an NFS server, we need an exports file */
767     if (!file_readable("/etc/exports")) {
768         WINDOW *w = savescr();
769
770         if (file_readable("/etc/exports.disabled"))
771             vsystem("mv /etc/exports.disabled /etc/exports");
772         else {
773             dialog_clear_norefresh();
774             msgConfirm("Operating as an NFS server means that you must first configure\n"
775                        "an /etc/exports file to indicate which hosts are allowed certain\n"
776                        "kinds of access to your local file systems.\n"
777                        "Press [ENTER] now to invoke an editor on /etc/exports\n");
778             vsystem("echo '#The following examples export /usr to 3 machines named after ducks,' > /etc/exports");
779             vsystem("echo '#/home and all directories under it to machines named after dead rock stars' >> /etc/exports");
780             vsystem("echo '#and, finally, /a to 2 privileged machines allowed to write on it as root.' >> /etc/exports");
781             vsystem("echo '#/usr                huey louie dewie' >> /etc/exports");
782             vsystem("echo '#/home   -alldirs    janice jimmy frank' >> /etc/exports");
783             vsystem("echo '#/a      -maproot=0  bill albert' >> /etc/exports");
784             vsystem("echo '#' >> /etc/exports");
785             vsystem("echo '# You should replace these lines with your actual exported filesystems.' >> /etc/exports");
786             vsystem("echo >> /etc/exports");
787             sprintf(cmd, "%s /etc/exports", variable_get(VAR_EDITOR));
788             dialog_clear();
789             systemExecute(cmd);
790             restorescr(w);
791         }
792         variable_set2(VAR_NFS_SERVER, "YES");
793     }
794     else if (variable_get(VAR_NFS_SERVER)) { /* We want to turn it off again? */
795         vsystem("mv -f /etc/exports /etc/exports.disabled");
796         variable_unset(VAR_NFS_SERVER);
797     }
798     return DITEM_SUCCESS;
799 }