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