disks.c revision 132984
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 * $FreeBSD: head/usr.sbin/sade/disks.c 132984 2004-08-01 22:44:40Z marcel $ 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 * 23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37#include "sysinstall.h" 38#include <ctype.h> 39#include <fcntl.h> 40#include <inttypes.h> 41#include <sys/stat.h> 42#include <sys/disklabel.h> 43 44#ifdef WITH_SLICES 45enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_GIG, UNIT_SIZE }; 46 47#ifdef PC98 48#define SUBTYPE_FREEBSD 50324 49#define SUBTYPE_FAT 37218 50#else 51#define SUBTYPE_FREEBSD 165 52#define SUBTYPE_FAT 6 53#endif 54#define SUBTYPE_EFI 239 55 56#ifdef PC98 57#define OTHER_SLICE_VALUES \ 58 "Other popular values are 37218 for a\n" \ 59 "DOS FAT partition.\n\n" 60#else 61#define OTHER_SLICE_VALUES \ 62 "Other popular values are 6 for a\n" \ 63 "DOS FAT partition, 131 for a Linux ext2fs partition, or\n" \ 64 "130 for a Linux swap partition.\n\n" 65#endif 66#define NON_FREEBSD_NOTE \ 67 "Note: If you choose a non-FreeBSD partition type, it will not\n" \ 68 "be formatted or otherwise prepared, it will simply reserve space\n" \ 69 "for you to use another tool, such as DOS format, to later format\n" \ 70 "and actually use the partition." 71 72/* Where we start displaying chunk information on the screen */ 73#define CHUNK_START_ROW 5 74 75/* Where we keep track of MBR chunks */ 76static struct chunk *chunk_info[16]; 77static int current_chunk; 78 79static void diskPartitionNonInteractive(Device *dev); 80static u_char * bootalloc(char *name, size_t *size); 81 82static void 83record_chunks(Disk *d) 84{ 85 struct chunk *c1 = NULL; 86 int i = 0; 87 daddr_t last_free = 0; 88 89 if (!d->chunks) 90 msgFatal("No chunk list found for %s!", d->name); 91 92 for (c1 = d->chunks->part; c1; c1 = c1->next) { 93 if (c1->type == unused && c1->size > last_free) { 94 last_free = c1->size; 95 current_chunk = i; 96 } 97 chunk_info[i++] = c1; 98 } 99 chunk_info[i] = NULL; 100 if (current_chunk >= i) 101 current_chunk = i - 1; 102} 103 104static daddr_t Total; 105 106static void 107print_chunks(Disk *d, int u) 108{ 109 int row; 110 int i; 111 daddr_t sz; 112 char *szstr; 113 114 szstr = (u == UNIT_GIG ? "GB" : (u == UNIT_MEG ? "MB" : 115 (u == UNIT_KILO ? "KB" : "ST"))); 116 117 Total = 0; 118 for (i = 0; chunk_info[i]; i++) 119 Total += chunk_info[i]->size; 120#ifdef PC98 121 if (d->bios_cyl >= 65536 || d->bios_hd > 16 || d->bios_sect >= 256) { 122#else 123 if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { 124#endif 125 dialog_clear_norefresh(); 126 msgConfirm("WARNING: A geometry of %lu/%lu/%lu for %s is incorrect. Using\n" 127 "a more likely geometry. If this geometry is incorrect or you\n" 128 "are unsure as to whether or not it's correct, please consult\n" 129 "the Hardware Guide in the Documentation submenu or use the\n" 130 "(G)eometry command to change it now.\n\n" 131 "Remember: you need to enter whatever your BIOS thinks the\n" 132 "geometry is! For IDE, it's what you were told in the BIOS\n" 133 "setup. For SCSI, it's the translation mode your controller is\n" 134 "using. Do NOT use a ``physical geometry''.", 135 d->bios_cyl, d->bios_hd, d->bios_sect, d->name); 136 Sanitize_Bios_Geom(d); 137 } 138 attrset(A_NORMAL); 139 mvaddstr(0, 0, "Disk name:\t"); 140 clrtobot(); 141 attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); 142 attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); 143 mvprintw(1, 0, 144 "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %jd sectors (%jdMB)", 145 d->bios_cyl, d->bios_hd, d->bios_sect, 146 (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect, 147 (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024); 148 mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", 149 "Offset", "Size", szstr, "End", "Name", "PType", "Desc", 150 "Subtype", "Flags"); 151 for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { 152 switch(u) { 153 default: /* fall thru */ 154 case UNIT_BLOCKS: 155 sz = chunk_info[i]->size; 156 break; 157 case UNIT_KILO: 158 sz = chunk_info[i]->size / (1024/512); 159 break; 160 case UNIT_MEG: 161 sz = chunk_info[i]->size / (1024/512) / 1024; 162 break; 163 case UNIT_GIG: 164 sz = chunk_info[i]->size / (1024/512) / 1024 / 1024; 165 break; 166 } 167 if (i == current_chunk) 168 attrset(ATTR_SELECTED); 169 mvprintw(row, 0, "%10jd %10jd %10jd %8s %6d %10s %8d\t%-6s", 170 (intmax_t)chunk_info[i]->offset, (intmax_t)sz, 171 (intmax_t)chunk_info[i]->end, chunk_info[i]->name, 172 chunk_info[i]->type, 173 slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), 174 chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); 175 if (i == current_chunk) 176 attrset(A_NORMAL); 177 } 178} 179 180static void 181print_command_summary() 182{ 183 mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); 184 mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice F = `DD' mode"); 185 mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable | = Wizard m."); 186 mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); 187 if (!RunningAsInit) 188 mvprintw(18, 47, "W = Write Changes"); 189 mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); 190 move(0, 0); 191} 192 193#ifdef PC98 194static void 195getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, 196 u_char **bootmenu, size_t *bootmenu_size) 197{ 198 static u_char *boot0; 199 static size_t boot0_size; 200 static u_char *boot05; 201 static size_t boot05_size; 202 203 char str[80]; 204 char *cp; 205 int i = 0; 206 207 cp = variable_get(VAR_BOOTMGR); 208 if (!cp) { 209 /* Figure out what kind of IPL the user wants */ 210 sprintf(str, "Install Boot Manager for drive %s?", dname); 211 MenuIPLType.title = str; 212 i = dmenuOpenSimple(&MenuIPLType, FALSE); 213 } else { 214 if (!strncmp(cp, "boot", 4)) 215 BootMgr = 0; 216 else 217 BootMgr = 1; 218 } 219 if (cp || i) { 220 switch (BootMgr) { 221 case 0: 222 if (!boot0) boot0 = bootalloc("boot0", &boot0_size); 223 *bootipl = boot0; 224 *bootipl_size = boot0_size; 225 if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size); 226 *bootmenu = boot05; 227 *bootmenu_size = boot05_size; 228 return; 229 case 1: 230 default: 231 break; 232 } 233 } 234 *bootipl = NULL; 235 *bootipl_size = 0; 236 *bootmenu = NULL; 237 *bootmenu_size = 0; 238} 239#else 240static void 241getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) 242{ 243#if defined(__i386__) || defined(__amd64__) /* only meaningful on x86 */ 244 static u_char *mbr, *boot0; 245 static size_t mbr_size, boot0_size; 246 char str[80]; 247 char *cp; 248 int i = 0; 249 250 cp = variable_get(VAR_BOOTMGR); 251 if (!cp) { 252 /* Figure out what kind of MBR the user wants */ 253 sprintf(str, "Install Boot Manager for drive %s?", dname); 254 MenuMBRType.title = str; 255 i = dmenuOpenSimple(&MenuMBRType, FALSE); 256 } 257 else { 258 if (!strncmp(cp, "boot", 4)) 259 BootMgr = 0; 260 else if (!strcmp(cp, "standard")) 261 BootMgr = 1; 262 else 263 BootMgr = 2; 264 } 265 if (cp || i) { 266 switch (BootMgr) { 267 case 0: 268 if (!boot0) boot0 = bootalloc("boot0", &boot0_size); 269 *bootCode = boot0; 270 *bootCodeSize = boot0_size; 271 return; 272 case 1: 273 if (!mbr) mbr = bootalloc("mbr", &mbr_size); 274 *bootCode = mbr; 275 *bootCodeSize = mbr_size; 276 return; 277 case 2: 278 default: 279 break; 280 } 281 } 282#endif 283 *bootCode = NULL; 284 *bootCodeSize = 0; 285} 286#endif 287#endif /* WITH_SLICES */ 288 289int 290diskGetSelectCount(Device ***devs) 291{ 292 int i, cnt, enabled; 293 char *cp; 294 Device **dp; 295 296 cp = variable_get(VAR_DISK); 297 dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); 298 cnt = deviceCount(dp); 299 if (!cnt) 300 return -1; 301 for (i = 0, enabled = 0; i < cnt; i++) { 302 if (dp[i]->enabled) 303 ++enabled; 304 } 305 return enabled; 306} 307 308#ifdef WITH_SLICES 309void 310diskPartition(Device *dev) 311{ 312 char *cp, *p; 313 int rv, key = 0; 314 Boolean chunking; 315 char *msg = NULL; 316#ifdef PC98 317 u_char *bootipl; 318 size_t bootipl_size; 319 u_char *bootmenu; 320 size_t bootmenu_size; 321#else 322 u_char *mbrContents; 323 size_t mbrSize; 324#endif 325 WINDOW *w = savescr(); 326 Disk *d = (Disk *)dev->private; 327 int size_unit; 328 329 size_unit = UNIT_BLOCKS; 330 chunking = TRUE; 331 keypad(stdscr, TRUE); 332 333 /* Flush both the dialog and curses library views of the screen 334 since we don't always know who called us */ 335 dialog_clear_norefresh(), clear(); 336 current_chunk = 0; 337 338 /* Set up the chunk array */ 339 record_chunks(d); 340 341 while (chunking) { 342 char *val, geometry[80]; 343 344 /* Now print our overall state */ 345 if (d) 346 print_chunks(d, size_unit); 347 print_command_summary(); 348 if (msg) { 349 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 350 beep(); 351 msg = NULL; 352 } 353 else { 354 move(23, 0); 355 clrtoeol(); 356 } 357 358 /* Get command character */ 359 key = getch(); 360 switch (toupper(key)) { 361 case '\014': /* ^L (redraw) */ 362 clear(); 363 msg = NULL; 364 break; 365 366 case '\020': /* ^P */ 367 case KEY_UP: 368 case '-': 369 if (current_chunk != 0) 370 --current_chunk; 371 break; 372 373 case '\016': /* ^N */ 374 case KEY_DOWN: 375 case '+': 376 case '\r': 377 case '\n': 378 if (chunk_info[current_chunk + 1]) 379 ++current_chunk; 380 break; 381 382 case KEY_HOME: 383 current_chunk = 0; 384 break; 385 386 case KEY_END: 387 while (chunk_info[current_chunk + 1]) 388 ++current_chunk; 389 break; 390 391 case KEY_F(1): 392 case '?': 393 systemDisplayHelp("slice"); 394 clear(); 395 break; 396 397 case 'A': 398 case 'F': /* Undocumented magic Dangerously Dedicated mode */ 399#if !defined(__i386__) && !defined(__amd64__) 400 rv = 1; 401#else /* The rest is only relevant on x86 */ 402 cp = variable_get(VAR_DEDICATE_DISK); 403 if (cp && !strcasecmp(cp, "always")) 404 rv = 1; 405 else if (toupper(key) == 'A') 406 rv = 0; 407 else { 408 rv = msgYesNo("Do you want to do this with a true partition entry\n" 409 "so as to remain cooperative with any future possible\n" 410 "operating systems on the drive(s)?\n" 411 "(See also the section about ``dangerously dedicated''\n" 412 "disks in the FreeBSD FAQ.)"); 413 if (rv == -1) 414 rv = 0; 415 } 416#endif 417 All_FreeBSD(d, rv); 418 variable_set2(DISK_PARTITIONED, "yes", 0); 419 record_chunks(d); 420 clear(); 421 break; 422 423 case 'C': 424 if (chunk_info[current_chunk]->type != unused) 425 msg = "Slice in use, delete it first or move to an unused one."; 426 else { 427 char *val, tmp[20], name[16], *cp; 428 daddr_t size; 429 int subtype; 430 chunk_e partitiontype; 431#ifdef PC98 432 snprintf(name, sizeof (name), "%s", "FreeBSD"); 433 val = msgGetInput(name, 434 "Please specify the name for new FreeBSD slice."); 435 if (val) 436 strncpy(name, val, sizeof (name)); 437#else 438 name[0] = '\0'; 439#endif 440 snprintf(tmp, 20, "%jd", (intmax_t)chunk_info[current_chunk]->size); 441 val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" 442 "or append a trailing `M' for megabytes (e.g. 20M)."); 443 if (val && (size = strtoimax(val, &cp, 0)) > 0) { 444 if (*cp && toupper(*cp) == 'M') 445 size *= ONE_MEG; 446 else if (*cp && toupper(*cp) == 'G') 447 size *= ONE_GIG; 448 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 449 val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 450 "Pressing Enter will choose the default, a native FreeBSD\n" 451 "slice (type %u). " 452 OTHER_SLICE_VALUES 453 NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); 454 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 455 if (subtype == SUBTYPE_FREEBSD) 456 partitiontype = freebsd; 457 else if (subtype == SUBTYPE_FAT) 458 partitiontype = fat; 459 else if (subtype == SUBTYPE_EFI) 460 partitiontype = efi; 461 else 462#ifdef PC98 463 partitiontype = pc98; 464#else 465 partitiontype = mbr; 466#endif 467 Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 468 (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); 469 variable_set2(DISK_PARTITIONED, "yes", 0); 470 record_chunks(d); 471 } 472 } 473 clear(); 474 } 475 break; 476 477 case KEY_DC: 478 case 'D': 479 if (chunk_info[current_chunk]->type == unused) 480 msg = "Slice is already unused!"; 481 else { 482 Delete_Chunk(d, chunk_info[current_chunk]); 483 variable_set2(DISK_PARTITIONED, "yes", 0); 484 record_chunks(d); 485 } 486 break; 487 488 case 'T': 489 if (chunk_info[current_chunk]->type == unused) 490 msg = "Slice is currently unused (use create instead)"; 491 else { 492 char *val, tmp[20]; 493 int subtype; 494 chunk_e partitiontype; 495 496 sprintf(tmp, "%d", chunk_info[current_chunk]->subtype); 497 val = msgGetInput(tmp, "New partition type:\n\n" 498 "Pressing Enter will use the current type. To choose a native\n" 499 "FreeBSD slice enter %u. " 500 OTHER_SLICE_VALUES 501 NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); 502 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 503 if (subtype == SUBTYPE_FREEBSD) 504 partitiontype = freebsd; 505 else if (subtype == SUBTYPE_FAT) 506 partitiontype = fat; 507 else if (subtype == SUBTYPE_EFI) 508 partitiontype = efi; 509 else 510#ifdef PC98 511 partitiontype = pc98; 512#else 513 partitiontype = mbr; 514#endif 515 chunk_info[current_chunk]->type = partitiontype; 516 chunk_info[current_chunk]->subtype = subtype; 517 } 518 } 519 break; 520 521 case 'G': 522 snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); 523 val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" 524 "Don't forget to use the two slash (/) separator characters!\n" 525 "It's not possible to parse the field without them."); 526 if (val) { 527 long nc, nh, ns; 528 nc = strtol(val, &val, 0); 529 nh = strtol(val + 1, &val, 0); 530 ns = strtol(val + 1, 0, 0); 531 Set_Bios_Geom(d, nc, nh, ns); 532 } 533 clear(); 534 break; 535 536 case 'S': 537 /* Set Bootable */ 538 chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 539 break; 540 541 case 'U': 542 if (!variable_cmp(DISK_LABELLED, "written")) { 543 msgConfirm("You've already written this information out - you\n" 544 "can't undo it."); 545 } 546 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 547 char cp[BUFSIZ]; 548 549 sstrncpy(cp, d->name, sizeof cp); 550 Free_Disk(dev->private); 551 d = Open_Disk(cp); 552 if (!d) 553 msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 554 dev->private = d; 555 variable_unset(DISK_PARTITIONED); 556 variable_unset(DISK_LABELLED); 557 if (d) 558 record_chunks(d); 559 } 560 clear(); 561 break; 562 563 case 'W': 564 if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 565 "installation. If you are installing FreeBSD for the first time\n" 566 "then you should simply type Q when you're finished here and your\n" 567 "changes will be committed in one batch automatically at the end of\n" 568 "these questions. If you're adding a disk, you should NOT write\n" 569 "from this screen, you should do it from the label editor.\n\n" 570 "Are you absolutely sure you want to do this now?")) { 571 variable_set2(DISK_PARTITIONED, "yes", 0); 572 573#ifdef PC98 574 /* 575 * Don't trash the IPL if the first (and therefore only) chunk 576 * is marked for a truly dedicated disk (i.e., the disklabel 577 * starts at sector 0), even in cases where the user has 578 * requested a FreeBSD Boot Manager -- both would be fatal in 579 * this case. 580 */ 581 /* 582 * Don't offer to update the IPL on this disk if the first 583 * "real" chunk looks like a FreeBSD "all disk" partition, 584 * or the disk is entirely FreeBSD. 585 */ 586 if ((d->chunks->part->type != freebsd) || 587 (d->chunks->part->offset > 1)) 588 getBootMgr(d->name, &bootipl, &bootipl_size, 589 &bootmenu, &bootmenu_size); 590 else { 591 bootipl = NULL; 592 bootipl_size = 0; 593 bootmenu = NULL; 594 bootmenu_size = 0; 595 } 596 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 597#else 598 /* 599 * Don't trash the MBR if the first (and therefore only) chunk 600 * is marked for a truly dedicated disk (i.e., the disklabel 601 * starts at sector 0), even in cases where the user has 602 * requested booteasy or a "standard" MBR -- both would be 603 * fatal in this case. 604 */ 605 /* 606 * Don't offer to update the MBR on this disk if the first 607 * "real" chunk looks like a FreeBSD "all disk" partition, 608 * or the disk is entirely FreeBSD. 609 */ 610 if ((d->chunks->part->type != freebsd) || 611 (d->chunks->part->offset > 1)) 612 getBootMgr(d->name, &mbrContents, &mbrSize); 613 else { 614 mbrContents = NULL; 615 mbrSize = 0; 616 } 617 Set_Boot_Mgr(d, mbrContents, mbrSize); 618#endif 619 620 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 621 msgConfirm("Disk partition write returned an error status!"); 622 else 623 msgConfirm("Wrote FDISK partition information out successfully."); 624 } 625 clear(); 626 break; 627 628 case '|': 629 if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" 630 "No seat belts whatsoever are provided!")) { 631 clear(); 632 refresh(); 633 slice_wizard(d); 634 variable_set2(DISK_PARTITIONED, "yes", 0); 635 record_chunks(d); 636 } 637 else 638 msg = "Wise choice!"; 639 clear(); 640 break; 641 642 case '\033': /* ESC */ 643 case 'Q': 644 chunking = FALSE; 645#ifdef PC98 646 /* 647 * Don't trash the IPL if the first (and therefore only) chunk 648 * is marked for a truly dedicated disk (i.e., the disklabel 649 * starts at sector 0), even in cases where the user has requested 650 * a FreeBSD Boot Manager -- both would be fatal in this case. 651 */ 652 /* 653 * Don't offer to update the IPL on this disk if the first "real" 654 * chunk looks like a FreeBSD "all disk" partition, or the disk is 655 * entirely FreeBSD. 656 */ 657 if ((d->chunks->part->type != freebsd) || 658 (d->chunks->part->offset > 1)) { 659 if (variable_cmp(DISK_PARTITIONED, "written")) { 660 getBootMgr(d->name, &bootipl, &bootipl_size, 661 &bootmenu, &bootmenu_size); 662 if (bootipl != NULL && bootmenu != NULL) 663 Set_Boot_Mgr(d, bootipl, bootipl_size, 664 bootmenu, bootmenu_size); 665 } 666 } 667#else 668 /* 669 * Don't trash the MBR if the first (and therefore only) chunk 670 * is marked for a truly dedicated disk (i.e., the disklabel 671 * starts at sector 0), even in cases where the user has requested 672 * booteasy or a "standard" MBR -- both would be fatal in this case. 673 */ 674 /* 675 * Don't offer to update the MBR on this disk if the first "real" 676 * chunk looks like a FreeBSD "all disk" partition, or the disk is 677 * entirely FreeBSD. 678 */ 679 if ((d->chunks->part->type != freebsd) || 680 (d->chunks->part->offset > 1)) { 681 if (variable_cmp(DISK_PARTITIONED, "written")) { 682 getBootMgr(d->name, &mbrContents, &mbrSize); 683 if (mbrContents != NULL) 684 Set_Boot_Mgr(d, mbrContents, mbrSize); 685 } 686 } 687#endif 688 break; 689 690 case 'Z': 691 size_unit = (size_unit + 1) % UNIT_SIZE; 692 break; 693 694 default: 695 beep(); 696 msg = "Type F1 or ? for help"; 697 break; 698 } 699 } 700 p = CheckRules(d); 701 if (p) { 702 char buf[FILENAME_MAX]; 703 704 use_helpline("Press F1 to read more about disk slices."); 705 use_helpfile(systemHelpFile("partition", buf)); 706 if (!variable_get(VAR_NO_WARN)) 707 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 708 free(p); 709 } 710 restorescr(w); 711} 712#endif /* WITH_SLICES */ 713 714static u_char * 715bootalloc(char *name, size_t *size) 716{ 717 char buf[FILENAME_MAX]; 718 struct stat sb; 719 720 snprintf(buf, sizeof buf, "/boot/%s", name); 721 if (stat(buf, &sb) != -1) { 722 int fd; 723 724 fd = open(buf, O_RDONLY); 725 if (fd != -1) { 726 u_char *cp; 727 728 cp = malloc(sb.st_size); 729 if (read(fd, cp, sb.st_size) != sb.st_size) { 730 free(cp); 731 close(fd); 732 msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); 733 return NULL; 734 } 735 close(fd); 736 if (size != NULL) 737 *size = sb.st_size; 738 return cp; 739 } 740 msgDebug("bootalloc: couldn't open %s\n", buf); 741 } 742 else 743 msgDebug("bootalloc: can't stat %s\n", buf); 744 return NULL; 745} 746 747#ifdef WITH_SLICES 748static int 749partitionHook(dialogMenuItem *selected) 750{ 751 Device **devs = NULL; 752 753 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 754 if (!devs) { 755 msgConfirm("Unable to find disk %s!", selected->prompt); 756 return DITEM_FAILURE; 757 } 758 /* Toggle enabled status? */ 759 if (!devs[0]->enabled) { 760 devs[0]->enabled = TRUE; 761 diskPartition(devs[0]); 762 } 763 else 764 devs[0]->enabled = FALSE; 765 return DITEM_SUCCESS; 766} 767 768static int 769partitionCheck(dialogMenuItem *selected) 770{ 771 Device **devs = NULL; 772 773 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 774 if (!devs || devs[0]->enabled == FALSE) 775 return FALSE; 776 return TRUE; 777} 778 779int 780diskPartitionEditor(dialogMenuItem *self) 781{ 782 DMenu *menu; 783 Device **devs; 784 int i, cnt, devcnt; 785 786 cnt = diskGetSelectCount(&devs); 787 devcnt = deviceCount(devs); 788 if (cnt == -1) { 789 msgConfirm("No disks found! Please verify that your disk controller is being\n" 790 "properly probed at boot time. See the Hardware Guide on the\n" 791 "Documentation menu for clues on diagnosing this type of problem."); 792 return DITEM_FAILURE; 793 } 794 else if (cnt) { 795 /* Some are already selected */ 796 for (i = 0; i < devcnt; i++) { 797 if (devs[i]->enabled) { 798 if (variable_get(VAR_NONINTERACTIVE) && 799 !variable_get(VAR_DISKINTERACTIVE)) 800 diskPartitionNonInteractive(devs[i]); 801 else 802 diskPartition(devs[i]); 803 } 804 } 805 } 806 else { 807 /* No disks are selected, fall-back case now */ 808 if (devcnt == 1) { 809 devs[0]->enabled = TRUE; 810 if (variable_get(VAR_NONINTERACTIVE) && 811 !variable_get(VAR_DISKINTERACTIVE)) 812 diskPartitionNonInteractive(devs[0]); 813 else 814 diskPartition(devs[0]); 815 return DITEM_SUCCESS; 816 } 817 else { 818 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 819 if (!menu) { 820 msgConfirm("No devices suitable for installation found!\n\n" 821 "Please verify that your disk controller (and attached drives)\n" 822 "were detected properly. This can be done by pressing the\n" 823 "[Scroll Lock] key and using the Arrow keys to move back to\n" 824 "the boot messages. Press [Scroll Lock] again to return."); 825 return DITEM_FAILURE; 826 } 827 else { 828 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 829 free(menu); 830 } 831 return i; 832 } 833 } 834 return DITEM_SUCCESS; 835} 836#endif /* WITH_SLICES */ 837 838int 839diskPartitionWrite(dialogMenuItem *self) 840{ 841 Device **devs; 842 int i; 843 844 if (!variable_cmp(DISK_PARTITIONED, "written")) 845 return DITEM_SUCCESS; 846 847 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 848 if (!devs) { 849 msgConfirm("Unable to find any disks to write to??"); 850 return DITEM_FAILURE; 851 } 852 if (isDebug()) 853 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 854 for (i = 0; devs[i]; i++) { 855 Disk *d = (Disk *)devs[i]->private; 856 static u_char *boot1; 857#if defined(__i386__) || defined(__amd64__) 858 static u_char *boot2; 859#endif 860 861 if (!devs[i]->enabled) 862 continue; 863 864#if defined(__i386__) || defined(__amd64__) 865 if (!boot1) boot1 = bootalloc("boot1", NULL); 866 if (!boot2) boot2 = bootalloc("boot2", NULL); 867 Set_Boot_Blocks(d, boot1, boot2); 868#elif !defined(__ia64__) 869 if (!boot1) boot1 = bootalloc("boot1", NULL); 870 Set_Boot_Blocks(d, boot1, NULL); 871#endif 872 873 msgNotify("Writing partition information to drive %s", d->name); 874 if (!Fake && Write_Disk(d)) { 875 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 876 return DITEM_FAILURE; 877 } 878 } 879 /* Now it's not "yes", but "written" */ 880 variable_set2(DISK_PARTITIONED, "written", 0); 881 return DITEM_SUCCESS | DITEM_RESTORE; 882} 883 884#ifdef WITH_SLICES 885/* Partition a disk based wholly on which variables are set */ 886static void 887diskPartitionNonInteractive(Device *dev) 888{ 889 char *cp; 890 int i, all_disk = 0; 891 daddr_t sz; 892#ifdef PC98 893 u_char *bootipl; 894 size_t bootipl_size; 895 u_char *bootmenu; 896 size_t bootmenu_size; 897#else 898 u_char *mbrContents; 899 size_t mbrSize; 900#endif 901 Disk *d = (Disk *)dev->private; 902 903 record_chunks(d); 904 cp = variable_get(VAR_GEOMETRY); 905 if (cp) { 906 msgDebug("Setting geometry from script to: %s\n", cp); 907 d->bios_cyl = strtol(cp, &cp, 0); 908 d->bios_hd = strtol(cp + 1, &cp, 0); 909 d->bios_sect = strtol(cp + 1, 0, 0); 910 } 911 912 cp = variable_get(VAR_PARTITION); 913 if (cp) { 914 if (!strcmp(cp, "free")) { 915 /* Do free disk space case */ 916 for (i = 0; chunk_info[i]; i++) { 917 /* If a chunk is at least 10MB in size, use it. */ 918 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 919 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 920 freebsd, 3, 921 (chunk_info[i]->flags & CHUNK_ALIGN), 922 "FreeBSD"); 923 variable_set2(DISK_PARTITIONED, "yes", 0); 924 break; 925 } 926 } 927 if (!chunk_info[i]) { 928 msgConfirm("Unable to find any free space on this disk!"); 929 return; 930 } 931 } 932 else if (!strcmp(cp, "all")) { 933 /* Do all disk space case */ 934 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 935 936 All_FreeBSD(d, FALSE); 937 } 938 else if (!strcmp(cp, "exclusive")) { 939 /* Do really-all-the-disk-space case */ 940 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 941 942 All_FreeBSD(d, all_disk = TRUE); 943 } 944 else if ((sz = strtoimax(cp, &cp, 0))) { 945 /* Look for sz bytes free */ 946 if (*cp && toupper(*cp) == 'M') 947 sz *= ONE_MEG; 948 else if (*cp && toupper(*cp) == 'G') 949 sz *= ONE_GIG; 950 for (i = 0; chunk_info[i]; i++) { 951 /* If a chunk is at least sz MB, use it. */ 952 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 953 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 954 (chunk_info[i]->flags & CHUNK_ALIGN), 955 "FreeBSD"); 956 variable_set2(DISK_PARTITIONED, "yes", 0); 957 break; 958 } 959 } 960 if (!chunk_info[i]) { 961 msgConfirm("Unable to find %jd free blocks on this disk!", 962 (intmax_t)sz); 963 return; 964 } 965 } 966 else if (!strcmp(cp, "existing")) { 967 /* Do existing FreeBSD case */ 968 for (i = 0; chunk_info[i]; i++) { 969 if (chunk_info[i]->type == freebsd) 970 break; 971 } 972 if (!chunk_info[i]) { 973 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 974 return; 975 } 976 } 977 else { 978 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 979 return; 980 } 981 if (!all_disk) { 982#ifdef PC98 983 getBootMgr(d->name, &bootipl, &bootipl_size, 984 &bootmenu, &bootmenu_size); 985 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 986#else 987 getBootMgr(d->name, &mbrContents, &mbrSize); 988 Set_Boot_Mgr(d, mbrContents, mbrSize); 989#endif 990 } 991 variable_set2(DISK_PARTITIONED, "yes", 0); 992 } 993} 994#endif /* WITH_SLICES */ 995