disks.c revision 107587
13125Sdg/* 23125Sdg * The new sysinstall program. 33125Sdg * 43125Sdg * This is probably the last program in the `sysinstall' line - the next 53125Sdg * generation being essentially a complete rewrite. 63125Sdg * 73125Sdg * $FreeBSD: head/usr.sbin/sade/disks.c 107587 2002-12-04 15:07:05Z nyan $ 83125Sdg * 93125Sdg * Copyright (c) 1995 103125Sdg * Jordan Hubbard. All rights reserved. 113125Sdg * 123125Sdg * Redistribution and use in source and binary forms, with or without 133125Sdg * modification, are permitted provided that the following conditions 143125Sdg * are met: 153125Sdg * 1. Redistributions of source code must retain the above copyright 163125Sdg * notice, this list of conditions and the following disclaimer, 173125Sdg * verbatim and that no modifications are made prior to this 183125Sdg * point in the file. 193125Sdg * 2. Redistributions in binary form must reproduce the above copyright 203125Sdg * notice, this list of conditions and the following disclaimer in the 213125Sdg * documentation and/or other materials provided with the distribution. 223125Sdg * 233125Sdg * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 243125Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 253125Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 263125Sdg * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 273125Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 283125Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 293125Sdg * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 3050479Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 313125Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 323125Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 333125Sdg * SUCH DAMAGE. 343125Sdg * 353125Sdg */ 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#ifdef PC98 454 partitiontype = pc98; 455#else 456 partitiontype = mbr; 457#endif 458 Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 459 (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); 460 variable_set2(DISK_PARTITIONED, "yes", 0); 461 record_chunks(d); 462 } 463 } 464 clear(); 465 } 466 break; 467 468 case KEY_DC: 469 case 'D': 470 if (chunk_info[current_chunk]->type == unused) 471 msg = "Slice is already unused!"; 472 else { 473 Delete_Chunk(d, chunk_info[current_chunk]); 474 variable_set2(DISK_PARTITIONED, "yes", 0); 475 record_chunks(d); 476 } 477 break; 478 479 case 'T': 480 if (chunk_info[current_chunk]->type == unused) 481 msg = "Slice is currently unused (use create instead)"; 482 else { 483 char *val, tmp[20]; 484 int subtype; 485 chunk_e partitiontype; 486 487 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 488#ifdef PC98 489 val = msgGetInput(tmp, "New partition type:\n\n" 490 "Pressing Enter will choose the default, a native FreeBSD\n" 491 "slice (type 50324). Other popular values are 37218 for\n" 492 "DOS FAT partition.\n\n" 493 "Note: If you choose a non-FreeBSD partition type, it will not\n" 494 "be formatted or otherwise prepared, it will simply reserve space\n" 495 "for you to use another tool, such as DOS format, to later format\n" 496 "and actually use the partition."); 497#else 498 val = msgGetInput(tmp, "New partition type:\n\n" 499 "Pressing Enter will choose the default, a native FreeBSD\n" 500 "slice (type 165). Other popular values are 6 for\n" 501 "DOS FAT partition, 131 for a Linux ext2fs partition or\n" 502 "130 for a Linux swap partition.\n\n" 503 "Note: If you choose a non-FreeBSD partition type, it will not\n" 504 "be formatted or otherwise prepared, it will simply reserve space\n" 505 "for you to use another tool, such as DOS format, to later format\n" 506 "and actually use the partition."); 507#endif /* PC98 */ 508 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 509 if (subtype == SUBTYPE_FREEBSD) 510 partitiontype = freebsd; 511 else if (subtype == SUBTYPE_FAT) 512 partitiontype = fat; 513 else if (subtype == SUBTYPE_EFI) 514 partitiontype = efi; 515 else 516#ifdef PC98 517 partitiontype = pc98; 518#else 519 partitiontype = mbr; 520#endif 521 chunk_info[current_chunk]->type = partitiontype; 522 chunk_info[current_chunk]->subtype = subtype; 523 } 524 } 525 break; 526 527 case 'G': 528 snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); 529 val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" 530 "Don't forget to use the two slash (/) separator characters!\n" 531 "It's not possible to parse the field without them."); 532 if (val) { 533 long nc, nh, ns; 534 nc = strtol(val, &val, 0); 535 nh = strtol(val + 1, &val, 0); 536 ns = strtol(val + 1, 0, 0); 537 Set_Bios_Geom(d, nc, nh, ns); 538 } 539 clear(); 540 break; 541 542 case 'S': 543 /* Set Bootable */ 544 chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 545 break; 546 547 case 'U': 548 if (!variable_cmp(DISK_LABELLED, "written")) { 549 msgConfirm("You've already written this information out - you\n" 550 "can't undo it."); 551 } 552 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 553 char cp[BUFSIZ]; 554 555 sstrncpy(cp, d->name, sizeof cp); 556 Free_Disk(dev->private); 557 d = Open_Disk(cp); 558 if (!d) 559 msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 560 dev->private = d; 561 variable_unset(DISK_PARTITIONED); 562 variable_unset(DISK_LABELLED); 563 if (d) 564 record_chunks(d); 565 } 566 clear(); 567 break; 568 569 case 'W': 570 if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 571 "installation. If you are installing FreeBSD for the first time\n" 572 "then you should simply type Q when you're finished here and your\n" 573 "changes will be committed in one batch automatically at the end of\n" 574 "these questions. If you're adding a disk, you should NOT write\n" 575 "from this screen, you should do it from the label editor.\n\n" 576 "Are you absolutely sure you want to do this now?")) { 577 variable_set2(DISK_PARTITIONED, "yes", 0); 578 579#ifdef PC98 580 /* 581 * Don't trash the IPL if the first (and therefore only) chunk 582 * is marked for a truly dedicated disk (i.e., the disklabel 583 * starts at sector 0), even in cases where the user has 584 * requested a FreeBSD Boot Manager -- both would be fatal in 585 * this case. 586 */ 587 /* 588 * Don't offer to update the IPL on this disk if the first 589 * "real" chunk looks like a FreeBSD "all disk" partition, 590 * or the disk is entirely FreeBSD. 591 */ 592 if ((d->chunks->part->type != freebsd) || 593 (d->chunks->part->offset > 1)) 594 getBootMgr(d->name, &bootipl, &bootipl_size, 595 &bootmenu, &bootmenu_size); 596 else { 597 bootipl = NULL; 598 bootipl_size = 0; 599 bootmenu = NULL; 600 bootmenu_size = 0; 601 } 602 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 603#else 604 /* 605 * Don't trash the MBR if the first (and therefore only) chunk 606 * is marked for a truly dedicated disk (i.e., the disklabel 607 * starts at sector 0), even in cases where the user has 608 * requested booteasy or a "standard" MBR -- both would be 609 * fatal in this case. 610 */ 611 /* 612 * Don't offer to update the MBR on this disk if the first 613 * "real" chunk looks like a FreeBSD "all disk" partition, 614 * or the disk is entirely FreeBSD. 615 */ 616 if ((d->chunks->part->type != freebsd) || 617 (d->chunks->part->offset > 1)) 618 getBootMgr(d->name, &mbrContents, &mbrSize); 619 else { 620 mbrContents = NULL; 621 mbrSize = 0; 622 } 623 Set_Boot_Mgr(d, mbrContents, mbrSize); 624#endif 625 626 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 627 msgConfirm("Disk partition write returned an error status!"); 628 else 629 msgConfirm("Wrote FDISK partition information out successfully."); 630 } 631 clear(); 632 break; 633 634 case '|': 635 if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" 636 "No seat belts whatsoever are provided!")) { 637 clear(); 638 refresh(); 639 slice_wizard(d); 640 variable_set2(DISK_PARTITIONED, "yes", 0); 641 record_chunks(d); 642 } 643 else 644 msg = "Wise choice!"; 645 clear(); 646 break; 647 648 case '\033': /* ESC */ 649 case 'Q': 650 chunking = FALSE; 651#ifdef PC98 652 /* 653 * Don't trash the IPL if the first (and therefore only) chunk 654 * is marked for a truly dedicated disk (i.e., the disklabel 655 * starts at sector 0), even in cases where the user has requested 656 * a FreeBSD Boot Manager -- both would be fatal in this case. 657 */ 658 /* 659 * Don't offer to update the IPL on this disk if the first "real" 660 * chunk looks like a FreeBSD "all disk" partition, or the disk is 661 * entirely FreeBSD. 662 */ 663 if ((d->chunks->part->type != freebsd) || 664 (d->chunks->part->offset > 1)) { 665 if (variable_cmp(DISK_PARTITIONED, "written")) { 666 getBootMgr(d->name, &bootipl, &bootipl_size, 667 &bootmenu, &bootmenu_size); 668 if (bootipl != NULL && bootmenu != NULL) 669 Set_Boot_Mgr(d, bootipl, bootipl_size, 670 bootmenu, bootmenu_size); 671 } 672 } 673#else 674 /* 675 * Don't trash the MBR if the first (and therefore only) chunk 676 * is marked for a truly dedicated disk (i.e., the disklabel 677 * starts at sector 0), even in cases where the user has requested 678 * booteasy or a "standard" MBR -- both would be fatal in this case. 679 */ 680 /* 681 * Don't offer to update the MBR on this disk if the first "real" 682 * chunk looks like a FreeBSD "all disk" partition, or the disk is 683 * entirely FreeBSD. 684 */ 685 if ((d->chunks->part->type != freebsd) || 686 (d->chunks->part->offset > 1)) { 687 if (variable_cmp(DISK_PARTITIONED, "written")) { 688 getBootMgr(d->name, &mbrContents, &mbrSize); 689 if (mbrContents != NULL) 690 Set_Boot_Mgr(d, mbrContents, mbrSize); 691 } 692 } 693#endif 694 break; 695 696 case 'Z': 697 size_unit = (size_unit + 1) % UNIT_SIZE; 698 break; 699 700 default: 701 beep(); 702 msg = "Type F1 or ? for help"; 703 break; 704 } 705 } 706 p = CheckRules(d); 707 if (p) { 708 char buf[FILENAME_MAX]; 709 710 use_helpline("Press F1 to read more about disk slices."); 711 use_helpfile(systemHelpFile("partition", buf)); 712 if (!variable_get(VAR_NO_WARN)) 713 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 714 free(p); 715 } 716 restorescr(w); 717} 718#endif /* WITH_SLICES */ 719 720static u_char * 721bootalloc(char *name, size_t *size) 722{ 723 char buf[FILENAME_MAX]; 724 struct stat sb; 725 726 snprintf(buf, sizeof buf, "/boot/%s", name); 727 if (stat(buf, &sb) != -1) { 728 int fd; 729 730 fd = open(buf, O_RDONLY); 731 if (fd != -1) { 732 u_char *cp; 733 734 cp = malloc(sb.st_size); 735 if (read(fd, cp, sb.st_size) != sb.st_size) { 736 free(cp); 737 close(fd); 738 msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); 739 return NULL; 740 } 741 close(fd); 742 if (size != NULL) 743 *size = sb.st_size; 744 return cp; 745 } 746 msgDebug("bootalloc: couldn't open %s\n", buf); 747 } 748 else 749 msgDebug("bootalloc: can't stat %s\n", buf); 750 return NULL; 751} 752 753#ifdef WITH_SLICES 754static int 755partitionHook(dialogMenuItem *selected) 756{ 757 Device **devs = NULL; 758 759 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 760 if (!devs) { 761 msgConfirm("Unable to find disk %s!", selected->prompt); 762 return DITEM_FAILURE; 763 } 764 /* Toggle enabled status? */ 765 if (!devs[0]->enabled) { 766 devs[0]->enabled = TRUE; 767 diskPartition(devs[0]); 768 } 769 else 770 devs[0]->enabled = FALSE; 771 return DITEM_SUCCESS; 772} 773 774static int 775partitionCheck(dialogMenuItem *selected) 776{ 777 Device **devs = NULL; 778 779 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 780 if (!devs || devs[0]->enabled == FALSE) 781 return FALSE; 782 return TRUE; 783} 784 785int 786diskPartitionEditor(dialogMenuItem *self) 787{ 788 DMenu *menu; 789 Device **devs; 790 int i, cnt, devcnt; 791 792 cnt = diskGetSelectCount(&devs); 793 devcnt = deviceCount(devs); 794 if (cnt == -1) { 795 msgConfirm("No disks found! Please verify that your disk controller is being\n" 796 "properly probed at boot time. See the Hardware Guide on the\n" 797 "Documentation menu for clues on diagnosing this type of problem."); 798 return DITEM_FAILURE; 799 } 800 else if (cnt) { 801 /* Some are already selected */ 802 for (i = 0; i < devcnt; i++) { 803 if (devs[i]->enabled) { 804 if (variable_get(VAR_NONINTERACTIVE) && 805 !variable_get(VAR_DISKINTERACTIVE)) 806 diskPartitionNonInteractive(devs[i]); 807 else 808 diskPartition(devs[i]); 809 } 810 } 811 } 812 else { 813 /* No disks are selected, fall-back case now */ 814 if (devcnt == 1) { 815 devs[0]->enabled = TRUE; 816 if (variable_get(VAR_NONINTERACTIVE) && 817 !variable_get(VAR_DISKINTERACTIVE)) 818 diskPartitionNonInteractive(devs[0]); 819 else 820 diskPartition(devs[0]); 821 return DITEM_SUCCESS; 822 } 823 else { 824 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 825 if (!menu) { 826 msgConfirm("No devices suitable for installation found!\n\n" 827 "Please verify that your disk controller (and attached drives)\n" 828 "were detected properly. This can be done by pressing the\n" 829 "[Scroll Lock] key and using the Arrow keys to move back to\n" 830 "the boot messages. Press [Scroll Lock] again to return."); 831 return DITEM_FAILURE; 832 } 833 else { 834 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 835 free(menu); 836 } 837 return i; 838 } 839 } 840 return DITEM_SUCCESS; 841} 842#endif /* WITH_SLICES */ 843 844int 845diskPartitionWrite(dialogMenuItem *self) 846{ 847 Device **devs; 848 int i; 849 850 if (!variable_cmp(DISK_PARTITIONED, "written")) 851 return DITEM_SUCCESS; 852 853 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 854 if (!devs) { 855 msgConfirm("Unable to find any disks to write to??"); 856 return DITEM_FAILURE; 857 } 858 if (isDebug()) 859 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 860 for (i = 0; devs[i]; i++) { 861 Disk *d = (Disk *)devs[i]->private; 862 static u_char *boot1; 863#if defined(__i386__) || defined(__ia64__) 864 static u_char *boot2; 865#endif 866 867 if (!devs[i]->enabled) 868 continue; 869 870#if defined(__i386__) || defined(__ia64__) 871 if (!boot1) boot1 = bootalloc("boot1", NULL); 872 if (!boot2) boot2 = bootalloc("boot2", NULL); 873 Set_Boot_Blocks(d, boot1, boot2); 874#else 875 if (!boot1) boot1 = bootalloc("boot1", NULL); 876 Set_Boot_Blocks(d, boot1, NULL); 877#endif 878 879 msgNotify("Writing partition information to drive %s", d->name); 880 if (!Fake && Write_Disk(d)) { 881 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 882 return DITEM_FAILURE; 883 } 884 } 885 /* Now it's not "yes", but "written" */ 886 variable_set2(DISK_PARTITIONED, "written", 0); 887 return DITEM_SUCCESS | DITEM_RESTORE; 888} 889 890#ifdef WITH_SLICES 891/* Partition a disk based wholly on which variables are set */ 892static void 893diskPartitionNonInteractive(Device *dev) 894{ 895 char *cp; 896 int i, sz, all_disk = 0; 897#ifdef PC98 898 u_char *bootipl; 899 size_t bootipl_size; 900 u_char *bootmenu; 901 size_t bootmenu_size; 902#else 903 u_char *mbrContents; 904 size_t mbrSize; 905#endif 906 Disk *d = (Disk *)dev->private; 907 908 record_chunks(d); 909 cp = variable_get(VAR_GEOMETRY); 910 if (cp) { 911 msgDebug("Setting geometry from script to: %s\n", cp); 912 d->bios_cyl = strtol(cp, &cp, 0); 913 d->bios_hd = strtol(cp + 1, &cp, 0); 914 d->bios_sect = strtol(cp + 1, 0, 0); 915 } 916 917 cp = variable_get(VAR_PARTITION); 918 if (cp) { 919 if (!strcmp(cp, "free")) { 920 /* Do free disk space case */ 921 for (i = 0; chunk_info[i]; i++) { 922 /* If a chunk is at least 10MB in size, use it. */ 923 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 924 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 925 freebsd, 3, 926 (chunk_info[i]->flags & CHUNK_ALIGN), 927 "FreeBSD"); 928 variable_set2(DISK_PARTITIONED, "yes", 0); 929 break; 930 } 931 } 932 if (!chunk_info[i]) { 933 msgConfirm("Unable to find any free space on this disk!"); 934 return; 935 } 936 } 937 else if (!strcmp(cp, "all")) { 938 /* Do all disk space case */ 939 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 940 941 All_FreeBSD(d, FALSE); 942 } 943 else if (!strcmp(cp, "exclusive")) { 944 /* Do really-all-the-disk-space case */ 945 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 946 947 All_FreeBSD(d, all_disk = TRUE); 948 } 949 else if ((sz = strtol(cp, &cp, 0))) { 950 /* Look for sz bytes free */ 951 if (*cp && toupper(*cp) == 'M') 952 sz *= ONE_MEG; 953 else if (*cp && toupper(*cp) == 'G') 954 sz *= ONE_GIG; 955 for (i = 0; chunk_info[i]; i++) { 956 /* If a chunk is at least sz MB, use it. */ 957 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 958 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 959 (chunk_info[i]->flags & CHUNK_ALIGN), 960 "FreeBSD"); 961 variable_set2(DISK_PARTITIONED, "yes", 0); 962 break; 963 } 964 } 965 if (!chunk_info[i]) { 966 msgConfirm("Unable to find %d free blocks on this disk!", sz); 967 return; 968 } 969 } 970 else if (!strcmp(cp, "existing")) { 971 /* Do existing FreeBSD case */ 972 for (i = 0; chunk_info[i]; i++) { 973 if (chunk_info[i]->type == freebsd) 974 break; 975 } 976 if (!chunk_info[i]) { 977 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 978 return; 979 } 980 } 981 else { 982 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 983 return; 984 } 985 if (!all_disk) { 986#ifdef PC98 987 getBootMgr(d->name, &bootipl, &bootipl_size, 988 &bootmenu, &bootmenu_size); 989 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 990#else 991 getBootMgr(d->name, &mbrContents, &mbrSize); 992 Set_Boot_Mgr(d, mbrContents, mbrSize); 993#endif 994 } 995 variable_set2(DISK_PARTITIONED, "yes", 0); 996 } 997} 998#endif /* WITH_SLICES */ 999