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