label.c revision 107902
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 107902 2002-12-15 12:05:00Z kuriyama $ 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.ufs2 = 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.ufs2 ? "-O2" : "-O1", 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.ufs2) 690 strcat(newfs, "2"); 691 else 692 strcat(newfs, "1"); 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 '2': 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#ifdef __i386__ 883 if (label_chunk_info[here].c->flags & CHUNK_IS_ROOT) 884 msg = MSG_NOT_APPLICABLE; 885 else 886#endif 887 pi->newfs_data.newfs_ufs.ufs2 = 888 !pi->newfs_data.newfs_ufs.ufs2; 889 } else 890 msg = MSG_NOT_APPLICABLE; 891 } else 892 msg = MSG_NOT_APPLICABLE; 893 break; 894 break; 895 896 case 'A': 897 if (label_chunk_info[here].type != PART_SLICE) { 898 msg = "You can only do this in a disk slice (at top of screen)"; 899 break; 900 } 901 /* 902 * Generate standard partitions automatically. If we do not 903 * have sufficient space we attempt to scale-down the size 904 * of the partitions within certain bounds. 905 */ 906 { 907 int perc; 908 int req = 0; 909 910 for (perc = 100; perc > 0; perc -= 5) { 911 req = 0; /* reset for each loop */ 912 if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL) 913 break; 914 } 915 if (msg) { 916 if (req) { 917 msgConfirm(msg); 918 clear_wins(); 919 msg = NULL; 920 } 921 } 922 } 923 break; 924 925 case 'C': 926 if (label_chunk_info[here].type != PART_SLICE) { 927 msg = "You can only do this in a master partition (see top of screen)"; 928 break; 929 } 930 sz = space_free(label_chunk_info[here].c); 931 if (sz <= FS_MIN_SIZE) { 932 msg = "Not enough space to create an additional FreeBSD partition"; 933 break; 934 } 935 else { 936 char *val; 937 int size; 938 struct chunk *tmp; 939 char osize[80]; 940 u_long flags = 0; 941 942 sprintf(osize, "%d", sz); 943 val = msgGetInput(osize, 944 "Please specify the partition size in blocks or append a trailing G for\n" 945 "gigabytes, M for megabytes, or C for cylinders.\n" 946 "%d blocks (%dMB) are free.", 947 sz, sz / ONE_MEG); 948 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 949 clear_wins(); 950 break; 951 } 952 953 if (*cp) { 954 if (toupper(*cp) == 'M') 955 size *= ONE_MEG; 956 else if (toupper(*cp) == 'G') 957 size *= ONE_GIG; 958 else if (toupper(*cp) == 'C') 959 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 960 } 961 if (size <= FS_MIN_SIZE) { 962 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 963 clear_wins(); 964 break; 965 } 966 type = get_partition_type(); 967 if (type == PART_NONE) { 968 clear_wins(); 969 beep(); 970 break; 971 } 972 973 if (type == PART_FILESYSTEM) { 974 if ((p = get_mountpoint(NULL)) == NULL) { 975 clear_wins(); 976 beep(); 977 break; 978 } 979 else if (!strcmp(p->mountpoint, "/")) 980 flags |= CHUNK_IS_ROOT; 981 else 982 flags &= ~CHUNK_IS_ROOT; 983 } 984 else 985 p = NULL; 986 987 if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) { 988 msgConfirm("Warning: This is smaller than the recommended size for a\n" 989 "root partition. For a variety of reasons, root\n" 990 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 991 } 992 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 993 label_chunk_info[here].c, 994 size, part, 995 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 996 flags); 997 if (!tmp) { 998 msgConfirm("Unable to create the partition. Too big?"); 999 clear_wins(); 1000 break; 1001 } 1002 1003#ifdef __alpha__ 1004 /* 1005 * SRM requires that the root partition is at the 1006 * begining of the disk and cannot boot otherwise. 1007 * Warn Alpha users if they are about to shoot themselves in 1008 * the foot in this way. 1009 * 1010 * Since partitions may not start precisely at offset 0 we 1011 * check for a "close to 0" instead. :-( 1012 */ 1013 if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) { 1014 msgConfirm("Your root partition `a' does not seem to be the first\n" 1015 "partition. The Alpha's firmware can only boot from the\n" 1016 "first partition. So it is unlikely that your current\n" 1017 "disk layout will be bootable boot after installation.\n" 1018 "\n" 1019 "Please allocate the root partition before allocating\n" 1020 "any others.\n"); 1021 } 1022#endif /* alpha */ 1023 1024 tmp->private_data = p; 1025 tmp->private_free = safe_free; 1026 if (variable_cmp(DISK_LABELLED, "written")) 1027 variable_set2(DISK_LABELLED, "yes", 0); 1028 record_label_chunks(devs, dev); 1029 clear_wins(); 1030 /* This is where we assign focus to new label so it shows. */ 1031 { 1032 int i; 1033 label_focus = -1; 1034 for (i = 0; label_chunk_info[i].c; ++i) { 1035 if (label_chunk_info[i].c == tmp) { 1036 label_focus = i; 1037 break; 1038 } 1039 } 1040 if (label_focus == -1) 1041 label_focus = i - 1; 1042 } 1043 } 1044 break; 1045 1046 case KEY_DC: 1047 case 'R': /* recover space (delete w/ recover) */ 1048 /* 1049 * Delete the partition w/ space recovery. 1050 */ 1051 rflags = DELCHUNK_RECOVER; 1052 /* fall through */ 1053 case 'D': /* delete */ 1054 if (label_chunk_info[here].type == PART_SLICE) { 1055 msg = MSG_NOT_APPLICABLE; 1056 break; 1057 } 1058 else if (label_chunk_info[here].type == PART_FAT) { 1059 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1060 break; 1061 } 1062 Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags); 1063 if (variable_cmp(DISK_LABELLED, "written")) 1064 variable_set2(DISK_LABELLED, "yes", 0); 1065 record_label_chunks(devs, dev); 1066 break; 1067 1068 case 'M': /* mount */ 1069 switch(label_chunk_info[here].type) { 1070 case PART_SLICE: 1071 msg = MSG_NOT_APPLICABLE; 1072 break; 1073 1074 case PART_SWAP: 1075 msg = "You don't need to specify a mountpoint for a swap partition."; 1076 break; 1077 1078 case PART_FAT: 1079 case PART_FILESYSTEM: 1080 oldp = label_chunk_info[here].c->private_data; 1081 p = get_mountpoint(label_chunk_info[here].c); 1082 if (p) { 1083 if (!oldp) 1084 p->do_newfs = FALSE; 1085 if (label_chunk_info[here].type == PART_FAT 1086 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1087 || !strcmp(p->mountpoint, "/var"))) { 1088 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1089 strcpy(p->mountpoint, "/bogus"); 1090 } 1091 } 1092 if (variable_cmp(DISK_LABELLED, "written")) 1093 variable_set2(DISK_LABELLED, "yes", 0); 1094 record_label_chunks(devs, dev); 1095 clear_wins(); 1096 break; 1097 1098 default: 1099 msgFatal("Bogus partition under cursor???"); 1100 break; 1101 } 1102 break; 1103 1104 case 'N': /* Set newfs options */ 1105 if (label_chunk_info[here].c->private_data && 1106 ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) 1107 getNewfsOptionalArguments( 1108 label_chunk_info[here].c->private_data); 1109 else 1110 msg = MSG_NOT_APPLICABLE; 1111 clear_wins(); 1112 break; 1113 1114 case 'S': /* Toggle soft updates flag */ 1115 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1116 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1117 if (pi != NULL && 1118 pi->newfs_type == NEWFS_UFS) 1119 pi->newfs_data.newfs_ufs.softupdates = 1120 !pi->newfs_data.newfs_ufs.softupdates; 1121 else 1122 msg = MSG_NOT_APPLICABLE; 1123 } 1124 else 1125 msg = MSG_NOT_APPLICABLE; 1126 break; 1127 1128 case 'T': /* Toggle newfs state */ 1129 if ((label_chunk_info[here].type == PART_FILESYSTEM) && 1130 (label_chunk_info[here].c->private_data)) { 1131 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1132 if (!pi->do_newfs) 1133 label_chunk_info[here].c->flags |= CHUNK_NEWFS; 1134 else 1135 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; 1136 1137 label_chunk_info[here].c->private_data = 1138 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs 1139 : TRUE); 1140 if (pi != NULL && 1141 pi->newfs_type == NEWFS_UFS) { 1142 PartInfo *pi_new = label_chunk_info[here].c->private_data; 1143 1144 pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs; 1145 } 1146 safe_free(pi); 1147 label_chunk_info[here].c->private_free = safe_free; 1148 if (variable_cmp(DISK_LABELLED, "written")) 1149 variable_set2(DISK_LABELLED, "yes", 0); 1150 } 1151#if defined(__ia64__) 1152 else if (label_chunk_info[here].type == PART_FAT && 1153 label_chunk_info[here].c->type == efi && 1154 label_chunk_info[here].c->private_data) { 1155 PartInfo *pi = 1156 ((PartInfo *)label_chunk_info[here].c->private_data); 1157 1158 if (!pi->do_newfs) 1159 label_chunk_info[here].c->flags |= CHUNK_NEWFS; 1160 else 1161 label_chunk_info[here].c->flags &= ~CHUNK_NEWFS; 1162 1163 label_chunk_info[here].c->private_data = 1164 new_efi_part(pi->mountpoint, !pi->do_newfs); 1165 safe_free(pi); 1166 label_chunk_info[here].c->private_free = safe_free; 1167 if (variable_cmp(DISK_LABELLED, "written")) 1168 variable_set2(DISK_LABELLED, "yes", 0); 1169 } 1170#endif 1171 else 1172 msg = MSG_NOT_APPLICABLE; 1173 break; 1174 1175 case 'U': 1176 clear(); 1177 if (!variable_cmp(DISK_LABELLED, "written")) { 1178 msgConfirm("You've already written out your changes -\n" 1179 "it's too late to undo!"); 1180 } 1181 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 1182 variable_unset(DISK_PARTITIONED); 1183 variable_unset(DISK_LABELLED); 1184 for (i = 0; devs[i]; i++) { 1185 Disk *d; 1186 1187 if (!devs[i]->enabled) 1188 continue; 1189 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1190 Free_Disk(devs[i]->private); 1191 devs[i]->private = d; 1192#ifdef WITH_SLICES 1193 diskPartition(devs[i]); 1194#endif 1195 } 1196 } 1197 record_label_chunks(devs, dev); 1198 } 1199 clear_wins(); 1200 break; 1201 1202 case 'W': 1203 if (!variable_cmp(DISK_LABELLED, "written")) { 1204 msgConfirm("You've already written out your changes - if you\n" 1205 "wish to overwrite them, you'll have to restart\n" 1206 "sysinstall first."); 1207 } 1208 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 1209 "installation. If you are installing FreeBSD for the first time\n" 1210 "then you should simply type Q when you're finished here and your\n" 1211 "changes will be committed in one batch automatically at the end of\n" 1212 "these questions.\n\n" 1213 "Are you absolutely sure you want to do this now?")) { 1214 variable_set2(DISK_LABELLED, "yes", 0); 1215 diskLabelCommit(NULL); 1216 } 1217 clear_wins(); 1218 break; 1219 1220 case 'Z': /* Set newfs command line */ 1221 if (label_chunk_info[here].c->private_data && 1222 ((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs) 1223 getNewfsCmd(label_chunk_info[here].c->private_data); 1224 else 1225 msg = MSG_NOT_APPLICABLE; 1226 clear_wins(); 1227 break; 1228 1229 1230 case '|': 1231 if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" 1232 "This is an entirely undocumented feature which you are not\n" 1233 "expected to understand!")) { 1234 int i; 1235 Device **devs; 1236 1237 dialog_clear(); 1238 end_dialog(); 1239 DialogActive = FALSE; 1240 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1241 if (!devs) { 1242 msgConfirm("Can't find any disk devices!"); 1243 break; 1244 } 1245 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1246 if (devs[i]->enabled) 1247 slice_wizard(((Disk *)devs[i]->private)); 1248 } 1249 if (variable_cmp(DISK_LABELLED, "written")) 1250 variable_set2(DISK_LABELLED, "yes", 0); 1251 DialogActive = TRUE; 1252 record_label_chunks(devs, dev); 1253 clear_wins(); 1254 } 1255 else 1256 msg = "A most prudent choice!"; 1257 break; 1258 1259 case '\033': /* ESC */ 1260 case 'Q': 1261 labeling = FALSE; 1262 break; 1263 1264 default: 1265 beep(); 1266 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1267 msg = _msg; 1268 break; 1269 } 1270 if (label_chunk_info[here].type == PART_SLICE) 1271 pslice_focus = here; 1272 else 1273 label_focus = here; 1274 } 1275 restorescr(w); 1276 return DITEM_SUCCESS; 1277} 1278 1279static __inline int 1280requested_part_size(char *varName, int nom, int def, int perc) 1281{ 1282 char *cp; 1283 int sz; 1284 1285 if ((cp = variable_get(varName)) != NULL) 1286 sz = atoi(cp); 1287 else 1288 sz = nom + (def - nom) * perc / 100; 1289 return(sz * ONE_MEG); 1290} 1291 1292/* 1293 * Attempt to auto-label the disk. 'perc' (0-100) scales 1294 * the size of the various partitions within appropriate 1295 * bounds (NOMINAL through DEFAULT sizes). The procedure 1296 * succeeds of NULL is returned. A non-null return message 1297 * is either a failure-status message (*req == 0), or 1298 * a confirmation requestor (*req == 1). *req is 0 on 1299 * entry to this call. 1300 * 1301 * We autolabel the following partitions: /, swap, /var, /tmp, /usr, 1302 * and /home. /home receives any extra left over disk space. 1303 */ 1304static char * 1305try_auto_label(Device **devs, Device *dev, int perc, int *req) 1306{ 1307 int sz; 1308 struct chunk *root_chunk = NULL; 1309 struct chunk *swap_chunk = NULL; 1310 struct chunk *usr_chunk = NULL; 1311 struct chunk *var_chunk = NULL; 1312 struct chunk *tmp_chunk = NULL; 1313 struct chunk *home_chunk = NULL; 1314 int mib[2]; 1315 unsigned long physmem; 1316 size_t size; 1317 Chunk *rootdev, *swapdev, *usrdev, *vardev; 1318 Chunk *tmpdev, *homedev; 1319 char *msg = NULL; 1320 1321 sz = space_free(label_chunk_info[here].c); 1322 if (sz <= FS_MIN_SIZE) 1323 return("Not enough free space to create a new partition in the slice"); 1324 1325 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, 1326 &vardev, &tmpdev, &homedev); 1327 if (!rootdev) { 1328 sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc); 1329 1330 root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1331 label_chunk_info[here].c, sz, part, 1332 FS_BSDFFS, CHUNK_IS_ROOT | CHUNK_AUTO_SIZE); 1333 if (!root_chunk) { 1334 *req = 1; 1335 msg = "Unable to create the root partition. Too big?"; 1336 goto done; 1337 } 1338 root_chunk->private_data = new_part("/", TRUE); 1339 root_chunk->private_free = safe_free; 1340 root_chunk->flags |= CHUNK_NEWFS; 1341 record_label_chunks(devs, dev); 1342 } 1343 if (!swapdev) { 1344 sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc); 1345 if (sz == 0) { 1346 int nom; 1347 int def; 1348 1349 mib[0] = CTL_HW; 1350 mib[1] = HW_PHYSMEM; 1351 size = sizeof physmem; 1352 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 1353 def = 2 * (int)(physmem / 512); 1354 if (def < SWAP_MIN_SIZE * ONE_MEG) 1355 def = SWAP_MIN_SIZE * ONE_MEG; 1356 if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG) 1357 def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG; 1358 nom = (int)(physmem / 512) / 2; 1359 sz = nom + (def - nom) * perc / 100; 1360 } 1361 swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1362 label_chunk_info[here].c, sz, part, 1363 FS_SWAP, CHUNK_AUTO_SIZE); 1364 if (!swap_chunk) { 1365 *req = 1; 1366 msg = "Unable to create the swap partition. Too big?"; 1367 goto done; 1368 } 1369 swap_chunk->private_data = 0; 1370 swap_chunk->private_free = safe_free; 1371 record_label_chunks(devs, dev); 1372 } 1373 if (!vardev) { 1374 sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc); 1375 1376 var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1377 label_chunk_info[here].c, sz, part, 1378 FS_BSDFFS, CHUNK_AUTO_SIZE); 1379 if (!var_chunk) { 1380 *req = 1; 1381 msg = "Not enough free space for /var - you will need to\n" 1382 "partition your disk manually with a custom install!"; 1383 goto done; 1384 } 1385 var_chunk->private_data = new_part("/var", TRUE); 1386 var_chunk->private_free = safe_free; 1387 var_chunk->flags |= CHUNK_NEWFS; 1388 record_label_chunks(devs, dev); 1389 } 1390 if (!tmpdev && !variable_get(VAR_NO_TMP)) { 1391 sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc); 1392 1393 tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1394 label_chunk_info[here].c, sz, part, 1395 FS_BSDFFS, CHUNK_AUTO_SIZE); 1396 if (!tmp_chunk) { 1397 *req = 1; 1398 msg = "Not enough free space for /tmp - you will need to\n" 1399 "partition your disk manually with a custom install!"; 1400 goto done; 1401 } 1402 tmp_chunk->private_data = new_part("/tmp", TRUE); 1403 tmp_chunk->private_free = safe_free; 1404 tmp_chunk->flags |= CHUNK_NEWFS; 1405 record_label_chunks(devs, dev); 1406 } 1407 if (!usrdev && !variable_get(VAR_NO_USR)) { 1408 sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc); 1409#if AUTO_HOME == 0 1410 sz = space_free(label_chunk_info[here].c); 1411#endif 1412 if (sz) { 1413 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 1414 *req = 1; 1415 msg = "Not enough free space for /usr - you will need to\n" 1416 "partition your disk manually with a custom install!"; 1417 } 1418 1419 usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1420 label_chunk_info[here].c, sz, part, 1421 FS_BSDFFS, CHUNK_AUTO_SIZE); 1422 if (!usr_chunk) { 1423 msg = "Unable to create the /usr partition. Not enough space?\n" 1424 "You will need to partition your disk manually with a custom install!"; 1425 goto done; 1426 } 1427 usr_chunk->private_data = new_part("/usr", TRUE); 1428 usr_chunk->private_free = safe_free; 1429 usr_chunk->flags |= CHUNK_NEWFS; 1430 record_label_chunks(devs, dev); 1431 } 1432 } 1433#if AUTO_HOME == 1 1434 if (!homedev && !variable_get(VAR_NO_HOME)) { 1435 sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc); 1436 if (sz < space_free(label_chunk_info[here].c)) 1437 sz = space_free(label_chunk_info[here].c); 1438 if (sz) { 1439 if (sz < (HOME_MIN_SIZE * ONE_MEG)) { 1440 *req = 1; 1441 msg = "Not enough free space for /home - you will need to\n" 1442 "partition your disk manually with a custom install!"; 1443 goto done; 1444 } 1445 1446 home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 1447 label_chunk_info[here].c, sz, part, 1448 FS_BSDFFS, CHUNK_AUTO_SIZE); 1449 if (!home_chunk) { 1450 msg = "Unable to create the /home partition. Not enough space?\n" 1451 "You will need to partition your disk manually with a custom install!"; 1452 goto done; 1453 } 1454 home_chunk->private_data = new_part("/home", TRUE); 1455 home_chunk->private_free = safe_free; 1456 home_chunk->flags |= CHUNK_NEWFS; 1457 record_label_chunks(devs, dev); 1458 } 1459 } 1460#endif 1461 1462 /* At this point, we're reasonably "labelled" */ 1463 if (variable_cmp(DISK_LABELLED, "written")) 1464 variable_set2(DISK_LABELLED, "yes", 0); 1465 1466done: 1467 if (msg) { 1468 if (root_chunk) 1469 Delete_Chunk(root_chunk->disk, root_chunk); 1470 if (swap_chunk) 1471 Delete_Chunk(swap_chunk->disk, swap_chunk); 1472 if (var_chunk) 1473 Delete_Chunk(var_chunk->disk, var_chunk); 1474 if (tmp_chunk) 1475 Delete_Chunk(tmp_chunk->disk, tmp_chunk); 1476 if (usr_chunk) 1477 Delete_Chunk(usr_chunk->disk, usr_chunk); 1478 if (home_chunk) 1479 Delete_Chunk(home_chunk->disk, home_chunk); 1480 record_label_chunks(devs, dev); 1481 } 1482 return(msg); 1483} 1484 1485static int 1486diskLabelNonInteractive(Device *dev) 1487{ 1488 char *cp; 1489 PartType type; 1490 PartInfo *p; 1491 u_long flags; 1492 int i, status; 1493 Device **devs; 1494 Disk *d; 1495 1496 status = DITEM_SUCCESS; 1497 cp = variable_get(VAR_DISK); 1498 if (!cp) { 1499 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1500 return DITEM_FAILURE; 1501 } 1502 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1503 if (!devs) { 1504 msgConfirm("diskLabel: No disk device %s found!", cp); 1505 return DITEM_FAILURE; 1506 } 1507 if (dev) 1508 d = dev->private; 1509 else 1510 d = devs[0]->private; 1511 record_label_chunks(devs, dev); 1512 for (i = 0; label_chunk_info[i].c; i++) { 1513 Chunk *c1 = label_chunk_info[i].c; 1514 1515 if (label_chunk_info[i].type == PART_SLICE) { 1516 char name[512]; 1517 char typ[10], mpoint[50]; 1518 int entries; 1519 1520 for (entries = 1;; entries++) { 1521 int sz, soft = 0; 1522 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1523 if ((cp = variable_get(name)) == NULL) 1524 break; 1525 if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) { 1526 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1527 status = DITEM_FAILURE; 1528 break; 1529 } else { 1530 Chunk *tmp; 1531 1532 flags = 0; 1533 if (!strcmp(typ, "swap")) { 1534 type = PART_SWAP; 1535 strcpy(mpoint, "SWAP"); 1536 } else { 1537 type = PART_FILESYSTEM; 1538 if (!strcmp(mpoint, "/")) 1539 flags |= CHUNK_IS_ROOT; 1540 } 1541 if (!sz) 1542 sz = space_free(c1); 1543 if (sz > space_free(c1)) { 1544 msgConfirm("Not enough free space to create partition: %s", mpoint); 1545 status = DITEM_FAILURE; 1546 break; 1547 } 1548 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1549 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1550 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1551 status = DITEM_FAILURE; 1552 break; 1553 } else { 1554 PartInfo *pi; 1555 pi = tmp->private_data = new_part(mpoint, TRUE); 1556 tmp->private_free = safe_free; 1557 pi->newfs_data.newfs_ufs.softupdates = soft; 1558 } 1559 } 1560 } 1561 } else { 1562 /* Must be something we can set a mountpoint for */ 1563 cp = variable_get(c1->name); 1564 if (cp) { 1565 char mpoint[50], do_newfs[8]; 1566 Boolean newfs = FALSE; 1567 1568 do_newfs[0] = '\0'; 1569 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1570 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1571 status = DITEM_FAILURE; 1572 break; 1573 } 1574 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1575 if (c1->private_data) { 1576 p = c1->private_data; 1577 p->do_newfs = newfs; 1578 strcpy(p->mountpoint, mpoint); 1579 } 1580 else { 1581 c1->private_data = new_part(mpoint, newfs); 1582 c1->private_free = safe_free; 1583 } 1584 if (!strcmp(mpoint, "/")) 1585 c1->flags |= CHUNK_IS_ROOT; 1586 else 1587 c1->flags &= ~CHUNK_IS_ROOT; 1588 } 1589 } 1590 } 1591 if (status == DITEM_SUCCESS) 1592 variable_set2(DISK_LABELLED, "yes", 0); 1593 return status; 1594} 1595