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