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