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