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