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$ 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(__ia64__) || defined(__sparc64__) || defined(__amd64__) 65#define ROOT_MIN_SIZE 280 66#else 67#define ROOT_MIN_SIZE 180 68#endif 69#define SWAP_MIN_SIZE 32 70#define USR_MIN_SIZE 160 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 1024 86#define USR_DEFAULT_SIZE 8192 87#define VAR_DEFAULT_SIZE 4096 88#define TMP_DEFAULT_SIZE 1024 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 512 97#define USR_NOMINAL_SIZE 1536 98#define VAR_NOMINAL_SIZE 512 99#define TMP_NOMINAL_SIZE 128 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(PartType type, char *mpoint, Boolean newfs) 368{ 369 PartInfo *pi; 370 371 if (!mpoint) 372 mpoint = (type == PART_EFI) ? "/efi" : "/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 if (type == PART_EFI) { 380 pi->newfs_type = NEWFS_MSDOS; 381 } else { 382 pi->newfs_type = NEWFS_UFS; 383 strcpy(pi->newfs_data.newfs_ufs.user_options, ""); 384 pi->newfs_data.newfs_ufs.acls = FALSE; 385 pi->newfs_data.newfs_ufs.multilabel = FALSE; 386 pi->newfs_data.newfs_ufs.softupdates = strcmp(mpoint, "/"); 387 pi->newfs_data.newfs_ufs.ufs1 = FALSE; 388 } 389 390 return pi; 391} 392 393/* Get the mountpoint for a partition and save it away */ 394static PartInfo * 395get_mountpoint(PartType type, struct chunk *old) 396{ 397 char *val; 398 PartInfo *tmp; 399 Boolean newfs; 400 401 if (old && old->private_data) 402 tmp = old->private_data; 403 else 404 tmp = NULL; 405 val = (tmp != NULL) ? tmp->mountpoint : (type == PART_EFI) ? "/efi" : NULL; 406 val = msgGetInput(val, "Please specify a mount point for the partition"); 407 if (!val || !*val) { 408 if (!old) 409 return NULL; 410 else { 411 free(old->private_data); 412 old->private_data = NULL; 413 } 414 return NULL; 415 } 416 417 /* Is it just the same value? */ 418 if (tmp && !strcmp(tmp->mountpoint, val)) 419 return NULL; 420 421 /* Did we use it already? */ 422 if (check_conflict(val)) { 423 msgConfirm("You already have a mount point for %s assigned!", val); 424 return NULL; 425 } 426 427 /* Is it bogus? */ 428 if (*val != '/') { 429 msgConfirm("Mount point must start with a / character"); 430 return NULL; 431 } 432 433 /* Is it going to be mounted on root? */ 434 if (!strcmp(val, "/")) { 435 if (old) 436 old->flags |= CHUNK_IS_ROOT; 437 } 438 else if (old) 439 old->flags &= ~CHUNK_IS_ROOT; 440 441 newfs = TRUE; 442 if (tmp) { 443 newfs = tmp->do_newfs; 444 safe_free(tmp); 445 } 446 val = string_skipwhite(string_prune(val)); 447 tmp = new_part(type, val, newfs); 448 if (old) { 449 old->private_data = tmp; 450 old->private_free = safe_free; 451 } 452 return tmp; 453} 454 455/* Get the type of the new partiton */ 456static PartType 457get_partition_type(void) 458{ 459 char selection[20]; 460 int i; 461 static unsigned char *fs_types[] = { 462#ifdef __ia64__ 463 "EFI", "An EFI system partition", 464#endif 465 "FS", "A file system", 466 "Swap", "A swap partition.", 467 }; 468 WINDOW *w = savescr(); 469 470 i = dialog_menu("Please choose a partition type", 471 "If you want to use this partition for swap space, select Swap.\n" 472 "If you want to put a filesystem on it, choose FS.", 473 -1, -1, 474#ifdef __ia64__ 475 3, 3, 476#else 477 2, 2, 478#endif 479 fs_types, selection, NULL, NULL); 480 restorescr(w); 481 if (!i) { 482#ifdef __ia64__ 483 if (!strcmp(selection, "EFI")) 484 return PART_EFI; 485#endif 486 if (!strcmp(selection, "FS")) 487 return PART_FILESYSTEM; 488 else if (!strcmp(selection, "Swap")) 489 return PART_SWAP; 490 } 491 return PART_NONE; 492} 493 494/* If the user wants a special newfs command for this, set it */ 495static void 496getNewfsCmd(PartInfo *p) 497{ 498 char buffer[NEWFS_CMD_ARGS_MAX]; 499 char *val; 500 501 switch (p->newfs_type) { 502 case NEWFS_UFS: 503 snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s %s %s %s", 504 NEWFS_UFS_CMD, p->newfs_data.newfs_ufs.softupdates ? "-U" : "", 505 p->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2", 506 p->newfs_data.newfs_ufs.user_options); 507 break; 508 case NEWFS_MSDOS: 509 snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s", NEWFS_MSDOS_CMD); 510 break; 511 case NEWFS_CUSTOM: 512 strcpy(buffer, p->newfs_data.newfs_custom.command); 513 break; 514 } 515 516 val = msgGetInput(buffer, 517 "Please enter the newfs command and options you'd like to use in\n" 518 "creating this file system."); 519 if (val != NULL) { 520 p->newfs_type = NEWFS_CUSTOM; 521 strlcpy(p->newfs_data.newfs_custom.command, val, NEWFS_CMD_ARGS_MAX); 522 } 523} 524 525static void 526getNewfsOptionalArguments(PartInfo *p) 527{ 528 char buffer[NEWFS_CMD_ARGS_MAX]; 529 char *val; 530 531 /* Must be UFS, per argument checking in I/O routines. */ 532 533 strlcpy(buffer, p->newfs_data.newfs_ufs.user_options, 534 NEWFS_CMD_ARGS_MAX); 535 val = msgGetInput(buffer, 536 "Please enter any additional UFS newfs options you'd like to\n" 537 "use in creating this file system."); 538 if (val != NULL) 539 strlcpy(p->newfs_data.newfs_ufs.user_options, val, 540 NEWFS_CMD_ARGS_MAX); 541} 542 543#define MAX_MOUNT_NAME 9 544 545#define PART_PART_COL 0 546#define PART_MOUNT_COL 10 547#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 548#define PART_NEWFS_COL (PART_SIZE_COL + 8) 549#define PART_OFF 38 550 551#define TOTAL_AVAIL_LINES (10) 552#define PSLICE_SHOWABLE (4) 553 554 555/* stick this all up on the screen */ 556static void 557print_label_chunks(void) 558{ 559 int i, j, srow, prow, pcol; 560 daddr_t sz; 561 char clrmsg[80]; 562 int ChunkPartStartRow; 563 WINDOW *ChunkWin; 564 565 /********************************************************/ 566 /*** These values are for controling screen resources ***/ 567 /*** Each label line holds up to 2 labels, so beware! ***/ 568 /*** strategy will be to try to always make sure the ***/ 569 /*** highlighted label is in the active display area. ***/ 570 /********************************************************/ 571 int pslice_max, label_max; 572 int pslice_count, label_count, label_focus_found, pslice_focus_found; 573 574 attrset(A_REVERSE); 575 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 576 attrset(A_NORMAL); 577 578 /*** Count the number of parition slices ***/ 579 pslice_count = 0; 580 for (i = 0; label_chunk_info[i].c ; i++) { 581 if (label_chunk_info[i].type == PART_SLICE) 582 ++pslice_count; 583 } 584 pslice_max = pslice_count; 585 586 /*** 4 line max for partition slices ***/ 587 if (pslice_max > PSLICE_SHOWABLE) { 588 pslice_max = PSLICE_SHOWABLE; 589 } 590 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; 591 592 /*** View partition slices modulo pslice_max ***/ 593 label_max = TOTAL_AVAIL_LINES - pslice_max; 594 595 for (i = 0; i < 2; i++) { 596 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 597 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 598 599 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 600 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 601 602 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); 603 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); 604 605 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 606 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 607 } 608 srow = CHUNK_SLICE_START_ROW; 609 prow = 0; 610 pcol = 0; 611 612 /*** these variables indicate that the focused item is shown currently ***/ 613 label_focus_found = 0; 614 pslice_focus_found = 0; 615 616 label_count = 0; 617 pslice_count = 0; 618 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 619 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 620 621 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 622 623 wclear(ChunkWin); 624 /*** wrefresh(ChunkWin); ***/ 625 626 for (i = 0; label_chunk_info[i].c; i++) { 627 /* Is it a slice entry displayed at the top? */ 628 if (label_chunk_info[i].type == PART_SLICE) { 629 /*** This causes the new pslice to replace the previous display ***/ 630 /*** focus must remain on the most recently active pslice ***/ 631 if (pslice_count == pslice_max) { 632 if (pslice_focus_found) { 633 /*** This is where we can mark the more following ***/ 634 attrset(A_BOLD); 635 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 636 attrset(A_NORMAL); 637 continue; 638 } 639 else { 640 /*** this is where we set the more previous ***/ 641 attrset(A_BOLD); 642 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 643 attrset(A_NORMAL); 644 pslice_count = 0; 645 srow = CHUNK_SLICE_START_ROW; 646 } 647 } 648 649 sz = space_free(label_chunk_info[i].c); 650 if (i == here) 651 attrset(ATTR_SELECTED); 652 if (i == pslice_focus) 653 pslice_focus_found = -1; 654 655 if (label_chunk_info[i].c->type == whole) { 656 if (sz >= 100 * ONE_GIG) 657 mvprintw(srow++, 0, 658 "Disk: %s\t\tFree: %jd blocks (%jdGB)", 659 label_chunk_info[i].c->disk->name, (intmax_t)sz, 660 (intmax_t)(sz / ONE_GIG)); 661 else 662 mvprintw(srow++, 0, 663 "Disk: %s\t\tFree: %jd blocks (%jdMB)", 664 label_chunk_info[i].c->disk->name, (intmax_t)sz, 665 (intmax_t)(sz / ONE_MEG)); 666 } else { 667 if (sz >= 100 * ONE_GIG) 668 mvprintw(srow++, 0, 669 "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdGB)", 670 label_chunk_info[i].c->disk->name, 671 label_chunk_info[i].c->name, 672 (intmax_t)sz, (intmax_t)(sz / ONE_GIG)); 673 else 674 mvprintw(srow++, 0, 675 "Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdMB)", 676 label_chunk_info[i].c->disk->name, 677 label_chunk_info[i].c->name, 678 (intmax_t)sz, (intmax_t)(sz / ONE_MEG)); 679 } 680 attrset(A_NORMAL); 681 clrtoeol(); 682 move(0, 0); 683 /*** refresh(); ***/ 684 ++pslice_count; 685 } 686 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 687 else { 688 char onestr[PART_OFF], num[10], *mountpoint, newfs[12]; 689 690 /* 691 * We copy this into a blank-padded string so that it looks like 692 * a solid bar in reverse-video 693 */ 694 memset(onestr, ' ', PART_OFF - 1); 695 onestr[PART_OFF - 1] = '\0'; 696 697 /*** Track how many labels have been displayed ***/ 698 if (label_count == ((label_max - 1 ) * 2)) { 699 if (label_focus_found) { 700 continue; 701 } 702 else { 703 label_count = 0; 704 prow = 0; 705 pcol = 0; 706 } 707 } 708 709 /* Go for two columns if we've written one full columns worth */ 710 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 711 if (label_count == label_max - 1) { 712 pcol = PART_OFF; 713 prow = 0; 714 } 715 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 716 /* If it's a filesystem, display the mountpoint */ 717 if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM 718 || label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI)) 719 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 720 else if (label_chunk_info[i].type == PART_SWAP) 721 mountpoint = "swap"; 722 else 723 mountpoint = "<none>"; 724 725 /* Now display the newfs field */ 726 if (label_chunk_info[i].type == PART_FAT) 727 strcpy(newfs, "DOS"); 728#if defined(__ia64__) 729 else if (label_chunk_info[i].type == PART_EFI) { 730 strcpy(newfs, "EFI"); 731 if (label_chunk_info[i].c->private_data) { 732 strcat(newfs, " "); 733 PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; 734 strcat(newfs, pi->do_newfs ? " Y" : " N"); 735 } 736 } 737#endif 738 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) { 739 PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data; 740 741 switch (pi->newfs_type) { 742 case NEWFS_UFS: 743 strcpy(newfs, NEWFS_UFS_STRING); 744 if (pi->newfs_data.newfs_ufs.ufs1) 745 strcat(newfs, "1"); 746 else 747 strcat(newfs, "2"); 748 if (pi->newfs_data.newfs_ufs.softupdates) 749 strcat(newfs, "+S"); 750 else 751 strcat(newfs, " "); 752 753 break; 754 case NEWFS_MSDOS: 755 strcpy(newfs, "FAT"); 756 break; 757 case NEWFS_CUSTOM: 758 strcpy(newfs, "CUST"); 759 break; 760 } 761 strcat(newfs, pi->do_newfs ? " Y" : " N "); 762 } 763 else if (label_chunk_info[i].type == PART_SWAP) 764 strcpy(newfs, "SWAP"); 765 else 766 strcpy(newfs, "*"); 767 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 768 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 769 if (label_chunk_info[i].c->size == 0) 770 snprintf(num, 10, "%5dMB", 0); 771 else if (label_chunk_info[i].c->size < (100 * ONE_GIG)) 772 snprintf(num, 10, "%5jdMB", 773 (intmax_t)label_chunk_info[i].c->size / ONE_MEG); 774 else 775 snprintf(num, 10, "%5jdGB", 776 (intmax_t)label_chunk_info[i].c->size / ONE_GIG); 777 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 778 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 779 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 780 if (i == label_focus) { 781 label_focus_found = -1; 782 wattrset(ChunkWin, A_BOLD); 783 } 784 if (i == here) 785 wattrset(ChunkWin, ATTR_SELECTED); 786 787 /*** lazy man's way of expensively padding this string ***/ 788 while (strlen(onestr) < 37) 789 strcat(onestr, " "); 790 791 mvwaddstr(ChunkWin, prow, pcol, onestr); 792 wattrset(ChunkWin, A_NORMAL); 793 move(0, 0); 794 ++prow; 795 ++label_count; 796 } 797 } 798 799 /*** this will erase all the extra stuff ***/ 800 memset(clrmsg, ' ', 37); 801 clrmsg[37] = '\0'; 802 803 while (pslice_count < pslice_max) { 804 mvprintw(srow++, 0, clrmsg); 805 clrtoeol(); 806 ++pslice_count; 807 } 808 while (label_count < (2 * (label_max - 1))) { 809 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 810 ++label_count; 811 if (prow == (label_max - 1)) { 812 prow = 0; 813 pcol = PART_OFF; 814 } 815 } 816 refresh(); 817 wrefresh(ChunkWin); 818} 819 820static void 821print_command_summary(void) 822{ 823 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 824 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 825 if (!RunningAsInit) 826 mvprintw(18, 56, "W = Write"); 827 mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates Z = Custom Newfs"); 828 mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults R = Delete+Merge"); 829 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 830 move(0, 0); 831} 832 833static void 834clear_wins(void) 835{ 836 clear(); 837 print_label_chunks(); 838} 839 840static int 841diskLabel(Device *dev) 842{ 843 daddr_t sz; 844 int key = 0; 845 Boolean labeling; 846 char *msg = NULL; 847 PartInfo *p, *oldp; 848 PartType type; 849 Device **devs; 850 WINDOW *w = savescr(); 851 852 label_focus = 0; 853 pslice_focus = 0; 854 here = 0; 855 856 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 857 if (!devs) { 858 msgConfirm("No disks found!"); 859 restorescr(w); 860 return DITEM_FAILURE; 861 } 862 labeling = TRUE; 863 keypad(stdscr, TRUE); 864 record_label_chunks(devs, dev); 865 866 clear(); 867 while (labeling) { 868 char *cp; 869 int rflags = DELCHUNK_NORMAL; 870 871 print_label_chunks(); 872 print_command_summary(); 873 if (msg) { 874 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 875 clrtoeol(); 876 beep(); 877 msg = NULL; 878 } 879 else { 880 move(23, 0); 881 clrtoeol(); 882 } 883 884 refresh(); 885 key = getch(); 886 switch (toupper(key)) { 887 int i; 888 static char _msg[40]; 889 890 case '\014': /* ^L */ 891 clear_wins(); 892 break; 893 894 case '\020': /* ^P */ 895 case KEY_UP: 896 case '-': 897 if (here != 0) 898 --here; 899 else 900 while (label_chunk_info[here + 1].c) 901 ++here; 902 break; 903 904 case '\016': /* ^N */ 905 case KEY_DOWN: 906 case '+': 907 case '\r': 908 case '\n': 909 if (label_chunk_info[here + 1].c) 910 ++here; 911 else 912 here = 0; 913 break; 914 915 case KEY_HOME: 916 here = 0; 917 break; 918 919 case KEY_END: 920 while (label_chunk_info[here + 1].c) 921 ++here; 922 break; 923 924 case KEY_F(1): 925 case '?': 926 systemDisplayHelp("partition"); 927 clear_wins(); 928 break; 929 930 case '1': 931 if (label_chunk_info[here].type == PART_FILESYSTEM) { 932 PartInfo *pi = 933 ((PartInfo *)label_chunk_info[here].c->private_data); 934 935 if ((pi != NULL) && 936 (pi->newfs_type == NEWFS_UFS)) { 937 pi->newfs_data.newfs_ufs.ufs1 = true; 938 } else 939 msg = MSG_NOT_APPLICABLE; 940 } else 941 msg = MSG_NOT_APPLICABLE; 942 break; 943 break; 944 945 case '2': 946 if (label_chunk_info[here].type == PART_FILESYSTEM) { 947 PartInfo *pi = 948 ((PartInfo *)label_chunk_info[here].c->private_data); 949 950 if ((pi != NULL) && 951 (pi->newfs_type == NEWFS_UFS)) { 952 pi->newfs_data.newfs_ufs.ufs1 = false; 953 } else 954 msg = MSG_NOT_APPLICABLE; 955 } else 956 msg = MSG_NOT_APPLICABLE; 957 break; 958 break; 959 960 case 'A': 961 if (label_chunk_info[here].type != PART_SLICE) { 962 msg = "You can only do this in a disk slice (at top of screen)"; 963 break; 964 } 965 /* 966 * Generate standard partitions automatically. If we do not 967 * have sufficient space we attempt to scale-down the size 968 * of the partitions within certain bounds. 969 */ 970 { 971 int perc; 972 int req = 0; 973 974 for (perc = 100; perc > 0; perc -= 5) { 975 req = 0; /* reset for each loop */ 976 if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL) 977 break; 978 } 979 if (msg) { 980 if (req) { 981 msgConfirm("%s", msg); 982 clear_wins(); 983 msg = NULL; 984 } 985 } 986 } 987 break; 988 989 case 'C': 990 if (label_chunk_info[here].type != PART_SLICE) { 991 msg = "You can only do this in a master partition (see top of screen)"; 992 break; 993 } 994 sz = space_free(label_chunk_info[here].c); 995 if (sz <= FS_MIN_SIZE) { 996 msg = "Not enough space to create an additional FreeBSD partition"; 997 break; 998 } 999 else { 1000 char *val; 1001 daddr_t size; 1002 long double dsize; 1003 struct chunk *tmp; 1004 char osize[80]; 1005 u_long flags = 0; 1006 1007#ifdef __powerpc__ 1008 /* Always use the maximum size for apple partitions */ 1009 if (label_chunk_info[here].c->type == apple) 1010 size = sz; 1011 else { 1012#endif 1013 sprintf(osize, "%jd", (intmax_t)sz); 1014 val = msgGetInput(osize, 1015 "Please specify the partition size in blocks or append a trailing G for\n" 1016#ifdef __ia64__ 1017 "gigabytes, M for megabytes.\n" 1018#else 1019 "gigabytes, M for megabytes, or C for cylinders.\n" 1020#endif 1021 "%jd blocks (%jdMB) are free.", 1022 (intmax_t)sz, (intmax_t)sz / ONE_MEG); 1023 if (!val || (dsize = strtold(val, &cp)) <= 0) { 1024 clear_wins(); 1025 break; 1026 } 1027 1028 if (*cp) { 1029 if (toupper(*cp) == 'M') 1030 size = (daddr_t) (dsize * ONE_MEG); 1031 else if (toupper(*cp) == 'G') 1032 size = (daddr_t) (dsize * ONE_GIG); 1033#ifndef __ia64__ 1034 else if (toupper(*cp) == 'C') 1035 size = (daddr_t) dsize * (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 1036#endif 1037 else 1038 size = (daddr_t) dsize; 1039 } else { 1040 size = (daddr_t) dsize; 1041 } 1042 1043 if (size < FS_MIN_SIZE) { 1044 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 1045 clear_wins(); 1046 break; 1047 } 1048#ifdef __powerpc__ 1049 } 1050#endif 1051 type = get_partition_type(); 1052 if (type == PART_NONE) { 1053 clear_wins(); 1054 beep(); 1055 break; 1056 } 1057 1058 if (type == PART_FILESYSTEM || type == PART_EFI) { 1059 if ((p = get_mountpoint(type, NULL)) == NULL) { 1060 clear_wins(); 1061 beep(); 1062 break; 1063 } 1064 else if (!strcmp(p->mountpoint, "/")) { 1065 if (type != PART_FILESYSTEM) { 1066 clear_wins(); 1067 beep(); 1068 break; 1069 } 1070 else 1071 flags |= CHUNK_IS_ROOT; 1072 } 1073 else 1074 flags &= ~CHUNK_IS_ROOT; 1075 } 1076 else 1077 p = NULL; 1078 1079 if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) { 1080 msgConfirm("Warning: This is smaller than the recommended size for a\n" 1081 "root partition. For a variety of reasons, root\n" 1082 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 1083 } 1084 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1085 label_chunk_info[here].c, size, 1086#ifdef __ia64__ 1087 (type == PART_EFI) ? efi : part, 1088 (type == PART_EFI) ? 0 : (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 1089#else 1090 part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 1091#endif 1092 flags); 1093 if (!tmp) { 1094 msgConfirm("Unable to create the partition. Too big?"); 1095 clear_wins(); 1096 break; 1097 } 1098 1099 tmp->private_data = p; 1100 tmp->private_free = safe_free; 1101 if (variable_cmp(DISK_LABELLED, "written")) 1102 variable_set2(DISK_LABELLED, "yes", 0); 1103 record_label_chunks(devs, dev); 1104 clear_wins(); 1105 /* This is where we assign focus to new label so it shows. */ 1106 { 1107 int i; 1108 label_focus = -1; 1109 for (i = 0; label_chunk_info[i].c; ++i) { 1110 if (label_chunk_info[i].c == tmp) { 1111 label_focus = i; 1112 break; 1113 } 1114 } 1115 if (label_focus == -1) 1116 label_focus = i - 1; 1117 } 1118 } 1119 break; 1120 1121 case KEY_DC: 1122 case 'R': /* recover space (delete w/ recover) */ 1123 /* 1124 * Delete the partition w/ space recovery. 1125 */ 1126 rflags = DELCHUNK_RECOVER; 1127 /* fall through */ 1128 case 'D': /* delete */ 1129 if (label_chunk_info[here].type == PART_SLICE) { 1130 msg = MSG_NOT_APPLICABLE; 1131 break; 1132 } 1133 else if (label_chunk_info[here].type == PART_FAT) { 1134 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1135 break; 1136 } 1137 Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags); 1138 if (variable_cmp(DISK_LABELLED, "written")) 1139 variable_set2(DISK_LABELLED, "yes", 0); 1140 record_label_chunks(devs, dev); 1141 break; 1142 1143 case 'M': /* mount */ 1144 switch(label_chunk_info[here].type) { 1145 case PART_SLICE: 1146 msg = MSG_NOT_APPLICABLE; 1147 break; 1148 1149 case PART_SWAP: 1150 msg = "You don't need to specify a mountpoint for a swap partition."; 1151 break; 1152 1153 case PART_FAT: 1154 case PART_EFI: 1155 case PART_FILESYSTEM: 1156 oldp = label_chunk_info[here].c->private_data; 1157 p = get_mountpoint(label_chunk_info[here].type, label_chunk_info[here].c); 1158 if (p) { 1159 if (!oldp) 1160 p->do_newfs = FALSE; 1161 if ((label_chunk_info[here].type == PART_FAT || 1162 label_chunk_info[here].type == PART_EFI) && 1163 (!strcmp(p->mountpoint, "/") || 1164 !strcmp(p->mountpoint, "/usr") || 1165 !strcmp(p->mountpoint, "/var"))) { 1166 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1167 strcpy(p->mountpoint, "/bogus"); 1168 } 1169 } 1170 if (variable_cmp(DISK_LABELLED, "written")) 1171 variable_set2(DISK_LABELLED, "yes", 0); 1172 record_label_chunks(devs, dev); 1173 clear_wins(); 1174 break; 1175 1176 default: 1177 msgFatal("Bogus partition under cursor???"); 1178 break; 1179 } 1180 break; 1181 1182 case 'N': /* Set newfs options */ 1183 if (label_chunk_info[here].c->private_data && 1184 ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) 1185 getNewfsOptionalArguments( 1186 label_chunk_info[here].c->private_data); 1187 else 1188 msg = MSG_NOT_APPLICABLE; 1189 clear_wins(); 1190 break; 1191 1192 case 'S': /* Toggle soft updates flag */ 1193 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1194 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1195 if (pi != NULL && 1196 pi->newfs_type == NEWFS_UFS) 1197 pi->newfs_data.newfs_ufs.softupdates = 1198 !pi->newfs_data.newfs_ufs.softupdates; 1199 else 1200 msg = MSG_NOT_APPLICABLE; 1201 } 1202 else 1203 msg = MSG_NOT_APPLICABLE; 1204 break; 1205 1206 case 'T': /* Toggle newfs state */ 1207 if ((label_chunk_info[here].type == PART_FILESYSTEM || 1208 label_chunk_info[here].type == PART_EFI) && 1209 (label_chunk_info[here].c->private_data)) { 1210 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1211 if (!pi->do_newfs) 1212 label_chunk_info[here].c->flags |= CHUNK_NEWFS; 1213 else 1214 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; 1215 1216 label_chunk_info[here].c->private_data = 1217 new_part(label_chunk_info[here].type, pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs 1218 : TRUE); 1219 if (pi != NULL && 1220 pi->newfs_type == NEWFS_UFS) { 1221 PartInfo *pi_new = label_chunk_info[here].c->private_data; 1222 1223 pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs; 1224 } 1225 safe_free(pi); 1226 label_chunk_info[here].c->private_free = safe_free; 1227 if (variable_cmp(DISK_LABELLED, "written")) 1228 variable_set2(DISK_LABELLED, "yes", 0); 1229 } 1230 else 1231 msg = MSG_NOT_APPLICABLE; 1232 break; 1233 1234 case 'U': 1235 clear(); 1236 if (!variable_cmp(DISK_LABELLED, "written")) { 1237 msgConfirm("You've already written out your changes -\n" 1238 "it's too late to undo!"); 1239 } 1240 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 1241 variable_unset(DISK_PARTITIONED); 1242 variable_unset(DISK_LABELLED); 1243 for (i = 0; devs[i]; i++) { 1244 Disk *d; 1245 1246 if (!devs[i]->enabled) 1247 continue; 1248 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1249 Free_Disk(devs[i]->private); 1250 devs[i]->private = d; 1251#ifdef WITH_SLICES 1252 diskPartition(devs[i]); 1253#endif 1254 } 1255 } 1256 record_label_chunks(devs, dev); 1257 } 1258 clear_wins(); 1259 break; 1260 1261 case 'W': 1262 if (!variable_cmp(DISK_LABELLED, "written")) { 1263 msgConfirm("You've already written out your changes - if you\n" 1264 "wish to overwrite them, you'll have to restart\n" 1265 "%s first.", ProgName); 1266 } 1267 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 1268 "installation. If you are installing FreeBSD for the first time\n" 1269 "then you should simply type Q when you're finished here and your\n" 1270 "changes will be committed in one batch automatically at the end of\n" 1271 "these questions.\n\n" 1272 "Are you absolutely sure you want to do this now?")) { 1273 variable_set2(DISK_LABELLED, "yes", 0); 1274 diskLabelCommit(NULL); 1275 } 1276 clear_wins(); 1277 break; 1278 1279 case 'Z': /* Set newfs command line */ 1280 if (label_chunk_info[here].c->private_data && 1281 ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) 1282 getNewfsCmd(label_chunk_info[here].c->private_data); 1283 else 1284 msg = MSG_NOT_APPLICABLE; 1285 clear_wins(); 1286 break; 1287 1288#ifndef __ia64__ 1289 case '|': 1290 if (!msgNoYes("Are you sure you want to go into Expert mode?\n\n" 1291 "This is an entirely undocumented feature which you are not\n" 1292 "expected to understand!")) { 1293 int i; 1294 Device **devs; 1295 1296 dialog_clear(); 1297 end_dialog(); 1298 DialogActive = FALSE; 1299 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1300 if (!devs) { 1301 msgConfirm("Can't find any disk devices!"); 1302 break; 1303 } 1304 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1305 if (devs[i]->enabled) 1306 slice_wizard(((Disk *)devs[i]->private)); 1307 } 1308 if (variable_cmp(DISK_LABELLED, "written")) 1309 variable_set2(DISK_LABELLED, "yes", 0); 1310 DialogActive = TRUE; 1311 record_label_chunks(devs, dev); 1312 clear_wins(); 1313 } 1314 else 1315 msg = "A most prudent choice!"; 1316 break; 1317#endif 1318 1319 case '\033': /* ESC */ 1320 case 'Q': 1321 labeling = FALSE; 1322 break; 1323 1324 default: 1325 beep(); 1326 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1327 msg = _msg; 1328 break; 1329 } 1330 if (label_chunk_info[here].type == PART_SLICE) 1331 pslice_focus = here; 1332 else 1333 label_focus = here; 1334 } 1335 restorescr(w); 1336 return DITEM_SUCCESS; 1337} 1338 1339static __inline daddr_t 1340requested_part_size(char *varName, daddr_t nom, int def, int perc) 1341{ 1342 char *cp; 1343 daddr_t sz; 1344 1345 if ((cp = variable_get(varName)) != NULL) 1346 sz = strtoimax(cp, NULL, 0); 1347 else 1348 sz = nom + (def - nom) * perc / 100; 1349 return(sz * ONE_MEG); 1350} 1351 1352/* 1353 * Attempt to auto-label the disk. 'perc' (0-100) scales 1354 * the size of the various partitions within appropriate 1355 * bounds (NOMINAL through DEFAULT sizes). The procedure 1356 * succeeds of NULL is returned. A non-null return message 1357 * is either a failure-status message (*req == 0), or 1358 * a confirmation requestor (*req == 1). *req is 0 on 1359 * entry to this call. 1360 * 1361 * As a special exception to the usual sizing rules, /var is given 1362 * additional space equal to the amount of physical memory present 1363 * if perc == 100 in order to ensure that users with large hard drives 1364 * will have enough space to store a crashdump in /var/crash. 1365 * 1366 * We autolabel the following partitions: /, swap, /var, /tmp, /usr, 1367 * and /home. /home receives any extra left over disk space. 1368 */ 1369static char * 1370try_auto_label(Device **devs, Device *dev, int perc, int *req) 1371{ 1372 daddr_t sz; 1373 Chunk *AutoHome, *AutoRoot, *AutoSwap; 1374 Chunk *AutoTmp, *AutoUsr, *AutoVar; 1375#ifdef __ia64__ 1376 Chunk *AutoEfi; 1377#endif 1378 int mib[2]; 1379 unsigned long physmem; 1380 size_t size; 1381 char *msg = NULL; 1382 1383 sz = space_free(label_chunk_info[here].c); 1384 if (sz <= FS_MIN_SIZE) 1385 return("Not enough free space to create a new partition in the slice"); 1386 1387 (void)checkLabels(FALSE); 1388 AutoHome = AutoRoot = AutoSwap = NULL; 1389 AutoTmp = AutoUsr = AutoVar = NULL; 1390 1391#ifdef __ia64__ 1392 AutoEfi = NULL; 1393 if (EfiChunk == NULL) { 1394 sz = 400 * ONE_MEG; 1395 AutoEfi = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1396 label_chunk_info[here].c, sz, efi, 0, 0); 1397 if (AutoEfi == NULL) { 1398 *req = 1; 1399 msg = "Unable to create the EFI system partition. Too big?"; 1400 goto done; 1401 } 1402 AutoEfi->private_data = new_part(PART_EFI, "/efi", TRUE); 1403 AutoEfi->private_free = safe_free; 1404 AutoEfi->flags |= CHUNK_NEWFS; 1405 record_label_chunks(devs, dev); 1406 } 1407#endif 1408 1409 if (RootChunk == NULL) { 1410 sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc); 1411 1412 AutoRoot = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1413 label_chunk_info[here].c, sz, part, 1414 FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE); 1415 if (!AutoRoot) { 1416 *req = 1; 1417 msg = "Unable to create the root partition. Too big?"; 1418 goto done; 1419 } 1420 AutoRoot->private_data = new_part(PART_FILESYSTEM, "/", TRUE); 1421 AutoRoot->private_free = safe_free; 1422 AutoRoot->flags |= CHUNK_NEWFS; 1423 record_label_chunks(devs, dev); 1424 } 1425 if (SwapChunk == NULL) { 1426 sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc); 1427 if (sz == 0) { 1428 daddr_t nom; 1429 daddr_t def; 1430 1431 mib[0] = CTL_HW; 1432 mib[1] = HW_PHYSMEM; 1433 size = sizeof physmem; 1434 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 1435 def = 2 * (int)(physmem / 512); 1436 if (def < SWAP_MIN_SIZE * ONE_MEG) 1437 def = SWAP_MIN_SIZE * ONE_MEG; 1438 if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG) 1439 def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG; 1440 nom = (int)(physmem / 512) / 8; 1441 sz = nom + (def - nom) * perc / 100; 1442 } 1443 AutoSwap = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1444 label_chunk_info[here].c, sz, part, 1445 FS_SWAP, CHUNK_AUTO_SIZE); 1446 if (!AutoSwap) { 1447 *req = 1; 1448 msg = "Unable to create the swap partition. Too big?"; 1449 goto done; 1450 } 1451 AutoSwap->private_data = 0; 1452 AutoSwap->private_free = safe_free; 1453 record_label_chunks(devs, dev); 1454 } 1455 if (VarChunk == NULL) { 1456 /* Work out how much extra space we want for a crash dump */ 1457 unsigned long crashdumpsz; 1458 1459 mib[0] = CTL_HW; 1460 mib[1] = HW_PHYSMEM; 1461 size = sizeof(physmem); 1462 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 1463 1464 if (perc == 100) 1465 crashdumpsz = physmem / 1048576; 1466 else 1467 crashdumpsz = 0; 1468 1469 sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, \ 1470 VAR_DEFAULT_SIZE + crashdumpsz, perc); 1471 1472 AutoVar = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1473 label_chunk_info[here].c, sz, part, 1474 FS_BSDFFS, CHUNK_AUTO_SIZE); 1475 if (!AutoVar) { 1476 *req = 1; 1477 msg = "Not enough free space for /var - you will need to\n" 1478 "partition your disk manually with a custom install!"; 1479 goto done; 1480 } 1481 AutoVar->private_data = new_part(PART_FILESYSTEM, "/var", TRUE); 1482 AutoVar->private_free = safe_free; 1483 AutoVar->flags |= CHUNK_NEWFS; 1484 record_label_chunks(devs, dev); 1485 } 1486 if (TmpChunk == NULL && !variable_get(VAR_NO_TMP)) { 1487 sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc); 1488 1489 AutoTmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1490 label_chunk_info[here].c, sz, part, 1491 FS_BSDFFS, CHUNK_AUTO_SIZE); 1492 if (!AutoTmp) { 1493 *req = 1; 1494 msg = "Not enough free space for /tmp - you will need to\n" 1495 "partition your disk manually with a custom install!"; 1496 goto done; 1497 } 1498 AutoTmp->private_data = new_part(PART_FILESYSTEM, "/tmp", TRUE); 1499 AutoTmp->private_free = safe_free; 1500 AutoTmp->flags |= CHUNK_NEWFS; 1501 record_label_chunks(devs, dev); 1502 } 1503 if (UsrChunk == NULL && !variable_get(VAR_NO_USR)) { 1504 sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc); 1505#if AUTO_HOME == 0 1506 if (sz < space_free(label_chunk_info[here].c)) 1507 sz = space_free(label_chunk_info[here].c); 1508#endif 1509 if (sz) { 1510 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 1511 *req = 1; 1512 msg = "Not enough free space for /usr - you will need to\n" 1513 "partition your disk manually with a custom install!"; 1514 } 1515 1516 AutoUsr = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1517 label_chunk_info[here].c, sz, part, 1518 FS_BSDFFS, CHUNK_AUTO_SIZE); 1519 if (!AutoUsr) { 1520 msg = "Unable to create the /usr partition. Not enough space?\n" 1521 "You will need to partition your disk manually with a custom install!"; 1522 goto done; 1523 } 1524 AutoUsr->private_data = new_part(PART_FILESYSTEM, "/usr", TRUE); 1525 AutoUsr->private_free = safe_free; 1526 AutoUsr->flags |= CHUNK_NEWFS; 1527 record_label_chunks(devs, dev); 1528 } 1529 } 1530#if AUTO_HOME == 1 1531 if (HomeChunk == NULL && !variable_get(VAR_NO_HOME)) { 1532 sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc); 1533 if (sz < space_free(label_chunk_info[here].c)) 1534 sz = space_free(label_chunk_info[here].c); 1535 if (sz) { 1536 if (sz < (HOME_MIN_SIZE * ONE_MEG)) { 1537 *req = 1; 1538 msg = "Not enough free space for /home - you will need to\n" 1539 "partition your disk manually with a custom install!"; 1540 goto done; 1541 } 1542 1543 AutoHome = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1544 label_chunk_info[here].c, sz, part, 1545 FS_BSDFFS, CHUNK_AUTO_SIZE); 1546 if (!AutoHome) { 1547 msg = "Unable to create the /home partition. Not enough space?\n" 1548 "You will need to partition your disk manually with a custom install!"; 1549 goto done; 1550 } 1551 AutoHome->private_data = new_part(PART_FILESYSTEM, "/home", TRUE); 1552 AutoHome->private_free = safe_free; 1553 AutoHome->flags |= CHUNK_NEWFS; 1554 record_label_chunks(devs, dev); 1555 } 1556 } 1557#endif 1558 1559 /* At this point, we're reasonably "labelled" */ 1560 if (variable_cmp(DISK_LABELLED, "written")) 1561 variable_set2(DISK_LABELLED, "yes", 0); 1562 1563done: 1564 if (msg) { 1565 if (AutoRoot != NULL) 1566 Delete_Chunk(AutoRoot->disk, AutoRoot); 1567 if (AutoSwap != NULL) 1568 Delete_Chunk(AutoSwap->disk, AutoSwap); 1569 if (AutoVar != NULL) 1570 Delete_Chunk(AutoVar->disk, AutoVar); 1571 if (AutoTmp != NULL) 1572 Delete_Chunk(AutoTmp->disk, AutoTmp); 1573 if (AutoUsr != NULL) 1574 Delete_Chunk(AutoUsr->disk, AutoUsr); 1575 if (AutoHome != NULL) 1576 Delete_Chunk(AutoHome->disk, AutoHome); 1577 record_label_chunks(devs, dev); 1578 } 1579 return(msg); 1580} 1581 1582static int 1583diskLabelNonInteractive(Device *dev) 1584{ 1585 char *cp; 1586 PartType type; 1587 PartInfo *p; 1588 u_long flags; 1589 int i, status; 1590 Device **devs; 1591 Disk *d; 1592 1593 status = DITEM_SUCCESS; 1594 cp = variable_get(VAR_DISK); 1595 if (!cp) { 1596 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1597 return DITEM_FAILURE; 1598 } 1599 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1600 if (!devs) { 1601 msgConfirm("diskLabel: No disk device %s found!", cp); 1602 return DITEM_FAILURE; 1603 } 1604 if (dev) 1605 d = dev->private; 1606 else 1607 d = devs[0]->private; 1608 record_label_chunks(devs, dev); 1609 for (i = 0; label_chunk_info[i].c; i++) { 1610 Chunk *c1 = label_chunk_info[i].c; 1611 1612 if (label_chunk_info[i].type == PART_SLICE) { 1613 char name[512]; 1614 char typ[10], mpoint[50]; 1615 int entries; 1616 1617 for (entries = 1;; entries++) { 1618 intmax_t sz; 1619 int soft = 0; 1620 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1621 if ((cp = variable_get(name)) == NULL) 1622 break; 1623 if (sscanf(cp, "%s %jd %s %d", typ, &sz, mpoint, &soft) < 3) { 1624 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1625 status = DITEM_FAILURE; 1626 break; 1627 } else { 1628 Chunk *tmp; 1629 1630 flags = 0; 1631 if (!strcmp(typ, "swap")) { 1632 type = PART_SWAP; 1633 strcpy(mpoint, "SWAP"); 1634 } else { 1635 type = PART_FILESYSTEM; 1636 if (!strcmp(mpoint, "/")) 1637 flags |= CHUNK_IS_ROOT; 1638 } 1639 if (!sz) 1640 sz = space_free(c1); 1641 if (sz > space_free(c1)) { 1642 msgConfirm("Not enough free space to create partition: %s", mpoint); 1643 status = DITEM_FAILURE; 1644 break; 1645 } 1646 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1647 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1648 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1649 status = DITEM_FAILURE; 1650 break; 1651 } else { 1652 PartInfo *pi; 1653 pi = tmp->private_data = new_part(PART_FILESYSTEM, mpoint, TRUE); 1654 tmp->private_free = safe_free; 1655 pi->newfs_data.newfs_ufs.softupdates = soft; 1656 if (!strcmp(typ, "ufs1")) 1657 pi->newfs_data.newfs_ufs.ufs1 = TRUE; 1658 } 1659 } 1660 } 1661 } else { 1662 /* Must be something we can set a mountpoint for */ 1663 cp = variable_get(c1->name); 1664 if (cp) { 1665 char mpoint[50], do_newfs[8]; 1666 Boolean newfs = FALSE; 1667 1668 do_newfs[0] = '\0'; 1669 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1670 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1671 status = DITEM_FAILURE; 1672 break; 1673 } 1674 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1675 if (c1->private_data) { 1676 p = c1->private_data; 1677 p->do_newfs = newfs; 1678 strcpy(p->mountpoint, mpoint); 1679 } 1680 else { 1681 c1->private_data = new_part(PART_FILESYSTEM, mpoint, newfs); 1682 c1->private_free = safe_free; 1683 } 1684 if (!strcmp(mpoint, "/")) 1685 c1->flags |= CHUNK_IS_ROOT; 1686 else 1687 c1->flags &= ~CHUNK_IS_ROOT; 1688 } 1689 } 1690 } 1691 if (status == DITEM_SUCCESS) 1692 variable_set2(DISK_LABELLED, "yes", 0); 1693 return status; 1694} 1695