label.c revision 74086
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 74086 2001-03-10 19:51:04Z 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 110 67#else 68#define ROOT_DEFAULT_SIZE 100 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 ret->soft = 0; 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 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 332 if (!val || !*val) { 333 if (!old) 334 return NULL; 335 else { 336 free(old->private_data); 337 old->private_data = NULL; 338 } 339 return NULL; 340 } 341 342 /* Is it just the same value? */ 343 if (tmp && !strcmp(tmp->mountpoint, val)) 344 return NULL; 345 346 /* Did we use it already? */ 347 if (check_conflict(val)) { 348 msgConfirm("You already have a mount point for %s assigned!", val); 349 return NULL; 350 } 351 352 /* Is it bogus? */ 353 if (*val != '/') { 354 msgConfirm("Mount point must start with a / character"); 355 return NULL; 356 } 357 358 /* Is it going to be mounted on root? */ 359 if (!strcmp(val, "/")) { 360 if (old) 361 old->flags |= CHUNK_IS_ROOT; 362 } 363 else if (old) 364 old->flags &= ~CHUNK_IS_ROOT; 365 366 safe_free(tmp); 367 val = string_skipwhite(string_prune(val)); 368 tmp = new_part(val, TRUE, 0); 369 if (old) { 370 old->private_data = tmp; 371 old->private_free = safe_free; 372 } 373 return tmp; 374} 375 376/* Get the type of the new partiton */ 377static PartType 378get_partition_type(void) 379{ 380 char selection[20]; 381 int i; 382 static unsigned char *fs_types[] = { 383 "FS", 384 "A file system", 385 "Swap", 386 "A swap partition.", 387 }; 388 WINDOW *w = savescr(); 389 390 i = dialog_menu("Please choose a partition type", 391 "If you want to use this partition for swap space, select Swap.\n" 392 "If you want to put a filesystem on it, choose FS.", 393 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 394 restorescr(w); 395 if (!i) { 396 if (!strcmp(selection, "FS")) 397 return PART_FILESYSTEM; 398 else if (!strcmp(selection, "Swap")) 399 return PART_SWAP; 400 } 401 return PART_NONE; 402} 403 404/* If the user wants a special newfs command for this, set it */ 405static void 406getNewfsCmd(PartInfo *p) 407{ 408 char *val; 409 410 val = msgGetInput(p->newfs_cmd, 411 "Please enter the newfs command and options you'd like to use in\n" 412 "creating this file system."); 413 if (val) 414 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 415} 416 417#define MAX_MOUNT_NAME 10 418 419#define PART_PART_COL 0 420#define PART_MOUNT_COL 10 421#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 422#define PART_NEWFS_COL (PART_SIZE_COL + 8) 423#define PART_OFF 38 424 425#define TOTAL_AVAIL_LINES (10) 426#define PSLICE_SHOWABLE (4) 427 428 429/* stick this all up on the screen */ 430static void 431print_label_chunks(void) 432{ 433 int i, j, srow, prow, pcol; 434 int sz; 435 char clrmsg[80]; 436 int ChunkPartStartRow; 437 WINDOW *ChunkWin; 438 439 /********************************************************/ 440 /*** These values are for controling screen resources ***/ 441 /*** Each label line holds up to 2 labels, so beware! ***/ 442 /*** strategy will be to try to always make sure the ***/ 443 /*** highlighted label is in the active display area. ***/ 444 /********************************************************/ 445 int pslice_max, label_max; 446 int pslice_count, label_count, label_focus_found, pslice_focus_found; 447 448 attrset(A_REVERSE); 449 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 450 attrset(A_NORMAL); 451 452 /*** Count the number of parition slices ***/ 453 pslice_count = 0; 454 for (i = 0; label_chunk_info[i].c ; i++) { 455 if (label_chunk_info[i].type == PART_SLICE) 456 ++pslice_count; 457 } 458 pslice_max = pslice_count; 459 460 /*** 4 line max for partition slices ***/ 461 if (pslice_max > PSLICE_SHOWABLE) { 462 pslice_max = PSLICE_SHOWABLE; 463 } 464 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; 465 466 /*** View partition slices modulo pslice_max ***/ 467 label_max = TOTAL_AVAIL_LINES - pslice_max; 468 469 for (i = 0; i < 2; i++) { 470 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 471 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 472 473 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 474 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 475 476 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); 477 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); 478 479 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 480 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 481 } 482 srow = CHUNK_SLICE_START_ROW; 483 prow = 0; 484 pcol = 0; 485 486 /*** these variables indicate that the focused item is shown currently ***/ 487 label_focus_found = 0; 488 pslice_focus_found = 0; 489 490 label_count = 0; 491 pslice_count = 0; 492 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 493 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 494 495 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 496 497 wclear(ChunkWin); 498 /*** wrefresh(ChunkWin); ***/ 499 500 for (i = 0; label_chunk_info[i].c; i++) { 501 /* Is it a slice entry displayed at the top? */ 502 if (label_chunk_info[i].type == PART_SLICE) { 503 /*** This causes the new pslice to replace the previous display ***/ 504 /*** focus must remain on the most recently active pslice ***/ 505 if (pslice_count == pslice_max) { 506 if (pslice_focus_found) { 507 /*** This is where we can mark the more following ***/ 508 attrset(A_BOLD); 509 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 510 attrset(A_NORMAL); 511 continue; 512 } 513 else { 514 /*** this is where we set the more previous ***/ 515 attrset(A_BOLD); 516 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 517 attrset(A_NORMAL); 518 pslice_count = 0; 519 srow = CHUNK_SLICE_START_ROW; 520 } 521 } 522 523 sz = space_free(label_chunk_info[i].c); 524 if (i == here) 525 attrset(ATTR_SELECTED); 526 if (i == pslice_focus) 527 pslice_focus_found = -1; 528 529 mvprintw(srow++, 0, 530 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 531 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, 532 sz, (sz / ONE_MEG)); 533 attrset(A_NORMAL); 534 clrtoeol(); 535 move(0, 0); 536 /*** refresh(); ***/ 537 ++pslice_count; 538 } 539 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 540 else { 541 char onestr[PART_OFF], num[10], *mountpoint, newfs[10]; 542 543 /* 544 * We copy this into a blank-padded string so that it looks like 545 * a solid bar in reverse-video 546 */ 547 memset(onestr, ' ', PART_OFF - 1); 548 onestr[PART_OFF - 1] = '\0'; 549 550 /*** Track how many labels have been displayed ***/ 551 if (label_count == ((label_max - 1 ) * 2)) { 552 if (label_focus_found) { 553 continue; 554 } 555 else { 556 label_count = 0; 557 prow = 0; 558 pcol = 0; 559 } 560 } 561 562 /* Go for two columns if we've written one full columns worth */ 563 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 564 if (label_count == label_max - 1) { 565 pcol = PART_OFF; 566 prow = 0; 567 } 568 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 569 /* If it's a filesystem, display the mountpoint */ 570 if (label_chunk_info[i].c->private_data 571 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 572 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 573 else if (label_chunk_info[i].type == PART_SWAP) 574 mountpoint = "swap"; 575 else 576 mountpoint = "<none>"; 577 578 /* Now display the newfs field */ 579 if (label_chunk_info[i].type == PART_FAT) 580 strcpy(newfs, "DOS"); 581 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) { 582 strcpy(newfs, "UFS"); 583 if (((PartInfo *)label_chunk_info[i].c->private_data)->soft) 584 strcat(newfs, "+S"); 585 strcat(newfs, ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? " Y" : " N"); 586 } 587 else if (label_chunk_info[i].type == PART_SWAP) 588 strcpy(newfs, "SWAP"); 589 else 590 strcpy(newfs, "*"); 591 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 592 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 593 snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 594 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 595 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 596 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 597 if (i == label_focus) { 598 label_focus_found = -1; 599 wattrset(ChunkWin, A_BOLD); 600 } 601 if (i == here) 602 wattrset(ChunkWin, ATTR_SELECTED); 603 604 /*** lazy man's way of expensively padding this string ***/ 605 while (strlen(onestr) < 37) 606 strcat(onestr, " "); 607 608 mvwaddstr(ChunkWin, prow, pcol, onestr); 609 wattrset(ChunkWin, A_NORMAL); 610 move(0, 0); 611 ++prow; 612 ++label_count; 613 } 614 } 615 616 /*** this will erase all the extra stuff ***/ 617 memset(clrmsg, ' ', 37); 618 clrmsg[37] = '\0'; 619 620 while (pslice_count < pslice_max) { 621 mvprintw(srow++, 0, clrmsg); 622 clrtoeol(); 623 ++pslice_count; 624 } 625 while (label_count < (2 * (label_max - 1))) { 626 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 627 ++label_count; 628 if (prow == (label_max - 1)) { 629 prow = 0; 630 pcol = PART_OFF; 631 } 632 } 633 refresh(); 634 wrefresh(ChunkWin); 635} 636 637static void 638print_command_summary(void) 639{ 640 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 641 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 642 if (!RunningAsInit) 643 mvprintw(18, 47, "W = Write"); 644 mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates"); 645 mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults"); 646 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 647 move(0, 0); 648} 649 650static void 651clear_wins(void) 652{ 653 extern void print_label_chunks(); 654 clear(); 655 print_label_chunks(); 656} 657 658#ifdef __alpha__ 659 660/* 661 * If there isn't a freebsd chunk already (i.e. there is no label), 662 * dedicate the disk. 663 */ 664static void 665maybe_dedicate(Disk* d) 666{ 667 struct chunk *c; 668 669 for (c = d->chunks->part; c; c = c->next) { 670 if (c->type == freebsd) 671 break; 672 } 673 674 if (!c) { 675 msgDebug("dedicating disk"); 676 All_FreeBSD(d, 1); 677 } 678} 679 680#endif 681 682static int 683diskLabel(Device *dev) 684{ 685 int sz, key = 0; 686 Boolean labeling; 687 char *msg = NULL; 688 PartInfo *p, *oldp; 689 PartType type; 690 Device **devs; 691#ifdef __alpha__ 692 int i; 693#endif 694 WINDOW *w = savescr(); 695 696 label_focus = 0; 697 pslice_focus = 0; 698 here = 0; 699 700 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 701 if (!devs) { 702 msgConfirm("No disks found!"); 703 restorescr(w); 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 val = msgGetInput(osize, 909 "Please specify the partition size in blocks or append a trailing G for\n" 910 "gigabytes, M for megabytes, or C for cylinders.\n" 911 "%d blocks (%dMB) are free.", 912 sz, sz / ONE_MEG); 913 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 914 clear_wins(); 915 break; 916 } 917 918 if (*cp) { 919 if (toupper(*cp) == 'M') 920 size *= ONE_MEG; 921 else if (toupper(*cp) == 'G') 922 size *= ONE_GIG; 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 (type != PART_SWAP) { 978 /* This is needed to tell the newfs -u about the size */ 979 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 980 safe_free(p); 981 } 982 else 983 tmp->private_data = p; 984 tmp->private_free = safe_free; 985 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 986 variable_set2(DISK_LABELLED, "yes", 0); 987 record_label_chunks(devs, dev); 988 clear_wins(); 989 /*** This is where we assign focus to new label so it shows ***/ 990 { 991 int i; 992 label_focus = -1; 993 for (i = 0; label_chunk_info[i].c; ++i) { 994 if (label_chunk_info[i].c == tmp) { 995 label_focus = i; 996 break; 997 } 998 } 999 if (label_focus == -1) 1000 label_focus = i - 1; 1001 } 1002 } 1003 break; 1004 1005 case KEY_DC: 1006 case 'D': /* delete */ 1007 if (label_chunk_info[here].type == PART_SLICE) { 1008 msg = MSG_NOT_APPLICABLE; 1009 break; 1010 } 1011 else if (label_chunk_info[here].type == PART_FAT) { 1012 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1013 break; 1014 } 1015 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 1016 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1017 variable_set2(DISK_LABELLED, "yes", 0); 1018 record_label_chunks(devs, dev); 1019 break; 1020 1021 case 'M': /* mount */ 1022 switch(label_chunk_info[here].type) { 1023 case PART_SLICE: 1024 msg = MSG_NOT_APPLICABLE; 1025 break; 1026 1027 case PART_SWAP: 1028 msg = "You don't need to specify a mountpoint for a swap partition."; 1029 break; 1030 1031 case PART_FAT: 1032 case PART_FILESYSTEM: 1033 oldp = label_chunk_info[here].c->private_data; 1034 p = get_mountpoint(label_chunk_info[here].c); 1035 if (p) { 1036 if (!oldp) 1037 p->newfs = FALSE; 1038 if (label_chunk_info[here].type == PART_FAT 1039 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1040 || !strcmp(p->mountpoint, "/var"))) { 1041 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1042 strcpy(p->mountpoint, "/bogus"); 1043 } 1044 } 1045 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1046 variable_set2(DISK_LABELLED, "yes", 0); 1047 record_label_chunks(devs, dev); 1048 clear_wins(); 1049 break; 1050 1051 default: 1052 msgFatal("Bogus partition under cursor???"); 1053 break; 1054 } 1055 break; 1056 1057 case 'N': /* Set newfs options */ 1058 if (label_chunk_info[here].c->private_data && 1059 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1060 getNewfsCmd(label_chunk_info[here].c->private_data); 1061 else 1062 msg = MSG_NOT_APPLICABLE; 1063 clear_wins(); 1064 break; 1065 1066 case 'S': /* Toggle soft updates flag */ 1067 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1068 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1069 if (pi) 1070 pi->soft = !pi->soft; 1071 else 1072 msg = MSG_NOT_APPLICABLE; 1073 } 1074 break; 1075 1076 case 'T': /* Toggle newfs state */ 1077 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1078 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1079 label_chunk_info[here].c->private_data = 1080 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 1081 safe_free(pi); 1082 label_chunk_info[here].c->private_free = safe_free; 1083 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1084 variable_set2(DISK_LABELLED, "yes", 0); 1085 } 1086 else 1087 msg = MSG_NOT_APPLICABLE; 1088 break; 1089 1090 case 'U': 1091 clear(); 1092 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1093 msgConfirm("You've already written out your changes -\n" 1094 "it's too late to undo!"); 1095 } 1096 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 1097 variable_unset(DISK_PARTITIONED); 1098 variable_unset(DISK_LABELLED); 1099 for (i = 0; devs[i]; i++) { 1100 Disk *d; 1101 1102 if (!devs[i]->enabled) 1103 continue; 1104 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1105 Free_Disk(devs[i]->private); 1106 devs[i]->private = d; 1107 diskPartition(devs[i]); 1108 } 1109 } 1110 record_label_chunks(devs, dev); 1111 } 1112 clear_wins(); 1113 break; 1114 1115 case 'W': 1116 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1117 msgConfirm("You've already written out your changes - if you\n" 1118 "wish to overwrite them, you'll have to start this\n" 1119 "procedure again from the beginning."); 1120 } 1121 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 1122 "installation. If you are installing FreeBSD for the first time\n" 1123 "then you should simply type Q when you're finished here and your\n" 1124 "changes will be committed in one batch automatically at the end of\n" 1125 "these questions.\n\n" 1126 "Are you absolutely sure you want to do this now?")) { 1127 variable_set2(DISK_LABELLED, "yes", 0); 1128 diskLabelCommit(NULL); 1129 } 1130 clear_wins(); 1131 break; 1132 1133 case '|': 1134 if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" 1135 "This is an entirely undocumented feature which you are not\n" 1136 "expected to understand!")) { 1137 int i; 1138 Device **devs; 1139 1140 dialog_clear(); 1141 end_dialog(); 1142 DialogActive = FALSE; 1143 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1144 if (!devs) { 1145 msgConfirm("Can't find any disk devices!"); 1146 break; 1147 } 1148 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1149 if (devs[i]->enabled) 1150 slice_wizard(((Disk *)devs[i]->private)); 1151 } 1152 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1153 variable_set2(DISK_LABELLED, "yes", 0); 1154 DialogActive = TRUE; 1155 record_label_chunks(devs, dev); 1156 clear_wins(); 1157 } 1158 else 1159 msg = "A most prudent choice!"; 1160 break; 1161 1162 case '\033': /* ESC */ 1163 case 'Q': 1164 labeling = FALSE; 1165 break; 1166 1167 default: 1168 beep(); 1169 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1170 msg = _msg; 1171 break; 1172 } 1173 if (label_chunk_info[here].type == PART_SLICE) 1174 pslice_focus = here; 1175 else 1176 label_focus = here; 1177 } 1178 restorescr(w); 1179 return DITEM_SUCCESS; 1180} 1181 1182static int 1183diskLabelNonInteractive(Device *dev) 1184{ 1185 char *cp; 1186 PartType type; 1187 PartInfo *p; 1188 u_long flags = 0; 1189 int i, status; 1190 Device **devs; 1191 Disk *d; 1192 1193 status = DITEM_SUCCESS; 1194 cp = variable_get(VAR_DISK); 1195 if (!cp) { 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 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1281 status = DITEM_FAILURE; 1282 continue; 1283 } 1284 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1285 if (c1->private_data) { 1286 p = c1->private_data; 1287 p->newfs = newfs; 1288 strcpy(p->mountpoint, mpoint); 1289 } 1290 else { 1291 c1->private_data = new_part(mpoint, newfs, 0); 1292 c1->private_free = safe_free; 1293 } 1294 if (!strcmp(mpoint, "/")) 1295 c1->flags |= CHUNK_IS_ROOT; 1296 else 1297 c1->flags &= ~CHUNK_IS_ROOT; 1298 } 1299 } 1300 } 1301 if (status == DITEM_SUCCESS) 1302 variable_set2(DISK_LABELLED, "yes", 0); 1303 return status; 1304} 1305