label.c revision 133040
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 133040 2004-08-02 23:18:48Z marcel $ 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 <inttypes.h> 40#include <libdisk.h> 41#include <sys/disklabel.h> 42#include <sys/param.h> 43#include <sys/sysctl.h> 44 45#define AUTO_HOME 0 /* do not create /home automatically */ 46 47/* 48 * Everything to do with editing the contents of disk labels. 49 */ 50 51/* A nice message we use a lot in the disklabel editor */ 52#define MSG_NOT_APPLICABLE "That option is not applicable here" 53 54/* Where to start printing the freebsd slices */ 55#define CHUNK_SLICE_START_ROW 2 56#define CHUNK_PART_START_ROW 11 57 58/* The smallest filesystem we're willing to create */ 59#define FS_MIN_SIZE ONE_MEG 60 61/* 62 * Minimum partition sizes 63 */ 64#if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__) || defined(__amd64__) 65#define ROOT_MIN_SIZE 128 66#else 67#define ROOT_MIN_SIZE 118 68#endif 69#define SWAP_MIN_SIZE 32 70#define USR_MIN_SIZE 80 71#define VAR_MIN_SIZE 20 72#define TMP_MIN_SIZE 20 73#define HOME_MIN_SIZE 20 74 75/* 76 * Swap size limit for auto-partitioning (4G). 77 */ 78#define SWAP_AUTO_LIMIT_SIZE 4096 79 80/* 81 * Default partition sizes. If we do not have sufficient disk space 82 * for this configuration we scale things relative to the NOM vs DEFAULT 83 * sizes. If the disk is larger then /home will get any remaining space. 84 */ 85#define ROOT_DEFAULT_SIZE 256 86#define USR_DEFAULT_SIZE 3072 87#define VAR_DEFAULT_SIZE 256 88#define TMP_DEFAULT_SIZE 256 89#define HOME_DEFAULT_SIZE USR_DEFAULT_SIZE 90 91/* 92 * Nominal partition sizes. These are used to scale the default sizes down 93 * when we have insufficient disk space. If this isn't sufficient we scale 94 * down using the MIN sizes instead. 95 */ 96#define ROOT_NOMINAL_SIZE 192 97#define USR_NOMINAL_SIZE 512 98#define VAR_NOMINAL_SIZE 64 99#define TMP_NOMINAL_SIZE 64 100#define HOME_NOMINAL_SIZE USR_NOMINAL_SIZE 101 102/* The bottom-most row we're allowed to scribble on */ 103#define CHUNK_ROW_MAX 16 104 105 106/* All the chunks currently displayed on the screen */ 107static struct { 108 struct chunk *c; 109 PartType type; 110} label_chunk_info[MAX_CHUNKS + 1]; 111static int here; 112 113/*** with this value we try to track the most recently added label ***/ 114static int label_focus = 0, pslice_focus = 0; 115 116static int diskLabel(Device *dev); 117static int diskLabelNonInteractive(Device *dev); 118static char *try_auto_label(Device **devs, Device *dev, int perc, int *req); 119 120static int 121labelHook(dialogMenuItem *selected) 122{ 123 Device **devs = NULL; 124 125 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 126 if (!devs) { 127 msgConfirm("Unable to find disk %s!", selected->prompt); 128 return DITEM_FAILURE; 129 } 130 /* Toggle enabled status? */ 131 if (!devs[0]->enabled) { 132 devs[0]->enabled = TRUE; 133 diskLabel(devs[0]); 134 } 135 else 136 devs[0]->enabled = FALSE; 137 return DITEM_SUCCESS; 138} 139 140static int 141labelCheck(dialogMenuItem *selected) 142{ 143 Device **devs = NULL; 144 145 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 146 if (!devs || devs[0]->enabled == FALSE) 147 return FALSE; 148 return TRUE; 149} 150 151int 152diskLabelEditor(dialogMenuItem *self) 153{ 154 DMenu *menu; 155 Device **devs; 156 int i, cnt; 157 158 i = 0; 159 cnt = diskGetSelectCount(&devs); 160 if (cnt == -1) { 161 msgConfirm("No disks found! Please verify that your disk controller is being\n" 162 "properly probed at boot time. See the Hardware Guide on the\n" 163 "Documentation menu for clues on diagnosing this type of problem."); 164 return DITEM_FAILURE; 165 } 166 else if (cnt) { 167 /* Some are already selected */ 168 if (variable_get(VAR_NONINTERACTIVE) && 169 !variable_get(VAR_DISKINTERACTIVE)) 170 i = diskLabelNonInteractive(NULL); 171 else 172 i = diskLabel(NULL); 173 } 174 else { 175 /* No disks are selected, fall-back case now */ 176 cnt = deviceCount(devs); 177 if (cnt == 1) { 178 devs[0]->enabled = TRUE; 179 if (variable_get(VAR_NONINTERACTIVE) && 180 !variable_get(VAR_DISKINTERACTIVE)) 181 i = diskLabelNonInteractive(devs[0]); 182 else 183 i = diskLabel(devs[0]); 184 } 185 else { 186 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); 187 if (!menu) { 188 msgConfirm("No devices suitable for installation found!\n\n" 189 "Please verify that your disk controller (and attached drives)\n" 190 "were detected properly. This can be done by pressing the\n" 191 "[Scroll Lock] key and using the Arrow keys to move back to\n" 192 "the boot messages. Press [Scroll Lock] again to return."); 193 i = DITEM_FAILURE; 194 } 195 else { 196 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 197 free(menu); 198 } 199 } 200 } 201 if (DITEM_STATUS(i) != DITEM_FAILURE) { 202 if (variable_cmp(DISK_LABELLED, "written")) 203 variable_set2(DISK_LABELLED, "yes", 0); 204 } 205 return i; 206} 207 208int 209diskLabelCommit(dialogMenuItem *self) 210{ 211 char *cp; 212 int i; 213 214 /* Already done? */ 215 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 216 i = DITEM_SUCCESS; 217 else if (!cp) { 218 msgConfirm("You must assign disk labels before this option can be used."); 219 i = DITEM_FAILURE; 220 } 221 /* The routine will guard against redundant writes, just as this one does */ 222 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 223 i = DITEM_FAILURE; 224 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 225 i = DITEM_FAILURE; 226 else { 227 msgInfo("All filesystem information written successfully."); 228 variable_set2(DISK_LABELLED, "written", 0); 229 i = DITEM_SUCCESS; 230 } 231 return i; 232} 233 234/* See if we're already using a desired partition name */ 235static Boolean 236check_conflict(char *name) 237{ 238 int i; 239 240 for (i = 0; label_chunk_info[i].c; i++) 241 if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT 242 || label_chunk_info[i].type == PART_EFI) && label_chunk_info[i].c->private_data 243 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 244 return TRUE; 245 return FALSE; 246} 247 248/* How much space is in this FreeBSD slice? */ 249static daddr_t 250space_free(struct chunk *c) 251{ 252 struct chunk *c1; 253 daddr_t sz = c->size; 254 255 for (c1 = c->part; c1; c1 = c1->next) { 256 if (c1->type != unused) 257 sz -= c1->size; 258 } 259 if (sz < 0) 260 msgFatal("Partitions are larger than actual chunk??"); 261 return sz; 262} 263 264/* Snapshot the current situation into the displayed chunks structure */ 265static void 266record_label_chunks(Device **devs, Device *dev) 267{ 268 int i, j, p; 269 struct chunk *c1, *c2; 270 Disk *d; 271 272 j = p = 0; 273 /* First buzz through and pick up the FreeBSD slices */ 274 for (i = 0; devs[i]; i++) { 275 if ((dev && devs[i] != dev) || !devs[i]->enabled) 276 continue; 277 d = (Disk *)devs[i]->private; 278 if (!d->chunks) 279 msgFatal("No chunk list found for %s!", d->name); 280 281#ifdef __ia64__ 282 label_chunk_info[j].type = PART_SLICE; 283 label_chunk_info[j].c = d->chunks; 284 j++; 285#endif 286 287 /* Put the slice entries first */ 288 for (c1 = d->chunks->part; c1; c1 = c1->next) { 289 if (c1->type == freebsd) { 290 label_chunk_info[j].type = PART_SLICE; 291 label_chunk_info[j].c = c1; 292 ++j; 293 } 294#ifdef __powerpc__ 295 if (c1->type == apple) { 296 label_chunk_info[j].type = PART_SLICE; 297 label_chunk_info[j].c = c1; 298 ++j; 299 } 300#endif 301 } 302 } 303 304 /* Now run through again and get the FreeBSD partition entries */ 305 for (i = 0; devs[i]; i++) { 306 if (!devs[i]->enabled) 307 continue; 308 d = (Disk *)devs[i]->private; 309 /* Then buzz through and pick up the partitions */ 310 for (c1 = d->chunks->part; c1; c1 = c1->next) { 311 if (c1->type == freebsd) { 312 for (c2 = c1->part; c2; c2 = c2->next) { 313 if (c2->type == part) { 314 if (c2->subtype == FS_SWAP) 315 label_chunk_info[j].type = PART_SWAP; 316 else 317 label_chunk_info[j].type = PART_FILESYSTEM; 318 label_chunk_info[j].c = c2; 319 ++j; 320 } 321 } 322 } 323 else if (c1->type == fat) { 324 label_chunk_info[j].type = PART_FAT; 325 label_chunk_info[j].c = c1; 326 ++j; 327 } 328#ifdef __ia64__ 329 else if (c1->type == efi) { 330 label_chunk_info[j].type = PART_EFI; 331 label_chunk_info[j].c = c1; 332 ++j; 333 } 334 else if (c1->type == part) { 335 if (c1->subtype == FS_SWAP) 336 label_chunk_info[j].type = PART_SWAP; 337 else 338 label_chunk_info[j].type = PART_FILESYSTEM; 339 label_chunk_info[j].c = c1; 340 ++j; 341 } 342#endif 343#ifdef __powerpc__ 344 else if (c1->type == apple) { 345 for (c2 = c1->part; c2; c2 = c2->next) { 346 if (c2->type == part) { 347 if (c2->subtype == FS_SWAP) 348 label_chunk_info[j].type = PART_SWAP; 349 else 350 label_chunk_info[j].type = PART_FILESYSTEM; 351 label_chunk_info[j].c = c2; 352 ++j; 353 } 354 } 355 } 356#endif 357 } 358 } 359 label_chunk_info[j].c = NULL; 360 if (here >= j) { 361 here = j ? j - 1 : 0; 362 } 363} 364 365/* A new partition entry */ 366static PartInfo * 367new_part(char *mpoint, Boolean newfs) 368{ 369 PartInfo *pi; 370 371 if (!mpoint) 372 mpoint = "/change_me"; 373 374 pi = (PartInfo *)safe_malloc(sizeof(PartInfo)); 375 sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX); 376 377 pi->do_newfs = newfs; 378 379 pi->newfs_type = NEWFS_UFS; 380 strcpy(pi->newfs_data.newfs_ufs.user_options, ""); 381 pi->newfs_data.newfs_ufs.acls = FALSE; 382 pi->newfs_data.newfs_ufs.multilabel = FALSE; 383 pi->newfs_data.newfs_ufs.softupdates = strcmp(mpoint, "/"); 384#ifdef PC98 385 pi->newfs_data.newfs_ufs.ufs1 = TRUE; 386#else 387 pi->newfs_data.newfs_ufs.ufs1 = FALSE; 388#endif 389 390 return pi; 391} 392 393#if defined(__ia64__) 394static PartInfo * 395new_efi_part(char *mpoint, Boolean newfs) 396{ 397 PartInfo *pi; 398 399 if (!mpoint) 400 mpoint = "/efi"; 401 402 pi = (PartInfo *)safe_malloc(sizeof(PartInfo)); 403 sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX); 404 405 pi->do_newfs = newfs; 406 pi->newfs_type = NEWFS_MSDOS; 407 408 return pi; 409} 410#endif 411 412/* Get the mountpoint for a partition and save it away */ 413static PartInfo * 414get_mountpoint(struct chunk *old) 415{ 416 char *val; 417 PartInfo *tmp; 418 Boolean newfs; 419 420 if (old && old->private_data) 421 tmp = old->private_data; 422 else 423 tmp = NULL; 424 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 425 if (!val || !*val) { 426 if (!old) 427 return NULL; 428 else { 429 free(old->private_data); 430 old->private_data = NULL; 431 } 432 return NULL; 433 } 434 435 /* Is it just the same value? */ 436 if (tmp && !strcmp(tmp->mountpoint, val)) 437 return NULL; 438 439 /* Did we use it already? */ 440 if (check_conflict(val)) { 441 msgConfirm("You already have a mount point for %s assigned!", val); 442 return NULL; 443 } 444 445 /* Is it bogus? */ 446 if (*val != '/') { 447 msgConfirm("Mount point must start with a / character"); 448 return NULL; 449 } 450 451 /* Is it going to be mounted on root? */ 452 if (!strcmp(val, "/")) { 453 if (old) 454 old->flags |= CHUNK_IS_ROOT; 455 } 456 else if (old) 457 old->flags &= ~CHUNK_IS_ROOT; 458 459 newfs = TRUE; 460 if (tmp) { 461 newfs = tmp->do_newfs; 462 safe_free(tmp); 463 } 464 val = string_skipwhite(string_prune(val)); 465 tmp = new_part(val, newfs); 466 if (old) { 467 old->private_data = tmp; 468 old->private_free = safe_free; 469 } 470 return tmp; 471} 472 473/* Get the type of the new partiton */ 474static PartType 475get_partition_type(void) 476{ 477 char selection[20]; 478 int i; 479 static unsigned char *fs_types[] = { 480#ifdef __ia64__ 481 "EFI", "An EFI system partition", 482#endif 483 "FS", "A file system", 484 "Swap", "A swap partition.", 485 }; 486 WINDOW *w = savescr(); 487 488 i = dialog_menu("Please choose a partition type", 489 "If you want to use this partition for swap space, select Swap.\n" 490 "If you want to put a filesystem on it, choose FS.", 491 -1, -1, 492#ifdef __ia64__ 493 3, 3, 494#else 495 2, 2, 496#endif 497 fs_types, selection, NULL, NULL); 498 restorescr(w); 499 if (!i) { 500#ifdef __ia64__ 501 if (!strcmp(selection, "EFI")) 502 return PART_EFI; 503#endif 504 if (!strcmp(selection, "FS")) 505 return PART_FILESYSTEM; 506 else if (!strcmp(selection, "Swap")) 507 return PART_SWAP; 508 } 509 return PART_NONE; 510} 511 512/* If the user wants a special newfs command for this, set it */ 513static void 514getNewfsCmd(PartInfo *p) 515{ 516 char buffer[NEWFS_CMD_ARGS_MAX]; 517 char *val; 518 519 switch (p->newfs_type) { 520 case NEWFS_UFS: 521 snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s %s %s %s", 522 NEWFS_UFS_CMD, p->newfs_data.newfs_ufs.softupdates ? "-U" : "", 523 p->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2", 524 p->newfs_data.newfs_ufs.user_options); 525 break; 526 case NEWFS_MSDOS: 527 snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s", NEWFS_MSDOS_CMD); 528 break; 529 case NEWFS_CUSTOM: 530 strcpy(buffer, p->newfs_data.newfs_custom.command); 531 break; 532 } 533 534 val = msgGetInput(buffer, 535 "Please enter the newfs command and options you'd like to use in\n" 536 "creating this file system."); 537 if (val != NULL) { 538 p->newfs_type = NEWFS_CUSTOM; 539 strlcpy(p->newfs_data.newfs_custom.command, val, NEWFS_CMD_ARGS_MAX); 540 } 541} 542 543static void 544getNewfsOptionalArguments(PartInfo *p) 545{ 546 char buffer[NEWFS_CMD_ARGS_MAX]; 547 char *val; 548 549 /* Must be UFS, per argument checking in I/O routines. */ 550 551 strlcpy(buffer, p->newfs_data.newfs_ufs.user_options, 552 NEWFS_CMD_ARGS_MAX); 553 val = msgGetInput(buffer, 554 "Please enter any additional UFS newfs options you'd like to\n" 555 "use in creating this file system."); 556 if (val != NULL) 557 strlcpy(p->newfs_data.newfs_ufs.user_options, val, 558 NEWFS_CMD_ARGS_MAX); 559} 560 561#define MAX_MOUNT_NAME 9 562 563#define PART_PART_COL 0 564#define PART_MOUNT_COL 10 565#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 566#define PART_NEWFS_COL (PART_SIZE_COL + 8) 567#define PART_OFF 38 568 569#define TOTAL_AVAIL_LINES (10) 570#define PSLICE_SHOWABLE (4) 571 572 573/* stick this all up on the screen */ 574static void 575print_label_chunks(void) 576{ 577 int i, j, srow, prow, pcol; 578 daddr_t sz; 579 char clrmsg[80]; 580 int ChunkPartStartRow; 581 WINDOW *ChunkWin; 582 583 /********************************************************/ 584 /*** These values are for controling screen resources ***/ 585 /*** Each label line holds up to 2 labels, so beware! ***/ 586 /*** strategy will be to try to always make sure the ***/ 587 /*** highlighted label is in the active display area. ***/ 588 /********************************************************/ 589 int pslice_max, label_max; 590 int pslice_count, label_count, label_focus_found, pslice_focus_found; 591 592 attrset(A_REVERSE); 593 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 594 attrset(A_NORMAL); 595 596 /*** Count the number of parition slices ***/ 597 pslice_count = 0; 598 for (i = 0; label_chunk_info[i].c ; i++) { 599 if (label_chunk_info[i].type == PART_SLICE) 600 ++pslice_count; 601 } 602 pslice_max = pslice_count; 603 604 /*** 4 line max for partition slices ***/ 605 if (pslice_max > PSLICE_SHOWABLE) { 606 pslice_max = PSLICE_SHOWABLE; 607 } 608 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; 609 610 /*** View partition slices modulo pslice_max ***/ 611 label_max = TOTAL_AVAIL_LINES - pslice_max; 612 613 for (i = 0; i < 2; i++) { 614 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 615 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 616 617 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 618 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 619 620 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); 621 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); 622 623 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 624 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 625 } 626 srow = CHUNK_SLICE_START_ROW; 627 prow = 0; 628 pcol = 0; 629 630 /*** these variables indicate that the focused item is shown currently ***/ 631 label_focus_found = 0; 632 pslice_focus_found = 0; 633 634 label_count = 0; 635 pslice_count = 0; 636 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 637 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 638 639 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 640 641 wclear(ChunkWin); 642 /*** wrefresh(ChunkWin); ***/ 643 644 for (i = 0; label_chunk_info[i].c; i++) { 645 /* Is it a slice entry displayed at the top? */ 646 if (label_chunk_info[i].type == PART_SLICE) { 647 /*** This causes the new pslice to replace the previous display ***/ 648 /*** focus must remain on the most recently active pslice ***/ 649 if (pslice_count == pslice_max) { 650 if (pslice_focus_found) { 651 /*** This is where we can mark the more following ***/ 652 attrset(A_BOLD); 653 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 654 attrset(A_NORMAL); 655 continue; 656 } 657 else { 658 /*** this is where we set the more previous ***/ 659 attrset(A_BOLD); 660 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 661 attrset(A_NORMAL); 662 pslice_count = 0; 663 srow = CHUNK_SLICE_START_ROW; 664 } 665 } 666 667 sz = space_free(label_chunk_info[i].c); 668 if (i == here) 669 attrset(ATTR_SELECTED); 670 if (i == pslice_focus) 671 pslice_focus_found = -1; 672 673 if (label_chunk_info[i].c->type == whole) { 674 if (sz >= 100 * ONE_GIG) 675 mvprintw(srow++, 0, 676 "Disk: %s\t\tFree: %jd blocks (%jdGB)", 677 label_chunk_info[i].c->disk->name, (intmax_t)sz, 678 (intmax_t)(sz / ONE_GIG)); 679 else 680 mvprintw(srow++, 0, 681 "Disk: %s\t\tFree: %jd blocks (%jdMB)", 682 label_chunk_info[i].c->disk->name, (intmax_t)sz, 683 (intmax_t)(sz / ONE_MEG)); 684 } else { 685 if (sz >= 100 * ONE_GIG) 686 mvprintw(srow++, 0, 687 "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdGB)", 688 label_chunk_info[i].c->disk->name, 689 label_chunk_info[i].c->name, 690 (intmax_t)sz, (intmax_t)(sz / ONE_GIG)); 691 else 692 mvprintw(srow++, 0, 693 "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdMB)", 694 label_chunk_info[i].c->disk->name, 695 label_chunk_info[i].c->name, 696 (intmax_t)sz, (intmax_t)(sz / ONE_MEG)); 697 } 698 attrset(A_NORMAL); 699 clrtoeol(); 700 move(0, 0); 701 /*** refresh(); ***/ 702 ++pslice_count; 703 } 704 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 705 else { 706 char onestr[PART_OFF], num[10], *mountpoint, newfs[12]; 707 708 /* 709 * We copy this into a blank-padded string so that it looks like 710 * a solid bar in reverse-video 711 */ 712 memset(onestr, ' ', PART_OFF - 1); 713 onestr[PART_OFF - 1] = '\0'; 714 715 /*** Track how many labels have been displayed ***/ 716 if (label_count == ((label_max - 1 ) * 2)) { 717 if (label_focus_found) { 718 continue; 719 } 720 else { 721 label_count = 0; 722 prow = 0; 723 pcol = 0; 724 } 725 } 726 727 /* Go for two columns if we've written one full columns worth */ 728 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 729 if (label_count == label_max - 1) { 730 pcol = PART_OFF; 731 prow = 0; 732 } 733 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 734 /* If it's a filesystem, display the mountpoint */ 735 if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM 736 || label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI)) 737 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 738 else if (label_chunk_info[i].type == PART_SWAP) 739 mountpoint = "swap"; 740 else 741 mountpoint = "<none>"; 742 743 /* Now display the newfs field */ 744 if (label_chunk_info[i].type == PART_FAT) 745 strcpy(newfs, "DOS"); 746#if defined(__ia64__) 747 else if (label_chunk_info[i].type == PART_EFI) { 748 strcpy(newfs, "EFI"); 749 if (label_chunk_info[i].c->private_data) { 750 strcat(newfs, " "); 751 PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; 752 strcat(newfs, pi->do_newfs ? " Y" : " N"); 753 } 754 } 755#endif 756 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) { 757 PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; 758 759 switch (pi->newfs_type) { 760 case NEWFS_UFS: 761 strcpy(newfs, NEWFS_UFS_STRING); 762 if (pi->newfs_data.newfs_ufs.ufs1) 763 strcat(newfs, "1"); 764 else 765 strcat(newfs, "2"); 766 if (pi->newfs_data.newfs_ufs.softupdates) 767 strcat(newfs, "+S"); 768 else 769 strcat(newfs, " "); 770 771 break; 772 case NEWFS_MSDOS: 773 strcpy(newfs, "FAT"); 774 break; 775 case NEWFS_CUSTOM: 776 strcpy(newfs, "CUST"); 777 break; 778 } 779 strcat(newfs, pi->do_newfs ? " Y" : " N "); 780 } 781 else if (label_chunk_info[i].type == PART_SWAP) 782 strcpy(newfs, "SWAP"); 783 else 784 strcpy(newfs, "*"); 785 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 786 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 787 if (label_chunk_info[i].c->size == 0) 788 snprintf(num, 10, "%5dMB", 0); 789 else if (label_chunk_info[i].c->size < (100 * ONE_GIG)) 790 snprintf(num, 10, "%5jdMB", 791 (intmax_t)label_chunk_info[i].c->size / ONE_MEG); 792 else 793 snprintf(num, 10, "%5jdGB", 794 (intmax_t)label_chunk_info[i].c->size / ONE_GIG); 795 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 796 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 797 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 798 if (i == label_focus) { 799 label_focus_found = -1; 800 wattrset(ChunkWin, A_BOLD); 801 } 802 if (i == here) 803 wattrset(ChunkWin, ATTR_SELECTED); 804 805 /*** lazy man's way of expensively padding this string ***/ 806 while (strlen(onestr) < 37) 807 strcat(onestr, " "); 808 809 mvwaddstr(ChunkWin, prow, pcol, onestr); 810 wattrset(ChunkWin, A_NORMAL); 811 move(0, 0); 812 ++prow; 813 ++label_count; 814 } 815 } 816 817 /*** this will erase all the extra stuff ***/ 818 memset(clrmsg, ' ', 37); 819 clrmsg[37] = '\0'; 820 821 while (pslice_count < pslice_max) { 822 mvprintw(srow++, 0, clrmsg); 823 clrtoeol(); 824 ++pslice_count; 825 } 826 while (label_count < (2 * (label_max - 1))) { 827 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 828 ++label_count; 829 if (prow == (label_max - 1)) { 830 prow = 0; 831 pcol = PART_OFF; 832 } 833 } 834 refresh(); 835 wrefresh(ChunkWin); 836} 837 838static void 839print_command_summary(void) 840{ 841 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 842 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 843 if (!RunningAsInit) 844 mvprintw(18, 56, "W = Write"); 845 mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates Z = Custom Newfs"); 846 mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults R = Delete+Merge"); 847 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 848 move(0, 0); 849} 850 851static void 852clear_wins(void) 853{ 854 extern void print_label_chunks(); 855 clear(); 856 print_label_chunks(); 857} 858 859static int 860diskLabel(Device *dev) 861{ 862 daddr_t sz; 863 int key = 0; 864 Boolean labeling; 865 char *msg = NULL; 866 PartInfo *p, *oldp; 867 PartType type; 868 Device **devs; 869 WINDOW *w = savescr(); 870 871 label_focus = 0; 872 pslice_focus = 0; 873 here = 0; 874 875 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 876 if (!devs) { 877 msgConfirm("No disks found!"); 878 restorescr(w); 879 return DITEM_FAILURE; 880 } 881 labeling = TRUE; 882 keypad(stdscr, TRUE); 883 record_label_chunks(devs, dev); 884 885 clear(); 886 while (labeling) { 887 char *cp; 888 int rflags = DELCHUNK_NORMAL; 889 890 print_label_chunks(); 891 print_command_summary(); 892 if (msg) { 893 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 894 clrtoeol(); 895 beep(); 896 msg = NULL; 897 } 898 else { 899 move(23, 0); 900 clrtoeol(); 901 } 902 903 refresh(); 904 key = getch(); 905 switch (toupper(key)) { 906 int i; 907 static char _msg[40]; 908 909 case '\014': /* ^L */ 910 clear_wins(); 911 break; 912 913 case '\020': /* ^P */ 914 case KEY_UP: 915 case '-': 916 if (here != 0) 917 --here; 918 else 919 while (label_chunk_info[here + 1].c) 920 ++here; 921 break; 922 923 case '\016': /* ^N */ 924 case KEY_DOWN: 925 case '+': 926 case '\r': 927 case '\n': 928 if (label_chunk_info[here + 1].c) 929 ++here; 930 else 931 here = 0; 932 break; 933 934 case KEY_HOME: 935 here = 0; 936 break; 937 938 case KEY_END: 939 while (label_chunk_info[here + 1].c) 940 ++here; 941 break; 942 943 case KEY_F(1): 944 case '?': 945 systemDisplayHelp("partition"); 946 clear_wins(); 947 break; 948 949 case '1': 950 if (label_chunk_info[here].type == PART_FILESYSTEM) { 951 PartInfo *pi = 952 ((PartInfo *)label_chunk_info[here].c->private_data); 953 954 if ((pi != NULL) && 955 (pi->newfs_type == NEWFS_UFS)) { 956 pi->newfs_data.newfs_ufs.ufs1 = true; 957 } else 958 msg = MSG_NOT_APPLICABLE; 959 } else 960 msg = MSG_NOT_APPLICABLE; 961 break; 962 break; 963 964 case '2': 965 if (label_chunk_info[here].type == PART_FILESYSTEM) { 966 PartInfo *pi = 967 ((PartInfo *)label_chunk_info[here].c->private_data); 968 969 if ((pi != NULL) && 970 (pi->newfs_type == NEWFS_UFS)) { 971 pi->newfs_data.newfs_ufs.ufs1 = false; 972 } else 973 msg = MSG_NOT_APPLICABLE; 974 } else 975 msg = MSG_NOT_APPLICABLE; 976 break; 977 break; 978 979 case 'A': 980 if (label_chunk_info[here].type != PART_SLICE) { 981 msg = "You can only do this in a disk slice (at top of screen)"; 982 break; 983 } 984 /* 985 * Generate standard partitions automatically. If we do not 986 * have sufficient space we attempt to scale-down the size 987 * of the partitions within certain bounds. 988 */ 989 { 990 int perc; 991 int req = 0; 992 993 for (perc = 100; perc > 0; perc -= 5) { 994 req = 0; /* reset for each loop */ 995 if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL) 996 break; 997 } 998 if (msg) { 999 if (req) { 1000 msgConfirm(msg); 1001 clear_wins(); 1002 msg = NULL; 1003 } 1004 } 1005 } 1006 break; 1007 1008 case 'C': 1009 if (label_chunk_info[here].type != PART_SLICE) { 1010 msg = "You can only do this in a master partition (see top of screen)"; 1011 break; 1012 } 1013 sz = space_free(label_chunk_info[here].c); 1014 if (sz <= FS_MIN_SIZE) { 1015 msg = "Not enough space to create an additional FreeBSD partition"; 1016 break; 1017 } 1018 else { 1019 char *val; 1020 daddr_t size; 1021 struct chunk *tmp; 1022 char osize[80]; 1023 u_long flags = 0; 1024 1025#ifdef __powerpc__ 1026 /* Always use the maximum size for apple partitions */ 1027 if (label_chunk_info[here].c->type == apple) 1028 size = sz; 1029 else { 1030#endif 1031 sprintf(osize, "%jd", (intmax_t)sz); 1032 val = msgGetInput(osize, 1033 "Please specify the partition size in blocks or append a trailing G for\n" 1034#ifdef __ia64__ 1035 "gigabytes, M for megabytes.\n" 1036#else 1037 "gigabytes, M for megabytes, or C for cylinders.\n" 1038#endif 1039 "%jd blocks (%jdMB) are free.", 1040 (intmax_t)sz, (intmax_t)sz / ONE_MEG); 1041 if (!val || (size = strtoimax(val, &cp, 0)) <= 0) { 1042 clear_wins(); 1043 break; 1044 } 1045 1046 if (*cp) { 1047 if (toupper(*cp) == 'M') 1048 size *= ONE_MEG; 1049 else if (toupper(*cp) == 'G') 1050 size *= ONE_GIG; 1051#ifndef __ia64__ 1052 else if (toupper(*cp) == 'C') 1053 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 1054#endif 1055 } 1056 if (size <= FS_MIN_SIZE) { 1057 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 1058 clear_wins(); 1059 break; 1060 } 1061#ifdef __powerpc__ 1062 } 1063#endif 1064 type = get_partition_type(); 1065 if (type == PART_NONE) { 1066 clear_wins(); 1067 beep(); 1068 break; 1069 } 1070 1071 if (type == PART_FILESYSTEM || type == PART_EFI) { 1072 if ((p = get_mountpoint(NULL)) == NULL) { 1073 clear_wins(); 1074 beep(); 1075 break; 1076 } 1077 else if (!strcmp(p->mountpoint, "/")) { 1078 if (type != PART_FILESYSTEM) { 1079 clear_wins(); 1080 beep(); 1081 break; 1082 } 1083 else 1084 flags |= CHUNK_IS_ROOT; 1085 } 1086 else 1087 flags &= ~CHUNK_IS_ROOT; 1088 } 1089 else 1090 p = NULL; 1091 1092 if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) { 1093 msgConfirm("Warning: This is smaller than the recommended size for a\n" 1094 "root partition. For a variety of reasons, root\n" 1095 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 1096 } 1097 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1098 label_chunk_info[here].c, size, 1099#ifdef __ia64__ 1100 (type == PART_EFI) ? efi : part, 1101 (type == PART_EFI) ? 0 : (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 1102#else 1103 part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 1104#endif 1105 flags); 1106 if (!tmp) { 1107 msgConfirm("Unable to create the partition. Too big?"); 1108 clear_wins(); 1109 break; 1110 } 1111 1112#ifdef __alpha__ 1113 /* 1114 * SRM requires that the root partition is at the 1115 * begining of the disk and cannot boot otherwise. 1116 * Warn Alpha users if they are about to shoot themselves in 1117 * the foot in this way. 1118 * 1119 * Since partitions may not start precisely at offset 0 we 1120 * check for a "close to 0" instead. :-( 1121 */ 1122 if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) { 1123 msgConfirm("Your root partition `a' does not seem to be the first\n" 1124 "partition. The Alpha's firmware can only boot from the\n" 1125 "first partition. So it is unlikely that your current\n" 1126 "disk layout will be bootable boot after installation.\n" 1127 "\n" 1128 "Please allocate the root partition before allocating\n" 1129 "any others.\n"); 1130 } 1131#endif /* alpha */ 1132 1133 tmp->private_data = p; 1134 tmp->private_free = safe_free; 1135 if (variable_cmp(DISK_LABELLED, "written")) 1136 variable_set2(DISK_LABELLED, "yes", 0); 1137 record_label_chunks(devs, dev); 1138 clear_wins(); 1139 /* This is where we assign focus to new label so it shows. */ 1140 { 1141 int i; 1142 label_focus = -1; 1143 for (i = 0; label_chunk_info[i].c; ++i) { 1144 if (label_chunk_info[i].c == tmp) { 1145 label_focus = i; 1146 break; 1147 } 1148 } 1149 if (label_focus == -1) 1150 label_focus = i - 1; 1151 } 1152 } 1153 break; 1154 1155 case KEY_DC: 1156 case 'R': /* recover space (delete w/ recover) */ 1157 /* 1158 * Delete the partition w/ space recovery. 1159 */ 1160 rflags = DELCHUNK_RECOVER; 1161 /* fall through */ 1162 case 'D': /* delete */ 1163 if (label_chunk_info[here].type == PART_SLICE) { 1164 msg = MSG_NOT_APPLICABLE; 1165 break; 1166 } 1167 else if (label_chunk_info[here].type == PART_FAT) { 1168 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1169 break; 1170 } 1171 Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags); 1172 if (variable_cmp(DISK_LABELLED, "written")) 1173 variable_set2(DISK_LABELLED, "yes", 0); 1174 record_label_chunks(devs, dev); 1175 break; 1176 1177 case 'M': /* mount */ 1178 switch(label_chunk_info[here].type) { 1179 case PART_SLICE: 1180 msg = MSG_NOT_APPLICABLE; 1181 break; 1182 1183 case PART_SWAP: 1184 msg = "You don't need to specify a mountpoint for a swap partition."; 1185 break; 1186 1187 case PART_FAT: 1188 case PART_EFI: 1189 case PART_FILESYSTEM: 1190 oldp = label_chunk_info[here].c->private_data; 1191 p = get_mountpoint(label_chunk_info[here].c); 1192 if (p) { 1193 if (!oldp) 1194 p->do_newfs = FALSE; 1195 if ((label_chunk_info[here].type == PART_FAT || 1196 label_chunk_info[here].type == PART_EFI) && 1197 (!strcmp(p->mountpoint, "/") || 1198 !strcmp(p->mountpoint, "/usr") || 1199 !strcmp(p->mountpoint, "/var"))) { 1200 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1201 strcpy(p->mountpoint, "/bogus"); 1202 } 1203 } 1204 if (variable_cmp(DISK_LABELLED, "written")) 1205 variable_set2(DISK_LABELLED, "yes", 0); 1206 record_label_chunks(devs, dev); 1207 clear_wins(); 1208 break; 1209 1210 default: 1211 msgFatal("Bogus partition under cursor???"); 1212 break; 1213 } 1214 break; 1215 1216 case 'N': /* Set newfs options */ 1217 if (label_chunk_info[here].c->private_data && 1218 ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) 1219 getNewfsOptionalArguments( 1220 label_chunk_info[here].c->private_data); 1221 else 1222 msg = MSG_NOT_APPLICABLE; 1223 clear_wins(); 1224 break; 1225 1226 case 'S': /* Toggle soft updates flag */ 1227 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1228 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1229 if (pi != NULL && 1230 pi->newfs_type == NEWFS_UFS) 1231 pi->newfs_data.newfs_ufs.softupdates = 1232 !pi->newfs_data.newfs_ufs.softupdates; 1233 else 1234 msg = MSG_NOT_APPLICABLE; 1235 } 1236 else 1237 msg = MSG_NOT_APPLICABLE; 1238 break; 1239 1240 case 'T': /* Toggle newfs state */ 1241 if ((label_chunk_info[here].type == PART_FILESYSTEM) && 1242 (label_chunk_info[here].c->private_data)) { 1243 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1244 if (!pi->do_newfs) 1245 label_chunk_info[here].c->flags |= CHUNK_NEWFS; 1246 else 1247 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; 1248 1249 label_chunk_info[here].c->private_data = 1250 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs 1251 : TRUE); 1252 if (pi != NULL && 1253 pi->newfs_type == NEWFS_UFS) { 1254 PartInfo *pi_new = label_chunk_info[here].c->private_data; 1255 1256 pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs; 1257 } 1258 safe_free(pi); 1259 label_chunk_info[here].c->private_free = safe_free; 1260 if (variable_cmp(DISK_LABELLED, "written")) 1261 variable_set2(DISK_LABELLED, "yes", 0); 1262 } 1263#if defined(__ia64__) 1264 else if (label_chunk_info[here].type == PART_EFI && 1265 label_chunk_info[here].c->private_data) { 1266 PartInfo *pi = 1267 ((PartInfo *)label_chunk_info[here].c->private_data); 1268 1269 if (!pi->do_newfs) 1270 label_chunk_info[here].c->flags |= CHUNK_NEWFS; 1271 else 1272 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; 1273 1274 label_chunk_info[here].c->private_data = 1275 new_efi_part(pi->mountpoint, !pi->do_newfs); 1276 safe_free(pi); 1277 label_chunk_info[here].c->private_free = safe_free; 1278 if (variable_cmp(DISK_LABELLED, "written")) 1279 variable_set2(DISK_LABELLED, "yes", 0); 1280 } 1281#endif 1282 else 1283 msg = MSG_NOT_APPLICABLE; 1284 break; 1285 1286 case 'U': 1287 clear(); 1288 if (!variable_cmp(DISK_LABELLED, "written")) { 1289 msgConfirm("You've already written out your changes -\n" 1290 "it's too late to undo!"); 1291 } 1292 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 1293 variable_unset(DISK_PARTITIONED); 1294 variable_unset(DISK_LABELLED); 1295 for (i = 0; devs[i]; i++) { 1296 Disk *d; 1297 1298 if (!devs[i]->enabled) 1299 continue; 1300 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1301 Free_Disk(devs[i]->private); 1302 devs[i]->private = d; 1303#ifdef WITH_SLICES 1304 diskPartition(devs[i]); 1305#endif 1306 } 1307 } 1308 record_label_chunks(devs, dev); 1309 } 1310 clear_wins(); 1311 break; 1312 1313 case 'W': 1314 if (!variable_cmp(DISK_LABELLED, "written")) { 1315 msgConfirm("You've already written out your changes - if you\n" 1316 "wish to overwrite them, you'll have to restart\n" 1317 "sysinstall first."); 1318 } 1319 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 1320 "installation. If you are installing FreeBSD for the first time\n" 1321 "then you should simply type Q when you're finished here and your\n" 1322 "changes will be committed in one batch automatically at the end of\n" 1323 "these questions.\n\n" 1324 "Are you absolutely sure you want to do this now?")) { 1325 variable_set2(DISK_LABELLED, "yes", 0); 1326 diskLabelCommit(NULL); 1327 } 1328 clear_wins(); 1329 break; 1330 1331 case 'Z': /* Set newfs command line */ 1332 if (label_chunk_info[here].c->private_data && 1333 ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) 1334 getNewfsCmd(label_chunk_info[here].c->private_data); 1335 else 1336 msg = MSG_NOT_APPLICABLE; 1337 clear_wins(); 1338 break; 1339 1340#ifndef __ia64__ 1341 case '|': 1342 if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" 1343 "This is an entirely undocumented feature which you are not\n" 1344 "expected to understand!")) { 1345 int i; 1346 Device **devs; 1347 1348 dialog_clear(); 1349 end_dialog(); 1350 DialogActive = FALSE; 1351 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1352 if (!devs) { 1353 msgConfirm("Can't find any disk devices!"); 1354 break; 1355 } 1356 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1357 if (devs[i]->enabled) 1358 slice_wizard(((Disk *)devs[i]->private)); 1359 } 1360 if (variable_cmp(DISK_LABELLED, "written")) 1361 variable_set2(DISK_LABELLED, "yes", 0); 1362 DialogActive = TRUE; 1363 record_label_chunks(devs, dev); 1364 clear_wins(); 1365 } 1366 else 1367 msg = "A most prudent choice!"; 1368 break; 1369#endif 1370 1371 case '\033': /* ESC */ 1372 case 'Q': 1373 labeling = FALSE; 1374 break; 1375 1376 default: 1377 beep(); 1378 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1379 msg = _msg; 1380 break; 1381 } 1382 if (label_chunk_info[here].type == PART_SLICE) 1383 pslice_focus = here; 1384 else 1385 label_focus = here; 1386 } 1387 restorescr(w); 1388 return DITEM_SUCCESS; 1389} 1390 1391static __inline daddr_t 1392requested_part_size(char *varName, daddr_t nom, int def, int perc) 1393{ 1394 char *cp; 1395 daddr_t sz; 1396 1397 if ((cp = variable_get(varName)) != NULL) 1398 sz = strtoimax(cp, NULL, 0); 1399 else 1400 sz = nom + (def - nom) * perc / 100; 1401 return(sz * ONE_MEG); 1402} 1403 1404/* 1405 * Attempt to auto-label the disk. 'perc' (0-100) scales 1406 * the size of the various partitions within appropriate 1407 * bounds (NOMINAL through DEFAULT sizes). The procedure 1408 * succeeds of NULL is returned. A non-null return message 1409 * is either a failure-status message (*req == 0), or 1410 * a confirmation requestor (*req == 1). *req is 0 on 1411 * entry to this call. 1412 * 1413 * We autolabel the following partitions: /, swap, /var, /tmp, /usr, 1414 * and /home. /home receives any extra left over disk space. 1415 */ 1416static char * 1417try_auto_label(Device **devs, Device *dev, int perc, int *req) 1418{ 1419 daddr_t sz; 1420 struct chunk *root_chunk = NULL; 1421 struct chunk *swap_chunk = NULL; 1422 struct chunk *usr_chunk = NULL; 1423 struct chunk *var_chunk = NULL; 1424 struct chunk *tmp_chunk = NULL; 1425 struct chunk *home_chunk = NULL; 1426 int mib[2]; 1427 unsigned long physmem; 1428 size_t size; 1429 Chunk *rootdev, *swapdev, *usrdev, *vardev; 1430 Chunk *tmpdev, *homedev; 1431 char *msg = NULL; 1432 1433 sz = space_free(label_chunk_info[here].c); 1434 if (sz <= FS_MIN_SIZE) 1435 return("Not enough free space to create a new partition in the slice"); 1436 1437 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, 1438 &vardev, &tmpdev, &homedev); 1439 if (!rootdev) { 1440 sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc); 1441 1442 root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1443 label_chunk_info[here].c, sz, part, 1444 FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE); 1445 if (!root_chunk) { 1446 *req = 1; 1447 msg = "Unable to create the root partition. Too big?"; 1448 goto done; 1449 } 1450 root_chunk->private_data = new_part("/", TRUE); 1451 root_chunk->private_free = safe_free; 1452 root_chunk->flags |= CHUNK_NEWFS; 1453 record_label_chunks(devs, dev); 1454 } 1455 if (!swapdev) { 1456 sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc); 1457 if (sz == 0) { 1458 daddr_t nom; 1459 daddr_t def; 1460 1461 mib[0] = CTL_HW; 1462 mib[1] = HW_PHYSMEM; 1463 size = sizeof physmem; 1464 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 1465 def = 2 * (int)(physmem / 512); 1466 if (def < SWAP_MIN_SIZE * ONE_MEG) 1467 def = SWAP_MIN_SIZE * ONE_MEG; 1468 if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG) 1469 def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG; 1470 nom = (int)(physmem / 512) / 8; 1471 sz = nom + (def - nom) * perc / 100; 1472 } 1473 swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1474 label_chunk_info[here].c, sz, part, 1475 FS_SWAP, CHUNK_AUTO_SIZE); 1476 if (!swap_chunk) { 1477 *req = 1; 1478 msg = "Unable to create the swap partition. Too big?"; 1479 goto done; 1480 } 1481 swap_chunk->private_data = 0; 1482 swap_chunk->private_free = safe_free; 1483 record_label_chunks(devs, dev); 1484 } 1485 if (!vardev) { 1486 sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc); 1487 1488 var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1489 label_chunk_info[here].c, sz, part, 1490 FS_BSDFFS, CHUNK_AUTO_SIZE); 1491 if (!var_chunk) { 1492 *req = 1; 1493 msg = "Not enough free space for /var - you will need to\n" 1494 "partition your disk manually with a custom install!"; 1495 goto done; 1496 } 1497 var_chunk->private_data = new_part("/var", TRUE); 1498 var_chunk->private_free = safe_free; 1499 var_chunk->flags |= CHUNK_NEWFS; 1500 record_label_chunks(devs, dev); 1501 } 1502 if (!tmpdev && !variable_get(VAR_NO_TMP)) { 1503 sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc); 1504 1505 tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1506 label_chunk_info[here].c, sz, part, 1507 FS_BSDFFS, CHUNK_AUTO_SIZE); 1508 if (!tmp_chunk) { 1509 *req = 1; 1510 msg = "Not enough free space for /tmp - you will need to\n" 1511 "partition your disk manually with a custom install!"; 1512 goto done; 1513 } 1514 tmp_chunk->private_data = new_part("/tmp", TRUE); 1515 tmp_chunk->private_free = safe_free; 1516 tmp_chunk->flags |= CHUNK_NEWFS; 1517 record_label_chunks(devs, dev); 1518 } 1519 if (!usrdev && !variable_get(VAR_NO_USR)) { 1520 sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc); 1521#if AUTO_HOME == 0 1522 sz = space_free(label_chunk_info[here].c); 1523#endif 1524 if (sz) { 1525 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 1526 *req = 1; 1527 msg = "Not enough free space for /usr - you will need to\n" 1528 "partition your disk manually with a custom install!"; 1529 } 1530 1531 usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1532 label_chunk_info[here].c, sz, part, 1533 FS_BSDFFS, CHUNK_AUTO_SIZE); 1534 if (!usr_chunk) { 1535 msg = "Unable to create the /usr partition. Not enough space?\n" 1536 "You will need to partition your disk manually with a custom install!"; 1537 goto done; 1538 } 1539 usr_chunk->private_data = new_part("/usr", TRUE); 1540 usr_chunk->private_free = safe_free; 1541 usr_chunk->flags |= CHUNK_NEWFS; 1542 record_label_chunks(devs, dev); 1543 } 1544 } 1545#if AUTO_HOME == 1 1546 if (!homedev && !variable_get(VAR_NO_HOME)) { 1547 sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc); 1548 if (sz < space_free(label_chunk_info[here].c)) 1549 sz = space_free(label_chunk_info[here].c); 1550 if (sz) { 1551 if (sz < (HOME_MIN_SIZE * ONE_MEG)) { 1552 *req = 1; 1553 msg = "Not enough free space for /home - you will need to\n" 1554 "partition your disk manually with a custom install!"; 1555 goto done; 1556 } 1557 1558 home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1559 label_chunk_info[here].c, sz, part, 1560 FS_BSDFFS, CHUNK_AUTO_SIZE); 1561 if (!home_chunk) { 1562 msg = "Unable to create the /home partition. Not enough space?\n" 1563 "You will need to partition your disk manually with a custom install!"; 1564 goto done; 1565 } 1566 home_chunk->private_data = new_part("/home", TRUE); 1567 home_chunk->private_free = safe_free; 1568 home_chunk->flags |= CHUNK_NEWFS; 1569 record_label_chunks(devs, dev); 1570 } 1571 } 1572#endif 1573 1574 /* At this point, we're reasonably "labelled" */ 1575 if (variable_cmp(DISK_LABELLED, "written")) 1576 variable_set2(DISK_LABELLED, "yes", 0); 1577 1578done: 1579 if (msg) { 1580 if (root_chunk) 1581 Delete_Chunk(root_chunk->disk, root_chunk); 1582 if (swap_chunk) 1583 Delete_Chunk(swap_chunk->disk, swap_chunk); 1584 if (var_chunk) 1585 Delete_Chunk(var_chunk->disk, var_chunk); 1586 if (tmp_chunk) 1587 Delete_Chunk(tmp_chunk->disk, tmp_chunk); 1588 if (usr_chunk) 1589 Delete_Chunk(usr_chunk->disk, usr_chunk); 1590 if (home_chunk) 1591 Delete_Chunk(home_chunk->disk, home_chunk); 1592 record_label_chunks(devs, dev); 1593 } 1594 return(msg); 1595} 1596 1597static int 1598diskLabelNonInteractive(Device *dev) 1599{ 1600 char *cp; 1601 PartType type; 1602 PartInfo *p; 1603 u_long flags; 1604 int i, status; 1605 Device **devs; 1606 Disk *d; 1607 1608 status = DITEM_SUCCESS; 1609 cp = variable_get(VAR_DISK); 1610 if (!cp) { 1611 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1612 return DITEM_FAILURE; 1613 } 1614 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1615 if (!devs) { 1616 msgConfirm("diskLabel: No disk device %s found!", cp); 1617 return DITEM_FAILURE; 1618 } 1619 if (dev) 1620 d = dev->private; 1621 else 1622 d = devs[0]->private; 1623 record_label_chunks(devs, dev); 1624 for (i = 0; label_chunk_info[i].c; i++) { 1625 Chunk *c1 = label_chunk_info[i].c; 1626 1627 if (label_chunk_info[i].type == PART_SLICE) { 1628 char name[512]; 1629 char typ[10], mpoint[50]; 1630 int entries; 1631 1632 for (entries = 1;; entries++) { 1633 intmax_t sz; 1634 int soft = 0; 1635 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1636 if ((cp = variable_get(name)) == NULL) 1637 break; 1638 if (sscanf(cp, "%s %jd %s %d", typ, &sz, mpoint, &soft) < 3) { 1639 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1640 status = DITEM_FAILURE; 1641 break; 1642 } else { 1643 Chunk *tmp; 1644 1645 flags = 0; 1646 if (!strcmp(typ, "swap")) { 1647 type = PART_SWAP; 1648 strcpy(mpoint, "SWAP"); 1649 } else { 1650 type = PART_FILESYSTEM; 1651 if (!strcmp(mpoint, "/")) 1652 flags |= CHUNK_IS_ROOT; 1653 } 1654 if (!sz) 1655 sz = space_free(c1); 1656 if (sz > space_free(c1)) { 1657 msgConfirm("Not enough free space to create partition: %s", mpoint); 1658 status = DITEM_FAILURE; 1659 break; 1660 } 1661 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1662 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1663 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1664 status = DITEM_FAILURE; 1665 break; 1666 } else { 1667 PartInfo *pi; 1668 pi = tmp->private_data = new_part(mpoint, TRUE); 1669 tmp->private_free = safe_free; 1670 pi->newfs_data.newfs_ufs.softupdates = soft; 1671 } 1672 } 1673 } 1674 } else { 1675 /* Must be something we can set a mountpoint for */ 1676 cp = variable_get(c1->name); 1677 if (cp) { 1678 char mpoint[50], do_newfs[8]; 1679 Boolean newfs = FALSE; 1680 1681 do_newfs[0] = '\0'; 1682 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1683 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1684 status = DITEM_FAILURE; 1685 break; 1686 } 1687 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1688 if (c1->private_data) { 1689 p = c1->private_data; 1690 p->do_newfs = newfs; 1691 strcpy(p->mountpoint, mpoint); 1692 } 1693 else { 1694 c1->private_data = new_part(mpoint, newfs); 1695 c1->private_free = safe_free; 1696 } 1697 if (!strcmp(mpoint, "/")) 1698 c1->flags |= CHUNK_IS_ROOT; 1699 else 1700 c1->flags &= ~CHUNK_IS_ROOT; 1701 } 1702 } 1703 } 1704 if (status == DITEM_SUCCESS) 1705 variable_set2(DISK_LABELLED, "yes", 0); 1706 return status; 1707} 1708