disks.c revision 29072
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.88 1997/06/18 05:11:36 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)?"); 259 if (rv == -1) 260 rv = 0; 261 } 262 All_FreeBSD(d, rv); 263 variable_set2(DISK_PARTITIONED, "yes"); 264 record_chunks(d); 265 clear(); 266 break; 267 268 case 'B': 269 if (chunk_info[current_chunk]->type != freebsd) 270 msg = "Can only scan for bad blocks in FreeBSD slice."; 271 else if (strncmp(d->name, "sd", 2) || 272 !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n" 273 "Are you sure you want to do this on a SCSI disk?")) { 274 if (chunk_info[current_chunk]->flags & CHUNK_BAD144) 275 chunk_info[current_chunk]->flags &= ~CHUNK_BAD144; 276 else 277 chunk_info[current_chunk]->flags |= CHUNK_BAD144; 278 } 279 clear(); 280 break; 281 282 case 'C': 283 if (chunk_info[current_chunk]->type != unused) 284 msg = "Slice in use, delete it first or move to an unused one."; 285 else { 286 char *val, tmp[20], *cp; 287 int size, subtype; 288 chunk_e partitiontype; 289 290 snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size); 291 val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" 292 "or append a trailing `M' for megabytes (e.g. 20M)."); 293 if (val && (size = strtol(val, &cp, 0)) > 0) { 294 if (*cp && toupper(*cp) == 'M') 295 size *= ONE_MEG; 296 strcpy(tmp, "165"); 297 val = msgGetInput(tmp, "Enter type of partition to create:\n\n" 298 "Pressing Enter will choose the default, a native FreeBSD\n" 299 "slice (type 165). You can choose other types, 6 for a\n" 300 "DOS partition or 131 for a Linux partition, for example.\n\n" 301 "Note: If you choose a non-FreeBSD partition type, it will not\n" 302 "be formatted or otherwise prepared, it will simply reserve space\n" 303 "for you to use another tool, such as DOS FORMAT, to later format\n" 304 "and use the partition."); 305 if (val && (subtype = strtol(val, NULL, 0)) > 0) { 306 if (subtype==165) 307 partitiontype=freebsd; 308 else if (subtype==6) 309 partitiontype=fat; 310 else 311 partitiontype=unknown; 312 Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, 313 (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); 314 variable_set2(DISK_PARTITIONED, "yes"); 315 record_chunks(d); 316 } 317 } 318 clear(); 319 } 320 break; 321 322 case KEY_DC: 323 case 'D': 324 if (chunk_info[current_chunk]->type == unused) 325 msg = "Slice is already unused!"; 326 else { 327 Delete_Chunk(d, chunk_info[current_chunk]); 328 variable_set2(DISK_PARTITIONED, "yes"); 329 record_chunks(d); 330 } 331 break; 332 333 case 'G': 334 snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); 335 val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" 336 "Don't forget to use the two slash (/) separator characters!\n" 337 "It's not possible to parse the field without them."); 338 if (val) { 339 long nc, nh, ns; 340 nc = strtol(val, &val, 0); 341 nh = strtol(val + 1, &val, 0); 342 ns = strtol(val + 1, 0, 0); 343 Set_Bios_Geom(d, nc, nh, ns); 344 } 345 clear(); 346 break; 347 348 case 'S': 349 /* Set Bootable */ 350 chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; 351 break; 352 353 case 'U': 354 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 355 msgConfirm("You've already written this information out - you\n" 356 "can't undo it."); 357 } 358 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 359 char cp[BUFSIZ]; 360 361 sstrncpy(cp, d->name, sizeof cp); 362 Free_Disk(dev->private); 363 d = Open_Disk(cp); 364 if (!d) 365 msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); 366 dev->private = d; 367 variable_unset(DISK_PARTITIONED); 368 variable_unset(DISK_LABELLED); 369 if (d) 370 record_chunks(d); 371 } 372 clear(); 373 break; 374 375 case 'W': 376 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 377 msgConfirm("You've already written this information out - if\n" 378 "you wish to overwrite it, you'll have to restart."); 379 } 380 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 381 "installation. If you are installing FreeBSD for the first time\n" 382 "then you should simply type Q when you're finished here and your\n" 383 "changes will be committed in one batch automatically at the end of\n" 384 "these questions.\n\n" 385 "Are you absolutely sure you want to do this now?")) { 386 variable_set2(DISK_PARTITIONED, "yes"); 387 388 /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated 389 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested 390 * booteasy or a "standard" MBR -- both would be fatal in this case. 391 */ 392 if (!(d->chunks->part->flags & CHUNK_FORCE_ALL) && (mbrContents = getBootMgr(d->name)) != NULL) 393 Set_Boot_Mgr(d, mbrContents); 394 395 if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) 396 msgConfirm("Disk partition write returned an error status!"); 397 else 398 msgConfirm("Wrote FDISK partition information out successfully."); 399 } 400 clear(); 401 break; 402 403 case '|': 404 if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n" 405 "No seat belts whatsoever are provided!")) { 406 clear(); 407 refresh(); 408 slice_wizard(d); 409 variable_set2(DISK_PARTITIONED, "yes"); 410 record_chunks(d); 411 } 412 else 413 msg = "Wise choice!"; 414 clear(); 415 break; 416 417 case '\033': /* ESC */ 418 case 'Q': 419 chunking = FALSE; 420 /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated 421 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested 422 * booteasy or a "standard" MBR -- both would be fatal in this case. 423 */ 424 if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL 425 && (mbrContents = getBootMgr(d->name)) != NULL) 426 Set_Boot_Mgr(d, mbrContents); 427 break; 428 429 default: 430 beep(); 431 msg = "Type F1 or ? for help"; 432 break; 433 } 434 } 435 p = CheckRules(d); 436 if (p) { 437 char buf[FILENAME_MAX]; 438 439 dialog_clear_norefresh(); 440 use_helpline("Press F1 to read more about disk slices."); 441 use_helpfile(systemHelpFile("partition", buf)); 442 if (!variable_get(VAR_NO_WARN)) 443 dialog_mesgbox("Disk slicing warning:", p, -1, -1); 444 free(p); 445 } 446 restorescr(w); 447} 448 449static int 450partitionHook(dialogMenuItem *selected) 451{ 452 Device **devs = NULL; 453 454 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 455 if (!devs) { 456 msgConfirm("Unable to find disk %s!", selected->prompt); 457 return DITEM_FAILURE; 458 } 459 /* Toggle enabled status? */ 460 if (!devs[0]->enabled) { 461 devs[0]->enabled = TRUE; 462 diskPartition(devs[0], (Disk *)devs[0]->private); 463 } 464 else 465 devs[0]->enabled = FALSE; 466 return DITEM_SUCCESS | DITEM_REDRAW; 467} 468 469static int 470partitionCheck(dialogMenuItem *selected) 471{ 472 Device **devs = NULL; 473 474 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 475 if (!devs || devs[0]->enabled == FALSE) 476 return FALSE; 477 return TRUE; 478} 479 480int 481diskPartitionEditor(dialogMenuItem *self) 482{ 483 DMenu *menu; 484 Device **devs; 485 int i, cnt; 486 char *cp; 487 488 cp = variable_get(VAR_DISK); 489 devs = deviceFind(cp, DEVICE_TYPE_DISK); 490 cnt = deviceCount(devs); 491 if (!cnt) { 492 msgConfirm("No disks found! Please verify that your disk controller is being\n" 493 "properly probed at boot time. See the Hardware Guide on the\n" 494 "Documentation menu for clues on diagnosing this type of problem."); 495 i = DITEM_FAILURE; 496 } 497 else if (cnt == 1) { 498 devs[0]->enabled = TRUE; 499 if (variable_get(VAR_NONINTERACTIVE)) 500 diskPartitionNonInteractive(devs[0], (Disk *)devs[0]->private); 501 else 502 diskPartition(devs[0], (Disk *)devs[0]->private); 503 i = DITEM_SUCCESS; 504 } 505 else { 506 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); 507 if (!menu) { 508 msgConfirm("No devices suitable for installation found!\n\n" 509 "Please verify that your disk controller (and attached drives)\n" 510 "were detected properly. This can be done by pressing the\n" 511 "[Scroll Lock] key and using the Arrow keys to move back to\n" 512 "the boot messages. Press [Scroll Lock] again to return."); 513 i = DITEM_FAILURE; 514 } 515 else { 516 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 517 free(menu); 518 } 519 i = i | DITEM_RESTORE; 520 } 521 return i; 522} 523 524int 525diskPartitionWrite(dialogMenuItem *self) 526{ 527 Device **devs; 528 char *cp; 529 int i; 530 531 if ((cp = variable_get(DISK_PARTITIONED)) && strcmp(cp, "yes")) 532 return DITEM_SUCCESS; 533 else if (!cp) { 534 msgConfirm("You must partition the disk(s) before this option can be used."); 535 return DITEM_FAILURE; 536 } 537 538 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 539 if (!devs) { 540 msgConfirm("Unable to find any disks to write to??"); 541 return DITEM_FAILURE; 542 } 543 if (isDebug()) 544 msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); 545 546 for (i = 0; devs[i]; i++) { 547 Chunk *c1; 548 Disk *d = (Disk *)devs[i]->private; 549 550 if (!devs[i]->enabled) 551 continue; 552 553 Set_Boot_Blocks(d, boot1, boot2); 554 msgNotify("Writing partition information to drive %s", d->name); 555 if (!Fake && Write_Disk(d)) { 556 msgConfirm("ERROR: Unable to write data to disk %s!", d->name); 557 return DITEM_FAILURE; 558 } 559 /* Now scan for bad blocks, if necessary */ 560 for (c1 = d->chunks->part; c1; c1 = c1->next) { 561 if (c1->flags & CHUNK_BAD144) { 562 int ret; 563 564 msgNotify("Running bad block scan on slice %s", c1->name); 565 if (!Fake) { 566 ret = vsystem("bad144 -v /dev/r%s 1234", c1->name); 567 if (ret) 568 msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret); 569 ret = vsystem("bad144 -v -s /dev/r%s", c1->name); 570 if (ret) 571 msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret); 572 } 573 } 574 } 575 } 576 /* Now it's not "yes", but "written" */ 577 variable_set2(DISK_PARTITIONED, "written"); 578 return DITEM_SUCCESS; 579} 580 581/* Partition a disk based wholly on which variables are set */ 582static void 583diskPartitionNonInteractive(Device *dev, Disk *d) 584{ 585 char *cp; 586 int i, sz, all_disk = 0; 587 u_char *mbrContents; 588 589 record_chunks(d); 590 cp = variable_get(VAR_GEOMETRY); 591 if (cp) { 592 msgDebug("Setting geometry from script to: %s\n", cp); 593 d->bios_cyl = strtol(cp, &cp, 0); 594 d->bios_hd = strtol(cp + 1, &cp, 0); 595 d->bios_sect = strtol(cp + 1, 0, 0); 596 } 597 598 cp = variable_get(VAR_PARTITION); 599 if (cp) { 600 if (!strcmp(cp, "free")) { 601 /* Do free disk space case */ 602 for (i = 0; chunk_info[i]; i++) { 603 /* If a chunk is at least 10MB in size, use it. */ 604 if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { 605 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, 606 (chunk_info[i]->flags & CHUNK_ALIGN)); 607 variable_set2(DISK_PARTITIONED, "yes"); 608 break; 609 } 610 } 611 if (!chunk_info[i]) { 612 dialog_clear(); 613 msgConfirm("Unable to find any free space on this disk!"); 614 return; 615 } 616 } 617 else if (!strcmp(cp, "all")) { 618 /* Do all disk space case */ 619 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 620 621 All_FreeBSD(d, FALSE); 622 } 623 else if (!strcmp(cp, "exclusive")) { 624 /* Do really-all-the-disk-space case */ 625 msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); 626 627 All_FreeBSD(d, all_disk = TRUE); 628 } 629 else if ((sz = strtol(cp, &cp, 0))) { 630 /* Look for sz bytes free */ 631 if (*cp && toupper(*cp) == 'M') 632 sz *= ONE_MEG; 633 for (i = 0; chunk_info[i]; i++) { 634 /* If a chunk is at least sz MB, use it. */ 635 if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { 636 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); 637 variable_set2(DISK_PARTITIONED, "yes"); 638 break; 639 } 640 } 641 if (!chunk_info[i]) { 642 dialog_clear(); 643 msgConfirm("Unable to find %d free blocks on this disk!", sz); 644 return; 645 } 646 } 647 else if (!strcmp(cp, "existing")) { 648 /* Do existing FreeBSD case */ 649 for (i = 0; chunk_info[i]; i++) { 650 if (chunk_info[i]->type == freebsd) 651 break; 652 } 653 if (!chunk_info[i]) { 654 dialog_clear(); 655 msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); 656 return; 657 } 658 } 659 else { 660 dialog_clear(); 661 msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); 662 return; 663 } 664 if (!all_disk) { 665 mbrContents = getBootMgr(d->name); 666 Set_Boot_Mgr(d, mbrContents); 667 } 668 variable_set2(DISK_PARTITIONED, "yes"); 669 } 670} 671