]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sysinstall/media.c
This commit was generated by cvs2svn to compensate for changes in r125820,
[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 void
126 mediaClose(void)
127 {
128     if (mediaDevice)
129         DEVICE_SHUTDOWN(mediaDevice);
130     mediaDevice = NULL;
131 }
132
133 /*
134  * Return 1 if we successfully found and set the installation type to
135  * be a CD.
136  */
137 int
138 mediaSetCDROM(dialogMenuItem *self)
139 {
140     Device **devs;
141     int cnt;
142
143     mediaClose();
144     devs = deviceFind(NULL, DEVICE_TYPE_CDROM);
145     cnt = deviceCount(devs);
146     if (!cnt) {
147         if (self)       /* Interactive? */
148             msgConfirm("No CD/DVD devices found!  Please check that your system's\n"
149                        "configuration is correct and that the CD/DVD drive is of a supported\n"
150                        "type.  For more information, consult the hardware guide\n"
151                        "in the Doc menu.");
152         return DITEM_FAILURE | DITEM_CONTINUE;
153     }
154     else if (cnt > 1) {
155         DMenu *menu;
156         int status;
157         
158         menu = deviceCreateMenu(&MenuMediaCDROM, DEVICE_TYPE_CDROM, cdromHook, NULL);
159         if (!menu)
160             msgFatal("Unable to create CDROM menu!  Something is seriously wrong.");
161         status = dmenuOpenSimple(menu, FALSE);
162         free(menu);
163         if (!status)
164             return DITEM_FAILURE;
165     }
166     else
167         mediaDevice = devs[0];
168     return (mediaDevice ? DITEM_SUCCESS | DITEM_LEAVE_MENU : DITEM_FAILURE);
169 }
170
171 static int
172 floppyHook(dialogMenuItem *self)
173 {
174     return genericHook(self, DEVICE_TYPE_FLOPPY);
175 }
176
177 /*
178  * Return 1 if we successfully found and set the installation type to
179  * be a floppy
180  */
181 int
182 mediaSetFloppy(dialogMenuItem *self)
183 {
184     Device **devs;
185     int cnt;
186
187     mediaClose();
188     devs = deviceFind(NULL, DEVICE_TYPE_FLOPPY);
189     cnt = deviceCount(devs);
190     if (!cnt) {
191         msgConfirm("No floppy devices found!  Please check that your system's configuration\n"
192                    "is correct.  For more information, consult the hardware guide in the Doc\n"
193                    "menu.");
194         return DITEM_FAILURE | DITEM_CONTINUE;
195     }
196     else if (cnt > 1) {
197         DMenu *menu;
198         int status;
199
200         menu = deviceCreateMenu(&MenuMediaFloppy, DEVICE_TYPE_FLOPPY, floppyHook, NULL);
201         if (!menu)
202             msgFatal("Unable to create Floppy menu!  Something is seriously wrong.");
203         status = dmenuOpenSimple(menu, FALSE);
204         free(menu);
205         if (!status)
206             return DITEM_FAILURE;
207     }
208     else
209         mediaDevice = devs[0];
210     if (mediaDevice)
211         mediaDevice->private = NULL;
212     return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE);
213 }
214
215 static int
216 DOSHook(dialogMenuItem *self)
217 {
218     return genericHook(self, DEVICE_TYPE_DOS);
219 }
220
221 /*
222  * Return 1 if we successfully found and set the installation type to
223  * be a DOS partition.
224  */
225 int
226 mediaSetDOS(dialogMenuItem *self)
227 {
228     Device **devs;
229     int cnt;
230
231     mediaClose();
232     devs = deviceFind(NULL, DEVICE_TYPE_DOS);
233     cnt = deviceCount(devs);
234     if (!cnt) {
235         msgConfirm("No DOS primary partitions found!  This installation method is unavailable");
236         return DITEM_FAILURE | DITEM_CONTINUE;
237     }
238     else if (cnt > 1) {
239         DMenu *menu;
240         int status;
241
242         menu = deviceCreateMenu(&MenuMediaDOS, DEVICE_TYPE_DOS, DOSHook, NULL);
243         if (!menu)
244             msgFatal("Unable to create DOS menu!  Something is seriously wrong.");
245         status = dmenuOpenSimple(menu, FALSE);
246         free(menu);
247         if (!status)
248             return DITEM_FAILURE;
249     }
250     else
251         mediaDevice = devs[0];
252     return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE);
253 }
254
255 static int
256 tapeHook(dialogMenuItem *self)
257 {
258     return genericHook(self, DEVICE_TYPE_TAPE);
259 }
260
261 /*
262  * Return 1 if we successfully found and set the installation type to
263  * be a tape drive.
264  */
265 int
266 mediaSetTape(dialogMenuItem *self)
267 {
268     Device **devs;
269     int cnt;
270
271     mediaClose();
272     devs = deviceFind(NULL, DEVICE_TYPE_TAPE);
273     cnt = deviceCount(devs);
274     if (!cnt) {
275         msgConfirm("No tape drive devices found!  Please check that your system's configuration\n"
276                    "is correct.  For more information, consult the hardware guide in the Doc\n"
277                    "menu.");
278         return DITEM_FAILURE | DITEM_CONTINUE;
279     }
280     else if (cnt > 1) {
281         DMenu *menu;
282         int status;
283
284         menu = deviceCreateMenu(&MenuMediaTape, DEVICE_TYPE_TAPE, tapeHook, NULL);
285         if (!menu)
286             msgFatal("Unable to create tape drive menu!  Something is seriously wrong.");
287         status = dmenuOpenSimple(menu, FALSE);
288         free(menu);
289         if (!status)
290             return DITEM_FAILURE;
291     }
292     else
293         mediaDevice = devs[0];
294     if (mediaDevice) {
295         char *val;
296
297         val = msgGetInput("/var/tmp", "Please enter the name of a temporary directory containing\n"
298                           "sufficient space for holding the contents of this tape (or\n"
299                           "tapes).  The contents of this directory will be removed\n"
300                           "after installation, so be sure to specify a directory that\n"
301                           "can be erased afterwards!\n");
302         if (!val)
303             mediaDevice = NULL;
304         else
305             mediaDevice->private = strdup(val);
306     }
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, 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     int 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(), "--block-size", mediaTapeBlocksize(), (char *)0);
659         else
660             i = execl(cpio, cpio, "-idum", "--block-size", mediaTapeBlocksize(), (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",
680                 USE_GZIP ? "gunzip" : "bunzip2", 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(), "--block-size", mediaTapeBlocksize(), (char *)0);
748         else
749             i = execl(cpio, cpio, "-idum", "--block-size", mediaTapeBlocksize(), (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",
797                 USE_GZIP ? "gunzip" : "bunzip2", i);
798         return FALSE;
799     }
800     i = waitpid(cpid, &j, 0);
801     if (i < 0 || WEXITSTATUS(j)) {
802         if (isDebug())
803             msgDebug("cpio returned error status of %d!\n", WEXITSTATUS(j));
804         return FALSE;
805     }
806     return TRUE;
807 }
808
809 int
810 mediaGetType(dialogMenuItem *self)
811 {
812     return ((dmenuOpenSimple(&MenuMedia, FALSE) && mediaDevice) ? DITEM_SUCCESS : DITEM_FAILURE);
813 }
814
815 /* Return TRUE if all the media variables are set up correctly */
816 Boolean
817 mediaVerify(void)
818 {
819     if (!mediaDevice)
820         return (DITEM_STATUS(mediaGetType(NULL)) == DITEM_SUCCESS);
821     return TRUE;
822 }
823
824 /* Set the FTP username and password fields */
825 int
826 mediaSetFTPUserPass(dialogMenuItem *self)
827 {
828     char *pass;
829
830     if (variable_get_value(VAR_FTP_USER, "Please enter the username you wish to login as:", 0)) {
831         DialogInputAttrs |= DITEM_NO_ECHO;
832         pass = variable_get_value(VAR_FTP_PASS, "Please enter the password for this user:", 0);
833         DialogInputAttrs &= ~DITEM_NO_ECHO;
834     }
835     else
836         pass = NULL;
837     return (pass ? DITEM_SUCCESS : DITEM_FAILURE);
838 }
839
840 /* Set CPIO verbosity level */
841 int
842 mediaSetCPIOVerbosity(dialogMenuItem *self)
843 {
844     char *cp = variable_get(VAR_CPIO_VERBOSITY);
845
846     if (!cp) {
847         msgConfirm("CPIO Verbosity is not set to anything!");
848         return DITEM_FAILURE;
849     }
850     else {
851         if (!strcmp(cp, "low"))
852             variable_set2(VAR_CPIO_VERBOSITY, "medium", 0);
853         else if (!strcmp(cp, "medium"))
854             variable_set2(VAR_CPIO_VERBOSITY, "high", 0);
855         else /* must be "high" - wrap around */
856             variable_set2(VAR_CPIO_VERBOSITY, "low", 0);
857     }
858     return DITEM_SUCCESS;
859 }
860
861 /* A generic open which follows a well-known "path" of places to look */
862 FILE *
863 mediaGenericGet(char *base, const char *file)
864 {
865     char        buf[PATH_MAX];
866
867     snprintf(buf, PATH_MAX, "%s/%s", base, file);
868     if (file_readable(buf))
869         return fopen(buf, "r");
870     snprintf(buf, PATH_MAX, "%s/FreeBSD/%s", base, file);
871     if (file_readable(buf))
872         return fopen(buf, "r");
873     snprintf(buf, PATH_MAX, "%s/releases/%s", base, file);
874     if (file_readable(buf))
875         return fopen(buf, "r");
876     snprintf(buf, PATH_MAX, "%s/%s/%s", base, variable_get(VAR_RELNAME), file);
877     if (file_readable(buf))
878         return fopen(buf, "r");
879     snprintf(buf, PATH_MAX, "%s/releases/%s/%s", base, variable_get(VAR_RELNAME), file);
880     return fopen(buf, "r");
881 }
882