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