label.c revision 37735
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.82 1998/03/13 11:09:03 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(NULL); 136 else 137 i = diskLabel(NULL); 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, 49, "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 if (cp) 790 sz = atoi(cp) * ONE_MEG; 791 else 792 sz = variable_get(VAR_NO_USR) 793 ? space_free(label_chunk_info[here].c) 794 : VAR_MIN_SIZE * ONE_MEG; 795 796 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 797 sz, part, FS_BSDFFS, 0); 798 if (!tmp) { 799 msgConfirm("Less than %dMB free for /var - you will need to\n" 800 "partition your disk manually with a custom install!", 801 (cp ? atoi(cp) : VAR_MIN_SIZE)); 802 clear_wins(); 803 break; 804 } 805 tmp->private_data = new_part("/var", TRUE, tmp->size); 806 tmp->private_free = safe_free; 807 record_label_chunks(devs, dev); 808 } 809 810 if (!usrdev && !variable_get(VAR_NO_USR)) { 811 cp = variable_get(VAR_USR_SIZE); 812 if (cp) 813 sz = atoi(cp) * ONE_MEG; 814 else 815 sz = space_free(label_chunk_info[here].c); 816 if (sz) { 817 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 818 msgConfirm("Less than %dMB free for /usr - you will need to\n" 819 "partition your disk manually with a custom install!", USR_MIN_SIZE); 820 clear_wins(); 821 break; 822 } 823 824 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 825 label_chunk_info[here].c, 826 sz, part, FS_BSDFFS, 0); 827 if (!tmp) { 828 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 829 "You will need to partition your disk manually with a custom install!"); 830 clear_wins(); 831 break; 832 } 833 tmp->private_data = new_part("/usr", TRUE, tmp->size); 834 tmp->private_free = safe_free; 835 record_label_chunks(devs, dev); 836 } 837 } 838 839 /* At this point, we're reasonably "labelled" */ 840 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 841 variable_set2(DISK_LABELLED, "yes"); 842 } 843 break; 844 845 case 'C': 846 if (label_chunk_info[here].type != PART_SLICE) { 847 msg = "You can only do this in a master partition (see top of screen)"; 848 break; 849 } 850 sz = space_free(label_chunk_info[here].c); 851 if (sz <= FS_MIN_SIZE) { 852 msg = "Not enough space to create an additional FreeBSD partition"; 853 break; 854 } 855 else { 856 char *val; 857 int size; 858 struct chunk *tmp; 859 char osize[80]; 860 u_long flags = 0; 861 862 sprintf(osize, "%d", sz); 863 DialogX = 3; 864 DialogY = 2; 865 val = msgGetInput(osize, 866 "Please specify the partition size in blocks or append a trailing M for\n" 867 "megabytes or C for cylinders. %d blocks (%dMB) are free.", 868 sz, sz / ONE_MEG); 869 DialogX = DialogY = 0; 870 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 871 clear_wins(); 872 break; 873 } 874 875 if (*cp) { 876 if (toupper(*cp) == 'M') 877 size *= ONE_MEG; 878 else if (toupper(*cp) == 'C') 879 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 880 } 881 if (size <= FS_MIN_SIZE) { 882 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 883 clear_wins(); 884 break; 885 } 886 type = get_partition_type(); 887 if (type == PART_NONE) { 888 clear_wins(); 889 beep(); 890 break; 891 } 892 893 if (type == PART_FILESYSTEM) { 894 if ((p = get_mountpoint(NULL)) == NULL) { 895 clear_wins(); 896 beep(); 897 break; 898 } 899 else if (!strcmp(p->mountpoint, "/")) 900 flags |= CHUNK_IS_ROOT; 901 else 902 flags &= ~CHUNK_IS_ROOT; 903 } 904 else 905 p = NULL; 906 907 if ((flags & CHUNK_IS_ROOT)) { 908 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 909 msgConfirm("This region cannot be used for your root partition as the\n" 910 "FreeBSD boot code cannot deal with a root partition created\n" 911 "in that location. Please choose another location or smaller\n" 912 "size for your root partition and try again!"); 913 clear_wins(); 914 break; 915 } 916 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 917 msgConfirm("Warning: This is smaller than the recommended size for a\n" 918 "root partition. For a variety of reasons, root\n" 919 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 920 } 921 } 922 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 923 label_chunk_info[here].c, 924 size, part, 925 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 926 flags); 927 if (!tmp) { 928 msgConfirm("Unable to create the partition. Too big?"); 929 clear_wins(); 930 break; 931 } 932 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 933 msgConfirm("This region cannot be used for your root partition as it starts\n" 934 "or extends past the 1024'th cylinder mark and is thus a\n" 935 "poor location to boot from. Please choose another\n" 936 "location (or smaller size) for your root partition and try again!"); 937 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 938 clear_wins(); 939 break; 940 } 941 if (type != PART_SWAP) { 942 /* This is needed to tell the newfs -u about the size */ 943 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 944 safe_free(p); 945 } 946 else 947 tmp->private_data = p; 948 tmp->private_free = safe_free; 949 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 950 variable_set2(DISK_LABELLED, "yes"); 951 record_label_chunks(devs, dev); 952 clear_wins(); 953 /*** This is where we assign focus to new label so it shows ***/ 954 { 955 int i; 956 label_focus = -1; 957 for (i = 0; label_chunk_info[i].c; ++i) { 958 if (label_chunk_info[i].c == tmp) { 959 label_focus = i; 960 break; 961 } 962 } 963 if (label_focus == -1) 964 label_focus = i - 1; 965 } 966 } 967 break; 968 969 case KEY_DC: 970 case 'D': /* delete */ 971 if (label_chunk_info[here].type == PART_SLICE) { 972 msg = MSG_NOT_APPLICABLE; 973 break; 974 } 975 else if (label_chunk_info[here].type == PART_FAT) { 976 msg = "Use the Disk Partition Editor to delete DOS partitions"; 977 break; 978 } 979 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 980 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 981 variable_set2(DISK_LABELLED, "yes"); 982 record_label_chunks(devs, dev); 983 break; 984 985 case 'M': /* mount */ 986 switch(label_chunk_info[here].type) { 987 case PART_SLICE: 988 msg = MSG_NOT_APPLICABLE; 989 break; 990 991 case PART_SWAP: 992 msg = "You don't need to specify a mountpoint for a swap partition."; 993 break; 994 995 case PART_FAT: 996 case PART_FILESYSTEM: 997 oldp = label_chunk_info[here].c->private_data; 998 p = get_mountpoint(label_chunk_info[here].c); 999 if (p) { 1000 if (!oldp) 1001 p->newfs = FALSE; 1002 if (label_chunk_info[here].type == PART_FAT 1003 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1004 || !strcmp(p->mountpoint, "/var"))) { 1005 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1006 strcpy(p->mountpoint, "/bogus"); 1007 } 1008 } 1009 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1010 variable_set2(DISK_LABELLED, "yes"); 1011 record_label_chunks(devs, dev); 1012 clear_wins(); 1013 break; 1014 1015 default: 1016 msgFatal("Bogus partition under cursor???"); 1017 break; 1018 } 1019 break; 1020 1021 case 'N': /* Set newfs options */ 1022 if (label_chunk_info[here].c->private_data && 1023 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1024 getNewfsCmd(label_chunk_info[here].c->private_data); 1025 else 1026 msg = MSG_NOT_APPLICABLE; 1027 clear_wins(); 1028 break; 1029 1030 case 'T': /* Toggle newfs state */ 1031 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1032 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1033 label_chunk_info[here].c->private_data = 1034 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 1035 safe_free(pi); 1036 label_chunk_info[here].c->private_free = safe_free; 1037 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1038 variable_set2(DISK_LABELLED, "yes"); 1039 } 1040 else 1041 msg = MSG_NOT_APPLICABLE; 1042 break; 1043 1044 case 'U': 1045 clear(); 1046 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1047 msgConfirm("You've already written out your changes -\n" 1048 "it's too late to undo!"); 1049 } 1050 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 1051 variable_unset(DISK_PARTITIONED); 1052 variable_unset(DISK_LABELLED); 1053 for (i = 0; devs[i]; i++) { 1054 Disk *d; 1055 1056 if (!devs[i]->enabled) 1057 continue; 1058 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1059 Free_Disk(devs[i]->private); 1060 devs[i]->private = d; 1061 diskPartition(devs[i]); 1062 } 1063 } 1064 record_label_chunks(devs, dev); 1065 } 1066 clear_wins(); 1067 break; 1068 1069 case 'W': 1070 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1071 msgConfirm("You've already written out your changes - if you\n" 1072 "wish to overwrite them, you'll have to start this\n" 1073 "procedure again from the beginning."); 1074 } 1075 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 1076 "installation. If you are installing FreeBSD for the first time\n" 1077 "then you should simply type Q when you're finished here and your\n" 1078 "changes will be committed in one batch automatically at the end of\n" 1079 "these questions.\n\n" 1080 "Are you absolutely sure you want to do this now?")) { 1081 variable_set2(DISK_LABELLED, "yes"); 1082 diskLabelCommit(NULL); 1083 } 1084 clear_wins(); 1085 break; 1086 1087 case '|': 1088 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1089 "This is an entirely undocumented feature which you are not\n" 1090 "expected to understand!")) { 1091 int i; 1092 Device **devs; 1093 1094 dialog_clear(); 1095 end_dialog(); 1096 DialogActive = FALSE; 1097 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1098 if (!devs) { 1099 msgConfirm("Can't find any disk devices!"); 1100 break; 1101 } 1102 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1103 if (devs[i]->enabled) 1104 slice_wizard(((Disk *)devs[i]->private)); 1105 } 1106 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1107 variable_set2(DISK_LABELLED, "yes"); 1108 DialogActive = TRUE; 1109 record_label_chunks(devs, dev); 1110 clear_wins(); 1111 } 1112 else 1113 msg = "A most prudent choice!"; 1114 break; 1115 1116 case '\033': /* ESC */ 1117 case 'Q': 1118 labeling = FALSE; 1119 break; 1120 1121 default: 1122 beep(); 1123 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1124 msg = _msg; 1125 break; 1126 } 1127 if (label_chunk_info[here].type == PART_SLICE) 1128 pslice_focus = here; 1129 else 1130 label_focus = here; 1131 } 1132 return DITEM_SUCCESS | DITEM_RESTORE; 1133} 1134 1135static int 1136diskLabelNonInteractive(Device *dev) 1137{ 1138 char *cp; 1139 PartType type; 1140 PartInfo *p; 1141 u_long flags = 0; 1142 int i, status; 1143 Device **devs; 1144 Disk *d; 1145 1146 status = DITEM_SUCCESS; 1147 1148 cp = variable_get(VAR_DISK); 1149 if (!cp) { 1150 dialog_clear(); 1151 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1152 return DITEM_FAILURE; 1153 } 1154 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1155 if (!devs) { 1156 msgConfirm("diskLabel: No disk device %s found!", cp); 1157 return DITEM_FAILURE; 1158 } 1159 if (dev) 1160 d = dev->private; 1161 else 1162 d = devs[0]->private; 1163 record_label_chunks(devs, dev); 1164 for (i = 0; label_chunk_info[i].c; i++) { 1165 Chunk *c1 = label_chunk_info[i].c; 1166 1167 if (label_chunk_info[i].type == PART_SLICE) { 1168 char name[512]; 1169 int entries = 1; 1170 1171 while (entries) { 1172 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1173 if ((cp = variable_get(name)) != NULL) { 1174 int sz; 1175 char typ[10], mpoint[50]; 1176 1177 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 1178 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1179 status = DITEM_FAILURE; 1180 continue; 1181 } 1182 else { 1183 Chunk *tmp; 1184 1185 if (!strcmp(typ, "swap")) { 1186 type = PART_SWAP; 1187 strcpy(mpoint, "SWAP"); 1188 } 1189 else { 1190 type = PART_FILESYSTEM; 1191 if (!strcmp(mpoint, "/")) 1192 flags |= CHUNK_IS_ROOT; 1193 else 1194 flags &= ~CHUNK_IS_ROOT; 1195 } 1196 if (!sz) 1197 sz = space_free(c1); 1198 if (sz > space_free(c1)) { 1199 msgConfirm("Not enough free space to create partition: %s", mpoint); 1200 status = DITEM_FAILURE; 1201 continue; 1202 } 1203 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1204 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1205 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1206 status = DITEM_FAILURE; 1207 break; 1208 } 1209 else { 1210 tmp->private_data = new_part(mpoint, TRUE, sz); 1211 tmp->private_free = safe_free; 1212 status = DITEM_SUCCESS; 1213 } 1214 } 1215 entries++; 1216 } 1217 else { 1218 /* No more matches, leave the loop */ 1219 entries = 0; 1220 } 1221 } 1222 } 1223 else { 1224 /* Must be something we can set a mountpoint for */ 1225 cp = variable_get(c1->name); 1226 if (cp) { 1227 char mpoint[50], do_newfs[8]; 1228 Boolean newfs = FALSE; 1229 1230 do_newfs[0] = '\0'; 1231 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1232 dialog_clear(); 1233 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1234 status = DITEM_FAILURE; 1235 continue; 1236 } 1237 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1238 if (c1->private_data) { 1239 p = c1->private_data; 1240 p->newfs = newfs; 1241 strcpy(p->mountpoint, mpoint); 1242 } 1243 else { 1244 c1->private_data = new_part(mpoint, newfs, 0); 1245 c1->private_free = safe_free; 1246 } 1247 if (!strcmp(mpoint, "/")) 1248 c1->flags |= CHUNK_IS_ROOT; 1249 else 1250 c1->flags &= ~CHUNK_IS_ROOT; 1251 } 1252 } 1253 } 1254 if (status == DITEM_SUCCESS) 1255 variable_set2(DISK_LABELLED, "yes"); 1256 return status; 1257} 1258