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