label.c revision 14335
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.36 1996/03/02 20:00:50 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 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by Jordan Hubbard 25 * for the FreeBSD Project. 26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to 27 * endorse or promote products derived from this software without specific 28 * prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 */ 43 44#include "sysinstall.h" 45#include <ctype.h> 46#include <sys/disklabel.h> 47#include <sys/param.h> 48#include <sys/sysctl.h> 49 50/* 51 * Everything to do with editing the contents of disk labels. 52 */ 53 54/* A nice message we use a lot in the disklabel editor */ 55#define MSG_NOT_APPLICABLE "That option is not applicable here" 56 57/* Where to start printing the freebsd slices */ 58#define CHUNK_SLICE_START_ROW 2 59#define CHUNK_PART_START_ROW 11 60 61/* The smallest filesystem we're willing to create */ 62#define FS_MIN_SIZE ONE_MEG 63 64/* The smallest root filesystem we're willing to create */ 65#define ROOT_MIN_SIZE 20 66 67/* The smallest swap partition we want to create by default */ 68#define SWAP_MIN_SIZE 16 69 70/* The smallest /usr partition we're willing to create by default */ 71#define USR_MIN_SIZE 80 72 73/* The smallest /var partition we're willing to create by default */ 74#define VAR_MIN_SIZE 30 75 76/* All the chunks currently displayed on the screen */ 77static struct { 78 struct chunk *c; 79 PartType type; 80} label_chunk_info[MAX_CHUNKS + 1]; 81static int here; 82 83static int diskLabel(char *str); 84static int scriptLabel(char *str); 85 86static int 87labelHook(char *str) 88{ 89 Device **devs = NULL; 90 91 /* Clip garbage off the ends */ 92 string_prune(str); 93 str = string_skipwhite(str); 94 /* Try and open all the disks */ 95 while (str) { 96 char *cp; 97 98 cp = index(str, '\n'); 99 if (cp) 100 *cp++ = 0; 101 if (!*str) { 102 beep(); 103 return 0; 104 } 105 devs = deviceFind(str, DEVICE_TYPE_DISK); 106 if (!devs) { 107 dialog_clear(); 108 msgConfirm("Unable to find disk %s!", str); 109 return 0; 110 } 111 devs[0]->enabled = TRUE; 112 str = cp; 113 } 114 return devs ? 1 : 0; 115} 116 117int 118diskLabelEditor(char *str) 119{ 120 Device **devs; 121 DMenu *menu; 122 int i, cnt; 123 char *cp; 124 125 cp = variable_get(VAR_DISK); 126 devs = deviceFind(cp, DEVICE_TYPE_DISK); 127 cnt = deviceCount(devs); 128 if (!cnt) { 129 dialog_clear(); 130 msgConfirm("No disks found! Please verify that your disk controller is being\n" 131 "properly probed at boot time. See the Hardware Guide on the\n" 132 "Documentation menu for clues on diagnosing this type of problem."); 133 return RET_FAIL; 134 } 135 else if (cnt == 1 || variable_get(DISK_SELECTED)) { 136 if (cnt == 1) 137 devs[0]->enabled = TRUE; 138 if (str && !strcmp(str, "script")) 139 i = scriptLabel(str); 140 else 141 i = diskLabel(str); 142 } 143 else { 144 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook); 145 if (!menu) { 146 dialog_clear(); 147 msgConfirm("No devices suitable for installation found!\n\n" 148 "Please verify that your disk controller (and attached drives)\n" 149 "were detected properly. This can be done by pressing the\n" 150 "[Scroll Lock] key and using the Arrow keys to move back to\n" 151 "the boot messages. Press [Scroll Lock] again to return."); 152 i = RET_FAIL; 153 } 154 else { 155 if (!dmenuOpenSimple(menu)) 156 i = RET_FAIL; 157 else 158 i = diskLabel(str); 159 free(menu); 160 } 161 } 162 return i; 163} 164 165int 166diskLabelCommit(char *str) 167{ 168 char *cp; 169 int i; 170 171 /* Already done? */ 172 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 173 i = RET_SUCCESS; 174 else if (!cp) { 175 dialog_clear(); 176 msgConfirm("You must assign disk labels before this option can be used."); 177 i = RET_FAIL; 178 } 179 /* The routine will guard against redundant writes, just as this one does */ 180 else if (diskPartitionWrite(str) != RET_SUCCESS) 181 i = RET_FAIL; 182 else if (installFilesystems(str) != RET_SUCCESS) 183 i = RET_FAIL; 184 else { 185 msgInfo("All filesystem information written successfully."); 186 variable_set2(DISK_LABELLED, "written"); 187 i = RET_SUCCESS; 188 } 189 return i; 190} 191 192/* See if we're already using a desired partition name */ 193static Boolean 194check_conflict(char *name) 195{ 196 int i; 197 198 for (i = 0; label_chunk_info[i].c; i++) 199 if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private 200 && !strcmp(((PartInfo *)label_chunk_info[i].c->private)->mountpoint, name)) 201 return TRUE; 202 return FALSE; 203} 204 205/* How much space is in this FreeBSD slice? */ 206static int 207space_free(struct chunk *c) 208{ 209 struct chunk *c1; 210 int sz = c->size; 211 212 for (c1 = c->part; c1; c1 = c1->next) { 213 if (c1->type != unused) 214 sz -= c1->size; 215 } 216 if (sz < 0) 217 msgFatal("Partitions are larger than actual chunk??"); 218 return sz; 219} 220 221/* Snapshot the current situation into the displayed chunks structure */ 222static void 223record_label_chunks(Device **devs) 224{ 225 int i, j, p; 226 struct chunk *c1, *c2; 227 Disk *d; 228 229 j = p = 0; 230 /* First buzz through and pick up the FreeBSD slices */ 231 for (i = 0; devs[i]; i++) { 232 if (!devs[i]->enabled) 233 continue; 234 d = (Disk *)devs[i]->private; 235 if (!d->chunks) 236 msgFatal("No chunk list found for %s!", d->name); 237 238 /* Put the slice entries first */ 239 for (c1 = d->chunks->part; c1; c1 = c1->next) { 240 if (c1->type == freebsd) { 241 label_chunk_info[j].type = PART_SLICE; 242 label_chunk_info[j].c = c1; 243 ++j; 244 } 245 } 246 } 247 248 /* Now run through again and get the FreeBSD partition entries */ 249 for (i = 0; devs[i]; i++) { 250 if (!devs[i]->enabled) 251 continue; 252 d = (Disk *)devs[i]->private; 253 /* Then buzz through and pick up the partitions */ 254 for (c1 = d->chunks->part; c1; c1 = c1->next) { 255 if (c1->type == freebsd) { 256 for (c2 = c1->part; c2; c2 = c2->next) { 257 if (c2->type == part) { 258 if (c2->subtype == FS_SWAP) 259 label_chunk_info[j].type = PART_SWAP; 260 else 261 label_chunk_info[j].type = PART_FILESYSTEM; 262 label_chunk_info[j].c = c2; 263 ++j; 264 } 265 } 266 } 267 else if (c1->type == fat) { 268 label_chunk_info[j].type = PART_FAT; 269 label_chunk_info[j].c = c1; 270 ++j; 271 } 272 } 273 } 274 label_chunk_info[j].c = NULL; 275 if (here >= j) 276 here = j ? j - 1 : 0; 277} 278 279/* A new partition entry */ 280static PartInfo * 281new_part(char *mpoint, Boolean newfs, u_long size) 282{ 283 PartInfo *ret; 284 u_long target, divisor; 285 286 if (!mpoint) 287 mpoint = "/change_me"; 288 289 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 290 strncpy(ret->mountpoint, mpoint, FILENAME_MAX); 291 strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 292 ret->newfs = newfs; 293 if (!size) 294 return ret; 295 for (target = size; target; target--) { 296 for (divisor = 4096 ; divisor > 1023; divisor--) { 297 if (!(target % divisor)) { 298 sprintf(ret->newfs_cmd + strlen(ret->newfs_cmd), " -u %ld",divisor); 299 return ret; 300 } 301 } 302 } 303 return ret; 304} 305 306/* Get the mountpoint for a partition and save it away */ 307static PartInfo * 308get_mountpoint(struct chunk *old) 309{ 310 char *val; 311 PartInfo *tmp; 312 313 if (old && old->private) 314 tmp = old->private; 315 else 316 tmp = NULL; 317 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 318 if (!val || !*val) { 319 if (!old) 320 return NULL; 321 else { 322 free(old->private); 323 old->private = NULL; 324 } 325 return NULL; 326 } 327 328 /* Is it just the same value? */ 329 if (tmp && !strcmp(tmp->mountpoint, val)) 330 return NULL; 331 332 /* Did we use it already? */ 333 if (check_conflict(val)) { 334 msgConfirm("You already have a mount point for %s assigned!", val); 335 return NULL; 336 } 337 338 /* Is it bogus? */ 339 if (*val != '/') { 340 msgConfirm("Mount point must start with a / character"); 341 return NULL; 342 } 343 344 /* Is it going to be mounted on root? */ 345 if (!strcmp(val, "/")) { 346 if (old) 347 old->flags |= CHUNK_IS_ROOT; 348 } 349 else if (old) 350 old->flags &= ~CHUNK_IS_ROOT; 351 352 safe_free(tmp); 353 tmp = new_part(val, TRUE, 0); 354 if (old) { 355 old->private = tmp; 356 old->private_free = safe_free; 357 } 358 return tmp; 359} 360 361/* Get the type of the new partiton */ 362static PartType 363get_partition_type(void) 364{ 365 char selection[20]; 366 int i; 367 368 static unsigned char *fs_types[] = { 369 "FS", 370 "A file system", 371 "Swap", 372 "A swap partition.", 373 }; 374 i = dialog_menu("Please choose a partition type", 375 "If you want to use this partition for swap space, select Swap.\n" 376 "If you want to put a filesystem on it, choose FS.", 377 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 378 if (!i) { 379 if (!strcmp(selection, "FS")) 380 return PART_FILESYSTEM; 381 else if (!strcmp(selection, "Swap")) 382 return PART_SWAP; 383 } 384 return PART_NONE; 385} 386 387/* If the user wants a special newfs command for this, set it */ 388static void 389getNewfsCmd(PartInfo *p) 390{ 391 char *val; 392 393 val = msgGetInput(p->newfs_cmd, 394 "Please enter the newfs command and options you'd like to use in\n" 395 "creating this file system."); 396 if (val) 397 strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 398} 399 400static int 401scriptLabel(char *str) 402{ 403 char *cp; 404 PartType type; 405 PartInfo *p; 406 u_long flags = 0; 407 int i, status; 408 Device **devs; 409 Disk *d; 410 411 status = RET_SUCCESS; 412 cp = variable_get(VAR_DISK); 413 if (!cp) { 414 dialog_clear(); 415 msgConfirm("scriptLabel: No disk selected - can't label automatically."); 416 return RET_FAIL; 417 } 418 419 devs = deviceFind(cp, DEVICE_TYPE_DISK); 420 if (!devs) { 421 dialog_clear(); 422 msgConfirm("scriptLabel: No disk device %s found!", cp); 423 return RET_FAIL; 424 } 425 d = devs[0]->private; 426 427 record_label_chunks(devs); 428 for (i = 0; label_chunk_info[i].c; i++) { 429 Chunk *c1 = label_chunk_info[i].c; 430 431 if (label_chunk_info[i].type == PART_SLICE) { 432 if ((cp = variable_get(c1->name)) != NULL) { 433 int sz; 434 char typ[10], mpoint[50]; 435 436 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 437 dialog_clear(); 438 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 439 status = RET_FAIL; 440 continue; 441 } 442 else { 443 Chunk *tmp; 444 445 if (!strcmp(typ, "swap")) { 446 type = PART_SWAP; 447 strcpy(mpoint, "<swap>"); 448 } 449 else { 450 type = PART_FILESYSTEM; 451 if (!strcmp(mpoint, "/")) 452 flags |= CHUNK_IS_ROOT; 453 } 454 if (!sz) 455 sz = space_free(c1); 456 if (sz > space_free(c1)) { 457 dialog_clear(); 458 msgConfirm("Not enough free space to create partition: %s", mpoint); 459 status = RET_FAIL; 460 continue; 461 } 462 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 463 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 464 dialog_clear(); 465 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 466 status = RET_FAIL; 467 break; 468 } 469 else { 470 tmp->private = new_part(mpoint, TRUE, sz); 471 tmp->private_free = safe_free; 472 status = RET_SUCCESS; 473 } 474 } 475 } 476 } 477 else { 478 /* Must be something we can set a mountpoint */ 479 cp = variable_get(c1->name); 480 if (cp) { 481 char mpoint[50], nwfs[8]; 482 Boolean newfs = FALSE; 483 484 nwfs[0] = '\0'; 485 if (sscanf(cp, "%s %s", mpoint, nwfs) != 2) { 486 dialog_clear(); 487 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 488 status = RET_FAIL; 489 continue; 490 } 491 newfs = toupper(nwfs[0]) == 'Y' ? TRUE : FALSE; 492 if (c1->private) { 493 p = c1->private; 494 p->newfs = newfs; 495 strcpy(p->mountpoint, mpoint); 496 } 497 else { 498 c1->private = new_part(mpoint, newfs, 0); 499 c1->private_free = safe_free; 500 } 501 if (!strcmp(mpoint, "/")) 502 c1->flags |= CHUNK_IS_ROOT; 503 else 504 c1->flags &= ~CHUNK_IS_ROOT; 505 } 506 } 507 } 508 if (status == RET_SUCCESS) 509 variable_set2(DISK_LABELLED, "yes"); 510 return status; 511} 512 513#define MAX_MOUNT_NAME 12 514 515#define PART_PART_COL 0 516#define PART_MOUNT_COL 8 517#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 518#define PART_NEWFS_COL (PART_SIZE_COL + 7) 519#define PART_OFF 38 520 521/* How many mounted partitions to display in column before going to next */ 522#define CHUNK_COLUMN_MAX 5 523 524/* stick this all up on the screen */ 525static void 526print_label_chunks(void) 527{ 528 int i, j, srow, prow, pcol; 529 int sz; 530 531 attrset(A_REVERSE); 532 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 533 clrtobot(); 534 attrset(A_NORMAL); 535 536 for (i = 0; i < 2; i++) { 537 mvaddstr(CHUNK_PART_START_ROW - 2, PART_PART_COL + (i * PART_OFF), "Part"); 538 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), "----"); 539 540 mvaddstr(CHUNK_PART_START_ROW - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 541 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 542 543 mvaddstr(CHUNK_PART_START_ROW - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 544 mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 545 546 mvaddstr(CHUNK_PART_START_ROW - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 547 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 548 } 549 srow = CHUNK_SLICE_START_ROW; 550 prow = CHUNK_PART_START_ROW; 551 pcol = 0; 552 553 for (i = 0; label_chunk_info[i].c; i++) { 554 if (i == here) 555 attrset(A_REVERSE); 556 /* Is it a slice entry displayed at the top? */ 557 if (label_chunk_info[i].type == PART_SLICE) { 558 sz = space_free(label_chunk_info[i].c); 559 mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 560 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); 561 } 562 /* Otherwise it's a DOS, swap or filesystem entry, at the bottom */ 563 else { 564 char onestr[PART_OFF], num[10], *mountpoint, *newfs; 565 566 /* 567 * We copy this into a blank-padded string so that it looks like 568 * a solid bar in reverse-video 569 */ 570 memset(onestr, ' ', PART_OFF - 1); 571 onestr[PART_OFF - 1] = '\0'; 572 /* Go for two columns */ 573 if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) { 574 pcol = PART_OFF; 575 prow = CHUNK_PART_START_ROW; 576 } 577 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 578 /* If it's a filesystem, display the mountpoint */ 579 if (label_chunk_info[i].c->private 580 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 581 mountpoint = ((PartInfo *)label_chunk_info[i].c->private)->mountpoint; 582 else 583 mountpoint = "<none>"; 584 585 /* Now display the newfs field */ 586 if (label_chunk_info[i].type == PART_FAT) 587 newfs = "DOS"; 588 else if (label_chunk_info[i].c->private && label_chunk_info[i].type == PART_FILESYSTEM) 589 newfs = ((PartInfo *)label_chunk_info[i].c->private)->newfs ? "UFS Y" : "UFS N"; 590 else if (label_chunk_info[i].type == PART_SWAP) 591 newfs = "SWAP"; 592 else 593 newfs = "*"; 594 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 595 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 596 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 597 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 598 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 599 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 600 mvaddstr(prow, pcol, onestr); 601 ++prow; 602 } 603 if (i == here) 604 attrset(A_NORMAL); 605 } 606} 607 608static void 609print_command_summary() 610{ 611 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 612 mvprintw(18, 0, "C = Create D = Delete M = Mount W = Write"); 613 mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 614 mvprintw(20, 0, "A = Auto Defaults for all!"); 615 mvprintw(22, 0, "The default target will be displayed in "); 616 617 attrset(A_REVERSE); 618 addstr("reverse"); 619 attrset(A_NORMAL); 620 addstr(" video."); 621 mvprintw(23, 0, "Use F1 or ? to get more help, arrow keys to move."); 622 move(0, 0); 623} 624 625static int 626diskLabel(char *str) 627{ 628 int sz, key = 0; 629 Boolean labeling; 630 char *msg = NULL; 631 PartInfo *p, *oldp; 632 PartType type; 633 Device **devs; 634 635 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 636 if (!devs) { 637 dialog_clear(); 638 msgConfirm("No disks found!"); 639 return RET_FAIL; 640 } 641 642 labeling = TRUE; 643 keypad(stdscr, TRUE); 644 record_label_chunks(devs); 645 646 dialog_clear(); clear(); 647 while (labeling) { 648 clear(); 649 print_label_chunks(); 650 print_command_summary(); 651 if (msg) { 652 attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL); 653 clrtoeol(); 654 beep(); 655 msg = NULL; 656 } 657 refresh(); 658 key = toupper(getch()); 659 switch (key) { 660 int i, cnt; 661 662 case '\014': /* ^L */ 663 continue; 664 665 case KEY_UP: 666 case '-': 667 if (here != 0) 668 --here; 669 else 670 while (label_chunk_info[here + 1].c) 671 ++here; 672 break; 673 674 case KEY_DOWN: 675 case '+': 676 case '\r': 677 case '\n': 678 if (label_chunk_info[here + 1].c) 679 ++here; 680 else 681 here = 0; 682 break; 683 684 case KEY_HOME: 685 here = 0; 686 break; 687 688 case KEY_END: 689 while (label_chunk_info[here + 1].c) 690 ++here; 691 break; 692 693 case KEY_F(1): 694 case '?': 695 systemDisplayHelp("partition"); 696 break; 697 698 case 'A': 699 if (label_chunk_info[here].type != PART_SLICE) { 700 msg = "You can only do this in a master partition (see top of screen)"; 701 break; 702 } 703 704 cnt = i = 0; 705 while (label_chunk_info[i].c) 706 if (label_chunk_info[i++].type != PART_SLICE) 707 cnt++; 708 if (cnt == (CHUNK_COLUMN_MAX * 2) + 4) { 709 dialog_clear(); 710 msgConfirm("Sorry, I can't fit any more partitions on the screen! You can get around\n" 711 "this limitation by partitioning your disks individually rather than all\n" 712 "at once. This will be fixed just as soon as we get a scrolling partition\n" 713 "box written. Sorry for the inconvenience!"); 714 break; 715 } 716 717 sz = space_free(label_chunk_info[here].c); 718 if (sz <= FS_MIN_SIZE) { 719 msg = "Not enough space to create an additional FreeBSD partition"; 720 break; 721 } 722 { 723 struct chunk *tmp; 724 int mib[2]; 725 int physmem; 726 size_t size, swsize; 727 char *cp; 728 729 cp = variable_get(VAR_ROOT_SIZE); 730 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 731 label_chunk_info[here].c, 732 (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, 733 CHUNK_IS_ROOT); 734 735 if (!tmp) { 736 dialog_clear(); 737 msgConfirm("Unable to create the root partition. Too big?"); 738 break; 739 } 740 tmp->private = new_part("/", TRUE, tmp->size); 741 tmp->private_free = safe_free; 742 record_label_chunks(devs); 743 744 cp = variable_get(VAR_SWAP_SIZE); 745 if (cp) 746 swsize = atoi(cp) * ONE_MEG; 747 else { 748 mib[0] = CTL_HW; 749 mib[1] = HW_PHYSMEM; 750 size = sizeof physmem; 751 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 752 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 753 } 754 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 755 label_chunk_info[here].c, 756 swsize, 757 part, FS_SWAP, 0); 758 if (!tmp) { 759 dialog_clear(); 760 msgConfirm("Unable to create the swap partition. Too big?"); 761 break; 762 } 763 764 tmp->private = 0; 765 tmp->private_free = safe_free; 766 record_label_chunks(devs); 767 768 cp = variable_get(VAR_VAR_SIZE); 769 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 770 label_chunk_info[here].c, 771 (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 772 if (!tmp) { 773 dialog_clear(); 774 msgConfirm("Less than %dMB free for /var - you will need to\n" 775 "partition your disk manually with a custom install!", (cp ? atoi(cp) : VAR_MIN_SIZE)); 776 break; 777 } 778 tmp->private = new_part("/var", TRUE, tmp->size); 779 tmp->private_free = safe_free; 780 record_label_chunks(devs); 781 782 cp = variable_get(VAR_USR_SIZE); 783 if (cp) 784 sz = atoi(cp) * ONE_MEG; 785 else 786 sz = space_free(label_chunk_info[here].c); 787 if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) { 788 dialog_clear(); 789 msgConfirm("Less than %dMB free for /usr - you will need to\n" 790 "partition your disk manually with a custom install!", USR_MIN_SIZE); 791 break; 792 } 793 794 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 795 label_chunk_info[here].c, 796 sz, part, FS_BSDFFS, 0); 797 if (!tmp) { 798 dialog_clear(); 799 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 800 "You will need to partition your disk manually with a custom install!"); 801 break; 802 } 803 /* At this point, we're reasonably "labelled" */ 804 variable_set2(DISK_LABELLED, "yes"); 805 tmp->private = new_part("/usr", TRUE, tmp->size); 806 tmp->private_free = safe_free; 807 record_label_chunks(devs); 808 } 809 break; 810 811 case 'C': 812 if (label_chunk_info[here].type != PART_SLICE) { 813 msg = "You can only do this in a master partition (see top of screen)"; 814 break; 815 } 816 else { 817 int i, cnt; 818 819 cnt = i = 0; 820 while (label_chunk_info[i].c) 821 if (label_chunk_info[i++].type != PART_SLICE) 822 cnt++; 823 if (cnt == (CHUNK_COLUMN_MAX * 2)) { 824 dialog_clear(); 825 msgConfirm("Sorry, I can't fit any more partitions on the screen! You can get around\n" 826 "this limitation by partitioning your disks individually rather than all\n" 827 "at once. This will be fixed just as soon as we get a scrolling partition\n" 828 "box written. Sorry for the inconvenience!"); 829 break; 830 } 831 } 832 sz = space_free(label_chunk_info[here].c); 833 if (sz <= FS_MIN_SIZE) { 834 msg = "Not enough space to create an additional FreeBSD partition"; 835 break; 836 } 837 { 838 char *val, *cp; 839 int size; 840 struct chunk *tmp; 841 char osize[80]; 842 u_long flags = 0; 843 844 sprintf(osize, "%d", sz); 845 val = msgGetInput(osize, "Please specify the size for new FreeBSD partition in blocks, or\n" 846 "append a trailing `M' for megabytes (e.g. 20M) or `C' for cylinders.\n\n" 847 "Space free is %d blocks (%dMB)", sz, sz / ONE_MEG); 848 if (!val || (size = strtol(val, &cp, 0)) <= 0) 849 break; 850 851 if (*cp) { 852 if (toupper(*cp) == 'M') 853 size *= ONE_MEG; 854 else if (toupper(*cp) == 'C') 855 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 856 } 857 if (size <= FS_MIN_SIZE) { 858 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 859 break; 860 } 861 type = get_partition_type(); 862 if (type == PART_NONE) 863 break; 864 865 if (type == PART_FILESYSTEM) { 866 if ((p = get_mountpoint(NULL)) == NULL) 867 break; 868 else if (!strcmp(p->mountpoint, "/")) 869 flags |= CHUNK_IS_ROOT; 870 else 871 flags &= ~CHUNK_IS_ROOT; 872 } else 873 p = NULL; 874 875 if ((flags & CHUNK_IS_ROOT)) { 876 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 877 msgConfirm("This region cannot be used for your root partition as the\n" 878 "FreeBSD boot code cannot deal with a root partition created\n" 879 "in that location. Please choose another location or smaller\n" 880 "size for your root partition and try again!"); 881 break; 882 } 883 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 884 msgConfirm("Warning: This is smaller than the recommended size for a\n" 885 "root partition. For a variety of reasons, root\n" 886 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 887 } 888 } 889 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 890 label_chunk_info[here].c, 891 size, part, 892 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 893 flags); 894 if (!tmp) { 895 msgConfirm("Unable to create the partition. Too big?"); 896 break; 897 } 898 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 899 msgConfirm("This region cannot be used for your root partition as it starts\n" 900 "or extends past the 1024'th cylinder mark and is thus a\n" 901 "poor location to boot from. Please choose another\n" 902 "location (or smaller size) for your root partition and try again!"); 903 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 904 break; 905 } 906 if (type != PART_SWAP) { 907 /* This is needed to tell the newfs -u about the size */ 908 tmp->private = new_part(p->mountpoint, p->newfs, tmp->size); 909 tmp->private_free = safe_free; 910 safe_free(p); 911 } else { 912 tmp->private = p; 913 } 914 tmp->private_free = safe_free; 915 variable_set2(DISK_LABELLED, "yes"); 916 record_label_chunks(devs); 917 } 918 break; 919 920 case 'D': /* delete */ 921 if (label_chunk_info[here].type == PART_SLICE) { 922 msg = MSG_NOT_APPLICABLE; 923 break; 924 } 925 else if (label_chunk_info[here].type == PART_FAT) { 926 msg = "Use the Disk Partition Editor to delete DOS partitions"; 927 break; 928 } 929 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 930 variable_set2(DISK_LABELLED, "yes"); 931 record_label_chunks(devs); 932 break; 933 934 case 'M': /* mount */ 935 switch(label_chunk_info[here].type) { 936 case PART_SLICE: 937 msg = MSG_NOT_APPLICABLE; 938 break; 939 940 case PART_SWAP: 941 msg = "You don't need to specify a mountpoint for a swap partition."; 942 break; 943 944 case PART_FAT: 945 case PART_FILESYSTEM: 946 oldp = label_chunk_info[here].c->private; 947 p = get_mountpoint(label_chunk_info[here].c); 948 if (p) { 949 if (!oldp) 950 p->newfs = FALSE; 951 if (label_chunk_info[here].type == PART_FAT 952 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 953 || !strcmp(p->mountpoint, "/var"))) { 954 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 955 strcpy(p->mountpoint, "/bogus"); 956 } 957 } 958 variable_set2(DISK_LABELLED, "yes"); 959 record_label_chunks(devs); 960 break; 961 962 default: 963 msgFatal("Bogus partition under cursor???"); 964 break; 965 } 966 break; 967 968 case 'N': /* Set newfs options */ 969 if (label_chunk_info[here].c->private && 970 ((PartInfo *)label_chunk_info[here].c->private)->newfs) 971 getNewfsCmd(label_chunk_info[here].c->private); 972 else 973 msg = MSG_NOT_APPLICABLE; 974 break; 975 976 case 'T': /* Toggle newfs state */ 977 if (label_chunk_info[here].type == PART_FILESYSTEM) { 978 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private); 979 label_chunk_info[here].c->private = new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 980 safe_free(pi); 981 label_chunk_info[here].c->private_free = safe_free; 982 variable_set2(DISK_LABELLED, "yes"); 983 } 984 else 985 msg = MSG_NOT_APPLICABLE; 986 break; 987 988 case 'U': 989 clear(); 990 if (msgYesNo("Are you SURE you want to Undo everything?")) 991 break; 992 variable_unset(DISK_PARTITIONED); 993 for (i = 0; devs[i]; i++) { 994 extern void diskPartition(Device *dev, Disk *d); 995 Disk *d; 996 997 if (!devs[i]->enabled) 998 continue; 999 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1000 Free_Disk(devs[i]->private); 1001 devs[i]->private = d; 1002 diskPartition(devs[i], d); 1003 } 1004 } 1005 variable_unset(DISK_LABELLED); 1006 record_label_chunks(devs); 1007 break; 1008 1009 case 'W': 1010 if (!msgYesNo("Are you SURE that you wish to make and mount all filesystems\n" 1011 "at this time? You also have the option of doing it later in\n" 1012 "one final 'commit' operation, and if you're at all unsure as\n" 1013 "to which option to chose, then PLEASE CHOSE NO! This option\n" 1014 "is DANGEROUS if you're not EXACTLY sure what you are doing!")) { 1015 variable_set2(DISK_LABELLED, "yes"); 1016 clear(); 1017 diskLabelCommit(NULL); 1018 } 1019 break; 1020 1021 case '|': 1022 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1023 "This is an entirely undocumented feature which you are not\n" 1024 "expected to understand!")) { 1025 int i; 1026 Device **devs; 1027 1028 dialog_clear(); 1029 end_dialog(); 1030 DialogActive = FALSE; 1031 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1032 if (!devs) { 1033 dialog_clear(); 1034 msgConfirm("Can't find any disk devices!"); 1035 break; 1036 } 1037 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1038 if (devs[i]->enabled) 1039 slice_wizard(((Disk *)devs[i]->private)); 1040 } 1041 variable_set2(DISK_LABELLED, "yes"); 1042 DialogActive = TRUE; 1043 dialog_clear(); 1044 record_label_chunks(devs); 1045 } 1046 else 1047 msg = "A most prudent choice!"; 1048 break; 1049 1050 case 'Q': 1051 labeling = FALSE; 1052 break; 1053 1054 default: 1055 beep(); 1056 msg = "Type F1 or ? for help"; 1057 break; 1058 } 1059 } 1060 dialog_clear(); 1061 return RET_SUCCESS; 1062} 1063