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