]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/sysinstall/media.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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 static Boolean http_skip_resolve = FALSE;
56
57 /* timeout handler */
58 static void
59 handle_intr(int sig)
60 {
61     msgDebug("User generated interrupt.\n");
62     got_intr = TRUE;
63 }
64
65 static int
66 check_for_interrupt(void)
67 {
68     if (got_intr) {
69         got_intr = FALSE;
70         return TRUE;
71     }
72     return FALSE;
73 }
74
75 static int
76 genericHook(dialogMenuItem *self, DeviceType type)
77 {
78     Device **devs;
79
80     devs = deviceFind(self->prompt, type);
81     if (devs)
82         mediaDevice = devs[0];
83     return (devs ? DITEM_LEAVE_MENU : DITEM_FAILURE);
84 }
85
86 static int
87 cdromHook(dialogMenuItem *self)
88 {
89     return genericHook(self, DEVICE_TYPE_CDROM);
90 }
91
92 static void
93 kickstart_dns(void)
94 {
95     static Boolean initted = FALSE;
96     int time;
97     char *cp;
98
99     cp = variable_get(VAR_MEDIA_TIMEOUT);
100     if (!cp)
101         time = MEDIA_TIMEOUT;
102     else
103         time = atoi(cp);
104     if (!time)
105         time = 100;
106     if (!initted) {
107         res_init();
108         _res.retry = 2; /* 2 times seems a reasonable number to me */
109         _res.retrans = time / 2; /* so spend half our alloted time on each try */
110         initted = TRUE;
111     }
112 }
113
114 char *
115 cpioVerbosity()
116 {
117     char *cp = variable_get(VAR_CPIO_VERBOSITY);
118
119     if (cp && !strcmp(cp, "high"))
120         return "-v";
121     return "";
122 }
123
124 int
125 mediaOpen(void)
126 {
127     if (!mediaDevice || !mediaVerify() || !DEVICE_INIT(mediaDevice))
128         return DITEM_FAILURE;
129     return DITEM_SUCCESS;
130 }
131
132 void
133 mediaClose(void)
134 {
135     if (mediaDevice)
136         DEVICE_SHUTDOWN(mediaDevice);
137     mediaDevice = NULL;
138 }
139
140 /*
141  * Return 1 if we successfully found and set the installation type to
142  * be a CD.
143  */
144 int
145 mediaSetCDROM(dialogMenuItem *self)
146 {
147     Device **devs;
148     int cnt;
149
150     mediaClose();
151     devs = deviceFind(NULL, DEVICE_TYPE_CDROM);
152     cnt = deviceCount(devs);
153     if (!cnt) {
154         if (self)       /* Interactive? */
155             msgConfirm("No CD/DVD devices found!  Please check that your system's\n"
156                        "configuration is correct and that the CD/DVD drive is of a supported\n"
157                        "type.  For more information, consult the hardware guide\n"
158                        "in the Doc menu.");
159         return DITEM_FAILURE | DITEM_CONTINUE;
160     }
161     else if (cnt > 1) {
162         DMenu *menu;
163         int status;
164         
165         menu = deviceCreateMenu(&MenuMediaCDROM, DEVICE_TYPE_CDROM, cdromHook, NULL);
166         if (!menu)
167             msgFatal("Unable to create CDROM menu!  Something is seriously wrong.");
168         status = dmenuOpenSimple(menu, FALSE);
169         free(menu);
170         if (!status)
171             return DITEM_FAILURE;
172     }
173     else
174         mediaDevice = devs[0];
175     return (mediaDevice ? DITEM_SUCCESS | DITEM_LEAVE_MENU : DITEM_FAILURE);
176 }
177
178 static int
179 floppyHook(dialogMenuItem *self)
180 {
181     return genericHook(self, DEVICE_TYPE_FLOPPY);
182 }
183
184 /*
185  * Return 1 if we successfully found and set the installation type to
186  * be a floppy
187  */
188 int
189 mediaSetFloppy(dialogMenuItem *self)
190 {
191     Device **devs;
192     int cnt;
193
194     mediaClose();
195     devs = deviceFind(NULL, DEVICE_TYPE_FLOPPY);
196     cnt = deviceCount(devs);
197     if (!cnt) {
198         msgConfirm("No floppy devices found!  Please check that your system's configuration\n"
199                    "is correct.  For more information, consult the hardware guide in the Doc\n"
200                    "menu.");
201         return DITEM_FAILURE | DITEM_CONTINUE;
202     }
203     else if (cnt > 1) {
204         DMenu *menu;
205         int status;
206
207         menu = deviceCreateMenu(&MenuMediaFloppy, DEVICE_TYPE_FLOPPY, floppyHook, NULL);
208         if (!menu)
209             msgFatal("Unable to create Floppy menu!  Something is seriously wrong.");
210         status = dmenuOpenSimple(menu, FALSE);
211         free(menu);
212         if (!status)
213             return DITEM_FAILURE;
214     }
215     else
216         mediaDevice = devs[0];
217     if (mediaDevice)
218         mediaDevice->private = NULL;
219     return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE);
220 }
221
222 static int
223 USBHook(dialogMenuItem *self)
224 {
225         return genericHook(self, DEVICE_TYPE_USB);
226 }
227
228
229 /*
230  * Attempt to use USB as the installation media type.
231  */
232 int
233 mediaSetUSB(dialogMenuItem *self)
234 {
235         Device **devs;
236         int cnt;
237
238         mediaClose();
239         devs = deviceFind(NULL, DEVICE_TYPE_USB);
240         cnt = deviceCount(devs);
241
242         if (!cnt) {
243                 msgConfirm("No USB devices found (try Options/Re-scan Devices)");
244                 return DITEM_FAILURE | DITEM_CONTINUE;
245         }
246         else if (cnt > 1) {
247                 DMenu *menu;
248                 int status;
249
250                 menu = deviceCreateMenu(&MenuMediaUSB, DEVICE_TYPE_USB, USBHook,
251                     NULL);
252                 if (!menu)
253                         msgFatal("Unable to create USB menu! Something is " \
254                             "seriously wrong.");
255                 status = dmenuOpenSimple(menu, FALSE);
256                 free(menu);
257                 if (!status)
258                         return DITEM_FAILURE;
259         }
260         else
261                 mediaDevice = devs[0];
262         if (mediaDevice)
263                 mediaDevice->private = NULL;
264         if (!variable_get(VAR_NONINTERACTIVE))
265                 msgConfirm("Using USB device: %s", mediaDevice->name);
266         return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE);
267 }
268
269 static int
270 DOSHook(dialogMenuItem *self)
271 {
272     return genericHook(self, DEVICE_TYPE_DOS);
273 }
274
275 /*
276  * Return 1 if we successfully found and set the installation type to
277  * be a DOS partition.
278  */
279 int
280 mediaSetDOS(dialogMenuItem *self)
281 {
282     Device **devs;
283     int cnt;
284
285     mediaClose();
286     devs = deviceFind(NULL, DEVICE_TYPE_DOS);
287     cnt = deviceCount(devs);
288     if (!cnt) {
289         msgConfirm("No DOS primary partitions found!  This installation method is unavailable");
290         return DITEM_FAILURE | DITEM_CONTINUE;
291     }
292     else if (cnt > 1) {
293         DMenu *menu;
294         int status;
295
296         menu = deviceCreateMenu(&MenuMediaDOS, DEVICE_TYPE_DOS, DOSHook, NULL);
297         if (!menu)
298             msgFatal("Unable to create DOS menu!  Something is seriously wrong.");
299         status = dmenuOpenSimple(menu, FALSE);
300         free(menu);
301         if (!status)
302             return DITEM_FAILURE;
303     }
304     else
305         mediaDevice = devs[0];
306     return (mediaDevice ? DITEM_LEAVE_MENU : DITEM_FAILURE);
307 }
308
309 /*
310  * Return 0 if we successfully found and set the installation type to
311  * be an ftp server
312  */
313 int
314 mediaSetFTP(dialogMenuItem *self)
315 {
316     static Device ftpDevice;
317     char *cp, hbuf[MAXHOSTNAMELEN], *hostname, *dir;
318     struct addrinfo hints, *res;
319     int af;
320     size_t urllen;
321     extern int FtpPort;
322     static Device *networkDev = NULL;
323
324     mediaClose();
325     cp = variable_get(VAR_FTP_PATH);
326     /* If we've been through here before ... */
327     if (networkDev && cp && msgYesNo("Re-use old FTP site selection values?"))
328         cp = NULL;
329     if (!cp) {
330         if (!dmenuOpenSimple(&MenuMediaFTP, FALSE))
331             return DITEM_FAILURE;
332         else
333             cp = variable_get(VAR_FTP_PATH);
334     }
335     if (!cp)
336         return DITEM_FAILURE;
337     else if (!strcmp(cp, "other")) {
338         variable_set2(VAR_FTP_PATH, "ftp://", 0);
339         cp = variable_get_value(VAR_FTP_PATH, "Please specify the URL of a FreeBSD distribution on a\n"
340                                 "remote ftp site.  This site must accept either anonymous\n"
341                                 "ftp or you should have set an ftp username and password\n"
342                                 "in the Options screen.\n\n"
343                                 "A URL looks like this:  ftp://<hostname>/<path>\n"
344                                 "Where <path> is relative to the anonymous ftp directory or the\n"
345                                 "home directory of the user being logged in as.", 0);
346         if (!cp || !*cp || !strcmp(cp, "ftp://")) {
347             variable_unset(VAR_FTP_PATH);
348             return DITEM_FAILURE;
349         }
350         urllen = strlen(cp);
351         if (urllen >= sizeof(ftpDevice.name)) {
352             msgConfirm("Length of specified URL is %zu characters. Allowable maximum is %zu.",
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  * Return 0 if we successfully found and set the installation type to
515  * be an http server
516  */
517 int
518 mediaSetHTTPDirect(dialogMenuItem *self)
519 {
520     static Device httpDevice;
521     char *cp, hbuf[MAXPATHLEN], *hostname, *dir;
522     struct addrinfo hints, *res;
523     int af;
524     size_t urllen;
525     int HttpPort;
526     static Device *networkDev = NULL;
527
528     mediaClose();
529     cp = variable_get(VAR_HTTP_PATH);
530     /* If we've been through here before ... */
531     if (networkDev && cp && msgYesNo("Re-use old HTTP site selection values?"))
532         cp = NULL;
533     if (!cp) {
534         if (!dmenuOpenSimple(&MenuMediaHTTPDirect, FALSE))
535             return DITEM_FAILURE;
536         else
537             cp = variable_get(VAR_HTTP_PATH);
538     }
539     if (!cp)
540         return DITEM_FAILURE;
541     else if (!strcmp(cp, "other")) {
542         variable_set2(VAR_HTTP_PATH, "http://", 0);
543         cp = variable_get_value(VAR_HTTP_PATH, "Please specify the URL of a FreeBSD distribution on a\n"
544                                 "remote http site.\n"
545                                 "A URL looks like this:  http://<hostname>/<path>", 0);
546         if (!cp || !*cp || !strcmp(cp, "http://")) {
547             variable_unset(VAR_HTTP_PATH);
548             return DITEM_FAILURE;
549         }
550         urllen = strlen(cp);
551         if (urllen >= sizeof(httpDevice.name)) {
552             msgConfirm("Length of specified URL is %zu characters. Allowable maximum is %zu.",
553                         urllen,sizeof(httpDevice.name)-1);
554             variable_unset(VAR_HTTP_PATH);
555             return DITEM_FAILURE;
556         }
557     }
558     if (strncmp("http://", cp, 7)) {
559         msgConfirm("Sorry, %s is an invalid URL!", cp);
560         variable_unset(VAR_HTTP_PATH);
561         return DITEM_FAILURE;
562     }
563     SAFE_STRCPY(httpDevice.name, cp);
564     SAFE_STRCPY(hbuf, cp + 7);
565     hostname = hbuf;
566
567     if (!networkDev || msgYesNo("You've already done the network configuration once,\n"
568                                 "would you like to skip over it now?") != 0) {
569         if (networkDev)
570             DEVICE_SHUTDOWN(networkDev);
571         if (!(networkDev = tcpDeviceSelect())) {
572             variable_unset(VAR_HTTP_PATH);
573             return DITEM_FAILURE;
574         }
575     }
576     if (!DEVICE_INIT(networkDev)) {
577         if (isDebug())
578             msgDebug("mediaSetHTTPDirect: Net device init failed.\n");
579         variable_unset(VAR_HTTP_PATH);
580         return DITEM_FAILURE;
581     }
582     if (*hostname == '[' && (cp = index(hostname + 1, ']')) != NULL &&
583         (*++cp == '\0' || *cp == '/' || *cp == ':')) {
584         ++hostname;
585         *(cp - 1) = '\0';
586     }
587     else
588         cp = index(hostname, ':');
589     if (cp != NULL && *cp == ':') {
590         *(cp++) = '\0';
591         HttpPort = strtol(cp, 0, 0);
592     }
593     else
594         HttpPort = 80;
595     if ((dir = index(cp ? cp : hostname, '/')) != NULL)
596         *(dir++) = '\0';
597     if (isDebug()) {
598         msgDebug("hostname = `%s'\n", hostname);
599         msgDebug("dir = `%s'\n", dir ? dir : "/");
600         msgDebug("port # = `%d'\n", HttpPort);
601     }
602     if (!http_skip_resolve && variable_get(VAR_NAMESERVER)) {
603         msgNotify("Looking up host %s.", hostname);
604         if (isDebug())
605             msgDebug("Starting DNS.\n");
606         kickstart_dns();
607         if (isDebug())
608             msgDebug("Looking up hostname, %s, using getaddrinfo(AI_NUMERICHOST).\n", hostname);
609         af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
610         memset(&hints, 0, sizeof(hints));
611         hints.ai_family = af;
612         hints.ai_socktype = SOCK_STREAM;
613         hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
614         if (getaddrinfo(hostname, NULL, &hints, &res) != 0) {
615             if (isDebug())
616                 msgDebug("Looking up hostname, %s, using getaddrinfo().\n",
617                          hostname);
618             hints.ai_flags = AI_PASSIVE;
619             if (getaddrinfo(hostname, NULL, &hints, &res) != 0) {
620                 msgConfirm("Cannot resolve hostname `%s'!  Are you sure that"
621                         " your\nname server, gateway and network interface are"
622                         " correctly configured?", hostname);
623                 if (networkDev)
624                     DEVICE_SHUTDOWN(networkDev);
625                 networkDev = NULL;
626                 variable_unset(VAR_HTTP_PATH);
627                 return DITEM_FAILURE;
628             }
629         }
630         freeaddrinfo(res);
631         if (isDebug())
632             msgDebug("Found DNS entry for %s successfully..\n", hostname);
633     }
634     variable_set2(VAR_HTTP_HOST, hostname, 0);
635     variable_set2(VAR_HTTP_DIR, dir ? dir : "/", 0);
636     variable_set2(VAR_HTTP_PORT, itoa(HttpPort), 0);
637     httpDevice.type = DEVICE_TYPE_HTTP_DIRECT;
638     httpDevice.init = mediaInitHTTPDirect;
639     httpDevice.get = mediaGetHTTPDirect;
640     httpDevice.shutdown = dummyShutdown;
641     httpDevice.private = networkDev;
642     mediaDevice = &httpDevice;
643     return DITEM_SUCCESS | DITEM_LEAVE_MENU | DITEM_RESTORE;
644 }
645    
646
647 int
648 mediaSetUFS(dialogMenuItem *self)
649 {
650     static Device ufsDevice;
651     struct statfs st;
652     char *cp;
653
654     mediaClose();
655     cp = variable_get_value(VAR_UFS_PATH, "Enter a fully qualified pathname for the directory\n"
656                             "containing the FreeBSD distribution files:", 0);
657     if (!cp)
658         return DITEM_FAILURE;
659
660     /* If they gave us a CDROM or something, try and pick a better name */
661     if (statfs(cp, &st))
662         strcpy(ufsDevice.name, "ufs");
663     else
664         strcpy(ufsDevice.name, st.f_fstypename);
665
666     ufsDevice.type = DEVICE_TYPE_UFS;
667     ufsDevice.init = dummyInit;
668     ufsDevice.get = mediaGetUFS;
669     ufsDevice.shutdown = dummyShutdown;
670     ufsDevice.private = strdup(cp);
671     mediaDevice = &ufsDevice;
672     return DITEM_LEAVE_MENU;
673 }
674
675 int
676 mediaSetNFS(dialogMenuItem *self)
677 {
678     static Device nfsDevice;
679     static Device *networkDev = NULL;
680     char *cp, *idx;
681     char hostname[MAXPATHLEN];
682     size_t pathlen;
683
684     mediaClose();
685     cp = variable_get_value(VAR_NFS_PATH, "Please enter the full NFS file specification for the remote\n"
686                             "host and directory containing the FreeBSD distribution files.\n"
687                             "This should be in the format:  hostname:/some/freebsd/dir", 0);
688     if (!cp)
689         return DITEM_FAILURE;
690     SAFE_STRCPY(hostname, cp);
691     if (!(idx = index(hostname, ':'))) {
692         msgConfirm("Invalid NFS path specification.  Must be of the form:\n"
693                    "host:/full/pathname/to/FreeBSD/distdir");
694         return DITEM_FAILURE;
695     }
696     pathlen = strlen(hostname);
697     if (pathlen >= sizeof(nfsDevice.name)) {
698         msgConfirm("Length of specified NFS path is %zu characters. Allowable maximum is %zu.",
699                    pathlen,sizeof(nfsDevice.name)-1);
700         variable_unset(VAR_NFS_PATH);
701         return DITEM_FAILURE;
702     }
703     SAFE_STRCPY(nfsDevice.name, hostname);
704     *idx = '\0';
705     if (!networkDev || msgYesNo("You've already done the network configuration once,\n"
706                                 "would you like to skip over it now?") != 0) {
707         if (networkDev)
708             DEVICE_SHUTDOWN(networkDev);
709         if (!(networkDev = tcpDeviceSelect()))
710             return DITEM_FAILURE;
711     }
712     if (!DEVICE_INIT(networkDev)) {
713         if (isDebug())
714             msgDebug("mediaSetNFS: Net device init failed\n");
715     }
716     if (variable_get(VAR_NAMESERVER)) {
717         kickstart_dns();
718         if ((inet_addr(hostname) == INADDR_NONE) && (gethostbyname(hostname) == NULL)) {
719             msgConfirm("Cannot resolve hostname `%s'!  Are you sure that your\n"
720                        "name server, gateway and network interface are correctly configured?", hostname);
721             if (networkDev)
722                 DEVICE_SHUTDOWN(networkDev);
723             networkDev = NULL;
724             variable_unset(VAR_NFS_PATH);
725             return DITEM_FAILURE;
726         }
727         else {
728             if (isDebug())
729                 msgDebug("Found DNS entry for %s successfully..\n", hostname);
730         }
731     }
732     variable_set2(VAR_NFS_HOST, hostname, 0);
733     nfsDevice.type = DEVICE_TYPE_NFS;
734     nfsDevice.init = mediaInitNFS;
735     nfsDevice.get = mediaGetNFS;
736     nfsDevice.shutdown = mediaShutdownNFS;
737     nfsDevice.private = networkDev;
738     mediaDevice = &nfsDevice;
739     return DITEM_LEAVE_MENU;
740 }
741
742 Boolean
743 mediaExtractDistBegin(char *dir, int *fd, int *zpid, int *cpid)
744 {
745     int i, pfd[2],qfd[2];
746
747     if (!dir)
748         dir = "/";
749     Mkdir(dir);
750     chdir(dir);
751     pipe(pfd);
752     pipe(qfd);
753     *zpid = fork();
754     if (!*zpid) {
755         char *unzipper = RunningAsInit ? "/stand/" UNZIPPER
756             : "/usr/bin/" UNZIPPER;
757
758         dup2(qfd[0], 0); close(qfd[0]);
759         dup2(pfd[1], 1); close(pfd[1]);
760         if (DebugFD != -1)
761             dup2(DebugFD, 2);
762         else {
763             close(2);
764             open("/dev/null", O_WRONLY);
765         }
766         close(qfd[1]);
767         close(pfd[0]);
768         i = execl(unzipper, unzipper, (char *)0);
769         if (isDebug())
770             msgDebug("%s command returns %d status\n", unzipper, i);
771         exit(i);
772     }
773     *fd = qfd[1];
774     close(qfd[0]);
775     *cpid = fork();
776     if (!*cpid) {
777         char *cpio = RunningAsInit ? "/stand/cpio" : "/usr/bin/cpio";
778
779         dup2(pfd[0], 0); close(pfd[0]);
780         close(pfd[1]);
781         close(qfd[1]);
782         if (DebugFD != -1) {
783             dup2(DebugFD, 1);
784             dup2(DebugFD, 2);
785         }
786         else {
787             close(1); open("/dev/null", O_WRONLY);
788             dup2(1, 2);
789         }
790         if (strlen(cpioVerbosity()))
791             i = execl(cpio, cpio, "-idum", cpioVerbosity(), (char *)0);
792         else
793             i = execl(cpio, cpio, "-idum", (char *)0);
794         if (isDebug())
795             msgDebug("%s command returns %d status\n", cpio, i);
796         exit(i);
797     }
798     close(pfd[0]);
799     close(pfd[1]);
800     return TRUE;
801 }
802
803 Boolean
804 mediaExtractDistEnd(int zpid, int cpid)
805 {
806     int i,j;
807
808     i = waitpid(zpid, &j, 0);
809     /* Don't check exit status - gunzip seems to return a bogus one! */
810     if (i < 0) {
811         if (isDebug())
812             msgDebug("wait for %s returned status of %d!\n", UNZIPPER, i);
813         return FALSE;
814     }
815     i = waitpid(cpid, &j, 0);
816     if (i < 0 || WEXITSTATUS(j)) {
817         if (isDebug())
818             msgDebug("cpio returned error status of %d!\n", WEXITSTATUS(j));
819         return FALSE;
820     }
821     return TRUE;
822 }
823
824 Boolean
825 mediaExtractDist(char *dir, char *dist, FILE *fp)
826 {
827     int i, j, total, seconds, zpid, cpid, pfd[2], qfd[2];
828     char buf[BUFSIZ];
829     struct timeval start, stop;
830     struct sigaction new, old;
831
832     if (!dir)
833         dir = "/";
834
835     Mkdir(dir);
836     chdir(dir);
837     pipe(pfd);  /* read end */
838     pipe(qfd);  /* write end */
839     zpid = fork();
840     if (!zpid) {
841         char *unzipper = RunningAsInit ? "/stand/" UNZIPPER
842             : "/usr/bin/" UNZIPPER;
843
844         fclose(fp);
845         close(qfd[1]);
846         dup2(qfd[0], 0); close(qfd[0]);
847
848         close(pfd[0]); 
849         dup2(pfd[1], 1); close(pfd[1]);
850
851         if (DebugFD != -1)
852             dup2(DebugFD, 2);
853         else {
854             close(2);
855             open("/dev/null", O_WRONLY);
856         }
857         i = execl(unzipper, unzipper, (char *)0);
858         if (isDebug())
859             msgDebug("%s command returns %d status\n", unzipper, i);
860         exit(i);
861     }
862     cpid = fork();
863     if (!cpid) {
864         char *cpio = RunningAsInit ? "/stand/cpio" : "/usr/bin/cpio";
865
866         close(pfd[1]);
867         dup2(pfd[0], 0); close(pfd[0]);
868         close (qfd[0]); close(qfd[1]);
869         fclose(fp);
870         if (DebugFD != -1) {
871             dup2(DebugFD, 1);
872             dup2(DebugFD, 2);
873         }
874         else {
875             dup2(open("/dev/null", O_WRONLY), 1);
876             dup2(1, 2);
877         }
878         if (strlen(cpioVerbosity()))
879             i = execl(cpio, cpio, "-idum", cpioVerbosity(), (char *)0);
880         else
881             i = execl(cpio, cpio, "-idum", "--block-size", (char *)0);
882         if (isDebug())
883             msgDebug("%s command returns %d status\n", cpio, i);
884         exit(i);
885     }
886     close(pfd[0]); close(pfd[1]);
887     close(qfd[0]);
888
889     total = 0;
890     (void)gettimeofday(&start, (struct timezone *)0);
891
892     /* Make ^C abort the current transfer rather than the whole show */
893     new.sa_handler = handle_intr;
894     new.sa_flags = 0;
895     (void)sigemptyset(&new.sa_mask);
896     sigaction(SIGINT, &new, &old);
897
898     while ((i = fread(buf, 1, BUFSIZ, fp)) > 0) {
899         if (check_for_interrupt()) {
900             msgConfirm("Failure to read from media:  User interrupt.");
901             break;
902         }
903         if (write(qfd[1], buf, i) != i) {
904             msgConfirm("Write error on transfer to cpio process, try of %d bytes.", i);
905             break;
906         }
907         else {
908             (void)gettimeofday(&stop, (struct timezone *)0);
909             stop.tv_sec = stop.tv_sec - start.tv_sec;
910             stop.tv_usec = stop.tv_usec - start.tv_usec;
911             if (stop.tv_usec < 0)
912                 stop.tv_sec--, stop.tv_usec += 1000000;
913             seconds = stop.tv_sec + (stop.tv_usec / 1000000.0);
914             if (!seconds)
915                 seconds = 1;
916             total += i;
917             msgInfo("%10d bytes read from %s dist @ %.1f KB/sec.",
918                     total, dist, (total / seconds) / 1024.0);
919         }
920     }
921     sigaction(SIGINT, &old, NULL);      /* restore sigint */
922     close(qfd[1]);
923
924     i = waitpid(zpid, &j, 0);
925     /* Don't check exit status - gunzip seems to return a bogus one! */
926     if (i < 0) {
927         if (isDebug())
928             msgDebug("wait for %s returned status of %d!\n", UNZIPPER, i);
929         return FALSE;
930     }
931     i = waitpid(cpid, &j, 0);
932     if (i < 0 || WEXITSTATUS(j)) {
933         if (isDebug())
934             msgDebug("cpio returned error status of %d!\n", WEXITSTATUS(j));
935         return FALSE;
936     }
937     return TRUE;
938 }
939
940 int
941 mediaGetType(dialogMenuItem *self)
942 {
943     return ((dmenuOpenSimple(&MenuMedia, FALSE) && mediaDevice) ? DITEM_SUCCESS : DITEM_FAILURE);
944 }
945
946 /* Return TRUE if all the media variables are set up correctly */
947 Boolean
948 mediaVerify(void)
949 {
950     if (!mediaDevice)
951         return (DITEM_STATUS(mediaGetType(NULL)) == DITEM_SUCCESS);
952     return TRUE;
953 }
954
955 /* Set the FTP username and password fields */
956 int
957 mediaSetFTPUserPass(dialogMenuItem *self)
958 {
959     char *pass;
960
961     if (variable_get_value(VAR_FTP_USER, "Please enter the username you wish to login as:", 0)) {
962         DialogInputAttrs |= DITEM_NO_ECHO;
963         pass = variable_get_value(VAR_FTP_PASS, "Please enter the password for this user:", 0);
964         DialogInputAttrs &= ~DITEM_NO_ECHO;
965     }
966     else
967         pass = NULL;
968     return (pass ? DITEM_SUCCESS : DITEM_FAILURE);
969 }
970
971 /* Set CPIO verbosity level */
972 int
973 mediaSetCPIOVerbosity(dialogMenuItem *self)
974 {
975     char *cp = variable_get(VAR_CPIO_VERBOSITY);
976
977     if (!cp) {
978         msgConfirm("CPIO Verbosity is not set to anything!");
979         return DITEM_FAILURE;
980     }
981     else {
982         if (!strcmp(cp, "low"))
983             variable_set2(VAR_CPIO_VERBOSITY, "high", 0);
984         else /* must be "high" - wrap around */
985             variable_set2(VAR_CPIO_VERBOSITY, "low", 0);
986     }
987     return DITEM_SUCCESS;
988 }
989
990 /* A generic open which follows a well-known "path" of places to look */
991 FILE *
992 mediaGenericGet(char *base, const char *file)
993 {
994     char        buf[PATH_MAX];
995
996     snprintf(buf, PATH_MAX, "%s/%s", base, file);
997     if (file_readable(buf))
998         return fopen(buf, "r");
999     snprintf(buf, PATH_MAX, "%s/FreeBSD/%s", base, file);
1000     if (file_readable(buf))
1001         return fopen(buf, "r");
1002     snprintf(buf, PATH_MAX, "%s/releases/%s", base, file);
1003     if (file_readable(buf))
1004         return fopen(buf, "r");
1005     snprintf(buf, PATH_MAX, "%s/%s/%s", base, variable_get(VAR_RELNAME), file);
1006     if (file_readable(buf))
1007         return fopen(buf, "r");
1008     snprintf(buf, PATH_MAX, "%s/releases/%s/%s", base, variable_get(VAR_RELNAME), file);
1009     return fopen(buf, "r");
1010 }
1011