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