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