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