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