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