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