install.c revision 40299
1/* 2 * The new sysinstall program. 3 * 4 * This is probably the last program in the `sysinstall' line - the next 5 * generation being essentially a complete rewrite. 6 * 7 * $Id: install.c,v 1.215 1998/10/12 23:47:50 jkh Exp $ 8 * 9 * Copyright (c) 1995 10 * Jordan Hubbard. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer, 17 * verbatim and that no modifications are made prior to this 18 * point in the file. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37#include "sysinstall.h" 38#include "uc_main.h" 39#include <ctype.h> 40#include <sys/disklabel.h> 41#include <sys/errno.h> 42#include <sys/ioctl.h> 43#include <sys/fcntl.h> 44#include <sys/wait.h> 45#include <sys/param.h> 46#define MSDOSFS 47#include <sys/mount.h> 48#include <ufs/ufs/ufsmount.h> 49#include <msdosfs/msdosfsmount.h> 50#undef MSDOSFS 51#include <sys/stat.h> 52#include <unistd.h> 53 54static void create_termcap(void); 55static void fixit_common(void); 56#ifdef SAVE_USERCONFIG 57static void save_userconfig_to_kernel(char *); 58#endif 59 60#define TERMCAP_FILE "/usr/share/misc/termcap" 61 62static void installConfigure(void); 63 64Boolean 65checkLabels(Boolean whinge, Chunk **rdev, Chunk **sdev, Chunk **udev, Chunk **vdev) 66{ 67 Device **devs; 68 Boolean status; 69 Disk *disk; 70 Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; 71 int i; 72 73 /* Don't allow whinging if noWarn is set */ 74 if (variable_get(VAR_NO_WARN)) 75 whinge = FALSE; 76 77 status = TRUE; 78 *rdev = *sdev = *udev = *vdev = rootdev = swapdev = usrdev = vardev = NULL; 79 80 /* We don't need to worry about root/usr/swap if we're already multiuser */ 81 if (!RunningAsInit) 82 return status; 83 84 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 85 /* First verify that we have a root device */ 86 for (i = 0; devs[i]; i++) { 87 if (!devs[i]->enabled) 88 continue; 89 disk = (Disk *)devs[i]->private; 90 msgDebug("Scanning disk %s for root filesystem\n", disk->name); 91 if (!disk->chunks) 92 msgFatal("No chunk list found for %s!", disk->name); 93 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 94 if (c1->type == freebsd) { 95 for (c2 = c1->part; c2; c2 = c2->next) { 96 if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { 97 if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/")) { 98 if (rootdev) { 99 if (whinge) 100 msgConfirm("WARNING: You have more than one root device set?!\n" 101 "Using the first one found."); 102 continue; 103 } 104 else { 105 rootdev = c2; 106 if (isDebug()) 107 msgDebug("Found rootdev at %s!\n", rootdev->name); 108 } 109 } 110 else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/usr")) { 111 if (usrdev) { 112 if (whinge) 113 msgConfirm("WARNING: You have more than one /usr filesystem.\n" 114 "Using the first one found."); 115 continue; 116 } 117 else { 118 usrdev = c2; 119 if (isDebug()) 120 msgDebug("Found usrdev at %s!\n", usrdev->name); 121 } 122 } 123 else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/var")) { 124 if (vardev) { 125 if (whinge) 126 msgConfirm("WARNING: You have more than one /var filesystem.\n" 127 "Using the first one found."); 128 continue; 129 } 130 else { 131 vardev = c2; 132 if (isDebug()) 133 msgDebug("Found vardev at %s!\n", vardev->name); 134 } 135 } 136 } 137 } 138 } 139 } 140 } 141 142 /* Now check for swap devices */ 143 for (i = 0; devs[i]; i++) { 144 if (!devs[i]->enabled) 145 continue; 146 disk = (Disk *)devs[i]->private; 147 msgDebug("Scanning disk %s for swap partitions\n", disk->name); 148 if (!disk->chunks) 149 msgFatal("No chunk list found for %s!", disk->name); 150 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 151 if (c1->type == freebsd) { 152 for (c2 = c1->part; c2; c2 = c2->next) { 153 if (c2->type == part && c2->subtype == FS_SWAP && !swapdev) { 154 swapdev = c2; 155 if (isDebug()) 156 msgDebug("Found swapdev at %s!\n", swapdev->name); 157 break; 158 } 159 } 160 } 161 } 162 } 163 164 /* Copy our values over */ 165 *rdev = rootdev; 166 *sdev = swapdev; 167 *udev = usrdev; 168 *vdev = vardev; 169 170 if (!rootdev && whinge) { 171 msgConfirm("No root device found - you must label a partition as /\n" 172 "in the label editor."); 173 status = FALSE; 174 } 175 if (!swapdev && whinge) { 176 msgConfirm("No swap devices found - you must create at least one\n" 177 "swap partition."); 178 status = FALSE; 179 } 180 if (!usrdev && whinge && !variable_get(VAR_NO_USR)) { 181 msgConfirm("WARNING: No /usr filesystem found. This is not technically\n" 182 "an error if your root filesystem is big enough (or you later\n" 183 "intend to mount your /usr filesystem over NFS), but it may otherwise\n" 184 "cause you trouble if you're not exactly sure what you are doing!"); 185 } 186 if (!vardev && whinge && variable_cmp(SYSTEM_STATE, "upgrade")) { 187 msgConfirm("WARNING: No /var filesystem found. This is not technically\n" 188 "an error if your root filesystem is big enough (or you later\n" 189 "intend to link /var to someplace else), but it may otherwise\n" 190 "cause your root filesystem to fill up if you receive lots of mail\n" 191 "or edit large temporary files."); 192 } 193 return status; 194} 195 196static int 197installInitial(void) 198{ 199 static Boolean alreadyDone = FALSE; 200 201 if (alreadyDone) 202 return DITEM_SUCCESS; 203 204 if (!variable_get(DISK_LABELLED)) { 205 msgConfirm("You need to assign disk labels before you can proceed with\n" 206 "the installation."); 207 return DITEM_FAILURE; 208 } 209 /* If it's labelled, assume it's also partitioned */ 210 if (!variable_get(DISK_PARTITIONED)) 211 variable_set2(DISK_PARTITIONED, "yes"); 212 213 /* If we refuse to proceed, bail. */ 214 dialog_clear_norefresh(); 215 if (!variable_get(VAR_NO_WARN)) 216 if (msgYesNo( 217 "Last Chance! Are you SURE you want continue the installation?\n\n" 218 "If you're running this on a disk with data you wish to save\n" 219 "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n" 220 "proceeding!\n\n" 221 "We can take no responsibility for lost disk contents!") != 0) 222 return DITEM_FAILURE | DITEM_RESTORE; 223 224 if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) { 225 msgConfirm("Couldn't make filesystems properly. Aborting."); 226 return DITEM_FAILURE; 227 } 228 229 if (!copySelf()) { 230 msgConfirm("installInitial: Couldn't clone the boot floppy onto the\n" 231 "root file system. Aborting!"); 232 return DITEM_FAILURE; 233 } 234 235 if (chroot("/mnt") == -1) { 236 msgConfirm("installInitial: Unable to chroot to %s - this is bad!", 237 "/mnt"); 238 return DITEM_FAILURE; 239 } 240 241 chdir("/"); 242 variable_set2(RUNNING_ON_ROOT, "yes"); 243 configResolv(); 244 245 /* stick a helpful shell over on the 4th VTY */ 246 systemCreateHoloshell(); 247 248 alreadyDone = TRUE; 249 return DITEM_SUCCESS; 250} 251 252int 253installFixitHoloShell(dialogMenuItem *self) 254{ 255 systemCreateHoloshell(); 256 return DITEM_SUCCESS; 257} 258 259int 260installFixitCDROM(dialogMenuItem *self) 261{ 262 struct stat sb; 263 264 if (!RunningAsInit) 265 return DITEM_SUCCESS; 266 267 variable_set2(SYSTEM_STATE, "fixit"); 268 (void)unlink("/mnt2"); 269 (void)rmdir("/mnt2"); 270 271 while (1) { 272 msgConfirm("Please insert the second FreeBSD CDROM and press return"); 273 if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS || !mediaDevice || !mediaDevice->init(mediaDevice)) { 274 /* If we can't initialize it, it's probably not a FreeBSD CDROM so punt on it */ 275 if (mediaDevice) { 276 mediaDevice->shutdown(mediaDevice); 277 mediaDevice = NULL; 278 } 279 if (msgYesNo("Unable to mount the CDROM - do you want to try again?") != 0) 280 return DITEM_FAILURE; 281 } 282 else 283 break; 284 } 285 286 /* Since the fixit code expects everything to be in /mnt2, and the CDROM mounting stuff /dist, do 287 * a little kludge dance here.. 288 */ 289 if (symlink("/dist", "/mnt2")) { 290 msgConfirm("Unable to symlink /mnt2 to the CDROM mount point. Please report this\n" 291 "unexpected failure to freebsd-bugs@FreeBSD.org."); 292 return DITEM_FAILURE; 293 } 294 295 /* 296 * If /tmp points to /mnt2/tmp from a previous fixit floppy session, it's 297 * not very good for us if we point it to the CDROM now. Rather make it 298 * a directory in the root MFS then. Experienced admins will still be 299 * able to mount their disk's /tmp over this if they need. 300 */ 301 if (lstat("/tmp", &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFLNK) 302 (void)unlink("/tmp"); 303 Mkdir("/tmp"); 304 305 /* 306 * Since setuid binaries ignore LD_LIBRARY_PATH, we indeed need the 307 * ld.so.hints file. Fortunately, it's fairly small (~ 3 KB). 308 */ 309 if (!file_readable("/var/run/ld.so.hints")) { 310 Mkdir("/var/run"); 311 if (vsystem("/mnt2/sbin/ldconfig -s /mnt2/usr/lib")) { 312 msgConfirm("Warning: ldconfig could not create the ld.so hints file.\n" 313 "Dynamic executables from the CDROM likely won't work."); 314 } 315 } 316 317 /* Yet another iggly hardcoded pathname. */ 318 if (!file_readable("/usr/libexec/ld.so")) { 319 Mkdir("/usr/libexec"); 320 if (symlink("/mnt2/usr/libexec/ld.so", "/usr/libexec/ld.so")) { 321 msgConfirm("Warning: could not create the symlink for ld.so.\n" 322 "Dynamic executables from the CDROM likely won't work."); 323 } 324 } 325 326 fixit_common(); 327 328 mediaDevice->shutdown(mediaDevice); 329 msgConfirm("Please remove the FreeBSD CDROM now."); 330 return DITEM_SUCCESS; 331} 332 333int 334installFixitFloppy(dialogMenuItem *self) 335{ 336 struct ufs_args args; 337 338 if (!RunningAsInit) 339 return DITEM_SUCCESS; 340 341 variable_set2(SYSTEM_STATE, "fixit"); 342 Mkdir("/mnt2"); 343 344 /* Try to open the floppy drive */ 345 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) { 346 msgConfirm("Unable to set media device to floppy."); 347 mediaClose(); 348 return DITEM_FAILURE; 349 } 350 351 memset(&args, 0, sizeof(args)); 352 args.fspec = mediaDevice->devname; 353 354 while (1) { 355 msgConfirm("Please insert a writable fixit floppy and press return"); 356 mediaDevice->private = "/mnt2"; 357 if (!mediaDevice->init(mediaDevice)) { 358 if (msgYesNo("The attempt to mount the fixit floppy failed, bad floppy\n" 359 "or unclean filesystem. Do you want to try again?")) 360 return DITEM_FAILURE; 361 } 362 } 363 if (!directory_exists("/tmp")) 364 (void)symlink("/mnt2/tmp", "/tmp"); 365 fixit_common(); 366 mediaDevice->shutdown(mediaDevice); 367 mediaDevice = NULL; 368 msgConfirm("Please remove the fixit floppy now."); 369 return DITEM_SUCCESS; 370} 371 372/* 373 * The common code for both fixit variants. 374 */ 375static void 376fixit_common(void) 377{ 378 pid_t child; 379 int waitstatus; 380 381 if (!directory_exists("/var/tmp/vi.recover")) { 382 if (DITEM_STATUS(Mkdir("/var/tmp/vi.recover")) != DITEM_SUCCESS) { 383 msgConfirm("Warning: Was unable to create a /var/tmp/vi.recover directory.\n" 384 "vi will kvetch and moan about it as a result but should still\n" 385 "be essentially usable."); 386 } 387 } 388 if (!directory_exists("/bin")) 389 (void)Mkdir("/bin"); 390 (void)symlink("/stand/sh", "/bin/sh"); 391 /* Link the /etc/ files */ 392 if (DITEM_STATUS(Mkdir("/etc")) != DITEM_SUCCESS) 393 msgConfirm("Unable to create an /etc directory! Things are weird on this floppy.."); 394 else if ((symlink("/mnt2/etc/spwd.db", "/etc/spwd.db") == -1 && errno != EEXIST) || 395 (symlink("/mnt2/etc/protocols", "/etc/protocols") == -1 && errno != EEXIST) || 396 (symlink("/mnt2/etc/services", "/etc/services") == -1 && errno != EEXIST)) 397 msgConfirm("Couldn't symlink the /etc/ files! I'm not sure I like this.."); 398 if (!file_readable(TERMCAP_FILE)) 399 create_termcap(); 400 if (!(child = fork())) { 401 int i, fd; 402 struct termios foo; 403 extern int login_tty(int); 404 405 ioctl(0, TIOCNOTTY, NULL); 406 for (i = getdtablesize(); i >= 0; --i) 407 close(i); 408 fd = open("/dev/ttyv3", O_RDWR); 409 ioctl(0, TIOCSCTTY, &fd); 410 dup2(0, 1); 411 dup2(0, 2); 412 DebugFD = 2; 413 if (login_tty(fd) == -1) 414 msgDebug("fixit: I can't set the controlling terminal.\n"); 415 416 signal(SIGTTOU, SIG_IGN); 417 if (tcgetattr(0, &foo) != -1) { 418 foo.c_cc[VERASE] = '\010'; 419 if (tcsetattr(0, TCSANOW, &foo) == -1) 420 msgDebug("fixit shell: Unable to set erase character.\n"); 421 } 422 else 423 msgDebug("fixit shell: Unable to get terminal attributes!\n"); 424 setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:" 425 "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1); 426 /* use the .profile from the fixit medium */ 427 setenv("HOME", "/mnt2", 1); 428 chdir("/mnt2"); 429 execlp("sh", "-sh", 0); 430 msgDebug("fixit shell: Failed to execute shell!\n"); 431 _exit(1);; 432 } 433 else { 434 msgNotify("Waiting for fixit shell to exit. Go to VTY4 now by\n" 435 "typing ALT-F4. When you are done, type ``exit'' to exit\n" 436 "the fixit shell and be returned here."); 437 (void)waitpid(child, &waitstatus, 0); 438 } 439 dialog_clear(); 440} 441 442 443int 444installExpress(dialogMenuItem *self) 445{ 446 int i; 447 448 variable_set2(SYSTEM_STATE, "express"); 449 if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE) 450 return i; 451 452 if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE) 453 return i; 454 455 dialog_clear_norefresh(); 456 if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) { 457 i |= DITEM_LEAVE_MENU; 458 /* Give user the option of one last configuration spree */ 459 installConfigure(); 460 } 461 return i | DITEM_RESTORE; 462} 463 464/* Novice mode installation */ 465int 466installNovice(dialogMenuItem *self) 467{ 468 int i, tries = 0; 469 Device **devs; 470 471 variable_set2(SYSTEM_STATE, "novice"); 472 dialog_clear_norefresh(); 473 msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n" 474 "scheme for your hard disk. If you simply wish to devote all disk space\n" 475 "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n" 476 "then use the (A)ll command to select the default partitioning scheme followed\n" 477 "by a (Q)uit. If you wish to allocate only free space to FreeBSD, move to a\n" 478 "partition marked \"unused\" and use the (C)reate command."); 479 480nodisks: 481 if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE) 482 return DITEM_FAILURE; 483 484 if (diskGetSelectCount(&devs) <= 0 && tries < 3) { 485 msgConfirm("You need to select some disks to operate on! Be sure to use SPACE\n" 486 "instead of RETURN in the disk selection menu when selecting a disk."); 487 ++tries; 488 goto nodisks; 489 } 490 491 dialog_clear_norefresh(); 492 msgConfirm("Next, you need to create BSD partitions inside of the fdisk partition(s)\n" 493 "just created. If you have a reasonable amount of disk space (200MB or more)\n" 494 "and don't have any special requirements, simply use the (A)uto command to\n" 495 "allocate space automatically. If you have more specific needs or just don't\n" 496 "care for the layout chosen by (A)uto, press F1 for more information on\n" 497 "manual layout."); 498 499 if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) 500 return DITEM_FAILURE; 501 502 dialog_clear_norefresh(); 503 if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) { 504 dialog_clear_norefresh(); 505 msgConfirm("Installation completed with some errors. You may wish to\n" 506 "scroll through the debugging messages on VTY1 with the\n" 507 "scroll-lock feature. You can also chose \"No\" at the next\n" 508 "prompt and go back into the installation menus to try and retry\n" 509 "whichever operations have failed."); 510 return i | DITEM_RESTORE; 511 512 } 513 else { 514 dialog_clear_norefresh(); 515 msgConfirm("Congratulations! You now have FreeBSD installed on your system.\n\n" 516 "We will now move on to the final configuration questions.\n" 517 "For any option you do not wish to configure, simply select\n" 518 "No.\n\n" 519 "If you wish to re-enter this utility after the system is up, you\n" 520 "may do so by typing: /stand/sysinstall."); 521 } 522 if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) { 523 if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) { 524 Device *tmp; 525 526 dialog_clear_norefresh(); 527 tmp = tcpDeviceSelect(); 528 dialog_clear_norefresh(); 529 if (tmp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) 530 if (!tmp->init(tmp)) 531 msgConfirm("Initialization of %s device failed.", tmp->name); 532 } 533 } 534 535 dialog_clear_norefresh(); 536 if (!msgYesNo("Will this machine be an IP gateway (e.g. will it forward packets\n" 537 "between interfaces)?")) 538 variable_set2("gateway_enable", "YES"); 539 540 dialog_clear_norefresh(); 541 if (!msgYesNo("Do you want to allow anonymous FTP connections to this machine?")) 542 configAnonFTP(self); 543 544 dialog_clear_norefresh(); 545 if (!msgYesNo("Do you want to configure this machine as an NFS server?")) 546 configNFSServer(self); 547 548 dialog_clear_norefresh(); 549 if (!msgYesNo("Do you want to configure this machine as an NFS client?")) 550 variable_set2("nfs_client_enable", "YES"); 551 552 dialog_clear_norefresh(); 553 if (!msgYesNo("Would you like to customize your system console settings?")) { 554 WINDOW *w = savescr(); 555 556 dmenuOpenSimple(&MenuSyscons, FALSE); 557 restorescr(w); 558 } 559 560 dialog_clear_norefresh(); 561 if (!msgYesNo("Would you like to set this machine's time zone now?")) { 562 WINDOW *w = savescr(); 563 564 dialog_clear(); 565 systemExecute("tzsetup"); 566 restorescr(w); 567 } 568 569 dialog_clear_norefresh(); 570 if (!msgYesNo("Does this system have a mouse attached to it?")) { 571 WINDOW *w = savescr(); 572 573 dmenuOpenSimple(&MenuMouse, FALSE); 574 restorescr(w); 575 } 576 577 /* Now would be a good time to checkpoint the configuration data */ 578 configRC_conf("/etc/rc.conf"); 579 sync(); 580 581 if (directory_exists("/usr/X11R6")) { 582 dialog_clear_norefresh(); 583 if (!msgYesNo("Would you like to configure your X server at this time?")) 584 configXEnvironment(self); 585 } 586 587 dialog_clear_norefresh(); 588 if (!msgYesNo("The FreeBSD package collection is a collection of hundreds of ready-to-run\n" 589 "applications, from text editors to games to WEB servers and more. Would you\n" 590 "like to browse the collection now?")) 591 configPackages(self); 592 593 dialog_clear_norefresh(); 594 if (!msgYesNo("Would you like to add any initial user accounts to the system?\n" 595 "Adding at least one account for yourself at this stage is suggested\n" 596 "since working as the \"root\" user is dangerous (it is easy to do\n" 597 "things which adversely affect the entire system).")) 598 configUsers(self); 599 600 dialog_clear_norefresh(); 601 msgConfirm("Now you must set the system manager's password.\n" 602 "This is the password you'll use to log in as \"root\"."); 603 { 604 WINDOW *w = savescr(); 605 606 if (!systemExecute("passwd root")) 607 variable_set2("root_password", "YES"); 608 restorescr(w); 609 } 610 611 dialog_clear_norefresh(); 612 if (!msgYesNo("Would you like to register your FreeBSD system at this time?\n\n" 613 "PLEASE, take just 5 minutes to do this. If we're ever to get any\n" 614 "significant base of commercial software for FreeBSD, we need to\n" 615 "be able to provide more information about the size of our user community.\n" 616 "This is where your registration can really help us, and you can also\n" 617 "sign up for the new FreeBSD newsletter (its free!) at the same time.\n")) 618 configRegister(NULL); 619 else { 620 dialog_clear_norefresh(); 621 msgConfirm("OK, but if you should change your mind then you always can register\n" 622 "later by typing ``/stand/sysinstall register'' or by simply visiting our\n" 623 "web site at http://www.freebsd.org/register.html"); 624 625 } 626 /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */ 627 628 /* Give user the option of one last configuration spree */ 629 dialog_clear_norefresh(); 630 installConfigure(); 631 632 return DITEM_LEAVE_MENU | DITEM_RESTORE; 633} 634 635/* The version of commit we call from the Install Custom menu */ 636int 637installCustomCommit(dialogMenuItem *self) 638{ 639 int i; 640 641 dialog_clear_norefresh(); 642 i = installCommit(self); 643 if (DITEM_STATUS(i) == DITEM_SUCCESS) { 644 /* Give user the option of one last configuration spree */ 645 installConfigure(); 646 return i; 647 } 648 else 649 msgConfirm("The commit operation completed with errors. Not\n" 650 "updating /etc files."); 651 return i; 652} 653 654/* 655 * What happens when we finally decide to going ahead with the installation. 656 * 657 * This is broken into multiple stages so that the user can do a full 658 * installation but come back here again to load more distributions, 659 * perhaps from a different media type. This would allow, for 660 * example, the user to load the majority of the system from CDROM and 661 * then use ftp to load just the DES dist. 662 */ 663int 664installCommit(dialogMenuItem *self) 665{ 666 int i; 667 char *str; 668 Boolean need_bin; 669 670 if (!Dists) 671 distConfig(NULL); 672 673 if (!Dists) 674 if (!dmenuOpenSimple(&MenuDistributions, FALSE) && !Dists) 675 return DITEM_FAILURE | DITEM_RESTORE; 676 677 if (!mediaVerify()) 678 return DITEM_FAILURE | DITEM_RESTORE; 679 680 str = variable_get(SYSTEM_STATE); 681 if (isDebug()) 682 msgDebug("installCommit: System state is `%s'\n", str); 683 684 if (RunningAsInit) { 685 /* Do things we wouldn't do to a multi-user system */ 686 if (DITEM_STATUS((i = installInitial())) == DITEM_FAILURE) 687 return i; 688 if (DITEM_STATUS((i = configFstab())) == DITEM_FAILURE) 689 return i; 690 } 691 692try_media: 693 if (!mediaDevice->init(mediaDevice)) { 694 if (!msgYesNo("Unable to initialize selected media. Would you like to\n" 695 "adjust your media configuration and try again?")) { 696 mediaDevice = NULL; 697 if (!mediaVerify()) 698 return DITEM_FAILURE | DITEM_RESTORE; 699 else 700 goto try_media; 701 } 702 else 703 return DITEM_FAILURE | DITEM_RESTORE; 704 } 705 706 need_bin = Dists & DIST_BIN; 707 i = distExtractAll(self); 708 /* Only do fixup if bin dist was successfully extracted */ 709 if (need_bin && !(Dists & DIST_BIN)) 710 i |= installFixup(self); 711 /* When running as init, *now* it's safe to grab the rc.foo vars */ 712 installEnvironment(); 713 714 variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install"); 715 716 return i | DITEM_RESTORE; 717} 718 719static void 720installConfigure(void) 721{ 722 /* Final menu of last resort */ 723 dialog_clear_norefresh(); 724 if (!msgYesNo("Visit the general configuration menu for a chance to set\n" 725 "any last options?")) { 726 WINDOW *w = savescr(); 727 728 dmenuOpenSimple(&MenuConfigure, FALSE); 729 restorescr(w); 730 } 731 configRC_conf("/etc/rc.conf"); 732 sync(); 733} 734 735int 736installFixup(dialogMenuItem *self) 737{ 738 Device **devs; 739 int i; 740 741 if (!file_readable("/kernel")) { 742 if (file_readable("/kernel.GENERIC")) { 743 if (vsystem("cp -p /kernel.GENERIC /kernel")) { 744 msgConfirm("Unable to link /kernel into place!"); 745 return DITEM_FAILURE; 746 } 747#ifdef SAVE_USERCONFIG 748 /* Snapshot any boot -c changes back to the new kernel */ 749 if (!variable_cmp(VAR_RELNAME, RELEASE_NAME)) 750 save_userconfig_to_kernel("/kernel"); 751#endif 752 } 753 else { 754 msgConfirm("Can't find a kernel image to link to on the root file system!\n" 755 "You're going to have a hard time getting this system to\n" 756 "boot from the hard disk, I'm afraid!"); 757 return DITEM_FAILURE; 758 } 759 } 760 761 /* Resurrect /dev after bin distribution screws it up */ 762 if (RunningAsInit) { 763 msgNotify("Remaking all devices.. Please wait!"); 764 if (vsystem("cd /dev; sh MAKEDEV all")) { 765 msgConfirm("MAKEDEV returned non-zero status"); 766 return DITEM_FAILURE; 767 } 768 769 msgNotify("Resurrecting /dev entries for slices.."); 770 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 771 if (!devs) 772 msgFatal("Couldn't get a disk device list!"); 773 774 /* Resurrect the slices that the former clobbered */ 775 for (i = 0; devs[i]; i++) { 776 Disk *disk = (Disk *)devs[i]->private; 777 Chunk *c1; 778 779 if (!devs[i]->enabled) 780 continue; 781 if (!disk->chunks) 782 msgFatal("No chunk list found for %s!", disk->name); 783 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 784 if (c1->type == freebsd) { 785 msgNotify("Making slice entries for %s", c1->name); 786 if (vsystem("cd /dev; sh MAKEDEV %sh", c1->name)) { 787 msgConfirm("Unable to make slice entries for %s!", c1->name); 788 return DITEM_FAILURE; 789 } 790 } 791 } 792 } 793 794 /* Do all the last ugly work-arounds here */ 795 msgNotify("Fixing permissions.."); 796 /* BOGON #1: XFree86 requires various specialized fixups */ 797 if (directory_exists("/usr/X11R6")) { 798 vsystem("chmod -R a+r /usr/X11R6"); 799 vsystem("find /usr/X11R6 -type d | xargs chmod a+x"); 800 801 /* Also do bogus minimal package registration so ports don't whine */ 802 if (file_readable("/usr/X11R6/lib/X11/pkgreg.tar.gz")) 803 vsystem("tar xpzf /usr/X11R6/lib/X11/pkgreg.tar.gz -C / && rm /usr/X11R6/lib/X11/pkgreg.tar.gz"); 804 } 805 806 /* BOGON #2: We leave /etc in a bad state */ 807 chmod("/etc", 0755); 808 809 /* BOGON #3: No /var/db/mountdtab complains */ 810 Mkdir("/var/db"); 811 creat("/var/db/mountdtab", 0644); 812 813 /* BOGON #4: /compat created by default in root fs */ 814 Mkdir("/usr/compat"); 815 vsystem("ln -s /usr/compat /compat"); 816 817 /* BOGON #5: aliases database not build for bin */ 818 vsystem("newaliases"); 819 820 /* BOGON #6: deal with new boot files */ 821 vsystem("touch /kernel.config"); 822 vsystem("touch /boot.config"); 823 if (file_readable("/stand/boot.help") && !file_readable("/boot.help")) 824 vsystem("mv /stand/boot.help /"); 825 826 /* Now run all the mtree stuff to fix things up */ 827 vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /"); 828 vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var"); 829 vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr"); 830 } 831 return DITEM_SUCCESS; 832} 833 834/* Go newfs and/or mount all the filesystems we've been asked to */ 835int 836installFilesystems(dialogMenuItem *self) 837{ 838 int i; 839 Disk *disk; 840 Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; 841 Device **devs; 842 PartInfo *root; 843 char dname[80]; 844 extern int MakeDevChunk(Chunk *c, char *n); 845 Boolean upgrade = FALSE; 846 847 /* If we've already done this, bail out */ 848 if (!variable_cmp(DISK_LABELLED, "written")) 849 return DITEM_SUCCESS; 850 851 upgrade = !variable_cmp(SYSTEM_STATE, "upgrade"); 852 if (!checkLabels(TRUE, &rootdev, &swapdev, &usrdev, &vardev)) 853 return DITEM_FAILURE; 854 855 if (rootdev) 856 root = (PartInfo *)rootdev->private_data; 857 else 858 root = NULL; 859 860 command_clear(); 861 if (swapdev && RunningAsInit) { 862 /* As the very first thing, try to get ourselves some swap space */ 863 sprintf(dname, "/dev/%s", swapdev->name); 864 if (!Fake && (!MakeDevChunk(swapdev, "/dev") || !file_readable(dname))) { 865 msgConfirm("Unable to make device node for %s in /dev!\n" 866 "The creation of filesystems will be aborted.", dname); 867 return DITEM_FAILURE; 868 } 869 870 if (!Fake) { 871 if (!swapon(dname)) 872 msgNotify("Added %s as initial swap device", dname); 873 else 874 msgConfirm("WARNING! Unable to swap to %s: %s\n" 875 "This may cause the installation to fail at some point\n" 876 "if you don't have a lot of memory.", dname, strerror(errno)); 877 } 878 } 879 880 if (rootdev && RunningAsInit) { 881 /* Next, create and/or mount the root device */ 882 sprintf(dname, "/dev/r%s", rootdev->name); 883 if (!Fake && (!MakeDevChunk(rootdev, "/dev") || !file_readable(dname))) { 884 msgConfirm("Unable to make device node for %s in /dev!\n" 885 "The creation of filesystems will be aborted.", dname); 886 return DITEM_FAILURE; 887 } 888 if (strcmp(root->mountpoint, "/")) 889 msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, root->mountpoint); 890 891 if (root->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs the root partition?"))) { 892 int i; 893 894 msgNotify("Making a new root filesystem on %s", dname); 895 i = vsystem("%s %s", root->newfs_cmd, dname); 896 if (i) { 897 msgConfirm("Unable to make new root filesystem on %s!\n" 898 "Command returned status %d", dname, i); 899 return DITEM_FAILURE; 900 } 901 } 902 else { 903 if (!upgrade) { 904 msgConfirm("Warning: Using existing root partition. It will be assumed\n" 905 "that you have the appropriate device entries already in /dev."); 906 } 907 msgNotify("Checking integrity of existing %s filesystem.", dname); 908 i = vsystem("fsck -y %s", dname); 909 if (i) 910 msgConfirm("Warning: fsck returned status of %d for %s.\n" 911 "This partition may be unsafe to use.", i, dname); 912 } 913 914 /* Switch to block device */ 915 sprintf(dname, "/dev/%s", rootdev->name); 916 if (Mount("/mnt", dname)) { 917 msgConfirm("Unable to mount the root file system on %s! Giving up.", dname); 918 return DITEM_FAILURE; 919 } 920 } 921 922 /* Now buzz through the rest of the partitions and mount them too */ 923 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 924 for (i = 0; devs[i]; i++) { 925 if (!devs[i]->enabled) 926 continue; 927 928 disk = (Disk *)devs[i]->private; 929 if (!disk->chunks) { 930 msgConfirm("No chunk list found for %s!", disk->name); 931 return DITEM_FAILURE; 932 } 933 if (RunningAsInit && root && (root->newfs || upgrade)) { 934 Mkdir("/mnt/dev"); 935 if (!Fake) 936 MakeDevDisk(disk, "/mnt/dev"); 937 } 938 else if (!RunningAsInit && !Fake) 939 MakeDevDisk(disk, "/dev"); 940 941 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 942 if (c1->type == freebsd) { 943 for (c2 = c1->part; c2; c2 = c2->next) { 944 if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { 945 PartInfo *tmp = (PartInfo *)c2->private_data; 946 947 /* Already did root */ 948 if (c2 == rootdev) 949 continue; 950 951 if (tmp->newfs && (!upgrade || !msgYesNo("You are upgradding - are you SURE you want to newfs /dev/%s?", c2->name))) 952 command_shell_add(tmp->mountpoint, "%s %s/dev/r%s", tmp->newfs_cmd, RunningAsInit ? "/mnt" : "", c2->name); 953 else 954 command_shell_add(tmp->mountpoint, "fsck -y %s/dev/r%s", RunningAsInit ? "/mnt" : "", c2->name); 955 command_func_add(tmp->mountpoint, Mount, c2->name); 956 } 957 else if (c2->type == part && c2->subtype == FS_SWAP) { 958 char fname[80]; 959 int i; 960 961 if (c2 == swapdev) 962 continue; 963 sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); 964 i = (Fake || swapon(fname)); 965 if (!i) 966 msgNotify("Added %s as an additional swap device", fname); 967 else 968 msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); 969 } 970 } 971 } 972 else if (c1->type == fat && c1->private_data && (root->newfs || upgrade)) { 973 char name[FILENAME_MAX]; 974 975 sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint); 976 Mkdir(name); 977 } 978 } 979 } 980 981 if (RunningAsInit) { 982 msgNotify("Copying initial device files.."); 983 /* Copy the boot floppy's dev files */ 984 if ((root->newfs || upgrade) && vsystem("find -x /dev | cpio %s -pdum /mnt", cpioVerbosity())) { 985 msgConfirm("Couldn't clone the /dev files!"); 986 return DITEM_FAILURE; 987 } 988 } 989 990 command_sort(); 991 command_execute(); 992 return DITEM_SUCCESS; 993} 994 995/* Initialize various user-settable values to their defaults */ 996int 997installVarDefaults(dialogMenuItem *self) 998{ 999 char *cp; 1000 1001 /* Set default startup options */ 1002 variable_set2(VAR_RELNAME, RELEASE_NAME); 1003 variable_set2(VAR_CPIO_VERBOSITY, "high"); 1004 variable_set2(VAR_TAPE_BLOCKSIZE, DEFAULT_TAPE_BLOCKSIZE); 1005 variable_set2(VAR_INSTALL_ROOT, "/"); 1006 variable_set2(VAR_INSTALL_CFG, "install.cfg"); 1007 cp = getenv("EDITOR"); 1008 if (!cp) 1009 cp = "/usr/bin/ee"; 1010 variable_set2(VAR_EDITOR, cp); 1011 variable_set2(VAR_FTP_USER, "ftp"); 1012 variable_set2(VAR_BROWSER_PACKAGE, PACKAGE_LYNX); 1013 variable_set2(VAR_BROWSER_BINARY, "/usr/local/bin/lynx"); 1014 variable_set2(VAR_FTP_STATE, "passive"); 1015 variable_set2(VAR_NFS_SECURE, "YES"); 1016 variable_set2(VAR_PKG_TMPDIR, "/usr/tmp"); 1017 variable_set2(VAR_GATED_PKG, PACKAGE_GATED); 1018 variable_set2(VAR_PCNFSD_PKG, PACKAGE_PCNFSD); 1019 variable_set2(VAR_MEDIA_TIMEOUT, itoa(MEDIA_TIMEOUT)); 1020 if (getpid() != 1) 1021 variable_set2(SYSTEM_STATE, "update"); 1022 else 1023 variable_set2(SYSTEM_STATE, "init"); 1024 return DITEM_SUCCESS; 1025} 1026 1027/* Load the environment up from various system configuration files */ 1028void 1029installEnvironment(void) 1030{ 1031 if (file_readable("/etc/rc.conf")) 1032 configEnvironmentRC_conf("/etc/rc.conf"); 1033 if (file_readable("/etc/resolv.conf")) 1034 configEnvironmentResolv("/etc/resolv.conf"); 1035} 1036 1037/* Copy the boot floppy contents into /stand */ 1038Boolean 1039copySelf(void) 1040{ 1041 int i; 1042 1043 if (file_readable("/boot.help")) 1044 vsystem("cp /boot.help /mnt"); 1045 msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); 1046 i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); 1047 if (i) { 1048 msgConfirm("Copy returned error status of %d!", i); 1049 return FALSE; 1050 } 1051 1052 /* Copy the /etc files into their rightful place */ 1053 if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) { 1054 msgConfirm("Couldn't copy up the /etc files!"); 1055 return TRUE; 1056 } 1057 return TRUE; 1058} 1059 1060static void 1061create_termcap(void) 1062{ 1063 FILE *fp; 1064 1065 const char *caps[] = { 1066 termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r, 1067 termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m, NULL, 1068 }; 1069 const char **cp; 1070 1071 if (!file_readable(TERMCAP_FILE)) { 1072 Mkdir("/usr/share/misc"); 1073 fp = fopen(TERMCAP_FILE, "w"); 1074 if (!fp) { 1075 msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work."); 1076 return; 1077 } 1078 cp = caps; 1079 while (*cp) 1080 fprintf(fp, "%s\n", *(cp++)); 1081 fclose(fp); 1082 } 1083} 1084 1085#ifdef SAVE_USERCONFIG 1086static void 1087save_userconfig_to_kernel(char *kern) 1088{ 1089 struct kernel *core, *boot; 1090 struct list *c_isa, *b_isa, *c_dev, *b_dev; 1091 int i, d; 1092 1093 if ((core = uc_open("-incore")) == NULL) { 1094 msgDebug("save_userconf: Can't read in-core information for kernel.\n"); 1095 return; 1096 } 1097 1098 if ((boot = uc_open(kern)) == NULL) { 1099 msgDebug("save_userconf: Can't read device information for kernel image %s\n", kern); 1100 return; 1101 } 1102 1103 msgNotify("Saving any boot -c changes to new kernel..."); 1104 c_isa = uc_getdev(core, "-isa"); 1105 b_isa = uc_getdev(boot, "-isa"); 1106 if (isDebug()) 1107 msgDebug("save_userconf: got %d ISA device entries from core, %d from boot.\n", c_isa->ac, b_isa->ac); 1108 for (d = 0; d < c_isa->ac; d++) { 1109 if (isDebug()) 1110 msgDebug("save_userconf: ISA device loop, c_isa->av[%d] = %s\n", d, c_isa->av[d]); 1111 if (strcmp(c_isa->av[d], "npx0")) { /* special case npx0, which mucks with its id_irq member */ 1112 c_dev = uc_getdev(core, c_isa->av[d]); 1113 b_dev = uc_getdev(boot, b_isa->av[d]); 1114 if (!c_dev || !b_dev) { 1115 msgDebug("save_userconf: c_dev: %x b_dev: %x\n", c_dev, b_dev); 1116 continue; 1117 } 1118 if (isDebug()) 1119 msgDebug("save_userconf: ISA device %s: %d config parameters (core), %d (boot)\n", 1120 c_isa->av[d], c_dev->ac, b_dev->ac); 1121 for (i = 0; i < c_dev->ac; i++) { 1122 if (isDebug()) 1123 msgDebug("save_userconf: c_dev->av[%d] = %s, b_dev->av[%d] = %s\n", i, c_dev->av[i], i, b_dev->av[i]); 1124 if (strcmp(c_dev->av[i], b_dev->av[i])) { 1125 if (isDebug()) 1126 msgDebug("save_userconf: %s (boot) -> %s (core)\n", 1127 c_dev->av[i], b_dev->av[i]); 1128 isa_setdev(boot, c_dev); 1129 } 1130 } 1131 } 1132 else { 1133 if (isDebug()) 1134 msgDebug("skipping npx0\n"); 1135 } 1136 } 1137 if (isDebug()) 1138 msgDebug("Closing kernels\n"); 1139 uc_close(core, 0); 1140 uc_close(boot, 1); 1141} 1142#endif 1143