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 53static Boolean got_intr = FALSE; 54static Boolean ftp_skip_resolve = FALSE; 55static Boolean http_skip_resolve = FALSE; 56 57/* timeout handler */ 58static void 59handle_intr(int sig) 60{ 61 msgDebug("User generated interrupt.\n"); 62 got_intr = TRUE; 63} 64 65static int 66check_for_interrupt(void) 67{ 68 if (got_intr) { 69 got_intr = FALSE; 70 return TRUE; 71 } 72 return FALSE; 73} 74 75static int 76genericHook(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 86static int 87cdromHook(dialogMenuItem *self) 88{ 89 return genericHook(self, DEVICE_TYPE_CDROM); 90} 91 92static void 93kickstart_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 114char * 115cpioVerbosity() 116{ 117 char *cp = variable_get(VAR_CPIO_VERBOSITY); 118 119 if (cp && !strcmp(cp, "high")) 120 return "-v"; 121 return ""; 122} 123 124int 125mediaOpen(void) 126{ 127 if (!mediaDevice || !mediaVerify() || !DEVICE_INIT(mediaDevice)) 128 return DITEM_FAILURE; 129 return DITEM_SUCCESS; 130} 131 132void 133mediaClose(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 */ 144int 145mediaSetCDROM(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 178static int 179floppyHook(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 */ 188int 189mediaSetFloppy(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 222static int 223USBHook(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 */ 232int 233mediaSetUSB(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 269static int 270DOSHook(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 */ 279int 280mediaSetDOS(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 */ 313int 314mediaSetFTP(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 446int 447mediaSetFTPActive(dialogMenuItem *self) 448{ 449 variable_set2(VAR_FTP_STATE, "active", 0); 450 return mediaSetFTP(self); 451} 452 453int 454mediaSetFTPPassive(dialogMenuItem *self) 455{ 456 variable_set2(VAR_FTP_STATE, "passive", 0); 457 return mediaSetFTP(self); 458} 459 460int 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 */ 517int 518mediaSetHTTPDirect(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 647int 648mediaSetUFS(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 675int 676mediaSetNFS(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 742Boolean 743mediaExtractDistBegin(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 803Boolean 804mediaExtractDistEnd(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 824Boolean 825mediaExtractDist(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 940int 941mediaGetType(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 */ 947Boolean 948mediaVerify(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 */ 956int 957mediaSetFTPUserPass(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 */ 972int 973mediaSetCPIOVerbosity(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 */ 991FILE * 992mediaGenericGet(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 1012