install.c revision 8868
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.68 1995/05/29 13:37:43 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 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 && c2->private && c2->flags & CHUNK_IS_ROOT) { 81 rootdev = c2; 82 break; 83 } 84 } 85 } 86 } 87 } 88 89 /* Now check for swap devices */ 90 for (i = 0; devs[i]; i++) { 91 disk = (Disk *)devs[i]->private; 92 msgDebug("Scanning disk %s for swap partitions\n", disk->name); 93 if (!disk->chunks) 94 msgFatal("No chunk list found for %s!", disk->name); 95 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 96 if (c1->type == freebsd) { 97 for (c2 = c1->part; c2; c2 = c2->next) { 98 if (c2->type == part && c2->subtype == FS_SWAP) { 99 swapdev = c2; 100 break; 101 } 102 } 103 } 104 } 105 } 106 107 if (!rootdev) { 108 msgConfirm("No root device found - you must label a partition as /\n in the label editor."); 109 return FALSE; 110 } 111 else if (rootdev->name[strlen(rootdev->name) - 1] != 'a') { 112 msgConfirm("Invalid placement of root partition. For now, we only support\nmounting root partitions on \"a\" partitions due to limitations\nin the FreeBSD boot block code. Please correct this and\ntry again."); 113 return FALSE; 114 } 115 if (!swapdev) { 116 msgConfirm("No swap devices found - you must create at least one\nswap partition."); 117 return FALSE; 118 } 119 return TRUE; 120} 121 122static Boolean 123installInitial(void) 124{ 125 extern u_char boot1[], boot2[]; 126 extern u_char mbr[], bteasy17[]; 127 u_char *mbrContents; 128 Device **devs; 129 int i; 130 static Boolean alreadyDone = FALSE; 131 char *cp; 132 133 if (alreadyDone) 134 return TRUE; 135 136 if (!getenv(DISK_PARTITIONED)) { 137 msgConfirm("You need to partition your disk before you can proceed with\nthe installation."); 138 return FALSE; 139 } 140 if (!getenv(DISK_LABELLED)) { 141 msgConfirm("You need to assign disk labels before you can proceed with\nthe installation."); 142 return FALSE; 143 } 144 if (!checkLabels()) 145 return FALSE; 146 147 /* Figure out what kind of MBR the user wants */ 148 dmenuOpenSimple(&MenuMBRType); 149 mbrContents = NULL; 150 cp = getenv("bootManager"); 151 if (cp) { 152 if (!strcmp(cp, "bteasy")) 153 mbrContents = bteasy17; 154 else if (!strcmp(cp, "mbr")) 155 mbrContents = mbr; 156 } 157 158 /* If we refuse to proceed, bail. */ 159 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!")) 160 return FALSE; 161 162 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 163 for (i = 0; devs[i]; i++) { 164 Chunk *c1; 165 Disk *d = (Disk *)devs[i]->private; 166 167 if (!devs[i]->enabled) 168 continue; 169 170 if (mbrContents) { 171 Set_Boot_Mgr(d, mbrContents); 172 mbrContents = NULL; 173 } 174 Set_Boot_Blocks(d, boot1, boot2); 175 msgNotify("Writing partition information to drive %s", d->name); 176 Write_Disk(d); 177 178 /* Now scan for bad blocks, if necessary */ 179 for (c1 = d->chunks->part; c1; c1 = c1->next) { 180 if (c1->flags & CHUNK_BAD144) { 181 int ret; 182 183 msgNotify("Running bad block scan on partition %s", c1->name); 184 ret = vsystem("bad144 -v /dev/r%s 1234", c1->name); 185 if (ret) 186 msgConfirm("Bad144 init on %s returned status of %d!", 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!", 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 /* stick a helpful shell over on the 4th VTY */ 200 msgDebug("Sticking a potentially helpful shell over on the 4th screen\n"); 201 if (!fork()) { 202 int i, fd; 203 extern int login_tty(int); 204 205 for (i = 0; i < 64; i++) 206 close(i); 207 fd = open("/dev/ttyv3", O_RDWR); 208 ioctl(0, TIOCSCTTY, &fd); 209 dup2(0, 1); 210 dup2(0, 2); 211 if (login_tty(fd)==-1) { 212 msgConfirm("Can't set controlling terminal"); 213 exit(1); 214 } 215 execlp("sh", "-sh", 0); 216 exit(1); 217 } 218 root_extract(); 219 alreadyDone = TRUE; 220 return TRUE; 221} 222 223/* 224 * What happens when we select "Install". This is broken into a 3 stage installation so that 225 * the user can do a full installation but come back here again to load more distributions, 226 * perhaps from a different media type. This would allow, for example, the user to load the 227 * majority of the system from CDROM and then use ftp to load just the DES dist. 228 */ 229int 230installCommit(char *str) 231{ 232 FILE *fp; 233 static Boolean hostsModified = FALSE; 234 235 if (!Dists) { 236 msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu."); 237 return 0; 238 } 239 if (!mediaVerify()) 240 return 0; 241 242 if (RunningAsInit) { 243 if (!installInitial()) 244 return 0; 245 configFstab(); 246 configResolv(); 247 } 248 distExtractAll(); 249 250 /* Tack ourselves at the end of /etc/hosts */ 251 if (RunningAsInit && getenv(VAR_IPADDR) && !hostsModified) { 252 fp = fopen("/etc/hosts", "a"); 253 fprintf(fp, "%s\t\t%s\n", getenv(VAR_IPADDR), getenv(VAR_HOSTNAME)); 254 fclose(fp); 255 hostsModified = TRUE; 256 } 257 /* If there's no kernel but there is a kernel.GENERIC, link it over */ 258 if (access("/kernel", R_OK)) 259 vsystem("ln -f /kernel.GENERIC /kernel"); 260 261 msgConfirm("Installation completed successfully.\nHit return now to go back to the main menu."); 262 SystemWasInstalled = TRUE; 263 return 0; 264} 265 266/* Go newfs and/or mount all the filesystems we've been asked to */ 267static void 268make_filesystems(void) 269{ 270 int i; 271 Disk *disk; 272 Chunk *c1, *c2; 273 Device **devs; 274 char dname[40]; 275 PartInfo *p = (PartInfo *)rootdev->private; 276 277 command_clear(); 278 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 279 280 /* First, create and mount the root device */ 281 if (strcmp(p->mountpoint, "/")) 282 msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, p->mountpoint); 283 284 if (p->newfs) { 285 int i; 286 287 sprintf(dname, "/dev/r%sa", rootdev->disk->name); 288 msgNotify("Making a new root filesystem on %s", dname); 289 i = vsystem("%s %s", p->newfs_cmd, dname); 290 if (i) { 291 msgConfirm("Unable to make new root filesystem! Command returned status %d", i); 292 return; 293 } 294 } 295 else { 296 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."); 297 sprintf(dname, "/dev/r%sa", rootdev->disk->name); 298 msgNotify("Checking integrity of existing %s filesystem", dname); 299 i = vsystem("fsck -y %s", dname); 300 if (i) 301 msgConfirm("Warning: fsck returned status off %d - this partition may be\nunsafe to use.", i); 302 } 303 sprintf(dname, "/dev/%sa", rootdev->disk->name); 304 if (Mount("/mnt", dname)) { 305 msgConfirm("Unable to mount the root file system! Giving up."); 306 return; 307 } 308 else { 309 extern int makedevs(void); 310 311 msgNotify("Making device files"); 312 if (Mkdir("/mnt/dev", NULL) || chdir("/mnt/dev") || makedevs()) 313 msgConfirm("Failed to make some of the devices in /mnt!"); 314 if (Mkdir("/mnt/stand", NULL)) { 315 msgConfirm("Unable to make /mnt/stand directory!"); 316 return; 317 } 318 chdir("/"); 319 } 320 321 /* Now buzz through the rest of the partitions and mount them too */ 322 for (i = 0; devs[i]; i++) { 323 if (!devs[i]->enabled) 324 continue; 325 326 disk = (Disk *)devs[i]->private; 327 if (!disk->chunks) 328 msgFatal("No chunk list found for %s!", disk->name); 329 330 /* Make the proper device mount points in /mnt/dev */ 331 MakeDevDisk(disk, "/mnt/dev"); 332 333 for (c1 = disk->chunks->part; c1; c1 = c1->next) { 334 if (c1->type == freebsd) { 335 for (c2 = c1->part; c2; c2 = c2->next) { 336 if (c2->type == part && c2->subtype != FS_SWAP && c2->private) { 337 PartInfo *tmp = (PartInfo *)c2->private; 338 339 if (!strcmp(tmp->mountpoint, "/")) 340 continue; 341 342 if (tmp->newfs) 343 command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name); 344 else 345 command_shell_add(tmp->mountpoint, "fsck -y /mnt/dev/r%s", c2->name); 346 command_func_add(tmp->mountpoint, Mount, c2->name); 347 } 348 else if (c2->type == part && c2->subtype == FS_SWAP) { 349 char fname[80]; 350 int i; 351 352 sprintf(fname, "/mnt/dev/%s", c2->name); 353 i = swapon(fname); 354 if (!i) 355 msgNotify("Added %s as a swap device", fname); 356 else 357 msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); 358 } 359 } 360 } 361 else if (c1->type == fat) { 362 PartInfo *tmp = (PartInfo *)c1->private; 363 364 if (!tmp) 365 continue; 366 command_func_add(tmp->mountpoint, Mount_DOS, c1->name); 367 } 368 } 369 } 370 command_sort(); 371 command_execute(); 372} 373 374/* Copy the boot floppy contents into /stand */ 375static void 376copy_self(void) 377{ 378 int i; 379 380 msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); 381 i = vsystem("find -x /stand | cpio -pdmV /mnt"); 382 if (i) 383 msgConfirm("Copy returned error status of %d!", i); 384 385 /* Copy the /etc files into their rightful place */ 386 (void)vsystem("cd /mnt/stand; find etc | cpio -pdmv /mnt"); 387} 388 389static void loop_on_root_floppy(); 390 391static void 392root_extract(void) 393{ 394 int fd; 395 396 if (OnCDROM) { 397 fd = open("/floppies/root.flp", O_RDONLY); 398 (void)mediaExtractDist("/", fd); 399 return; 400 } 401 if (mediaDevice) { 402 switch(mediaDevice->type) { 403 404 case DEVICE_TYPE_TAPE: 405 case DEVICE_TYPE_FLOPPY: 406 loop_on_root_floppy(); 407 break; 408 409 default: 410 if (mediaDevice->init) 411 if (!(*mediaDevice->init)(mediaDevice)) 412 break; 413 fd = (*mediaDevice->get)("floppies/root.flp"); 414 if (fd != -1) { 415 msgNotify("Loading root floppy from %s", mediaDevice->name); 416 (void)mediaExtractDist("/", fd); 417 if (mediaDevice->close) 418 (*mediaDevice->close)(mediaDevice, fd); 419 else 420 close(fd); 421 } 422 else { 423 msgConfirm("Couldn't get root floppy image from %s\n, falling back to floppy.", mediaDevice->name); 424 if (mediaDevice->shutdown) 425 (*mediaDevice->shutdown)(mediaDevice); 426 loop_on_root_floppy(); 427 } 428 break; 429 } 430 } 431 else 432 loop_on_root_floppy(); 433} 434 435static void 436loop_on_root_floppy(void) 437{ 438 int fd; 439 440 while (1) { 441 fd = getRootFloppy(); 442 if (fd != -1) { 443 mediaExtractDist("/", fd); 444 break; 445 } 446 } 447} 448