disks.c revision 133040
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 133040 2004-08-02 23:18:48Z marcel $ 8 * 9 * Copyright (c) 1995 10 * Jordan Hubbard. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer, 17 * verbatim and that no modifications are made prior to this 18 * point in the file. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37#include "sysinstall.h" 38#include <ctype.h> 39#include <fcntl.h> 40#include <inttypes.h> 41#include <libdisk.h> 42#include <sys/stat.h> 43#include <sys/disklabel.h> 44 45#ifdef WITH_SLICES 46enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_GIG, UNIT_SIZE }; 47 48#ifdef PC98 49#define SUBTYPE_FREEBSD 50324 50#define SUBTYPE_FAT 37218 51#else 52#define SUBTYPE_FREEBSD 165 53#define SUBTYPE_FAT 6 54#endif 55#define SUBTYPE_EFI 239 56 57#ifdef PC98 58#define OTHER_SLICE_VALUES \ 59 "Other popular values are 37218 for a\n" \ 60 "DOS FAT partition.\n\n" 61#else 62#define OTHER_SLICE_VALUES \ 63 "Other popular values are 6 for a\n" \ 64 "DOS FAT partition, 131 for a Linux ext2fs partition, or\n" \ 65 "130 for a Linux swap partition.\n\n" 66#endif 67#define NON_FREEBSD_NOTE \ 68 "Note: If you choose a non-FreeBSD partition type, it will not\n" \ 69 "be formatted or otherwise prepared, it will simply reserve space\n" \ 70 "for you to use another tool, such as DOS format, to later format\n" \ 71 "and actually use the partition." 72 73/* Where we start displaying chunk information on the screen */ 74#define CHUNK_START_ROW 5 75 76/* Where we keep track of MBR chunks */ 77static struct chunk *chunk_info[16]; 78static int current_chunk; 79 80static void diskPartitionNonInteractive(Device *dev); 81static u_char * bootalloc(char *name, size_t *size); 82 83static void 84record_chunks(Disk *d) 85{ 86 struct chunk *c1 = NULL; 87 int i = 0; 88 daddr_t last_free = 0; 89 90 if (!d->chunks) 91 msgFatal("No chunk list found for %s!", d->name); 92 93 for (c1 = d->chunks->part; c1; c1 = c1->next) { 94 if (c1->type == unused && c1->size > last_free) { 95 last_free = c1->size; 96 current_chunk = i; 97 } 98 chunk_info[i++] = c1; 99 } 100 chunk_info[i] = NULL; 101 if (current_chunk >= i) 102 current_chunk = i - 1; 103} 104 105static daddr_t Total; 106 107static void 108print_chunks(Disk *d, int u) 109{ 110 int row; 111 int i; 112 daddr_t sz; 113 char *szstr; 114 115 szstr = (u == UNIT_GIG ? "GB" : (u == UNIT_MEG ? "MB" : 116 (u == UNIT_KILO ? "KB" : "ST"))); 117 118 Total = 0; 119 for (i = 0; chunk_info[i]; i++) 120 Total += chunk_info[i]->size; 121#ifdef PC98 122 if (d->bios_cyl >= 65536 || d->bios_hd > 16 || d->bios_sect >= 256) { 123#else 124 if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { 125#endif 126 dialog_clear_norefresh(); 127 msgConfirm("WARNING: A geometry of %lu/%lu/%lu for %s is incorrect. Using\n" 128 "a more likely geometry. If this geometry is incorrect or you\n" 129 "are unsure as to whether or not it's correct, please consult\n" 130 "the Hardware Guide in the Documentation submenu or use the\n" 131 "(G)eometry command to change it now.\n\n" 132 "Remember: you need to enter whatever your BIOS thinks the\n" 133 "geometry is! For IDE, it's what you were told in the BIOS\n" 134 "setup. For SCSI, it's the translation mode your controller is\n" 135 "using. Do NOT use a ``physical geometry''.", 136 d->bios_cyl, d->bios_hd, d->bios_sect, d->name); 137 Sanitize_Bios_Geom(d); 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() 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 if (!RunningAsInit) 189 mvprintw(18, 47, "W = Write Changes"); 190 mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); 191 move(0, 0); 192} 193 194#ifdef PC98 195static void 196getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, 197 u_char **bootmenu, size_t *bootmenu_size) 198{ 199 static u_char *boot0; 200 static size_t boot0_size; 201 static u_char *boot05; 202 static size_t boot05_size; 203 204 char str[80]; 205 char *cp; 206 int i = 0; 207 208 cp = variable_get(VAR_BOOTMGR); 209 if (!cp) { 210 /* Figure out what kind of IPL the user wants */ 211 sprintf(str, "Install Boot Manager for drive %s?", dname); 212 MenuIPLType.title = str; 213 i = dmenuOpenSimple(&MenuIPLType, FALSE); 214 } else { 215 if (!strncmp(cp, "boot", 4)) 216 BootMgr = 0; 217 else 218 BootMgr = 1; 219 } 220 if (cp || i) { 221 switch (BootMgr) { 222 case 0: 223 if (!boot0) boot0 = bootalloc("boot0", &boot0_size); 224 *bootipl = boot0; 225 *bootipl_size = boot0_size; 226 if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size); 227 *bootmenu = boot05; 228 *bootmenu_size = boot05_size; 229 return; 230 case 1: 231 default: 232 break; 233 } 234 } 235 *bootipl = NULL; 236 *bootipl_size = 0; 237 *bootmenu = NULL; 238 *bootmenu_size = 0; 239} 240#else 241static void 242getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) 243{ 244#if defined(__i386__) || defined(__amd64__) /* only meaningful on x86 */ 245 static u_char *mbr, *boot0; 246 static size_t mbr_size, boot0_size; 247 char str[80]; 248 char *cp; 249 int i = 0; 250 251 cp = variable_get(VAR_BOOTMGR); 252 if (!cp) { 253 /* Figure out what kind of MBR the user wants */ 254 sprintf(str, "Install Boot Manager for drive %s?", dname); 255 MenuMBRType.title = str; 256 i = dmenuOpenSimple(&MenuMBRType, FALSE); 257 } 258 else { 259 if (!strncmp(cp, "boot", 4)) 260 BootMgr = 0; 261 else if (!strcmp(cp, "standard")) 262 BootMgr = 1; 263 else 264 BootMgr = 2; 265 } 266 if (cp || i) { 267 switch (BootMgr) { 268 case 0: 269 if (!boot0) boot0 = bootalloc("boot0", &boot0_size); 270 *bootCode = boot0; 271 *bootCodeSize = boot0_size; 272 return; 273 case 1: 274 if (!mbr) mbr = bootalloc("mbr", &mbr_size); 275 *bootCode = mbr; 276 *bootCodeSize = mbr_size; 277 return; 278 case 2: 279 default: 280 break; 281 } 282 } 283#endif 284 *bootCode = NULL; 285 *bootCodeSize = 0; 286} 287#endif 288#endif /* WITH_SLICES */ 289 290int 291diskGetSelectCount(Device ***devs) 292{ 293 int i, cnt, enabled; 294 char *cp; 295 Device **dp; 296 297 cp = variable_get(VAR_DISK); 298 dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); 299 cnt = deviceCount(dp); 300 if (!cnt) 301 return -1; 302 for (i = 0, enabled = 0; i < cnt; i++) { 303 if (dp[i]->enabled) 304 ++enabled; 305 } 306 return enabled; 307} 308 309#ifdef WITH_SLICES 310void 311diskPartition(Device *dev) 312{ 313 char *cp, *p; 314 int rv, key = 0; 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 /* Set Bootable */ 539 chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 540 break; 541 542 case 'U': 543 if (!variable_cmp(DISK_LABELLED, "written")) { 544 msgConfirm("You've already written this information out - you\n" 545 "can't undo it."); 546 } 547 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 548 char cp[BUFSIZ]; 549 550 sstrncpy(cp, d->name, sizeof cp); 551 Free_Disk(dev->private); 552 d = Open_Disk(cp); 553 if (!d) 554 msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 555 dev->private = d; 556 variable_unset(DISK_PARTITIONED); 557 variable_unset(DISK_LABELLED); 558 if (d) 559 record_chunks(d); 560 } 561 clear(); 562 break; 563 564 case 'W': 565 if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 566 "installation. If you are installing FreeBSD for the first time\n" 567 "then you should simply type Q when you're finished here and your\n" 568 "changes will be committed in one batch automatically at the end of\n" 569 "these questions. If you're adding a disk, you should NOT write\n" 570 "from this screen, you should do it from the label editor.\n\n" 571 "Are you absolutely sure you want to do this now?")) { 572 variable_set2(DISK_PARTITIONED, "yes", 0); 573 574#ifdef PC98 575 /* 576 * Don't trash the IPL if the first (and therefore only) chunk 577 * is marked for a truly dedicated disk (i.e., the disklabel 578 * starts at sector 0), even in cases where the user has 579 * requested a FreeBSD Boot Manager -- both would be fatal in 580 * this case. 581 */ 582 /* 583 * Don't offer to update the IPL on this disk if the first 584 * "real" chunk looks like a FreeBSD "all disk" partition, 585 * or the disk is entirely FreeBSD. 586 */ 587 if ((d->chunks->part->type != freebsd) || 588 (d->chunks->part->offset > 1)) 589 getBootMgr(d->name, &bootipl, &bootipl_size, 590 &bootmenu, &bootmenu_size); 591 else { 592 bootipl = NULL; 593 bootipl_size = 0; 594 bootmenu = NULL; 595 bootmenu_size = 0; 596 } 597 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 598#else 599 /* 600 * Don't trash the MBR 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 booteasy or a "standard" MBR -- both would be 604 * fatal in this case. 605 */ 606 /* 607 * Don't offer to update the MBR 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, &mbrContents, &mbrSize); 614 else { 615 mbrContents = NULL; 616 mbrSize = 0; 617 } 618 Set_Boot_Mgr(d, mbrContents, mbrSize); 619#endif 620 621 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 622 msgConfirm("Disk partition write returned an error status!"); 623 else 624 msgConfirm("Wrote FDISK partition information out successfully."); 625 } 626 clear(); 627 break; 628 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 643 case '\033': /* ESC */ 644 case 'Q': 645 chunking = FALSE; 646#ifdef PC98 647 /* 648 * Don't trash the IPL if the first (and therefore only) chunk 649 * is marked for a truly dedicated disk (i.e., the disklabel 650 * starts at sector 0), even in cases where the user has requested 651 * a FreeBSD Boot Manager -- both would be fatal in this case. 652 */ 653 /* 654 * Don't offer to update the IPL on this disk if the first "real" 655 * chunk looks like a FreeBSD "all disk" partition, or the disk is 656 * entirely FreeBSD. 657 */ 658 if ((d->chunks->part->type != freebsd) || 659 (d->chunks->part->offset > 1)) { 660 if (variable_cmp(DISK_PARTITIONED, "written")) { 661 getBootMgr(d->name, &bootipl, &bootipl_size, 662 &bootmenu, &bootmenu_size); 663 if (bootipl != NULL && bootmenu != NULL) 664 Set_Boot_Mgr(d, bootipl, bootipl_size, 665 bootmenu, bootmenu_size); 666 } 667 } 668#else 669 /* 670 * Don't trash the MBR if the first (and therefore only) chunk 671 * is marked for a truly dedicated disk (i.e., the disklabel 672 * starts at sector 0), even in cases where the user has requested 673 * booteasy or a "standard" MBR -- both would be fatal in this case. 674 */ 675 /* 676 * Don't offer to update the MBR on this disk if the first "real" 677 * chunk looks like a FreeBSD "all disk" partition, or the disk is 678 * entirely FreeBSD. 679 */ 680 if ((d->chunks->part->type != freebsd) || 681 (d->chunks->part->offset > 1)) { 682 if (variable_cmp(DISK_PARTITIONED, "written")) { 683 getBootMgr(d->name, &mbrContents, &mbrSize); 684 if (mbrContents != NULL) 685 Set_Boot_Mgr(d, mbrContents, mbrSize); 686 } 687 } 688#endif 689 break; 690 691 case 'Z': 692 size_unit = (size_unit + 1) % UNIT_SIZE; 693 break; 694 695 default: 696 beep(); 697 msg = "Type F1 or ? for help"; 698 break; 699 } 700 } 701 p = CheckRules(d); 702 if (p) { 703 char buf[FILENAME_MAX]; 704 705 use_helpline("Press F1 to read more about disk slices."); 706 use_helpfile(systemHelpFile("partition", buf)); 707 if (!variable_get(VAR_NO_WARN)) 708 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 709 free(p); 710 } 711 restorescr(w); 712} 713#endif /* WITH_SLICES */ 714 715static u_char * 716bootalloc(char *name, size_t *size) 717{ 718 char buf[FILENAME_MAX]; 719 struct stat sb; 720 721 snprintf(buf, sizeof buf, "/boot/%s", name); 722 if (stat(buf, &sb) != -1) { 723 int fd; 724 725 fd = open(buf, O_RDONLY); 726 if (fd != -1) { 727 u_char *cp; 728 729 cp = malloc(sb.st_size); 730 if (read(fd, cp, sb.st_size) != sb.st_size) { 731 free(cp); 732 close(fd); 733 msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); 734 return NULL; 735 } 736 close(fd); 737 if (size != NULL) 738 *size = sb.st_size; 739 return cp; 740 } 741 msgDebug("bootalloc: couldn't open %s\n", buf); 742 } 743 else 744 msgDebug("bootalloc: can't stat %s\n", buf); 745 return NULL; 746} 747 748#ifdef WITH_SLICES 749static int 750partitionHook(dialogMenuItem *selected) 751{ 752 Device **devs = NULL; 753 754 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 755 if (!devs) { 756 msgConfirm("Unable to find disk %s!", selected->prompt); 757 return DITEM_FAILURE; 758 } 759 /* Toggle enabled status? */ 760 if (!devs[0]->enabled) { 761 devs[0]->enabled = TRUE; 762 diskPartition(devs[0]); 763 } 764 else 765 devs[0]->enabled = FALSE; 766 return DITEM_SUCCESS; 767} 768 769static int 770partitionCheck(dialogMenuItem *selected) 771{ 772 Device **devs = NULL; 773 774 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 775 if (!devs || devs[0]->enabled == FALSE) 776 return FALSE; 777 return TRUE; 778} 779 780int 781diskPartitionEditor(dialogMenuItem *self) 782{ 783 DMenu *menu; 784 Device **devs; 785 int i, cnt, devcnt; 786 787 cnt = diskGetSelectCount(&devs); 788 devcnt = deviceCount(devs); 789 if (cnt == -1) { 790 msgConfirm("No disks found! Please verify that your disk controller is being\n" 791 "properly probed at boot time. See the Hardware Guide on the\n" 792 "Documentation menu for clues on diagnosing this type of problem."); 793 return DITEM_FAILURE; 794 } 795 else if (cnt) { 796 /* Some are already selected */ 797 for (i = 0; i < devcnt; i++) { 798 if (devs[i]->enabled) { 799 if (variable_get(VAR_NONINTERACTIVE) && 800 !variable_get(VAR_DISKINTERACTIVE)) 801 diskPartitionNonInteractive(devs[i]); 802 else 803 diskPartition(devs[i]); 804 } 805 } 806 } 807 else { 808 /* No disks are selected, fall-back case now */ 809 if (devcnt == 1) { 810 devs[0]->enabled = TRUE; 811 if (variable_get(VAR_NONINTERACTIVE) && 812 !variable_get(VAR_DISKINTERACTIVE)) 813 diskPartitionNonInteractive(devs[0]); 814 else 815 diskPartition(devs[0]); 816 return DITEM_SUCCESS; 817 } 818 else { 819 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 820 if (!menu) { 821 msgConfirm("No devices suitable for installation found!\n\n" 822 "Please verify that your disk controller (and attached drives)\n" 823 "were detected properly. This can be done by pressing the\n" 824 "[Scroll Lock] key and using the Arrow keys to move back to\n" 825 "the boot messages. Press [Scroll Lock] again to return."); 826 return DITEM_FAILURE; 827 } 828 else { 829 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 830 free(menu); 831 } 832 return i; 833 } 834 } 835 return DITEM_SUCCESS; 836} 837#endif /* WITH_SLICES */ 838 839int 840diskPartitionWrite(dialogMenuItem *self) 841{ 842 Device **devs; 843 int i; 844 845 if (!variable_cmp(DISK_PARTITIONED, "written")) 846 return DITEM_SUCCESS; 847 848 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 849 if (!devs) { 850 msgConfirm("Unable to find any disks to write to??"); 851 return DITEM_FAILURE; 852 } 853 if (isDebug()) 854 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 855 for (i = 0; devs[i]; i++) { 856 Disk *d = (Disk *)devs[i]->private; 857 static u_char *boot1; 858#if defined(__i386__) || defined(__amd64__) 859 static u_char *boot2; 860#endif 861 862 if (!devs[i]->enabled) 863 continue; 864 865#if defined(__i386__) || defined(__amd64__) 866 if (!boot1) boot1 = bootalloc("boot1", NULL); 867 if (!boot2) boot2 = bootalloc("boot2", NULL); 868 Set_Boot_Blocks(d, boot1, boot2); 869#elif !defined(__ia64__) 870 if (!boot1) boot1 = bootalloc("boot1", NULL); 871 Set_Boot_Blocks(d, boot1, NULL); 872#endif 873 874 msgNotify("Writing partition information to drive %s", d->name); 875 if (!Fake && Write_Disk(d)) { 876 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 877 return DITEM_FAILURE; 878 } 879 } 880 /* Now it's not "yes", but "written" */ 881 variable_set2(DISK_PARTITIONED, "written", 0); 882 return DITEM_SUCCESS | DITEM_RESTORE; 883} 884 885#ifdef WITH_SLICES 886/* Partition a disk based wholly on which variables are set */ 887static void 888diskPartitionNonInteractive(Device *dev) 889{ 890 char *cp; 891 int i, all_disk = 0; 892 daddr_t sz; 893#ifdef PC98 894 u_char *bootipl; 895 size_t bootipl_size; 896 u_char *bootmenu; 897 size_t bootmenu_size; 898#else 899 u_char *mbrContents; 900 size_t mbrSize; 901#endif 902 Disk *d = (Disk *)dev->private; 903 904 record_chunks(d); 905 cp = variable_get(VAR_GEOMETRY); 906 if (cp) { 907 msgDebug("Setting geometry from script to: %s\n", cp); 908 d->bios_cyl = strtol(cp, &cp, 0); 909 d->bios_hd = strtol(cp + 1, &cp, 0); 910 d->bios_sect = strtol(cp + 1, 0, 0); 911 } 912 913 cp = variable_get(VAR_PARTITION); 914 if (cp) { 915 if (!strcmp(cp, "free")) { 916 /* Do free disk space case */ 917 for (i = 0; chunk_info[i]; i++) { 918 /* If a chunk is at least 10MB in size, use it. */ 919 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 920 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 921 freebsd, 3, 922 (chunk_info[i]->flags & CHUNK_ALIGN), 923 "FreeBSD"); 924 variable_set2(DISK_PARTITIONED, "yes", 0); 925 break; 926 } 927 } 928 if (!chunk_info[i]) { 929 msgConfirm("Unable to find any free space on this disk!"); 930 return; 931 } 932 } 933 else if (!strcmp(cp, "all")) { 934 /* Do all disk space case */ 935 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 936 937 All_FreeBSD(d, FALSE); 938 } 939 else if (!strcmp(cp, "exclusive")) { 940 /* Do really-all-the-disk-space case */ 941 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 942 943 All_FreeBSD(d, all_disk = TRUE); 944 } 945 else if ((sz = strtoimax(cp, &cp, 0))) { 946 /* Look for sz bytes free */ 947 if (*cp && toupper(*cp) == 'M') 948 sz *= ONE_MEG; 949 else if (*cp && toupper(*cp) == 'G') 950 sz *= ONE_GIG; 951 for (i = 0; chunk_info[i]; i++) { 952 /* If a chunk is at least sz MB, use it. */ 953 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 954 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 955 (chunk_info[i]->flags & CHUNK_ALIGN), 956 "FreeBSD"); 957 variable_set2(DISK_PARTITIONED, "yes", 0); 958 break; 959 } 960 } 961 if (!chunk_info[i]) { 962 msgConfirm("Unable to find %jd free blocks on this disk!", 963 (intmax_t)sz); 964 return; 965 } 966 } 967 else if (!strcmp(cp, "existing")) { 968 /* Do existing FreeBSD case */ 969 for (i = 0; chunk_info[i]; i++) { 970 if (chunk_info[i]->type == freebsd) 971 break; 972 } 973 if (!chunk_info[i]) { 974 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 975 return; 976 } 977 } 978 else { 979 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 980 return; 981 } 982 if (!all_disk) { 983#ifdef PC98 984 getBootMgr(d->name, &bootipl, &bootipl_size, 985 &bootmenu, &bootmenu_size); 986 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 987#else 988 getBootMgr(d->name, &mbrContents, &mbrSize); 989 Set_Boot_Mgr(d, mbrContents, mbrSize); 990#endif 991 } 992 variable_set2(DISK_PARTITIONED, "yes", 0); 993 } 994} 995#endif /* WITH_SLICES */ 996