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