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