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