install.c revision 44029
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.228 1999/02/14 21:26:28 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 <ctype.h> 39#include <sys/disklabel.h> 40#include <sys/errno.h> 41#include <sys/ioctl.h> 42#include <sys/fcntl.h> 43#include <sys/wait.h> 44#include <sys/param.h> 45#define MSDOSFS 46#include <sys/mount.h> 47#include <ufs/ufs/ufsmount.h> 48#include <msdosfs/msdosfsmount.h> 49#undef MSDOSFS 50#include <sys/stat.h> 51#include <sys/sysctl.h> 52#include <unistd.h> 53 54static void create_termcap(void); 55static void fixit_common(void); 56 57#define TERMCAP_FILE "/usr/share/misc/termcap" 58 59static void installConfigure(void); 60 61Boolean 62checkLabels(Boolean whinge, Chunk **rdev, Chunk **sdev, Chunk **udev, Chunk **vdev) 63{ 64 Device **devs; 65 Boolean status; 66 Disk *disk; 67 Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; 68 int i; 69 70 /* Don't allow whinging if noWarn is set */ 71 if (variable_get(VAR_NO_WARN)) 72 whinge = FALSE; 73 74 status = TRUE; 75 *rdev = *sdev = *udev = *vdev = rootdev = swapdev = usrdev = vardev = NULL; 76 77 /* We don't need to worry about root/usr/swap if we're already multiuser */ 78 if (!RunningAsInit) 79 return status; 80 81 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 82 /* First verify that we have a root device */ 83 for (i = 0; devs[i]; i++) { 84 if (!devs[i]->enabled) 85 continue; 86 disk = (Disk *)devs[i]->private; 87 msgDebug("Scanning disk %s for root filesystem\n", disk->name); 88 if (!disk->chunks) 89 msgFatal("No chunk list found for %s!", disk->name); 90 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 91 if (c1->type == freebsd) { 92 for (c2 = c1->part; c2; c2 = c2->next) { 93 if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { 94 if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/")) { 95 if (rootdev) { 96 if (whinge) 97 msgConfirm("WARNING: You have more than one root device set?!\n" 98 "Using the first one found."); 99 continue; 100 } 101 else { 102 rootdev = c2; 103 if (isDebug()) 104 msgDebug("Found rootdev at %s!\n", rootdev->name); 105 } 106 } 107 else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/usr")) { 108 if (usrdev) { 109 if (whinge) 110 msgConfirm("WARNING: You have more than one /usr filesystem.\n" 111 "Using the first one found."); 112 continue; 113 } 114 else { 115 usrdev = c2; 116 if (isDebug()) 117 msgDebug("Found usrdev at %s!\n", usrdev->name); 118 } 119 } 120 else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/var")) { 121 if (vardev) { 122 if (whinge) 123 msgConfirm("WARNING: You have more than one /var filesystem.\n" 124 "Using the first one found."); 125 continue; 126 } 127 else { 128 vardev = c2; 129 if (isDebug()) 130 msgDebug("Found vardev at %s!\n", vardev->name); 131 } 132 } 133 } 134 } 135 } 136 } 137 } 138 139 /* Now check for swap devices */ 140 for (i = 0; devs[i]; i++) { 141 if (!devs[i]->enabled) 142 continue; 143 disk = (Disk *)devs[i]->private; 144 msgDebug("Scanning disk %s for swap partitions\n", disk->name); 145 if (!disk->chunks) 146 msgFatal("No chunk list found for %s!", disk->name); 147 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 148 if (c1->type == freebsd) { 149 for (c2 = c1->part; c2; c2 = c2->next) { 150 if (c2->type == part && c2->subtype == FS_SWAP && !swapdev) { 151 swapdev = c2; 152 if (isDebug()) 153 msgDebug("Found swapdev at %s!\n", swapdev->name); 154 break; 155 } 156 } 157 } 158 } 159 } 160 161 /* Copy our values over */ 162 *rdev = rootdev; 163 *sdev = swapdev; 164 *udev = usrdev; 165 *vdev = vardev; 166 167 if (!rootdev && whinge) { 168 msgConfirm("No root device found - you must label a partition as /\n" 169 "in the label editor."); 170 status = FALSE; 171 } 172 if (!swapdev && whinge) { 173 msgConfirm("No swap devices found - you must create at least one\n" 174 "swap partition."); 175 status = FALSE; 176 } 177 if (!usrdev && whinge && !variable_get(VAR_NO_USR)) { 178 msgConfirm("WARNING: No /usr filesystem found. This is not technically\n" 179 "an error if your root filesystem is big enough (or you later\n" 180 "intend to mount your /usr filesystem over NFS), but it may otherwise\n" 181 "cause you trouble if you're not exactly sure what you are doing!"); 182 } 183 if (!vardev && whinge && variable_cmp(SYSTEM_STATE, "upgrade")) { 184 msgConfirm("WARNING: No /var filesystem found. This is not technically\n" 185 "an error if your root filesystem is big enough (or you later\n" 186 "intend to link /var to someplace else), but it may otherwise\n" 187 "cause your root filesystem to fill up if you receive lots of mail\n" 188 "or edit large temporary files."); 189 } 190 return status; 191} 192 193static int 194installInitial(void) 195{ 196 static Boolean alreadyDone = FALSE; 197 int status = DITEM_SUCCESS; 198 199 if (alreadyDone) 200 return DITEM_SUCCESS; 201 202 if (!variable_get(DISK_LABELLED)) { 203 msgConfirm("You need to assign disk labels before you can proceed with\n" 204 "the installation."); 205 return DITEM_FAILURE; 206 } 207 /* If it's labelled, assume it's also partitioned */ 208 if (!variable_get(DISK_PARTITIONED)) 209 variable_set2(DISK_PARTITIONED, "yes", 0); 210 211 /* If we refuse to proceed, bail. */ 212 dialog_clear_norefresh(); 213 if (!variable_get(VAR_NO_WARN)) 214 if (msgYesNo( 215 "Last Chance! Are you SURE you want continue the installation?\n\n" 216 "If you're running this on a disk with data you wish to save\n" 217 "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n" 218 "proceeding!\n\n" 219 "We can take no responsibility for lost disk contents!") != 0) 220 return DITEM_FAILURE | DITEM_RESTORE; 221 222 if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) { 223 msgConfirm("Couldn't make filesystems properly. Aborting."); 224 return DITEM_FAILURE; 225 } 226 227 if (!copySelf()) { 228 msgConfirm("installInitial: Couldn't clone the boot floppy onto the\n" 229 "root file system. Aborting!"); 230 return DITEM_FAILURE; 231 } 232 233 if (chroot("/mnt") == -1) { 234 msgConfirm("installInitial: Unable to chroot to %s - this is bad!", 235 "/mnt"); 236 return DITEM_FAILURE; 237 } 238 239 chdir("/"); 240 variable_set2(RUNNING_ON_ROOT, "yes", 0); 241 242 /* Configure various files in /etc */ 243 if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE) 244 status = DITEM_FAILURE; 245 if (DITEM_STATUS(configFstab(NULL)) == DITEM_FAILURE) 246 status = DITEM_FAILURE; 247 248 /* stick a helpful shell over on the 4th VTY */ 249 systemCreateHoloshell(); 250 251 alreadyDone = TRUE; 252 return status; 253} 254 255int 256installFixitHoloShell(dialogMenuItem *self) 257{ 258 systemCreateHoloshell(); 259 return DITEM_SUCCESS; 260} 261 262int 263installFixitCDROM(dialogMenuItem *self) 264{ 265 struct stat sb; 266 267 if (!RunningAsInit) 268 return DITEM_SUCCESS; 269 270 variable_set2(SYSTEM_STATE, "fixit", 0); 271 (void)unlink("/mnt2"); 272 (void)rmdir("/mnt2"); 273 274 while (1) { 275 msgConfirm("Please insert a FreeBSD live filesystem CDROM and press return"); 276 if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS || !mediaDevice || !mediaDevice->init(mediaDevice)) { 277 /* If we can't initialize it, it's probably not a FreeBSD CDROM so punt on it */ 278 mediaClose(); 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 fixit_common(); 326 mediaClose(); 327 msgConfirm("Please remove the FreeBSD fixit CDROM now."); 328 return DITEM_SUCCESS; 329} 330 331int 332installFixitFloppy(dialogMenuItem *self) 333{ 334 struct ufs_args args; 335 extern char *distWanted; 336 337 if (!RunningAsInit) 338 return DITEM_SUCCESS; 339 340 /* Try to open the floppy drive */ 341 if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE || !mediaDevice) { 342 msgConfirm("Unable to set media device to floppy."); 343 mediaClose(); 344 return DITEM_FAILURE; 345 } 346 347 memset(&args, 0, sizeof(args)); 348 args.fspec = mediaDevice->devname; 349 mediaDevice->private = "/mnt2"; 350 distWanted = NULL; 351 Mkdir("/mnt2"); 352 353 variable_set2(SYSTEM_STATE, "fixit", 0); 354 355 while (1) { 356 if (!mediaDevice->init(mediaDevice)) { 357 if (msgYesNo("The attempt to mount the fixit floppy failed, bad floppy\n" 358 "or unclean filesystem. Do you want to try again?")) 359 return DITEM_FAILURE; 360 } 361 else 362 break; 363 } 364 if (!directory_exists("/tmp")) 365 (void)symlink("/mnt2/tmp", "/tmp"); 366 fixit_common(); 367 mediaClose(); 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", 0); 449#ifndef __alpha__ 450 if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE) 451 return i; 452#endif 453 454 if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE) 455 return i; 456 457 dialog_clear_norefresh(); 458 if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) { 459 i |= DITEM_LEAVE_MENU; 460 /* Give user the option of one last configuration spree */ 461 installConfigure(); 462 } 463 return i | DITEM_RESTORE; 464} 465 466/* Novice mode installation */ 467int 468installNovice(dialogMenuItem *self) 469{ 470 int i, tries = 0; 471 Device **devs; 472 473 variable_set2(SYSTEM_STATE, "novice", 0); 474#ifndef __alpha__ 475 dialog_clear_norefresh(); 476 msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n" 477 "scheme for your hard disk. If you simply wish to devote all disk space\n" 478 "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n" 479 "then use the (A)ll command to select the default partitioning scheme followed\n" 480 "by a (Q)uit. If you wish to allocate only free space to FreeBSD, move to a\n" 481 "partition marked \"unused\" and use the (C)reate command."); 482 483nodisks: 484 if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE) 485 return DITEM_FAILURE; 486 487 if (diskGetSelectCount(&devs) <= 0 && tries < 3) { 488 msgConfirm("You need to select some disks to operate on! Be sure to use SPACE\n" 489 "instead of RETURN in the disk selection menu when selecting a disk."); 490 ++tries; 491 goto nodisks; 492 } 493#endif 494 495 dialog_clear_norefresh(); 496#ifdef __alpha__ 497 msgConfirm("First, you need to create BSD partitions on the disk which you are\n" 498 "installing to. If you have a reasonable amount of disk space (200MB or more)\n" 499 "and don't have any special requirements, simply use the (A)uto command to\n" 500 "allocate space automatically. If you have more specific needs or just don't\n" 501 "care for the layout chosen by (A)uto, press F1 for more information on\n" 502 "manual layout."); 503#else 504 msgConfirm("First, you need to create BSD partitions inside of the fdisk partition(s)\n" 505 "just created. If you have a reasonable amount of disk space (200MB or more)\n" 506 "and don't have any special requirements, simply use the (A)uto command to\n" 507 "allocate space automatically. If you have more specific needs or just don't\n" 508 "care for the layout chosen by (A)uto, press F1 for more information on\n" 509 "manual layout."); 510#endif 511 512 if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) 513 return DITEM_FAILURE; 514 515 dialog_clear_norefresh(); 516 if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) { 517 dialog_clear_norefresh(); 518 msgConfirm("Installation completed with some errors. You may wish to\n" 519 "scroll through the debugging messages on VTY1 with the\n" 520 "scroll-lock feature. You can also chose \"No\" at the next\n" 521 "prompt and go back into the installation menus to try and retry\n" 522 "whichever operations have failed."); 523 return i | DITEM_RESTORE; 524 525 } 526 else { 527 dialog_clear_norefresh(); 528 msgConfirm("Congratulations! You now have FreeBSD installed on your system.\n\n" 529 "We will now move on to the final configuration questions.\n" 530 "For any option you do not wish to configure, simply select\n" 531 "No.\n\n" 532 "If you wish to re-enter this utility after the system is up, you\n" 533 "may do so by typing: /stand/sysinstall."); 534 } 535 if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) { 536 if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) { 537 Device *tmp; 538 539 dialog_clear_norefresh(); 540 tmp = tcpDeviceSelect(); 541 dialog_clear_norefresh(); 542 if (tmp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) 543 if (!tmp->init(tmp)) 544 msgConfirm("Initialization of %s device failed.", tmp->name); 545 } 546 } 547 548 dialog_clear_norefresh(); 549 if (!msgYesNo("Will this machine be an IP gateway (e.g. will it forward packets\n" 550 "between interfaces)?")) 551 variable_set2("gateway_enable", "YES", 1); 552 553 dialog_clear_norefresh(); 554 if (!msgYesNo("Do you want to allow anonymous FTP connections to this machine?")) 555 configAnonFTP(self); 556 557 dialog_clear_norefresh(); 558 if (!msgYesNo("Do you want to configure this machine as an NFS server?")) 559 configNFSServer(self); 560 561 dialog_clear_norefresh(); 562 if (!msgYesNo("Do you want to configure this machine as an NFS client?")) 563 variable_set2("nfs_client_enable", "YES", 1); 564 565 dialog_clear_norefresh(); 566 if (!msgYesNo("Would you like to customize your system console settings?")) { 567 WINDOW *w = savescr(); 568 569 dmenuOpenSimple(&MenuSyscons, FALSE); 570 restorescr(w); 571 } 572 573 dialog_clear_norefresh(); 574 if (!msgYesNo("Would you like to set this machine's time zone now?")) { 575 WINDOW *w = savescr(); 576 577 dialog_clear(); 578 systemExecute("tzsetup"); 579 restorescr(w); 580 } 581 582 dialog_clear_norefresh(); 583 if (!msgYesNo("Does this system have a mouse attached to it?")) { 584 WINDOW *w = savescr(); 585 586 dmenuOpenSimple(&MenuMouse, FALSE); 587 restorescr(w); 588 } 589 590 /* Now would be a good time to checkpoint the configuration data */ 591 configRC_conf(); 592 sync(); 593 594 if (directory_exists("/usr/X11R6")) { 595 dialog_clear_norefresh(); 596 if (!msgYesNo("Would you like to configure your X server at this time?")) 597 configXEnvironment(self); 598 } 599 600 dialog_clear_norefresh(); 601 if (!msgYesNo("The FreeBSD package collection is a collection of hundreds of ready-to-run\n" 602 "applications, from text editors to games to WEB servers and more. Would you\n" 603 "like to browse the collection now?")) 604 configPackages(self); 605 606 dialog_clear_norefresh(); 607 if (!msgYesNo("Would you like to add any initial user accounts to the system?\n" 608 "Adding at least one account for yourself at this stage is suggested\n" 609 "since working as the \"root\" user is dangerous (it is easy to do\n" 610 "things which adversely affect the entire system).")) 611 configUsers(self); 612 613 dialog_clear_norefresh(); 614 msgConfirm("Now you must set the system manager's password.\n" 615 "This is the password you'll use to log in as \"root\"."); 616 { 617 WINDOW *w = savescr(); 618 619 if (!systemExecute("passwd root")) 620 variable_set2("root_password", "YES", 0); 621 restorescr(w); 622 } 623 624 dialog_clear_norefresh(); 625 if (!msgYesNo("Would you like to register your FreeBSD system at this time?\n\n" 626 "PLEASE, take just 5 minutes to do this. If we're ever to get any\n" 627 "significant base of commercial software for FreeBSD, we need to\n" 628 "be able to provide more information about the size of our user community.\n" 629 "This is where your registration can really help us, and you can also\n" 630 "sign up for the new FreeBSD newsletter (its free!) at the same time.\n")) 631 configRegister(NULL); 632 else { 633 dialog_clear_norefresh(); 634 msgConfirm("OK, but if you should change your mind then you always can register\n" 635 "later by typing ``/stand/sysinstall register'' or by simply visiting our\n" 636 "web site at http://www.freebsd.org/register.html"); 637 638 } 639 /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */ 640 641 /* Give user the option of one last configuration spree */ 642 dialog_clear_norefresh(); 643 installConfigure(); 644 645 return DITEM_LEAVE_MENU | DITEM_RESTORE; 646} 647 648/* The version of commit we call from the Install Custom menu */ 649int 650installCustomCommit(dialogMenuItem *self) 651{ 652 int i; 653 654 dialog_clear_norefresh(); 655 i = installCommit(self); 656 if (DITEM_STATUS(i) == DITEM_SUCCESS) { 657 /* Give user the option of one last configuration spree */ 658 installConfigure(); 659 return i; 660 } 661 else 662 msgConfirm("The commit operation completed with errors. Not\n" 663 "updating /etc files."); 664 return i; 665} 666 667/* 668 * What happens when we finally decide to going ahead with the installation. 669 * 670 * This is broken into multiple stages so that the user can do a full 671 * installation but come back here again to load more distributions, 672 * perhaps from a different media type. This would allow, for 673 * example, the user to load the majority of the system from CDROM and 674 * then use ftp to load just the DES dist. 675 */ 676int 677installCommit(dialogMenuItem *self) 678{ 679 int i; 680 char *str; 681 682 if (!Dists) 683 distConfig(NULL); 684 685 if (!Dists) 686 if (!dmenuOpenSimple(&MenuDistributions, FALSE) && !Dists) 687 return DITEM_FAILURE | DITEM_RESTORE; 688 689 if (!mediaVerify()) 690 return DITEM_FAILURE | DITEM_RESTORE; 691 692 str = variable_get(SYSTEM_STATE); 693 if (isDebug()) 694 msgDebug("installCommit: System state is `%s'\n", str); 695 696 /* Installation stuff we wouldn't do to a running system */ 697 if (RunningAsInit && DITEM_STATUS((i = installInitial())) == DITEM_FAILURE) 698 return i; 699 700try_media: 701 if (!mediaDevice->init(mediaDevice)) { 702 if (!msgYesNo("Unable to initialize selected media. Would you like to\n" 703 "adjust your media configuration and try again?")) { 704 mediaDevice = NULL; 705 if (!mediaVerify()) 706 return DITEM_FAILURE | DITEM_RESTORE; 707 else 708 goto try_media; 709 } 710 else 711 return DITEM_FAILURE | DITEM_RESTORE; 712 } 713 714 /* Now go get it all */ 715 i = distExtractAll(self); 716 717 /* When running as init, *now* it's safe to grab the rc.foo vars */ 718 installEnvironment(); 719 720 variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install", 0); 721 722 return i | DITEM_RESTORE; 723} 724 725static void 726installConfigure(void) 727{ 728 /* Final menu of last resort */ 729 dialog_clear_norefresh(); 730 if (!msgYesNo("Visit the general configuration menu for a chance to set\n" 731 "any last options?")) { 732 WINDOW *w = savescr(); 733 734 dmenuOpenSimple(&MenuConfigure, FALSE); 735 restorescr(w); 736 } 737 configRC_conf(); 738 sync(); 739} 740 741int 742installFixupBin(dialogMenuItem *self) 743{ 744 Device **devs; 745 int i; 746 747 /* All of this is done only as init, just to be safe */ 748 if (RunningAsInit) { 749 /* Fix up kernel first */ 750 if (!file_readable("/kernel")) { 751 if (file_readable("/kernel.GENERIC")) { 752 if (vsystem("cp -p /kernel.GENERIC /kernel")) { 753 msgConfirm("Unable to copy /kernel into place!"); 754 return DITEM_FAILURE; 755 } 756#ifndef __alpha__ 757 /* Snapshot any boot -c changes back to the new kernel */ 758 if (kget("/boot/kernel.conf")) { 759 msgConfirm("Kernel copied OK, but unable to save boot -c changes\n" 760 "to it. See the debug screen (ALT-F2) for details."); 761 } 762 else { 763 if (!file_readable("/boot/loader.rc")) { 764 FILE *fp; 765 766 if ((fp = fopen("/boot/loader.rc", "w")) != NULL) { 767 fprintf(fp, "load /kernel\n"); 768 fprintf(fp, "load -t userconfig_script /boot/kernel.conf\n"); 769 fprintf(fp, "autoboot 5\n"); 770 fclose(fp); 771 } 772 } 773 else { 774 msgConfirm("You already have a /boot/loader.rc file so I won't touch it.\n" 775 "You will need to add a: load -t userconfig_script /boot/kernel.conf\n" 776 "line to your /boot/loader.rc before your saved kernel changes\n" 777 "(if any) can go into effect."); 778 } 779 } 780#endif 781 } 782 else { 783 msgConfirm("Can't find a kernel image to link to on the root file system!\n" 784 "You're going to have a hard time getting this system to\n" 785 "boot from the hard disk, I'm afraid!"); 786 return DITEM_FAILURE; 787 } 788 } 789 790 /* BOGON #1: Resurrect /dev after bin distribution screws it up */ 791 msgNotify("Remaking all devices.. Please wait!"); 792 if (vsystem("cd /dev; sh MAKEDEV all")) { 793 msgConfirm("MAKEDEV returned non-zero status"); 794 return DITEM_FAILURE; 795 } 796 797 msgNotify("Resurrecting /dev entries for slices.."); 798 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 799 if (!devs) 800 msgFatal("Couldn't get a disk device list!"); 801 802 /* Resurrect the slices that the former clobbered */ 803 for (i = 0; devs[i]; i++) { 804 Disk *disk = (Disk *)devs[i]->private; 805 Chunk *c1; 806 807 if (!devs[i]->enabled) 808 continue; 809 if (!disk->chunks) 810 msgFatal("No chunk list found for %s!", disk->name); 811 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 812 if (c1->type == freebsd) { 813 msgNotify("Making slice entries for %s", c1->name); 814 if (vsystem("cd /dev; sh MAKEDEV %sh", c1->name)) { 815 msgConfirm("Unable to make slice entries for %s!", c1->name); 816 return DITEM_FAILURE; 817 } 818 } 819 } 820 } 821 822 /* BOGON #2: We leave /etc in a bad state */ 823 chmod("/etc", 0755); 824 825 /* BOGON #3: No /var/db/mountdtab complains */ 826 Mkdir("/var/db"); 827 creat("/var/db/mountdtab", 0644); 828 829 /* BOGON #4: /compat created by default in root fs */ 830 Mkdir("/usr/compat"); 831 vsystem("ln -s /usr/compat /compat"); 832 833 /* BOGON #5: aliases database not build for bin */ 834 vsystem("newaliases"); 835 836 /* Now run all the mtree stuff to fix things up */ 837 vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /"); 838 vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var"); 839 vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr"); 840 841 /* Do all the last ugly work-arounds here */ 842 } 843 return DITEM_SUCCESS; 844} 845 846/* Fix side-effects from the the XFree86 installation */ 847int 848installFixupXFree(dialogMenuItem *self) 849{ 850 /* BOGON #1: XFree86 requires various specialized fixups */ 851 if (directory_exists("/usr/X11R6")) { 852 msgNotify("Fixing permissions in XFree86 tree.."); 853 vsystem("chmod -R a+r /usr/X11R6"); 854 vsystem("find /usr/X11R6 -type d | xargs chmod a+x"); 855 856 /* Also do bogus minimal package registration so ports don't whine */ 857 if (file_readable("/usr/X11R6/lib/X11/pkgreg.tar.gz")) { 858 msgNotify("Installing package metainfo.."); 859 vsystem("tar xpzf /usr/X11R6/lib/X11/pkgreg.tar.gz -C / && rm /usr/X11R6/lib/X11/pkgreg.tar.gz"); 860 } 861 } 862 return DITEM_SUCCESS; 863} 864 865/* Go newfs and/or mount all the filesystems we've been asked to */ 866int 867installFilesystems(dialogMenuItem *self) 868{ 869 int i; 870 Disk *disk; 871 Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; 872 Device **devs; 873 PartInfo *root; 874 char dname[80]; 875 extern int MakeDevChunk(Chunk *c, char *n); 876 Boolean upgrade = FALSE; 877 878 /* If we've already done this, bail out */ 879 if (!variable_cmp(DISK_LABELLED, "written")) 880 return DITEM_SUCCESS; 881 882 upgrade = !variable_cmp(SYSTEM_STATE, "upgrade"); 883 if (!checkLabels(TRUE, &rootdev, &swapdev, &usrdev, &vardev)) 884 return DITEM_FAILURE; 885 886 if (rootdev) 887 root = (PartInfo *)rootdev->private_data; 888 else 889 root = NULL; 890 891 command_clear(); 892 if (swapdev && RunningAsInit) { 893 /* As the very first thing, try to get ourselves some swap space */ 894 sprintf(dname, "/dev/%s", swapdev->name); 895 if (!Fake && (!MakeDevChunk(swapdev, "/dev") || !file_readable(dname))) { 896 msgConfirm("Unable to make device node for %s in /dev!\n" 897 "The creation of filesystems will be aborted.", dname); 898 return DITEM_FAILURE; 899 } 900 901 if (!Fake) { 902 if (!swapon(dname)) 903 msgNotify("Added %s as initial swap device", dname); 904 else 905 msgConfirm("WARNING! Unable to swap to %s: %s\n" 906 "This may cause the installation to fail at some point\n" 907 "if you don't have a lot of memory.", dname, strerror(errno)); 908 } 909 } 910 911 if (rootdev && RunningAsInit) { 912 /* Next, create and/or mount the root device */ 913 sprintf(dname, "/dev/r%s", rootdev->name); 914 if (!Fake && (!MakeDevChunk(rootdev, "/dev") || !file_readable(dname))) { 915 msgConfirm("Unable to make device node for %s in /dev!\n" 916 "The creation of filesystems will be aborted.", dname); 917 return DITEM_FAILURE; 918 } 919 if (strcmp(root->mountpoint, "/")) 920 msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, root->mountpoint); 921 922 if (root->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs the root partition?"))) { 923 int i; 924 925 msgNotify("Making a new root filesystem on %s", dname); 926 i = vsystem("%s %s", root->newfs_cmd, dname); 927 if (i) { 928 msgConfirm("Unable to make new root filesystem on %s!\n" 929 "Command returned status %d", dname, i); 930 return DITEM_FAILURE; 931 } 932 } 933 else { 934 if (!upgrade) { 935 msgConfirm("Warning: Using existing root partition. It will be assumed\n" 936 "that you have the appropriate device entries already in /dev."); 937 } 938 msgNotify("Checking integrity of existing %s filesystem.", dname); 939 i = vsystem("fsck -y %s", dname); 940 if (i) 941 msgConfirm("Warning: fsck returned status of %d for %s.\n" 942 "This partition may be unsafe to use.", i, dname); 943 } 944 945 /* Switch to block device */ 946 sprintf(dname, "/dev/%s", rootdev->name); 947 if (Mount("/mnt", dname)) { 948 msgConfirm("Unable to mount the root file system on %s! Giving up.", dname); 949 return DITEM_FAILURE; 950 } 951 } 952 953 /* Now buzz through the rest of the partitions and mount them too */ 954 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 955 for (i = 0; devs[i]; i++) { 956 if (!devs[i]->enabled) 957 continue; 958 959 disk = (Disk *)devs[i]->private; 960 if (!disk->chunks) { 961 msgConfirm("No chunk list found for %s!", disk->name); 962 return DITEM_FAILURE; 963 } 964 if (RunningAsInit && root && (root->newfs || upgrade)) { 965 Mkdir("/mnt/dev"); 966 if (!Fake) 967 MakeDevDisk(disk, "/mnt/dev"); 968 } 969 else if (!RunningAsInit && !Fake) 970 MakeDevDisk(disk, "/dev"); 971 972 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 973 if (c1->type == freebsd) { 974 for (c2 = c1->part; c2; c2 = c2->next) { 975 if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { 976 PartInfo *tmp = (PartInfo *)c2->private_data; 977 978 /* Already did root */ 979 if (c2 == rootdev) 980 continue; 981 982 if (tmp->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name))) 983 command_shell_add(tmp->mountpoint, "%s %s/dev/r%s", tmp->newfs_cmd, RunningAsInit ? "/mnt" : "", c2->name); 984 else 985 command_shell_add(tmp->mountpoint, "fsck -y %s/dev/r%s", RunningAsInit ? "/mnt" : "", c2->name); 986 command_func_add(tmp->mountpoint, Mount, c2->name); 987 } 988 else if (c2->type == part && c2->subtype == FS_SWAP) { 989 char fname[80]; 990 int i; 991 992 if (c2 == swapdev) 993 continue; 994 sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); 995 i = (Fake || swapon(fname)); 996 if (!i) 997 msgNotify("Added %s as an additional swap device", fname); 998 else 999 msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); 1000 } 1001 } 1002 } 1003 else if (c1->type == fat && c1->private_data && (root->newfs || upgrade)) { 1004 char name[FILENAME_MAX]; 1005 1006 sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint); 1007 Mkdir(name); 1008 } 1009 } 1010 } 1011 1012 if (RunningAsInit) { 1013 msgNotify("Copying initial device files.."); 1014 /* Copy the boot floppy's dev files */ 1015 if ((root->newfs || upgrade) && vsystem("find -x /dev | cpio %s -pdum /mnt", cpioVerbosity())) { 1016 msgConfirm("Couldn't clone the /dev files!"); 1017 return DITEM_FAILURE; 1018 } 1019 } 1020 1021 command_sort(); 1022 command_execute(); 1023 return DITEM_SUCCESS; 1024} 1025 1026static char * 1027getRelname(void) 1028{ 1029 static char buf[64]; 1030 int sz = (sizeof buf) - 1; 1031 1032 if (sysctlbyname("kern.osrelease", buf, &sz, NULL, 0) != -1) { 1033 buf[sz] = '\0'; 1034 return buf; 1035 } 1036 else 1037 return "<unknown>"; 1038} 1039 1040/* Initialize various user-settable values to their defaults */ 1041int 1042installVarDefaults(dialogMenuItem *self) 1043{ 1044 char *cp; 1045 1046 /* Set default startup options */ 1047 variable_set2(VAR_RELNAME, getRelname(), 0); 1048 variable_set2(VAR_CPIO_VERBOSITY, "high", 0); 1049 variable_set2(VAR_TAPE_BLOCKSIZE, DEFAULT_TAPE_BLOCKSIZE, 0); 1050 variable_set2(VAR_INSTALL_ROOT, "/", 0); 1051 variable_set2(VAR_INSTALL_CFG, "install.cfg", 0); 1052 cp = getenv("EDITOR"); 1053 if (!cp) 1054 cp = "/usr/bin/ee"; 1055 variable_set2(VAR_EDITOR, cp, 0); 1056 variable_set2(VAR_FTP_USER, "ftp", 0); 1057 variable_set2(VAR_BROWSER_PACKAGE, "lynx", 0); 1058 variable_set2(VAR_BROWSER_BINARY, "/usr/local/bin/lynx", 0); 1059 variable_set2(VAR_FTP_STATE, "passive", 0); 1060 variable_set2(VAR_NFS_SECURE, "YES", 0); 1061 variable_set2(VAR_PKG_TMPDIR, "/usr/tmp", 0); 1062 variable_set2(VAR_GATED_PKG, "gated", 0); 1063 variable_set2(VAR_PCNFSD_PKG, "pcnfsd", 0); 1064 variable_set2(VAR_MEDIA_TIMEOUT, itoa(MEDIA_TIMEOUT), 0); 1065 if (getpid() != 1) 1066 variable_set2(SYSTEM_STATE, "update", 0); 1067 else 1068 variable_set2(SYSTEM_STATE, "init", 0); 1069 return DITEM_SUCCESS; 1070} 1071 1072/* Load the environment up from various system configuration files */ 1073void 1074installEnvironment(void) 1075{ 1076 configEnvironmentRC_conf(); 1077 if (file_readable("/etc/resolv.conf")) 1078 configEnvironmentResolv("/etc/resolv.conf"); 1079} 1080 1081/* Copy the boot floppy contents into /stand */ 1082Boolean 1083copySelf(void) 1084{ 1085 int i; 1086 1087 if (file_readable("/boot.help")) 1088 vsystem("cp /boot.help /mnt"); 1089 msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); 1090 i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); 1091 if (i) { 1092 msgConfirm("Copy returned error status of %d!", i); 1093 return FALSE; 1094 } 1095 1096 /* Copy the /etc files into their rightful place */ 1097 if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) { 1098 msgConfirm("Couldn't copy up the /etc files!"); 1099 return TRUE; 1100 } 1101 return TRUE; 1102} 1103 1104static void 1105create_termcap(void) 1106{ 1107 FILE *fp; 1108 1109 const char *caps[] = { 1110 termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r, 1111 termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m, NULL, 1112 }; 1113 const char **cp; 1114 1115 if (!file_readable(TERMCAP_FILE)) { 1116 Mkdir("/usr/share/misc"); 1117 fp = fopen(TERMCAP_FILE, "w"); 1118 if (!fp) { 1119 msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work."); 1120 return; 1121 } 1122 cp = caps; 1123 while (*cp) 1124 fprintf(fp, "%s\n", *(cp++)); 1125 fclose(fp); 1126 } 1127} 1128