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