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