install.c revision 8715
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.49 1995/05/23 18:06:13 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); 56static void do_final_setup(void); 57 58static Disk *rootdisk; 59static Chunk *rootdev; 60 61static Boolean 62checkLabels(void) 63{ 64 Device **devs; 65 Disk *disk; 66 Chunk *c1, *c2, *swapdev = NULL; 67 int i; 68 69 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 70 /* First verify that we have a root device */ 71 for (i = 0; devs[i]; i++) { 72 if (!devs[i]->enabled) 73 continue; 74 disk = (Disk *)devs[i]->private; 75 msgDebug("Scanning disk %s for root filesystem\n", disk->name); 76 if (!disk->chunks) 77 msgFatal("No chunk list found for %s!", disk->name); 78 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 79 if (c1->type == freebsd) { 80 for (c2 = c1->part; c2; c2 = c2->next) { 81 if (c2->type == part && c2->subtype != FS_SWAP && 82 c2->private && c2->flags & CHUNK_IS_ROOT) { 83 rootdisk = disk; 84 rootdev = c2; 85 break; 86 } 87 } 88 } 89 } 90 } 91 92 /* Now check for swap devices */ 93 for (i = 0; devs[i]; i++) { 94 disk = (Disk *)devs[i]->private; 95 msgDebug("Scanning disk %s for swap partitions\n", disk->name); 96 if (!disk->chunks) 97 msgFatal("No chunk list found for %s!", disk->name); 98 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 99 if (c1->type == freebsd) { 100 for (c2 = c1->part; c2; c2 = c2->next) { 101 if (c2->type == part && c2->subtype == FS_SWAP) { 102 swapdev = c2; 103 break; 104 } 105 } 106 } 107 } 108 } 109 110 if (!rootdev) { 111 msgConfirm("No root device found - you must label a partition as /\n in the label editor."); 112 return FALSE; 113 } 114 if (!swapdev) { 115 msgConfirm("No swap devices found - you must create at least one\nswap partition."); 116 return FALSE; 117 } 118 return TRUE; 119} 120 121static void 122installInitial(void) 123{ 124 extern u_char boot1[], boot2[]; 125 extern u_char mbr[], bteasy17[]; 126 u_char *mbrContents; 127 Device **devs; 128 int i; 129 static Boolean alreadyDone = FALSE; 130 char *cp; 131 132 if (alreadyDone) 133 return; 134 135 if (!getenv(DISK_PARTITIONED)) { 136 msgConfirm("You need to partition your disk before you can proceed with\nthe installation."); 137 return; 138 } 139 if (!getenv(DISK_LABELLED)) { 140 msgConfirm("You need to assign disk labels before you can proceed with\nthe installation."); 141 return; 142 } 143 if (!checkLabels()) 144 return; 145 146 /* Figure out what kind of MBR the user wants */ 147 dmenuOpenSimple(&MenuMBRType); 148 mbrContents = NULL; 149 cp = getenv("bootManager"); 150 if (cp) { 151 if (!strcmp(cp, "bteasy")) 152 mbrContents = bteasy17; 153 else if (!strcmp(cp, "mbr")) 154 mbrContents = mbr; 155 } 156 157 /* If we refuse to proceed, bail. */ 158 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!")) 159 return; 160 161 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 162 for (i = 0; devs[i]; i++) { 163 Chunk *c1; 164 Disk *d = (Disk *)devs[i]->private; 165 166 if (!devs[i]->enabled) 167 continue; 168 169 if (mbrContents) { 170 Set_Boot_Mgr(d, mbrContents); 171 mbrContents = NULL; 172 } 173 Set_Boot_Blocks(d, boot1, boot2); 174 msgNotify("Writing partition information to drive %s", d->name); 175 Write_Disk(d); 176 177 /* Now scan for bad blocks, if necessary */ 178 for (c1 = d->chunks->part; c1; c1 = c1->next) { 179 if (c1->flags & CHUNK_BAD144) { 180 int ret; 181 182 msgNotify("Running bad block scan on partition %s", c1->name); 183 ret = vsystem("bad144 -v /dev/r%s 1234", c1->name); 184 if (ret) 185 msgConfirm("Bad144 init on %s returned status of %d!", 186 c1->name, ret); 187 ret = vsystem("bad144 -v -s /dev/r%s", c1->name); 188 if (ret) 189 msgConfirm("Bad144 scan on %s returned status of %d!", 190 c1->name, ret); 191 } 192 } 193 } 194 make_filesystems(); 195 copy_self(); 196 dialog_clear(); 197 chroot("/mnt"); 198 chdir("/"); 199 variable_set2(RUNNING_ON_ROOT, "yes"); 200 cpio_extract(); 201 alreadyDone = TRUE; 202} 203 204static void 205installFinal(void) 206{ 207 static Boolean alreadyDone = FALSE; 208 209 if (alreadyDone) 210 return; 211 config_fstab(); 212 config_sysconfig(); 213 config_resolv(); 214 do_final_setup(); 215 alreadyDone = TRUE; 216 SystemWasInstalled = TRUE; 217} 218 219/* 220 * What happens when we select "GO". This is broken into a 3 stage installation so that 221 * the user can do a full installation but come back here again to load more distributions, 222 * perhaps from a different media type. This would allow, for example, the user to load the 223 * majority of the system from CDROM and then use ftp to load just the DES dist. 224 */ 225int 226installCommit(char *str) 227{ 228 if (!Dists) { 229 msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu."); 230 return 0; 231 } 232 if (!mediaVerify()) 233 return 0; 234 235 installInitial(); 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/%sa", rootdisk->name); 273 if (Mount("/mnt", dname)) { 274 msgConfirm("Unable to mount the root file system! Giving up."); 275 return; 276 } 277 else { 278 extern int makedevs(void); 279 280 msgNotify("Making device files"); 281 if (Mkdir("/mnt/dev", NULL) || chdir("/mnt/dev") || makedevs()) 282 msgConfirm("Failed to make some of the devices in /mnt!"); 283 if (Mkdir("/mnt/stand", NULL)) { 284 msgConfirm("Unable to make /mnt/stand directory!"); 285 return; 286 } 287 chdir("/"); 288 } 289 290 /* Now buzz through the rest of the partitions and mount them too */ 291 for (i = 0; devs[i]; i++) { 292 disk = (Disk *)devs[i]->private; 293 if (!disk->chunks) 294 msgFatal("No chunk list found for %s!", disk->name); 295 296 /* Make the proper device mount points in /mnt/dev */ 297 MakeDevDisk(disk, "/mnt/dev"); 298 299 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 300 if (c1->type == freebsd) { 301 for (c2 = c1->part; c2; c2 = c2->next) { 302 if (c2->type == part && c2->subtype != FS_SWAP && c2->private) { 303 PartInfo *tmp = (PartInfo *)c2->private; 304 305 if (!strcmp(tmp->mountpoint, "/")) 306 continue; 307 308 if (tmp->newfs) 309 command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name); 310 command_func_add(tmp->mountpoint, Mount, c2->name); 311 } 312 else if (c2->type == part && c2->subtype == FS_SWAP) { 313 char fname[80]; 314 int i; 315 316 sprintf(fname, "/mnt/dev/%s", c2->name); 317 i = swapon(fname); 318 if (!i) 319 msgNotify("Added %s as a swap device", fname); 320 else 321 msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); 322 } 323 } 324 } 325 } 326 } 327 command_sort(); 328 command_execute(); 329} 330 331/* Copy the boot floppy contents into /stand */ 332static void 333copy_self(void) 334{ 335 int i; 336 337 msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); 338 i = vsystem("find -x /stand | cpio -pdmv /mnt"); 339 if (i) 340 msgConfirm("Copy returned error status of %d!", i); 341} 342 343static void 344cpio_extract(void) 345{ 346 int i, j, zpid, cpid, pfd[2]; 347 Boolean onCDROM = FALSE; 348 349#if 0 350 if (mediaDevice && mediaDevice->type == DEVICE_TYPE_CDROM) { 351 if (mediaDevice->init) { 352 if ((*mediaDevice->init)(mediaDevice)) { 353 CpioFD = open("/cdrom/floppies/cpio.flp", O_RDONLY); 354 if (CpioFD != -1) { 355 msgNotify("Loading CPIO floppy from CDROM"); 356 onCDROM = TRUE; 357 } 358 } 359 } 360 } 361#endif 362 tryagain: 363 while (CpioFD == -1) { 364 msgConfirm("Please Insert CPIO floppy in floppy drive 0"); 365 CpioFD = open("/dev/rfd0", O_RDONLY); 366 if (CpioFD >= 0) 367 break; 368 msgDebug("Error on open of cpio floppy: %s (%d)\n", strerror(errno), errno); 369 } 370 j = fork(); 371 if (!j) { 372 chdir("/"); 373 msgWeHaveOutput("Extracting contents of CPIO floppy..."); 374 pipe(pfd); 375 zpid = fork(); 376 if (!zpid) { 377 dup2(CpioFD, 0); close(CpioFD); 378 dup2(pfd[1], 1); close(pfd[1]); 379 if (DebugFD != -1) 380 dup2(DebugFD, 2); 381 close(pfd[0]); 382 i = execl("/stand/gunzip", "/stand/gunzip", 0); 383 msgDebug("/stand/gunzip command returns %d status\n", i); 384 exit(i); 385 } 386 cpid = fork(); 387 if (!cpid) { 388 dup2(pfd[0], 0); close(pfd[0]); 389 close(CpioFD); 390 close(pfd[1]); 391 if (DebugFD != -1) { 392 dup2(DebugFD, 1); 393 dup2(DebugFD, 2); 394 } 395 else { 396 close(1); open("/dev/null", O_WRONLY); 397 dup2(1, 2); 398 } 399 i = execl("/stand/cpio", "/stand/cpio", "-iduvm", 0); 400 msgDebug("/stand/cpio command returns %d status\n", i); 401 exit(i); 402 } 403 close(pfd[0]); 404 close(pfd[1]); 405 close(CpioFD); 406 407 i = waitpid(zpid, &j, 0); 408 if (i < 0) { /* Don't check status - gunzip seems to return a bogus one! */ 409 dialog_clear(); 410 msgConfirm("wait for gunzip returned status of %d!", i); 411 exit(1); 412 } 413 i = waitpid(cpid, &j, 0); 414 if (i < 0 || WEXITSTATUS(j)) { 415 dialog_clear(); 416 msgConfirm("cpio returned error status of %d!", WEXITSTATUS(j)); 417 exit(2); 418 } 419 exit(0); 420 } 421 else 422 i = wait(&j); 423 if (i < 0 || WEXITSTATUS(j) || access("/OK", R_OK) == -1) { 424 dialog_clear(); 425 msgConfirm("CPIO floppy did not extract properly! Please verify\nthat your media is correct and try again."); 426 close(CpioFD); 427 CpioFD = -1; 428 goto tryagain; 429 } 430 unlink("/OK"); 431 if (!onCDROM) 432 msgConfirm("Please remove the CPIO floppy from the drive"); 433} 434 435static void 436do_final_setup(void) 437{ 438 dmenuOpenSimple(&MenuConfigure); 439} 440