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