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