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