disks.c revision 161059
155714Skris/* 255714Skris * The new sysinstall program. 355714Skris * 455714Skris * This is probably the last program in the `sysinstall' line - the next 555714Skris * generation being essentially a complete rewrite. 655714Skris * 755714Skris * $FreeBSD: head/usr.sbin/sade/disks.c 156123 2006-02-28 21:49:33Z jhb $ 855714Skris * 955714Skris * Copyright (c) 1995 1055714Skris * Jordan Hubbard. All rights reserved. 1155714Skris * 1255714Skris * Redistribution and use in source and binary forms, with or without 1355714Skris * modification, are permitted provided that the following conditions 1455714Skris * are met: 1555714Skris * 1. Redistributions of source code must retain the above copyright 1655714Skris * notice, this list of conditions and the following disclaimer, 1755714Skris * verbatim and that no modifications are made prior to this 1855714Skris * point in the file. 1955714Skris * 2. Redistributions in binary form must reproduce the above copyright 2055714Skris * notice, this list of conditions and the following disclaimer in the 2155714Skris * documentation and/or other materials provided with the distribution. 2255714Skris * 2355714Skris * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 2455714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2555714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2655714Skris * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 2755714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2855714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2955714Skris * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 3055714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3155714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3255714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3355714Skris * SUCH DAMAGE. 3455714Skris * 3555714Skris */ 3655714Skris 3755714Skris#include "sysinstall.h" 3855714Skris#include <ctype.h> 3955714Skris#include <fcntl.h> 4055714Skris#include <inttypes.h> 4155714Skris#include <libdisk.h> 4255714Skris#include <sys/stat.h> 4355714Skris#include <sys/disklabel.h> 4455714Skris 4555714Skris#ifdef WITH_SLICES 4655714Skrisenum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_GIG, UNIT_SIZE }; 4755714Skris 4855714Skris#ifdef PC98 4955714Skris#define SUBTYPE_FREEBSD 50324 5055714Skris#define SUBTYPE_FAT 37218 5155714Skris#else 5255714Skris#define SUBTYPE_FREEBSD 165 5355714Skris#define SUBTYPE_FAT 6 5455714Skris#endif 5555714Skris#define SUBTYPE_EFI 239 5655714Skris 5755714Skris#ifdef PC98 5855714Skris#define OTHER_SLICE_VALUES \ 5955714Skris "Other popular values are 37218 for a\n" \ 6055714Skris "DOS FAT partition.\n\n" 6155714Skris#else 6255714Skris#define OTHER_SLICE_VALUES \ 6355714Skris "Other popular values are 6 for a\n" \ 6455714Skris "DOS FAT partition, 131 for a Linux ext2fs partition, or\n" \ 6555714Skris "130 for a Linux swap partition.\n\n" 6655714Skris#endif 6755714Skris#define NON_FREEBSD_NOTE \ 6855714Skris "Note: If you choose a non-FreeBSD partition type, it will not\n" \ 6955714Skris "be formatted or otherwise prepared, it will simply reserve space\n" \ 7055714Skris "for you to use another tool, such as DOS format, to later format\n" \ 7155714Skris "and actually use the partition." 7255714Skris 7355714Skris/* Where we start displaying chunk information on the screen */ 7455714Skris#define CHUNK_START_ROW 5 7559191Skris 7655714Skris/* Where we keep track of MBR chunks */ 7755714Skris#define CHUNK_INFO_ENTRIES 16 7855714Skrisstatic struct chunk *chunk_info[CHUNK_INFO_ENTRIES]; 7955714Skrisstatic int current_chunk; 8055714Skris 8155714Skrisstatic void diskPartitionNonInteractive(Device *dev); 8255714Skrisstatic u_char * bootalloc(char *name, size_t *size); 8355714Skris 8455714Skrisstatic void 8555714Skrisrecord_chunks(Disk *d) 8655714Skris{ 8759191Skris struct chunk *c1 = NULL; 8859191Skris int i = 0; 8959191Skris daddr_t last_free = 0; 9055714Skris 9155714Skris if (!d->chunks) 9255714Skris msgFatal("No chunk list found for %s!", d->name); 9355714Skris 9455714Skris for (c1 = d->chunks->part; c1; c1 = c1->next) { 9555714Skris if (c1->type == unused && c1->size > last_free) { 9655714Skris last_free = c1->size; 9755714Skris current_chunk = i; 9855714Skris } 9955714Skris chunk_info[i++] = c1; 10055714Skris } 10155714Skris chunk_info[i] = NULL; 10255714Skris if (current_chunk >= i) 10355714Skris current_chunk = i - 1; 10455714Skris} 10555714Skris 10655714Skrisstatic daddr_t Total; 10755714Skris 10855714Skrisstatic void 10955714Skrisprint_chunks(Disk *d, int u) 11055714Skris{ 11155714Skris int row; 11255714Skris int i; 11355714Skris daddr_t sz; 11455714Skris char *szstr; 11555714Skris 11655714Skris szstr = (u == UNIT_GIG ? "GB" : (u == UNIT_MEG ? "MB" : 11755714Skris (u == UNIT_KILO ? "KB" : "ST"))); 11855714Skris 11955714Skris Total = 0; 12055714Skris for (i = 0; chunk_info[i]; i++) 12155714Skris Total += chunk_info[i]->size; 12255714Skris#ifdef PC98 12355714Skris if (d->bios_cyl >= 65536 || d->bios_hd > 256 || d->bios_sect >= 256) { 12455714Skris#else 12555714Skris if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { 12655714Skris#endif 12755714Skris dialog_clear_norefresh(); 12855714Skris msgConfirm("WARNING: A geometry of %lu/%lu/%lu for %s is incorrect. Using\n" 12955714Skris "a more likely geometry. If this geometry is incorrect or you\n" 13055714Skris "are unsure as to whether or not it's correct, please consult\n" 13155714Skris "the Hardware Guide in the Documentation submenu or use the\n" 13255714Skris "(G)eometry command to change it now.\n\n" 13355714Skris "Remember: you need to enter whatever your BIOS thinks the\n" 13455714Skris "geometry is! For IDE, it's what you were told in the BIOS\n" 13555714Skris "setup. For SCSI, it's the translation mode your controller is\n" 13655714Skris "using. Do NOT use a ``physical geometry''.", 13755714Skris d->bios_cyl, d->bios_hd, d->bios_sect, d->name); 13855714Skris Sanitize_Bios_Geom(d); 13955714Skris } 14055714Skris attrset(A_NORMAL); 14155714Skris mvaddstr(0, 0, "Disk name:\t"); 14255714Skris clrtobot(); 14355714Skris attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); 14455714Skris attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); 14555714Skris mvprintw(1, 0, 14655714Skris "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %jd sectors (%jdMB)", 14755714Skris d->bios_cyl, d->bios_hd, d->bios_sect, 14855714Skris (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect, 14955714Skris (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024); 15055714Skris mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", 15155714Skris "Offset", "Size", szstr, "End", "Name", "PType", "Desc", 15255714Skris "Subtype", "Flags"); 15355714Skris for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { 15455714Skris switch(u) { 15555714Skris default: /* fall thru */ 15655714Skris case UNIT_BLOCKS: 15755714Skris sz = chunk_info[i]->size; 15855714Skris break; 15955714Skris case UNIT_KILO: 16055714Skris sz = chunk_info[i]->size / (1024/512); 16155714Skris break; 16255714Skris case UNIT_MEG: 16355714Skris sz = chunk_info[i]->size / (1024/512) / 1024; 16455714Skris break; 16555714Skris case UNIT_GIG: 16655714Skris sz = chunk_info[i]->size / (1024/512) / 1024 / 1024; 16755714Skris break; 16855714Skris } 16955714Skris if (i == current_chunk) 17055714Skris attrset(ATTR_SELECTED); 17155714Skris mvprintw(row, 0, "%10jd %10jd %10jd %8s %6d %10s %8d\t%-6s", 17255714Skris (intmax_t)chunk_info[i]->offset, (intmax_t)sz, 17355714Skris (intmax_t)chunk_info[i]->end, chunk_info[i]->name, 17455714Skris chunk_info[i]->type, 17555714Skris slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), 17655714Skris chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); 17755714Skris if (i == current_chunk) 17855714Skris attrset(A_NORMAL); 17955714Skris } 18055714Skris} 18155714Skris 18255714Skrisstatic void 18355714Skrisprint_command_summary(void) 18455714Skris{ 18555714Skris mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); 18655714Skris mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice F = `DD' mode"); 18755714Skris mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable | = Wizard m."); 18855714Skris mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); 18955714Skris if (!RunningAsInit) 19055714Skris mvprintw(18, 47, "W = Write Changes"); 19155714Skris mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); 19255714Skris move(0, 0); 19355714Skris} 19455714Skris 19555714Skris#ifdef PC98 19655714Skrisstatic void 19755714SkrisgetBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, 19855714Skris u_char **bootmenu, size_t *bootmenu_size) 19955714Skris{ 20055714Skris static u_char *boot0; 20155714Skris static size_t boot0_size; 20255714Skris static u_char *boot05; 20355714Skris static size_t boot05_size; 20455714Skris 20555714Skris char str[80]; 20655714Skris char *cp; 20755714Skris int i = 0; 20855714Skris 20955714Skris cp = variable_get(VAR_BOOTMGR); 21055714Skris if (!cp) { 21155714Skris /* Figure out what kind of IPL the user wants */ 21255714Skris sprintf(str, "Install Boot Manager for drive %s?", dname); 21355714Skris MenuIPLType.title = str; 21455714Skris i = dmenuOpenSimple(&MenuIPLType, FALSE); 21555714Skris } else { 21655714Skris if (!strncmp(cp, "boot", 4)) 21755714Skris BootMgr = 0; 21855714Skris else 21955714Skris BootMgr = 1; 22055714Skris } 22155714Skris if (cp || i) { 22255714Skris switch (BootMgr) { 22355714Skris case 0: 22455714Skris if (!boot0) boot0 = bootalloc("boot0", &boot0_size); 22555714Skris *bootipl = boot0; 22655714Skris *bootipl_size = boot0_size; 22755714Skris if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size); 22855714Skris *bootmenu = boot05; 22955714Skris *bootmenu_size = boot05_size; 23055714Skris return; 23155714Skris case 1: 23255714Skris default: 23355714Skris break; 23455714Skris } 23555714Skris } 23655714Skris *bootipl = NULL; 23755714Skris *bootipl_size = 0; 23855714Skris *bootmenu = NULL; 23955714Skris *bootmenu_size = 0; 24055714Skris} 24155714Skris#else 24255714Skrisstatic void 24355714SkrisgetBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) 24455714Skris{ 24555714Skris#if defined(__i386__) || defined(__amd64__) /* only meaningful on x86 */ 24655714Skris static u_char *mbr, *boot0; 24755714Skris static size_t mbr_size, boot0_size; 24855714Skris char str[80]; 24955714Skris char *cp; 25055714Skris int i = 0; 25155714Skris 25255714Skris cp = variable_get(VAR_BOOTMGR); 25355714Skris if (!cp) { 25455714Skris /* Figure out what kind of MBR the user wants */ 25555714Skris sprintf(str, "Install Boot Manager for drive %s?", dname); 25655714Skris MenuMBRType.title = str; 25755714Skris i = dmenuOpenSimple(&MenuMBRType, FALSE); 25855714Skris } 25955714Skris else { 26055714Skris if (!strncmp(cp, "boot", 4)) 26155714Skris BootMgr = 0; 26255714Skris else if (!strcmp(cp, "standard")) 26355714Skris BootMgr = 1; 26455714Skris else 26555714Skris BootMgr = 2; 26655714Skris } 26755714Skris if (cp || i) { 26855714Skris switch (BootMgr) { 26955714Skris case 0: 27055714Skris if (!boot0) boot0 = bootalloc("boot0", &boot0_size); 27155714Skris *bootCode = boot0; 27255714Skris *bootCodeSize = boot0_size; 27355714Skris return; 27455714Skris case 1: 27555714Skris if (!mbr) mbr = bootalloc("mbr", &mbr_size); 27655714Skris *bootCode = mbr; 27755714Skris *bootCodeSize = mbr_size; 27855714Skris return; 27955714Skris case 2: 28055714Skris default: 28155714Skris break; 28255714Skris } 28355714Skris } 28455714Skris#endif 28555714Skris *bootCode = NULL; 28655714Skris *bootCodeSize = 0; 28755714Skris} 28855714Skris#endif 28955714Skris#endif /* WITH_SLICES */ 29055714Skris 29155714Skrisint 29255714SkrisdiskGetSelectCount(Device ***devs) 29355714Skris{ 29455714Skris int i, cnt, enabled; 29555714Skris char *cp; 29655714Skris Device **dp; 29755714Skris 29855714Skris cp = variable_get(VAR_DISK); 29955714Skris dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); 30055714Skris cnt = deviceCount(dp); 30155714Skris if (!cnt) 30255714Skris return -1; 30355714Skris for (i = 0, enabled = 0; i < cnt; i++) { 30455714Skris if (dp[i]->enabled) 30555714Skris ++enabled; 30655714Skris } 30755714Skris return enabled; 30855714Skris} 30955714Skris 31055714Skris#ifdef WITH_SLICES 31155714Skrisvoid 312diskPartition(Device *dev) 313{ 314 char *cp, *p; 315 int rv, key = 0; 316 int i; 317 Boolean chunking; 318 char *msg = NULL; 319#ifdef PC98 320 u_char *bootipl; 321 size_t bootipl_size; 322 u_char *bootmenu; 323 size_t bootmenu_size; 324#else 325 u_char *mbrContents; 326 size_t mbrSize; 327#endif 328 WINDOW *w = savescr(); 329 Disk *d = (Disk *)dev->private; 330 int size_unit; 331 332 size_unit = UNIT_BLOCKS; 333 chunking = TRUE; 334 keypad(stdscr, TRUE); 335 336 /* Flush both the dialog and curses library views of the screen 337 since we don't always know who called us */ 338 dialog_clear_norefresh(), clear(); 339 current_chunk = 0; 340 341 /* Set up the chunk array */ 342 record_chunks(d); 343 344 while (chunking) { 345 char *val, geometry[80]; 346 347 /* Now print our overall state */ 348 if (d) 349 print_chunks(d, size_unit); 350 print_command_summary(); 351 if (msg) { 352 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 353 beep(); 354 msg = NULL; 355 } 356 else { 357 move(23, 0); 358 clrtoeol(); 359 } 360 361 /* Get command character */ 362 key = getch(); 363 switch (toupper(key)) { 364 case '\014': /* ^L (redraw) */ 365 clear(); 366 msg = NULL; 367 break; 368 369 case '\020': /* ^P */ 370 case KEY_UP: 371 case '-': 372 if (current_chunk != 0) 373 --current_chunk; 374 break; 375 376 case '\016': /* ^N */ 377 case KEY_DOWN: 378 case '+': 379 case '\r': 380 case '\n': 381 if (chunk_info[current_chunk + 1]) 382 ++current_chunk; 383 break; 384 385 case KEY_HOME: 386 current_chunk = 0; 387 break; 388 389 case KEY_END: 390 while (chunk_info[current_chunk + 1]) 391 ++current_chunk; 392 break; 393 394 case KEY_F(1): 395 case '?': 396 systemDisplayHelp("slice"); 397 clear(); 398 break; 399 400 case 'A': 401 case 'F': /* Undocumented magic Dangerously Dedicated mode */ 402#if !defined(__i386__) && !defined(__amd64__) 403 rv = 1; 404#else /* The rest is only relevant on x86 */ 405 cp = variable_get(VAR_DEDICATE_DISK); 406 if (cp && !strcasecmp(cp, "always")) 407 rv = 1; 408 else if (toupper(key) == 'A') 409 rv = 0; 410 else { 411 rv = msgYesNo("Do you want to do this with a true partition entry\n" 412 "so as to remain cooperative with any future possible\n" 413 "operating systems on the drive(s)?\n" 414 "(See also the section about ``dangerously dedicated''\n" 415 "disks in the FreeBSD FAQ.)"); 416 if (rv == -1) 417 rv = 0; 418 } 419#endif 420 All_FreeBSD(d, rv); 421 variable_set2(DISK_PARTITIONED, "yes", 0); 422 record_chunks(d); 423 clear(); 424 break; 425 426 case 'C': 427 if (chunk_info[current_chunk]->type != unused) 428 msg = "Slice in use, delete it first or move to an unused one."; 429 else { 430 char *val, tmp[20], name[16], *cp; 431 daddr_t size; 432 int subtype; 433 chunk_e partitiontype; 434#ifdef PC98 435 snprintf(name, sizeof (name), "%s", "FreeBSD"); 436 val = msgGetInput(name, 437 "Please specify the name for new FreeBSD slice."); 438 if (val) 439 strncpy(name, val, sizeof (name)); 440#else 441 name[0] = '\0'; 442#endif 443 snprintf(tmp, 20, "%jd", (intmax_t)chunk_info[current_chunk]->size); 444 val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" 445 "or append a trailing `M' for megabytes (e.g. 20M)."); 446 if (val && (size = strtoimax(val, &cp, 0)) > 0) { 447 if (*cp && toupper(*cp) == 'M') 448 size *= ONE_MEG; 449 else if (*cp && toupper(*cp) == 'G') 450 size *= ONE_GIG; 451 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 452 val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 453 "Pressing Enter will choose the default, a native FreeBSD\n" 454 "slice (type %u). " 455 OTHER_SLICE_VALUES 456 NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); 457 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 458 if (subtype == SUBTYPE_FREEBSD) 459 partitiontype = freebsd; 460 else if (subtype == SUBTYPE_FAT) 461 partitiontype = fat; 462 else if (subtype == SUBTYPE_EFI) 463 partitiontype = efi; 464 else 465#ifdef PC98 466 partitiontype = pc98; 467#else 468 partitiontype = mbr; 469#endif 470 Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 471 (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); 472 variable_set2(DISK_PARTITIONED, "yes", 0); 473 record_chunks(d); 474 } 475 } 476 clear(); 477 } 478 break; 479 480 case KEY_DC: 481 case 'D': 482 if (chunk_info[current_chunk]->type == unused) 483 msg = "Slice is already unused!"; 484 else { 485 Delete_Chunk(d, chunk_info[current_chunk]); 486 variable_set2(DISK_PARTITIONED, "yes", 0); 487 record_chunks(d); 488 } 489 break; 490 491 case 'T': 492 if (chunk_info[current_chunk]->type == unused) 493 msg = "Slice is currently unused (use create instead)"; 494 else { 495 char *val, tmp[20]; 496 int subtype; 497 chunk_e partitiontype; 498 499 sprintf(tmp, "%d", chunk_info[current_chunk]->subtype); 500 val = msgGetInput(tmp, "New partition type:\n\n" 501 "Pressing Enter will use the current type. To choose a native\n" 502 "FreeBSD slice enter %u. " 503 OTHER_SLICE_VALUES 504 NON_FREEBSD_NOTE, SUBTYPE_FREEBSD); 505 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 506 if (subtype == SUBTYPE_FREEBSD) 507 partitiontype = freebsd; 508 else if (subtype == SUBTYPE_FAT) 509 partitiontype = fat; 510 else if (subtype == SUBTYPE_EFI) 511 partitiontype = efi; 512 else 513#ifdef PC98 514 partitiontype = pc98; 515#else 516 partitiontype = mbr; 517#endif 518 chunk_info[current_chunk]->type = partitiontype; 519 chunk_info[current_chunk]->subtype = subtype; 520 } 521 } 522 break; 523 524 case 'G': 525 snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); 526 val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" 527 "Don't forget to use the two slash (/) separator characters!\n" 528 "It's not possible to parse the field without them."); 529 if (val) { 530 long nc, nh, ns; 531 nc = strtol(val, &val, 0); 532 nh = strtol(val + 1, &val, 0); 533 ns = strtol(val + 1, 0, 0); 534 Set_Bios_Geom(d, nc, nh, ns); 535 } 536 clear(); 537 break; 538 539 case 'S': 540 /* Clear active states so we won't have two */ 541 for (i = 0; (chunk_info[i] != NULL) && (i < CHUNK_INFO_ENTRIES); i++) 542 chunk_info[i]->flags &= !CHUNK_ACTIVE; 543 544 /* Set Bootable */ 545 chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 546 break; 547 548 case 'U': 549 if (!variable_cmp(DISK_LABELLED, "written")) { 550 msgConfirm("You've already written this information out - you\n" 551 "can't undo it."); 552 } 553 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 554 char cp[BUFSIZ]; 555 556 sstrncpy(cp, d->name, sizeof cp); 557 Free_Disk(dev->private); 558 d = Open_Disk(cp); 559 if (!d) 560 msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 561 dev->private = d; 562 variable_unset(DISK_PARTITIONED); 563 variable_unset(DISK_LABELLED); 564 if (d) 565 record_chunks(d); 566 } 567 clear(); 568 break; 569 570 case 'W': 571 if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 572 "installation. If you are installing FreeBSD for the first time\n" 573 "then you should simply type Q when you're finished here and your\n" 574 "changes will be committed in one batch automatically at the end of\n" 575 "these questions. If you're adding a disk, you should NOT write\n" 576 "from this screen, you should do it from the label editor.\n\n" 577 "Are you absolutely sure you want to do this now?")) { 578 variable_set2(DISK_PARTITIONED, "yes", 0); 579 580#ifdef PC98 581 /* 582 * Don't trash the IPL if the first (and therefore only) chunk 583 * is marked for a truly dedicated disk (i.e., the disklabel 584 * starts at sector 0), even in cases where the user has 585 * requested a FreeBSD Boot Manager -- both would be fatal in 586 * this case. 587 */ 588 /* 589 * Don't offer to update the IPL on this disk if the first 590 * "real" chunk looks like a FreeBSD "all disk" partition, 591 * or the disk is entirely FreeBSD. 592 */ 593 if ((d->chunks->part->type != freebsd) || 594 (d->chunks->part->offset > 1)) 595 getBootMgr(d->name, &bootipl, &bootipl_size, 596 &bootmenu, &bootmenu_size); 597 else { 598 bootipl = NULL; 599 bootipl_size = 0; 600 bootmenu = NULL; 601 bootmenu_size = 0; 602 } 603 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 604#else 605 /* 606 * Don't trash the MBR if the first (and therefore only) chunk 607 * is marked for a truly dedicated disk (i.e., the disklabel 608 * starts at sector 0), even in cases where the user has 609 * requested booteasy or a "standard" MBR -- both would be 610 * fatal in this case. 611 */ 612 /* 613 * Don't offer to update the MBR on this disk if the first 614 * "real" chunk looks like a FreeBSD "all disk" partition, 615 * or the disk is entirely FreeBSD. 616 */ 617 if ((d->chunks->part->type != freebsd) || 618 (d->chunks->part->offset > 1)) 619 getBootMgr(d->name, &mbrContents, &mbrSize); 620 else { 621 mbrContents = NULL; 622 mbrSize = 0; 623 } 624 Set_Boot_Mgr(d, mbrContents, mbrSize); 625#endif 626 627 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 628 msgConfirm("Disk partition write returned an error status!"); 629 else 630 msgConfirm("Wrote FDISK partition information out successfully."); 631 } 632 clear(); 633 break; 634 635 case '|': 636 if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" 637 "No seat belts whatsoever are provided!")) { 638 clear(); 639 refresh(); 640 slice_wizard(d); 641 variable_set2(DISK_PARTITIONED, "yes", 0); 642 record_chunks(d); 643 } 644 else 645 msg = "Wise choice!"; 646 clear(); 647 break; 648 649 case '\033': /* ESC */ 650 case 'Q': 651 chunking = FALSE; 652#ifdef PC98 653 /* 654 * Don't trash the IPL if the first (and therefore only) chunk 655 * is marked for a truly dedicated disk (i.e., the disklabel 656 * starts at sector 0), even in cases where the user has requested 657 * a FreeBSD Boot Manager -- both would be fatal in this case. 658 */ 659 /* 660 * Don't offer to update the IPL on this disk if the first "real" 661 * chunk looks like a FreeBSD "all disk" partition, or the disk is 662 * entirely FreeBSD. 663 */ 664 if ((d->chunks->part->type != freebsd) || 665 (d->chunks->part->offset > 1)) { 666 if (variable_cmp(DISK_PARTITIONED, "written")) { 667 getBootMgr(d->name, &bootipl, &bootipl_size, 668 &bootmenu, &bootmenu_size); 669 if (bootipl != NULL && bootmenu != NULL) 670 Set_Boot_Mgr(d, bootipl, bootipl_size, 671 bootmenu, bootmenu_size); 672 } 673 } 674#else 675 /* 676 * Don't trash the MBR if the first (and therefore only) chunk 677 * is marked for a truly dedicated disk (i.e., the disklabel 678 * starts at sector 0), even in cases where the user has requested 679 * booteasy or a "standard" MBR -- both would be fatal in this case. 680 */ 681 /* 682 * Don't offer to update the MBR on this disk if the first "real" 683 * chunk looks like a FreeBSD "all disk" partition, or the disk is 684 * entirely FreeBSD. 685 */ 686 if ((d->chunks->part->type != freebsd) || 687 (d->chunks->part->offset > 1)) { 688 if (variable_cmp(DISK_PARTITIONED, "written")) { 689 getBootMgr(d->name, &mbrContents, &mbrSize); 690 if (mbrContents != NULL) 691 Set_Boot_Mgr(d, mbrContents, mbrSize); 692 } 693 } 694#endif 695 break; 696 697 case 'Z': 698 size_unit = (size_unit + 1) % UNIT_SIZE; 699 break; 700 701 default: 702 beep(); 703 msg = "Type F1 or ? for help"; 704 break; 705 } 706 } 707 p = CheckRules(d); 708 if (p) { 709 char buf[FILENAME_MAX]; 710 711 use_helpline("Press F1 to read more about disk slices."); 712 use_helpfile(systemHelpFile("partition", buf)); 713 if (!variable_get(VAR_NO_WARN)) 714 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 715 free(p); 716 } 717 restorescr(w); 718} 719#endif /* WITH_SLICES */ 720 721static u_char * 722bootalloc(char *name, size_t *size) 723{ 724 char buf[FILENAME_MAX]; 725 struct stat sb; 726 727 snprintf(buf, sizeof buf, "/boot/%s", name); 728 if (stat(buf, &sb) != -1) { 729 int fd; 730 731 fd = open(buf, O_RDONLY); 732 if (fd != -1) { 733 u_char *cp; 734 735 cp = malloc(sb.st_size); 736 if (read(fd, cp, sb.st_size) != sb.st_size) { 737 free(cp); 738 close(fd); 739 msgDebug("bootalloc: couldn't read %ld bytes from %s\n", (long)sb.st_size, buf); 740 return NULL; 741 } 742 close(fd); 743 if (size != NULL) 744 *size = sb.st_size; 745 return cp; 746 } 747 msgDebug("bootalloc: couldn't open %s\n", buf); 748 } 749 else 750 msgDebug("bootalloc: can't stat %s\n", buf); 751 return NULL; 752} 753 754#ifdef WITH_SLICES 755static int 756partitionHook(dialogMenuItem *selected) 757{ 758 Device **devs = NULL; 759 760 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 761 if (!devs) { 762 msgConfirm("Unable to find disk %s!", selected->prompt); 763 return DITEM_FAILURE; 764 } 765 /* Toggle enabled status? */ 766 if (!devs[0]->enabled) { 767 devs[0]->enabled = TRUE; 768 diskPartition(devs[0]); 769 } 770 else 771 devs[0]->enabled = FALSE; 772 return DITEM_SUCCESS; 773} 774 775static int 776partitionCheck(dialogMenuItem *selected) 777{ 778 Device **devs = NULL; 779 780 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 781 if (!devs || devs[0]->enabled == FALSE) 782 return FALSE; 783 return TRUE; 784} 785 786int 787diskPartitionEditor(dialogMenuItem *self) 788{ 789 DMenu *menu; 790 Device **devs; 791 int i, cnt, devcnt; 792 793 cnt = diskGetSelectCount(&devs); 794 devcnt = deviceCount(devs); 795 if (cnt == -1) { 796 msgConfirm("No disks found! Please verify that your disk controller is being\n" 797 "properly probed at boot time. See the Hardware Guide on the\n" 798 "Documentation menu for clues on diagnosing this type of problem."); 799 return DITEM_FAILURE; 800 } 801 else if (cnt) { 802 /* Some are already selected */ 803 for (i = 0; i < devcnt; i++) { 804 if (devs[i]->enabled) { 805 if (variable_get(VAR_NONINTERACTIVE) && 806 !variable_get(VAR_DISKINTERACTIVE)) 807 diskPartitionNonInteractive(devs[i]); 808 else 809 diskPartition(devs[i]); 810 } 811 } 812 } 813 else { 814 /* No disks are selected, fall-back case now */ 815 if (devcnt == 1) { 816 devs[0]->enabled = TRUE; 817 if (variable_get(VAR_NONINTERACTIVE) && 818 !variable_get(VAR_DISKINTERACTIVE)) 819 diskPartitionNonInteractive(devs[0]); 820 else 821 diskPartition(devs[0]); 822 return DITEM_SUCCESS; 823 } 824 else { 825 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 826 if (!menu) { 827 msgConfirm("No devices suitable for installation found!\n\n" 828 "Please verify that your disk controller (and attached drives)\n" 829 "were detected properly. This can be done by pressing the\n" 830 "[Scroll Lock] key and using the Arrow keys to move back to\n" 831 "the boot messages. Press [Scroll Lock] again to return."); 832 return DITEM_FAILURE; 833 } 834 else { 835 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 836 free(menu); 837 } 838 return i; 839 } 840 } 841 return DITEM_SUCCESS; 842} 843#endif /* WITH_SLICES */ 844 845int 846diskPartitionWrite(dialogMenuItem *self) 847{ 848 Device **devs; 849 int i; 850 851 if (!variable_cmp(DISK_PARTITIONED, "written")) 852 return DITEM_SUCCESS; 853 854 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 855 if (!devs) { 856 msgConfirm("Unable to find any disks to write to??"); 857 return DITEM_FAILURE; 858 } 859 if (isDebug()) 860 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 861 for (i = 0; devs[i]; i++) { 862 Disk *d = (Disk *)devs[i]->private; 863 static u_char *boot1; 864#if defined(__i386__) || defined(__amd64__) 865 static u_char *boot2; 866#endif 867 868 if (!devs[i]->enabled) 869 continue; 870 871#if defined(__i386__) || defined(__amd64__) 872 if (!boot1) boot1 = bootalloc("boot1", NULL); 873 if (!boot2) boot2 = bootalloc("boot2", NULL); 874 Set_Boot_Blocks(d, boot1, boot2); 875#elif !defined(__ia64__) 876 if (!boot1) boot1 = bootalloc("boot1", NULL); 877 Set_Boot_Blocks(d, boot1, NULL); 878#endif 879 880 msgNotify("Writing partition information to drive %s", d->name); 881 if (!Fake && Write_Disk(d)) { 882 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 883 return DITEM_FAILURE; 884 } 885 } 886 /* Now it's not "yes", but "written" */ 887 variable_set2(DISK_PARTITIONED, "written", 0); 888 return DITEM_SUCCESS | DITEM_RESTORE; 889} 890 891#ifdef WITH_SLICES 892/* Partition a disk based wholly on which variables are set */ 893static void 894diskPartitionNonInteractive(Device *dev) 895{ 896 char *cp; 897 int i, all_disk = 0; 898 daddr_t sz; 899#ifdef PC98 900 u_char *bootipl; 901 size_t bootipl_size; 902 u_char *bootmenu; 903 size_t bootmenu_size; 904#else 905 u_char *mbrContents; 906 size_t mbrSize; 907#endif 908 Disk *d = (Disk *)dev->private; 909 910 record_chunks(d); 911 cp = variable_get(VAR_GEOMETRY); 912 if (cp) { 913 msgDebug("Setting geometry from script to: %s\n", cp); 914 d->bios_cyl = strtol(cp, &cp, 0); 915 d->bios_hd = strtol(cp + 1, &cp, 0); 916 d->bios_sect = strtol(cp + 1, 0, 0); 917 } 918 919#ifdef PC98 920 if (d->bios_cyl >= 65536 || d->bios_hd > 256 || d->bios_sect >= 256) { 921#else 922 if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { 923#endif 924 msgDebug("Warning: A geometry of %lu/%lu/%lu for %s is incorrect.\n", 925 d->bios_cyl, d->bios_hd, d->bios_sect, d->name); 926 Sanitize_Bios_Geom(d); 927 msgDebug("Sanitized geometry for %s is %lu/%lu/%lu.\n", 928 d->name, d->bios_cyl, d->bios_hd, d->bios_sect); 929 } 930 931 cp = variable_get(VAR_PARTITION); 932 if (cp) { 933 if (!strcmp(cp, "free")) { 934 /* Do free disk space case */ 935 for (i = 0; chunk_info[i]; i++) { 936 /* If a chunk is at least 10MB in size, use it. */ 937 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 938 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 939 freebsd, 3, 940 (chunk_info[i]->flags & CHUNK_ALIGN), 941 "FreeBSD"); 942 variable_set2(DISK_PARTITIONED, "yes", 0); 943 break; 944 } 945 } 946 if (!chunk_info[i]) { 947 msgConfirm("Unable to find any free space on this disk!"); 948 return; 949 } 950 } 951 else if (!strcmp(cp, "all")) { 952 /* Do all disk space case */ 953 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 954 955 All_FreeBSD(d, FALSE); 956 } 957 else if (!strcmp(cp, "exclusive")) { 958 /* Do really-all-the-disk-space case */ 959 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 960 961 All_FreeBSD(d, all_disk = TRUE); 962 } 963 else if ((sz = strtoimax(cp, &cp, 0))) { 964 /* Look for sz bytes free */ 965 if (*cp && toupper(*cp) == 'M') 966 sz *= ONE_MEG; 967 else if (*cp && toupper(*cp) == 'G') 968 sz *= ONE_GIG; 969 for (i = 0; chunk_info[i]; i++) { 970 /* If a chunk is at least sz MB, use it. */ 971 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 972 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 973 (chunk_info[i]->flags & CHUNK_ALIGN), 974 "FreeBSD"); 975 variable_set2(DISK_PARTITIONED, "yes", 0); 976 break; 977 } 978 } 979 if (!chunk_info[i]) { 980 msgConfirm("Unable to find %jd free blocks on this disk!", 981 (intmax_t)sz); 982 return; 983 } 984 } 985 else if (!strcmp(cp, "existing")) { 986 /* Do existing FreeBSD case */ 987 for (i = 0; chunk_info[i]; i++) { 988 if (chunk_info[i]->type == freebsd) 989 break; 990 } 991 if (!chunk_info[i]) { 992 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 993 return; 994 } 995 } 996 else { 997 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 998 return; 999 } 1000 if (!all_disk) { 1001#ifdef PC98 1002 getBootMgr(d->name, &bootipl, &bootipl_size, 1003 &bootmenu, &bootmenu_size); 1004 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 1005#else 1006 getBootMgr(d->name, &mbrContents, &mbrSize); 1007 Set_Boot_Mgr(d, mbrContents, mbrSize); 1008#endif 1009 } 1010 variable_set2(DISK_PARTITIONED, "yes", 0); 1011 } 1012} 1013#endif /* WITH_SLICES */ 1014