disks.c revision 29204
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 * $Id: disks.c,v 1.89 1997/09/03 10:47:44 jkh Exp $ 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 <sys/disklabel.h> 40 41/* Where we start displaying chunk information on the screen */ 42#define CHUNK_START_ROW 5 43 44/* Where we keep track of MBR chunks */ 45static struct chunk *chunk_info[16]; 46static int current_chunk; 47 48static void diskPartitionNonInteractive(Device *dev, Disk *d); 49 50static void 51record_chunks(Disk *d) 52{ 53 struct chunk *c1 = NULL; 54 int i = 0; 55 int last_free = 0; 56 57 if (!d->chunks) 58 msgFatal("No chunk list found for %s!", d->name); 59 60 for (c1 = d->chunks->part; c1; c1 = c1->next) { 61 if (c1->type == unused && c1->size > last_free) { 62 last_free = c1->size; 63 current_chunk = i; 64 } 65 chunk_info[i++] = c1; 66 } 67 chunk_info[i] = NULL; 68 if (current_chunk >= i) 69 current_chunk = i - 1; 70} 71 72static int Total; 73 74static void 75print_chunks(Disk *d) 76{ 77 int row; 78 int i; 79 80 for (i = Total = 0; chunk_info[i]; i++) 81 Total += chunk_info[i]->size; 82 if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { 83 dialog_clear_norefresh(); 84 msgConfirm("WARNING: A geometry of %d/%d/%d for %s is incorrect. Using\n" 85 "a more likely geometry. If this geometry is incorrect or you\n" 86 "are unsure as to whether or not it's correct, please consult\n" 87 "the Hardware Guide in the Documentation submenu or use the\n" 88 "(G)eometry command to change it now.\n\n" 89 "Remember: you need to enter whatever your BIOS thinks the\n" 90 "geometry is! For IDE, it's what you were told in the BIOS\n" 91 "setup. For SCSI, it's the translation mode your controller is\n" 92 "using. Do NOT use a ``physical geometry''.", 93 d->bios_cyl, d->bios_hd, d->bios_sect, d->name); 94 Sanitize_Bios_Geom(d); 95 } 96 attrset(A_NORMAL); 97 mvaddstr(0, 0, "Disk name:\t"); 98 clrtobot(); 99 attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); 100 attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); 101 mvprintw(1, 0, 102 "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors", 103 d->bios_cyl, d->bios_hd, d->bios_sect, 104 d->bios_cyl * d->bios_hd * d->bios_sect); 105 mvprintw(3, 1, "%10s %10s %10s %8s %8s %8s %8s %8s", 106 "Offset", "Size", "End", "Name", "PType", "Desc", 107 "Subtype", "Flags"); 108 for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { 109 if (i == current_chunk) 110 attrset(ATTR_SELECTED); 111 mvprintw(row, 2, "%10ld %10lu %10lu %8s %8d %8s %8d\t%-6s", 112 chunk_info[i]->offset, chunk_info[i]->size, 113 chunk_info[i]->end, chunk_info[i]->name, 114 chunk_info[i]->type, 115 slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), 116 chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); 117 if (i == current_chunk) 118 attrset(A_NORMAL); 119 } 120} 121 122static void 123print_command_summary() 124{ 125 mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); 126 mvprintw(16, 0, "A = Use Entire Disk B = Bad Block Scan C = Create Slice"); 127 mvprintw(17, 0, "D = Delete Slice G = Set Drive Geometry S = Set Bootable"); 128 mvprintw(18, 0, "U = Undo All Changes Q = Finish"); 129 if (!RunningAsInit) 130 mvprintw(18, 48, "W = Write Changes"); 131 mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); 132 move(0, 0); 133} 134 135static u_char * 136getBootMgr(char *dname) 137{ 138 extern u_char mbr[], bteasy17[]; 139 char str[80]; 140 char *cp; 141 int i = 0; 142 143 cp = variable_get(VAR_BOOTMGR); 144 if (!cp) { 145 /* Figure out what kind of MBR the user wants */ 146 sprintf(str, "Install Boot Manager for drive %s?", dname); 147 MenuMBRType.title = str; 148 i = dmenuOpenSimple(&MenuMBRType, FALSE); 149 } 150 else { 151 if (!strncmp(cp, "boot", 4)) 152 BootMgr = 0; 153 else if (!strcmp(cp, "standard")) 154 BootMgr = 1; 155 else 156 BootMgr = 2; 157 } 158 if (cp || i) { 159 switch (BootMgr) { 160 case 0: 161 return bteasy17; 162 163 case 1: 164 return mbr; 165 166 case 2: 167 default: 168 break; 169 } 170 } 171 return NULL; 172} 173 174void 175diskPartition(Device *dev, Disk *d) 176{ 177 char *cp, *p; 178 int rv, key = 0; 179 Boolean chunking; 180 char *msg = NULL; 181 u_char *mbrContents; 182 WINDOW *w = savescr(); 183 184 chunking = TRUE; 185 keypad(stdscr, TRUE); 186 187 /* Flush both the dialog and curses library views of the screen 188 since we don't always know who called us */ 189 dialog_clear_norefresh(), clear(); 190 current_chunk = 0; 191 192 /* Set up the chunk array */ 193 record_chunks(d); 194 195 while (chunking) { 196 char *val, geometry[80]; 197 198 /* Now print our overall state */ 199 if (d) 200 print_chunks(d); 201 print_command_summary(); 202 if (msg) { 203 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 204 beep(); 205 msg = NULL; 206 } 207 else { 208 move(23, 0); 209 clrtoeol(); 210 } 211 212 /* Get command character */ 213 key = getch(); 214 switch (toupper(key)) { 215 case '\014': /* ^L (redraw) */ 216 clear(); 217 msg = NULL; 218 break; 219 220 case '\020': /* ^P */ 221 case KEY_UP: 222 case '-': 223 if (current_chunk != 0) 224 --current_chunk; 225 break; 226 227 case '\016': /* ^N */ 228 case KEY_DOWN: 229 case '+': 230 case '\r': 231 case '\n': 232 if (chunk_info[current_chunk + 1]) 233 ++current_chunk; 234 break; 235 236 case KEY_HOME: 237 current_chunk = 0; 238 break; 239 240 case KEY_END: 241 while (chunk_info[current_chunk + 1]) 242 ++current_chunk; 243 break; 244 245 case KEY_F(1): 246 case '?': 247 systemDisplayHelp("slice"); 248 clear(); 249 break; 250 251 case 'A': 252 cp = variable_get(VAR_DEDICATE_DISK); 253 if (cp && !strcasecmp(cp, "always")) 254 rv = 1; 255 else { 256 rv = msgYesNo("Do you want to do this with a true partition entry\n" 257 "so as to remain cooperative with any future possible\n" 258 "operating systems on the drive(s)?\n" 259 "(See also the section about ``dangerously dedicated''\n" 260 "disks in the FreeBSD FAQ.)"); 261 if (rv == -1) 262 rv = 0; 263 } 264 All_FreeBSD(d, rv); 265 variable_set2(DISK_PARTITIONED, "yes"); 266 record_chunks(d); 267 clear(); 268 break; 269 270 case 'B': 271 if (chunk_info[current_chunk]->type != freebsd) 272 msg = "Can only scan for bad blocks in FreeBSD slice."; 273 else if (strncmp(d->name, "sd", 2) || 274 !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n" 275 "Are you sure you want to do this on a SCSI disk?")) { 276 if (chunk_info[current_chunk]->flags & CHUNK_BAD144) 277 chunk_info[current_chunk]->flags &= ~CHUNK_BAD144; 278 else 279 chunk_info[current_chunk]->flags |= CHUNK_BAD144; 280 } 281 clear(); 282 break; 283 284 case 'C': 285 if (chunk_info[current_chunk]->type != unused) 286 msg = "Slice in use, delete it first or move to an unused one."; 287 else { 288 char *val, tmp[20], *cp; 289 int size, subtype; 290 chunk_e partitiontype; 291 292 snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size); 293 val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" 294 "or append a trailing `M' for megabytes (e.g. 20M)."); 295 if (val && (size = strtol(val, &cp, 0)) > 0) { 296 if (*cp && toupper(*cp) == 'M') 297 size *= ONE_MEG; 298 strcpy(tmp, "165"); 299 val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 300 "Pressing Enter will choose the default, a native FreeBSD\n" 301 "slice (type 165). You can choose other types, 6 for a\n" 302 "DOS partition or 131 for a Linux partition, for example.\n\n" 303 "Note: If you choose a non-FreeBSD partition type, it will not\n" 304 "be formatted or otherwise prepared, it will simply reserve space\n" 305 "for you to use another tool, such as DOS FORMAT, to later format\n" 306 "and use the partition."); 307 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 308 if (subtype==165) 309 partitiontype=freebsd; 310 else if (subtype==6) 311 partitiontype=fat; 312 else 313 partitiontype=unknown; 314 Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 315 (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); 316 variable_set2(DISK_PARTITIONED, "yes"); 317 record_chunks(d); 318 } 319 } 320 clear(); 321 } 322 break; 323 324 case KEY_DC: 325 case 'D': 326 if (chunk_info[current_chunk]->type == unused) 327 msg = "Slice is already unused!"; 328 else { 329 Delete_Chunk(d, chunk_info[current_chunk]); 330 variable_set2(DISK_PARTITIONED, "yes"); 331 record_chunks(d); 332 } 333 break; 334 335 case 'G': 336 snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); 337 val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" 338 "Don't forget to use the two slash (/) separator characters!\n" 339 "It's not possible to parse the field without them."); 340 if (val) { 341 long nc, nh, ns; 342 nc = strtol(val, &val, 0); 343 nh = strtol(val + 1, &val, 0); 344 ns = strtol(val + 1, 0, 0); 345 Set_Bios_Geom(d, nc, nh, ns); 346 } 347 clear(); 348 break; 349 350 case 'S': 351 /* Set Bootable */ 352 chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 353 break; 354 355 case 'U': 356 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 357 msgConfirm("You've already written this information out - you\n" 358 "can't undo it."); 359 } 360 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 361 char cp[BUFSIZ]; 362 363 sstrncpy(cp, d->name, sizeof cp); 364 Free_Disk(dev->private); 365 d = Open_Disk(cp); 366 if (!d) 367 msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 368 dev->private = d; 369 variable_unset(DISK_PARTITIONED); 370 variable_unset(DISK_LABELLED); 371 if (d) 372 record_chunks(d); 373 } 374 clear(); 375 break; 376 377 case 'W': 378 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 379 msgConfirm("You've already written this information out - if\n" 380 "you wish to overwrite it, you'll have to restart."); 381 } 382 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 383 "installation. If you are installing FreeBSD for the first time\n" 384 "then you should simply type Q when you're finished here and your\n" 385 "changes will be committed in one batch automatically at the end of\n" 386 "these questions.\n\n" 387 "Are you absolutely sure you want to do this now?")) { 388 variable_set2(DISK_PARTITIONED, "yes"); 389 390 /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated 391 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested 392 * booteasy or a "standard" MBR -- both would be fatal in this case. 393 */ 394 if (!(d->chunks->part->flags & CHUNK_FORCE_ALL) && (mbrContents = getBootMgr(d->name)) != NULL) 395 Set_Boot_Mgr(d, mbrContents); 396 397 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 398 msgConfirm("Disk partition write returned an error status!"); 399 else 400 msgConfirm("Wrote FDISK partition information out successfully."); 401 } 402 clear(); 403 break; 404 405 case '|': 406 if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n" 407 "No seat belts whatsoever are provided!")) { 408 clear(); 409 refresh(); 410 slice_wizard(d); 411 variable_set2(DISK_PARTITIONED, "yes"); 412 record_chunks(d); 413 } 414 else 415 msg = "Wise choice!"; 416 clear(); 417 break; 418 419 case '\033': /* ESC */ 420 case 'Q': 421 chunking = FALSE; 422 /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated 423 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested 424 * booteasy or a "standard" MBR -- both would be fatal in this case. 425 */ 426 if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL 427 && (mbrContents = getBootMgr(d->name)) != NULL) 428 Set_Boot_Mgr(d, mbrContents); 429 break; 430 431 default: 432 beep(); 433 msg = "Type F1 or ? for help"; 434 break; 435 } 436 } 437 p = CheckRules(d); 438 if (p) { 439 char buf[FILENAME_MAX]; 440 441 dialog_clear_norefresh(); 442 use_helpline("Press F1 to read more about disk slices."); 443 use_helpfile(systemHelpFile("partition", buf)); 444 if (!variable_get(VAR_NO_WARN)) 445 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 446 free(p); 447 } 448 restorescr(w); 449} 450 451static int 452partitionHook(dialogMenuItem *selected) 453{ 454 Device **devs = NULL; 455 456 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 457 if (!devs) { 458 msgConfirm("Unable to find disk %s!", selected->prompt); 459 return DITEM_FAILURE; 460 } 461 /* Toggle enabled status? */ 462 if (!devs[0]->enabled) { 463 devs[0]->enabled = TRUE; 464 diskPartition(devs[0], (Disk *)devs[0]->private); 465 } 466 else 467 devs[0]->enabled = FALSE; 468 return DITEM_SUCCESS | DITEM_REDRAW; 469} 470 471static int 472partitionCheck(dialogMenuItem *selected) 473{ 474 Device **devs = NULL; 475 476 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 477 if (!devs || devs[0]->enabled == FALSE) 478 return FALSE; 479 return TRUE; 480} 481 482int 483diskPartitionEditor(dialogMenuItem *self) 484{ 485 DMenu *menu; 486 Device **devs; 487 int i, cnt; 488 char *cp; 489 490 cp = variable_get(VAR_DISK); 491 devs = deviceFind(cp, DEVICE_TYPE_DISK); 492 cnt = deviceCount(devs); 493 if (!cnt) { 494 msgConfirm("No disks found! Please verify that your disk controller is being\n" 495 "properly probed at boot time. See the Hardware Guide on the\n" 496 "Documentation menu for clues on diagnosing this type of problem."); 497 i = DITEM_FAILURE; 498 } 499 else if (cnt == 1) { 500 devs[0]->enabled = TRUE; 501 if (variable_get(VAR_NONINTERACTIVE)) 502 diskPartitionNonInteractive(devs[0], (Disk *)devs[0]->private); 503 else 504 diskPartition(devs[0], (Disk *)devs[0]->private); 505 i = DITEM_SUCCESS; 506 } 507 else { 508 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 509 if (!menu) { 510 msgConfirm("No devices suitable for installation found!\n\n" 511 "Please verify that your disk controller (and attached drives)\n" 512 "were detected properly. This can be done by pressing the\n" 513 "[Scroll Lock] key and using the Arrow keys to move back to\n" 514 "the boot messages. Press [Scroll Lock] again to return."); 515 i = DITEM_FAILURE; 516 } 517 else { 518 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 519 free(menu); 520 } 521 i = i | DITEM_RESTORE; 522 } 523 return i; 524} 525 526int 527diskPartitionWrite(dialogMenuItem *self) 528{ 529 Device **devs; 530 char *cp; 531 int i; 532 533 if ((cp = variable_get(DISK_PARTITIONED)) && strcmp(cp, "yes")) 534 return DITEM_SUCCESS; 535 else if (!cp) { 536 msgConfirm("You must partition the disk(s) before this option can be used."); 537 return DITEM_FAILURE; 538 } 539 540 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 541 if (!devs) { 542 msgConfirm("Unable to find any disks to write to??"); 543 return DITEM_FAILURE; 544 } 545 if (isDebug()) 546 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 547 548 for (i = 0; devs[i]; i++) { 549 Chunk *c1; 550 Disk *d = (Disk *)devs[i]->private; 551 552 if (!devs[i]->enabled) 553 continue; 554 555 Set_Boot_Blocks(d, boot1, boot2); 556 msgNotify("Writing partition information to drive %s", d->name); 557 if (!Fake && Write_Disk(d)) { 558 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 559 return DITEM_FAILURE; 560 } 561 /* Now scan for bad blocks, if necessary */ 562 for (c1 = d->chunks->part; c1; c1 = c1->next) { 563 if (c1->flags & CHUNK_BAD144) { 564 int ret; 565 566 msgNotify("Running bad block scan on slice %s", c1->name); 567 if (!Fake) { 568 ret = vsystem("bad144 -v /dev/r%s 1234", c1->name); 569 if (ret) 570 msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret); 571 ret = vsystem("bad144 -v -s /dev/r%s", c1->name); 572 if (ret) 573 msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret); 574 } 575 } 576 } 577 } 578 /* Now it's not "yes", but "written" */ 579 variable_set2(DISK_PARTITIONED, "written"); 580 return DITEM_SUCCESS; 581} 582 583/* Partition a disk based wholly on which variables are set */ 584static void 585diskPartitionNonInteractive(Device *dev, Disk *d) 586{ 587 char *cp; 588 int i, sz, all_disk = 0; 589 u_char *mbrContents; 590 591 record_chunks(d); 592 cp = variable_get(VAR_GEOMETRY); 593 if (cp) { 594 msgDebug("Setting geometry from script to: %s\n", cp); 595 d->bios_cyl = strtol(cp, &cp, 0); 596 d->bios_hd = strtol(cp + 1, &cp, 0); 597 d->bios_sect = strtol(cp + 1, 0, 0); 598 } 599 600 cp = variable_get(VAR_PARTITION); 601 if (cp) { 602 if (!strcmp(cp, "free")) { 603 /* Do free disk space case */ 604 for (i = 0; chunk_info[i]; i++) { 605 /* If a chunk is at least 10MB in size, use it. */ 606 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 607 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, 608 (chunk_info[i]->flags & CHUNK_ALIGN)); 609 variable_set2(DISK_PARTITIONED, "yes"); 610 break; 611 } 612 } 613 if (!chunk_info[i]) { 614 dialog_clear(); 615 msgConfirm("Unable to find any free space on this disk!"); 616 return; 617 } 618 } 619 else if (!strcmp(cp, "all")) { 620 /* Do all disk space case */ 621 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 622 623 All_FreeBSD(d, FALSE); 624 } 625 else if (!strcmp(cp, "exclusive")) { 626 /* Do really-all-the-disk-space case */ 627 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 628 629 All_FreeBSD(d, all_disk = TRUE); 630 } 631 else if ((sz = strtol(cp, &cp, 0))) { 632 /* Look for sz bytes free */ 633 if (*cp && toupper(*cp) == 'M') 634 sz *= ONE_MEG; 635 for (i = 0; chunk_info[i]; i++) { 636 /* If a chunk is at least sz MB, use it. */ 637 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 638 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); 639 variable_set2(DISK_PARTITIONED, "yes"); 640 break; 641 } 642 } 643 if (!chunk_info[i]) { 644 dialog_clear(); 645 msgConfirm("Unable to find %d free blocks on this disk!", sz); 646 return; 647 } 648 } 649 else if (!strcmp(cp, "existing")) { 650 /* Do existing FreeBSD case */ 651 for (i = 0; chunk_info[i]; i++) { 652 if (chunk_info[i]->type == freebsd) 653 break; 654 } 655 if (!chunk_info[i]) { 656 dialog_clear(); 657 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 658 return; 659 } 660 } 661 else { 662 dialog_clear(); 663 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 664 return; 665 } 666 if (!all_disk) { 667 mbrContents = getBootMgr(d->name); 668 Set_Boot_Mgr(d, mbrContents); 669 } 670 variable_set2(DISK_PARTITIONED, "yes"); 671 } 672} 673