install.c revision 8771
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.59 1995/05/26 10:32: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/ioctl.h> 48#include <sys/fcntl.h> 49#include <sys/wait.h> 50#include <unistd.h> 51 52Boolean SystemWasInstalled; 53 54static void make_filesystems(void); 55static void copy_self(void); 56static void root_extract(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 Boolean 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 TRUE; 134 135 if (!getenv(DISK_PARTITIONED)) { 136 msgConfirm("You need to partition your disk before you can proceed with\nthe installation."); 137 return FALSE; 138 } 139 if (!getenv(DISK_LABELLED)) { 140 msgConfirm("You need to assign disk labels before you can proceed with\nthe installation."); 141 return FALSE; 142 } 143 if (!checkLabels()) 144 return FALSE; 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 FALSE; 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 /* If we're running as init, stick a shell over on the 4th VTY */ 201 if (RunningAsInit && !fork()) { 202 int i, fd; 203 204 for (i = 0; i < 64; i++) 205 close(i); 206 fd = open("/dev/ttyv3", O_RDWR); 207 ioctl(0, TIOCSCTTY, &fd); 208 dup2(0, 1); 209 dup2(0, 2); 210 execlp("sh", "-sh", 0); 211 exit(1); 212 } 213 root_extract(); 214 vsystem("(cd /stand; find etc | cpio -o) | (cd /; cpio -idmv)"); 215 alreadyDone = TRUE; 216 return TRUE; 217} 218 219static void 220installFinal(void) 221{ 222 static Boolean alreadyDone = FALSE; 223 FILE *fp; 224 225 if (alreadyDone) 226 return; 227 configFstab(); 228 configSysconfig(); 229 configResolv(); 230 231 /* Tack ourselves at the end of /etc/hosts */ 232 if (getenv(VAR_IPADDR)) { 233 fp = fopen("/etc/hosts", "a"); 234 fprintf(fp, "%s\t\t%s\n", getenv(VAR_IPADDR), getenv(VAR_HOSTNAME)); 235 fclose(fp); 236 } 237 alreadyDone = TRUE; 238 msgConfirm("Installation completed successfully.\nHit return now to go back to the main menu."); 239 SystemWasInstalled = TRUE; 240} 241 242/* 243 * What happens when we select "GO". This is broken into a 3 stage installation so that 244 * the user can do a full installation but come back here again to load more distributions, 245 * perhaps from a different media type. This would allow, for example, the user to load the 246 * majority of the system from CDROM and then use ftp to load just the DES dist. 247 */ 248int 249installCommit(char *str) 250{ 251 if (!Dists) { 252 msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu."); 253 return 0; 254 } 255 if (!mediaVerify()) 256 return 0; 257 258 if (!installInitial()) 259 return 0; 260 distExtractAll(); 261 installFinal(); 262 return 0; 263} 264 265/* Go newfs and/or mount all the filesystems we've been asked to */ 266static void 267make_filesystems(void) 268{ 269 int i; 270 Disk *disk; 271 Chunk *c1, *c2; 272 Device **devs; 273 char dname[40]; 274 PartInfo *p = (PartInfo *)rootdev->private; 275 276 command_clear(); 277 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 278 279 /* First, create and mount the root device */ 280 if (strcmp(p->mountpoint, "/")) 281 msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, p->mountpoint); 282 283 if (p->newfs) { 284 int i; 285 286 sprintf(dname, "/dev/r%sa", rootdisk->name); 287 msgNotify("Making a new root filesystem on %s", dname); 288 i = vsystem("%s %s", p->newfs_cmd, dname); 289 if (i) { 290 msgConfirm("Unable to make new root filesystem! Command returned status %d", i); 291 return; 292 } 293 } 294 else { 295 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."); 296 sprintf(dname, "/dev/r%sa", rootdisk->name); 297 msgNotify("Checking integrity of existing %s filesystem", dname); 298 i = vsystem("fsck -y %s", dname); 299 if (i) 300 msgConfirm("Warning: fsck returned status off %d - this partition may be\nunsafe to use.", i); 301 } 302 sprintf(dname, "/dev/%sa", rootdisk->name); 303 if (Mount("/mnt", dname)) { 304 msgConfirm("Unable to mount the root file system! Giving up."); 305 return; 306 } 307 else { 308 extern int makedevs(void); 309 310 msgNotify("Making device files"); 311 if (Mkdir("/mnt/dev", NULL) || chdir("/mnt/dev") || makedevs()) 312 msgConfirm("Failed to make some of the devices in /mnt!"); 313 if (Mkdir("/mnt/stand", NULL)) { 314 msgConfirm("Unable to make /mnt/stand directory!"); 315 return; 316 } 317 chdir("/"); 318 } 319 320 /* Now buzz through the rest of the partitions and mount them too */ 321 for (i = 0; devs[i]; i++) { 322 disk = (Disk *)devs[i]->private; 323 if (!disk->chunks) 324 msgFatal("No chunk list found for %s!", disk->name); 325 326 /* Make the proper device mount points in /mnt/dev */ 327 MakeDevDisk(disk, "/mnt/dev"); 328 329 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 330 if (c1->type == freebsd) { 331 for (c2 = c1->part; c2; c2 = c2->next) { 332 if (c2->type == part && c2->subtype != FS_SWAP && c2->private) { 333 PartInfo *tmp = (PartInfo *)c2->private; 334 335 if (!strcmp(tmp->mountpoint, "/")) 336 continue; 337 338 if (tmp->newfs) 339 command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name); 340 else 341 command_shell_add(tmp->mountpoint, "fsck -y /mnt/dev/r%s", c2->name); 342 command_func_add(tmp->mountpoint, Mount, c2->name); 343 } 344 else if (c2->type == part && c2->subtype == FS_SWAP) { 345 char fname[80]; 346 int i; 347 348 sprintf(fname, "/mnt/dev/%s", c2->name); 349 i = swapon(fname); 350 if (!i) 351 msgNotify("Added %s as a swap device", fname); 352 else 353 msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); 354 } 355 } 356 } 357 else if (c1->type == fat) { 358 PartInfo *tmp = (PartInfo *)c1->private; 359 360 if (!tmp) 361 continue; 362 command_func_add(tmp->mountpoint, Mount_DOS, c1->name); 363 } 364 } 365 } 366 command_sort(); 367 command_execute(); 368} 369 370/* Copy the boot floppy contents into /stand */ 371static void 372copy_self(void) 373{ 374 int i; 375 376 msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); 377 i = vsystem("find -x /stand | cpio -pdmv /mnt"); 378 if (i) 379 msgConfirm("Copy returned error status of %d!", i); 380 /* copy up the etc files */ 381 (void)vsystem("(cd /mnt/stand; find etc) | cpio -pdmv /mnt"); 382} 383 384static void loop_on_root_floppy(); 385 386static void 387root_extract(void) 388{ 389 int fd, status; 390 391 if (OnCDROM) { 392 fd = open("/floppies/root.flp", O_RDONLY); 393 mediaExtractDist("root.flp", "/", fd); 394 return; 395 } 396 if (mediaDevice) { 397 switch(mediaDevice->type) { 398 399 case DEVICE_TYPE_DOS: 400 case DEVICE_TYPE_FTP: 401 case DEVICE_TYPE_DISK: 402 case DEVICE_TYPE_NETWORK: 403 case DEVICE_TYPE_CDROM: 404 if (mediaDevice->init) 405 if (!(*mediaDevice->init)(mediaDevice)) 406 break; 407 fd = (*mediaDevice->get)("root.flp", "floppies/"); 408 if (fd != -1) { 409 msgNotify("Loading root floppy from %s", mediaDevice->name); 410 status = mediaExtractDist("root.flp", "/", fd); 411 if (mediaDevice->close) 412 (*mediaDevice->close)(mediaDevice, fd); 413 else 414 close(fd); 415 } 416 break; 417 418 case DEVICE_TYPE_FLOPPY: 419 default: 420 loop_on_root_floppy(); 421 break; 422 } 423 } 424 else 425 loop_on_root_floppy(); 426} 427 428static void 429loop_on_root_floppy(void) 430{ 431 int fd; 432 433 mediaDevice = NULL; 434 fd = genericGetDist("root.flp", NULL, TRUE); 435 if (fd == -1) 436 return; 437 mediaExtractDist("root.flp", "/", fd); 438} 439