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