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