label.c revision 43685
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.85 1999/01/29 11:39:04 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", 0); 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", 0); 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 647#ifdef __alpha__ 648 649/* 650 * If there isn't a freebsd chunk already (i.e. there is no label), 651 * dedicate the disk. 652 */ 653static void 654maybe_dedicate(Disk* d) 655{ 656 struct chunk *c; 657 658 for (c = d->chunks->part; c; c = c->next) { 659 if (c->type == freebsd) 660 break; 661 } 662 663 if (!c) { 664 msgDebug("dedicating disk"); 665 All_FreeBSD(d, 1); 666 } 667} 668 669#endif 670 671static int 672diskLabel(Device *dev) 673{ 674 int sz, key = 0; 675 Boolean labeling; 676 char *msg = NULL; 677 PartInfo *p, *oldp; 678 PartType type; 679 Device **devs; 680#ifdef __alpha__ 681 int i; 682#endif 683 684 label_focus = 0; 685 pslice_focus = 0; 686 here = 0; 687 688 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 689 if (!devs) { 690 msgConfirm("No disks found!"); 691 return DITEM_FAILURE; 692 } 693 labeling = TRUE; 694 keypad(stdscr, TRUE); 695#ifdef __alpha__ 696 for (i = 0; devs[i]; i++) { 697 maybe_dedicate((Disk*) devs[i]->private); 698 } 699#endif 700 record_label_chunks(devs, dev); 701 702 clear(); 703 while (labeling) { 704 char *cp; 705 706 print_label_chunks(); 707 print_command_summary(); 708 if (msg) { 709 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 710 clrtoeol(); 711 beep(); 712 msg = NULL; 713 } 714 else { 715 move(23, 0); 716 clrtoeol(); 717 } 718 719 refresh(); 720 key = getch(); 721 switch (toupper(key)) { 722 int i; 723 static char _msg[40]; 724 725 case '\014': /* ^L */ 726 clear_wins(); 727 break; 728 729 case '\020': /* ^P */ 730 case KEY_UP: 731 case '-': 732 if (here != 0) 733 --here; 734 else 735 while (label_chunk_info[here + 1].c) 736 ++here; 737 break; 738 739 case '\016': /* ^N */ 740 case KEY_DOWN: 741 case '+': 742 case '\r': 743 case '\n': 744 if (label_chunk_info[here + 1].c) 745 ++here; 746 else 747 here = 0; 748 break; 749 750 case KEY_HOME: 751 here = 0; 752 break; 753 754 case KEY_END: 755 while (label_chunk_info[here + 1].c) 756 ++here; 757 break; 758 759 case KEY_F(1): 760 case '?': 761 systemDisplayHelp("partition"); 762 clear_wins(); 763 break; 764 765 case 'A': 766 if (label_chunk_info[here].type != PART_SLICE) { 767 msg = "You can only do this in a disk slice (at top of screen)"; 768 break; 769 } 770 sz = space_free(label_chunk_info[here].c); 771 if (sz <= FS_MIN_SIZE) 772 msg = "Not enough free space to create a new partition in the slice"; 773 else { 774 struct chunk *tmp; 775 int mib[2]; 776 int physmem; 777 size_t size, swsize; 778 char *cp; 779 Chunk *rootdev, *swapdev, *usrdev, *vardev; 780 781 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 782 if (!rootdev) { 783 cp = variable_get(VAR_ROOT_SIZE); 784 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 785 (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 786 if (!tmp) { 787 msgConfirm("Unable to create the root partition. Too big?"); 788 clear_wins(); 789 break; 790 } 791 tmp->private_data = new_part("/", TRUE, tmp->size); 792 tmp->private_free = safe_free; 793 record_label_chunks(devs, dev); 794 } 795 796 if (!swapdev) { 797 cp = variable_get(VAR_SWAP_SIZE); 798 if (cp) 799 swsize = atoi(cp) * ONE_MEG; 800 else { 801 mib[0] = CTL_HW; 802 mib[1] = HW_PHYSMEM; 803 size = sizeof physmem; 804 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 805 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 806 } 807 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 808 swsize, part, FS_SWAP, 0); 809 if (!tmp) { 810 msgConfirm("Unable to create the swap partition. Too big?"); 811 clear_wins(); 812 break; 813 } 814 tmp->private_data = 0; 815 tmp->private_free = safe_free; 816 record_label_chunks(devs, dev); 817 } 818 819 if (!vardev) { 820 cp = variable_get(VAR_VAR_SIZE); 821 if (cp) 822 sz = atoi(cp) * ONE_MEG; 823 else 824 sz = variable_get(VAR_NO_USR) 825 ? space_free(label_chunk_info[here].c) 826 : VAR_MIN_SIZE * ONE_MEG; 827 828 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 829 sz, part, FS_BSDFFS, 0); 830 if (!tmp) { 831 msgConfirm("Less than %dMB free for /var - you will need to\n" 832 "partition your disk manually with a custom install!", 833 (cp ? atoi(cp) : VAR_MIN_SIZE)); 834 clear_wins(); 835 break; 836 } 837 tmp->private_data = new_part("/var", TRUE, tmp->size); 838 tmp->private_free = safe_free; 839 record_label_chunks(devs, dev); 840 } 841 842 if (!usrdev && !variable_get(VAR_NO_USR)) { 843 cp = variable_get(VAR_USR_SIZE); 844 if (cp) 845 sz = atoi(cp) * ONE_MEG; 846 else 847 sz = space_free(label_chunk_info[here].c); 848 if (sz) { 849 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 850 msgConfirm("Less than %dMB free for /usr - you will need to\n" 851 "partition your disk manually with a custom install!", USR_MIN_SIZE); 852 clear_wins(); 853 break; 854 } 855 856 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 857 label_chunk_info[here].c, 858 sz, part, FS_BSDFFS, 0); 859 if (!tmp) { 860 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 861 "You will need to partition your disk manually with a custom install!"); 862 clear_wins(); 863 break; 864 } 865 tmp->private_data = new_part("/usr", TRUE, tmp->size); 866 tmp->private_free = safe_free; 867 record_label_chunks(devs, dev); 868 } 869 } 870 871 /* At this point, we're reasonably "labelled" */ 872 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 873 variable_set2(DISK_LABELLED, "yes", 0); 874 } 875 break; 876 877 case 'C': 878 if (label_chunk_info[here].type != PART_SLICE) { 879 msg = "You can only do this in a master partition (see top of screen)"; 880 break; 881 } 882 sz = space_free(label_chunk_info[here].c); 883 if (sz <= FS_MIN_SIZE) { 884 msg = "Not enough space to create an additional FreeBSD partition"; 885 break; 886 } 887 else { 888 char *val; 889 int size; 890 struct chunk *tmp; 891 char osize[80]; 892 u_long flags = 0; 893 894 sprintf(osize, "%d", sz); 895 DialogX = 3; 896 DialogY = 2; 897 val = msgGetInput(osize, 898 "Please specify the partition size in blocks or append a trailing M for\n" 899 "megabytes or C for cylinders. %d blocks (%dMB) are free.", 900 sz, sz / ONE_MEG); 901 DialogX = DialogY = 0; 902 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 903 clear_wins(); 904 break; 905 } 906 907 if (*cp) { 908 if (toupper(*cp) == 'M') 909 size *= ONE_MEG; 910 else if (toupper(*cp) == 'C') 911 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 912 } 913 if (size <= FS_MIN_SIZE) { 914 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 915 clear_wins(); 916 break; 917 } 918 type = get_partition_type(); 919 if (type == PART_NONE) { 920 clear_wins(); 921 beep(); 922 break; 923 } 924 925 if (type == PART_FILESYSTEM) { 926 if ((p = get_mountpoint(NULL)) == NULL) { 927 clear_wins(); 928 beep(); 929 break; 930 } 931 else if (!strcmp(p->mountpoint, "/")) 932 flags |= CHUNK_IS_ROOT; 933 else 934 flags &= ~CHUNK_IS_ROOT; 935 } 936 else 937 p = NULL; 938 939 if ((flags & CHUNK_IS_ROOT)) { 940 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 941 msgConfirm("This region cannot be used for your root partition as the\n" 942 "FreeBSD boot code cannot deal with a root partition created\n" 943 "in that location. Please choose another location or smaller\n" 944 "size for your root partition and try again!"); 945 clear_wins(); 946 break; 947 } 948 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 949 msgConfirm("Warning: This is smaller than the recommended size for a\n" 950 "root partition. For a variety of reasons, root\n" 951 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 952 } 953 } 954 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 955 label_chunk_info[here].c, 956 size, part, 957 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 958 flags); 959 if (!tmp) { 960 msgConfirm("Unable to create the partition. Too big?"); 961 clear_wins(); 962 break; 963 } 964 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 965 msgConfirm("This region cannot be used for your root partition as it starts\n" 966 "or extends past the 1024'th cylinder mark and is thus a\n" 967 "poor location to boot from. Please choose another\n" 968 "location (or smaller size) for your root partition and try again!"); 969 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 970 clear_wins(); 971 break; 972 } 973 if (type != PART_SWAP) { 974 /* This is needed to tell the newfs -u about the size */ 975 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 976 safe_free(p); 977 } 978 else 979 tmp->private_data = p; 980 tmp->private_free = safe_free; 981 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 982 variable_set2(DISK_LABELLED, "yes", 0); 983 record_label_chunks(devs, dev); 984 clear_wins(); 985 /*** This is where we assign focus to new label so it shows ***/ 986 { 987 int i; 988 label_focus = -1; 989 for (i = 0; label_chunk_info[i].c; ++i) { 990 if (label_chunk_info[i].c == tmp) { 991 label_focus = i; 992 break; 993 } 994 } 995 if (label_focus == -1) 996 label_focus = i - 1; 997 } 998 } 999 break; 1000 1001 case KEY_DC: 1002 case 'D': /* delete */ 1003 if (label_chunk_info[here].type == PART_SLICE) { 1004 msg = MSG_NOT_APPLICABLE; 1005 break; 1006 } 1007 else if (label_chunk_info[here].type == PART_FAT) { 1008 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1009 break; 1010 } 1011 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 1012 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1013 variable_set2(DISK_LABELLED, "yes", 0); 1014 record_label_chunks(devs, dev); 1015 break; 1016 1017 case 'M': /* mount */ 1018 switch(label_chunk_info[here].type) { 1019 case PART_SLICE: 1020 msg = MSG_NOT_APPLICABLE; 1021 break; 1022 1023 case PART_SWAP: 1024 msg = "You don't need to specify a mountpoint for a swap partition."; 1025 break; 1026 1027 case PART_FAT: 1028 case PART_FILESYSTEM: 1029 oldp = label_chunk_info[here].c->private_data; 1030 p = get_mountpoint(label_chunk_info[here].c); 1031 if (p) { 1032 if (!oldp) 1033 p->newfs = FALSE; 1034 if (label_chunk_info[here].type == PART_FAT 1035 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1036 || !strcmp(p->mountpoint, "/var"))) { 1037 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1038 strcpy(p->mountpoint, "/bogus"); 1039 } 1040 } 1041 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1042 variable_set2(DISK_LABELLED, "yes", 0); 1043 record_label_chunks(devs, dev); 1044 clear_wins(); 1045 break; 1046 1047 default: 1048 msgFatal("Bogus partition under cursor???"); 1049 break; 1050 } 1051 break; 1052 1053 case 'N': /* Set newfs options */ 1054 if (label_chunk_info[here].c->private_data && 1055 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1056 getNewfsCmd(label_chunk_info[here].c->private_data); 1057 else 1058 msg = MSG_NOT_APPLICABLE; 1059 clear_wins(); 1060 break; 1061 1062 case 'T': /* Toggle newfs state */ 1063 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1064 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1065 label_chunk_info[here].c->private_data = 1066 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 1067 safe_free(pi); 1068 label_chunk_info[here].c->private_free = safe_free; 1069 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1070 variable_set2(DISK_LABELLED, "yes", 0); 1071 } 1072 else 1073 msg = MSG_NOT_APPLICABLE; 1074 break; 1075 1076 case 'U': 1077 clear(); 1078 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1079 msgConfirm("You've already written out your changes -\n" 1080 "it's too late to undo!"); 1081 } 1082 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 1083 variable_unset(DISK_PARTITIONED); 1084 variable_unset(DISK_LABELLED); 1085 for (i = 0; devs[i]; i++) { 1086 Disk *d; 1087 1088 if (!devs[i]->enabled) 1089 continue; 1090 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1091 Free_Disk(devs[i]->private); 1092 devs[i]->private = d; 1093 diskPartition(devs[i]); 1094 } 1095 } 1096 record_label_chunks(devs, dev); 1097 } 1098 clear_wins(); 1099 break; 1100 1101 case 'W': 1102 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1103 msgConfirm("You've already written out your changes - if you\n" 1104 "wish to overwrite them, you'll have to start this\n" 1105 "procedure again from the beginning."); 1106 } 1107 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 1108 "installation. If you are installing FreeBSD for the first time\n" 1109 "then you should simply type Q when you're finished here and your\n" 1110 "changes will be committed in one batch automatically at the end of\n" 1111 "these questions.\n\n" 1112 "Are you absolutely sure you want to do this now?")) { 1113 variable_set2(DISK_LABELLED, "yes", 0); 1114 diskLabelCommit(NULL); 1115 } 1116 clear_wins(); 1117 break; 1118 1119 case '|': 1120 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1121 "This is an entirely undocumented feature which you are not\n" 1122 "expected to understand!")) { 1123 int i; 1124 Device **devs; 1125 1126 dialog_clear(); 1127 end_dialog(); 1128 DialogActive = FALSE; 1129 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1130 if (!devs) { 1131 msgConfirm("Can't find any disk devices!"); 1132 break; 1133 } 1134 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1135 if (devs[i]->enabled) 1136 slice_wizard(((Disk *)devs[i]->private)); 1137 } 1138 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1139 variable_set2(DISK_LABELLED, "yes", 0); 1140 DialogActive = TRUE; 1141 record_label_chunks(devs, dev); 1142 clear_wins(); 1143 } 1144 else 1145 msg = "A most prudent choice!"; 1146 break; 1147 1148 case '\033': /* ESC */ 1149 case 'Q': 1150 labeling = FALSE; 1151 break; 1152 1153 default: 1154 beep(); 1155 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1156 msg = _msg; 1157 break; 1158 } 1159 if (label_chunk_info[here].type == PART_SLICE) 1160 pslice_focus = here; 1161 else 1162 label_focus = here; 1163 } 1164 return DITEM_SUCCESS | DITEM_RESTORE; 1165} 1166 1167static int 1168diskLabelNonInteractive(Device *dev) 1169{ 1170 char *cp; 1171 PartType type; 1172 PartInfo *p; 1173 u_long flags = 0; 1174 int i, status; 1175 Device **devs; 1176 Disk *d; 1177 1178 status = DITEM_SUCCESS; 1179 1180 cp = variable_get(VAR_DISK); 1181 if (!cp) { 1182 dialog_clear(); 1183 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1184 return DITEM_FAILURE; 1185 } 1186 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1187 if (!devs) { 1188 msgConfirm("diskLabel: No disk device %s found!", cp); 1189 return DITEM_FAILURE; 1190 } 1191 if (dev) 1192 d = dev->private; 1193 else 1194 d = devs[0]->private; 1195#ifdef __alpha__ 1196 maybe_dedicate(d); 1197#endif 1198 record_label_chunks(devs, dev); 1199 for (i = 0; label_chunk_info[i].c; i++) { 1200 Chunk *c1 = label_chunk_info[i].c; 1201 1202 if (label_chunk_info[i].type == PART_SLICE) { 1203 char name[512]; 1204 int entries = 1; 1205 1206 while (entries) { 1207 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1208 if ((cp = variable_get(name)) != NULL) { 1209 int sz; 1210 char typ[10], mpoint[50]; 1211 1212 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 1213 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1214 status = DITEM_FAILURE; 1215 continue; 1216 } 1217 else { 1218 Chunk *tmp; 1219 1220 if (!strcmp(typ, "swap")) { 1221 type = PART_SWAP; 1222 strcpy(mpoint, "SWAP"); 1223 } 1224 else { 1225 type = PART_FILESYSTEM; 1226 if (!strcmp(mpoint, "/")) 1227 flags |= CHUNK_IS_ROOT; 1228 else 1229 flags &= ~CHUNK_IS_ROOT; 1230 } 1231 if (!sz) 1232 sz = space_free(c1); 1233 if (sz > space_free(c1)) { 1234 msgConfirm("Not enough free space to create partition: %s", mpoint); 1235 status = DITEM_FAILURE; 1236 continue; 1237 } 1238 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1239 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1240 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1241 status = DITEM_FAILURE; 1242 break; 1243 } 1244 else { 1245 tmp->private_data = new_part(mpoint, TRUE, sz); 1246 tmp->private_free = safe_free; 1247 status = DITEM_SUCCESS; 1248 } 1249 } 1250 entries++; 1251 } 1252 else { 1253 /* No more matches, leave the loop */ 1254 entries = 0; 1255 } 1256 } 1257 } 1258 else { 1259 /* Must be something we can set a mountpoint for */ 1260 cp = variable_get(c1->name); 1261 if (cp) { 1262 char mpoint[50], do_newfs[8]; 1263 Boolean newfs = FALSE; 1264 1265 do_newfs[0] = '\0'; 1266 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1267 dialog_clear(); 1268 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1269 status = DITEM_FAILURE; 1270 continue; 1271 } 1272 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1273 if (c1->private_data) { 1274 p = c1->private_data; 1275 p->newfs = newfs; 1276 strcpy(p->mountpoint, mpoint); 1277 } 1278 else { 1279 c1->private_data = new_part(mpoint, newfs, 0); 1280 c1->private_free = safe_free; 1281 } 1282 if (!strcmp(mpoint, "/")) 1283 c1->flags |= CHUNK_IS_ROOT; 1284 else 1285 c1->flags &= ~CHUNK_IS_ROOT; 1286 } 1287 } 1288 } 1289 if (status == DITEM_SUCCESS) 1290 variable_set2(DISK_LABELLED, "yes", 0); 1291 return status; 1292} 1293