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