label.c revision 74156
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 74156 2001-03-12 10:18:54Z 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 if (variable_cmp(DISK_LABELLED, "written")) 178 variable_set2(DISK_LABELLED, "yes", 0); 179 } 180 return i; 181} 182 183int 184diskLabelCommit(dialogMenuItem *self) 185{ 186 char *cp; 187 int i; 188 189 /* Already done? */ 190 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 191 i = DITEM_SUCCESS; 192 else if (!cp) { 193 msgConfirm("You must assign disk labels before this option can be used."); 194 i = DITEM_FAILURE; 195 } 196 /* The routine will guard against redundant writes, just as this one does */ 197 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 198 i = DITEM_FAILURE; 199 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 200 i = DITEM_FAILURE; 201 else { 202 msgInfo("All filesystem information written successfully."); 203 variable_set2(DISK_LABELLED, "written", 0); 204 i = DITEM_SUCCESS; 205 } 206 return i; 207} 208 209/* See if we're already using a desired partition name */ 210static Boolean 211check_conflict(char *name) 212{ 213 int i; 214 215 for (i = 0; label_chunk_info[i].c; i++) 216 if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) 217 && label_chunk_info[i].c->private_data 218 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 219 return TRUE; 220 return FALSE; 221} 222 223/* How much space is in this FreeBSD slice? */ 224static int 225space_free(struct chunk *c) 226{ 227 struct chunk *c1; 228 int sz = c->size; 229 230 for (c1 = c->part; c1; c1 = c1->next) { 231 if (c1->type != unused) 232 sz -= c1->size; 233 } 234 if (sz < 0) 235 msgFatal("Partitions are larger than actual chunk??"); 236 return sz; 237} 238 239/* Snapshot the current situation into the displayed chunks structure */ 240static void 241record_label_chunks(Device **devs, Device *dev) 242{ 243 int i, j, p; 244 struct chunk *c1, *c2; 245 Disk *d; 246 247 j = p = 0; 248 /* First buzz through and pick up the FreeBSD slices */ 249 for (i = 0; devs[i]; i++) { 250 if ((dev && devs[i] != dev) || !devs[i]->enabled) 251 continue; 252 d = (Disk *)devs[i]->private; 253 if (!d->chunks) 254 msgFatal("No chunk list found for %s!", d->name); 255 256 /* Put the slice entries first */ 257 for (c1 = d->chunks->part; c1; c1 = c1->next) { 258 if (c1->type == freebsd) { 259 label_chunk_info[j].type = PART_SLICE; 260 label_chunk_info[j].c = c1; 261 ++j; 262 } 263 } 264 } 265 266 /* Now run through again and get the FreeBSD partition entries */ 267 for (i = 0; devs[i]; i++) { 268 if (!devs[i]->enabled) 269 continue; 270 d = (Disk *)devs[i]->private; 271 /* Then buzz through and pick up the partitions */ 272 for (c1 = d->chunks->part; c1; c1 = c1->next) { 273 if (c1->type == freebsd) { 274 for (c2 = c1->part; c2; c2 = c2->next) { 275 if (c2->type == part) { 276 if (c2->subtype == FS_SWAP) 277 label_chunk_info[j].type = PART_SWAP; 278 else 279 label_chunk_info[j].type = PART_FILESYSTEM; 280 label_chunk_info[j].c = c2; 281 ++j; 282 } 283 } 284 } 285 else if (c1->type == fat) { 286 label_chunk_info[j].type = PART_FAT; 287 label_chunk_info[j].c = c1; 288 ++j; 289 } 290 } 291 } 292 label_chunk_info[j].c = NULL; 293 if (here >= j) { 294 here = j ? j - 1 : 0; 295 } 296} 297 298/* A new partition entry */ 299static PartInfo * 300new_part(char *mpoint, Boolean newfs, u_long size) 301{ 302 PartInfo *ret; 303 304 if (!mpoint) 305 mpoint = "/change_me"; 306 307 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 308 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); 309 strcpy(ret->newfs_cmd, "newfs "); 310 strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS)); 311 ret->newfs = newfs; 312 ret->soft = 0; 313 if (!size) 314 return ret; 315 return ret; 316} 317 318/* Get the mountpoint for a partition and save it away */ 319static PartInfo * 320get_mountpoint(struct chunk *old) 321{ 322 char *val; 323 PartInfo *tmp; 324 325 if (old && old->private_data) 326 tmp = old->private_data; 327 else 328 tmp = NULL; 329 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 330 if (!val || !*val) { 331 if (!old) 332 return NULL; 333 else { 334 free(old->private_data); 335 old->private_data = NULL; 336 } 337 return NULL; 338 } 339 340 /* Is it just the same value? */ 341 if (tmp && !strcmp(tmp->mountpoint, val)) 342 return NULL; 343 344 /* Did we use it already? */ 345 if (check_conflict(val)) { 346 msgConfirm("You already have a mount point for %s assigned!", val); 347 return NULL; 348 } 349 350 /* Is it bogus? */ 351 if (*val != '/') { 352 msgConfirm("Mount point must start with a / character"); 353 return NULL; 354 } 355 356 /* Is it going to be mounted on root? */ 357 if (!strcmp(val, "/")) { 358 if (old) 359 old->flags |= CHUNK_IS_ROOT; 360 } 361 else if (old) 362 old->flags &= ~CHUNK_IS_ROOT; 363 364 safe_free(tmp); 365 val = string_skipwhite(string_prune(val)); 366 tmp = new_part(val, TRUE, 0); 367 if (old) { 368 old->private_data = tmp; 369 old->private_free = safe_free; 370 } 371 return tmp; 372} 373 374/* Get the type of the new partiton */ 375static PartType 376get_partition_type(void) 377{ 378 char selection[20]; 379 int i; 380 static unsigned char *fs_types[] = { 381 "FS", 382 "A file system", 383 "Swap", 384 "A swap partition.", 385 }; 386 WINDOW *w = savescr(); 387 388 i = dialog_menu("Please choose a partition type", 389 "If you want to use this partition for swap space, select Swap.\n" 390 "If you want to put a filesystem on it, choose FS.", 391 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 392 restorescr(w); 393 if (!i) { 394 if (!strcmp(selection, "FS")) 395 return PART_FILESYSTEM; 396 else if (!strcmp(selection, "Swap")) 397 return PART_SWAP; 398 } 399 return PART_NONE; 400} 401 402/* If the user wants a special newfs command for this, set it */ 403static void 404getNewfsCmd(PartInfo *p) 405{ 406 char *val; 407 408 val = msgGetInput(p->newfs_cmd, 409 "Please enter the newfs command and options you'd like to use in\n" 410 "creating this file system."); 411 if (val) 412 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 413} 414 415#define MAX_MOUNT_NAME 10 416 417#define PART_PART_COL 0 418#define PART_MOUNT_COL 10 419#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 420#define PART_NEWFS_COL (PART_SIZE_COL + 8) 421#define PART_OFF 39 422 423#define TOTAL_AVAIL_LINES (10) 424#define PSLICE_SHOWABLE (4) 425 426 427/* stick this all up on the screen */ 428static void 429print_label_chunks(void) 430{ 431 int i, j, srow, prow, pcol; 432 int sz; 433 char clrmsg[80]; 434 int ChunkPartStartRow; 435 WINDOW *ChunkWin; 436 437 /********************************************************/ 438 /*** These values are for controling screen resources ***/ 439 /*** Each label line holds up to 2 labels, so beware! ***/ 440 /*** strategy will be to try to always make sure the ***/ 441 /*** highlighted label is in the active display area. ***/ 442 /********************************************************/ 443 int pslice_max, label_max; 444 int pslice_count, label_count, label_focus_found, pslice_focus_found; 445 446 attrset(A_REVERSE); 447 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 448 attrset(A_NORMAL); 449 450 /*** Count the number of parition slices ***/ 451 pslice_count = 0; 452 for (i = 0; label_chunk_info[i].c ; i++) { 453 if (label_chunk_info[i].type == PART_SLICE) 454 ++pslice_count; 455 } 456 pslice_max = pslice_count; 457 458 /*** 4 line max for partition slices ***/ 459 if (pslice_max > PSLICE_SHOWABLE) { 460 pslice_max = PSLICE_SHOWABLE; 461 } 462 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; 463 464 /*** View partition slices modulo pslice_max ***/ 465 label_max = TOTAL_AVAIL_LINES - pslice_max; 466 467 for (i = 0; i < 2; i++) { 468 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 469 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 470 471 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 472 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 473 474 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); 475 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); 476 477 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 478 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 479 } 480 srow = CHUNK_SLICE_START_ROW; 481 prow = 0; 482 pcol = 0; 483 484 /*** these variables indicate that the focused item is shown currently ***/ 485 label_focus_found = 0; 486 pslice_focus_found = 0; 487 488 label_count = 0; 489 pslice_count = 0; 490 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 491 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 492 493 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 494 495 wclear(ChunkWin); 496 /*** wrefresh(ChunkWin); ***/ 497 498 for (i = 0; label_chunk_info[i].c; i++) { 499 /* Is it a slice entry displayed at the top? */ 500 if (label_chunk_info[i].type == PART_SLICE) { 501 /*** This causes the new pslice to replace the previous display ***/ 502 /*** focus must remain on the most recently active pslice ***/ 503 if (pslice_count == pslice_max) { 504 if (pslice_focus_found) { 505 /*** This is where we can mark the more following ***/ 506 attrset(A_BOLD); 507 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 508 attrset(A_NORMAL); 509 continue; 510 } 511 else { 512 /*** this is where we set the more previous ***/ 513 attrset(A_BOLD); 514 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 515 attrset(A_NORMAL); 516 pslice_count = 0; 517 srow = CHUNK_SLICE_START_ROW; 518 } 519 } 520 521 sz = space_free(label_chunk_info[i].c); 522 if (i == here) 523 attrset(ATTR_SELECTED); 524 if (i == pslice_focus) 525 pslice_focus_found = -1; 526 527 mvprintw(srow++, 0, 528 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 529 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, 530 sz, (sz / ONE_MEG)); 531 attrset(A_NORMAL); 532 clrtoeol(); 533 move(0, 0); 534 /*** refresh(); ***/ 535 ++pslice_count; 536 } 537 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 538 else { 539 char onestr[PART_OFF], num[10], *mountpoint, newfs[10]; 540 541 /* 542 * We copy this into a blank-padded string so that it looks like 543 * a solid bar in reverse-video 544 */ 545 memset(onestr, ' ', PART_OFF - 1); 546 onestr[PART_OFF - 1] = '\0'; 547 548 /*** Track how many labels have been displayed ***/ 549 if (label_count == ((label_max - 1 ) * 2)) { 550 if (label_focus_found) { 551 continue; 552 } 553 else { 554 label_count = 0; 555 prow = 0; 556 pcol = 0; 557 } 558 } 559 560 /* Go for two columns if we've written one full columns worth */ 561 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 562 if (label_count == label_max - 1) { 563 pcol = PART_OFF; 564 prow = 0; 565 } 566 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 567 /* If it's a filesystem, display the mountpoint */ 568 if (label_chunk_info[i].c->private_data 569 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 570 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 571 else if (label_chunk_info[i].type == PART_SWAP) 572 mountpoint = "swap"; 573 else 574 mountpoint = "<none>"; 575 576 /* Now display the newfs field */ 577 if (label_chunk_info[i].type == PART_FAT) 578 strcpy(newfs, "DOS"); 579 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) { 580 strcpy(newfs, "UFS"); 581 if (((PartInfo *)label_chunk_info[i].c->private_data)->soft) 582 strcat(newfs, "+S"); 583 strcat(newfs, ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? " Y" : " N"); 584 } 585 else if (label_chunk_info[i].type == PART_SWAP) 586 strcpy(newfs, "SWAP"); 587 else 588 strcpy(newfs, "*"); 589 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 590 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 591 snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 592 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 593 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 594 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 595 if (i == label_focus) { 596 label_focus_found = -1; 597 wattrset(ChunkWin, A_BOLD); 598 } 599 if (i == here) 600 wattrset(ChunkWin, ATTR_SELECTED); 601 602 /*** lazy man's way of expensively padding this string ***/ 603 while (strlen(onestr) < 37) 604 strcat(onestr, " "); 605 606 mvwaddstr(ChunkWin, prow, pcol, onestr); 607 wattrset(ChunkWin, A_NORMAL); 608 move(0, 0); 609 ++prow; 610 ++label_count; 611 } 612 } 613 614 /*** this will erase all the extra stuff ***/ 615 memset(clrmsg, ' ', 37); 616 clrmsg[37] = '\0'; 617 618 while (pslice_count < pslice_max) { 619 mvprintw(srow++, 0, clrmsg); 620 clrtoeol(); 621 ++pslice_count; 622 } 623 while (label_count < (2 * (label_max - 1))) { 624 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 625 ++label_count; 626 if (prow == (label_max - 1)) { 627 prow = 0; 628 pcol = PART_OFF; 629 } 630 } 631 refresh(); 632 wrefresh(ChunkWin); 633} 634 635static void 636print_command_summary(void) 637{ 638 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 639 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 640 if (!RunningAsInit) 641 mvprintw(18, 47, "W = Write"); 642 mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates"); 643 mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults"); 644 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 645 move(0, 0); 646} 647 648static void 649clear_wins(void) 650{ 651 extern void print_label_chunks(); 652 clear(); 653 print_label_chunks(); 654} 655 656#ifdef __alpha__ 657 658/* 659 * If there isn't a freebsd chunk already (i.e. there is no label), 660 * dedicate the disk. 661 */ 662static void 663maybe_dedicate(Disk* d) 664{ 665 struct chunk *c; 666 667 for (c = d->chunks->part; c; c = c->next) { 668 if (c->type == freebsd) 669 break; 670 } 671 672 if (!c) { 673 msgDebug("dedicating disk"); 674 All_FreeBSD(d, 1); 675 } 676} 677 678#endif 679 680static int 681diskLabel(Device *dev) 682{ 683 int sz, key = 0; 684 Boolean labeling; 685 char *msg = NULL; 686 PartInfo *p, *oldp; 687 PartType type; 688 Device **devs; 689#ifdef __alpha__ 690 int i; 691#endif 692 WINDOW *w = savescr(); 693 694 label_focus = 0; 695 pslice_focus = 0; 696 here = 0; 697 698 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 699 if (!devs) { 700 msgConfirm("No disks found!"); 701 restorescr(w); 702 return DITEM_FAILURE; 703 } 704 labeling = TRUE; 705 keypad(stdscr, TRUE); 706#ifdef __alpha__ 707 for (i = 0; devs[i]; i++) { 708 maybe_dedicate((Disk*) devs[i]->private); 709 } 710#endif 711 record_label_chunks(devs, dev); 712 713 clear(); 714 while (labeling) { 715 char *cp; 716 717 print_label_chunks(); 718 print_command_summary(); 719 if (msg) { 720 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 721 clrtoeol(); 722 beep(); 723 msg = NULL; 724 } 725 else { 726 move(23, 0); 727 clrtoeol(); 728 } 729 730 refresh(); 731 key = getch(); 732 switch (toupper(key)) { 733 int i; 734 static char _msg[40]; 735 736 case '\014': /* ^L */ 737 clear_wins(); 738 break; 739 740 case '\020': /* ^P */ 741 case KEY_UP: 742 case '-': 743 if (here != 0) 744 --here; 745 else 746 while (label_chunk_info[here + 1].c) 747 ++here; 748 break; 749 750 case '\016': /* ^N */ 751 case KEY_DOWN: 752 case '+': 753 case '\r': 754 case '\n': 755 if (label_chunk_info[here + 1].c) 756 ++here; 757 else 758 here = 0; 759 break; 760 761 case KEY_HOME: 762 here = 0; 763 break; 764 765 case KEY_END: 766 while (label_chunk_info[here + 1].c) 767 ++here; 768 break; 769 770 case KEY_F(1): 771 case '?': 772 systemDisplayHelp("partition"); 773 clear_wins(); 774 break; 775 776 case 'A': 777 if (label_chunk_info[here].type != PART_SLICE) { 778 msg = "You can only do this in a disk slice (at top of screen)"; 779 break; 780 } 781 sz = space_free(label_chunk_info[here].c); 782 if (sz <= FS_MIN_SIZE) 783 msg = "Not enough free space to create a new partition in the slice"; 784 else { 785 struct chunk *tmp; 786 int mib[2]; 787 int physmem; 788 size_t size, swsize; 789 char *cp; 790 Chunk *rootdev, *swapdev, *usrdev, *vardev; 791 792 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 793 if (!rootdev) { 794 cp = variable_get(VAR_ROOT_SIZE); 795 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 796 (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 797 if (!tmp) { 798 msgConfirm("Unable to create the root partition. Too big?"); 799 clear_wins(); 800 break; 801 } 802 tmp->private_data = new_part("/", TRUE, tmp->size); 803 tmp->private_free = safe_free; 804 record_label_chunks(devs, dev); 805 } 806 807 if (!swapdev) { 808 cp = variable_get(VAR_SWAP_SIZE); 809 if (cp) 810 swsize = atoi(cp) * ONE_MEG; 811 else { 812 mib[0] = CTL_HW; 813 mib[1] = HW_PHYSMEM; 814 size = sizeof physmem; 815 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 816 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 817 } 818 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 819 swsize, part, FS_SWAP, 0); 820 if (!tmp) { 821 msgConfirm("Unable to create the swap partition. Too big?"); 822 clear_wins(); 823 break; 824 } 825 tmp->private_data = 0; 826 tmp->private_free = safe_free; 827 record_label_chunks(devs, dev); 828 } 829 830 if (!vardev) { 831 cp = variable_get(VAR_VAR_SIZE); 832 if (cp) 833 sz = atoi(cp) * ONE_MEG; 834 else 835 sz = variable_get(VAR_NO_USR) 836 ? space_free(label_chunk_info[here].c) 837 : VAR_MIN_SIZE * ONE_MEG; 838 839 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 840 sz, part, FS_BSDFFS, 0); 841 if (!tmp) { 842 msgConfirm("Less than %dMB free for /var - you will need to\n" 843 "partition your disk manually with a custom install!", 844 (cp ? atoi(cp) : VAR_MIN_SIZE)); 845 clear_wins(); 846 break; 847 } 848 tmp->private_data = new_part("/var", TRUE, tmp->size); 849 tmp->private_free = safe_free; 850 record_label_chunks(devs, dev); 851 } 852 853 if (!usrdev && !variable_get(VAR_NO_USR)) { 854 cp = variable_get(VAR_USR_SIZE); 855 if (cp) 856 sz = atoi(cp) * ONE_MEG; 857 else 858 sz = space_free(label_chunk_info[here].c); 859 if (sz) { 860 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 861 msgConfirm("Less than %dMB free for /usr - you will need to\n" 862 "partition your disk manually with a custom install!", USR_MIN_SIZE); 863 clear_wins(); 864 break; 865 } 866 867 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 868 label_chunk_info[here].c, 869 sz, part, FS_BSDFFS, 0); 870 if (!tmp) { 871 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 872 "You will need to partition your disk manually with a custom install!"); 873 clear_wins(); 874 break; 875 } 876 tmp->private_data = new_part("/usr", TRUE, tmp->size); 877 tmp->private_free = safe_free; 878 record_label_chunks(devs, dev); 879 } 880 } 881 882 /* At this point, we're reasonably "labelled" */ 883 if (variable_cmp(DISK_LABELLED, "written")) 884 variable_set2(DISK_LABELLED, "yes", 0); 885 } 886 break; 887 888 case 'C': 889 if (label_chunk_info[here].type != PART_SLICE) { 890 msg = "You can only do this in a master partition (see top of screen)"; 891 break; 892 } 893 sz = space_free(label_chunk_info[here].c); 894 if (sz <= FS_MIN_SIZE) { 895 msg = "Not enough space to create an additional FreeBSD partition"; 896 break; 897 } 898 else { 899 char *val; 900 int size; 901 struct chunk *tmp; 902 char osize[80]; 903 u_long flags = 0; 904 905 sprintf(osize, "%d", sz); 906 val = msgGetInput(osize, 907 "Please specify the partition size in blocks or append a trailing G for\n" 908 "gigabytes, M for megabytes, or C for cylinders.\n" 909 "%d blocks (%dMB) are free.", 910 sz, sz / ONE_MEG); 911 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 912 clear_wins(); 913 break; 914 } 915 916 if (*cp) { 917 if (toupper(*cp) == 'M') 918 size *= ONE_MEG; 919 else if (toupper(*cp) == 'G') 920 size *= ONE_GIG; 921 else if (toupper(*cp) == 'C') 922 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 923 } 924 if (size <= FS_MIN_SIZE) { 925 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 926 clear_wins(); 927 break; 928 } 929 type = get_partition_type(); 930 if (type == PART_NONE) { 931 clear_wins(); 932 beep(); 933 break; 934 } 935 936 if (type == PART_FILESYSTEM) { 937 if ((p = get_mountpoint(NULL)) == NULL) { 938 clear_wins(); 939 beep(); 940 break; 941 } 942 else if (!strcmp(p->mountpoint, "/")) 943 flags |= CHUNK_IS_ROOT; 944 else 945 flags &= ~CHUNK_IS_ROOT; 946 } 947 else 948 p = NULL; 949 950 if ((flags & CHUNK_IS_ROOT)) { 951 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 952 msgConfirm("This region cannot be used for your root partition as the\n" 953 "FreeBSD boot code cannot deal with a root partition created\n" 954 "in that location. Please choose another location or smaller\n" 955 "size for your root partition and try again!"); 956 clear_wins(); 957 break; 958 } 959 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 960 msgConfirm("Warning: This is smaller than the recommended size for a\n" 961 "root partition. For a variety of reasons, root\n" 962 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 963 } 964 } 965 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 966 label_chunk_info[here].c, 967 size, part, 968 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 969 flags); 970 if (!tmp) { 971 msgConfirm("Unable to create the partition. Too big?"); 972 clear_wins(); 973 break; 974 } 975 if (type != PART_SWAP) { 976 /* This is needed to tell the newfs -u about the size */ 977 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 978 safe_free(p); 979 } 980 else 981 tmp->private_data = p; 982 tmp->private_free = safe_free; 983 if (variable_cmp(DISK_LABELLED, "written")) 984 variable_set2(DISK_LABELLED, "yes", 0); 985 record_label_chunks(devs, dev); 986 clear_wins(); 987 /*** This is where we assign focus to new label so it shows ***/ 988 { 989 int i; 990 label_focus = -1; 991 for (i = 0; label_chunk_info[i].c; ++i) { 992 if (label_chunk_info[i].c == tmp) { 993 label_focus = i; 994 break; 995 } 996 } 997 if (label_focus == -1) 998 label_focus = i - 1; 999 } 1000 } 1001 break; 1002 1003 case KEY_DC: 1004 case 'D': /* delete */ 1005 if (label_chunk_info[here].type == PART_SLICE) { 1006 msg = MSG_NOT_APPLICABLE; 1007 break; 1008 } 1009 else if (label_chunk_info[here].type == PART_FAT) { 1010 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1011 break; 1012 } 1013 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 1014 if (variable_cmp(DISK_LABELLED, "written")) 1015 variable_set2(DISK_LABELLED, "yes", 0); 1016 record_label_chunks(devs, dev); 1017 break; 1018 1019 case 'M': /* mount */ 1020 switch(label_chunk_info[here].type) { 1021 case PART_SLICE: 1022 msg = MSG_NOT_APPLICABLE; 1023 break; 1024 1025 case PART_SWAP: 1026 msg = "You don't need to specify a mountpoint for a swap partition."; 1027 break; 1028 1029 case PART_FAT: 1030 case PART_FILESYSTEM: 1031 oldp = label_chunk_info[here].c->private_data; 1032 p = get_mountpoint(label_chunk_info[here].c); 1033 if (p) { 1034 if (!oldp) 1035 p->newfs = FALSE; 1036 if (label_chunk_info[here].type == PART_FAT 1037 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1038 || !strcmp(p->mountpoint, "/var"))) { 1039 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1040 strcpy(p->mountpoint, "/bogus"); 1041 } 1042 } 1043 if (variable_cmp(DISK_LABELLED, "written")) 1044 variable_set2(DISK_LABELLED, "yes", 0); 1045 record_label_chunks(devs, dev); 1046 clear_wins(); 1047 break; 1048 1049 default: 1050 msgFatal("Bogus partition under cursor???"); 1051 break; 1052 } 1053 break; 1054 1055 case 'N': /* Set newfs options */ 1056 if (label_chunk_info[here].c->private_data && 1057 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1058 getNewfsCmd(label_chunk_info[here].c->private_data); 1059 else 1060 msg = MSG_NOT_APPLICABLE; 1061 clear_wins(); 1062 break; 1063 1064 case 'S': /* Toggle soft updates flag */ 1065 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1066 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1067 if (pi) 1068 pi->soft = !pi->soft; 1069 else 1070 msg = MSG_NOT_APPLICABLE; 1071 } 1072 else 1073 msg = MSG_NOT_APPLICABLE; 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 if (pi && pi->soft) 1082 ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1; 1083 safe_free(pi); 1084 label_chunk_info[here].c->private_free = safe_free; 1085 if (variable_cmp(DISK_LABELLED, "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 (!variable_cmp(DISK_LABELLED, "written")) { 1095 msgConfirm("You've already written out your changes -\n" 1096 "it's too late to undo!"); 1097 } 1098 else if (!msgNoYes("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 (!variable_cmp(DISK_LABELLED, "written")) { 1119 msgConfirm("You've already written out your changes - if you\n" 1120 "wish to overwrite them, you'll have to restart\n" 1121 "sysinstall first."); 1122 } 1123 else if (!msgNoYes("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 (!msgNoYes("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 (variable_cmp(DISK_LABELLED, "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 soft, 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 %d", typ, &sz, mpoint, &soft) < 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 if (!soft) 1263 ((PartInfo *)tmp->private_data)->soft = 1; 1264 status = DITEM_SUCCESS; 1265 } 1266 } 1267 entries++; 1268 } 1269 else { 1270 /* No more matches, leave the loop */ 1271 entries = 0; 1272 } 1273 } 1274 } 1275 else { 1276 /* Must be something we can set a mountpoint for */ 1277 cp = variable_get(c1->name); 1278 if (cp) { 1279 char mpoint[50], do_newfs[8]; 1280 Boolean newfs = FALSE; 1281 1282 do_newfs[0] = '\0'; 1283 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1284 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1285 status = DITEM_FAILURE; 1286 continue; 1287 } 1288 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1289 if (c1->private_data) { 1290 p = c1->private_data; 1291 p->newfs = newfs; 1292 strcpy(p->mountpoint, mpoint); 1293 } 1294 else { 1295 c1->private_data = new_part(mpoint, newfs, 0); 1296 c1->private_free = safe_free; 1297 } 1298 if (!strcmp(mpoint, "/")) 1299 c1->flags |= CHUNK_IS_ROOT; 1300 else 1301 c1->flags &= ~CHUNK_IS_ROOT; 1302 } 1303 } 1304 } 1305 if (status == DITEM_SUCCESS) 1306 variable_set2(DISK_LABELLED, "yes", 0); 1307 return status; 1308} 1309