disks.c revision 64555
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 64555 2000-08-12 14:20:31Z nyan $ 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#ifdef __alpha__ 366 rv = 1; 367#else /* The rest is only relevant on x86 */ 368 cp = variable_get(VAR_DEDICATE_DISK); 369 if (cp && !strcasecmp(cp, "always")) 370 rv = 1; 371 else { 372 rv = msgYesNo("Do you want to do this with a true partition entry\n" 373 "so as to remain cooperative with any future possible\n" 374 "operating systems on the drive(s)?\n" 375 "(See also the section about ``dangerously dedicated''\n" 376 "disks in the FreeBSD FAQ.)"); 377 if (rv == -1) 378 rv = 0; 379 } 380#endif 381 All_FreeBSD(d, rv); 382 variable_set2(DISK_PARTITIONED, "yes", 0); 383 record_chunks(d); 384 clear(); 385 break; 386 387 case 'C': 388 if (chunk_info[current_chunk]->type != unused) 389 msg = "Slice in use, delete it first or move to an unused one."; 390 else { 391 char *val, tmp[20], *cp; 392 int size; 393#ifdef PC98 394 char name[16]; 395 396 snprintf(name, 16, "%s", "FreeBSD"); 397 val = msgGetInput(name, 398 "Please specify the name for new FreeBSD slice."); 399 if (val) 400 strncpy(name, val, 16); 401#else 402 int subtype; 403 chunk_e partitiontype; 404#endif 405 snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); 406 val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" 407 "or append a trailing `M' for megabytes (e.g. 20M)."); 408 if (val && (size = strtol(val, &cp, 0)) > 0) { 409 if (*cp && toupper(*cp) == 'M') 410 size *= ONE_MEG; 411 else if (*cp && toupper(*cp) == 'G') 412 size *= ONE_GIG; 413#ifdef PC98 414 Create_Chunk(d, chunk_info[current_chunk]->offset, size, 415 freebsd, 3, 416 (chunk_info[current_chunk]->flags & CHUNK_ALIGN), 417 name); 418 variable_set2(DISK_PARTITIONED, "yes", 0); 419 record_chunks(d); 420#else 421 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 422 val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 423 "Pressing Enter will choose the default, a native FreeBSD\n" 424 "slice (type 165). You can choose other types, 6 for a\n" 425 "DOS partition or 131 for a Linux partition, for example.\n\n" 426 "Note: If you choose a non-FreeBSD partition type, it will not\n" 427 "be formatted or otherwise prepared, it will simply reserve space\n" 428 "for you to use another tool, such as DOS FORMAT, to later format\n" 429 "and use the partition."); 430 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 431 if (subtype == SUBTYPE_FREEBSD) 432 partitiontype = freebsd; 433 else if (subtype == SUBTYPE_FAT) 434 partitiontype = fat; 435 else 436 partitiontype = unknown; 437#ifdef __alpha__ 438 if (partitiontype == freebsd && size == chunk_info[current_chunk]->size) 439 All_FreeBSD(d, 1); 440 else 441#endif 442 Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 443 (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); 444 variable_set2(DISK_PARTITIONED, "yes", 0); 445 record_chunks(d); 446 } 447#endif /* PC98 */ 448 } 449 clear(); 450 } 451 break; 452 453 case KEY_DC: 454 case 'D': 455 if (chunk_info[current_chunk]->type == unused) 456 msg = "Slice is already unused!"; 457 else { 458 Delete_Chunk(d, chunk_info[current_chunk]); 459 variable_set2(DISK_PARTITIONED, "yes", 0); 460 record_chunks(d); 461 } 462 break; 463 464 case 'T': 465 if (chunk_info[current_chunk]->type == unused) 466 msg = "Slice is currently unused (use create instead)"; 467 else { 468 char *val, tmp[20]; 469 int subtype; 470 chunk_e partitiontype; 471 472 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 473#ifdef PC98 474 val = msgGetInput(tmp, "New partition type:\n\n" 475 "Pressing Enter will choose the default, a native FreeBSD\n" 476 "slice (type 50324). Other popular values are 37218 for\n" 477 "DOS FAT partition.\n\n" 478 "Note: If you choose a non-FreeBSD partition type, it will not\n" 479 "be formatted or otherwise prepared, it will simply reserve space\n" 480 "for you to use another tool, such as DOS format, to later format\n" 481 "and actually use the partition."); 482#else 483 val = msgGetInput(tmp, "New partition type:\n\n" 484 "Pressing Enter will choose the default, a native FreeBSD\n" 485 "slice (type 165). Other popular values are 6 for\n" 486 "DOS FAT partition, 131 for a Linux ext2fs partition or\n" 487 "130 for a Linux swap partition.\n\n" 488 "Note: If you choose a non-FreeBSD partition type, it will not\n" 489 "be formatted or otherwise prepared, it will simply reserve space\n" 490 "for you to use another tool, such as DOS format, to later format\n" 491 "and actually use the partition."); 492#endif /* PC98 */ 493 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 494 if (subtype == SUBTYPE_FREEBSD) 495 partitiontype = freebsd; 496 else if (subtype == SUBTYPE_FAT) 497 partitiontype = fat; 498 else 499 partitiontype = unknown; 500 chunk_info[current_chunk]->type = partitiontype; 501 chunk_info[current_chunk]->subtype = subtype; 502 } 503 } 504 break; 505 506 case 'G': 507 snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); 508 val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" 509 "Don't forget to use the two slash (/) separator characters!\n" 510 "It's not possible to parse the field without them."); 511 if (val) { 512 long nc, nh, ns; 513 nc = strtol(val, &val, 0); 514 nh = strtol(val + 1, &val, 0); 515 ns = strtol(val + 1, 0, 0); 516 Set_Bios_Geom(d, nc, nh, ns); 517 } 518 clear(); 519 break; 520 521 case 'S': 522 /* Set Bootable */ 523 chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 524 break; 525 526 case 'U': 527 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 528 msgConfirm("You've already written this information out - you\n" 529 "can't undo it."); 530 } 531 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 532 char cp[BUFSIZ]; 533 534 sstrncpy(cp, d->name, sizeof cp); 535 Free_Disk(dev->private); 536 d = Open_Disk(cp); 537 if (!d) 538 msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 539 dev->private = d; 540 variable_unset(DISK_PARTITIONED); 541 variable_unset(DISK_LABELLED); 542 if (d) 543 record_chunks(d); 544 } 545 clear(); 546 break; 547 548 case 'W': 549 if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 550 "installation. If you are installing FreeBSD for the first time\n" 551 "then you should simply type Q when you're finished here and your\n" 552 "changes will be committed in one batch automatically at the end of\n" 553 "these questions. If you're adding a disk, you should NOT write\n" 554 "from this screen, you should do it from the label editor.\n\n" 555 "Are you absolutely sure you want to do this now?")) { 556 variable_set2(DISK_PARTITIONED, "yes", 0); 557 558 /* 559 * Don't trash the MBR if the first (and therefore only) chunk 560 * is marked for a truly dedicated disk (i.e., the disklabel 561 * starts at sector 0), even in cases where the user has 562 * requested booteasy or a "standard" MBR -- both would be 563 * fatal in this case. 564 */ 565 /* 566 * Don't offer to update the MBR on this disk if the first 567 * "real" chunk looks like a FreeBSD "all disk" partition, 568 * or the disk is entirely FreeBSD. 569 */ 570#ifdef PC98 571 if ((d->chunks->part->type != freebsd) || 572 (d->chunks->part->offset > 1)) 573 getBootMgr(d->name, &bootipl, &bootipl_size, 574 &bootmenu, &bootmenu_size); 575 else { 576 bootipl = NULL; 577 bootipl_size = 0; 578 bootmenu = NULL; 579 bootmenu_size = 0; 580 } 581 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 582#else 583 if ((d->chunks->part->type != freebsd) || 584 (d->chunks->part->offset > 1)) 585 getBootMgr(d->name, &mbrContents, &mbrSize); 586 else { 587 mbrContents = NULL; 588 mbrSize = 0; 589 } 590 Set_Boot_Mgr(d, mbrContents, mbrSize); 591#endif 592 593 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 594 msgConfirm("Disk partition write returned an error status!"); 595 else 596 msgConfirm("Wrote FDISK partition information out successfully."); 597 } 598 clear(); 599 break; 600 601 case '|': 602 if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n" 603 "No seat belts whatsoever are provided!")) { 604 clear(); 605 refresh(); 606 slice_wizard(d); 607 variable_set2(DISK_PARTITIONED, "yes", 0); 608 record_chunks(d); 609 } 610 else 611 msg = "Wise choice!"; 612 clear(); 613 break; 614 615 case '\033': /* ESC */ 616 case 'Q': 617 chunking = FALSE; 618 /* 619 * Don't trash the MBR if the first (and therefore only) chunk 620 * is marked for a truly dedicated disk (i.e., the disklabel 621 * starts at sector 0), even in cases where the user has requested 622 * booteasy or a "standard" MBR -- both would be fatal in this case. 623 */ 624#if 0 625 if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL) { 626#ifdef PC98 627 getBootMgr(d->name, &bootipl, &bootipl_size, 628 &bootmenu, &bootmenu_size); 629 if (bootipl != NULL && bootmenu != NULL) 630 Set_Boot_Mgr(d, bootipl, bootipl_size, 631 bootmenu, bootmenu_size); 632#else 633 getBootMgr(d->name, &mbrContents, &mbrSize); 634 if (mbrContents != NULL) 635 Set_Boot_Mgr(d, mbrContents, mbrSize); 636#endif 637 } 638#else 639 /* 640 * Don't offer to update the MBR on this disk if the first "real" 641 * chunk looks like a FreeBSD "all disk" partition, or the disk is 642 * entirely FreeBSD. 643 */ 644 if ((d->chunks->part->type != freebsd) || 645 (d->chunks->part->offset > 1)) { 646#ifdef PC98 647 getBootMgr(d->name, &bootipl, &bootipl_size, 648 &bootmenu, &bootmenu_size); 649 if (bootipl != NULL && bootmenu != NULL) 650 Set_Boot_Mgr(d, bootipl, bootipl_size, 651 bootmenu, bootmenu_size); 652#else 653 getBootMgr(d->name, &mbrContents, &mbrSize); 654 if (mbrContents != NULL) 655 Set_Boot_Mgr(d, mbrContents, mbrSize); 656#endif 657 } 658#endif 659 break; 660 661 case 'Z': 662 size_unit = (size_unit + 1) % UNIT_SIZE; 663 break; 664 665 default: 666 beep(); 667 msg = "Type F1 or ? for help"; 668 break; 669 } 670 } 671 p = CheckRules(d); 672 if (p) { 673 char buf[FILENAME_MAX]; 674 675 use_helpline("Press F1 to read more about disk slices."); 676 use_helpfile(systemHelpFile("partition", buf)); 677 if (!variable_get(VAR_NO_WARN)) 678 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 679 free(p); 680 } 681 restorescr(w); 682} 683 684static u_char * 685bootalloc(char *name) 686{ 687 char buf[FILENAME_MAX]; 688 struct stat sb; 689 690 snprintf(buf, sizeof buf, "/boot/%s", name); 691 if (stat(buf, &sb) != -1) { 692 int fd; 693 694 fd = open(buf, O_RDONLY); 695 if (fd != -1) { 696 u_char *cp; 697 698 cp = malloc(sb.st_size); 699 if (read(fd, cp, sb.st_size) != sb.st_size) { 700 free(cp); 701 close(fd); 702 msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf); 703 return NULL; 704 } 705 close(fd); 706 return cp; 707 } 708 msgDebug("bootalloc: couldn't open %s\n", buf); 709 } 710 else 711 msgDebug("bootalloc: can't stat %s\n", buf); 712 return NULL; 713} 714 715static int 716partitionHook(dialogMenuItem *selected) 717{ 718 Device **devs = NULL; 719 720 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 721 if (!devs) { 722 msgConfirm("Unable to find disk %s!", selected->prompt); 723 return DITEM_FAILURE; 724 } 725 /* Toggle enabled status? */ 726 if (!devs[0]->enabled) { 727 devs[0]->enabled = TRUE; 728 diskPartition(devs[0]); 729 } 730 else 731 devs[0]->enabled = FALSE; 732 return DITEM_SUCCESS; 733} 734 735static int 736partitionCheck(dialogMenuItem *selected) 737{ 738 Device **devs = NULL; 739 740 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 741 if (!devs || devs[0]->enabled == FALSE) 742 return FALSE; 743 return TRUE; 744} 745 746int 747diskPartitionEditor(dialogMenuItem *self) 748{ 749 DMenu *menu; 750 Device **devs; 751 int i, cnt, devcnt; 752 753 cnt = diskGetSelectCount(&devs); 754 devcnt = deviceCount(devs); 755 if (cnt == -1) { 756 msgConfirm("No disks found! Please verify that your disk controller is being\n" 757 "properly probed at boot time. See the Hardware Guide on the\n" 758 "Documentation menu for clues on diagnosing this type of problem."); 759 return DITEM_FAILURE; 760 } 761 else if (cnt) { 762 /* Some are already selected */ 763 for (i = 0; i < devcnt; i++) { 764 if (devs[i]->enabled) { 765 if (variable_get(VAR_NONINTERACTIVE)) 766 diskPartitionNonInteractive(devs[i]); 767 else 768 diskPartition(devs[i]); 769 } 770 } 771 } 772 else { 773 /* No disks are selected, fall-back case now */ 774 if (devcnt == 1) { 775 devs[0]->enabled = TRUE; 776 if (variable_get(VAR_NONINTERACTIVE)) 777 diskPartitionNonInteractive(devs[0]); 778 else 779 diskPartition(devs[0]); 780 return DITEM_SUCCESS; 781 } 782 else { 783 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 784 if (!menu) { 785 msgConfirm("No devices suitable for installation found!\n\n" 786 "Please verify that your disk controller (and attached drives)\n" 787 "were detected properly. This can be done by pressing the\n" 788 "[Scroll Lock] key and using the Arrow keys to move back to\n" 789 "the boot messages. Press [Scroll Lock] again to return."); 790 return DITEM_FAILURE; 791 } 792 else { 793 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 794 free(menu); 795 } 796 return i; 797 } 798 } 799 return DITEM_SUCCESS; 800} 801 802int 803diskPartitionWrite(dialogMenuItem *self) 804{ 805 Device **devs; 806 int i; 807 char *cp; 808 809 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 810 if (!devs) { 811 msgConfirm("Unable to find any disks to write to??"); 812 return DITEM_FAILURE; 813 } 814 if (isDebug()) 815 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 816 cp = variable_get(DISK_PARTITIONED); 817 if (cp && !strcmp(cp, "written")) 818 return DITEM_SUCCESS; 819 820 for (i = 0; devs[i]; i++) { 821 Disk *d = (Disk *)devs[i]->private; 822 static u_char *boot1; 823#ifndef __alpha__ 824 static u_char *boot2; 825#endif 826 827 if (!devs[i]->enabled) 828 continue; 829 830#ifdef __alpha__ 831 if (!boot1) boot1 = bootalloc("boot1"); 832 Set_Boot_Blocks(d, boot1, NULL); 833#else 834 if (!boot1) boot1 = bootalloc("boot1"); 835 if (!boot2) boot2 = bootalloc("boot2"); 836 Set_Boot_Blocks(d, boot1, boot2); 837#endif 838 839 msgNotify("Writing partition information to drive %s", d->name); 840 if (!Fake && Write_Disk(d)) { 841 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 842 return DITEM_FAILURE; 843 } 844 845 /* If we've been through here before, we don't need to do the rest */ 846 if (cp && !strcmp(cp, "written")) 847 return DITEM_SUCCESS; 848 } 849 /* Now it's not "yes", but "written" */ 850 variable_set2(DISK_PARTITIONED, "written", 0); 851 return DITEM_SUCCESS | DITEM_RESTORE; 852} 853 854/* Partition a disk based wholly on which variables are set */ 855static void 856diskPartitionNonInteractive(Device *dev) 857{ 858 char *cp; 859 int i, sz, all_disk = 0; 860#ifdef PC98 861 u_char *bootipl; 862 size_t bootipl_size; 863 u_char *bootmenu; 864 size_t bootmenu_size; 865#else 866 u_char *mbrContents; 867 size_t mbrSize; 868#endif 869 Disk *d = (Disk *)dev->private; 870 871 record_chunks(d); 872 cp = variable_get(VAR_GEOMETRY); 873 if (cp) { 874 msgDebug("Setting geometry from script to: %s\n", cp); 875 d->bios_cyl = strtol(cp, &cp, 0); 876 d->bios_hd = strtol(cp + 1, &cp, 0); 877 d->bios_sect = strtol(cp + 1, 0, 0); 878 } 879 880 cp = variable_get(VAR_PARTITION); 881 if (cp) { 882 if (!strcmp(cp, "free")) { 883 /* Do free disk space case */ 884 for (i = 0; chunk_info[i]; i++) { 885 /* If a chunk is at least 10MB in size, use it. */ 886 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 887#ifdef PC98 888 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 889 freebsd, 3, 890 (chunk_info[i]->flags & CHUNK_ALIGN), 891 "FreeBSD"); 892#else 893 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 894 freebsd, 3, 895 (chunk_info[i]->flags & CHUNK_ALIGN)); 896#endif 897 variable_set2(DISK_PARTITIONED, "yes", 0); 898 break; 899 } 900 } 901 if (!chunk_info[i]) { 902 msgConfirm("Unable to find any free space on this disk!"); 903 return; 904 } 905 } 906 else if (!strcmp(cp, "all")) { 907 /* Do all disk space case */ 908 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 909 910 All_FreeBSD(d, FALSE); 911 } 912 else if (!strcmp(cp, "exclusive")) { 913 /* Do really-all-the-disk-space case */ 914 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 915 916 All_FreeBSD(d, all_disk = TRUE); 917 } 918 else if ((sz = strtol(cp, &cp, 0))) { 919 /* Look for sz bytes free */ 920 if (*cp && toupper(*cp) == 'M') 921 sz *= ONE_MEG; 922 else if (*cp && toupper(*cp) == 'G') 923 sz *= ONE_GIG; 924 for (i = 0; chunk_info[i]; i++) { 925 /* If a chunk is at least sz MB, use it. */ 926 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 927#ifdef PC98 928 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 929 (chunk_info[i]->flags & CHUNK_ALIGN), 930 "FreeBSD"); 931#else 932 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 933 (chunk_info[i]->flags & CHUNK_ALIGN)); 934#endif 935 variable_set2(DISK_PARTITIONED, "yes", 0); 936 break; 937 } 938 } 939 if (!chunk_info[i]) { 940 msgConfirm("Unable to find %d free blocks on this disk!", sz); 941 return; 942 } 943 } 944 else if (!strcmp(cp, "existing")) { 945 /* Do existing FreeBSD case */ 946 for (i = 0; chunk_info[i]; i++) { 947 if (chunk_info[i]->type == freebsd) 948 break; 949 } 950 if (!chunk_info[i]) { 951 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 952 return; 953 } 954 } 955 else { 956 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 957 return; 958 } 959 if (!all_disk) { 960#ifdef PC98 961 getBootMgr(d->name, &bootipl, &bootipl_size, 962 &bootmenu, &bootmenu_size); 963 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 964#else 965 getBootMgr(d->name, &mbrContents, &mbrSize); 966 Set_Boot_Mgr(d, mbrContents, mbrSize); 967#endif 968 } 969 variable_set2(DISK_PARTITIONED, "yes", 0); 970 } 971} 972