disks.c revision 107554
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 107554 2002-12-03 16:09:55Z jhb $ 8 * 9 * Copyright (c) 1995 10 * Jordan Hubbard. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer, 17 * verbatim and that no modifications are made prior to this 18 * point in the file. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37#include "sysinstall.h" 38#include <ctype.h> 39#include <fcntl.h> 40#include <sys/stat.h> 41#include <sys/disklabel.h> 42 43#ifdef WITH_SLICES 44enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_SIZE }; 45 46#ifdef PC98 47#define SUBTYPE_FREEBSD 50324 48#define SUBTYPE_FAT 37218 49#else 50#define SUBTYPE_FREEBSD 165 51#define SUBTYPE_FAT 6 52#endif 53#define SUBTYPE_EFI 239 54 55/* Where we start displaying chunk information on the screen */ 56#define CHUNK_START_ROW 5 57 58/* Where we keep track of MBR chunks */ 59static struct chunk *chunk_info[16]; 60static int current_chunk; 61 62static void diskPartitionNonInteractive(Device *dev); 63static u_char * bootalloc(char *name, size_t *size); 64 65static void 66record_chunks(Disk *d) 67{ 68 struct chunk *c1 = NULL; 69 int i = 0; 70 int last_free = 0; 71 72 if (!d->chunks) 73 msgFatal("No chunk list found for %s!", d->name); 74 75 for (c1 = d->chunks->part; c1; c1 = c1->next) { 76 if (c1->type == unused && c1->size > last_free) { 77 last_free = c1->size; 78 current_chunk = i; 79 } 80 chunk_info[i++] = c1; 81 } 82 chunk_info[i] = NULL; 83 if (current_chunk >= i) 84 current_chunk = i - 1; 85} 86 87static int Total; 88 89static void 90print_chunks(Disk *d, int u) 91{ 92 int row; 93 int i; 94 int sz; 95 char *szstr; 96 97 szstr = (u == UNIT_MEG ? "MB" : (u == UNIT_KILO ? "KB" : "ST")); 98 99 for (i = Total = 0; chunk_info[i]; i++) 100 Total += chunk_info[i]->size; 101#ifdef PC98 102 if (d->bios_cyl >= 65536 || d->bios_hd > 16 || d->bios_sect >= 256) { 103#else 104 if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { 105#endif 106 dialog_clear_norefresh(); 107 msgConfirm("WARNING: A geometry of %lu/%lu/%lu for %s is incorrect. Using\n" 108 "a more likely geometry. If this geometry is incorrect or you\n" 109 "are unsure as to whether or not it's correct, please consult\n" 110 "the Hardware Guide in the Documentation submenu or use the\n" 111 "(G)eometry command to change it now.\n\n" 112 "Remember: you need to enter whatever your BIOS thinks the\n" 113 "geometry is! For IDE, it's what you were told in the BIOS\n" 114 "setup. For SCSI, it's the translation mode your controller is\n" 115 "using. Do NOT use a ``physical geometry''.", 116 d->bios_cyl, d->bios_hd, d->bios_sect, d->name); 117 Sanitize_Bios_Geom(d); 118 } 119 attrset(A_NORMAL); 120 mvaddstr(0, 0, "Disk name:\t"); 121 clrtobot(); 122 attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); 123 attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); 124 mvprintw(1, 0, 125 "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors (%luMB)", 126 d->bios_cyl, d->bios_hd, d->bios_sect, 127 d->bios_cyl * d->bios_hd * d->bios_sect, 128 d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024); 129 mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", 130 "Offset", "Size", szstr, "End", "Name", "PType", "Desc", 131 "Subtype", "Flags"); 132 for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { 133 switch(u) { 134 default: /* fall thru */ 135 case UNIT_BLOCKS: 136 sz = chunk_info[i]->size; 137 break; 138 case UNIT_KILO: 139 sz = chunk_info[i]->size / (1024/512); 140 break; 141 case UNIT_MEG: 142 sz = chunk_info[i]->size / (1024/512) / 1024; 143 break; 144 } 145 if (i == current_chunk) 146 attrset(ATTR_SELECTED); 147 mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s", 148 chunk_info[i]->offset, sz, 149 chunk_info[i]->end, chunk_info[i]->name, 150 chunk_info[i]->type, 151 slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), 152 chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); 153 if (i == current_chunk) 154 attrset(A_NORMAL); 155 } 156} 157 158static void 159print_command_summary() 160{ 161 mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); 162 mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice F = `DD' mode"); 163 mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable | = Wizard m."); 164 mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); 165 if (!RunningAsInit) 166 mvprintw(18, 47, "W = Write Changes"); 167 mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); 168 move(0, 0); 169} 170 171#ifdef PC98 172static void 173getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, 174 u_char **bootmenu, size_t *bootmenu_size) 175{ 176 static u_char *boot0; 177 static size_t boot0_size; 178 static u_char *boot05; 179 static size_t boot05_size; 180 181 char str[80]; 182 char *cp; 183 int i = 0; 184 185 cp = variable_get(VAR_BOOTMGR); 186 if (!cp) { 187 /* Figure out what kind of IPL the user wants */ 188 sprintf(str, "Install Boot Manager for drive %s?", dname); 189 MenuIPLType.title = str; 190 i = dmenuOpenSimple(&MenuIPLType, FALSE); 191 } else { 192 if (!strncmp(cp, "boot", 4)) 193 BootMgr = 0; 194 else 195 BootMgr = 1; 196 } 197 if (cp || i) { 198 switch (BootMgr) { 199 case 0: 200 if (!boot0) boot0 = bootalloc("boot0", &boot0_size); 201 *bootipl = boot0; 202 *bootipl_size = boot0_size; 203 if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size); 204 *bootmenu = boot05; 205 *bootmenu_size = boot05_size; 206 return; 207 case 1: 208 default: 209 break; 210 } 211 } 212 *bootipl = NULL; 213 *bootipl_size = 0; 214 *bootmenu = NULL; 215 *bootmenu_size = 0; 216} 217#else 218static void 219getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) 220{ 221#ifdef __i386__ /* only meaningful on x86 */ 222 static u_char *mbr, *boot0; 223 static size_t mbr_size, boot0_size; 224 char str[80]; 225 char *cp; 226 int i = 0; 227 228 cp = variable_get(VAR_BOOTMGR); 229 if (!cp) { 230 /* Figure out what kind of MBR the user wants */ 231 sprintf(str, "Install Boot Manager for drive %s?", dname); 232 MenuMBRType.title = str; 233 i = dmenuOpenSimple(&MenuMBRType, FALSE); 234 } 235 else { 236 if (!strncmp(cp, "boot", 4)) 237 BootMgr = 0; 238 else if (!strcmp(cp, "standard")) 239 BootMgr = 1; 240 else 241 BootMgr = 2; 242 } 243 if (cp || i) { 244 switch (BootMgr) { 245 case 0: 246 if (!boot0) boot0 = bootalloc("boot0", &boot0_size); 247 *bootCode = boot0; 248 *bootCodeSize = boot0_size; 249 return; 250 case 1: 251 if (!mbr) mbr = bootalloc("mbr", &mbr_size); 252 *bootCode = mbr; 253 *bootCodeSize = mbr_size; 254 return; 255 case 2: 256 default: 257 break; 258 } 259 } 260#endif 261 *bootCode = NULL; 262 *bootCodeSize = 0; 263} 264#endif 265#endif /* WITH_SLICES */ 266 267int 268diskGetSelectCount(Device ***devs) 269{ 270 int i, cnt, enabled; 271 char *cp; 272 Device **dp; 273 274 cp = variable_get(VAR_DISK); 275 dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); 276 cnt = deviceCount(dp); 277 if (!cnt) 278 return -1; 279 for (i = 0, enabled = 0; i < cnt; i++) { 280 if (dp[i]->enabled) 281 ++enabled; 282 } 283 return enabled; 284} 285 286#ifdef WITH_SLICES 287void 288diskPartition(Device *dev) 289{ 290 char *cp, *p; 291 int rv, key = 0; 292 Boolean chunking; 293 char *msg = NULL; 294#ifdef PC98 295 u_char *bootipl; 296 size_t bootipl_size; 297 u_char *bootmenu; 298 size_t bootmenu_size; 299#else 300 u_char *mbrContents; 301 size_t mbrSize; 302#endif 303 WINDOW *w = savescr(); 304 Disk *d = (Disk *)dev->private; 305 int size_unit; 306 307 size_unit = UNIT_BLOCKS; 308 chunking = TRUE; 309 keypad(stdscr, TRUE); 310 311 /* Flush both the dialog and curses library views of the screen 312 since we don't always know who called us */ 313 dialog_clear_norefresh(), clear(); 314 current_chunk = 0; 315 316 /* Set up the chunk array */ 317 record_chunks(d); 318 319 while (chunking) { 320 char *val, geometry[80]; 321 322 /* Now print our overall state */ 323 if (d) 324 print_chunks(d, size_unit); 325 print_command_summary(); 326 if (msg) { 327 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 328 beep(); 329 msg = NULL; 330 } 331 else { 332 move(23, 0); 333 clrtoeol(); 334 } 335 336 /* Get command character */ 337 key = getch(); 338 switch (toupper(key)) { 339 case '\014': /* ^L (redraw) */ 340 clear(); 341 msg = NULL; 342 break; 343 344 case '\020': /* ^P */ 345 case KEY_UP: 346 case '-': 347 if (current_chunk != 0) 348 --current_chunk; 349 break; 350 351 case '\016': /* ^N */ 352 case KEY_DOWN: 353 case '+': 354 case '\r': 355 case '\n': 356 if (chunk_info[current_chunk + 1]) 357 ++current_chunk; 358 break; 359 360 case KEY_HOME: 361 current_chunk = 0; 362 break; 363 364 case KEY_END: 365 while (chunk_info[current_chunk + 1]) 366 ++current_chunk; 367 break; 368 369 case KEY_F(1): 370 case '?': 371 systemDisplayHelp("slice"); 372 clear(); 373 break; 374 375 case 'A': 376 case 'F': /* Undocumented magic Dangerously Dedicated mode */ 377#ifndef __i386__ 378 rv = 1; 379#else /* The rest is only relevant on x86 */ 380 cp = variable_get(VAR_DEDICATE_DISK); 381 if (cp && !strcasecmp(cp, "always")) 382 rv = 1; 383 else if (toupper(key) == 'A') 384 rv = 0; 385 else { 386 rv = msgYesNo("Do you want to do this with a true partition entry\n" 387 "so as to remain cooperative with any future possible\n" 388 "operating systems on the drive(s)?\n" 389 "(See also the section about ``dangerously dedicated''\n" 390 "disks in the FreeBSD FAQ.)"); 391 if (rv == -1) 392 rv = 0; 393 } 394#endif 395 All_FreeBSD(d, rv); 396 variable_set2(DISK_PARTITIONED, "yes", 0); 397 record_chunks(d); 398 clear(); 399 break; 400 401 case 'C': 402 if (chunk_info[current_chunk]->type != unused) 403 msg = "Slice in use, delete it first or move to an unused one."; 404 else { 405 char *val, tmp[20], name[16], *cp; 406 int size, subtype; 407 chunk_e partitiontype; 408#ifdef PC98 409 snprintf(name, sizeof (name), "%s", "FreeBSD"); 410 val = msgGetInput(name, 411 "Please specify the name for new FreeBSD slice."); 412 if (val) 413 strncpy(name, val, sizeof (name)); 414#else 415 name[0] = '\0'; 416#endif 417 snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); 418 val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" 419 "or append a trailing `M' for megabytes (e.g. 20M)."); 420 if (val && (size = strtol(val, &cp, 0)) > 0) { 421 if (*cp && toupper(*cp) == 'M') 422 size *= ONE_MEG; 423 else if (*cp && toupper(*cp) == 'G') 424 size *= ONE_GIG; 425 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 426#ifdef PC98 427 val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 428 "Pressing Enter will choose the default, a native FreeBSD\n" 429 "slice (type 50324). You can choose other types, 37218 for a\n" 430 "DOS partition, for example.\n\n" 431 "Note: If you choose a non-FreeBSD partition type, it will not\n" 432 "be formatted or otherwise prepared, it will simply reserve space\n" 433 "for you to use another tool, such as DOS FORMAT, to later format\n" 434 "and use the partition."); 435#else 436 val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 437 "Pressing Enter will choose the default, a native FreeBSD\n" 438 "slice (type 165). You can choose other types, 6 for a\n" 439 "DOS partition or 131 for a Linux partition, for example.\n\n" 440 "Note: If you choose a non-FreeBSD partition type, it will not\n" 441 "be formatted or otherwise prepared, it will simply reserve space\n" 442 "for you to use another tool, such as DOS FORMAT, to later format\n" 443 "and use the partition."); 444#endif /* PC98 */ 445 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 446 if (subtype == SUBTYPE_FREEBSD) 447 partitiontype = freebsd; 448 else if (subtype == SUBTYPE_FAT) 449 partitiontype = fat; 450 else if (subtype == SUBTYPE_EFI) 451 partitiontype = efi; 452 else 453 partitiontype = mbr; 454 Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 455 (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); 456 variable_set2(DISK_PARTITIONED, "yes", 0); 457 record_chunks(d); 458 } 459 } 460 clear(); 461 } 462 break; 463 464 case KEY_DC: 465 case 'D': 466 if (chunk_info[current_chunk]->type == unused) 467 msg = "Slice is already unused!"; 468 else { 469 Delete_Chunk(d, chunk_info[current_chunk]); 470 variable_set2(DISK_PARTITIONED, "yes", 0); 471 record_chunks(d); 472 } 473 break; 474 475 case 'T': 476 if (chunk_info[current_chunk]->type == unused) 477 msg = "Slice is currently unused (use create instead)"; 478 else { 479 char *val, tmp[20]; 480 int subtype; 481 chunk_e partitiontype; 482 483 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 484#ifdef PC98 485 val = msgGetInput(tmp, "New partition type:\n\n" 486 "Pressing Enter will choose the default, a native FreeBSD\n" 487 "slice (type 50324). Other popular values are 37218 for\n" 488 "DOS FAT partition.\n\n" 489 "Note: If you choose a non-FreeBSD partition type, it will not\n" 490 "be formatted or otherwise prepared, it will simply reserve space\n" 491 "for you to use another tool, such as DOS format, to later format\n" 492 "and actually use the partition."); 493#else 494 val = msgGetInput(tmp, "New partition type:\n\n" 495 "Pressing Enter will choose the default, a native FreeBSD\n" 496 "slice (type 165). Other popular values are 6 for\n" 497 "DOS FAT partition, 131 for a Linux ext2fs partition or\n" 498 "130 for a Linux swap partition.\n\n" 499 "Note: If you choose a non-FreeBSD partition type, it will not\n" 500 "be formatted or otherwise prepared, it will simply reserve space\n" 501 "for you to use another tool, such as DOS format, to later format\n" 502 "and actually use the partition."); 503#endif /* PC98 */ 504 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 505 if (subtype == SUBTYPE_FREEBSD) 506 partitiontype = freebsd; 507 else if (subtype == SUBTYPE_FAT) 508 partitiontype = fat; 509 else if (subtype == SUBTYPE_EFI) 510 partitiontype = efi; 511 else 512 partitiontype = mbr; 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#endif /* WITH_SLICES */ 711 712static u_char * 713bootalloc(char *name, size_t *size) 714{ 715 char buf[FILENAME_MAX]; 716 struct stat sb; 717 718 snprintf(buf, sizeof buf, "/boot/%s", name); 719 if (stat(buf, &sb) != -1) { 720 int fd; 721 722 fd = open(buf, O_RDONLY); 723 if (fd != -1) { 724 u_char *cp; 725 726 cp = malloc(sb.st_size); 727 if (read(fd, cp, sb.st_size) != sb.st_size) { 728 free(cp); 729 close(fd); 730 msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); 731 return NULL; 732 } 733 close(fd); 734 if (size != NULL) 735 *size = sb.st_size; 736 return cp; 737 } 738 msgDebug("bootalloc: couldn't open %s\n", buf); 739 } 740 else 741 msgDebug("bootalloc: can't stat %s\n", buf); 742 return NULL; 743} 744 745#ifdef WITH_SLICES 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#endif /* WITH_SLICES */ 835 836int 837diskPartitionWrite(dialogMenuItem *self) 838{ 839 Device **devs; 840 int i; 841 842 if (!variable_cmp(DISK_PARTITIONED, "written")) 843 return DITEM_SUCCESS; 844 845 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 846 if (!devs) { 847 msgConfirm("Unable to find any disks to write to??"); 848 return DITEM_FAILURE; 849 } 850 if (isDebug()) 851 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 852 for (i = 0; devs[i]; i++) { 853 Disk *d = (Disk *)devs[i]->private; 854 static u_char *boot1; 855#if defined(__i386__) || defined(__ia64__) 856 static u_char *boot2; 857#endif 858 859 if (!devs[i]->enabled) 860 continue; 861 862#if defined(__i386__) || defined(__ia64__) 863 if (!boot1) boot1 = bootalloc("boot1", NULL); 864 if (!boot2) boot2 = bootalloc("boot2", NULL); 865 Set_Boot_Blocks(d, boot1, boot2); 866#else 867 if (!boot1) boot1 = bootalloc("boot1", NULL); 868 Set_Boot_Blocks(d, boot1, NULL); 869#endif 870 871 msgNotify("Writing partition information to drive %s", d->name); 872 if (!Fake && Write_Disk(d)) { 873 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 874 return DITEM_FAILURE; 875 } 876 } 877 /* Now it's not "yes", but "written" */ 878 variable_set2(DISK_PARTITIONED, "written", 0); 879 return DITEM_SUCCESS | DITEM_RESTORE; 880} 881 882#ifdef WITH_SLICES 883/* Partition a disk based wholly on which variables are set */ 884static void 885diskPartitionNonInteractive(Device *dev) 886{ 887 char *cp; 888 int i, sz, all_disk = 0; 889#ifdef PC98 890 u_char *bootipl; 891 size_t bootipl_size; 892 u_char *bootmenu; 893 size_t bootmenu_size; 894#else 895 u_char *mbrContents; 896 size_t mbrSize; 897#endif 898 Disk *d = (Disk *)dev->private; 899 900 record_chunks(d); 901 cp = variable_get(VAR_GEOMETRY); 902 if (cp) { 903 msgDebug("Setting geometry from script to: %s\n", cp); 904 d->bios_cyl = strtol(cp, &cp, 0); 905 d->bios_hd = strtol(cp + 1, &cp, 0); 906 d->bios_sect = strtol(cp + 1, 0, 0); 907 } 908 909 cp = variable_get(VAR_PARTITION); 910 if (cp) { 911 if (!strcmp(cp, "free")) { 912 /* Do free disk space case */ 913 for (i = 0; chunk_info[i]; i++) { 914 /* If a chunk is at least 10MB in size, use it. */ 915 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 916 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 917 freebsd, 3, 918 (chunk_info[i]->flags & CHUNK_ALIGN), 919 "FreeBSD"); 920 variable_set2(DISK_PARTITIONED, "yes", 0); 921 break; 922 } 923 } 924 if (!chunk_info[i]) { 925 msgConfirm("Unable to find any free space on this disk!"); 926 return; 927 } 928 } 929 else if (!strcmp(cp, "all")) { 930 /* Do all disk space case */ 931 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 932 933 All_FreeBSD(d, FALSE); 934 } 935 else if (!strcmp(cp, "exclusive")) { 936 /* Do really-all-the-disk-space case */ 937 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 938 939 All_FreeBSD(d, all_disk = TRUE); 940 } 941 else if ((sz = strtol(cp, &cp, 0))) { 942 /* Look for sz bytes free */ 943 if (*cp && toupper(*cp) == 'M') 944 sz *= ONE_MEG; 945 else if (*cp && toupper(*cp) == 'G') 946 sz *= ONE_GIG; 947 for (i = 0; chunk_info[i]; i++) { 948 /* If a chunk is at least sz MB, use it. */ 949 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 950 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 951 (chunk_info[i]->flags & CHUNK_ALIGN), 952 "FreeBSD"); 953 variable_set2(DISK_PARTITIONED, "yes", 0); 954 break; 955 } 956 } 957 if (!chunk_info[i]) { 958 msgConfirm("Unable to find %d free blocks on this disk!", sz); 959 return; 960 } 961 } 962 else if (!strcmp(cp, "existing")) { 963 /* Do existing FreeBSD case */ 964 for (i = 0; chunk_info[i]; i++) { 965 if (chunk_info[i]->type == freebsd) 966 break; 967 } 968 if (!chunk_info[i]) { 969 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 970 return; 971 } 972 } 973 else { 974 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 975 return; 976 } 977 if (!all_disk) { 978#ifdef PC98 979 getBootMgr(d->name, &bootipl, &bootipl_size, 980 &bootmenu, &bootmenu_size); 981 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 982#else 983 getBootMgr(d->name, &mbrContents, &mbrSize); 984 Set_Boot_Mgr(d, mbrContents, mbrSize); 985#endif 986 } 987 variable_set2(DISK_PARTITIONED, "yes", 0); 988 } 989} 990#endif /* WITH_SLICES */ 991