]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - usr.sbin/sysinstall/media.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / usr.sbin / sysinstall / media.c
1 /*
2  * The new sysinstall program.
3  *
4  * This is probably the last attempt in the `sysinstall' line, the next
5  * generation being slated to 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 <signal.h>
39 #include <netdb.h>
40 #include <sys/socket.h>
41 #include <sys/param.h>
42 #include <sys/mount.h>
43 #include <sys/errno.h>
44 #include <sys/fcntl.h>
45 #include <sys/stat.h>
46 #include <sys/time.h>
47 #include <sys/mman.h>
48 #include <sys/wait.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <resolv.h>
52
53 static Boolean got_intr = FALSE;
54 static Boolean ftp_skip_resolve = FALSE;
55
56 /* timeout handler */
57 static void
58 handle_intr(int sig)
59 {
60     msgDebug("User generated interrupt.\n");
61     got_intr = TRUE;
62 }
63
64 static int
65 check_for_interrupt(void)
66 {
67     if (got_intr) {
68         got_intr = FALSE;
69         return TRUE;
70     }
71     return FALSE;
72 }
73
74 static int
75 genericHook(dialogMenuItem *self, DeviceType type)
76 {
77     Device **devs;
78
79     devs = deviceFind(self->prompt, type);
80     if (devs)
81         mediaDevice = devs[0];
82     return (devs ? DITEM_LEAVE_MENU : DITEM_FAILURE);
83 }
84
85 static int
86 cdromHook(dialogMenuItem *self)
87 {
88     return genericHook(self, DEVICE_TYPE_CDROM);
89 }
90
91 static void
92 kickstart_dns(void)
93 {
94     static Boolean initted = FALSE;
95     int time;
96     char *cp;
97
98     cp = variable_get(VAR_MEDIA_TIMEOUT);
99     if (!cp)
100         time = MEDIA_TIMEOUT;
101     else
102         time = atoi(cp);
103     if (!time)
104         time = 100;
105     if (!initted) {
106         res_init();
107         _res.retry = 2; /* 2 times seems a reasonable number to me */
108         _res.retrans = time / 2; /* so spend half our alloted time on each try */
109         initted = TRUE;
110     }
111 }
112
113 char *
114 cpioVerbosity()
115 {
116     char *cp = variable_get(VAR_CPIO_VERBOSITY);
117
118     if (cp && !strcmp(cp, "high"))
119         return "-v";
120     return "";
121 }
122
123 int
124 mediaOpen(void)
125 {
126     if (!mediaDevice || !mediaVerify() || !DEVICE_INIT(mediaDevice))
127         return DITEM_FAILURE;
128     return DITEM_SUCCESS;
129 }
130
131 void
132 mediaClose(void)
133 {
134     if (mediaDevice)
135         DEVICE_SHUTDOWN(mediaDevice);
136     mediaDevice = NULL;
137 }
138
139 /*
140  * Return 1 if we successfully found and set the installation type to
141  * be a CD.
142  */
143 int
144 mediaSetCDROM(dialogMenuItem *self)
145 {
146     Device **devs;
147     int cnt;
148
149     mediaClose();
150     devs = deviceFind(NULL, DEVICE_TYPE_CDROM);
151     cnt = deviceCount(devs);
152     if (!cnt) {
153         if (self)       /* Interactive? */
154             msgConfirm("No CD/DVD devices found!  Please check that your system's\n"
155                        "configuration is correct and that the CD/DVD drive is of a supported\n"
156                        "type.  For more information, consult the hardware guide\n"
157                        "in the Doc menu.");
158         return DITEM_FAILURE | DITEM_CONTINUE;
159     }
160     else if (cnt > 1) {
161         DMenu *menu;
162         int status;
163         
164         menu = deviceCreateMenu(&MenuMediaCDROM, DEVICE_TYPE_CDROM, cdromHook, NULL);
165         if (!menu)
166             msgFatal("Unable to create CDROM menu!  Something is seriously wrong.");
167         status = dmenuOpenSimple(menu, FALSE);
168         free(menu);
169         if (!status)
170             return DITEM_FAILURE;
171     }
172     else
173         mediaDevice = devs[0];
174     return (mediaDevice ? DITEM_SUCCESS | DITEM_LEAVE_MENU : DITEM_FAILURE);
175 }
176
177 static int
178 floppyHook(dialogMenuItem *self)
179 {
180     return genericHook(self, DEVICE_TYPE_FLOPPY);
181 }
182
183 /*
184  * Return 1 if we successfully found and set the installation type to
185  * be a floppy
186  */
187 int
188 mediaSetFloppy(dialogMenuItem *self)
189 {
190     Device **devs;
191     int cnt;
192
193     mediaClose();
194     devs = deviceFind(NULL, DEVICE_TYPE_FLOPPY);
195     cnt = deviceCount(devs);
196     if (!cnt) {
197         msgConfirm("No floppy devices found!  Please check that your system's configuration\n"
198                    "is correct.  For more information, consult the hardware guide in the Doc\n"
199                    "menu.");
200         return DITEM_FAILURE | DITEM_CONTINUE;
201     }
202     else if (cnt > 1) {
203         DMenu *menu;
204         int status;
205
206         menu = deviceCreateMenu(&MenuMediaFloppy, DEVICE_TYPE_FLOPPY, floppyHook, NULL);
207         if (!menu)
208             msgFatal("Unable to create Floppy menu!  Something is seriously wrong.");
209         status = dmenuOpenSimple(menu, FALSE);
210         free(menu);
211         if (!status)
212             return DITEM_FAILURE;
213     }
214     else
215         mediaDevice = devs[0];
216     if (mediaDevice)
217         mediaDevice->private = NULL;
218     return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE);
219 }
220
221 static int
222 USBHook(dialogMenuItem *self)
223 {
224         return genericHook(self, DEVICE_TYPE_USB);
225 }
226
227
228 /*
229  * Attempt to use USB as the installation media type.
230  */
231 int
232 mediaSetUSB(dialogMenuItem *self)
233 {
234         Device **devs;
235         int cnt;
236
237         mediaClose();
238         devs = deviceFind(NULL, DEVICE_TYPE_USB);
239         cnt = deviceCount(devs);
240
241         if (!cnt) {
242                 msgConfirm("No USB devices found (try Options/Re-scan Devices)");
243                 return DITEM_FAILURE | DITEM_CONTINUE;
244         }
245         else if (cnt > 1) {
246                 DMenu *menu;
247                 int status;
248
249                 menu = deviceCreateMenu(&MenuMediaUSB, DEVICE_TYPE_USB, USBHook,
250                     NULL);
251                 if (!menu)
252                         msgFatal("Unable to create USB menu! Something is " \
253                             "seriously wrong.");
254                 status = dmenuOpenSimple(menu, FALSE);
255                 free(menu);
256                 if (!status)
257                         return DITEM_FAILURE;
258         }
259         else
260                 mediaDevice = devs[0];
261         if (mediaDevice)
262                 mediaDevice->private = NULL;
263         if (!variable_get(VAR_NONINTERACTIVE))
264                 msgConfirm("Using USB device: %s", mediaDevice->name);
265         return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE);
266 }
267
268 static int
269 DOSHook(dialogMenuItem *self)
270 {
271     return genericHook(self, DEVICE_TYPE_DOS);
272 }
273
274 /*
275  * Return 1 if we successfully found and set the installation type to
276  * be a DOS partition.
277  */
278 int
279 mediaSetDOS(dialogMenuItem *self)
280 {
281     Device **devs;
282     int cnt;
283
284     mediaClose();
285     devs = deviceFind(NULL, DEVICE_TYPE_DOS);
286     cnt = deviceCount(devs);
287     if (!cnt) {
288         msgConfirm("No DOS primary partitions found!  This installation method is unavailable");
289         return DITEM_FAILURE | DITEM_CONTINUE;
290     }
291     else if (cnt > 1) {
292         DMenu *menu;
293         int status;
294
295         menu = deviceCreateMenu(&MenuMediaDOS, DEVICE_TYPE_DOS, DOSHook, NULL);
296         if (!menu)
297             msgFatal("Unable to create DOS menu!  Something is seriously wrong.");
298         status = dmenuOpenSimple(menu, FALSE);
299         free(menu);
300         if (!status)
301             return DITEM_FAILURE;
302     }
303     else
304         mediaDevice = devs[0];
305     return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE);
306 }
307
308 /*
309  * Return 0 if we successfully found and set the installation type to
310  * be an ftp server
311  */
312 int
313 mediaSetFTP(dialogMenuItem *self)
314 {
315     static Device ftpDevice;
316     char *cp, hbuf[MAXHOSTNAMELEN], *hostname, *dir;
317     struct addrinfo hints, *res;
318     int af;
319     size_t urllen;
320     extern int FtpPort;
321     static Device *networkDev = NULL;
322
323     mediaClose();
324     cp = variable_get(VAR_FTP_PATH);
325     /* If we've been through here before ... */
326     if (networkDev && cp && msgYesNo("Re-use old FTP site selection values?"))
327         cp = NULL;
328     if (!cp) {
329         if (!dmenuOpenSimple(&MenuMediaFTP, FALSE))
330             return DITEM_FAILURE;
331         else
332             cp = variable_get(VAR_FTP_PATH);
333     }
334     if (!cp)
335         return DITEM_FAILURE;
336     else if (!strcmp(cp, "other")) {
337         variable_set2(VAR_FTP_PATH, "ftp://", 0);
338         cp = variable_get_value(VAR_FTP_PATH, "Please specify the URL of a FreeBSD distribution on a\n"
339                                 "remote ftp site.  This site must accept either anonymous\n"
340                                 "ftp or you should have set an ftp username and password\n"
341                                 "in the Options screen.\n\n"
342                                 "A URL looks like this:  ftp://<hostname>/<path>\n"
343                                 "Where <path> is relative to the anonymous ftp directory or the\n"
344                                 "home directory of the user being logged in as.", 0);
345         if (!cp || !*cp || !strcmp(cp, "ftp://")) {
346             variable_unset(VAR_FTP_PATH);
347             return DITEM_FAILURE;
348         }
349         urllen = strlen(cp);
350         if (urllen >= sizeof(ftpDevice.name)) {
351             msgConfirm("Length of specified URL is %zu characters. Allowable maximum is %zu.",
352                         urllen,sizeof(ftpDevice.name)-1);
353             variable_unset(VAR_FTP_PATH);
354             return DITEM_FAILURE;
355         }
356     }
357     if (strncmp("ftp://", cp, 6)) {
358         msgConfirm("Sorry, %s is an invalid URL!", cp);
359         variable_unset(VAR_FTP_PATH);
360         return DITEM_FAILURE;
361     }
362     SAFE_STRCPY(ftpDevice.name, cp);
363     SAFE_STRCPY(hbuf, cp + 6);
364     hostname = hbuf;
365
366     if (!networkDev || msgYesNo("You've already done the network configuration once,\n"
367                                 "would you like to skip over it now?") != 0) {
368         if (networkDev)
369             DEVICE_SHUTDOWN(networkDev);
370         if (!(networkDev = tcpDeviceSelect())) {
371             variable_unset(VAR_FTP_PATH);
372             return DITEM_FAILURE;
373         }
374     }
375     if (!DEVICE_INIT(networkDev)) {
376         if (isDebug())
377             msgDebug("mediaSetFTP: Net device init failed.\n");
378         variable_unset(VAR_FTP_PATH);
379         return DITEM_FAILURE;
380     }
381     if (*hostname == '[' && (cp = index(hostname + 1, ']')) != NULL &&
382         (*++cp == '\0' || *cp == '/' || *cp == ':')) {
383         ++hostname;
384         *(cp - 1) = '\0';
385     }
386     else
387         cp = index(hostname, ':');
388     if (cp != NULL && *cp == ':') {
389         *(cp++) = '\0';
390         FtpPort = strtol(cp, 0, 0);
391     }
392     else
393         FtpPort = 21;
394     if ((dir = index(cp ? cp : hostname, '/')) != NULL)
395         *(dir++) = '\0';
396     if (isDebug()) {
397         msgDebug("hostname = `%s'\n", hostname);
398         msgDebug("dir = `%s'\n", dir ? dir : "/");
399         msgDebug("port # = `%d'\n", FtpPort);
400     }
401     if (!ftp_skip_resolve && variable_get(VAR_NAMESERVER)) {
402         msgNotify("Looking up host %s.", hostname);
403         if (isDebug())
404             msgDebug("Starting DNS.\n");
405         kickstart_dns();
406         if (isDebug())
407             msgDebug("Looking up hostname, %s, using getaddrinfo(AI_NUMERICHOST).\n", hostname);
408         af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
409         memset(&hints, 0, sizeof(hints));
410         hints.ai_family = af;
411         hints.ai_socktype = SOCK_STREAM;
412         hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
413         if (getaddrinfo(hostname, NULL, &hints, &res) != 0) {
414             if (isDebug())
415                 msgDebug("Looking up hostname, %s, using getaddrinfo().\n",
416                          hostname);
417             hints.ai_flags = AI_PASSIVE;
418             if (getaddrinfo(hostname, NULL, &hints, &res) != 0) {
419                 msgConfirm("Cannot resolve hostname `%s'!  Are you sure that"
420                         " your\nname server, gateway and network interface are"
421                         " correctly configured?", hostname);
422                 if (networkDev)
423                     DEVICE_SHUTDOWN(networkDev);
424                 networkDev = NULL;
425                 variable_unset(VAR_FTP_PATH);
426                 return DITEM_FAILURE;
427             }
428         }
429         freeaddrinfo(res);
430         if (isDebug())
431             msgDebug("Found DNS entry for %s successfully..\n", hostname);
432     }
433     variable_set2(VAR_FTP_HOST, hostname, 0);
434     variable_set2(VAR_FTP_DIR, dir ? dir : "/", 0);
435     variable_set2(VAR_FTP_PORT, itoa(FtpPort), 0);
436     ftpDevice.type = DEVICE_TYPE_FTP;
437     ftpDevice.init = mediaInitFTP;
438     ftpDevice.get = mediaGetFTP;
439     ftpDevice.shutdown = mediaShutdownFTP;
440     ftpDevice.private = networkDev;
441     mediaDevice = &ftpDevice;
442     return DITEM_SUCCESS | DITEM_LEAVE_MENU | DITEM_RESTORE;
443 }
444
445 int
446 mediaSetFTPActive(dialogMenuItem *self)
447 {
448     variable_set2(VAR_FTP_STATE, "active", 0);
449     return mediaSetFTP(self);
450 }
451
452 int
453 mediaSetFTPPassive(dialogMenuItem *self)
454 {
455     variable_set2(VAR_FTP_STATE, "passive", 0);
456     return mediaSetFTP(self);
457 }
458
459 int mediaSetHTTP(dialogMenuItem *self)
460 {
461     Boolean tmp;
462     int result;
463     char *cp, *idx, hbuf[MAXHOSTNAMELEN], *hostname;
464     int HttpPort;
465     int what = DITEM_RESTORE;
466
467
468     tmp = ftp_skip_resolve;
469     ftp_skip_resolve = TRUE;
470     result = mediaSetFTP(self);
471     ftp_skip_resolve = tmp;
472
473     if (DITEM_STATUS(result) != DITEM_SUCCESS)
474         return result;
475  
476     cp = variable_get_value(VAR_HTTP_PROXY,
477         "Please enter the address of the HTTP proxy in this format:\n"
478         " hostname:port (the ':port' is optional, default is 3128)",0);
479     if (!cp)
480         return DITEM_FAILURE;
481     SAFE_STRCPY(hbuf, cp);
482     hostname = hbuf;
483     if (*hostname == '[' && (idx = index(hostname + 1, ']')) != NULL &&
484         (*++idx == '\0' || *idx == ':')) {
485         ++hostname;
486         *(idx - 1) = '\0';
487     } else
488         idx = index(hostname, ':');
489     if (idx == NULL || *idx != ':')
490         HttpPort = 3128;                /* try this as default */
491     else {
492         *(idx++) = '\0';
493         HttpPort = strtol(idx, 0, 0);
494     }
495
496     variable_set2(VAR_HTTP_HOST, hostname, 0);
497     variable_set2(VAR_HTTP_PORT, itoa(HttpPort), 0);
498     if (isDebug()) {
499       msgDebug("VAR_FTP_PATH : %s\n",variable_get(VAR_FTP_PATH));
500       msgDebug("VAR_HTTP_HOST, _PORT: %s:%s\n",variable_get(VAR_HTTP_HOST),
501                                              variable_get(VAR_HTTP_PORT));
502     }
503
504     /* mediaDevice has been set by mediaSetFTP(), overwrite partly: */
505     mediaDevice->type = DEVICE_TYPE_HTTP;
506     mediaDevice->init = mediaInitHTTP;
507     mediaDevice->get = mediaGetHTTP;
508     mediaDevice->shutdown = dummyShutdown;
509     return DITEM_SUCCESS | DITEM_LEAVE_MENU | what;
510 }
511    
512
513 int
514 mediaSetUFS(dialogMenuItem *self)
515 {
516     static Device ufsDevice;
517     struct statfs st;
518     char *cp;
519
520     mediaClose();
521     cp = variable_get_value(VAR_UFS_PATH, "Enter a fully qualified pathname for the directory\n"
522                             "containing the FreeBSD distribution files:", 0);
523     if (!cp)
524         return DITEM_FAILURE;
525
526     /* If they gave us a CDROM or something, try and pick a better name */
527     if (statfs(cp, &st))
528         strcpy(ufsDevice.name, "ufs");
529     else
530         strcpy(ufsDevice.name, st.f_fstypename);
531
532     ufsDevice.type = DEVICE_TYPE_UFS;
533     ufsDevice.init = dummyInit;
534     ufsDevice.get = mediaGetUFS;
535     ufsDevice.shutdown = dummyShutdown;
536     ufsDevice.private = strdup(cp);
537     mediaDevice = &ufsDevice;
538     return DITEM_LEAVE_MENU;
539 }
540
541 int
542 mediaSetNFS(dialogMenuItem *self)
543 {
544     static Device nfsDevice;
545     static Device *networkDev = NULL;
546     char *cp, *idx;
547     char hostname[MAXPATHLEN];
548     size_t pathlen;
549
550     mediaClose();
551     cp = variable_get_value(VAR_NFS_PATH, "Please enter the full NFS file specification for the remote\n"
552                             "host and directory containing the FreeBSD distribution files.\n"
553                             "This should be in the format:  hostname:/some/freebsd/dir", 0);
554     if (!cp)
555         return DITEM_FAILURE;
556     SAFE_STRCPY(hostname, cp);
557     if (!(idx = index(hostname, ':'))) {
558         msgConfirm("Invalid NFS path specification.  Must be of the form:\n"
559                    "host:/full/pathname/to/FreeBSD/distdir");
560         return DITEM_FAILURE;
561     }
562     pathlen = strlen(hostname);
563     if (pathlen >= sizeof(nfsDevice.name)) {
564         msgConfirm("Length of specified NFS path is %zu characters. Allowable maximum is %zu.",
565                    pathlen,sizeof(nfsDevice.name)-1);
566         variable_unset(VAR_NFS_PATH);
567         return DITEM_FAILURE;
568     }
569     SAFE_STRCPY(nfsDevice.name, hostname);
570     *idx = '\0';
571     if (!networkDev || msgYesNo("You've already done the network configuration once,\n"
572                                 "would you like to skip over it now?") != 0) {
573         if (networkDev)
574             DEVICE_SHUTDOWN(networkDev);
575         if (!(networkDev = tcpDeviceSelect()))
576             return DITEM_FAILURE;
577     }
578     if (!DEVICE_INIT(networkDev)) {
579         if (isDebug())
580             msgDebug("mediaSetNFS: Net device init failed\n");
581     }
582     if (variable_get(VAR_NAMESERVER)) {
583         kickstart_dns();
584         if ((inet_addr(hostname) == INADDR_NONE) && (gethostbyname(hostname) == NULL)) {
585             msgConfirm("Cannot resolve hostname `%s'!  Are you sure that your\n"
586                        "name server, gateway and network interface are correctly configured?", hostname);
587             if (networkDev)
588                 DEVICE_SHUTDOWN(networkDev);
589             networkDev = NULL;
590             variable_unset(VAR_NFS_PATH);
591             return DITEM_FAILURE;
592         }
593         else {
594             if (isDebug())
595                 msgDebug("Found DNS entry for %s successfully..\n", hostname);
596         }
597     }
598     variable_set2(VAR_NFS_HOST, hostname, 0);
599     nfsDevice.type = DEVICE_TYPE_NFS;
600     nfsDevice.init = mediaInitNFS;
601     nfsDevice.get = mediaGetNFS;
602     nfsDevice.shutdown = mediaShutdownNFS;
603     nfsDevice.private = networkDev;
604     mediaDevice = &nfsDevice;
605     return DITEM_LEAVE_MENU;
606 }
607
608 Boolean
609 mediaExtractDistBegin(char *dir, int *fd, int *zpid, int *cpid)
610 {
611     int i, pfd[2],qfd[2];
612
613     if (!dir)
614         dir = "/";
615     Mkdir(dir);
616     chdir(dir);
617     pipe(pfd);
618     pipe(qfd);
619     *zpid = fork();
620     if (!*zpid) {
621         char *unzipper = RunningAsInit ? "/stand/" UNZIPPER
622             : "/usr/bin/" UNZIPPER;
623
624         dup2(qfd[0], 0); close(qfd[0]);
625         dup2(pfd[1], 1); close(pfd[1]);
626         if (DebugFD != -1)
627             dup2(DebugFD, 2);
628         else {
629             close(2);
630             open("/dev/null", O_WRONLY);
631         }
632         close(qfd[1]);
633         close(pfd[0]);
634         i = execl(unzipper, unzipper, (char *)0);
635         if (isDebug())
636             msgDebug("%s command returns %d status\n", unzipper, i);
637         exit(i);
638     }
639     *fd = qfd[1];
640     close(qfd[0]);
641     *cpid = fork();
642     if (!*cpid) {
643         char *cpio = RunningAsInit ? "/stand/cpio" : "/usr/bin/cpio";
644
645         dup2(pfd[0], 0); close(pfd[0]);
646         close(pfd[1]);
647         close(qfd[1]);
648         if (DebugFD != -1) {
649             dup2(DebugFD, 1);
650             dup2(DebugFD, 2);
651         }
652         else {
653             close(1); open("/dev/null", O_WRONLY);
654             dup2(1, 2);
655         }
656         if (strlen(cpioVerbosity()))
657             i = execl(cpio, cpio, "-idum", cpioVerbosity(), (char *)0);
658         else
659             i = execl(cpio, cpio, "-idum", (char *)0);
660         if (isDebug())
661             msgDebug("%s command returns %d status\n", cpio, i);
662         exit(i);
663     }
664     close(pfd[0]);
665     close(pfd[1]);
666     return TRUE;
667 }
668
669 Boolean
670 mediaExtractDistEnd(int zpid, int cpid)
671 {
672     int i,j;
673
674     i = waitpid(zpid, &j, 0);
675     /* Don't check exit status - gunzip seems to return a bogus one! */
676     if (i < 0) {
677         if (isDebug())
678             msgDebug("wait for %s returned status of %d!\n", UNZIPPER, i);
679         return FALSE;
680     }
681     i = waitpid(cpid, &j, 0);
682     if (i < 0 || WEXITSTATUS(j)) {
683         if (isDebug())
684             msgDebug("cpio returned error status of %d!\n", WEXITSTATUS(j));
685         return FALSE;
686     }
687     return TRUE;
688 }
689
690 Boolean
691 mediaExtractDist(char *dir, char *dist, FILE *fp)
692 {
693     int i, j, total, seconds, zpid, cpid, pfd[2], qfd[2];
694     char buf[BUFSIZ];
695     struct timeval start, stop;
696     struct sigaction new, old;
697
698     if (!dir)
699         dir = "/";
700
701     Mkdir(dir);
702     chdir(dir);
703     pipe(pfd);  /* read end */
704     pipe(qfd);  /* write end */
705     zpid = fork();
706     if (!zpid) {
707         char *unzipper = RunningAsInit ? "/stand/" UNZIPPER
708             : "/usr/bin/" UNZIPPER;
709
710         fclose(fp);
711         close(qfd[1]);
712         dup2(qfd[0], 0); close(qfd[0]);
713
714         close(pfd[0]); 
715         dup2(pfd[1], 1); close(pfd[1]);
716
717         if (DebugFD != -1)
718             dup2(DebugFD, 2);
719         else {
720             close(2);
721             open("/dev/null", O_WRONLY);
722         }
723         i = execl(unzipper, unzipper, (char *)0);
724         if (isDebug())
725             msgDebug("%s command returns %d status\n", unzipper, i);
726         exit(i);
727     }
728     cpid = fork();
729     if (!cpid) {
730         char *cpio = RunningAsInit ? "/stand/cpio" : "/usr/bin/cpio";
731
732         close(pfd[1]);
733         dup2(pfd[0], 0); close(pfd[0]);
734         close (qfd[0]); close(qfd[1]);
735         fclose(fp);
736         if (DebugFD != -1) {
737             dup2(DebugFD, 1);
738             dup2(DebugFD, 2);
739         }
740         else {
741             dup2(open("/dev/null", O_WRONLY), 1);
742             dup2(1, 2);
743         }
744         if (strlen(cpioVerbosity()))
745             i = execl(cpio, cpio, "-idum", cpioVerbosity(), (char *)0);
746         else
747             i = execl(cpio, cpio, "-idum", "--block-size", (char *)0);
748         if (isDebug())
749             msgDebug("%s command returns %d status\n", cpio, i);
750         exit(i);
751     }
752     close(pfd[0]); close(pfd[1]);
753     close(qfd[0]);
754
755     total = 0;
756     (void)gettimeofday(&start, (struct timezone *)0);
757
758     /* Make ^C abort the current transfer rather than the whole show */
759     new.sa_handler = handle_intr;
760     new.sa_flags = 0;
761     (void)sigemptyset(&new.sa_mask);
762     sigaction(SIGINT, &new, &old);
763
764     while ((i = fread(buf, 1, BUFSIZ, fp)) > 0) {
765         if (check_for_interrupt()) {
766             msgConfirm("Failure to read from media:  User interrupt.");
767             break;
768         }
769         if (write(qfd[1], buf, i) != i) {
770             msgConfirm("Write error on transfer to cpio process, try of %d bytes.", i);
771             break;
772         }
773         else {
774             (void)gettimeofday(&stop, (struct timezone *)0);
775             stop.tv_sec = stop.tv_sec - start.tv_sec;
776             stop.tv_usec = stop.tv_usec - start.tv_usec;
777             if (stop.tv_usec < 0)
778                 stop.tv_sec--, stop.tv_usec += 1000000;
779             seconds = stop.tv_sec + (stop.tv_usec / 1000000.0);
780             if (!seconds)
781                 seconds = 1;
782             total += i;
783             msgInfo("%10d bytes read from %s dist @ %.1f KB/sec.",
784                     total, dist, (total / seconds) / 1024.0);
785         }
786     }
787     sigaction(SIGINT, &old, NULL);      /* restore sigint */
788     close(qfd[1]);
789
790     i = waitpid(zpid, &j, 0);
791     /* Don't check exit status - gunzip seems to return a bogus one! */
792     if (i < 0) {
793         if (isDebug())
794             msgDebug("wait for %s returned status of %d!\n", UNZIPPER, i);
795         return FALSE;
796     }
797     i = waitpid(cpid, &j, 0);
798     if (i < 0 || WEXITSTATUS(j)) {
799         if (isDebug())
800             msgDebug("cpio returned error status of %d!\n", WEXITSTATUS(j));
801         return FALSE;
802     }
803     return TRUE;
804 }
805
806 int
807 mediaGetType(dialogMenuItem *self)
808 {
809     return ((dmenuOpenSimple(&MenuMedia, FALSE) && mediaDevice) ? DITEM_SUCCESS : DITEM_FAILURE);
810 }
811
812 /* Return TRUE if all the media variables are set up correctly */
813 Boolean
814 mediaVerify(void)
815 {
816     if (!mediaDevice)
817         return (DITEM_STATUS(mediaGetType(NULL)) == DITEM_SUCCESS);
818     return TRUE;
819 }
820
821 /* Set the FTP username and password fields */
822 int
823 mediaSetFTPUserPass(dialogMenuItem *self)
824 {
825     char *pass;
826
827     if (variable_get_value(VAR_FTP_USER, "Please enter the username you wish to login as:", 0)) {
828         DialogInputAttrs |= DITEM_NO_ECHO;
829         pass = variable_get_value(VAR_FTP_PASS, "Please enter the password for this user:", 0);
830         DialogInputAttrs &= ~DITEM_NO_ECHO;
831     }
832     else
833         pass = NULL;
834     return (pass ? DITEM_SUCCESS : DITEM_FAILURE);
835 }
836
837 /* Set CPIO verbosity level */
838 int
839 mediaSetCPIOVerbosity(dialogMenuItem *self)
840 {
841     char *cp = variable_get(VAR_CPIO_VERBOSITY);
842
843     if (!cp) {
844         msgConfirm("CPIO Verbosity is not set to anything!");
845         return DITEM_FAILURE;
846     }
847     else {
848         if (!strcmp(cp, "low"))
849             variable_set2(VAR_CPIO_VERBOSITY, "high", 0);
850         else /* must be "high" - wrap around */
851             variable_set2(VAR_CPIO_VERBOSITY, "low", 0);
852     }
853     return DITEM_SUCCESS;
854 }
855
856 /* A generic open which follows a well-known "path" of places to look */
857 FILE *
858 mediaGenericGet(char *base, const char *file)
859 {
860     char        buf[PATH_MAX];
861
862     snprintf(buf, PATH_MAX, "%s/%s", base, file);
863     if (file_readable(buf))
864         return fopen(buf, "r");
865     snprintf(buf, PATH_MAX, "%s/FreeBSD/%s", base, file);
866     if (file_readable(buf))
867         return fopen(buf, "r");
868     snprintf(buf, PATH_MAX, "%s/releases/%s", base, file);
869     if (file_readable(buf))
870         return fopen(buf, "r");
871     snprintf(buf, PATH_MAX, "%s/%s/%s", base, variable_get(VAR_RELNAME), file);
872     if (file_readable(buf))
873         return fopen(buf, "r");
874     snprintf(buf, PATH_MAX, "%s/releases/%s/%s", base, variable_get(VAR_RELNAME), file);
875     return fopen(buf, "r");
876 }
877