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