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