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