label.c revision 76237
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 76237 2001-05-03 09:23:48Z 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 120 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) && (size < (ROOT_MIN_SIZE * ONE_MEG))) { 951 msgConfirm("Warning: This is smaller than the recommended size for a\n" 952 "root partition. For a variety of reasons, root\n" 953 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 954 } 955 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 956 label_chunk_info[here].c, 957 size, part, 958 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 959 flags); 960 if (!tmp) { 961 msgConfirm("Unable to create the partition. Too big?"); 962 clear_wins(); 963 break; 964 } 965 if (type != PART_SWAP) { 966 /* This is needed to tell the newfs -u about the size */ 967 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 968 safe_free(p); 969 } 970 else 971 tmp->private_data = p; 972 tmp->private_free = safe_free; 973 if (variable_cmp(DISK_LABELLED, "written")) 974 variable_set2(DISK_LABELLED, "yes", 0); 975 record_label_chunks(devs, dev); 976 clear_wins(); 977 /*** This is where we assign focus to new label so it shows ***/ 978 { 979 int i; 980 label_focus = -1; 981 for (i = 0; label_chunk_info[i].c; ++i) { 982 if (label_chunk_info[i].c == tmp) { 983 label_focus = i; 984 break; 985 } 986 } 987 if (label_focus == -1) 988 label_focus = i - 1; 989 } 990 } 991 break; 992 993 case KEY_DC: 994 case 'D': /* delete */ 995 if (label_chunk_info[here].type == PART_SLICE) { 996 msg = MSG_NOT_APPLICABLE; 997 break; 998 } 999 else if (label_chunk_info[here].type == PART_FAT) { 1000 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1001 break; 1002 } 1003 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 1004 if (variable_cmp(DISK_LABELLED, "written")) 1005 variable_set2(DISK_LABELLED, "yes", 0); 1006 record_label_chunks(devs, dev); 1007 break; 1008 1009 case 'M': /* mount */ 1010 switch(label_chunk_info[here].type) { 1011 case PART_SLICE: 1012 msg = MSG_NOT_APPLICABLE; 1013 break; 1014 1015 case PART_SWAP: 1016 msg = "You don't need to specify a mountpoint for a swap partition."; 1017 break; 1018 1019 case PART_FAT: 1020 case PART_FILESYSTEM: 1021 oldp = label_chunk_info[here].c->private_data; 1022 p = get_mountpoint(label_chunk_info[here].c); 1023 if (p) { 1024 if (!oldp) 1025 p->newfs = FALSE; 1026 if (label_chunk_info[here].type == PART_FAT 1027 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1028 || !strcmp(p->mountpoint, "/var"))) { 1029 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1030 strcpy(p->mountpoint, "/bogus"); 1031 } 1032 } 1033 if (variable_cmp(DISK_LABELLED, "written")) 1034 variable_set2(DISK_LABELLED, "yes", 0); 1035 record_label_chunks(devs, dev); 1036 clear_wins(); 1037 break; 1038 1039 default: 1040 msgFatal("Bogus partition under cursor???"); 1041 break; 1042 } 1043 break; 1044 1045 case 'N': /* Set newfs options */ 1046 if (label_chunk_info[here].c->private_data && 1047 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1048 getNewfsCmd(label_chunk_info[here].c->private_data); 1049 else 1050 msg = MSG_NOT_APPLICABLE; 1051 clear_wins(); 1052 break; 1053 1054 case 'S': /* Toggle soft updates flag */ 1055 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1056 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1057 if (pi) 1058 pi->soft = !pi->soft; 1059 else 1060 msg = MSG_NOT_APPLICABLE; 1061 } 1062 else 1063 msg = MSG_NOT_APPLICABLE; 1064 break; 1065 1066 case 'T': /* Toggle newfs state */ 1067 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1068 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1069 label_chunk_info[here].c->private_data = 1070 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 1071 if (pi && pi->soft) 1072 ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1; 1073 safe_free(pi); 1074 label_chunk_info[here].c->private_free = safe_free; 1075 if (variable_cmp(DISK_LABELLED, "written")) 1076 variable_set2(DISK_LABELLED, "yes", 0); 1077 } 1078 else 1079 msg = MSG_NOT_APPLICABLE; 1080 break; 1081 1082 case 'U': 1083 clear(); 1084 if (!variable_cmp(DISK_LABELLED, "written")) { 1085 msgConfirm("You've already written out your changes -\n" 1086 "it's too late to undo!"); 1087 } 1088 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 1089 variable_unset(DISK_PARTITIONED); 1090 variable_unset(DISK_LABELLED); 1091 for (i = 0; devs[i]; i++) { 1092 Disk *d; 1093 1094 if (!devs[i]->enabled) 1095 continue; 1096 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1097 Free_Disk(devs[i]->private); 1098 devs[i]->private = d; 1099 diskPartition(devs[i]); 1100 } 1101 } 1102 record_label_chunks(devs, dev); 1103 } 1104 clear_wins(); 1105 break; 1106 1107 case 'W': 1108 if (!variable_cmp(DISK_LABELLED, "written")) { 1109 msgConfirm("You've already written out your changes - if you\n" 1110 "wish to overwrite them, you'll have to restart\n" 1111 "sysinstall first."); 1112 } 1113 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 1114 "installation. If you are installing FreeBSD for the first time\n" 1115 "then you should simply type Q when you're finished here and your\n" 1116 "changes will be committed in one batch automatically at the end of\n" 1117 "these questions.\n\n" 1118 "Are you absolutely sure you want to do this now?")) { 1119 variable_set2(DISK_LABELLED, "yes", 0); 1120 diskLabelCommit(NULL); 1121 } 1122 clear_wins(); 1123 break; 1124 1125 case '|': 1126 if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" 1127 "This is an entirely undocumented feature which you are not\n" 1128 "expected to understand!")) { 1129 int i; 1130 Device **devs; 1131 1132 dialog_clear(); 1133 end_dialog(); 1134 DialogActive = FALSE; 1135 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1136 if (!devs) { 1137 msgConfirm("Can't find any disk devices!"); 1138 break; 1139 } 1140 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1141 if (devs[i]->enabled) 1142 slice_wizard(((Disk *)devs[i]->private)); 1143 } 1144 if (variable_cmp(DISK_LABELLED, "written")) 1145 variable_set2(DISK_LABELLED, "yes", 0); 1146 DialogActive = TRUE; 1147 record_label_chunks(devs, dev); 1148 clear_wins(); 1149 } 1150 else 1151 msg = "A most prudent choice!"; 1152 break; 1153 1154 case '\033': /* ESC */ 1155 case 'Q': 1156 labeling = FALSE; 1157 break; 1158 1159 default: 1160 beep(); 1161 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1162 msg = _msg; 1163 break; 1164 } 1165 if (label_chunk_info[here].type == PART_SLICE) 1166 pslice_focus = here; 1167 else 1168 label_focus = here; 1169 } 1170 restorescr(w); 1171 return DITEM_SUCCESS; 1172} 1173 1174static int 1175diskLabelNonInteractive(Device *dev) 1176{ 1177 char *cp; 1178 PartType type; 1179 PartInfo *p; 1180 u_long flags = 0; 1181 int i, status; 1182 Device **devs; 1183 Disk *d; 1184 1185 status = DITEM_SUCCESS; 1186 cp = variable_get(VAR_DISK); 1187 if (!cp) { 1188 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1189 return DITEM_FAILURE; 1190 } 1191 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1192 if (!devs) { 1193 msgConfirm("diskLabel: No disk device %s found!", cp); 1194 return DITEM_FAILURE; 1195 } 1196 if (dev) 1197 d = dev->private; 1198 else 1199 d = devs[0]->private; 1200#ifdef __alpha__ 1201 maybe_dedicate(d); 1202#endif 1203 record_label_chunks(devs, dev); 1204 for (i = 0; label_chunk_info[i].c; i++) { 1205 Chunk *c1 = label_chunk_info[i].c; 1206 1207 if (label_chunk_info[i].type == PART_SLICE) { 1208 char name[512]; 1209 int entries = 1; 1210 1211 while (entries) { 1212 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1213 if ((cp = variable_get(name)) != NULL) { 1214 int sz, soft = 0; 1215 char typ[10], mpoint[50]; 1216 1217 if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) { 1218 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1219 status = DITEM_FAILURE; 1220 continue; 1221 } 1222 else { 1223 Chunk *tmp; 1224 1225 if (!strcmp(typ, "swap")) { 1226 type = PART_SWAP; 1227 strcpy(mpoint, "SWAP"); 1228 } 1229 else { 1230 type = PART_FILESYSTEM; 1231 if (!strcmp(mpoint, "/")) 1232 flags |= CHUNK_IS_ROOT; 1233 else 1234 flags &= ~CHUNK_IS_ROOT; 1235 } 1236 if (!sz) 1237 sz = space_free(c1); 1238 if (sz > space_free(c1)) { 1239 msgConfirm("Not enough free space to create partition: %s", mpoint); 1240 status = DITEM_FAILURE; 1241 continue; 1242 } 1243 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1244 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1245 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1246 status = DITEM_FAILURE; 1247 break; 1248 } 1249 else { 1250 tmp->private_data = new_part(mpoint, TRUE, sz); 1251 tmp->private_free = safe_free; 1252 ((PartInfo *)tmp->private_data)->soft = soft; 1253 status = DITEM_SUCCESS; 1254 } 1255 } 1256 entries++; 1257 } 1258 else { 1259 /* No more matches, leave the loop */ 1260 entries = 0; 1261 } 1262 } 1263 } 1264 else { 1265 /* Must be something we can set a mountpoint for */ 1266 cp = variable_get(c1->name); 1267 if (cp) { 1268 char mpoint[50], do_newfs[8]; 1269 Boolean newfs = FALSE; 1270 1271 do_newfs[0] = '\0'; 1272 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1273 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1274 status = DITEM_FAILURE; 1275 continue; 1276 } 1277 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1278 if (c1->private_data) { 1279 p = c1->private_data; 1280 p->newfs = newfs; 1281 strcpy(p->mountpoint, mpoint); 1282 } 1283 else { 1284 c1->private_data = new_part(mpoint, newfs, 0); 1285 c1->private_free = safe_free; 1286 } 1287 if (!strcmp(mpoint, "/")) 1288 c1->flags |= CHUNK_IS_ROOT; 1289 else 1290 c1->flags &= ~CHUNK_IS_ROOT; 1291 } 1292 } 1293 } 1294 if (status == DITEM_SUCCESS) 1295 variable_set2(DISK_LABELLED, "yes", 0); 1296 return status; 1297} 1298