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