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