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