disks.c revision 97667
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 97667 2002-05-31 13:38:17Z jhb $ 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 !variable_get(VAR_DISKINTERACTIVE)) 763 diskPartitionNonInteractive(devs[i]); 764 else 765 diskPartition(devs[i]); 766 } 767 } 768 } 769 else { 770 /* No disks are selected, fall-back case now */ 771 if (devcnt == 1) { 772 devs[0]->enabled = TRUE; 773 if (variable_get(VAR_NONINTERACTIVE) && 774 !variable_get(VAR_DISKINTERACTIVE)) 775 diskPartitionNonInteractive(devs[0]); 776 else 777 diskPartition(devs[0]); 778 return DITEM_SUCCESS; 779 } 780 else { 781 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 782 if (!menu) { 783 msgConfirm("No devices suitable for installation found!\n\n" 784 "Please verify that your disk controller (and attached drives)\n" 785 "were detected properly. This can be done by pressing the\n" 786 "[Scroll Lock] key and using the Arrow keys to move back to\n" 787 "the boot messages. Press [Scroll Lock] again to return."); 788 return DITEM_FAILURE; 789 } 790 else { 791 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 792 free(menu); 793 } 794 return i; 795 } 796 } 797 return DITEM_SUCCESS; 798} 799 800int 801diskPartitionWrite(dialogMenuItem *self) 802{ 803 Device **devs; 804 int i; 805 806 if (!variable_cmp(DISK_PARTITIONED, "written")) 807 return DITEM_SUCCESS; 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 for (i = 0; devs[i]; i++) { 817 Disk *d = (Disk *)devs[i]->private; 818 static u_char *boot1; 819#ifndef __alpha__ 820 static u_char *boot2; 821#endif 822 823 if (!devs[i]->enabled) 824 continue; 825 826#ifdef __alpha__ 827 if (!boot1) boot1 = bootalloc("boot1", NULL); 828 Set_Boot_Blocks(d, boot1, NULL); 829#else 830 if (!boot1) boot1 = bootalloc("boot1", NULL); 831 if (!boot2) boot2 = bootalloc("boot2", NULL); 832 Set_Boot_Blocks(d, boot1, boot2); 833#endif 834 835 msgNotify("Writing partition information to drive %s", d->name); 836 if (!Fake && Write_Disk(d)) { 837 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 838 return DITEM_FAILURE; 839 } 840 } 841 /* Now it's not "yes", but "written" */ 842 variable_set2(DISK_PARTITIONED, "written", 0); 843 return DITEM_SUCCESS | DITEM_RESTORE; 844} 845 846/* Partition a disk based wholly on which variables are set */ 847static void 848diskPartitionNonInteractive(Device *dev) 849{ 850 char *cp; 851 int i, sz, all_disk = 0; 852#ifdef PC98 853 u_char *bootipl; 854 size_t bootipl_size; 855 u_char *bootmenu; 856 size_t bootmenu_size; 857#else 858 u_char *mbrContents; 859 size_t mbrSize; 860#endif 861 Disk *d = (Disk *)dev->private; 862 863 record_chunks(d); 864 cp = variable_get(VAR_GEOMETRY); 865 if (cp) { 866 msgDebug("Setting geometry from script to: %s\n", cp); 867 d->bios_cyl = strtol(cp, &cp, 0); 868 d->bios_hd = strtol(cp + 1, &cp, 0); 869 d->bios_sect = strtol(cp + 1, 0, 0); 870 } 871 872 cp = variable_get(VAR_PARTITION); 873 if (cp) { 874 if (!strcmp(cp, "free")) { 875 /* Do free disk space case */ 876 for (i = 0; chunk_info[i]; i++) { 877 /* If a chunk is at least 10MB in size, use it. */ 878 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 879#ifdef PC98 880 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 881 freebsd, 3, 882 (chunk_info[i]->flags & CHUNK_ALIGN), 883 "FreeBSD"); 884#else 885 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 886 freebsd, 3, 887 (chunk_info[i]->flags & CHUNK_ALIGN)); 888#endif 889 variable_set2(DISK_PARTITIONED, "yes", 0); 890 break; 891 } 892 } 893 if (!chunk_info[i]) { 894 msgConfirm("Unable to find any free space on this disk!"); 895 return; 896 } 897 } 898 else if (!strcmp(cp, "all")) { 899 /* Do all disk space case */ 900 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 901 902 All_FreeBSD(d, FALSE); 903 } 904 else if (!strcmp(cp, "exclusive")) { 905 /* Do really-all-the-disk-space case */ 906 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 907 908 All_FreeBSD(d, all_disk = TRUE); 909 } 910 else if ((sz = strtol(cp, &cp, 0))) { 911 /* Look for sz bytes free */ 912 if (*cp && toupper(*cp) == 'M') 913 sz *= ONE_MEG; 914 else if (*cp && toupper(*cp) == 'G') 915 sz *= ONE_GIG; 916 for (i = 0; chunk_info[i]; i++) { 917 /* If a chunk is at least sz MB, use it. */ 918 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 919#ifdef PC98 920 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 921 (chunk_info[i]->flags & CHUNK_ALIGN), 922 "FreeBSD"); 923#else 924 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 925 (chunk_info[i]->flags & CHUNK_ALIGN)); 926#endif 927 variable_set2(DISK_PARTITIONED, "yes", 0); 928 break; 929 } 930 } 931 if (!chunk_info[i]) { 932 msgConfirm("Unable to find %d free blocks on this disk!", sz); 933 return; 934 } 935 } 936 else if (!strcmp(cp, "existing")) { 937 /* Do existing FreeBSD case */ 938 for (i = 0; chunk_info[i]; i++) { 939 if (chunk_info[i]->type == freebsd) 940 break; 941 } 942 if (!chunk_info[i]) { 943 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 944 return; 945 } 946 } 947 else { 948 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 949 return; 950 } 951 if (!all_disk) { 952#ifdef PC98 953 getBootMgr(d->name, &bootipl, &bootipl_size, 954 &bootmenu, &bootmenu_size); 955 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 956#else 957 getBootMgr(d->name, &mbrContents, &mbrSize); 958 Set_Boot_Mgr(d, mbrContents, mbrSize); 959#endif 960 } 961 variable_set2(DISK_PARTITIONED, "yes", 0); 962 } 963} 964 965