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