label.c revision 54716
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 54716 1999-12-17 02:02:51Z 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 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 val = string_skipwhite(string_prune(val)); 372 tmp = new_part(val, TRUE, 0); 373 if (old) { 374 old->private_data = tmp; 375 old->private_free = safe_free; 376 } 377 return tmp; 378} 379 380/* Get the type of the new partiton */ 381static PartType 382get_partition_type(void) 383{ 384 char selection[20]; 385 int i; 386 static unsigned char *fs_types[] = { 387 "FS", 388 "A file system", 389 "Swap", 390 "A swap partition.", 391 }; 392 WINDOW *w = savescr(); 393 394 DialogX = 7; 395 DialogY = 8; 396 i = dialog_menu("Please choose a partition type", 397 "If you want to use this partition for swap space, select Swap.\n" 398 "If you want to put a filesystem on it, choose FS.", 399 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 400 DialogX = DialogY = 0; 401 restorescr(w); 402 if (!i) { 403 if (!strcmp(selection, "FS")) 404 return PART_FILESYSTEM; 405 else if (!strcmp(selection, "Swap")) 406 return PART_SWAP; 407 } 408 return PART_NONE; 409} 410 411/* If the user wants a special newfs command for this, set it */ 412static void 413getNewfsCmd(PartInfo *p) 414{ 415 char *val; 416 417 val = msgGetInput(p->newfs_cmd, 418 "Please enter the newfs command and options you'd like to use in\n" 419 "creating this file system."); 420 if (val) 421 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 422} 423 424#define MAX_MOUNT_NAME 10 425 426#define PART_PART_COL 0 427#define PART_MOUNT_COL 10 428#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 429#define PART_NEWFS_COL (PART_SIZE_COL + 8) 430#define PART_OFF 38 431 432#define TOTAL_AVAIL_LINES (10) 433#define PSLICE_SHOWABLE (4) 434 435 436/* stick this all up on the screen */ 437static void 438print_label_chunks(void) 439{ 440 int i, j, srow, prow, pcol; 441 int sz; 442 char clrmsg[80]; 443 int ChunkPartStartRow; 444 WINDOW *ChunkWin; 445 446 /********************************************************/ 447 /*** These values are for controling screen resources ***/ 448 /*** Each label line holds up to 2 labels, so beware! ***/ 449 /*** strategy will be to try to always make sure the ***/ 450 /*** highlighted label is in the active display area. ***/ 451 /********************************************************/ 452 int pslice_max, label_max; 453 int pslice_count, label_count, label_focus_found, pslice_focus_found; 454 455 attrset(A_REVERSE); 456 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 457 attrset(A_NORMAL); 458 459 /*** Count the number of parition slices ***/ 460 pslice_count = 0; 461 for (i = 0; label_chunk_info[i].c ; i++) { 462 if (label_chunk_info[i].type == PART_SLICE) 463 ++pslice_count; 464 } 465 pslice_max = pslice_count; 466 467 /*** 4 line max for partition slices ***/ 468 if (pslice_max > PSLICE_SHOWABLE) { 469 pslice_max = PSLICE_SHOWABLE; 470 } 471 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; 472 473 /*** View partition slices modulo pslice_max ***/ 474 label_max = TOTAL_AVAIL_LINES - pslice_max; 475 476 for (i = 0; i < 2; i++) { 477 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 478 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 479 480 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 481 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 482 483 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); 484 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); 485 486 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 487 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 488 } 489 srow = CHUNK_SLICE_START_ROW; 490 prow = 0; 491 pcol = 0; 492 493 /*** these variables indicate that the focused item is shown currently ***/ 494 label_focus_found = 0; 495 pslice_focus_found = 0; 496 497 label_count = 0; 498 pslice_count = 0; 499 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 500 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 501 502 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 503 504 wclear(ChunkWin); 505 /*** wrefresh(ChunkWin); ***/ 506 507 for (i = 0; label_chunk_info[i].c; i++) { 508 /* Is it a slice entry displayed at the top? */ 509 if (label_chunk_info[i].type == PART_SLICE) { 510 /*** This causes the new pslice to replace the previous display ***/ 511 /*** focus must remain on the most recently active pslice ***/ 512 if (pslice_count == pslice_max) { 513 if (pslice_focus_found) { 514 /*** This is where we can mark the more following ***/ 515 attrset(A_BOLD); 516 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 517 attrset(A_NORMAL); 518 continue; 519 } 520 else { 521 /*** this is where we set the more previous ***/ 522 attrset(A_BOLD); 523 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 524 attrset(A_NORMAL); 525 pslice_count = 0; 526 srow = CHUNK_SLICE_START_ROW; 527 } 528 } 529 530 sz = space_free(label_chunk_info[i].c); 531 if (i == here) 532 attrset(ATTR_SELECTED); 533 if (i == pslice_focus) 534 pslice_focus_found = -1; 535 536 mvprintw(srow++, 0, 537 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 538 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, 539 sz, (sz / ONE_MEG)); 540 attrset(A_NORMAL); 541 clrtoeol(); 542 move(0, 0); 543 /*** refresh(); ***/ 544 ++pslice_count; 545 } 546 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 547 else { 548 char onestr[PART_OFF], num[10], *mountpoint, *newfs; 549 550 /* 551 * We copy this into a blank-padded string so that it looks like 552 * a solid bar in reverse-video 553 */ 554 memset(onestr, ' ', PART_OFF - 1); 555 onestr[PART_OFF - 1] = '\0'; 556 557 /*** Track how many labels have been displayed ***/ 558 if (label_count == ((label_max - 1 ) * 2)) { 559 if (label_focus_found) { 560 continue; 561 } 562 else { 563 label_count = 0; 564 prow = 0; 565 pcol = 0; 566 } 567 } 568 569 /* Go for two columns if we've written one full columns worth */ 570 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 571 if (label_count == label_max - 1) { 572 pcol = PART_OFF; 573 prow = 0; 574 } 575 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 576 /* If it's a filesystem, display the mountpoint */ 577 if (label_chunk_info[i].c->private_data 578 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 579 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 580 else if (label_chunk_info[i].type == PART_SWAP) 581 mountpoint = "swap"; 582 else 583 mountpoint = "<none>"; 584 585 /* Now display the newfs field */ 586 if (label_chunk_info[i].type == PART_FAT) 587 newfs = "DOS"; 588 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 589 newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 590 else if (label_chunk_info[i].type == PART_SWAP) 591 newfs = "SWAP"; 592 else 593 newfs = "*"; 594 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 595 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 596 snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 597 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 598 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 599 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 600 if (i == label_focus) { 601 label_focus_found = -1; 602 wattrset(ChunkWin, A_BOLD); 603 } 604 if (i == here) 605 wattrset(ChunkWin, ATTR_SELECTED); 606 607 /*** lazy man's way of padding this string ***/ 608 while (strlen( onestr ) < 37) 609 strcat(onestr, " "); 610 611 mvwaddstr(ChunkWin, prow, pcol, onestr); 612 wattrset(ChunkWin, A_NORMAL); 613 move(0, 0); 614 ++prow; 615 ++label_count; 616 } 617 } 618 619 /*** this will erase all the extra stuff ***/ 620 memset(clrmsg, ' ', 37); 621 clrmsg[37] = '\0'; 622 623 while (pslice_count < pslice_max) { 624 mvprintw(srow++, 0, clrmsg); 625 clrtoeol(); 626 ++pslice_count; 627 } 628 while (label_count < (2 * (label_max - 1))) { 629 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 630 ++label_count; 631 if (prow == (label_max - 1)) { 632 prow = 0; 633 pcol = PART_OFF; 634 } 635 } 636 refresh(); 637 wrefresh(ChunkWin); 638} 639 640static void 641print_command_summary(void) 642{ 643 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 644 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 645 if (!RunningAsInit) 646 mvprintw(18, 49, "W = Write"); 647 mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 648 mvprintw(20, 0, "A = Auto Defaults for all!"); 649 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 650 move(0, 0); 651} 652 653static void 654clear_wins(void) 655{ 656 extern void print_label_chunks(); 657 clear(); 658 print_label_chunks(); 659} 660 661#ifdef __alpha__ 662 663/* 664 * If there isn't a freebsd chunk already (i.e. there is no label), 665 * dedicate the disk. 666 */ 667static void 668maybe_dedicate(Disk* d) 669{ 670 struct chunk *c; 671 672 for (c = d->chunks->part; c; c = c->next) { 673 if (c->type == freebsd) 674 break; 675 } 676 677 if (!c) { 678 msgDebug("dedicating disk"); 679 All_FreeBSD(d, 1); 680 } 681} 682 683#endif 684 685static int 686diskLabel(Device *dev) 687{ 688 int sz, key = 0; 689 Boolean labeling; 690 char *msg = NULL; 691 PartInfo *p, *oldp; 692 PartType type; 693 Device **devs; 694#ifdef __alpha__ 695 int i; 696#endif 697 WINDOW *w = savescr(); 698 699 label_focus = 0; 700 pslice_focus = 0; 701 here = 0; 702 703 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 704 if (!devs) { 705 msgConfirm("No disks found!"); 706 restorescr(w); 707 return DITEM_FAILURE; 708 } 709 labeling = TRUE; 710 keypad(stdscr, TRUE); 711#ifdef __alpha__ 712 for (i = 0; devs[i]; i++) { 713 maybe_dedicate((Disk*) devs[i]->private); 714 } 715#endif 716 record_label_chunks(devs, dev); 717 718 clear(); 719 while (labeling) { 720 char *cp; 721 722 print_label_chunks(); 723 print_command_summary(); 724 if (msg) { 725 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 726 clrtoeol(); 727 beep(); 728 msg = NULL; 729 } 730 else { 731 move(23, 0); 732 clrtoeol(); 733 } 734 735 refresh(); 736 key = getch(); 737 switch (toupper(key)) { 738 int i; 739 static char _msg[40]; 740 741 case '\014': /* ^L */ 742 clear_wins(); 743 break; 744 745 case '\020': /* ^P */ 746 case KEY_UP: 747 case '-': 748 if (here != 0) 749 --here; 750 else 751 while (label_chunk_info[here + 1].c) 752 ++here; 753 break; 754 755 case '\016': /* ^N */ 756 case KEY_DOWN: 757 case '+': 758 case '\r': 759 case '\n': 760 if (label_chunk_info[here + 1].c) 761 ++here; 762 else 763 here = 0; 764 break; 765 766 case KEY_HOME: 767 here = 0; 768 break; 769 770 case KEY_END: 771 while (label_chunk_info[here + 1].c) 772 ++here; 773 break; 774 775 case KEY_F(1): 776 case '?': 777 systemDisplayHelp("partition"); 778 clear_wins(); 779 break; 780 781 case 'A': 782 if (label_chunk_info[here].type != PART_SLICE) { 783 msg = "You can only do this in a disk slice (at top of screen)"; 784 break; 785 } 786 sz = space_free(label_chunk_info[here].c); 787 if (sz <= FS_MIN_SIZE) 788 msg = "Not enough free space to create a new partition in the slice"; 789 else { 790 struct chunk *tmp; 791 int mib[2]; 792 int physmem; 793 size_t size, swsize; 794 char *cp; 795 Chunk *rootdev, *swapdev, *usrdev, *vardev; 796 797 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 798 if (!rootdev) { 799 cp = variable_get(VAR_ROOT_SIZE); 800 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 801 (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 802 if (!tmp) { 803 msgConfirm("Unable to create the root partition. Too big?"); 804 clear_wins(); 805 break; 806 } 807 tmp->private_data = new_part("/", TRUE, tmp->size); 808 tmp->private_free = safe_free; 809 record_label_chunks(devs, dev); 810 } 811 812 if (!swapdev) { 813 cp = variable_get(VAR_SWAP_SIZE); 814 if (cp) 815 swsize = atoi(cp) * ONE_MEG; 816 else { 817 mib[0] = CTL_HW; 818 mib[1] = HW_PHYSMEM; 819 size = sizeof physmem; 820 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 821 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 822 } 823 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 824 swsize, part, FS_SWAP, 0); 825 if (!tmp) { 826 msgConfirm("Unable to create the swap partition. Too big?"); 827 clear_wins(); 828 break; 829 } 830 tmp->private_data = 0; 831 tmp->private_free = safe_free; 832 record_label_chunks(devs, dev); 833 } 834 835 if (!vardev) { 836 cp = variable_get(VAR_VAR_SIZE); 837 if (cp) 838 sz = atoi(cp) * ONE_MEG; 839 else 840 sz = variable_get(VAR_NO_USR) 841 ? space_free(label_chunk_info[here].c) 842 : VAR_MIN_SIZE * ONE_MEG; 843 844 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 845 sz, part, FS_BSDFFS, 0); 846 if (!tmp) { 847 msgConfirm("Less than %dMB free for /var - you will need to\n" 848 "partition your disk manually with a custom install!", 849 (cp ? atoi(cp) : VAR_MIN_SIZE)); 850 clear_wins(); 851 break; 852 } 853 tmp->private_data = new_part("/var", TRUE, tmp->size); 854 tmp->private_free = safe_free; 855 record_label_chunks(devs, dev); 856 } 857 858 if (!usrdev && !variable_get(VAR_NO_USR)) { 859 cp = variable_get(VAR_USR_SIZE); 860 if (cp) 861 sz = atoi(cp) * ONE_MEG; 862 else 863 sz = space_free(label_chunk_info[here].c); 864 if (sz) { 865 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 866 msgConfirm("Less than %dMB free for /usr - you will need to\n" 867 "partition your disk manually with a custom install!", USR_MIN_SIZE); 868 clear_wins(); 869 break; 870 } 871 872 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 873 label_chunk_info[here].c, 874 sz, part, FS_BSDFFS, 0); 875 if (!tmp) { 876 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 877 "You will need to partition your disk manually with a custom install!"); 878 clear_wins(); 879 break; 880 } 881 tmp->private_data = new_part("/usr", TRUE, tmp->size); 882 tmp->private_free = safe_free; 883 record_label_chunks(devs, dev); 884 } 885 } 886 887 /* At this point, we're reasonably "labelled" */ 888 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 889 variable_set2(DISK_LABELLED, "yes", 0); 890 } 891 break; 892 893 case 'C': 894 if (label_chunk_info[here].type != PART_SLICE) { 895 msg = "You can only do this in a master partition (see top of screen)"; 896 break; 897 } 898 sz = space_free(label_chunk_info[here].c); 899 if (sz <= FS_MIN_SIZE) { 900 msg = "Not enough space to create an additional FreeBSD partition"; 901 break; 902 } 903 else { 904 char *val; 905 int size; 906 struct chunk *tmp; 907 char osize[80]; 908 u_long flags = 0; 909 910 sprintf(osize, "%d", sz); 911 DialogX = 3; 912 DialogY = 2; 913 val = msgGetInput(osize, 914 "Please specify the partition size in blocks or append a trailing M for\n" 915 "megabytes or C for cylinders. %d blocks (%dMB) are free.", 916 sz, sz / ONE_MEG); 917 DialogX = DialogY = 0; 918 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 919 clear_wins(); 920 break; 921 } 922 923 if (*cp) { 924 if (toupper(*cp) == 'M') 925 size *= ONE_MEG; 926 else if (toupper(*cp) == 'C') 927 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 928 } 929 if (size <= FS_MIN_SIZE) { 930 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 931 clear_wins(); 932 break; 933 } 934 type = get_partition_type(); 935 if (type == PART_NONE) { 936 clear_wins(); 937 beep(); 938 break; 939 } 940 941 if (type == PART_FILESYSTEM) { 942 if ((p = get_mountpoint(NULL)) == NULL) { 943 clear_wins(); 944 beep(); 945 break; 946 } 947 else if (!strcmp(p->mountpoint, "/")) 948 flags |= CHUNK_IS_ROOT; 949 else 950 flags &= ~CHUNK_IS_ROOT; 951 } 952 else 953 p = NULL; 954 955 if ((flags & CHUNK_IS_ROOT)) { 956 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 957 msgConfirm("This region cannot be used for your root partition as the\n" 958 "FreeBSD boot code cannot deal with a root partition created\n" 959 "in that location. Please choose another location or smaller\n" 960 "size for your root partition and try again!"); 961 clear_wins(); 962 break; 963 } 964 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 965 msgConfirm("Warning: This is smaller than the recommended size for a\n" 966 "root partition. For a variety of reasons, root\n" 967 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 968 } 969 } 970 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 971 label_chunk_info[here].c, 972 size, part, 973 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 974 flags); 975 if (!tmp) { 976 msgConfirm("Unable to create the partition. Too big?"); 977 clear_wins(); 978 break; 979 } 980 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 981 msgConfirm("This region cannot be used for your root partition as it starts\n" 982 "or extends past the 1024'th cylinder mark and is thus a\n" 983 "poor location to boot from. Please choose another\n" 984 "location (or smaller size) for your root partition and try again!"); 985 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 986 clear_wins(); 987 break; 988 } 989 if (type != PART_SWAP) { 990 /* This is needed to tell the newfs -u about the size */ 991 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 992 safe_free(p); 993 } 994 else 995 tmp->private_data = p; 996 tmp->private_free = safe_free; 997 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 998 variable_set2(DISK_LABELLED, "yes", 0); 999 record_label_chunks(devs, dev); 1000 clear_wins(); 1001 /*** This is where we assign focus to new label so it shows ***/ 1002 { 1003 int i; 1004 label_focus = -1; 1005 for (i = 0; label_chunk_info[i].c; ++i) { 1006 if (label_chunk_info[i].c == tmp) { 1007 label_focus = i; 1008 break; 1009 } 1010 } 1011 if (label_focus == -1) 1012 label_focus = i - 1; 1013 } 1014 } 1015 break; 1016 1017 case KEY_DC: 1018 case 'D': /* delete */ 1019 if (label_chunk_info[here].type == PART_SLICE) { 1020 msg = MSG_NOT_APPLICABLE; 1021 break; 1022 } 1023 else if (label_chunk_info[here].type == PART_FAT) { 1024 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1025 break; 1026 } 1027 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 1028 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1029 variable_set2(DISK_LABELLED, "yes", 0); 1030 record_label_chunks(devs, dev); 1031 break; 1032 1033 case 'M': /* mount */ 1034 switch(label_chunk_info[here].type) { 1035 case PART_SLICE: 1036 msg = MSG_NOT_APPLICABLE; 1037 break; 1038 1039 case PART_SWAP: 1040 msg = "You don't need to specify a mountpoint for a swap partition."; 1041 break; 1042 1043 case PART_FAT: 1044 case PART_FILESYSTEM: 1045 oldp = label_chunk_info[here].c->private_data; 1046 p = get_mountpoint(label_chunk_info[here].c); 1047 if (p) { 1048 if (!oldp) 1049 p->newfs = FALSE; 1050 if (label_chunk_info[here].type == PART_FAT 1051 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1052 || !strcmp(p->mountpoint, "/var"))) { 1053 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1054 strcpy(p->mountpoint, "/bogus"); 1055 } 1056 } 1057 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1058 variable_set2(DISK_LABELLED, "yes", 0); 1059 record_label_chunks(devs, dev); 1060 clear_wins(); 1061 break; 1062 1063 default: 1064 msgFatal("Bogus partition under cursor???"); 1065 break; 1066 } 1067 break; 1068 1069 case 'N': /* Set newfs options */ 1070 if (label_chunk_info[here].c->private_data && 1071 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1072 getNewfsCmd(label_chunk_info[here].c->private_data); 1073 else 1074 msg = MSG_NOT_APPLICABLE; 1075 clear_wins(); 1076 break; 1077 1078 case 'T': /* Toggle newfs state */ 1079 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1080 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1081 label_chunk_info[here].c->private_data = 1082 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 1083 safe_free(pi); 1084 label_chunk_info[here].c->private_free = safe_free; 1085 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1086 variable_set2(DISK_LABELLED, "yes", 0); 1087 } 1088 else 1089 msg = MSG_NOT_APPLICABLE; 1090 break; 1091 1092 case 'U': 1093 clear(); 1094 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1095 msgConfirm("You've already written out your changes -\n" 1096 "it's too late to undo!"); 1097 } 1098 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 1099 variable_unset(DISK_PARTITIONED); 1100 variable_unset(DISK_LABELLED); 1101 for (i = 0; devs[i]; i++) { 1102 Disk *d; 1103 1104 if (!devs[i]->enabled) 1105 continue; 1106 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1107 Free_Disk(devs[i]->private); 1108 devs[i]->private = d; 1109 diskPartition(devs[i]); 1110 } 1111 } 1112 record_label_chunks(devs, dev); 1113 } 1114 clear_wins(); 1115 break; 1116 1117 case 'W': 1118 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1119 msgConfirm("You've already written out your changes - if you\n" 1120 "wish to overwrite them, you'll have to start this\n" 1121 "procedure again from the beginning."); 1122 } 1123 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 1124 "installation. If you are installing FreeBSD for the first time\n" 1125 "then you should simply type Q when you're finished here and your\n" 1126 "changes will be committed in one batch automatically at the end of\n" 1127 "these questions.\n\n" 1128 "Are you absolutely sure you want to do this now?")) { 1129 variable_set2(DISK_LABELLED, "yes", 0); 1130 diskLabelCommit(NULL); 1131 } 1132 clear_wins(); 1133 break; 1134 1135 case '|': 1136 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1137 "This is an entirely undocumented feature which you are not\n" 1138 "expected to understand!")) { 1139 int i; 1140 Device **devs; 1141 1142 dialog_clear(); 1143 end_dialog(); 1144 DialogActive = FALSE; 1145 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1146 if (!devs) { 1147 msgConfirm("Can't find any disk devices!"); 1148 break; 1149 } 1150 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1151 if (devs[i]->enabled) 1152 slice_wizard(((Disk *)devs[i]->private)); 1153 } 1154 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1155 variable_set2(DISK_LABELLED, "yes", 0); 1156 DialogActive = TRUE; 1157 record_label_chunks(devs, dev); 1158 clear_wins(); 1159 } 1160 else 1161 msg = "A most prudent choice!"; 1162 break; 1163 1164 case '\033': /* ESC */ 1165 case 'Q': 1166 labeling = FALSE; 1167 break; 1168 1169 default: 1170 beep(); 1171 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1172 msg = _msg; 1173 break; 1174 } 1175 if (label_chunk_info[here].type == PART_SLICE) 1176 pslice_focus = here; 1177 else 1178 label_focus = here; 1179 } 1180 restorescr(w); 1181 return DITEM_SUCCESS; 1182} 1183 1184static int 1185diskLabelNonInteractive(Device *dev) 1186{ 1187 char *cp; 1188 PartType type; 1189 PartInfo *p; 1190 u_long flags = 0; 1191 int i, status; 1192 Device **devs; 1193 Disk *d; 1194 1195 status = DITEM_SUCCESS; 1196 cp = variable_get(VAR_DISK); 1197 if (!cp) { 1198 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1199 return DITEM_FAILURE; 1200 } 1201 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1202 if (!devs) { 1203 msgConfirm("diskLabel: No disk device %s found!", cp); 1204 return DITEM_FAILURE; 1205 } 1206 if (dev) 1207 d = dev->private; 1208 else 1209 d = devs[0]->private; 1210#ifdef __alpha__ 1211 maybe_dedicate(d); 1212#endif 1213 record_label_chunks(devs, dev); 1214 for (i = 0; label_chunk_info[i].c; i++) { 1215 Chunk *c1 = label_chunk_info[i].c; 1216 1217 if (label_chunk_info[i].type == PART_SLICE) { 1218 char name[512]; 1219 int entries = 1; 1220 1221 while (entries) { 1222 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1223 if ((cp = variable_get(name)) != NULL) { 1224 int sz; 1225 char typ[10], mpoint[50]; 1226 1227 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 1228 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1229 status = DITEM_FAILURE; 1230 continue; 1231 } 1232 else { 1233 Chunk *tmp; 1234 1235 if (!strcmp(typ, "swap")) { 1236 type = PART_SWAP; 1237 strcpy(mpoint, "SWAP"); 1238 } 1239 else { 1240 type = PART_FILESYSTEM; 1241 if (!strcmp(mpoint, "/")) 1242 flags |= CHUNK_IS_ROOT; 1243 else 1244 flags &= ~CHUNK_IS_ROOT; 1245 } 1246 if (!sz) 1247 sz = space_free(c1); 1248 if (sz > space_free(c1)) { 1249 msgConfirm("Not enough free space to create partition: %s", mpoint); 1250 status = DITEM_FAILURE; 1251 continue; 1252 } 1253 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1254 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1255 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1256 status = DITEM_FAILURE; 1257 break; 1258 } 1259 else { 1260 tmp->private_data = new_part(mpoint, TRUE, sz); 1261 tmp->private_free = safe_free; 1262 status = DITEM_SUCCESS; 1263 } 1264 } 1265 entries++; 1266 } 1267 else { 1268 /* No more matches, leave the loop */ 1269 entries = 0; 1270 } 1271 } 1272 } 1273 else { 1274 /* Must be something we can set a mountpoint for */ 1275 cp = variable_get(c1->name); 1276 if (cp) { 1277 char mpoint[50], do_newfs[8]; 1278 Boolean newfs = FALSE; 1279 1280 do_newfs[0] = '\0'; 1281 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1282 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1283 status = DITEM_FAILURE; 1284 continue; 1285 } 1286 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1287 if (c1->private_data) { 1288 p = c1->private_data; 1289 p->newfs = newfs; 1290 strcpy(p->mountpoint, mpoint); 1291 } 1292 else { 1293 c1->private_data = new_part(mpoint, newfs, 0); 1294 c1->private_free = safe_free; 1295 } 1296 if (!strcmp(mpoint, "/")) 1297 c1->flags |= CHUNK_IS_ROOT; 1298 else 1299 c1->flags &= ~CHUNK_IS_ROOT; 1300 } 1301 } 1302 } 1303 if (status == DITEM_SUCCESS) 1304 variable_set2(DISK_LABELLED, "yes", 0); 1305 return status; 1306} 1307