]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - release/sysinstall/dist.c
This commit was generated by cvs2svn to compensate for changes in r47142,
[FreeBSD/FreeBSD.git] / release / sysinstall / dist.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: dist.c,v 1.138 1999/04/21 07:22:37 obrien 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/time.h>
39 #include <signal.h>
40 #include <libutil.h>
41
42 unsigned int Dists;
43 unsigned int DESDists;
44 unsigned int SrcDists;
45 unsigned int XF86Dists;
46 unsigned int XF86ServerDists;
47 unsigned int XF86FontDists;
48
49 typedef struct _dist {
50     char *my_name;
51     char *my_dir;
52     unsigned int *my_mask;
53     unsigned int my_bit;
54     struct _dist *my_dist;
55 } Distribution;
56
57 extern Distribution DistTable[];
58 extern Distribution DESDistTable[];
59 extern Distribution SrcDistTable[];
60 extern Distribution XF86DistTable[];
61 extern Distribution XF86FontDistTable[];
62 extern Distribution XF86ServerDistTable[];
63
64 /* The top-level distribution categories */
65 static Distribution DistTable[] = {
66 { "bin",        "/",                    &Dists,         DIST_BIN,               NULL            },
67 { "doc",        "/",                    &Dists,         DIST_DOC,               NULL            },
68 { "games",      "/",                    &Dists,         DIST_GAMES,             NULL            },
69 { "manpages",   "/",                    &Dists,         DIST_MANPAGES,          NULL            },
70 { "catpages",   "/",                    &Dists,         DIST_CATPAGES,          NULL            },
71 { "proflibs",   "/",                    &Dists,         DIST_PROFLIBS,          NULL            },
72 { "dict",       "/",                    &Dists,         DIST_DICT,              NULL            },
73 { "info",       "/",                    &Dists,         DIST_INFO,              NULL            },
74 { "src",        "/",                    &Dists,         DIST_SRC,               SrcDistTable    },
75 { "des",        "/",                    &Dists,         DIST_DES,               DESDistTable    },
76 { "compat1x",   "/",                    &Dists,         DIST_COMPAT1X,          NULL            },
77 { "compat20",   "/",                    &Dists,         DIST_COMPAT20,          NULL            },
78 { "compat21",   "/",                    &Dists,         DIST_COMPAT21,          NULL            },
79 { "compat22",   "/",                    &Dists,         DIST_COMPAT22,          NULL            },
80 #if __FreeBSD__ > 3
81 { "compat3x",   "/",                    &Dists,         DIST_COMPAT3X,          NULL            },
82 #endif
83 { "ports",      "/usr",                 &Dists,         DIST_PORTS,             NULL            },
84 { "XF86333",    "/usr",                 &Dists,         DIST_XF86,              XF86DistTable   },
85 { NULL },
86 };
87
88 /* The DES distribution (not for export!) */
89 static Distribution DESDistTable[] = {
90 { "des",        "/",                    &DESDists,      DIST_DES_DES,           NULL            },
91 { "krb",        "/",                    &DESDists,      DIST_DES_KERBEROS,      NULL            },
92 { "ssecure",    "/usr/src",             &DESDists,      DIST_DES_SSECURE,       NULL            },
93 { "scrypto",    "/usr/src",             &DESDists,      DIST_DES_SCRYPTO,       NULL            },
94 { "skerbero",   "/usr/src",             &DESDists,      DIST_DES_SKERBEROS,     NULL            },
95 { NULL },
96 };
97
98 /* The /usr/src distribution */
99 static Distribution SrcDistTable[] = {
100 { "sbase",      "/usr/src",             &SrcDists,      DIST_SRC_BASE,          NULL            },
101 { "scontrib",   "/usr/src",             &SrcDists,      DIST_SRC_CONTRIB,       NULL            },
102 { "sgnu",       "/usr/src",             &SrcDists,      DIST_SRC_GNU,           NULL            },
103 { "setc",       "/usr/src",             &SrcDists,      DIST_SRC_ETC,           NULL            },
104 { "sgames",     "/usr/src",             &SrcDists,      DIST_SRC_GAMES,         NULL            },
105 { "sinclude",   "/usr/src",             &SrcDists,      DIST_SRC_INCLUDE,       NULL            },
106 { "slib",       "/usr/src",             &SrcDists,      DIST_SRC_LIB,           NULL            },
107 { "slibexec",   "/usr/src",             &SrcDists,      DIST_SRC_LIBEXEC,       NULL            },
108 { "srelease",   "/usr/src",             &SrcDists,      DIST_SRC_RELEASE,       NULL            },
109 { "sbin",       "/usr/src",             &SrcDists,      DIST_SRC_BIN,           NULL            },
110 { "ssbin",      "/usr/src",             &SrcDists,      DIST_SRC_SBIN,          NULL            },
111 { "sshare",     "/usr/src",             &SrcDists,      DIST_SRC_SHARE,         NULL            },
112 { "ssys",       "/usr/src",             &SrcDists,      DIST_SRC_SYS,           NULL            },
113 { "subin",      "/usr/src",             &SrcDists,      DIST_SRC_UBIN,          NULL            },
114 { "susbin",     "/usr/src",             &SrcDists,      DIST_SRC_USBIN,         NULL            },
115 { NULL },
116 };
117
118 /* The XFree86 distribution */
119 static Distribution XF86DistTable[] = {
120 { "XF86333",    "/usr/X11R6",           &XF86Dists,     DIST_XF86_FONTS,        XF86FontDistTable },
121 { "XF86333",    "/usr/X11R6",           &XF86Dists,     DIST_XF86_SERVER,       XF86ServerDistTable },
122 { "Xsrc1",      "/usr/X11R6/src",       &XF86Dists,     DIST_XF86_SRC,          NULL            },
123 { "Xsrcctrb",   "/usr/X11R6/src",       &XF86Dists,     DIST_XF86_CSRC,         NULL            },
124 { "Xbin",       "/usr/X11R6",           &XF86Dists,     DIST_XF86_BIN,          NULL            },
125 { "Xcfg",       "/usr/X11R6",           &XF86Dists,     DIST_XF86_CFG,          NULL            },
126 { "Xdoc",       "/usr/X11R6",           &XF86Dists,     DIST_XF86_DOC,          NULL            },
127 { "Xhtml",      "/usr/X11R6",           &XF86Dists,     DIST_XF86_HTML,         NULL            },
128 { "Xlib",       "/usr/X11R6",           &XF86Dists,     DIST_XF86_LIB,          NULL            },
129 { "Xlk98",      "/usr/X11R6",           &XF86Dists,     DIST_XF86_LKIT98,       NULL            },
130 { "Xlkit",      "/usr/X11R6",           &XF86Dists,     DIST_XF86_LKIT,         NULL            },
131 { "Xman",       "/usr/X11R6",           &XF86Dists,     DIST_XF86_MAN,          NULL            },
132 { "Xprog",      "/usr/X11R6",           &XF86Dists,     DIST_XF86_PROG,         NULL            },
133 { "Xps",        "/usr/X11R6",           &XF86Dists,     DIST_XF86_PS,           NULL            },
134 { "Xset",       "/usr/X11R6",           &XF86Dists,     DIST_XF86_SET,          NULL            },
135 { "X9set",      "/usr/X11R6",           &XF86Dists,     DIST_XF86_9SET,         NULL            },
136 { NULL },
137 };
138
139 /* The XFree86 server distribution */
140 static Distribution XF86ServerDistTable[] = {
141 { "PC98-Servers/X9480", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9480,  NULL            },
142 { "PC98-Servers/X9EGC", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9EGC,  NULL            },
143 { "PC98-Servers/X9GA9", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9GA9,  NULL            },
144 { "PC98-Servers/X9GAN", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9GAN,  NULL            },
145 { "PC98-Servers/X9LPW", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9LPW,  NULL            },
146 { "PC98-Servers/X9MGA", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9MGA,  NULL            },
147 { "PC98-Servers/X9NKV", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9NKV,  NULL            },
148 { "PC98-Servers/X9NS3", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9NS3,  NULL            },
149 { "PC98-Servers/X9SPW", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9SPW,  NULL            },
150 { "PC98-Servers/X9SVG", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9SVG,  NULL            },
151 { "PC98-Servers/X9TGU", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9TGU,  NULL            },
152 { "PC98-Servers/X9WEP", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9WEP,  NULL            },
153 { "PC98-Servers/X9WS",  "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9WS,   NULL            },
154 { "PC98-Servers/X9WSN", "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_9WSN,  NULL            },
155 { "Servers/X8514",      "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_8514,  NULL            },
156 { "Servers/XAGX",       "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_AGX,   NULL            },
157 { "Servers/XI128",      "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_I128,  NULL            },
158 { "Servers/XMa8",       "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_MACH8, NULL            },
159 { "Servers/XMa32",      "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_MACH32,NULL            },
160 { "Servers/XMa64",      "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_MACH64,NULL            },
161 { "Servers/XMono",      "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_MONO,  NULL            },
162 { "Servers/XP9K",       "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_P9000, NULL            },
163 { "Servers/XS3",        "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_S3,    NULL            },
164 { "Servers/XS3V",       "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_S3V,   NULL            },
165 { "Servers/XSVGA",      "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_SVGA,  NULL            },
166 { "Servers/XVG16",      "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_VGA16, NULL            },
167 { "Servers/XW32",       "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_W32,   NULL            },
168 { "Xnest",      "/usr/X11R6",           &XF86ServerDists,       DIST_XF86_SERVER_NEST,  NULL            },
169 { NULL },
170 };
171
172 /* The XFree86 font distribution */
173 static Distribution XF86FontDistTable[] = {
174 { "Xfnts",      "/usr/X11R6",           &XF86FontDists,         DIST_XF86_FONTS_MISC,   NULL            },
175 { "Xf100",      "/usr/X11R6",           &XF86FontDists,         DIST_XF86_FONTS_100,    NULL            },
176 { "Xfcyr",      "/usr/X11R6",           &XF86FontDists,         DIST_XF86_FONTS_CYR,    NULL            },
177 { "Xfscl",      "/usr/X11R6",           &XF86FontDists,         DIST_XF86_FONTS_SCALE,  NULL            },
178 { "Xfnon",      "/usr/X11R6",           &XF86FontDists,         DIST_XF86_FONTS_NON,    NULL            },
179 { "Xfsrv",      "/usr/X11R6",           &XF86FontDists,         DIST_XF86_FONTS_SERVER, NULL            },
180 { NULL },
181 };
182
183 static int      distMaybeSetDES(dialogMenuItem *self);
184 static int      distMaybeSetPorts(dialogMenuItem *self);
185
186
187 static void
188 distVerifyFlags(void)
189 {
190     if (SrcDists)
191         Dists |= DIST_SRC;
192     if (DESDists) {
193         if (DESDists & DIST_DES_KERBEROS)
194             DESDists |= DIST_DES_DES;
195         Dists |= DIST_DES;
196     }
197     if (XF86Dists & DIST_XF86_SET)
198         XF86ServerDists |= DIST_XF86_SERVER_VGA16;
199     if (XF86ServerDists)
200         XF86Dists |= DIST_XF86_SERVER;
201     if (XF86FontDists)
202         XF86Dists |= DIST_XF86_FONTS;
203     if (XF86Dists || XF86ServerDists || XF86FontDists)
204         Dists |= DIST_XF86;
205     if (isDebug())
206         msgDebug("Dist Masks: Dists: %0x, DES: %0x, Srcs: %0x\nXServer: %0x, XFonts: %0x, XDists: %0x\n",
207                  Dists, DESDists, SrcDists, XF86ServerDists, XF86FontDists, XF86Dists);
208 }
209
210 int
211 distReset(dialogMenuItem *self)
212 {
213     Dists = 0;
214     DESDists = 0;
215     SrcDists = 0;
216     XF86Dists = 0;
217     XF86ServerDists = 0;
218     XF86FontDists = 0;
219     return DITEM_SUCCESS | DITEM_REDRAW;
220 }
221
222 int
223 distConfig(dialogMenuItem *self)
224 {
225     char *cp;
226
227     distReset(NULL);
228
229     if ((cp = variable_get(VAR_DIST_MAIN)) != NULL)
230         Dists = atoi(cp);
231
232     if ((cp = variable_get(VAR_DIST_DES)) != NULL)
233         DESDists = atoi(cp);
234
235     if ((cp = variable_get(VAR_DIST_SRC)) != NULL)
236         SrcDists = atoi(cp);
237
238     if ((cp = variable_get(VAR_DIST_X11)) != NULL)
239         XF86Dists = atoi(cp);
240
241     if ((cp = variable_get(VAR_DIST_XSERVER)) != NULL)
242         XF86ServerDists = atoi(cp);
243
244     if ((cp = variable_get(VAR_DIST_XFONTS)) != NULL)
245         XF86FontDists = atoi(cp);
246     distVerifyFlags();
247     return DITEM_SUCCESS | DITEM_REDRAW;
248 }
249
250 static int
251 distSetX(void)
252 {
253     Dists |= DIST_XF86;
254     XF86Dists = DIST_XF86_BIN | DIST_XF86_SET | DIST_XF86_CFG | DIST_XF86_LIB | DIST_XF86_PROG | DIST_XF86_MAN | DIST_XF86_SERVER | DIST_XF86_FONTS;
255     XF86ServerDists = DIST_XF86_SERVER_SVGA | DIST_XF86_SERVER_VGA16;
256     XF86FontDists = DIST_XF86_FONTS_MISC;
257     return distSetXF86(NULL);
258 }
259
260 int
261 distSetDeveloper(dialogMenuItem *self)
262 {
263     int i;
264
265     distReset(NULL);
266     Dists = _DIST_DEVELOPER;
267     SrcDists = DIST_SRC_ALL;
268     i = distMaybeSetDES(self) | distMaybeSetPorts(self);
269     distVerifyFlags();
270     return i;
271 }
272
273 int
274 distSetXDeveloper(dialogMenuItem *self)
275 {
276     int i;
277
278     i = distSetDeveloper(self);
279     i |= distSetX();
280     distVerifyFlags();
281     return i;
282 }
283
284 int
285 distSetKernDeveloper(dialogMenuItem *self)
286 {
287     int i;
288
289     distReset(NULL);
290     Dists = _DIST_DEVELOPER;
291     SrcDists = DIST_SRC_SYS;
292     i = distMaybeSetDES(self) | distMaybeSetPorts(self);
293     distVerifyFlags();
294     return i;
295 }
296
297 int
298 distSetXKernDeveloper(dialogMenuItem *self)
299 {
300     int i;
301
302     i = distSetKernDeveloper(self);
303     i |= distSetX();
304     distVerifyFlags();
305     return i;
306 }
307
308 int
309 distSetUser(dialogMenuItem *self)
310 {
311     int i;
312
313     distReset(NULL);
314     Dists = _DIST_USER;
315     i = distMaybeSetDES(self) | distMaybeSetPorts(self);
316     distVerifyFlags();
317     return i;
318 }
319
320 int
321 distSetXUser(dialogMenuItem *self)
322 {
323     int i;
324
325     i = distSetUser(self);
326     i |= distSetX();
327     distVerifyFlags();
328     return i;
329 }
330
331 int
332 distSetMinimum(dialogMenuItem *self)
333 {
334     distReset(NULL);
335     Dists = DIST_BIN;
336     return DITEM_SUCCESS | DITEM_REDRAW;
337 }
338
339 int
340 distSetEverything(dialogMenuItem *self)
341 {
342     int i;
343
344     Dists = DIST_ALL | DIST_XF86;
345     SrcDists = DIST_SRC_ALL;
346     XF86Dists = DIST_XF86_ALL;
347     XF86ServerDists = DIST_XF86_SERVER_ALL;
348     XF86FontDists = DIST_XF86_FONTS_ALL;
349     i = distMaybeSetDES(self) | distMaybeSetPorts(self);
350     distVerifyFlags();
351     return i;
352 }
353
354 int
355 distSetDES(dialogMenuItem *self)
356 {
357     int i;
358  
359     if (!dmenuOpenSimple(&MenuDESDistributions, FALSE))
360         i = DITEM_FAILURE;
361     else
362         i = DITEM_SUCCESS;
363     distVerifyFlags();
364     return i | DITEM_RESTORE;
365 }
366
367 static int
368 distMaybeSetDES(dialogMenuItem *self)
369 {
370     int i = DITEM_SUCCESS;
371
372     dialog_clear_norefresh();
373     if (!msgYesNo("Do wish to install DES cryptographic software?\n\n"
374                   "If you choose No, FreeBSD will use an MD5 based password scheme which,\n"
375                   "while perhaps more secure, is not interoperable with the traditional\n"
376                   "UNIX DES passwords on other non-FreeBSD systems.\n\n"
377                   "Please do NOT choose Yes at this point if you are outside the\n"
378                   "United States and Canada yet are installing from a U.S. FTP server.\n"
379                   "This will violate U.S. export restrictions and possibly get the\n"
380                   "server site into trouble!  In such cases, install everything but the\n"
381                   "DES distribution from the U.S. server then switch your media type to\n"
382                   "point to an international FTP server, using the Custom installation\n"
383                   "option to select and extract the DES distribution in a second pass.")) {
384         if (!dmenuOpenSimple(&MenuDESDistributions, FALSE))
385             i = DITEM_FAILURE;
386     }
387     distVerifyFlags();
388     return i | DITEM_RESTORE;
389 }
390
391 static int
392 distMaybeSetPorts(dialogMenuItem *self)
393 {
394     dialog_clear_norefresh();
395     if (!msgYesNo("Would you like to install the FreeBSD ports collection?\n\n"
396                   "This will give you ready access to over 2000 ported software packages,\n"
397                   "though at a cost of around 50MB of disk space when \"clean\" and possibly\n"
398                   "much more than that if a lot of the distribution tarballs are loaded\n"
399                   "(unless you have the extra CDs available from a FreeBSD CDROM distribution\n"
400                   "and can mount them on /cdrom, in which case this is far less of a problem).\n\n"
401                   "The ports collection is a very valuable resource and, if you have at least\n"
402                   "100MB to spare in your /usr partition, well worth having around.\n\n"
403                   "For more information on the ports collection & the latest ports, visit:\n"
404                   "    http://www.freebsd.org/ports\n"))
405         Dists |= DIST_PORTS;
406     else
407         Dists &= ~DIST_PORTS;
408     return DITEM_SUCCESS | DITEM_RESTORE;
409 }
410
411 static Boolean
412 distSetByName(Distribution *dist, char *name)
413 {
414     int i, status = FALSE;
415     
416     /* Loop through current set */
417     for (i = 0; dist[i].my_name; i++) {
418         /* This is shorthand for "dist currently disabled" */
419         if (!dist[i].my_dir)
420             continue;
421         if (!strcmp(dist[i].my_name, name)) {
422             *(dist[i].my_mask) |= dist[i].my_bit;
423             status = TRUE;
424         }
425         if (dist[i].my_dist) {
426             if (distSetByName(dist[i].my_dist, name)) {
427                 status = TRUE;
428             }
429         }
430     }
431     distVerifyFlags();
432     return status;
433 }
434
435 /* Just for the dispatch stuff */
436 int
437 distSetCustom(dialogMenuItem *self)
438 {
439     char *cp, *cp2, *tmp;
440
441     if (!(tmp = variable_get(VAR_DISTS))) {
442         msgDebug("distSetCustom() called without %s variable set.\n", VAR_DISTS);
443         return DITEM_FAILURE;
444     }
445
446     cp = alloca(strlen(tmp) + 1);
447     if (!cp)
448         msgFatal("Couldn't alloca() %d bytes!\n", strlen(tmp) + 1);
449     strcpy(cp, tmp);
450     while (cp) {
451         if ((cp2 = index(cp, ' ')) != NULL)
452             *(cp2++) = '\0';
453         if (!distSetByName(DistTable, cp))
454             msgDebug("distSetCustom: Warning, no such release \"%s\"\n", cp);
455         cp = cp2;
456     }
457     distVerifyFlags();
458     return DITEM_SUCCESS;
459 }
460     
461 int
462 distSetSrc(dialogMenuItem *self)
463 {
464     int i;
465
466     if (!dmenuOpenSimple(&MenuSrcDistributions, FALSE))
467         i = DITEM_FAILURE;
468     else
469         i = DITEM_SUCCESS;
470     distVerifyFlags();
471     return i | DITEM_RESTORE;
472 }
473
474 int
475 distSetXF86(dialogMenuItem *self)
476 {
477     int i = DITEM_SUCCESS;
478
479     if (!dmenuOpenSimple(&MenuXF86Select, FALSE))
480         i = DITEM_FAILURE;
481     distVerifyFlags();
482     return i | DITEM_RESTORE;
483 }
484
485 static Boolean got_intr = FALSE;
486
487 /* timeout handler */
488 static void
489 handle_intr(int sig)
490 {
491     msgDebug("User generated interrupt.\n");
492     got_intr = TRUE;
493 }
494
495 static int
496 check_for_interrupt(void)
497 {
498     if (got_intr) {
499         got_intr = FALSE;
500         return TRUE;
501     }
502     return FALSE;
503 }
504
505 static Boolean
506 distExtract(char *parent, Distribution *me)
507 {
508     int i, status, total, intr;
509     int cpid, zpid, fd2, chunk, numchunks;
510     char *path, *dist, buf[BUFSIZ];
511     const char *tmp;
512     FILE *fp;
513     WINDOW *w = savescr();
514     struct timeval start, stop;
515     struct sigaction old, new;
516
517     status = TRUE;
518     dialog_clear_norefresh();
519     if (isDebug())
520         msgDebug("distExtract: parent: %s, me: %s\n", parent ? parent : "(none)", me->my_name);
521
522     /* Make ^C fake a sudden timeout */
523     new.sa_handler = handle_intr;
524     new.sa_flags = 0;
525     new.sa_mask = 0;
526     sigaction(SIGINT, &new, &old);
527
528     /* Loop through to see if we're in our parent's plans */
529     for (i = 0; me[i].my_name; i++) {
530         dist = me[i].my_name;
531         path = parent ? parent : dist;
532
533         /* If our bit isn't set, go to the next */
534         if (!(me[i].my_bit & *(me[i].my_mask)))
535             continue;
536
537         /* This is shorthand for "dist currently disabled" */
538         if (!me[i].my_dir) {
539             *(me[i].my_mask) &= ~(me[i].my_bit);
540             continue;
541         }
542
543         /* Recurse if we actually have a sub-distribution */
544         if (me[i].my_dist) {
545             if ((status = distExtract(dist, me[i].my_dist)) == TRUE)
546                 *(me[i].my_mask) &= ~(me[i].my_bit);
547             goto done;
548         }
549
550         /*
551          * Try to get distribution as multiple pieces, locating and parsing an
552          * info file which tells us how many we need for this distribution.
553          */
554         numchunks = 0;
555         snprintf(buf, sizeof buf, "%s/%s.inf", path, dist);
556
557     getinfo:
558         fp = mediaDevice->get(mediaDevice, buf, TRUE);
559         intr = check_for_interrupt();
560         if (fp == (FILE *)IO_ERROR || intr) {   /* Hard error, can't continue */
561             if (!msgYesNo("Unable to open %s: %s.\nReinitialize media?",
562                           buf, !intr ? "I/O error." : "User interrupt.")) {
563                 mediaDevice->shutdown(mediaDevice);
564                 if (!mediaDevice->init(mediaDevice)) {
565                     status = FALSE;
566                     goto done;
567                 }
568                 else
569                     goto getinfo;
570             }
571             else {
572                 status = FALSE;
573                 goto done;
574             }
575         }
576         else if (fp > 0) {
577             properties dist_attr;
578
579             if (isDebug())
580                 msgDebug("Parsing attributes file for distribution %s\n", dist);
581
582             dist_attr = properties_read(fileno(fp));
583             intr = check_for_interrupt();
584             if (intr || !dist_attr) {
585                 msgConfirm("Cannot parse information file for the %s distribution: %s\n"
586                            "Please verify that your media is valid and try again.",
587                            dist, !intr ? "I/O error" : "User interrupt");
588             }
589             else {
590                 tmp = property_find(dist_attr, "Pieces");
591                 if (tmp)
592                     numchunks = strtol(tmp, 0, 0);
593             }
594             fclose(fp);
595             properties_free(dist_attr);
596             if (!numchunks)
597                 continue;
598         }
599         else {
600             /* Try to get the distribution as a single file */
601             snprintf(buf, sizeof buf, "%s/%s.tgz", path, dist);
602             /*
603              * Passing TRUE as 3rd parm to get routine makes this a "probing" get, for which errors
604              * are not considered too significant.
605              */
606         getsingle:
607             fp = mediaDevice->get(mediaDevice, buf, TRUE);
608             intr = check_for_interrupt();
609             if (fp == (FILE *)IO_ERROR || intr) {       /* Hard error, can't continue */
610                 if (intr)       /* result of an interrupt */
611                     msgConfirm("Unable to open %s: User interrupt", buf);
612                 else
613                     msgConfirm("Unable to open %s: I/O error", buf);
614                 mediaDevice->shutdown(mediaDevice);
615                 if (!mediaDevice->init(mediaDevice)) {
616                     status = FALSE;
617                     goto done;
618                 }
619                 else
620                     goto getsingle;
621             }
622             else if (fp > 0) {
623                 char *dir = root_bias(me[i].my_dir);
624
625                 msgNotify("Extracting %s into %s directory...", dist, dir);
626                 status = mediaExtractDist(dir, dist, fp);
627                 fclose(fp);
628                 goto done;
629             }
630             else
631                 numchunks = 0;
632         }
633
634         /* Fall through from "we got the attribute file, now get the pieces" step */
635         if (!numchunks)
636             continue;
637
638         if (isDebug())
639             msgDebug("Attempting to extract distribution from %u chunks.\n", numchunks);
640
641         total = 0;
642         (void)gettimeofday(&start, (struct timezone *)0);
643
644         /* We have one or more chunks, initialize unpackers... */
645         mediaExtractDistBegin(root_bias(me[i].my_dir), &fd2, &zpid, &cpid);
646
647         /* And go for all the chunks */
648         for (chunk = 0; chunk < numchunks; chunk++) {
649             int n, retval, last_msg;
650             char prompt[80];
651
652             last_msg = 0;
653
654         getchunk:
655             snprintf(buf, sizeof buf, "%s/%s.%c%c", path, dist, (chunk / 26) + 'a', (chunk % 26) + 'a');
656             if (isDebug())
657                 msgDebug("trying for piece %d of %d: %s\n", chunk + 1, numchunks, buf);
658             fp = mediaDevice->get(mediaDevice, buf, FALSE);
659             intr = check_for_interrupt();
660             if (fp <= (FILE *)0 || intr) {
661                 if (fp == (FILE *)0)
662                     msgConfirm("Failed to find %s on this media.  Reinitializing media.", buf);
663                 else
664                     msgConfirm("failed to retreive piece file %s.\n"
665                                "%s: Reinitializing media.", buf, !intr ? "I/O error" : "User interrupt");
666                 mediaDevice->shutdown(mediaDevice);
667                 if (!mediaDevice->init(mediaDevice))
668                     goto punt;
669                 else
670                     goto getchunk;
671             }
672
673             snprintf(prompt, sizeof prompt, "Extracting %s into %s directory...", dist, root_bias(me[i].my_dir));
674             dialog_gauge("Progress", prompt, 8, 15, 6, 50, (int)((float)(chunk + 1) / numchunks * 100));
675
676             while (1) {
677                 int seconds;
678
679                 n = fread(buf, 1, BUFSIZ, fp);
680                 if (check_for_interrupt()) {
681                     msgConfirm("Media read error:  User interrupt.");
682                     fclose(fp);
683                     goto punt;
684                 }
685                 else if (n <= 0)
686                     break;
687                 total += n;
688
689                 /* Print statistics about how we're doing */
690                 (void) gettimeofday(&stop, (struct timezone *)0);
691                 stop.tv_sec = stop.tv_sec - start.tv_sec;
692                 stop.tv_usec = stop.tv_usec - start.tv_usec;
693                 if (stop.tv_usec < 0)
694                     stop.tv_sec--, stop.tv_usec += 1000000;
695                 seconds = stop.tv_sec + (stop.tv_usec / 1000000.0);
696                 if (!seconds)
697                     seconds = 1;
698
699                 if (seconds != last_msg) {
700                     last_msg = seconds;
701                     msgInfo("%10d bytes read from %s dist, chunk %2d of %2d @ %.1f KB/sec.",
702                             total, dist, chunk + 1, numchunks, (total / seconds) / 1024.0);
703                 }
704                 retval = write(fd2, buf, n);
705                 if (retval != n) {
706                     fclose(fp);
707                     dialog_clear_norefresh();
708                     msgConfirm("Write failure on transfer! (wrote %d bytes of %d bytes)", retval, n);
709                     goto punt;
710                 }
711             }
712             fclose(fp);
713         }
714         close(fd2);
715         status = mediaExtractDistEnd(zpid, cpid);
716         goto done;
717
718     punt:
719         close(fd2);
720         mediaExtractDistEnd(zpid, cpid);
721         status = FALSE;
722
723     done:
724         if (!status) {
725             if (me[i].my_dist) {
726                 msgConfirm("Unable to transfer all components of the %s distribution.\n"
727                            "If this is a CDROM install, it may be because export restrictions prohibit\n"
728                            "DES code from being shipped from the U.S.  Try to get this code from a\n"
729                            "local FTP site instead!", me[i].my_name);
730             }
731             else {
732                 status = msgYesNo("Unable to transfer the %s distribution from\n%s.\n\n"
733                                   "Do you want to try to retrieve it again?",
734                                   me[i].my_name, mediaDevice->name);
735                 if (!status)
736                     --i;
737                 dialog_clear();
738             }
739         }
740         /* If extract was successful, remove ourselves from further consideration */
741         if (status)
742             *(me[i].my_mask) &= ~(me[i].my_bit);
743         else
744             continue;
745     }
746     sigaction(SIGINT, &old, NULL);      /* Restore signal handler */
747     restorescr(w);
748     return status;
749 }
750
751 static void
752 printSelected(char *buf, int selected, Distribution *me, int *col)
753 {
754     int i;
755
756     /* Loop through to see if we're in our parent's plans */
757     for (i = 0; me[i].my_name; i++) {
758
759         /* If our bit isn't set, go to the next */
760         if (!(me[i].my_bit & selected))
761             continue;
762
763         /* This is shorthand for "dist currently disabled" */
764         if (!me[i].my_dir)
765             continue;
766
767         *col += strlen(me[i].my_name);
768         if (*col > 50) {
769             *col = 0;
770             strcat(buf, "\n");
771         }
772         sprintf(&buf[strlen(buf)], " %s", me[i].my_name);
773         /* Recurse if have a sub-distribution */
774         if (me[i].my_dist)
775             printSelected(buf, *(me[i].my_mask), me[i].my_dist, col);
776     }
777 }
778
779 int
780 distExtractAll(dialogMenuItem *self)
781 {
782     int old_dists, retries = 0, status = DITEM_SUCCESS;
783     char buf[512];
784
785     /* paranoia */
786     if (!Dists) {
787         if (!dmenuOpenSimple(&MenuSubDistributions, FALSE) || !Dists)
788             return DITEM_FAILURE | DITEM_RESTORE;
789     }
790
791     if (!mediaVerify() || !mediaDevice->init(mediaDevice))
792         return DITEM_FAILURE;
793
794     old_dists = Dists;
795     distVerifyFlags();
796
797     dialog_clear_norefresh();
798     msgNotify("Attempting to install all selected distributions..");
799
800     /* Try for 3 times around the loop, then give up. */
801     while (Dists && ++retries < 3)
802         distExtract(NULL, DistTable);
803
804     /* Only do bin fixup if bin dist was successfully extracted */
805     if ((old_dists & DIST_BIN) && !(Dists & DIST_BIN))
806         status |= installFixupBin(self);
807     if (old_dists & DIST_XF86)
808         status |= installFixupXFree(self);
809
810     if (Dists) {
811         int col = 0;
812
813         buf[0] = '\0';
814         printSelected(buf, Dists, DistTable, &col);
815         dialog_clear_norefresh();
816         msgConfirm("Couldn't extract the following distributions.  This may\n"
817                    "be because they were not available on the installation\n"
818                    "media you've chosen:\n\n\t%s", buf);
819         status |= DITEM_RESTORE;
820     }
821     return status;
822 }