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