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