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