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