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