label.c revision 57617
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 * $FreeBSD: head/usr.sbin/sade/label.c 57617 2000-02-29 10:40:59Z jkh $ 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 70 67#else 68#define ROOT_DEFAULT_SIZE 50 69#endif 70 71/* The smallest swap partition we want to create by default */ 72#define SWAP_MIN_SIZE 32 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; 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 } 175 } 176 if (DITEM_STATUS(i) != DITEM_FAILURE) { 177 char *cp; 178 179 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 180 variable_set2(DISK_LABELLED, "yes", 0); 181 } 182 return i; 183} 184 185int 186diskLabelCommit(dialogMenuItem *self) 187{ 188 char *cp; 189 int i; 190 191 /* Already done? */ 192 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 193 i = DITEM_SUCCESS; 194 else if (!cp) { 195 msgConfirm("You must assign disk labels before this option can be used."); 196 i = DITEM_FAILURE; 197 } 198 /* The routine will guard against redundant writes, just as this one does */ 199 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 200 i = DITEM_FAILURE; 201 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 202 i = DITEM_FAILURE; 203 else { 204 msgInfo("All filesystem information written successfully."); 205 variable_set2(DISK_LABELLED, "written", 0); 206 i = DITEM_SUCCESS; 207 } 208 return i; 209} 210 211/* See if we're already using a desired partition name */ 212static Boolean 213check_conflict(char *name) 214{ 215 int i; 216 217 for (i = 0; label_chunk_info[i].c; i++) 218 if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) 219 && label_chunk_info[i].c->private_data 220 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 221 return TRUE; 222 return FALSE; 223} 224 225/* How much space is in this FreeBSD slice? */ 226static int 227space_free(struct chunk *c) 228{ 229 struct chunk *c1; 230 int sz = c->size; 231 232 for (c1 = c->part; c1; c1 = c1->next) { 233 if (c1->type != unused) 234 sz -= c1->size; 235 } 236 if (sz < 0) 237 msgFatal("Partitions are larger than actual chunk??"); 238 return sz; 239} 240 241/* Snapshot the current situation into the displayed chunks structure */ 242static void 243record_label_chunks(Device **devs, Device *dev) 244{ 245 int i, j, p; 246 struct chunk *c1, *c2; 247 Disk *d; 248 249 j = p = 0; 250 /* First buzz through and pick up the FreeBSD slices */ 251 for (i = 0; devs[i]; i++) { 252 if ((dev && devs[i] != dev) || !devs[i]->enabled) 253 continue; 254 d = (Disk *)devs[i]->private; 255 if (!d->chunks) 256 msgFatal("No chunk list found for %s!", d->name); 257 258 /* Put the slice entries first */ 259 for (c1 = d->chunks->part; c1; c1 = c1->next) { 260 if (c1->type == freebsd) { 261 label_chunk_info[j].type = PART_SLICE; 262 label_chunk_info[j].c = c1; 263 ++j; 264 } 265 } 266 } 267 268 /* Now run through again and get the FreeBSD partition entries */ 269 for (i = 0; devs[i]; i++) { 270 if (!devs[i]->enabled) 271 continue; 272 d = (Disk *)devs[i]->private; 273 /* Then buzz through and pick up the partitions */ 274 for (c1 = d->chunks->part; c1; c1 = c1->next) { 275 if (c1->type == freebsd) { 276 for (c2 = c1->part; c2; c2 = c2->next) { 277 if (c2->type == part) { 278 if (c2->subtype == FS_SWAP) 279 label_chunk_info[j].type = PART_SWAP; 280 else 281 label_chunk_info[j].type = PART_FILESYSTEM; 282 label_chunk_info[j].c = c2; 283 ++j; 284 } 285 } 286 } 287 else if (c1->type == fat) { 288 label_chunk_info[j].type = PART_FAT; 289 label_chunk_info[j].c = c1; 290 ++j; 291 } 292 } 293 } 294 label_chunk_info[j].c = NULL; 295 if (here >= j) { 296 here = j ? j - 1 : 0; 297 } 298} 299 300/* A new partition entry */ 301static PartInfo * 302new_part(char *mpoint, Boolean newfs, u_long size) 303{ 304 PartInfo *ret; 305 306 if (!mpoint) 307 mpoint = "/change_me"; 308 309 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 310 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); 311 strcpy(ret->newfs_cmd, "newfs "); 312 strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS)); 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 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 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 val = string_skipwhite(string_prune(val)); 367 tmp = new_part(val, TRUE, 0); 368 if (old) { 369 old->private_data = tmp; 370 old->private_free = safe_free; 371 } 372 return tmp; 373} 374 375/* Get the type of the new partiton */ 376static PartType 377get_partition_type(void) 378{ 379 char selection[20]; 380 int i; 381 static unsigned char *fs_types[] = { 382 "FS", 383 "A file system", 384 "Swap", 385 "A swap partition.", 386 }; 387 WINDOW *w = savescr(); 388 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 restorescr(w); 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 10 417 418#define PART_PART_COL 0 419#define PART_MOUNT_COL 10 420#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 421#define PART_NEWFS_COL (PART_SIZE_COL + 8) 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) + 3, "Size"); 476 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); 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, "%5ldMB", 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, 49, "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 653#ifdef __alpha__ 654 655/* 656 * If there isn't a freebsd chunk already (i.e. there is no label), 657 * dedicate the disk. 658 */ 659static void 660maybe_dedicate(Disk* d) 661{ 662 struct chunk *c; 663 664 for (c = d->chunks->part; c; c = c->next) { 665 if (c->type == freebsd) 666 break; 667 } 668 669 if (!c) { 670 msgDebug("dedicating disk"); 671 All_FreeBSD(d, 1); 672 } 673} 674 675#endif 676 677static int 678diskLabel(Device *dev) 679{ 680 int sz, key = 0; 681 Boolean labeling; 682 char *msg = NULL; 683 PartInfo *p, *oldp; 684 PartType type; 685 Device **devs; 686#ifdef __alpha__ 687 int i; 688#endif 689 WINDOW *w = savescr(); 690 691 label_focus = 0; 692 pslice_focus = 0; 693 here = 0; 694 695 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 696 if (!devs) { 697 msgConfirm("No disks found!"); 698 restorescr(w); 699 return DITEM_FAILURE; 700 } 701 labeling = TRUE; 702 keypad(stdscr, TRUE); 703#ifdef __alpha__ 704 for (i = 0; devs[i]; i++) { 705 maybe_dedicate((Disk*) devs[i]->private); 706 } 707#endif 708 record_label_chunks(devs, dev); 709 710 clear(); 711 while (labeling) { 712 char *cp; 713 714 print_label_chunks(); 715 print_command_summary(); 716 if (msg) { 717 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 718 clrtoeol(); 719 beep(); 720 msg = NULL; 721 } 722 else { 723 move(23, 0); 724 clrtoeol(); 725 } 726 727 refresh(); 728 key = getch(); 729 switch (toupper(key)) { 730 int i; 731 static char _msg[40]; 732 733 case '\014': /* ^L */ 734 clear_wins(); 735 break; 736 737 case '\020': /* ^P */ 738 case KEY_UP: 739 case '-': 740 if (here != 0) 741 --here; 742 else 743 while (label_chunk_info[here + 1].c) 744 ++here; 745 break; 746 747 case '\016': /* ^N */ 748 case KEY_DOWN: 749 case '+': 750 case '\r': 751 case '\n': 752 if (label_chunk_info[here + 1].c) 753 ++here; 754 else 755 here = 0; 756 break; 757 758 case KEY_HOME: 759 here = 0; 760 break; 761 762 case KEY_END: 763 while (label_chunk_info[here + 1].c) 764 ++here; 765 break; 766 767 case KEY_F(1): 768 case '?': 769 systemDisplayHelp("partition"); 770 clear_wins(); 771 break; 772 773 case 'A': 774 if (label_chunk_info[here].type != PART_SLICE) { 775 msg = "You can only do this in a disk slice (at top of screen)"; 776 break; 777 } 778 sz = space_free(label_chunk_info[here].c); 779 if (sz <= FS_MIN_SIZE) 780 msg = "Not enough free space to create a new partition in the slice"; 781 else { 782 struct chunk *tmp; 783 int mib[2]; 784 int physmem; 785 size_t size, swsize; 786 char *cp; 787 Chunk *rootdev, *swapdev, *usrdev, *vardev; 788 789 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 790 if (!rootdev) { 791 cp = variable_get(VAR_ROOT_SIZE); 792 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 793 (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 794 if (!tmp) { 795 msgConfirm("Unable to create the root partition. Too big?"); 796 clear_wins(); 797 break; 798 } 799 tmp->private_data = new_part("/", TRUE, tmp->size); 800 tmp->private_free = safe_free; 801 record_label_chunks(devs, dev); 802 } 803 804 if (!swapdev) { 805 cp = variable_get(VAR_SWAP_SIZE); 806 if (cp) 807 swsize = atoi(cp) * ONE_MEG; 808 else { 809 mib[0] = CTL_HW; 810 mib[1] = HW_PHYSMEM; 811 size = sizeof physmem; 812 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 813 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 814 } 815 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 816 swsize, part, FS_SWAP, 0); 817 if (!tmp) { 818 msgConfirm("Unable to create the swap partition. Too big?"); 819 clear_wins(); 820 break; 821 } 822 tmp->private_data = 0; 823 tmp->private_free = safe_free; 824 record_label_chunks(devs, dev); 825 } 826 827 if (!vardev) { 828 cp = variable_get(VAR_VAR_SIZE); 829 if (cp) 830 sz = atoi(cp) * ONE_MEG; 831 else 832 sz = variable_get(VAR_NO_USR) 833 ? space_free(label_chunk_info[here].c) 834 : VAR_MIN_SIZE * ONE_MEG; 835 836 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 837 sz, part, FS_BSDFFS, 0); 838 if (!tmp) { 839 msgConfirm("Less than %dMB free for /var - you will need to\n" 840 "partition your disk manually with a custom install!", 841 (cp ? atoi(cp) : VAR_MIN_SIZE)); 842 clear_wins(); 843 break; 844 } 845 tmp->private_data = new_part("/var", TRUE, tmp->size); 846 tmp->private_free = safe_free; 847 record_label_chunks(devs, dev); 848 } 849 850 if (!usrdev && !variable_get(VAR_NO_USR)) { 851 cp = variable_get(VAR_USR_SIZE); 852 if (cp) 853 sz = atoi(cp) * ONE_MEG; 854 else 855 sz = space_free(label_chunk_info[here].c); 856 if (sz) { 857 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 858 msgConfirm("Less than %dMB free for /usr - you will need to\n" 859 "partition your disk manually with a custom install!", USR_MIN_SIZE); 860 clear_wins(); 861 break; 862 } 863 864 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 865 label_chunk_info[here].c, 866 sz, part, FS_BSDFFS, 0); 867 if (!tmp) { 868 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 869 "You will need to partition your disk manually with a custom install!"); 870 clear_wins(); 871 break; 872 } 873 tmp->private_data = new_part("/usr", TRUE, tmp->size); 874 tmp->private_free = safe_free; 875 record_label_chunks(devs, dev); 876 } 877 } 878 879 /* At this point, we're reasonably "labelled" */ 880 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 881 variable_set2(DISK_LABELLED, "yes", 0); 882 } 883 break; 884 885 case 'C': 886 if (label_chunk_info[here].type != PART_SLICE) { 887 msg = "You can only do this in a master partition (see top of screen)"; 888 break; 889 } 890 sz = space_free(label_chunk_info[here].c); 891 if (sz <= FS_MIN_SIZE) { 892 msg = "Not enough space to create an additional FreeBSD partition"; 893 break; 894 } 895 else { 896 char *val; 897 int size; 898 struct chunk *tmp; 899 char osize[80]; 900 u_long flags = 0; 901 902 sprintf(osize, "%d", sz); 903 val = msgGetInput(osize, 904 "Please specify the partition size in blocks or append a trailing G for\n" 905 "gigabytes, M for megabytes, or C for cylinders.\n" 906 "%d blocks (%dMB) are free.", 907 sz, sz / ONE_MEG); 908 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 909 clear_wins(); 910 break; 911 } 912 913 if (*cp) { 914 if (toupper(*cp) == 'M') 915 size *= ONE_MEG; 916 else if (toupper(*cp) == 'G') 917 size *= ONE_GIG; 918 else if (toupper(*cp) == 'C') 919 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 920 } 921 if (size <= FS_MIN_SIZE) { 922 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 923 clear_wins(); 924 break; 925 } 926 type = get_partition_type(); 927 if (type == PART_NONE) { 928 clear_wins(); 929 beep(); 930 break; 931 } 932 933 if (type == PART_FILESYSTEM) { 934 if ((p = get_mountpoint(NULL)) == NULL) { 935 clear_wins(); 936 beep(); 937 break; 938 } 939 else if (!strcmp(p->mountpoint, "/")) 940 flags |= CHUNK_IS_ROOT; 941 else 942 flags &= ~CHUNK_IS_ROOT; 943 } 944 else 945 p = NULL; 946 947 if ((flags & CHUNK_IS_ROOT)) { 948 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 949 msgConfirm("This region cannot be used for your root partition as the\n" 950 "FreeBSD boot code cannot deal with a root partition created\n" 951 "in that location. Please choose another location or smaller\n" 952 "size for your root partition and try again!"); 953 clear_wins(); 954 break; 955 } 956 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 957 msgConfirm("Warning: This is smaller than the recommended size for a\n" 958 "root partition. For a variety of reasons, root\n" 959 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 960 } 961 } 962 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 963 label_chunk_info[here].c, 964 size, part, 965 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 966 flags); 967 if (!tmp) { 968 msgConfirm("Unable to create the partition. Too big?"); 969 clear_wins(); 970 break; 971 } 972 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 973 msgConfirm("This region cannot be used for your root partition as it starts\n" 974 "or extends past the 1024'th cylinder mark and is thus a\n" 975 "poor location to boot from. Please choose another\n" 976 "location (or smaller size) for your root partition and try again!"); 977 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 978 clear_wins(); 979 break; 980 } 981 if (type != PART_SWAP) { 982 /* This is needed to tell the newfs -u about the size */ 983 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 984 safe_free(p); 985 } 986 else 987 tmp->private_data = p; 988 tmp->private_free = safe_free; 989 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 990 variable_set2(DISK_LABELLED, "yes", 0); 991 record_label_chunks(devs, dev); 992 clear_wins(); 993 /*** This is where we assign focus to new label so it shows ***/ 994 { 995 int i; 996 label_focus = -1; 997 for (i = 0; label_chunk_info[i].c; ++i) { 998 if (label_chunk_info[i].c == tmp) { 999 label_focus = i; 1000 break; 1001 } 1002 } 1003 if (label_focus == -1) 1004 label_focus = i - 1; 1005 } 1006 } 1007 break; 1008 1009 case KEY_DC: 1010 case 'D': /* delete */ 1011 if (label_chunk_info[here].type == PART_SLICE) { 1012 msg = MSG_NOT_APPLICABLE; 1013 break; 1014 } 1015 else if (label_chunk_info[here].type == PART_FAT) { 1016 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1017 break; 1018 } 1019 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 1020 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1021 variable_set2(DISK_LABELLED, "yes", 0); 1022 record_label_chunks(devs, dev); 1023 break; 1024 1025 case 'M': /* mount */ 1026 switch(label_chunk_info[here].type) { 1027 case PART_SLICE: 1028 msg = MSG_NOT_APPLICABLE; 1029 break; 1030 1031 case PART_SWAP: 1032 msg = "You don't need to specify a mountpoint for a swap partition."; 1033 break; 1034 1035 case PART_FAT: 1036 case PART_FILESYSTEM: 1037 oldp = label_chunk_info[here].c->private_data; 1038 p = get_mountpoint(label_chunk_info[here].c); 1039 if (p) { 1040 if (!oldp) 1041 p->newfs = FALSE; 1042 if (label_chunk_info[here].type == PART_FAT 1043 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1044 || !strcmp(p->mountpoint, "/var"))) { 1045 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1046 strcpy(p->mountpoint, "/bogus"); 1047 } 1048 } 1049 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1050 variable_set2(DISK_LABELLED, "yes", 0); 1051 record_label_chunks(devs, dev); 1052 clear_wins(); 1053 break; 1054 1055 default: 1056 msgFatal("Bogus partition under cursor???"); 1057 break; 1058 } 1059 break; 1060 1061 case 'N': /* Set newfs options */ 1062 if (label_chunk_info[here].c->private_data && 1063 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1064 getNewfsCmd(label_chunk_info[here].c->private_data); 1065 else 1066 msg = MSG_NOT_APPLICABLE; 1067 clear_wins(); 1068 break; 1069 1070 case 'T': /* Toggle newfs state */ 1071 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1072 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1073 label_chunk_info[here].c->private_data = 1074 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 1075 safe_free(pi); 1076 label_chunk_info[here].c->private_free = safe_free; 1077 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1078 variable_set2(DISK_LABELLED, "yes", 0); 1079 } 1080 else 1081 msg = MSG_NOT_APPLICABLE; 1082 break; 1083 1084 case 'U': 1085 clear(); 1086 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1087 msgConfirm("You've already written out your changes -\n" 1088 "it's too late to undo!"); 1089 } 1090 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 1091 variable_unset(DISK_PARTITIONED); 1092 variable_unset(DISK_LABELLED); 1093 for (i = 0; devs[i]; i++) { 1094 Disk *d; 1095 1096 if (!devs[i]->enabled) 1097 continue; 1098 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1099 Free_Disk(devs[i]->private); 1100 devs[i]->private = d; 1101 diskPartition(devs[i]); 1102 } 1103 } 1104 record_label_chunks(devs, dev); 1105 } 1106 clear_wins(); 1107 break; 1108 1109 case 'W': 1110 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1111 msgConfirm("You've already written out your changes - if you\n" 1112 "wish to overwrite them, you'll have to start this\n" 1113 "procedure again from the beginning."); 1114 } 1115 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 1116 "installation. If you are installing FreeBSD for the first time\n" 1117 "then you should simply type Q when you're finished here and your\n" 1118 "changes will be committed in one batch automatically at the end of\n" 1119 "these questions.\n\n" 1120 "Are you absolutely sure you want to do this now?")) { 1121 variable_set2(DISK_LABELLED, "yes", 0); 1122 diskLabelCommit(NULL); 1123 } 1124 clear_wins(); 1125 break; 1126 1127 case '|': 1128 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1129 "This is an entirely undocumented feature which you are not\n" 1130 "expected to understand!")) { 1131 int i; 1132 Device **devs; 1133 1134 dialog_clear(); 1135 end_dialog(); 1136 DialogActive = FALSE; 1137 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1138 if (!devs) { 1139 msgConfirm("Can't find any disk devices!"); 1140 break; 1141 } 1142 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1143 if (devs[i]->enabled) 1144 slice_wizard(((Disk *)devs[i]->private)); 1145 } 1146 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1147 variable_set2(DISK_LABELLED, "yes", 0); 1148 DialogActive = TRUE; 1149 record_label_chunks(devs, dev); 1150 clear_wins(); 1151 } 1152 else 1153 msg = "A most prudent choice!"; 1154 break; 1155 1156 case '\033': /* ESC */ 1157 case 'Q': 1158 labeling = FALSE; 1159 break; 1160 1161 default: 1162 beep(); 1163 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1164 msg = _msg; 1165 break; 1166 } 1167 if (label_chunk_info[here].type == PART_SLICE) 1168 pslice_focus = here; 1169 else 1170 label_focus = here; 1171 } 1172 restorescr(w); 1173 return DITEM_SUCCESS; 1174} 1175 1176static int 1177diskLabelNonInteractive(Device *dev) 1178{ 1179 char *cp; 1180 PartType type; 1181 PartInfo *p; 1182 u_long flags = 0; 1183 int i, status; 1184 Device **devs; 1185 Disk *d; 1186 1187 status = DITEM_SUCCESS; 1188 cp = variable_get(VAR_DISK); 1189 if (!cp) { 1190 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1191 return DITEM_FAILURE; 1192 } 1193 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1194 if (!devs) { 1195 msgConfirm("diskLabel: No disk device %s found!", cp); 1196 return DITEM_FAILURE; 1197 } 1198 if (dev) 1199 d = dev->private; 1200 else 1201 d = devs[0]->private; 1202#ifdef __alpha__ 1203 maybe_dedicate(d); 1204#endif 1205 record_label_chunks(devs, dev); 1206 for (i = 0; label_chunk_info[i].c; i++) { 1207 Chunk *c1 = label_chunk_info[i].c; 1208 1209 if (label_chunk_info[i].type == PART_SLICE) { 1210 char name[512]; 1211 int entries = 1; 1212 1213 while (entries) { 1214 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1215 if ((cp = variable_get(name)) != NULL) { 1216 int sz; 1217 char typ[10], mpoint[50]; 1218 1219 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 1220 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1221 status = DITEM_FAILURE; 1222 continue; 1223 } 1224 else { 1225 Chunk *tmp; 1226 1227 if (!strcmp(typ, "swap")) { 1228 type = PART_SWAP; 1229 strcpy(mpoint, "SWAP"); 1230 } 1231 else { 1232 type = PART_FILESYSTEM; 1233 if (!strcmp(mpoint, "/")) 1234 flags |= CHUNK_IS_ROOT; 1235 else 1236 flags &= ~CHUNK_IS_ROOT; 1237 } 1238 if (!sz) 1239 sz = space_free(c1); 1240 if (sz > space_free(c1)) { 1241 msgConfirm("Not enough free space to create partition: %s", mpoint); 1242 status = DITEM_FAILURE; 1243 continue; 1244 } 1245 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1246 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1247 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1248 status = DITEM_FAILURE; 1249 break; 1250 } 1251 else { 1252 tmp->private_data = new_part(mpoint, TRUE, sz); 1253 tmp->private_free = safe_free; 1254 status = DITEM_SUCCESS; 1255 } 1256 } 1257 entries++; 1258 } 1259 else { 1260 /* No more matches, leave the loop */ 1261 entries = 0; 1262 } 1263 } 1264 } 1265 else { 1266 /* Must be something we can set a mountpoint for */ 1267 cp = variable_get(c1->name); 1268 if (cp) { 1269 char mpoint[50], do_newfs[8]; 1270 Boolean newfs = FALSE; 1271 1272 do_newfs[0] = '\0'; 1273 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1274 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1275 status = DITEM_FAILURE; 1276 continue; 1277 } 1278 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1279 if (c1->private_data) { 1280 p = c1->private_data; 1281 p->newfs = newfs; 1282 strcpy(p->mountpoint, mpoint); 1283 } 1284 else { 1285 c1->private_data = new_part(mpoint, newfs, 0); 1286 c1->private_free = safe_free; 1287 } 1288 if (!strcmp(mpoint, "/")) 1289 c1->flags |= CHUNK_IS_ROOT; 1290 else 1291 c1->flags &= ~CHUNK_IS_ROOT; 1292 } 1293 } 1294 } 1295 if (status == DITEM_SUCCESS) 1296 variable_set2(DISK_LABELLED, "yes", 0); 1297 return status; 1298} 1299