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