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