disks.c revision 61277
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 61277 2000-06-05 13:17:23Z 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#ifndef PC98 167static u_char * 168getBootMgr(char *dname) 169{ 170#ifndef __alpha__ /* only meaningful on x86 */ 171 extern u_char mbr[], boot0[]; 172 char str[80]; 173 char *cp; 174 int i = 0; 175 176 cp = variable_get(VAR_BOOTMGR); 177 if (!cp) { 178 /* Figure out what kind of MBR the user wants */ 179 sprintf(str, "Install Boot Manager for drive %s?", dname); 180 MenuMBRType.title = str; 181 i = dmenuOpenSimple(&MenuMBRType, FALSE); 182 } 183 else { 184 if (!strncmp(cp, "boot", 4)) 185 BootMgr = 0; 186 else if (!strcmp(cp, "standard")) 187 BootMgr = 1; 188 else 189 BootMgr = 2; 190 } 191 if (cp || i) { 192 switch (BootMgr) { 193 case 0: 194 return boot0; 195 196 case 1: 197 return mbr; 198 199 case 2: 200 default: 201 break; 202 } 203 } 204#endif 205 return NULL; 206} 207#endif 208 209int 210diskGetSelectCount(Device ***devs) 211{ 212 int i, cnt, enabled; 213 char *cp; 214 Device **dp; 215 216 cp = variable_get(VAR_DISK); 217 dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); 218 cnt = deviceCount(dp); 219 if (!cnt) 220 return -1; 221 for (i = 0, enabled = 0; i < cnt; i++) { 222 if (dp[i]->enabled) 223 ++enabled; 224 } 225 return enabled; 226} 227 228void 229diskPartition(Device *dev) 230{ 231 char *cp, *p; 232 int rv, key = 0; 233 Boolean chunking; 234 char *msg = NULL; 235#ifndef PC98 236 u_char *mbrContents; 237#endif 238 WINDOW *w = savescr(); 239 Disk *d = (Disk *)dev->private; 240 int size_unit; 241 242 size_unit = UNIT_BLOCKS; 243 chunking = TRUE; 244 keypad(stdscr, TRUE); 245 246 /* Flush both the dialog and curses library views of the screen 247 since we don't always know who called us */ 248 dialog_clear_norefresh(), clear(); 249 current_chunk = 0; 250 251 /* Set up the chunk array */ 252 record_chunks(d); 253 254 while (chunking) { 255 char *val, geometry[80]; 256 257 /* Now print our overall state */ 258 if (d) 259 print_chunks(d, size_unit); 260 print_command_summary(); 261 if (msg) { 262 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 263 beep(); 264 msg = NULL; 265 } 266 else { 267 move(23, 0); 268 clrtoeol(); 269 } 270 271 /* Get command character */ 272 key = getch(); 273 switch (toupper(key)) { 274 case '\014': /* ^L (redraw) */ 275 clear(); 276 msg = NULL; 277 break; 278 279 case '\020': /* ^P */ 280 case KEY_UP: 281 case '-': 282 if (current_chunk != 0) 283 --current_chunk; 284 break; 285 286 case '\016': /* ^N */ 287 case KEY_DOWN: 288 case '+': 289 case '\r': 290 case '\n': 291 if (chunk_info[current_chunk + 1]) 292 ++current_chunk; 293 break; 294 295 case KEY_HOME: 296 current_chunk = 0; 297 break; 298 299 case KEY_END: 300 while (chunk_info[current_chunk + 1]) 301 ++current_chunk; 302 break; 303 304 case KEY_F(1): 305 case '?': 306 systemDisplayHelp("slice"); 307 clear(); 308 break; 309 310 case 'A': 311#ifdef __alpha__ 312 rv = 1; 313#else /* The rest is only relevant on x86 */ 314 cp = variable_get(VAR_DEDICATE_DISK); 315 if (cp && !strcasecmp(cp, "always")) 316 rv = 1; 317 else { 318 rv = msgYesNo("Do you want to do this with a true partition entry\n" 319 "so as to remain cooperative with any future possible\n" 320 "operating systems on the drive(s)?\n" 321 "(See also the section about ``dangerously dedicated''\n" 322 "disks in the FreeBSD FAQ.)"); 323 if (rv == -1) 324 rv = 0; 325 } 326#endif 327 All_FreeBSD(d, rv); 328 variable_set2(DISK_PARTITIONED, "yes", 0); 329 record_chunks(d); 330 clear(); 331 break; 332 333 case 'C': 334 if (chunk_info[current_chunk]->type != unused) 335 msg = "Slice in use, delete it first or move to an unused one."; 336 else { 337 char *val, tmp[20], *cp; 338 int size; 339#ifdef PC98 340 char name[16]; 341 342 snprintf(name, 16, "%s", "FreeBSD"); 343 val = msgGetInput(name, 344 "Please specify the name for new FreeBSD slice."); 345 if (val) 346 strncpy(name, val, 16); 347#else 348 int subtype; 349 chunk_e partitiontype; 350#endif 351 snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); 352 val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" 353 "or append a trailing `M' for megabytes (e.g. 20M)."); 354 if (val && (size = strtol(val, &cp, 0)) > 0) { 355 if (*cp && toupper(*cp) == 'M') 356 size *= ONE_MEG; 357 else if (*cp && toupper(*cp) == 'G') 358 size *= ONE_GIG; 359#ifdef PC98 360 Create_Chunk(d, chunk_info[current_chunk]->offset, size, 361 freebsd, 3, 362 (chunk_info[current_chunk]->flags & CHUNK_ALIGN), 363 name); 364 variable_set2(DISK_PARTITIONED, "yes", 0); 365 record_chunks(d); 366#else 367 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 368 val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 369 "Pressing Enter will choose the default, a native FreeBSD\n" 370 "slice (type 165). You can choose other types, 6 for a\n" 371 "DOS partition or 131 for a Linux partition, for example.\n\n" 372 "Note: If you choose a non-FreeBSD partition type, it will not\n" 373 "be formatted or otherwise prepared, it will simply reserve space\n" 374 "for you to use another tool, such as DOS FORMAT, to later format\n" 375 "and use the partition."); 376 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 377 if (subtype == SUBTYPE_FREEBSD) 378 partitiontype = freebsd; 379 else if (subtype == SUBTYPE_FAT) 380 partitiontype = fat; 381 else 382 partitiontype = unknown; 383#ifdef __alpha__ 384 if (partitiontype == freebsd && size == chunk_info[current_chunk]->size) 385 All_FreeBSD(d, 1); 386 else 387#endif 388 Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 389 (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); 390 variable_set2(DISK_PARTITIONED, "yes", 0); 391 record_chunks(d); 392 } 393#endif /* PC98 */ 394 } 395 clear(); 396 } 397 break; 398 399 case KEY_DC: 400 case 'D': 401 if (chunk_info[current_chunk]->type == unused) 402 msg = "Slice is already unused!"; 403 else { 404 Delete_Chunk(d, chunk_info[current_chunk]); 405 variable_set2(DISK_PARTITIONED, "yes", 0); 406 record_chunks(d); 407 } 408 break; 409 410 case 'T': 411 if (chunk_info[current_chunk]->type == unused) 412 msg = "Slice is currently unused (use create instead)"; 413 else { 414 char *val, tmp[20]; 415 int subtype; 416 chunk_e partitiontype; 417 418 sprintf(tmp, "%d", SUBTYPE_FREEBSD); 419#ifdef PC98 420 val = msgGetInput(tmp, "New partition type:\n\n" 421 "Pressing Enter will choose the default, a native FreeBSD\n" 422 "slice (type 50324). Other popular values are 37218 for\n" 423 "DOS FAT partition.\n\n" 424 "Note: If you choose a non-FreeBSD partition type, it will not\n" 425 "be formatted or otherwise prepared, it will simply reserve space\n" 426 "for you to use another tool, such as DOS format, to later format\n" 427 "and actually use the partition."); 428#else 429 val = msgGetInput(tmp, "New partition type:\n\n" 430 "Pressing Enter will choose the default, a native FreeBSD\n" 431 "slice (type 165). Other popular values are 6 for\n" 432 "DOS FAT partition, 131 for a Linux ext2fs partition or\n" 433 "130 for a Linux swap partition.\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 actually use the partition."); 438#endif /* PC98 */ 439 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 440 if (subtype == SUBTYPE_FREEBSD) 441 partitiontype = freebsd; 442 else if (subtype == SUBTYPE_FAT) 443 partitiontype = fat; 444 else 445 partitiontype = unknown; 446 chunk_info[current_chunk]->type = partitiontype; 447 chunk_info[current_chunk]->subtype = subtype; 448 } 449 } 450 break; 451 452 case 'G': 453 snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); 454 val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" 455 "Don't forget to use the two slash (/) separator characters!\n" 456 "It's not possible to parse the field without them."); 457 if (val) { 458 long nc, nh, ns; 459 nc = strtol(val, &val, 0); 460 nh = strtol(val + 1, &val, 0); 461 ns = strtol(val + 1, 0, 0); 462 Set_Bios_Geom(d, nc, nh, ns); 463 } 464 clear(); 465 break; 466 467 case 'S': 468 /* Set Bootable */ 469 chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 470 break; 471 472 case 'U': 473 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 474 msgConfirm("You've already written this information out - you\n" 475 "can't undo it."); 476 } 477 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 478 char cp[BUFSIZ]; 479 480 sstrncpy(cp, d->name, sizeof cp); 481 Free_Disk(dev->private); 482 d = Open_Disk(cp); 483 if (!d) 484 msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 485 dev->private = d; 486 variable_unset(DISK_PARTITIONED); 487 variable_unset(DISK_LABELLED); 488 if (d) 489 record_chunks(d); 490 } 491 clear(); 492 break; 493 494 case 'W': 495 if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 496 "installation. If you are installing FreeBSD for the first time\n" 497 "then you should simply type Q when you're finished here and your\n" 498 "changes will be committed in one batch automatically at the end of\n" 499 "these questions. If you're adding a disk, you should NOT write\n" 500 "from this screen, you should do it from the label editor.\n\n" 501 "Are you absolutely sure you want to do this now?")) { 502 variable_set2(DISK_PARTITIONED, "yes", 0); 503 504#ifndef PC98 505 /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated 506 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested 507 * booteasy or a "standard" MBR -- both would be fatal in this case. 508 */ 509 /* 510 * Don't offer to update the MBR on this disk if the first "real" chunk looks like 511 * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD. 512 */ 513 if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1))) 514 mbrContents = getBootMgr(d->name); 515 else 516 mbrContents = NULL; 517 Set_Boot_Mgr(d, mbrContents); 518#endif /* !PC98 */ 519 520 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 521 msgConfirm("Disk partition write returned an error status!"); 522 else 523 msgConfirm("Wrote FDISK partition information out successfully."); 524 } 525 clear(); 526 break; 527 528 case '|': 529 if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n" 530 "No seat belts whatsoever are provided!")) { 531 clear(); 532 refresh(); 533 slice_wizard(d); 534 variable_set2(DISK_PARTITIONED, "yes", 0); 535 record_chunks(d); 536 } 537 else 538 msg = "Wise choice!"; 539 clear(); 540 break; 541 542 case '\033': /* ESC */ 543 case 'Q': 544 chunking = FALSE; 545#ifndef PC98 546 /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated 547 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested 548 * booteasy or a "standard" MBR -- both would be fatal in this case. 549 */ 550#if 0 551 if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL 552 && (mbrContents = getBootMgr(d->name)) != NULL) 553 Set_Boot_Mgr(d, mbrContents); 554#else 555 /* 556 * Don't offer to update the MBR on this disk if the first "real" chunk looks like 557 * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD. 558 */ 559 if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) && 560 (mbrContents = getBootMgr(d->name)) != NULL) 561 Set_Boot_Mgr(d, mbrContents); 562#endif 563#endif /* !PC98 */ 564 break; 565 566 case 'Z': 567 size_unit = (size_unit + 1) % UNIT_SIZE; 568 break; 569 570 default: 571 beep(); 572 msg = "Type F1 or ? for help"; 573 break; 574 } 575 } 576 p = CheckRules(d); 577 if (p) { 578 char buf[FILENAME_MAX]; 579 580 use_helpline("Press F1 to read more about disk slices."); 581 use_helpfile(systemHelpFile("partition", buf)); 582 if (!variable_get(VAR_NO_WARN)) 583 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 584 free(p); 585 } 586 restorescr(w); 587} 588 589static u_char * 590bootalloc(char *name) 591{ 592 char buf[FILENAME_MAX]; 593 struct stat sb; 594 595 snprintf(buf, sizeof buf, "/boot/%s", name); 596 if (stat(buf, &sb) != -1) { 597 int fd; 598 599 fd = open(buf, O_RDONLY); 600 if (fd != -1) { 601 u_char *cp; 602 603 cp = malloc(sb.st_size); 604 if (read(fd, cp, sb.st_size) != sb.st_size) { 605 free(cp); 606 close(fd); 607 msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf); 608 return NULL; 609 } 610 close(fd); 611 return cp; 612 } 613 msgDebug("bootalloc: couldn't open %s\n", buf); 614 } 615 else 616 msgDebug("bootalloc: can't stat %s\n", buf); 617 return NULL; 618} 619 620static int 621partitionHook(dialogMenuItem *selected) 622{ 623 Device **devs = NULL; 624 625 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 626 if (!devs) { 627 msgConfirm("Unable to find disk %s!", selected->prompt); 628 return DITEM_FAILURE; 629 } 630 /* Toggle enabled status? */ 631 if (!devs[0]->enabled) { 632 devs[0]->enabled = TRUE; 633 diskPartition(devs[0]); 634 } 635 else 636 devs[0]->enabled = FALSE; 637 return DITEM_SUCCESS; 638} 639 640static int 641partitionCheck(dialogMenuItem *selected) 642{ 643 Device **devs = NULL; 644 645 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 646 if (!devs || devs[0]->enabled == FALSE) 647 return FALSE; 648 return TRUE; 649} 650 651int 652diskPartitionEditor(dialogMenuItem *self) 653{ 654 DMenu *menu; 655 Device **devs; 656 int i, cnt, devcnt; 657 658 cnt = diskGetSelectCount(&devs); 659 devcnt = deviceCount(devs); 660 if (cnt == -1) { 661 msgConfirm("No disks found! Please verify that your disk controller is being\n" 662 "properly probed at boot time. See the Hardware Guide on the\n" 663 "Documentation menu for clues on diagnosing this type of problem."); 664 return DITEM_FAILURE; 665 } 666 else if (cnt) { 667 /* Some are already selected */ 668 for (i = 0; i < devcnt; i++) { 669 if (devs[i]->enabled) { 670 if (variable_get(VAR_NONINTERACTIVE)) 671 diskPartitionNonInteractive(devs[i]); 672 else 673 diskPartition(devs[i]); 674 } 675 } 676 } 677 else { 678 /* No disks are selected, fall-back case now */ 679 if (devcnt == 1) { 680 devs[0]->enabled = TRUE; 681 if (variable_get(VAR_NONINTERACTIVE)) 682 diskPartitionNonInteractive(devs[0]); 683 else 684 diskPartition(devs[0]); 685 return DITEM_SUCCESS; 686 } 687 else { 688 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 689 if (!menu) { 690 msgConfirm("No devices suitable for installation found!\n\n" 691 "Please verify that your disk controller (and attached drives)\n" 692 "were detected properly. This can be done by pressing the\n" 693 "[Scroll Lock] key and using the Arrow keys to move back to\n" 694 "the boot messages. Press [Scroll Lock] again to return."); 695 return DITEM_FAILURE; 696 } 697 else { 698 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 699 free(menu); 700 } 701 return i; 702 } 703 } 704 return DITEM_SUCCESS; 705} 706 707int 708diskPartitionWrite(dialogMenuItem *self) 709{ 710 Device **devs; 711 int i; 712 char *cp; 713 714 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 715 if (!devs) { 716 msgConfirm("Unable to find any disks to write to??"); 717 return DITEM_FAILURE; 718 } 719 if (isDebug()) 720 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 721 cp = variable_get(DISK_PARTITIONED); 722 if (cp && !strcmp(cp, "written")) 723 return DITEM_SUCCESS; 724 725 for (i = 0; devs[i]; i++) { 726 Disk *d = (Disk *)devs[i]->private; 727 static u_char *boot1; 728#ifndef __alpha__ 729 static u_char *boot2; 730#endif 731 732 if (!devs[i]->enabled) 733 continue; 734 735#ifdef __alpha__ 736 if (!boot1) boot1 = bootalloc("boot1"); 737 Set_Boot_Blocks(d, boot1, NULL); 738#else 739 if (!boot1) boot1 = bootalloc("boot1"); 740 if (!boot2) boot2 = bootalloc("boot2"); 741 Set_Boot_Blocks(d, boot1, boot2); 742#endif 743 744 msgNotify("Writing partition information to drive %s", d->name); 745 if (!Fake && Write_Disk(d)) { 746 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 747 return DITEM_FAILURE; 748 } 749 750 /* If we've been through here before, we don't need to do the rest */ 751 if (cp && !strcmp(cp, "written")) 752 return DITEM_SUCCESS; 753 } 754 /* Now it's not "yes", but "written" */ 755 variable_set2(DISK_PARTITIONED, "written", 0); 756 return DITEM_SUCCESS | DITEM_RESTORE; 757} 758 759/* Partition a disk based wholly on which variables are set */ 760static void 761diskPartitionNonInteractive(Device *dev) 762{ 763 char *cp; 764 int i, sz, all_disk = 0; 765#ifndef PC98 766 u_char *mbrContents; 767#endif 768 Disk *d = (Disk *)dev->private; 769 770 record_chunks(d); 771 cp = variable_get(VAR_GEOMETRY); 772 if (cp) { 773 msgDebug("Setting geometry from script to: %s\n", cp); 774 d->bios_cyl = strtol(cp, &cp, 0); 775 d->bios_hd = strtol(cp + 1, &cp, 0); 776 d->bios_sect = strtol(cp + 1, 0, 0); 777 } 778 779 cp = variable_get(VAR_PARTITION); 780 if (cp) { 781 if (!strcmp(cp, "free")) { 782 /* Do free disk space case */ 783 for (i = 0; chunk_info[i]; i++) { 784 /* If a chunk is at least 10MB in size, use it. */ 785 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 786#ifdef PC98 787 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 788 freebsd, 3, 789 (chunk_info[i]->flags & CHUNK_ALIGN), 790 "FreeBSD"); 791#else 792 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, 793 freebsd, 3, 794 (chunk_info[i]->flags & CHUNK_ALIGN)); 795#endif 796 variable_set2(DISK_PARTITIONED, "yes", 0); 797 break; 798 } 799 } 800 if (!chunk_info[i]) { 801 msgConfirm("Unable to find any free space on this disk!"); 802 return; 803 } 804 } 805 else if (!strcmp(cp, "all")) { 806 /* Do all disk space case */ 807 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 808 809 All_FreeBSD(d, FALSE); 810 } 811 else if (!strcmp(cp, "exclusive")) { 812 /* Do really-all-the-disk-space case */ 813 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 814 815 All_FreeBSD(d, all_disk = TRUE); 816 } 817 else if ((sz = strtol(cp, &cp, 0))) { 818 /* Look for sz bytes free */ 819 if (*cp && toupper(*cp) == 'M') 820 sz *= ONE_MEG; 821 else if (*cp && toupper(*cp) == 'G') 822 sz *= ONE_GIG; 823 for (i = 0; chunk_info[i]; i++) { 824 /* If a chunk is at least sz MB, use it. */ 825 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 826#ifdef PC98 827 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 828 (chunk_info[i]->flags & CHUNK_ALIGN), 829 "FreeBSD"); 830#else 831 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, 832 (chunk_info[i]->flags & CHUNK_ALIGN)); 833#endif 834 variable_set2(DISK_PARTITIONED, "yes", 0); 835 break; 836 } 837 } 838 if (!chunk_info[i]) { 839 msgConfirm("Unable to find %d free blocks on this disk!", sz); 840 return; 841 } 842 } 843 else if (!strcmp(cp, "existing")) { 844 /* Do existing FreeBSD case */ 845 for (i = 0; chunk_info[i]; i++) { 846 if (chunk_info[i]->type == freebsd) 847 break; 848 } 849 if (!chunk_info[i]) { 850 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 851 return; 852 } 853 } 854 else { 855 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 856 return; 857 } 858#ifndef PC98 859 if (!all_disk) { 860 mbrContents = getBootMgr(d->name); 861 Set_Boot_Mgr(d, mbrContents); 862 } 863#endif 864 variable_set2(DISK_PARTITIONED, "yes", 0); 865 } 866} 867