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