label.c revision 30956
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.63.2.15 1997/11/05 05:54:27 obrien 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 80/*** with this value we try to track the most recently added label ***/ 81static int label_focus = 0, pslice_focus = 0; 82 83static int diskLabel(Device *dev); 84static int diskLabelNonInteractive(Device *dev); 85 86static int 87labelHook(dialogMenuItem *selected) 88{ 89 Device **devs = NULL; 90 91 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 92 if (!devs) { 93 msgConfirm("Unable to find disk %s!", selected->prompt); 94 return DITEM_FAILURE; 95 } 96 /* Toggle enabled status? */ 97 if (!devs[0]->enabled) { 98 devs[0]->enabled = TRUE; 99 diskLabel(devs[0]); 100 } 101 else 102 devs[0]->enabled = FALSE; 103 return DITEM_SUCCESS | DITEM_RESTORE; 104} 105 106static int 107labelCheck(dialogMenuItem *selected) 108{ 109 Device **devs = NULL; 110 111 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 112 if (!devs || devs[0]->enabled == FALSE) 113 return FALSE; 114 return TRUE; 115} 116 117int 118diskLabelEditor(dialogMenuItem *self) 119{ 120 DMenu *menu; 121 Device **devs; 122 int i, cnt; 123 124 i = 0; 125 cnt = diskGetSelectCount(&devs); 126 if (cnt == -1) { 127 msgConfirm("No disks found! Please verify that your disk controller is being\n" 128 "properly probed at boot time. See the Hardware Guide on the\n" 129 "Documentation menu for clues on diagnosing this type of problem."); 130 return DITEM_FAILURE; 131 } 132 else if (cnt) { 133 int i; 134 135 /* Some are already selected */ 136 if (variable_get(VAR_NONINTERACTIVE)) 137 i |= diskLabelNonInteractive(NULL); 138 else 139 i |= diskLabel(NULL); 140 } 141 else { 142 /* No disks are selected, fall-back case now */ 143 cnt = deviceCount(devs); 144 if (cnt == 1) { 145 devs[0]->enabled = TRUE; 146 if (variable_get(VAR_NONINTERACTIVE)) 147 i = diskLabelNonInteractive(devs[0]); 148 else 149 i = diskLabel(devs[0]); 150 } 151 else { 152 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); 153 if (!menu) { 154 msgConfirm("No devices suitable for installation found!\n\n" 155 "Please verify that your disk controller (and attached drives)\n" 156 "were detected properly. This can be done by pressing the\n" 157 "[Scroll Lock] key and using the Arrow keys to move back to\n" 158 "the boot messages. Press [Scroll Lock] again to return."); 159 i = DITEM_FAILURE; 160 } 161 else { 162 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 163 free(menu); 164 } 165 i |= DITEM_RESTORE; 166 } 167 } 168 if (DITEM_STATUS(i) != DITEM_FAILURE) { 169 char *cp; 170 171 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 172 variable_set2(DISK_LABELLED, "yes"); 173 } 174 return i; 175} 176 177int 178diskLabelCommit(dialogMenuItem *self) 179{ 180 char *cp; 181 int i; 182 183 /* Already done? */ 184 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 185 i = DITEM_SUCCESS; 186 else if (!cp) { 187 msgConfirm("You must assign disk labels before this option can be used."); 188 i = DITEM_FAILURE; 189 } 190 /* The routine will guard against redundant writes, just as this one does */ 191 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 192 i = DITEM_FAILURE; 193 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 194 i = DITEM_FAILURE; 195 else { 196 msgInfo("All filesystem information written successfully."); 197 variable_set2(DISK_LABELLED, "written"); 198 i = DITEM_SUCCESS; 199 } 200 return i; 201} 202 203/* See if we're already using a desired partition name */ 204static Boolean 205check_conflict(char *name) 206{ 207 int i; 208 209 for (i = 0; label_chunk_info[i].c; i++) 210 if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) 211 && label_chunk_info[i].c->private_data 212 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 213 return TRUE; 214 return FALSE; 215} 216 217/* How much space is in this FreeBSD slice? */ 218static int 219space_free(struct chunk *c) 220{ 221 struct chunk *c1; 222 int sz = c->size; 223 224 for (c1 = c->part; c1; c1 = c1->next) { 225 if (c1->type != unused) 226 sz -= c1->size; 227 } 228 if (sz < 0) 229 msgFatal("Partitions are larger than actual chunk??"); 230 return sz; 231} 232 233/* Snapshot the current situation into the displayed chunks structure */ 234static void 235record_label_chunks(Device **devs, Device *dev) 236{ 237 int i, j, p; 238 struct chunk *c1, *c2; 239 Disk *d; 240 241 j = p = 0; 242 /* First buzz through and pick up the FreeBSD slices */ 243 for (i = 0; devs[i]; i++) { 244 if ((dev && devs[i] != dev) || !devs[i]->enabled) 245 continue; 246 d = (Disk *)devs[i]->private; 247 if (!d->chunks) 248 msgFatal("No chunk list found for %s!", d->name); 249 250 /* Put the slice entries first */ 251 for (c1 = d->chunks->part; c1; c1 = c1->next) { 252 if (c1->type == freebsd) { 253 label_chunk_info[j].type = PART_SLICE; 254 label_chunk_info[j].c = c1; 255 ++j; 256 } 257 } 258 } 259 260 /* Now run through again and get the FreeBSD partition entries */ 261 for (i = 0; devs[i]; i++) { 262 if (!devs[i]->enabled) 263 continue; 264 d = (Disk *)devs[i]->private; 265 /* Then buzz through and pick up the partitions */ 266 for (c1 = d->chunks->part; c1; c1 = c1->next) { 267 if (c1->type == freebsd) { 268 for (c2 = c1->part; c2; c2 = c2->next) { 269 if (c2->type == part) { 270 if (c2->subtype == FS_SWAP) 271 label_chunk_info[j].type = PART_SWAP; 272 else 273 label_chunk_info[j].type = PART_FILESYSTEM; 274 label_chunk_info[j].c = c2; 275 ++j; 276 } 277 } 278 } 279 else if (c1->type == fat) { 280 label_chunk_info[j].type = PART_FAT; 281 label_chunk_info[j].c = c1; 282 ++j; 283 } 284 } 285 } 286 label_chunk_info[j].c = NULL; 287 if (here >= j) { 288 here = j ? j - 1 : 0; 289 } 290} 291 292/* A new partition entry */ 293static PartInfo * 294new_part(char *mpoint, Boolean newfs, u_long size) 295{ 296 PartInfo *ret; 297 298 if (!mpoint) 299 mpoint = "/change_me"; 300 301 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 302 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); 303 strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 304 ret->newfs = newfs; 305 if (!size) 306 return ret; 307 return ret; 308} 309 310/* Get the mountpoint for a partition and save it away */ 311static PartInfo * 312get_mountpoint(struct chunk *old) 313{ 314 char *val; 315 PartInfo *tmp; 316 317 if (old && old->private_data) 318 tmp = old->private_data; 319 else 320 tmp = NULL; 321 if (!old) { 322 DialogX = 14; 323 DialogY = 16; 324 } 325 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 326 DialogX = DialogY = 0; 327 if (!val || !*val) { 328 if (!old) 329 return NULL; 330 else { 331 free(old->private_data); 332 old->private_data = NULL; 333 } 334 return NULL; 335 } 336 337 /* Is it just the same value? */ 338 if (tmp && !strcmp(tmp->mountpoint, val)) 339 return NULL; 340 341 /* Did we use it already? */ 342 if (check_conflict(val)) { 343 msgConfirm("You already have a mount point for %s assigned!", val); 344 return NULL; 345 } 346 347 /* Is it bogus? */ 348 if (*val != '/') { 349 msgConfirm("Mount point must start with a / character"); 350 return NULL; 351 } 352 353 /* Is it going to be mounted on root? */ 354 if (!strcmp(val, "/")) { 355 if (old) 356 old->flags |= CHUNK_IS_ROOT; 357 } 358 else if (old) 359 old->flags &= ~CHUNK_IS_ROOT; 360 361 safe_free(tmp); 362 tmp = new_part(val, TRUE, 0); 363 if (old) { 364 old->private_data = tmp; 365 old->private_free = safe_free; 366 } 367 return tmp; 368} 369 370/* Get the type of the new partiton */ 371static PartType 372get_partition_type(void) 373{ 374 char selection[20]; 375 int i; 376 377 static unsigned char *fs_types[] = { 378 "FS", 379 "A file system", 380 "Swap", 381 "A swap partition.", 382 }; 383 DialogX = 7; 384 DialogY = 8; 385 i = dialog_menu("Please choose a partition type", 386 "If you want to use this partition for swap space, select Swap.\n" 387 "If you want to put a filesystem on it, choose FS.", 388 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 389 DialogX = DialogY = 0; 390 if (!i) { 391 if (!strcmp(selection, "FS")) 392 return PART_FILESYSTEM; 393 else if (!strcmp(selection, "Swap")) 394 return PART_SWAP; 395 } 396 return PART_NONE; 397} 398 399/* If the user wants a special newfs command for this, set it */ 400static void 401getNewfsCmd(PartInfo *p) 402{ 403 char *val; 404 405 val = msgGetInput(p->newfs_cmd, 406 "Please enter the newfs command and options you'd like to use in\n" 407 "creating this file system."); 408 if (val) 409 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 410} 411 412#define MAX_MOUNT_NAME 12 413 414#define PART_PART_COL 0 415#define PART_MOUNT_COL 8 416#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 417#define PART_NEWFS_COL (PART_SIZE_COL + 7) 418#define PART_OFF 38 419 420#define TOTAL_AVAIL_LINES (10) 421#define PSLICE_SHOWABLE (4) 422 423 424/* stick this all up on the screen */ 425static void 426print_label_chunks(void) 427{ 428 int i, j, srow, prow, pcol; 429 int sz; 430 char clrmsg[80]; 431 int ChunkPartStartRow; 432 WINDOW *ChunkWin; 433 434 /********************************************************/ 435 /*** These values are for controling screen resources ***/ 436 /*** Each label line holds up to 2 labels, so beware! ***/ 437 /*** strategy will be to try to always make sure the ***/ 438 /*** highlighted label is in the active display area. ***/ 439 /********************************************************/ 440 int pslice_max, label_max; 441 int pslice_count, label_count, label_focus_found, pslice_focus_found; 442 443 attrset(A_REVERSE); 444 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 445 attrset(A_NORMAL); 446 447 /*** Count the number of parition slices ***/ 448 pslice_count = 0; 449 for (i = 0; label_chunk_info[i].c ; i++) { 450 if (label_chunk_info[i].type == PART_SLICE) 451 ++pslice_count; 452 } 453 pslice_max = pslice_count; 454 455 /*** 4 line max for partition slices ***/ 456 if (pslice_max > PSLICE_SHOWABLE) { 457 pslice_max = PSLICE_SHOWABLE; 458 } 459 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; 460 461 /*** View partition slices modulo pslice_max ***/ 462 label_max = TOTAL_AVAIL_LINES - pslice_max; 463 464 for (i = 0; i < 2; i++) { 465 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 466 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 467 468 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 469 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 470 471 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 472 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 473 474 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 475 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 476 } 477 srow = CHUNK_SLICE_START_ROW; 478 prow = 0; 479 pcol = 0; 480 481 /*** these variables indicate that the focused item is shown currently ***/ 482 label_focus_found = 0; 483 pslice_focus_found = 0; 484 485 label_count = 0; 486 pslice_count = 0; 487 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 488 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 489 490 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 491 492 wclear(ChunkWin); 493 /*** wrefresh(ChunkWin); ***/ 494 495 for (i = 0; label_chunk_info[i].c; i++) { 496 /* Is it a slice entry displayed at the top? */ 497 if (label_chunk_info[i].type == PART_SLICE) { 498 /*** This causes the new pslice to replace the previous display ***/ 499 /*** focus must remain on the most recently active pslice ***/ 500 if (pslice_count == pslice_max) { 501 if (pslice_focus_found) { 502 /*** This is where we can mark the more following ***/ 503 attrset(A_BOLD); 504 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 505 attrset(A_NORMAL); 506 continue; 507 } 508 else { 509 /*** this is where we set the more previous ***/ 510 attrset(A_BOLD); 511 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 512 attrset(A_NORMAL); 513 pslice_count = 0; 514 srow = CHUNK_SLICE_START_ROW; 515 } 516 } 517 518 sz = space_free(label_chunk_info[i].c); 519 if (i == here) 520 attrset(ATTR_SELECTED); 521 if (i == pslice_focus) 522 pslice_focus_found = -1; 523 524 mvprintw(srow++, 0, 525 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 526 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, 527 sz, (sz / ONE_MEG)); 528 attrset(A_NORMAL); 529 clrtoeol(); 530 move(0, 0); 531 /*** refresh(); ***/ 532 ++pslice_count; 533 } 534 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 535 else { 536 char onestr[PART_OFF], num[10], *mountpoint, *newfs; 537 538 /* 539 * We copy this into a blank-padded string so that it looks like 540 * a solid bar in reverse-video 541 */ 542 memset(onestr, ' ', PART_OFF - 1); 543 onestr[PART_OFF - 1] = '\0'; 544 545 /*** Track how many labels have been displayed ***/ 546 if (label_count == ((label_max - 1 ) * 2)) { 547 if (label_focus_found) { 548 continue; 549 } 550 else { 551 label_count = 0; 552 prow = 0; 553 pcol = 0; 554 } 555 } 556 557 /* Go for two columns if we've written one full columns worth */ 558 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 559 if (label_count == label_max - 1) { 560 pcol = PART_OFF; 561 prow = 0; 562 } 563 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 564 /* If it's a filesystem, display the mountpoint */ 565 if (label_chunk_info[i].c->private_data 566 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 567 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 568 else if (label_chunk_info[i].type == PART_SWAP) 569 mountpoint = "swap"; 570 else 571 mountpoint = "<none>"; 572 573 /* Now display the newfs field */ 574 if (label_chunk_info[i].type == PART_FAT) 575 newfs = "DOS"; 576 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 577 newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 578 else if (label_chunk_info[i].type == PART_SWAP) 579 newfs = "SWAP"; 580 else 581 newfs = "*"; 582 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 583 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 584 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 585 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 586 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 587 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 588 if (i == label_focus) { 589 label_focus_found = -1; 590 wattrset(ChunkWin, A_BOLD); 591 } 592 if (i == here) 593 wattrset(ChunkWin, ATTR_SELECTED); 594 595 /*** lazy man's way of padding this string ***/ 596 while (strlen( onestr ) < 37) 597 strcat(onestr, " "); 598 599 mvwaddstr(ChunkWin, prow, pcol, onestr); 600 wattrset(ChunkWin, A_NORMAL); 601 move(0, 0); 602 ++prow; 603 ++label_count; 604 } 605 } 606 607 /*** this will erase all the extra stuff ***/ 608 memset(clrmsg, ' ', 37); 609 clrmsg[37] = '\0'; 610 611 while (pslice_count < pslice_max) { 612 mvprintw(srow++, 0, clrmsg); 613 clrtoeol(); 614 ++pslice_count; 615 } 616 while (label_count < (2 * (label_max - 1))) { 617 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 618 ++label_count; 619 if (prow == (label_max - 1)) { 620 prow = 0; 621 pcol = PART_OFF; 622 } 623 } 624 refresh(); 625 wrefresh(ChunkWin); 626} 627 628static void 629print_command_summary(void) 630{ 631 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 632 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 633 if (!RunningAsInit) 634 mvprintw(18, 49, "W = Write"); 635 mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 636 mvprintw(20, 0, "A = Auto Defaults for all!"); 637 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 638 move(0, 0); 639} 640 641static void 642clear_wins(void) 643{ 644 extern void print_label_chunks(); 645 clear(); 646 print_label_chunks(); 647} 648 649static int 650diskLabel(Device *dev) 651{ 652 int sz, key = 0; 653 Boolean labeling; 654 char *msg = NULL; 655 PartInfo *p, *oldp; 656 PartType type; 657 Device **devs; 658 659 label_focus = 0; 660 pslice_focus = 0; 661 here = 0; 662 663 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 664 if (!devs) { 665 msgConfirm("No disks found!"); 666 return DITEM_FAILURE; 667 } 668 labeling = TRUE; 669 keypad(stdscr, TRUE); 670 record_label_chunks(devs, dev); 671 672 clear(); 673 while (labeling) { 674 char *cp; 675 676 print_label_chunks(); 677 print_command_summary(); 678 if (msg) { 679 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 680 clrtoeol(); 681 beep(); 682 msg = NULL; 683 } 684 else { 685 move(23, 0); 686 clrtoeol(); 687 } 688 689 refresh(); 690 key = getch(); 691 switch (toupper(key)) { 692 int i; 693 static char _msg[40]; 694 695 case '\014': /* ^L */ 696 clear_wins(); 697 break; 698 699 case '\020': /* ^P */ 700 case KEY_UP: 701 case '-': 702 if (here != 0) 703 --here; 704 else 705 while (label_chunk_info[here + 1].c) 706 ++here; 707 break; 708 709 case '\016': /* ^N */ 710 case KEY_DOWN: 711 case '+': 712 case '\r': 713 case '\n': 714 if (label_chunk_info[here + 1].c) 715 ++here; 716 else 717 here = 0; 718 break; 719 720 case KEY_HOME: 721 here = 0; 722 break; 723 724 case KEY_END: 725 while (label_chunk_info[here + 1].c) 726 ++here; 727 break; 728 729 case KEY_F(1): 730 case '?': 731 systemDisplayHelp("partition"); 732 clear_wins(); 733 break; 734 735 case 'A': 736 if (label_chunk_info[here].type != PART_SLICE) { 737 msg = "You can only do this in a disk slice (at top of screen)"; 738 break; 739 } 740 sz = space_free(label_chunk_info[here].c); 741 if (sz <= FS_MIN_SIZE) 742 msg = "Not enough free space to create a new partition in the slice"; 743 else { 744 struct chunk *tmp; 745 int mib[2]; 746 int physmem; 747 size_t size, swsize; 748 char *cp; 749 Chunk *rootdev, *swapdev, *usrdev, *vardev; 750 751 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 752 if (!rootdev) { 753 cp = variable_get(VAR_ROOT_SIZE); 754 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 755 (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 756 if (!tmp) { 757 msgConfirm("Unable to create the root partition. Too big?"); 758 clear_wins(); 759 break; 760 } 761 tmp->private_data = new_part("/", TRUE, tmp->size); 762 tmp->private_free = safe_free; 763 record_label_chunks(devs, dev); 764 } 765 766 if (!swapdev) { 767 cp = variable_get(VAR_SWAP_SIZE); 768 if (cp) 769 swsize = atoi(cp) * ONE_MEG; 770 else { 771 mib[0] = CTL_HW; 772 mib[1] = HW_PHYSMEM; 773 size = sizeof physmem; 774 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 775 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 776 } 777 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 778 swsize, part, FS_SWAP, 0); 779 if (!tmp) { 780 msgConfirm("Unable to create the swap partition. Too big?"); 781 clear_wins(); 782 break; 783 } 784 tmp->private_data = 0; 785 tmp->private_free = safe_free; 786 record_label_chunks(devs, dev); 787 } 788 789 if (!vardev) { 790 cp = variable_get(VAR_VAR_SIZE); 791 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 792 (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 793 if (!tmp) { 794 msgConfirm("Less than %dMB free for /var - you will need to\n" 795 "partition your disk manually with a custom install!", 796 (cp ? atoi(cp) : VAR_MIN_SIZE)); 797 clear_wins(); 798 break; 799 } 800 tmp->private_data = new_part("/var", TRUE, tmp->size); 801 tmp->private_free = safe_free; 802 record_label_chunks(devs, dev); 803 } 804 805 if (!usrdev) { 806 cp = variable_get(VAR_USR_SIZE); 807 if (cp) 808 sz = atoi(cp) * ONE_MEG; 809 else 810 sz = space_free(label_chunk_info[here].c); 811 if (sz) { 812 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 813 msgConfirm("Less than %dMB free for /usr - you will need to\n" 814 "partition your disk manually with a custom install!", USR_MIN_SIZE); 815 clear_wins(); 816 break; 817 } 818 819 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 820 label_chunk_info[here].c, 821 sz, part, FS_BSDFFS, 0); 822 if (!tmp) { 823 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 824 "You will need to partition your disk manually with a custom install!"); 825 clear_wins(); 826 break; 827 } 828 tmp->private_data = new_part("/usr", TRUE, tmp->size); 829 tmp->private_free = safe_free; 830 record_label_chunks(devs, dev); 831 } 832 } 833 /* At this point, we're reasonably "labelled" */ 834 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 835 variable_set2(DISK_LABELLED, "yes"); 836 } 837 break; 838 839 case 'C': 840 if (label_chunk_info[here].type != PART_SLICE) { 841 msg = "You can only do this in a master partition (see top of screen)"; 842 break; 843 } 844 sz = space_free(label_chunk_info[here].c); 845 if (sz <= FS_MIN_SIZE) { 846 msg = "Not enough space to create an additional FreeBSD partition"; 847 break; 848 } 849 else { 850 char *val; 851 int size; 852 struct chunk *tmp; 853 char osize[80]; 854 u_long flags = 0; 855 856 sprintf(osize, "%d", sz); 857 DialogX = 3; 858 DialogY = 2; 859 val = msgGetInput(osize, 860 "Please specify the partition size in blocks or append a trailing M for\n" 861 "megabytes or C for cylinders. %d blocks (%dMB) are free.", 862 sz, sz / ONE_MEG); 863 DialogX = DialogY = 0; 864 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 865 clear_wins(); 866 break; 867 } 868 869 if (*cp) { 870 if (toupper(*cp) == 'M') 871 size *= ONE_MEG; 872 else if (toupper(*cp) == 'C') 873 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 874 } 875 if (size <= FS_MIN_SIZE) { 876 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 877 clear_wins(); 878 break; 879 } 880 type = get_partition_type(); 881 if (type == PART_NONE) { 882 clear_wins(); 883 beep(); 884 break; 885 } 886 887 if (type == PART_FILESYSTEM) { 888 if ((p = get_mountpoint(NULL)) == NULL) { 889 clear_wins(); 890 beep(); 891 break; 892 } 893 else if (!strcmp(p->mountpoint, "/")) 894 flags |= CHUNK_IS_ROOT; 895 else 896 flags &= ~CHUNK_IS_ROOT; 897 } 898 else 899 p = NULL; 900 901 if ((flags & CHUNK_IS_ROOT)) { 902 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 903 msgConfirm("This region cannot be used for your root partition as the\n" 904 "FreeBSD boot code cannot deal with a root partition created\n" 905 "in that location. Please choose another location or smaller\n" 906 "size for your root partition and try again!"); 907 clear_wins(); 908 break; 909 } 910 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 911 msgConfirm("Warning: This is smaller than the recommended size for a\n" 912 "root partition. For a variety of reasons, root\n" 913 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 914 } 915 } 916 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 917 label_chunk_info[here].c, 918 size, part, 919 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 920 flags); 921 if (!tmp) { 922 msgConfirm("Unable to create the partition. Too big?"); 923 clear_wins(); 924 break; 925 } 926 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 927 msgConfirm("This region cannot be used for your root partition as it starts\n" 928 "or extends past the 1024'th cylinder mark and is thus a\n" 929 "poor location to boot from. Please choose another\n" 930 "location (or smaller size) for your root partition and try again!"); 931 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 932 clear_wins(); 933 break; 934 } 935 if (type != PART_SWAP) { 936 /* This is needed to tell the newfs -u about the size */ 937 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 938 safe_free(p); 939 } 940 else 941 tmp->private_data = p; 942 tmp->private_free = safe_free; 943 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 944 variable_set2(DISK_LABELLED, "yes"); 945 record_label_chunks(devs, dev); 946 clear_wins(); 947 /*** This is where we assign focus to new label so it shows ***/ 948 { 949 int i; 950 label_focus = -1; 951 for (i = 0; label_chunk_info[i].c; ++i) { 952 if (label_chunk_info[i].c == tmp) { 953 label_focus = i; 954 break; 955 } 956 } 957 if (label_focus == -1) 958 label_focus = i - 1; 959 } 960 } 961 break; 962 963 case KEY_DC: 964 case 'D': /* delete */ 965 if (label_chunk_info[here].type == PART_SLICE) { 966 msg = MSG_NOT_APPLICABLE; 967 break; 968 } 969 else if (label_chunk_info[here].type == PART_FAT) { 970 msg = "Use the Disk Partition Editor to delete DOS partitions"; 971 break; 972 } 973 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 974 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 975 variable_set2(DISK_LABELLED, "yes"); 976 record_label_chunks(devs, dev); 977 break; 978 979 case 'M': /* mount */ 980 switch(label_chunk_info[here].type) { 981 case PART_SLICE: 982 msg = MSG_NOT_APPLICABLE; 983 break; 984 985 case PART_SWAP: 986 msg = "You don't need to specify a mountpoint for a swap partition."; 987 break; 988 989 case PART_FAT: 990 case PART_FILESYSTEM: 991 oldp = label_chunk_info[here].c->private_data; 992 p = get_mountpoint(label_chunk_info[here].c); 993 if (p) { 994 if (!oldp) 995 p->newfs = FALSE; 996 if (label_chunk_info[here].type == PART_FAT 997 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 998 || !strcmp(p->mountpoint, "/var"))) { 999 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1000 strcpy(p->mountpoint, "/bogus"); 1001 } 1002 } 1003 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1004 variable_set2(DISK_LABELLED, "yes"); 1005 record_label_chunks(devs, dev); 1006 clear_wins(); 1007 break; 1008 1009 default: 1010 msgFatal("Bogus partition under cursor???"); 1011 break; 1012 } 1013 break; 1014 1015 case 'N': /* Set newfs options */ 1016 if (label_chunk_info[here].c->private_data && 1017 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1018 getNewfsCmd(label_chunk_info[here].c->private_data); 1019 else 1020 msg = MSG_NOT_APPLICABLE; 1021 clear_wins(); 1022 break; 1023 1024 case 'T': /* Toggle newfs state */ 1025 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1026 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1027 label_chunk_info[here].c->private_data = 1028 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 1029 safe_free(pi); 1030 label_chunk_info[here].c->private_free = safe_free; 1031 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1032 variable_set2(DISK_LABELLED, "yes"); 1033 } 1034 else 1035 msg = MSG_NOT_APPLICABLE; 1036 break; 1037 1038 case 'U': 1039 clear(); 1040 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1041 msgConfirm("You've already written out your changes -\n" 1042 "it's too late to undo!"); 1043 } 1044 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 1045 variable_unset(DISK_PARTITIONED); 1046 variable_unset(DISK_LABELLED); 1047 for (i = 0; devs[i]; i++) { 1048 Disk *d; 1049 1050 if (!devs[i]->enabled) 1051 continue; 1052 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1053 Free_Disk(devs[i]->private); 1054 devs[i]->private = d; 1055 diskPartition(devs[i]); 1056 } 1057 } 1058 record_label_chunks(devs, dev); 1059 } 1060 clear_wins(); 1061 break; 1062 1063 case 'W': 1064 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1065 msgConfirm("You've already written out your changes - if you\n" 1066 "wish to overwrite them, you'll have to start this\n" 1067 "procedure again from the beginning."); 1068 } 1069 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 1070 "installation. If you are installing FreeBSD for the first time\n" 1071 "then you should simply type Q when you're finished here and your\n" 1072 "changes will be committed in one batch automatically at the end of\n" 1073 "these questions.\n\n" 1074 "Are you absolutely sure you want to do this now?")) { 1075 variable_set2(DISK_LABELLED, "yes"); 1076 diskLabelCommit(NULL); 1077 } 1078 clear_wins(); 1079 break; 1080 1081 case '|': 1082 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1083 "This is an entirely undocumented feature which you are not\n" 1084 "expected to understand!")) { 1085 int i; 1086 Device **devs; 1087 1088 dialog_clear(); 1089 end_dialog(); 1090 DialogActive = FALSE; 1091 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1092 if (!devs) { 1093 msgConfirm("Can't find any disk devices!"); 1094 break; 1095 } 1096 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1097 if (devs[i]->enabled) 1098 slice_wizard(((Disk *)devs[i]->private)); 1099 } 1100 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1101 variable_set2(DISK_LABELLED, "yes"); 1102 DialogActive = TRUE; 1103 record_label_chunks(devs, dev); 1104 clear_wins(); 1105 } 1106 else 1107 msg = "A most prudent choice!"; 1108 break; 1109 1110 case '\033': /* ESC */ 1111 case 'Q': 1112 labeling = FALSE; 1113 break; 1114 1115 default: 1116 beep(); 1117 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1118 msg = _msg; 1119 break; 1120 } 1121 if (label_chunk_info[here].type == PART_SLICE) 1122 pslice_focus = here; 1123 else 1124 label_focus = here; 1125 } 1126 return DITEM_SUCCESS | DITEM_RESTORE; 1127} 1128 1129static int 1130diskLabelNonInteractive(Device *dev) 1131{ 1132 char *cp; 1133 PartType type; 1134 PartInfo *p; 1135 u_long flags = 0; 1136 int i, status; 1137 Device **devs; 1138 Disk *d; 1139 1140 status = DITEM_SUCCESS; 1141 1142 cp = variable_get(VAR_DISK); 1143 if (!cp) { 1144 dialog_clear(); 1145 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1146 return DITEM_FAILURE; 1147 } 1148 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1149 if (!devs) { 1150 msgConfirm("diskLabel: No disk device %s found!", cp); 1151 return DITEM_FAILURE; 1152 } 1153 if (dev) 1154 d = dev->private; 1155 else 1156 d = devs[0]->private; 1157 record_label_chunks(devs, dev); 1158 for (i = 0; label_chunk_info[i].c; i++) { 1159 Chunk *c1 = label_chunk_info[i].c; 1160 1161 if (label_chunk_info[i].type == PART_SLICE) { 1162 char name[512]; 1163 int entries = 1; 1164 1165 while (entries) { 1166 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1167 if ((cp = variable_get(name)) != NULL) { 1168 int sz; 1169 char typ[10], mpoint[50]; 1170 1171 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 1172 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1173 status = DITEM_FAILURE; 1174 continue; 1175 } 1176 else { 1177 Chunk *tmp; 1178 1179 if (!strcmp(typ, "swap")) { 1180 type = PART_SWAP; 1181 strcpy(mpoint, "SWAP"); 1182 } 1183 else { 1184 type = PART_FILESYSTEM; 1185 if (!strcmp(mpoint, "/")) 1186 flags |= CHUNK_IS_ROOT; 1187 } 1188 if (!sz) 1189 sz = space_free(c1); 1190 if (sz > space_free(c1)) { 1191 msgConfirm("Not enough free space to create partition: %s", mpoint); 1192 status = DITEM_FAILURE; 1193 continue; 1194 } 1195 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1196 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1197 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1198 status = DITEM_FAILURE; 1199 break; 1200 } 1201 else { 1202 tmp->private_data = new_part(mpoint, TRUE, sz); 1203 tmp->private_free = safe_free; 1204 status = DITEM_SUCCESS; 1205 } 1206 } 1207 entries++; 1208 } 1209 else { 1210 /* No more matches, leave the loop */ 1211 entries = 0; 1212 } 1213 } 1214 } 1215 else { 1216 /* Must be something we can set a mountpoint for */ 1217 cp = variable_get(c1->name); 1218 if (cp) { 1219 char mpoint[50], do_newfs[8]; 1220 Boolean newfs = FALSE; 1221 1222 do_newfs[0] = '\0'; 1223 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1224 dialog_clear(); 1225 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1226 status = DITEM_FAILURE; 1227 continue; 1228 } 1229 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1230 if (c1->private_data) { 1231 p = c1->private_data; 1232 p->newfs = newfs; 1233 strcpy(p->mountpoint, mpoint); 1234 } 1235 else { 1236 c1->private_data = new_part(mpoint, newfs, 0); 1237 c1->private_free = safe_free; 1238 } 1239 if (!strcmp(mpoint, "/")) 1240 c1->flags |= CHUNK_IS_ROOT; 1241 else 1242 c1->flags &= ~CHUNK_IS_ROOT; 1243 } 1244 } 1245 } 1246 if (status == DITEM_SUCCESS) 1247 variable_set2(DISK_LABELLED, "yes"); 1248 return status; 1249} 1250