disks.c revision 74297
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 74297 2001-03-15 12:33:52Z 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 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 (!variable_cmp(DISK_LABELLED, "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 /* 628 * Don't offer to update the MBR on this disk if the first "real" 629 * chunk looks like a FreeBSD "all disk" partition, or the disk is 630 * entirely FreeBSD. 631 */ 632 if ((d->chunks->part->type != freebsd) || 633 (d->chunks->part->offset > 1)) { 634 if (variable_cmp(DISK_PARTITIONED, "written")) { 635#ifdef PC98 636 getBootMgr(d->name, &bootipl, &bootipl_size, 637 &bootmenu, &bootmenu_size); 638 if (bootipl != NULL && bootmenu != NULL) 639 Set_Boot_Mgr(d, bootipl, bootipl_size, 640 bootmenu, bootmenu_size); 641#else 642 getBootMgr(d->name, &mbrContents, &mbrSize); 643 if (mbrContents != NULL) 644 Set_Boot_Mgr(d, mbrContents, mbrSize); 645#endif 646 } 647 } 648 break; 649 650 case 'Z': 651 size_unit = (size_unit + 1) % UNIT_SIZE; 652 break; 653 654 default: 655 beep(); 656 msg = "Type F1 or ? for help"; 657 break; 658 } 659 } 660 p = CheckRules(d); 661 if (p) { 662 char buf[FILENAME_MAX]; 663 664 use_helpline("Press F1 to read more about disk slices."); 665 use_helpfile(systemHelpFile("partition", buf)); 666 if (!variable_get(VAR_NO_WARN)) 667 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 668 free(p); 669 } 670 restorescr(w); 671} 672 673static u_char * 674bootalloc(char *name) 675{ 676 char buf[FILENAME_MAX]; 677 struct stat sb; 678 679 snprintf(buf, sizeof buf, "/boot/%s", name); 680 if (stat(buf, &sb) != -1) { 681 int fd; 682 683 fd = open(buf, O_RDONLY); 684 if (fd != -1) { 685 u_char *cp; 686 687 cp = malloc(sb.st_size); 688 if (read(fd, cp, sb.st_size) != sb.st_size) { 689 free(cp); 690 close(fd); 691 msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf); 692 return NULL; 693 } 694 close(fd); 695 return cp; 696 } 697 msgDebug("bootalloc: couldn't open %s\n", buf); 698 } 699 else 700 msgDebug("bootalloc: can't stat %s\n", buf); 701 return NULL; 702} 703 704static int 705partitionHook(dialogMenuItem *selected) 706{ 707 Device **devs = NULL; 708 709 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 710 if (!devs) { 711 msgConfirm("Unable to find disk %s!", selected->prompt); 712 return DITEM_FAILURE; 713 } 714 /* Toggle enabled status? */ 715 if (!devs[0]->enabled) { 716 devs[0]->enabled = TRUE; 717 diskPartition(devs[0]); 718 } 719 else 720 devs[0]->enabled = FALSE; 721 return DITEM_SUCCESS; 722} 723 724static int 725partitionCheck(dialogMenuItem *selected) 726{ 727 Device **devs = NULL; 728 729 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 730 if (!devs || devs[0]->enabled == FALSE) 731 return FALSE; 732 return TRUE; 733} 734 735int 736diskPartitionEditor(dialogMenuItem *self) 737{ 738 DMenu *menu; 739 Device **devs; 740 int i, cnt, devcnt; 741 742 cnt = diskGetSelectCount(&devs); 743 devcnt = deviceCount(devs); 744 if (cnt == -1) { 745 msgConfirm("No disks found! Please verify that your disk controller is being\n" 746 "properly probed at boot time. See the Hardware Guide on the\n" 747 "Documentation menu for clues on diagnosing this type of problem."); 748 return DITEM_FAILURE; 749 } 750 else if (cnt) { 751 /* Some are already selected */ 752 for (i = 0; i < devcnt; i++) { 753 if (devs[i]->enabled) { 754 if (variable_get(VAR_NONINTERACTIVE)) 755 diskPartitionNonInteractive(devs[i]); 756 else 757 diskPartition(devs[i]); 758 } 759 } 760 } 761 else { 762 /* No disks are selected, fall-back case now */ 763 if (devcnt == 1) { 764 devs[0]->enabled = TRUE; 765 if (variable_get(VAR_NONINTERACTIVE)) 766 diskPartitionNonInteractive(devs[0]); 767 else 768 diskPartition(devs[0]); 769 return DITEM_SUCCESS; 770 } 771 else { 772 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 773 if (!menu) { 774 msgConfirm("No devices suitable for installation found!\n\n" 775 "Please verify that your disk controller (and attached drives)\n" 776 "were detected properly. This can be done by pressing the\n" 777 "[Scroll Lock] key and using the Arrow keys to move back to\n" 778 "the boot messages. Press [Scroll Lock] again to return."); 779 return DITEM_FAILURE; 780 } 781 else { 782 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 783 free(menu); 784 } 785 return i; 786 } 787 } 788 return DITEM_SUCCESS; 789} 790 791int 792diskPartitionWrite(dialogMenuItem *self) 793{ 794 Device **devs; 795 int i; 796 797 if (!variable_cmp(DISK_PARTITIONED, "written")) 798 return DITEM_SUCCESS; 799 800 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 801 if (!devs) { 802 msgConfirm("Unable to find any disks to write to??"); 803 return DITEM_FAILURE; 804 } 805 if (isDebug()) 806 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 807 for (i = 0; devs[i]; i++) { 808 Disk *d = (Disk *)devs[i]->private; 809 static u_char *boot1; 810#ifndef __alpha__ 811 static u_char *boot2; 812#endif 813 814 if (!devs[i]->enabled) 815 continue; 816 817#ifdef __alpha__ 818 if (!boot1) boot1 = bootalloc("boot1"); 819 Set_Boot_Blocks(d, boot1, NULL); 820#else 821 if (!boot1) boot1 = bootalloc("boot1"); 822 if (!boot2) boot2 = bootalloc("boot2"); 823 Set_Boot_Blocks(d, boot1, boot2); 824#endif 825 826 msgNotify("Writing partition information to drive %s", d->name); 827 if (!Fake && Write_Disk(d)) { 828 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 829 return DITEM_FAILURE; 830 } 831 } 832 /* Now it's not "yes", but "written" */ 833 variable_set2(DISK_PARTITIONED, "written", 0); 834 return DITEM_SUCCESS | DITEM_RESTORE; 835} 836 837/* Partition a disk based wholly on which variables are set */ 838static void 839diskPartitionNonInteractive(Device *dev) 840{ 841 char *cp; 842 int i, sz, all_disk = 0; 843#ifdef PC98 844 u_char *bootipl; 845 size_t bootipl_size; 846 u_char *bootmenu; 847 size_t bootmenu_size; 848#else 849 u_char *mbrContents; 850 size_t mbrSize; 851#endif 852 Disk *d = (Disk *)dev->private; 853 854 record_chunks(d); 855 cp = variable_get(VAR_GEOMETRY); 856 if (cp) { 857 msgDebug("Setting geometry from script to: %s\n", cp); 858 d->bios_cyl = strtol(cp, &cp, 0); 859 d->bios_hd = strtol(cp + 1, &cp, 0); 860 d->bios_sect = strtol(cp + 1, 0, 0); 861 } 862 863 cp = variable_get(VAR_PARTITION); 864 if (cp) { 865 if (!strcmp(cp, "free")) { 866 /* Do free disk space case */ 867 for (i = 0; chunk_info[i]; i++) { 868 /* If a chunk is at least 10MB in size, use it. */ 869 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 870#ifdef PC98 871 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 872 freebsd, 3, 873 (chunk_info[i]->flags & CHUNK_ALIGN), 874 "FreeBSD"); 875#else 876 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 877 freebsd, 3, 878 (chunk_info[i]->flags & CHUNK_ALIGN)); 879#endif 880 variable_set2(DISK_PARTITIONED, "yes", 0); 881 break; 882 } 883 } 884 if (!chunk_info[i]) { 885 msgConfirm("Unable to find any free space on this disk!"); 886 return; 887 } 888 } 889 else if (!strcmp(cp, "all")) { 890 /* Do all disk space case */ 891 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 892 893 All_FreeBSD(d, FALSE); 894 } 895 else if (!strcmp(cp, "exclusive")) { 896 /* Do really-all-the-disk-space case */ 897 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 898 899 All_FreeBSD(d, all_disk = TRUE); 900 } 901 else if ((sz = strtol(cp, &cp, 0))) { 902 /* Look for sz bytes free */ 903 if (*cp && toupper(*cp) == 'M') 904 sz *= ONE_MEG; 905 else if (*cp && toupper(*cp) == 'G') 906 sz *= ONE_GIG; 907 for (i = 0; chunk_info[i]; i++) { 908 /* If a chunk is at least sz MB, use it. */ 909 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 910#ifdef PC98 911 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 912 (chunk_info[i]->flags & CHUNK_ALIGN), 913 "FreeBSD"); 914#else 915 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 916 (chunk_info[i]->flags & CHUNK_ALIGN)); 917#endif 918 variable_set2(DISK_PARTITIONED, "yes", 0); 919 break; 920 } 921 } 922 if (!chunk_info[i]) { 923 msgConfirm("Unable to find %d free blocks on this disk!", sz); 924 return; 925 } 926 } 927 else if (!strcmp(cp, "existing")) { 928 /* Do existing FreeBSD case */ 929 for (i = 0; chunk_info[i]; i++) { 930 if (chunk_info[i]->type == freebsd) 931 break; 932 } 933 if (!chunk_info[i]) { 934 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 935 return; 936 } 937 } 938 else { 939 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 940 return; 941 } 942 if (!all_disk) { 943#ifdef PC98 944 getBootMgr(d->name, &bootipl, &bootipl_size, 945 &bootmenu, &bootmenu_size); 946 Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); 947#else 948 getBootMgr(d->name, &mbrContents, &mbrSize); 949 Set_Boot_Mgr(d, mbrContents, mbrSize); 950#endif 951 } 952 variable_set2(DISK_PARTITIONED, "yes", 0); 953 } 954} 955 956