install.c revision 8727
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.51 1995/05/24 09:00: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 * 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 void 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; 133 134 if (!getenv(DISK_PARTITIONED)) { 135 msgConfirm("You need to partition your disk before you can proceed with\nthe installation."); 136 return; 137 } 138 if (!getenv(DISK_LABELLED)) { 139 msgConfirm("You need to assign disk labels before you can proceed with\nthe installation."); 140 return; 141 } 142 if (!checkLabels()) 143 return; 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; 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} 202 203static void 204installFinal(void) 205{ 206 static Boolean alreadyDone = FALSE; 207 208 if (alreadyDone) 209 return; 210 configFstab(); 211 configSysconfig(); 212 configResolv(); 213 alreadyDone = TRUE; 214 SystemWasInstalled = TRUE; 215} 216 217/* 218 * What happens when we select "GO". This is broken into a 3 stage installation so that 219 * the user can do a full installation but come back here again to load more distributions, 220 * perhaps from a different media type. This would allow, for example, the user to load the 221 * majority of the system from CDROM and then use ftp to load just the DES dist. 222 */ 223int 224installCommit(char *str) 225{ 226 if (!Dists) { 227 msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu."); 228 return 0; 229 } 230 if (!mediaVerify()) 231 return 0; 232 233 installInitial(); 234 distExtractAll(); 235 installFinal(); 236 return 0; 237} 238 239/* Go newfs and/or mount all the filesystems we've been asked to */ 240static void 241make_filesystems(void) 242{ 243 int i; 244 Disk *disk; 245 Chunk *c1, *c2; 246 Device **devs; 247 char dname[40]; 248 PartInfo *p = (PartInfo *)rootdev->private; 249 250 command_clear(); 251 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 252 253 /* First, create and mount the root device */ 254 if (strcmp(p->mountpoint, "/")) 255 msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, p->mountpoint); 256 257 if (p->newfs) { 258 int i; 259 260 sprintf(dname, "/dev/r%sa", rootdisk->name); 261 msgNotify("Making a new root filesystem on %s", dname); 262 i = vsystem("%s %s", p->newfs_cmd, dname); 263 if (i) { 264 msgConfirm("Unable to make new root filesystem! Command returned status %d", i); 265 return; 266 } 267 } 268 else { 269 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."); 270 sprintf(dname, "/dev/r%sa", rootdisk->name); 271 msgNotify("Checking integrity of existing %s filesystem", dname); 272 i = vsystem("fsck -y %s", dname); 273 if (i) 274 msgConfirm("Warning: fsck returned status off %d - this partition may be\nunsafe to use.", i); 275 } 276 sprintf(dname, "/dev/%sa", rootdisk->name); 277 if (Mount("/mnt", dname)) { 278 msgConfirm("Unable to mount the root file system! Giving up."); 279 return; 280 } 281 else { 282 extern int makedevs(void); 283 284 msgNotify("Making device files"); 285 if (Mkdir("/mnt/dev", NULL) || chdir("/mnt/dev") || makedevs()) 286 msgConfirm("Failed to make some of the devices in /mnt!"); 287 if (Mkdir("/mnt/stand", NULL)) { 288 msgConfirm("Unable to make /mnt/stand directory!"); 289 return; 290 } 291 chdir("/"); 292 } 293 294 /* Now buzz through the rest of the partitions and mount them too */ 295 for (i = 0; devs[i]; i++) { 296 disk = (Disk *)devs[i]->private; 297 if (!disk->chunks) 298 msgFatal("No chunk list found for %s!", disk->name); 299 300 /* Make the proper device mount points in /mnt/dev */ 301 MakeDevDisk(disk, "/mnt/dev"); 302 303 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 304 if (c1->type == freebsd) { 305 for (c2 = c1->part; c2; c2 = c2->next) { 306 if (c2->type == part && c2->subtype != FS_SWAP && c2->private) { 307 PartInfo *tmp = (PartInfo *)c2->private; 308 309 if (!strcmp(tmp->mountpoint, "/")) 310 continue; 311 312 if (tmp->newfs) 313 command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name); 314 else 315 command_shell_add(tmp->mountpoint, "fsck -y /mnt/dev/r%s", c2->name); 316 command_func_add(tmp->mountpoint, Mount, c2->name); 317 } 318 else if (c2->type == part && c2->subtype == FS_SWAP) { 319 char fname[80]; 320 int i; 321 322 sprintf(fname, "/mnt/dev/%s", c2->name); 323 i = swapon(fname); 324 if (!i) 325 msgNotify("Added %s as a swap device", fname); 326 else 327 msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); 328 } 329 } 330 } 331 else if (c1->type == fat) { 332 PartInfo *tmp = (PartInfo *)c1->private; 333 334 if (!tmp) 335 continue; 336 command_func_add(tmp->mountpoint, Mount, c1->name); 337 } 338 } 339 } 340 command_sort(); 341 command_execute(); 342} 343 344/* Copy the boot floppy contents into /stand */ 345static void 346copy_self(void) 347{ 348 int i; 349 350 msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); 351 i = vsystem("find -x /stand | cpio -pdmv /mnt"); 352 if (i) 353 msgConfirm("Copy returned error status of %d!", i); 354} 355 356static Device *floppyDev; 357 358static int 359floppyChoiceHook(char *str) 360{ 361 Device **devs; 362 363 /* Clip garbage off the ends */ 364 string_prune(str); 365 str = string_skipwhite(str); 366 if (!*str) 367 return 0; 368 devs = deviceFind(str, DEVICE_TYPE_FLOPPY); 369 if (devs) 370 floppyDev = devs[0]; 371 return devs ? 1 : 0; 372} 373 374static void 375cpio_extract(void) 376{ 377 int i, j, zpid, cpid, pfd[2]; 378 Boolean onCDROM = FALSE; 379 380 if (mediaDevice && mediaDevice->type == DEVICE_TYPE_CDROM) { 381 if (mediaDevice->init) { 382 if ((*mediaDevice->init)(mediaDevice)) { 383 CpioFD = open("/cdrom/floppies/cpio.flp", O_RDONLY); 384 if (CpioFD != -1) { 385 msgNotify("Loading CPIO floppy from CDROM"); 386 onCDROM = TRUE; 387 } 388 } 389 } 390 } 391 392 tryagain: 393 while (CpioFD == -1) { 394 if (!floppyDev) { 395 Device **devs; 396 int cnt; 397 398 devs = deviceFind(NULL, DEVICE_TYPE_FLOPPY); 399 cnt = deviceCount(devs); 400 if (cnt == 1) 401 floppyDev = devs[0]; 402 else if (cnt > 1) { 403 DMenu *menu; 404 405 menu = deviceCreateMenu(&MenuMediaFloppy, DEVICE_TYPE_FLOPPY, floppyChoiceHook); 406 dmenuOpenSimple(menu); 407 } 408 else { 409 msgConfirm("No floppy devices found! Something is seriously wrong!"); 410 return; 411 } 412 if (!floppyDev) 413 continue; 414 } 415 msgConfirm("Please Insert CPIO floppy in %s", floppyDev->description); 416 CpioFD = open(floppyDev->devname, O_RDONLY); 417 if (CpioFD >= 0) 418 break; 419 msgDebug("Error on open of cpio floppy: %s (%d)\n", strerror(errno), errno); 420 } 421 j = fork(); 422 if (!j) { 423 chdir("/"); 424 msgWeHaveOutput("Extracting contents of CPIO floppy..."); 425 pipe(pfd); 426 zpid = fork(); 427 if (!zpid) { 428 dup2(CpioFD, 0); close(CpioFD); 429 dup2(pfd[1], 1); close(pfd[1]); 430 if (DebugFD != -1) 431 dup2(DebugFD, 2); 432 close(pfd[0]); 433 i = execl("/stand/gunzip", "/stand/gunzip", 0); 434 msgDebug("/stand/gunzip command returns %d status\n", i); 435 exit(i); 436 } 437 cpid = fork(); 438 if (!cpid) { 439 dup2(pfd[0], 0); close(pfd[0]); 440 close(CpioFD); 441 close(pfd[1]); 442 if (DebugFD != -1) { 443 dup2(DebugFD, 1); 444 dup2(DebugFD, 2); 445 } 446 else { 447 close(1); open("/dev/null", O_WRONLY); 448 dup2(1, 2); 449 } 450 i = execl("/stand/cpio", "/stand/cpio", "-iduvm", 0); 451 msgDebug("/stand/cpio command returns %d status\n", i); 452 exit(i); 453 } 454 close(pfd[0]); 455 close(pfd[1]); 456 close(CpioFD); 457 458 i = waitpid(zpid, &j, 0); 459 if (i < 0) { /* Don't check status - gunzip seems to return a bogus one! */ 460 dialog_clear(); 461 msgConfirm("wait for gunzip returned status of %d!", i); 462 exit(1); 463 } 464 i = waitpid(cpid, &j, 0); 465 if (i < 0 || WEXITSTATUS(j)) { 466 dialog_clear(); 467 msgConfirm("cpio returned error status of %d!", WEXITSTATUS(j)); 468 exit(2); 469 } 470 exit(0); 471 } 472 else 473 i = wait(&j); 474 if (i < 0 || WEXITSTATUS(j) || access("/OK", R_OK) == -1) { 475 dialog_clear(); 476 msgConfirm("CPIO floppy did not extract properly! Please verify\nthat your media is correct and try again."); 477 close(CpioFD); 478 CpioFD = -1; 479 goto tryagain; 480 } 481 unlink("/OK"); 482 if (!onCDROM) 483 msgConfirm("Please remove the CPIO floppy from the drive"); 484} 485