disks.c revision 127081
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 127081 2004-03-16 17:07:06Z jhb $ 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__) && !defined(__ia64__) 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#ifndef __ia64__ 629 case '|': 630 if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" 631 "No seat belts whatsoever are provided!")) { 632 clear(); 633 refresh(); 634 slice_wizard(d); 635 variable_set2(DISK_PARTITIONED, "yes", 0); 636 record_chunks(d); 637 } 638 else 639 msg = "Wise choice!"; 640 clear(); 641 break; 642#endif 643 644 case '\033': /* ESC */ 645 case 'Q': 646 chunking = FALSE; 647#ifdef PC98 648 /* 649 * Don't trash the IPL if the first (and therefore only) chunk 650 * is marked for a truly dedicated disk (i.e., the disklabel 651 * starts at sector 0), even in cases where the user has requested 652 * a FreeBSD Boot Manager -- both would be fatal in this case. 653 */ 654 /* 655 * Don't offer to update the IPL on this disk if the first "real" 656 * chunk looks like a FreeBSD "all disk" partition, or the disk is 657 * entirely FreeBSD. 658 */ 659 if ((d->chunks->part->type != freebsd) || 660 (d->chunks->part->offset > 1)) { 661 if (variable_cmp(DISK_PARTITIONED, "written")) { 662 getBootMgr(d->name, &bootipl, &bootipl_size, 663 &bootmenu, &bootmenu_size); 664 if (bootipl != NULL && bootmenu != NULL) 665 Set_Boot_Mgr(d, bootipl, bootipl_size, 666 bootmenu, bootmenu_size); 667 } 668 } 669#else 670 /* 671 * Don't trash the MBR if the first (and therefore only) chunk 672 * is marked for a truly dedicated disk (i.e., the disklabel 673 * starts at sector 0), even in cases where the user has requested 674 * booteasy or a "standard" MBR -- both would be fatal in this case. 675 */ 676 /* 677 * Don't offer to update the MBR on this disk if the first "real" 678 * chunk looks like a FreeBSD "all disk" partition, or the disk is 679 * entirely FreeBSD. 680 */ 681 if ((d->chunks->part->type != freebsd) || 682 (d->chunks->part->offset > 1)) { 683 if (variable_cmp(DISK_PARTITIONED, "written")) { 684 getBootMgr(d->name, &mbrContents, &mbrSize); 685 if (mbrContents != NULL) 686 Set_Boot_Mgr(d, mbrContents, mbrSize); 687 } 688 } 689#endif 690 break; 691 692 case 'Z': 693 size_unit = (size_unit + 1) % UNIT_SIZE; 694 break; 695 696 default: 697 beep(); 698 msg = "Type F1 or ? for help"; 699 break; 700 } 701 } 702 p = CheckRules(d); 703 if (p) { 704 char buf[FILENAME_MAX]; 705 706 use_helpline("Press F1 to read more about disk slices."); 707 use_helpfile(systemHelpFile("partition", buf)); 708 if (!variable_get(VAR_NO_WARN)) 709 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 710 free(p); 711 } 712 restorescr(w); 713} 714#endif /* WITH_SLICES */ 715 716static u_char * 717bootalloc(char *name, size_t *size) 718{ 719 char buf[FILENAME_MAX]; 720 struct stat sb; 721 722 snprintf(buf, sizeof buf, "/boot/%s", name); 723 if (stat(buf, &sb) != -1) { 724 int fd; 725 726 fd = open(buf, O_RDONLY); 727 if (fd != -1) { 728 u_char *cp; 729 730 cp = malloc(sb.st_size); 731 if (read(fd, cp, sb.st_size) != sb.st_size) { 732 free(cp); 733 close(fd); 734 msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); 735 return NULL; 736 } 737 close(fd); 738 if (size != NULL) 739 *size = sb.st_size; 740 return cp; 741 } 742 msgDebug("bootalloc: couldn't open %s\n", buf); 743 } 744 else 745 msgDebug("bootalloc: can't stat %s\n", buf); 746 return NULL; 747} 748 749#ifdef WITH_SLICES 750static int 751partitionHook(dialogMenuItem *selected) 752{ 753 Device **devs = NULL; 754 755 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 756 if (!devs) { 757 msgConfirm("Unable to find disk %s!", selected->prompt); 758 return DITEM_FAILURE; 759 } 760 /* Toggle enabled status? */ 761 if (!devs[0]->enabled) { 762 devs[0]->enabled = TRUE; 763 diskPartition(devs[0]); 764 } 765 else 766 devs[0]->enabled = FALSE; 767 return DITEM_SUCCESS; 768} 769 770static int 771partitionCheck(dialogMenuItem *selected) 772{ 773 Device **devs = NULL; 774 775 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 776 if (!devs || devs[0]->enabled == FALSE) 777 return FALSE; 778 return TRUE; 779} 780 781int 782diskPartitionEditor(dialogMenuItem *self) 783{ 784 DMenu *menu; 785 Device **devs; 786 int i, cnt, devcnt; 787 788 cnt = diskGetSelectCount(&devs); 789 devcnt = deviceCount(devs); 790 if (cnt == -1) { 791 msgConfirm("No disks found! Please verify that your disk controller is being\n" 792 "properly probed at boot time. See the Hardware Guide on the\n" 793 "Documentation menu for clues on diagnosing this type of problem."); 794 return DITEM_FAILURE; 795 } 796 else if (cnt) { 797 /* Some are already selected */ 798 for (i = 0; i < devcnt; i++) { 799 if (devs[i]->enabled) { 800 if (variable_get(VAR_NONINTERACTIVE) && 801 !variable_get(VAR_DISKINTERACTIVE)) 802 diskPartitionNonInteractive(devs[i]); 803 else 804 diskPartition(devs[i]); 805 } 806 } 807 } 808 else { 809 /* No disks are selected, fall-back case now */ 810 if (devcnt == 1) { 811 devs[0]->enabled = TRUE; 812 if (variable_get(VAR_NONINTERACTIVE) && 813 !variable_get(VAR_DISKINTERACTIVE)) 814 diskPartitionNonInteractive(devs[0]); 815 else 816 diskPartition(devs[0]); 817 return DITEM_SUCCESS; 818 } 819 else { 820 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 821 if (!menu) { 822 msgConfirm("No devices suitable for installation found!\n\n" 823 "Please verify that your disk controller (and attached drives)\n" 824 "were detected properly. This can be done by pressing the\n" 825 "[Scroll Lock] key and using the Arrow keys to move back to\n" 826 "the boot messages. Press [Scroll Lock] again to return."); 827 return DITEM_FAILURE; 828 } 829 else { 830 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 831 free(menu); 832 } 833 return i; 834 } 835 } 836 return DITEM_SUCCESS; 837} 838#endif /* WITH_SLICES */ 839 840int 841diskPartitionWrite(dialogMenuItem *self) 842{ 843 Device **devs; 844 int i; 845 846 if (!variable_cmp(DISK_PARTITIONED, "written")) 847 return DITEM_SUCCESS; 848 849 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 850 if (!devs) { 851 msgConfirm("Unable to find any disks to write to??"); 852 return DITEM_FAILURE; 853 } 854 if (isDebug()) 855 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 856 for (i = 0; devs[i]; i++) { 857 Disk *d = (Disk *)devs[i]->private; 858 static u_char *boot1; 859#if defined(__i386__) || defined(__ia64__) || defined(__amd64__) 860 static u_char *boot2; 861#endif 862 863 if (!devs[i]->enabled) 864 continue; 865 866#if defined(__i386__) || defined(__amd64__) 867 if (!boot1) boot1 = bootalloc("boot1", NULL); 868 if (!boot2) boot2 = bootalloc("boot2", NULL); 869 Set_Boot_Blocks(d, boot1, boot2); 870#elif !defined(__ia64__) 871 if (!boot1) boot1 = bootalloc("boot1", NULL); 872 Set_Boot_Blocks(d, boot1, NULL); 873#endif 874 875 msgNotify("Writing partition information to drive %s", d->name); 876 if (!Fake && Write_Disk(d)) { 877 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 878 return DITEM_FAILURE; 879 } 880 } 881 /* Now it's not "yes", but "written" */ 882 variable_set2(DISK_PARTITIONED, "written", 0); 883 return DITEM_SUCCESS | DITEM_RESTORE; 884} 885 886#ifdef WITH_SLICES 887/* Partition a disk based wholly on which variables are set */ 888static void 889diskPartitionNonInteractive(Device *dev) 890{ 891 char *cp; 892 int i, all_disk = 0; 893 daddr_t sz; 894#ifdef PC98 895 u_char *bootipl; 896 size_t bootipl_size; 897 u_char *bootmenu; 898 size_t bootmenu_size; 899#else 900 u_char *mbrContents; 901 size_t mbrSize; 902#endif 903 Disk *d = (Disk *)dev->private; 904 905 record_chunks(d); 906 cp = variable_get(VAR_GEOMETRY); 907 if (cp) { 908 msgDebug("Setting geometry from script to: %s\n", cp); 909 d->bios_cyl = strtol(cp, &cp, 0); 910 d->bios_hd = strtol(cp + 1, &cp, 0); 911 d->bios_sect = strtol(cp + 1, 0, 0); 912 } 913 914 cp = variable_get(VAR_PARTITION); 915 if (cp) { 916 if (!strcmp(cp, "free")) { 917 /* Do free disk space case */ 918 for (i = 0; chunk_info[i]; i++) { 919 /* If a chunk is at least 10MB in size, use it. */ 920 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 921 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 922 freebsd, 3, 923 (chunk_info[i]->flags & CHUNK_ALIGN), 924 "FreeBSD"); 925 variable_set2(DISK_PARTITIONED, "yes", 0); 926 break; 927 } 928 } 929 if (!chunk_info[i]) { 930 msgConfirm("Unable to find any free space on this disk!"); 931 return; 932 } 933 } 934 else if (!strcmp(cp, "all")) { 935 /* Do all disk space case */ 936 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 937 938 All_FreeBSD(d, FALSE); 939 } 940 else if (!strcmp(cp, "exclusive")) { 941 /* Do really-all-the-disk-space case */ 942 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 943 944 All_FreeBSD(d, all_disk = TRUE); 945 } 946 else if ((sz = strtoimax(cp, &cp, 0))) { 947 /* Look for sz bytes free */ 948 if (*cp && toupper(*cp) == 'M') 949 sz *= ONE_MEG; 950 else if (*cp && toupper(*cp) == 'G') 951 sz *= ONE_GIG; 952 for (i = 0; chunk_info[i]; i++) { 953 /* If a chunk is at least sz MB, use it. */ 954 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 955 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 956 (chunk_info[i]->flags & CHUNK_ALIGN), 957 "FreeBSD"); 958 variable_set2(DISK_PARTITIONED, "yes", 0); 959 break; 960 } 961 } 962 if (!chunk_info[i]) { 963 msgConfirm("Unable to find %jd free blocks on this disk!", 964 (intmax_t)sz); 965 return; 966 } 967 } 968 else if (!strcmp(cp, "existing")) { 969 /* Do existing FreeBSD case */ 970 for (i = 0; chunk_info[i]; i++) { 971 if (chunk_info[i]->type == freebsd) 972 break; 973 } 974 if (!chunk_info[i]) { 975 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 976 return; 977 } 978 } 979 else { 980 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 981 return; 982 } 983 if (!all_disk) { 984#ifdef PC98 985 getBootMgr(d->name, &bootipl, &bootipl_size, 986 &bootmenu, &bootmenu_size); 987 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 988#else 989 getBootMgr(d->name, &mbrContents, &mbrSize); 990 Set_Boot_Mgr(d, mbrContents, mbrSize); 991#endif 992 } 993 variable_set2(DISK_PARTITIONED, "yes", 0); 994 } 995} 996#endif /* WITH_SLICES */ 997