label.c revision 15419
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: label.c,v 1.44 1996/04/25 17:31:21 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#include <sys/param.h> 41#include <sys/sysctl.h> 42 43/* 44 * Everything to do with editing the contents of disk labels. 45 */ 46 47/* A nice message we use a lot in the disklabel editor */ 48#define MSG_NOT_APPLICABLE "That option is not applicable here" 49 50/* Where to start printing the freebsd slices */ 51#define CHUNK_SLICE_START_ROW 2 52#define CHUNK_PART_START_ROW 11 53 54/* The smallest filesystem we're willing to create */ 55#define FS_MIN_SIZE ONE_MEG 56 57/* The smallest root filesystem we're willing to create */ 58#define ROOT_MIN_SIZE 20 59 60/* The smallest swap partition we want to create by default */ 61#define SWAP_MIN_SIZE 16 62 63/* The smallest /usr partition we're willing to create by default */ 64#define USR_MIN_SIZE 80 65 66/* The smallest /var partition we're willing to create by default */ 67#define VAR_MIN_SIZE 30 68 69/* All the chunks currently displayed on the screen */ 70static struct { 71 struct chunk *c; 72 PartType type; 73} label_chunk_info[MAX_CHUNKS + 1]; 74static int here; 75 76static int diskLabel(char *str); 77 78int 79diskLabelEditor(dialogMenuItem *self) 80{ 81 Device **devs; 82 int i, cnt, enabled; 83 char *cp; 84 85 cp = variable_get(VAR_DISK); 86 devs = deviceFind(cp, DEVICE_TYPE_DISK); 87 cnt = deviceCount(devs); 88 if (!cnt) { 89 msgConfirm("No disks found! Please verify that your disk controller is being\n" 90 "properly probed at boot time. See the Hardware Guide on the\n" 91 "Documentation menu for clues on diagnosing this type of problem."); 92 return DITEM_FAILURE; 93 } 94 for (i = 0, enabled = 0; i < cnt; i++) { 95 if (devs[i]->enabled) 96 ++enabled; 97 } 98 if (!enabled) { 99 devs[0]->enabled = TRUE; 100 if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE) 101 return DITEM_FAILURE; 102 } 103 i = diskLabel(devs[0]->name); 104 if (DITEM_STATUS(i) != DITEM_FAILURE) 105 variable_set2(DISK_LABELLED, "yes"); 106 return i; 107} 108 109int 110diskLabelCommit(dialogMenuItem *self) 111{ 112 char *cp; 113 int i; 114 115 /* Already done? */ 116 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) { 117 variable_set2(DISK_PARTITIONED, "yes"); 118 i = DITEM_SUCCESS; 119 } 120 else if (!cp) { 121 msgConfirm("You must assign disk labels before this option can be used."); 122 i = DITEM_FAILURE; 123 } 124 /* The routine will guard against redundant writes, just as this one does */ 125 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 126 i = DITEM_FAILURE; 127 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 128 i = DITEM_FAILURE; 129 else { 130 msgInfo("All filesystem information written successfully."); 131 variable_set2(DISK_LABELLED, "written"); 132 i = DITEM_SUCCESS; 133 } 134 return i; 135} 136 137/* See if we're already using a desired partition name */ 138static Boolean 139check_conflict(char *name) 140{ 141 int i; 142 143 for (i = 0; label_chunk_info[i].c; i++) 144 if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private_data 145 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 146 return TRUE; 147 return FALSE; 148} 149 150/* How much space is in this FreeBSD slice? */ 151static int 152space_free(struct chunk *c) 153{ 154 struct chunk *c1; 155 int sz = c->size; 156 157 for (c1 = c->part; c1; c1 = c1->next) { 158 if (c1->type != unused) 159 sz -= c1->size; 160 } 161 if (sz < 0) 162 msgFatal("Partitions are larger than actual chunk??"); 163 return sz; 164} 165 166/* Snapshot the current situation into the displayed chunks structure */ 167static void 168record_label_chunks(Device **devs) 169{ 170 int i, j, p; 171 struct chunk *c1, *c2; 172 Disk *d; 173 174 j = p = 0; 175 /* First buzz through and pick up the FreeBSD slices */ 176 for (i = 0; devs[i]; i++) { 177 if (!devs[i]->enabled) 178 continue; 179 d = (Disk *)devs[i]->private; 180 if (!d->chunks) 181 msgFatal("No chunk list found for %s!", d->name); 182 183 /* Put the slice entries first */ 184 for (c1 = d->chunks->part; c1; c1 = c1->next) { 185 if (c1->type == freebsd) { 186 label_chunk_info[j].type = PART_SLICE; 187 label_chunk_info[j].c = c1; 188 ++j; 189 } 190 } 191 } 192 193 /* Now run through again and get the FreeBSD partition entries */ 194 for (i = 0; devs[i]; i++) { 195 if (!devs[i]->enabled) 196 continue; 197 d = (Disk *)devs[i]->private; 198 /* Then buzz through and pick up the partitions */ 199 for (c1 = d->chunks->part; c1; c1 = c1->next) { 200 if (c1->type == freebsd) { 201 for (c2 = c1->part; c2; c2 = c2->next) { 202 if (c2->type == part) { 203 if (c2->subtype == FS_SWAP) 204 label_chunk_info[j].type = PART_SWAP; 205 else 206 label_chunk_info[j].type = PART_FILESYSTEM; 207 label_chunk_info[j].c = c2; 208 ++j; 209 } 210 } 211 } 212 else if (c1->type == fat) { 213 label_chunk_info[j].type = PART_FAT; 214 label_chunk_info[j].c = c1; 215 ++j; 216 } 217 } 218 } 219 label_chunk_info[j].c = NULL; 220 if (here >= j) 221 here = j ? j - 1 : 0; 222} 223 224/* A new partition entry */ 225static PartInfo * 226new_part(char *mpoint, Boolean newfs, u_long size) 227{ 228 PartInfo *ret; 229 u_long target, divisor; 230 231 if (!mpoint) 232 mpoint = "/change_me"; 233 234 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 235 strncpy(ret->mountpoint, mpoint, FILENAME_MAX); 236 strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 237 ret->newfs = newfs; 238 if (!size) 239 return ret; 240 for (target = size; target; target--) { 241 for (divisor = 4096 ; divisor > 1023; divisor--) { 242 if (!(target % divisor)) { 243 sprintf(ret->newfs_cmd + strlen(ret->newfs_cmd), " -u %ld",divisor); 244 return ret; 245 } 246 } 247 } 248 return ret; 249} 250 251/* Get the mountpoint for a partition and save it away */ 252static PartInfo * 253get_mountpoint(struct chunk *old) 254{ 255 char *val; 256 PartInfo *tmp; 257 258 if (old && old->private_data) 259 tmp = old->private_data; 260 else 261 tmp = NULL; 262 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 263 if (!val || !*val) { 264 if (!old) 265 return NULL; 266 else { 267 free(old->private_data); 268 old->private_data = NULL; 269 } 270 return NULL; 271 } 272 273 /* Is it just the same value? */ 274 if (tmp && !strcmp(tmp->mountpoint, val)) 275 return NULL; 276 277 /* Did we use it already? */ 278 if (check_conflict(val)) { 279 msgConfirm("You already have a mount point for %s assigned!", val); 280 return NULL; 281 } 282 283 /* Is it bogus? */ 284 if (*val != '/') { 285 msgConfirm("Mount point must start with a / character"); 286 return NULL; 287 } 288 289 /* Is it going to be mounted on root? */ 290 if (!strcmp(val, "/")) { 291 if (old) 292 old->flags |= CHUNK_IS_ROOT; 293 } 294 else if (old) 295 old->flags &= ~CHUNK_IS_ROOT; 296 297 safe_free(tmp); 298 tmp = new_part(val, TRUE, 0); 299 if (old) { 300 old->private_data = tmp; 301 old->private_free = safe_free; 302 } 303 return tmp; 304} 305 306/* Get the type of the new partiton */ 307static PartType 308get_partition_type(void) 309{ 310 char selection[20]; 311 int i; 312 313 static unsigned char *fs_types[] = { 314 "FS", 315 "A file system", 316 "Swap", 317 "A swap partition.", 318 }; 319 i = dialog_menu("Please choose a partition type", 320 "If you want to use this partition for swap space, select Swap.\n" 321 "If you want to put a filesystem on it, choose FS.", 322 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 323 if (!i) { 324 if (!strcmp(selection, "FS")) 325 return PART_FILESYSTEM; 326 else if (!strcmp(selection, "Swap")) 327 return PART_SWAP; 328 } 329 return PART_NONE; 330} 331 332/* If the user wants a special newfs command for this, set it */ 333static void 334getNewfsCmd(PartInfo *p) 335{ 336 char *val; 337 338 val = msgGetInput(p->newfs_cmd, 339 "Please enter the newfs command and options you'd like to use in\n" 340 "creating this file system."); 341 if (val) 342 strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 343} 344 345#define MAX_MOUNT_NAME 12 346 347#define PART_PART_COL 0 348#define PART_MOUNT_COL 8 349#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 350#define PART_NEWFS_COL (PART_SIZE_COL + 7) 351#define PART_OFF 38 352 353/* How many mounted partitions to display in column before going to next */ 354#define CHUNK_COLUMN_MAX 5 355 356/* stick this all up on the screen */ 357static void 358print_label_chunks(void) 359{ 360 int i, j, srow, prow, pcol; 361 int sz; 362 363 attrset(A_REVERSE); 364 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 365 clrtobot(); 366 attrset(A_NORMAL); 367 368 for (i = 0; i < 2; i++) { 369 mvaddstr(CHUNK_PART_START_ROW - 2, PART_PART_COL + (i * PART_OFF), "Part"); 370 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), "----"); 371 372 mvaddstr(CHUNK_PART_START_ROW - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 373 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 374 375 mvaddstr(CHUNK_PART_START_ROW - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 376 mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 377 378 mvaddstr(CHUNK_PART_START_ROW - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 379 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 380 } 381 srow = CHUNK_SLICE_START_ROW; 382 prow = CHUNK_PART_START_ROW; 383 pcol = 0; 384 385 for (i = 0; label_chunk_info[i].c; i++) { 386 if (i == here) 387 attrset(A_REVERSE); 388 /* Is it a slice entry displayed at the top? */ 389 if (label_chunk_info[i].type == PART_SLICE) { 390 sz = space_free(label_chunk_info[i].c); 391 mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 392 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); 393 } 394 /* Otherwise it's a DOS, swap or filesystem entry, at the bottom */ 395 else { 396 char onestr[PART_OFF], num[10], *mountpoint, *newfs; 397 398 /* 399 * We copy this into a blank-padded string so that it looks like 400 * a solid bar in reverse-video 401 */ 402 memset(onestr, ' ', PART_OFF - 1); 403 onestr[PART_OFF - 1] = '\0'; 404 /* Go for two columns */ 405 if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) { 406 pcol = PART_OFF; 407 prow = CHUNK_PART_START_ROW; 408 } 409 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 410 /* If it's a filesystem, display the mountpoint */ 411 if (label_chunk_info[i].c->private_data 412 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 413 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 414 else 415 mountpoint = "<none>"; 416 417 /* Now display the newfs field */ 418 if (label_chunk_info[i].type == PART_FAT) 419 newfs = "DOS"; 420 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 421 newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 422 else if (label_chunk_info[i].type == PART_SWAP) 423 newfs = "SWAP"; 424 else 425 newfs = "*"; 426 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 427 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 428 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 429 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 430 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 431 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 432 mvaddstr(prow, pcol, onestr); 433 ++prow; 434 } 435 if (i == here) 436 attrset(A_NORMAL); 437 } 438} 439 440static void 441print_command_summary() 442{ 443 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 444 mvprintw(18, 0, "C = Create D = Delete M = Mount W = Write"); 445 mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 446 mvprintw(20, 0, "A = Auto Defaults for all!"); 447 mvprintw(22, 0, "The default target will be displayed in "); 448 449 attrset(A_REVERSE); 450 addstr("reverse"); 451 attrset(A_NORMAL); 452 addstr(" video."); 453 mvprintw(23, 0, "Use F1 or ? to get more help, arrow keys to move."); 454 move(0, 0); 455} 456 457static int 458diskLabel(char *str) 459{ 460 int sz, key = 0; 461 Boolean labeling; 462 char *msg = NULL; 463 PartInfo *p, *oldp; 464 PartType type; 465 Device **devs; 466 WINDOW *w; 467 468 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 469 if (!devs) { 470 msgConfirm("No disks found!"); 471 return DITEM_FAILURE; 472 } 473 474 labeling = TRUE; 475 keypad(stdscr, TRUE); 476 record_label_chunks(devs); 477 478 w = savescr(); 479 dialog_clear(); clear(); 480 while (labeling) { 481 clear(); 482 print_label_chunks(); 483 print_command_summary(); 484 if (msg) { 485 attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL); 486 clrtoeol(); 487 beep(); 488 msg = NULL; 489 } 490 refresh(); 491 key = toupper(getch()); 492 switch (key) { 493 int i, cnt; 494 495 case '\014': /* ^L */ 496 continue; 497 498 case KEY_UP: 499 case '-': 500 if (here != 0) 501 --here; 502 else 503 while (label_chunk_info[here + 1].c) 504 ++here; 505 break; 506 507 case KEY_DOWN: 508 case '+': 509 case '\r': 510 case '\n': 511 if (label_chunk_info[here + 1].c) 512 ++here; 513 else 514 here = 0; 515 break; 516 517 case KEY_HOME: 518 here = 0; 519 break; 520 521 case KEY_END: 522 while (label_chunk_info[here + 1].c) 523 ++here; 524 break; 525 526 case KEY_F(1): 527 case '?': 528 systemDisplayHelp("partition"); 529 break; 530 531 case 'A': 532 if (label_chunk_info[here].type != PART_SLICE) { 533 msg = "You can only do this in a master partition (see top of screen)"; 534 break; 535 } 536 537 cnt = i = 0; 538 while (label_chunk_info[i].c) 539 if (label_chunk_info[i++].type != PART_SLICE) 540 cnt++; 541 if (cnt == (CHUNK_COLUMN_MAX * 2) + 4) { 542 msgConfirm("Sorry, I can't fit any more partitions on the screen! You can get around\n" 543 "this limitation by partitioning your disks individually rather than all\n" 544 "at once. This will be fixed just as soon as we get a scrolling partition\n" 545 "box written. Sorry for the inconvenience!"); 546 break; 547 } 548 549 sz = space_free(label_chunk_info[here].c); 550 if (sz <= FS_MIN_SIZE) { 551 msg = "Not enough space to create an additional FreeBSD partition"; 552 break; 553 } 554 { 555 struct chunk *tmp; 556 int mib[2]; 557 int physmem; 558 size_t size, swsize; 559 char *cp; 560 561 cp = variable_get(VAR_ROOT_SIZE); 562 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 563 label_chunk_info[here].c, 564 (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, 565 CHUNK_IS_ROOT); 566 567 if (!tmp) { 568 msgConfirm("Unable to create the root partition. Too big?"); 569 break; 570 } 571 tmp->private_data = new_part("/", TRUE, tmp->size); 572 tmp->private_free = safe_free; 573 record_label_chunks(devs); 574 575 cp = variable_get(VAR_SWAP_SIZE); 576 if (cp) 577 swsize = atoi(cp) * ONE_MEG; 578 else { 579 mib[0] = CTL_HW; 580 mib[1] = HW_PHYSMEM; 581 size = sizeof physmem; 582 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 583 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 584 } 585 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 586 label_chunk_info[here].c, 587 swsize, 588 part, FS_SWAP, 0); 589 if (!tmp) { 590 msgConfirm("Unable to create the swap partition. Too big?"); 591 break; 592 } 593 594 tmp->private_data = 0; 595 tmp->private_free = safe_free; 596 record_label_chunks(devs); 597 598 cp = variable_get(VAR_VAR_SIZE); 599 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 600 label_chunk_info[here].c, 601 (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 602 if (!tmp) { 603 msgConfirm("Less than %dMB free for /var - you will need to\n" 604 "partition your disk manually with a custom install!", (cp ? atoi(cp) : VAR_MIN_SIZE)); 605 break; 606 } 607 tmp->private_data = new_part("/var", TRUE, tmp->size); 608 tmp->private_free = safe_free; 609 record_label_chunks(devs); 610 611 cp = variable_get(VAR_USR_SIZE); 612 if (cp) 613 sz = atoi(cp) * ONE_MEG; 614 else 615 sz = space_free(label_chunk_info[here].c); 616 if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) { 617 msgConfirm("Less than %dMB free for /usr - you will need to\n" 618 "partition your disk manually with a custom install!", USR_MIN_SIZE); 619 break; 620 } 621 622 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 623 label_chunk_info[here].c, 624 sz, part, FS_BSDFFS, 0); 625 if (!tmp) { 626 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 627 "You will need to partition your disk manually with a custom install!"); 628 break; 629 } 630 /* At this point, we're reasonably "labelled" */ 631 variable_set2(DISK_LABELLED, "yes"); 632 tmp->private_data = new_part("/usr", TRUE, tmp->size); 633 tmp->private_free = safe_free; 634 record_label_chunks(devs); 635 } 636 break; 637 638 case 'C': 639 if (label_chunk_info[here].type != PART_SLICE) { 640 msg = "You can only do this in a master partition (see top of screen)"; 641 break; 642 } 643 else { 644 int i, cnt; 645 646 cnt = i = 0; 647 while (label_chunk_info[i].c) 648 if (label_chunk_info[i++].type != PART_SLICE) 649 cnt++; 650 if (cnt == (CHUNK_COLUMN_MAX * 2)) { 651 msgConfirm("Sorry, I can't fit any more partitions on the screen! You can get around\n" 652 "this limitation by partitioning your disks individually rather than all\n" 653 "at once. This will be fixed just as soon as we get a scrolling partition\n" 654 "box written. Sorry for the inconvenience!"); 655 break; 656 } 657 } 658 sz = space_free(label_chunk_info[here].c); 659 if (sz <= FS_MIN_SIZE) { 660 msg = "Not enough space to create an additional FreeBSD partition"; 661 break; 662 } 663 { 664 char *val, *cp; 665 int size; 666 struct chunk *tmp; 667 char osize[80]; 668 u_long flags = 0; 669 670 sprintf(osize, "%d", sz); 671 val = msgGetInput(osize, "Please specify the size for new FreeBSD partition in blocks, or\n" 672 "append a trailing `M' for megabytes (e.g. 20M) or `C' for cylinders.\n\n" 673 "Space free is %d blocks (%dMB)", sz, sz / ONE_MEG); 674 if (!val || (size = strtol(val, &cp, 0)) <= 0) 675 break; 676 677 if (*cp) { 678 if (toupper(*cp) == 'M') 679 size *= ONE_MEG; 680 else if (toupper(*cp) == 'C') 681 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 682 } 683 if (size <= FS_MIN_SIZE) { 684 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 685 break; 686 } 687 type = get_partition_type(); 688 if (type == PART_NONE) 689 break; 690 691 if (type == PART_FILESYSTEM) { 692 if ((p = get_mountpoint(NULL)) == NULL) 693 break; 694 else if (!strcmp(p->mountpoint, "/")) 695 flags |= CHUNK_IS_ROOT; 696 else 697 flags &= ~CHUNK_IS_ROOT; 698 } else 699 p = NULL; 700 701 if ((flags & CHUNK_IS_ROOT)) { 702 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 703 msgConfirm("This region cannot be used for your root partition as the\n" 704 "FreeBSD boot code cannot deal with a root partition created\n" 705 "in that location. Please choose another location or smaller\n" 706 "size for your root partition and try again!"); 707 break; 708 } 709 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 710 msgConfirm("Warning: This is smaller than the recommended size for a\n" 711 "root partition. For a variety of reasons, root\n" 712 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 713 } 714 } 715 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 716 label_chunk_info[here].c, 717 size, part, 718 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 719 flags); 720 if (!tmp) { 721 msgConfirm("Unable to create the partition. Too big?"); 722 break; 723 } 724 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 725 msgConfirm("This region cannot be used for your root partition as it starts\n" 726 "or extends past the 1024'th cylinder mark and is thus a\n" 727 "poor location to boot from. Please choose another\n" 728 "location (or smaller size) for your root partition and try again!"); 729 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 730 break; 731 } 732 if (type != PART_SWAP) { 733 /* This is needed to tell the newfs -u about the size */ 734 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 735 tmp->private_free = safe_free; 736 safe_free(p); 737 } 738 else 739 tmp->private_data = p; 740 tmp->private_free = safe_free; 741 variable_set2(DISK_LABELLED, "yes"); 742 record_label_chunks(devs); 743 } 744 break; 745 746 case '\177': 747 case 'D': /* delete */ 748 if (label_chunk_info[here].type == PART_SLICE) { 749 msg = MSG_NOT_APPLICABLE; 750 break; 751 } 752 else if (label_chunk_info[here].type == PART_FAT) { 753 msg = "Use the Disk Partition Editor to delete DOS partitions"; 754 break; 755 } 756 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 757 variable_set2(DISK_LABELLED, "yes"); 758 record_label_chunks(devs); 759 break; 760 761 case 'M': /* mount */ 762 switch(label_chunk_info[here].type) { 763 case PART_SLICE: 764 msg = MSG_NOT_APPLICABLE; 765 break; 766 767 case PART_SWAP: 768 msg = "You don't need to specify a mountpoint for a swap partition."; 769 break; 770 771 case PART_FAT: 772 case PART_FILESYSTEM: 773 oldp = label_chunk_info[here].c->private_data; 774 p = get_mountpoint(label_chunk_info[here].c); 775 if (p) { 776 if (!oldp) 777 p->newfs = FALSE; 778 if (label_chunk_info[here].type == PART_FAT 779 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 780 || !strcmp(p->mountpoint, "/var"))) { 781 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 782 strcpy(p->mountpoint, "/bogus"); 783 } 784 } 785 variable_set2(DISK_LABELLED, "yes"); 786 record_label_chunks(devs); 787 break; 788 789 default: 790 msgFatal("Bogus partition under cursor???"); 791 break; 792 } 793 break; 794 795 case 'N': /* Set newfs options */ 796 if (label_chunk_info[here].c->private_data && 797 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 798 getNewfsCmd(label_chunk_info[here].c->private_data); 799 else 800 msg = MSG_NOT_APPLICABLE; 801 break; 802 803 case 'T': /* Toggle newfs state */ 804 if (label_chunk_info[here].type == PART_FILESYSTEM) { 805 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 806 label_chunk_info[here].c->private_data = 807 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 808 safe_free(pi); 809 label_chunk_info[here].c->private_free = safe_free; 810 variable_set2(DISK_LABELLED, "yes"); 811 } 812 else 813 msg = MSG_NOT_APPLICABLE; 814 break; 815 816 case 'U': 817 clear(); 818 if (msgYesNo("Are you SURE you want to Undo everything?")) 819 break; 820 variable_unset(DISK_PARTITIONED); 821 for (i = 0; devs[i]; i++) { 822 Disk *d; 823 824 if (!devs[i]->enabled) 825 continue; 826 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 827 Free_Disk(devs[i]->private); 828 devs[i]->private = d; 829 diskPartition(devs[i], d); 830 } 831 } 832 variable_unset(DISK_LABELLED); 833 record_label_chunks(devs); 834 break; 835 836 case 'W': 837 if (!msgYesNo("You also have the option of doing this later in one final 'commit'\n" 838 "operation, and it should also be noted that this option is NOT for\n" 839 "use during new installations but rather for modifying existing ones.\n\n" 840 "Are you absolutely SURE you want to do this now?")) { 841 variable_set2(DISK_LABELLED, "yes"); 842 clear(); 843 diskLabelCommit(NULL); 844 } 845 break; 846 847 case '|': 848 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 849 "This is an entirely undocumented feature which you are not\n" 850 "expected to understand!")) { 851 int i; 852 Device **devs; 853 854 dialog_clear(); 855 end_dialog(); 856 DialogActive = FALSE; 857 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 858 if (!devs) { 859 msgConfirm("Can't find any disk devices!"); 860 break; 861 } 862 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 863 if (devs[i]->enabled) 864 slice_wizard(((Disk *)devs[i]->private)); 865 } 866 variable_set2(DISK_LABELLED, "yes"); 867 DialogActive = TRUE; 868 dialog_clear(); 869 record_label_chunks(devs); 870 } 871 else 872 msg = "A most prudent choice!"; 873 break; 874 875 case 'Q': 876 labeling = FALSE; 877 break; 878 879 default: 880 beep(); 881 msg = "Type F1 or ? for help"; 882 break; 883 } 884 } 885 restorescr(w); 886 return DITEM_SUCCESS; 887} 888