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