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