install.c revision 8739
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.52 1995/05/24 17:49:16 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 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by Jordan Hubbard 25 * for the FreeBSD Project. 26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to 27 * endorse or promote products derived from this software without specific 28 * prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 */ 43 44#include "sysinstall.h" 45#include <sys/disklabel.h> 46#include <sys/errno.h> 47#include <sys/fcntl.h> 48#include <sys/wait.h> 49#include <unistd.h> 50 51Boolean SystemWasInstalled; 52 53static void make_filesystems(void); 54static void copy_self(void); 55static void cpio_extract(void); 56 57static Disk *rootdisk; 58static Chunk *rootdev; 59 60static Boolean 61checkLabels(void) 62{ 63 Device **devs; 64 Disk *disk; 65 Chunk *c1, *c2, *swapdev = NULL; 66 int i; 67 68 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 69 /* First verify that we have a root device */ 70 for (i = 0; devs[i]; i++) { 71 if (!devs[i]->enabled) 72 continue; 73 disk = (Disk *)devs[i]->private; 74 msgDebug("Scanning disk %s for root filesystem\n", disk->name); 75 if (!disk->chunks) 76 msgFatal("No chunk list found for %s!", disk->name); 77 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 78 if (c1->type == freebsd) { 79 for (c2 = c1->part; c2; c2 = c2->next) { 80 if (c2->type == part && c2->subtype != FS_SWAP && 81 c2->private && c2->flags & CHUNK_IS_ROOT) { 82 rootdisk = disk; 83 rootdev = c2; 84 break; 85 } 86 } 87 } 88 } 89 } 90 91 /* Now check for swap devices */ 92 for (i = 0; devs[i]; i++) { 93 disk = (Disk *)devs[i]->private; 94 msgDebug("Scanning disk %s for swap partitions\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) { 101 swapdev = c2; 102 break; 103 } 104 } 105 } 106 } 107 } 108 109 if (!rootdev) { 110 msgConfirm("No root device found - you must label a partition as /\n in the label editor."); 111 return FALSE; 112 } 113 if (!swapdev) { 114 msgConfirm("No swap devices found - you must create at least one\nswap partition."); 115 return FALSE; 116 } 117 return TRUE; 118} 119 120static Boolean 121installInitial(void) 122{ 123 extern u_char boot1[], boot2[]; 124 extern u_char mbr[], bteasy17[]; 125 u_char *mbrContents; 126 Device **devs; 127 int i; 128 static Boolean alreadyDone = FALSE; 129 char *cp; 130 131 if (alreadyDone) 132 return TRUE; 133 134 if (!getenv(DISK_PARTITIONED)) { 135 msgConfirm("You need to partition your disk before you can proceed with\nthe installation."); 136 return FALSE; 137 } 138 if (!getenv(DISK_LABELLED)) { 139 msgConfirm("You need to assign disk labels before you can proceed with\nthe installation."); 140 return FALSE; 141 } 142 if (!checkLabels()) 143 return FALSE; 144 145 /* Figure out what kind of MBR the user wants */ 146 dmenuOpenSimple(&MenuMBRType); 147 mbrContents = NULL; 148 cp = getenv("bootManager"); 149 if (cp) { 150 if (!strcmp(cp, "bteasy")) 151 mbrContents = bteasy17; 152 else if (!strcmp(cp, "mbr")) 153 mbrContents = mbr; 154 } 155 156 /* If we refuse to proceed, bail. */ 157 if (msgYesNo("Last Chance! Are you SURE you want continue the installation?\n\nIf you're running this on an existing system, we STRONGLY\nencourage you to make proper backups before proceeding.\nWe take no responsibility for lost disk contents!")) 158 return FALSE; 159 160 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 161 for (i = 0; devs[i]; i++) { 162 Chunk *c1; 163 Disk *d = (Disk *)devs[i]->private; 164 165 if (!devs[i]->enabled) 166 continue; 167 168 if (mbrContents) { 169 Set_Boot_Mgr(d, mbrContents); 170 mbrContents = NULL; 171 } 172 Set_Boot_Blocks(d, boot1, boot2); 173 msgNotify("Writing partition information to drive %s", d->name); 174 Write_Disk(d); 175 176 /* Now scan for bad blocks, if necessary */ 177 for (c1 = d->chunks->part; c1; c1 = c1->next) { 178 if (c1->flags & CHUNK_BAD144) { 179 int ret; 180 181 msgNotify("Running bad block scan on partition %s", c1->name); 182 ret = vsystem("bad144 -v /dev/r%s 1234", c1->name); 183 if (ret) 184 msgConfirm("Bad144 init on %s returned status of %d!", 185 c1->name, ret); 186 ret = vsystem("bad144 -v -s /dev/r%s", c1->name); 187 if (ret) 188 msgConfirm("Bad144 scan on %s returned status of %d!", 189 c1->name, ret); 190 } 191 } 192 } 193 make_filesystems(); 194 copy_self(); 195 dialog_clear(); 196 chroot("/mnt"); 197 chdir("/"); 198 variable_set2(RUNNING_ON_ROOT, "yes"); 199 cpio_extract(); 200 alreadyDone = TRUE; 201 return TRUE; 202} 203 204static void 205installFinal(void) 206{ 207 static Boolean alreadyDone = FALSE; 208 209 if (alreadyDone) 210 return; 211 configFstab(); 212 configSysconfig(); 213 configResolv(); 214 alreadyDone = TRUE; 215 SystemWasInstalled = TRUE; 216} 217 218/* 219 * What happens when we select "GO". This is broken into a 3 stage installation so that 220 * the user can do a full installation but come back here again to load more distributions, 221 * perhaps from a different media type. This would allow, for example, the user to load the 222 * majority of the system from CDROM and then use ftp to load just the DES dist. 223 */ 224int 225installCommit(char *str) 226{ 227 if (!Dists) { 228 msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu."); 229 return 0; 230 } 231 if (!mediaVerify()) 232 return 0; 233 234 if (!installInitial()) 235 return 0; 236 distExtractAll(); 237 installFinal(); 238 return 0; 239} 240 241/* Go newfs and/or mount all the filesystems we've been asked to */ 242static void 243make_filesystems(void) 244{ 245 int i; 246 Disk *disk; 247 Chunk *c1, *c2; 248 Device **devs; 249 char dname[40]; 250 PartInfo *p = (PartInfo *)rootdev->private; 251 252 command_clear(); 253 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 254 255 /* First, create and mount the root device */ 256 if (strcmp(p->mountpoint, "/")) 257 msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, p->mountpoint); 258 259 if (p->newfs) { 260 int i; 261 262 sprintf(dname, "/dev/r%sa", rootdisk->name); 263 msgNotify("Making a new root filesystem on %s", dname); 264 i = vsystem("%s %s", p->newfs_cmd, dname); 265 if (i) { 266 msgConfirm("Unable to make new root filesystem! Command returned status %d", i); 267 return; 268 } 269 } 270 else { 271 msgConfirm("Warning: You have selected a Read-Only root device\nand may be unable to find the appropriate device entries on it\nif it is from an older pre-slice version of FreeBSD."); 272 sprintf(dname, "/dev/r%sa", rootdisk->name); 273 msgNotify("Checking integrity of existing %s filesystem", dname); 274 i = vsystem("fsck -y %s", dname); 275 if (i) 276 msgConfirm("Warning: fsck returned status off %d - this partition may be\nunsafe to use.", i); 277 } 278 sprintf(dname, "/dev/%sa", rootdisk->name); 279 if (Mount("/mnt", dname)) { 280 msgConfirm("Unable to mount the root file system! Giving up."); 281 return; 282 } 283 else { 284 extern int makedevs(void); 285 286 msgNotify("Making device files"); 287 if (Mkdir("/mnt/dev", NULL) || chdir("/mnt/dev") || makedevs()) 288 msgConfirm("Failed to make some of the devices in /mnt!"); 289 if (Mkdir("/mnt/stand", NULL)) { 290 msgConfirm("Unable to make /mnt/stand directory!"); 291 return; 292 } 293 chdir("/"); 294 } 295 296 /* Now buzz through the rest of the partitions and mount them too */ 297 for (i = 0; devs[i]; i++) { 298 disk = (Disk *)devs[i]->private; 299 if (!disk->chunks) 300 msgFatal("No chunk list found for %s!", disk->name); 301 302 /* Make the proper device mount points in /mnt/dev */ 303 MakeDevDisk(disk, "/mnt/dev"); 304 305 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 306 if (c1->type == freebsd) { 307 for (c2 = c1->part; c2; c2 = c2->next) { 308 if (c2->type == part && c2->subtype != FS_SWAP && c2->private) { 309 PartInfo *tmp = (PartInfo *)c2->private; 310 311 if (!strcmp(tmp->mountpoint, "/")) 312 continue; 313 314 if (tmp->newfs) 315 command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name); 316 else 317 command_shell_add(tmp->mountpoint, "fsck -y /mnt/dev/r%s", c2->name); 318 command_func_add(tmp->mountpoint, Mount, c2->name); 319 } 320 else if (c2->type == part && c2->subtype == FS_SWAP) { 321 char fname[80]; 322 int i; 323 324 sprintf(fname, "/mnt/dev/%s", c2->name); 325 i = swapon(fname); 326 if (!i) 327 msgNotify("Added %s as a swap device", fname); 328 else 329 msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); 330 } 331 } 332 } 333 else if (c1->type == fat) { 334 PartInfo *tmp = (PartInfo *)c1->private; 335 336 if (!tmp) 337 continue; 338 command_func_add(tmp->mountpoint, Mount_DOS, c1->name); 339 } 340 } 341 } 342 command_sort(); 343 command_execute(); 344} 345 346/* Copy the boot floppy contents into /stand */ 347static void 348copy_self(void) 349{ 350 int i; 351 352 msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); 353 i = vsystem("find -x /stand | cpio -pdmv /mnt"); 354 if (i) 355 msgConfirm("Copy returned error status of %d!", i); 356} 357 358static Device *floppyDev; 359 360static int 361floppyChoiceHook(char *str) 362{ 363 Device **devs; 364 365 /* Clip garbage off the ends */ 366 string_prune(str); 367 str = string_skipwhite(str); 368 if (!*str) 369 return 0; 370 devs = deviceFind(str, DEVICE_TYPE_FLOPPY); 371 if (devs) 372 floppyDev = devs[0]; 373 return devs ? 1 : 0; 374} 375 376static void 377cpio_extract(void) 378{ 379 int i, j, zpid, cpid, pfd[2]; 380 Boolean onCDROM = FALSE; 381 382 if (mediaDevice && mediaDevice->type == DEVICE_TYPE_CDROM) { 383 if (mediaDevice->init) { 384 if ((*mediaDevice->init)(mediaDevice)) { 385 CpioFD = open("/cdrom/floppies/cpio.flp", O_RDONLY); 386 if (CpioFD != -1) { 387 msgNotify("Loading CPIO floppy from CDROM"); 388 onCDROM = TRUE; 389 } 390 } 391 } 392 } 393 394 tryagain: 395 while (CpioFD == -1) { 396 if (!floppyDev) { 397 Device **devs; 398 int cnt; 399 400 devs = deviceFind(NULL, DEVICE_TYPE_FLOPPY); 401 cnt = deviceCount(devs); 402 if (cnt == 1) 403 floppyDev = devs[0]; 404 else if (cnt > 1) { 405 DMenu *menu; 406 407 menu = deviceCreateMenu(&MenuMediaFloppy, DEVICE_TYPE_FLOPPY, floppyChoiceHook); 408 dmenuOpenSimple(menu); 409 } 410 else { 411 msgConfirm("No floppy devices found! Something is seriously wrong!"); 412 return; 413 } 414 if (!floppyDev) 415 continue; 416 } 417 msgConfirm("Please Insert CPIO floppy in %s", floppyDev->description); 418 CpioFD = open(floppyDev->devname, O_RDONLY); 419 if (CpioFD >= 0) 420 break; 421 msgDebug("Error on open of cpio floppy: %s (%d)\n", strerror(errno), errno); 422 } 423 j = fork(); 424 if (!j) { 425 chdir("/"); 426 msgWeHaveOutput("Extracting contents of CPIO floppy..."); 427 pipe(pfd); 428 zpid = fork(); 429 if (!zpid) { 430 dup2(CpioFD, 0); close(CpioFD); 431 dup2(pfd[1], 1); close(pfd[1]); 432 if (DebugFD != -1) 433 dup2(DebugFD, 2); 434 close(pfd[0]); 435 i = execl("/stand/gunzip", "/stand/gunzip", 0); 436 msgDebug("/stand/gunzip command returns %d status\n", i); 437 exit(i); 438 } 439 cpid = fork(); 440 if (!cpid) { 441 dup2(pfd[0], 0); close(pfd[0]); 442 close(CpioFD); 443 close(pfd[1]); 444 if (DebugFD != -1) { 445 dup2(DebugFD, 1); 446 dup2(DebugFD, 2); 447 } 448 else { 449 close(1); open("/dev/null", O_WRONLY); 450 dup2(1, 2); 451 } 452 i = execl("/stand/cpio", "/stand/cpio", "-iduvm", 0); 453 msgDebug("/stand/cpio command returns %d status\n", i); 454 exit(i); 455 } 456 close(pfd[0]); 457 close(pfd[1]); 458 close(CpioFD); 459 460 i = waitpid(zpid, &j, 0); 461 if (i < 0) { /* Don't check status - gunzip seems to return a bogus one! */ 462 dialog_clear(); 463 msgConfirm("wait for gunzip returned status of %d!", i); 464 exit(1); 465 } 466 i = waitpid(cpid, &j, 0); 467 if (i < 0 || WEXITSTATUS(j)) { 468 dialog_clear(); 469 msgConfirm("cpio returned error status of %d!", WEXITSTATUS(j)); 470 exit(2); 471 } 472 exit(0); 473 } 474 else 475 i = wait(&j); 476 if (i < 0 || WEXITSTATUS(j) || access("/OK", R_OK) == -1) { 477 dialog_clear(); 478 msgConfirm("CPIO floppy did not extract properly! Please verify\nthat your media is correct and try again."); 479 close(CpioFD); 480 CpioFD = -1; 481 goto tryagain; 482 } 483 unlink("/OK"); 484 if (!onCDROM) 485 msgConfirm("Please remove the CPIO floppy from the drive"); 486} 487