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