label.c revision 29628
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 * $Id: label.c,v 1.74 1997/09/16 10:14:21 jkh Exp $ 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/* 44 * Everything to do with editing the contents of disk labels. 45 */ 46 47/* A nice message we use a lot in the disklabel editor */ 48#define MSG_NOT_APPLICABLE "That option is not applicable here" 49 50/* Where to start printing the freebsd slices */ 51#define CHUNK_SLICE_START_ROW 2 52#define CHUNK_PART_START_ROW 11 53 54/* The smallest filesystem we're willing to create */ 55#define FS_MIN_SIZE ONE_MEG 56 57/* The smallest root filesystem we're willing to create */ 58#define ROOT_MIN_SIZE 20 59 60/* The smallest swap partition we want to create by default */ 61#define SWAP_MIN_SIZE 16 62 63/* The smallest /usr partition we're willing to create by default */ 64#define USR_MIN_SIZE 80 65 66/* The smallest /var partition we're willing to create by default */ 67#define VAR_MIN_SIZE 30 68 69/* The bottom-most row we're allowed to scribble on */ 70#define CHUNK_ROW_MAX 16 71 72 73/* All the chunks currently displayed on the screen */ 74static struct { 75 struct chunk *c; 76 PartType type; 77} label_chunk_info[MAX_CHUNKS + 1]; 78static int here; 79 80/*** with this value we try to track the most recently added label ***/ 81static int label_focus = 0, pslice_focus = 0; 82 83static int ChunkPartStartRow; 84static WINDOW *ChunkWin; 85 86static int diskLabel(char *str); 87static int diskLabelNonInteractive(char *str); 88 89int 90diskLabelEditor(dialogMenuItem *self) 91{ 92 Device **devs; 93 int i, cnt, enabled; 94 char *cp; 95 96 cp = variable_get(VAR_DISK); 97 devs = deviceFind(cp, DEVICE_TYPE_DISK); 98 cnt = deviceCount(devs); 99 if (!cnt) { 100 msgConfirm("No disks found! Please verify that your disk controller is being\n" 101 "properly probed at boot time. See the Hardware Guide on the\n" 102 "Documentation menu for clues on diagnosing this type of problem."); 103 return DITEM_FAILURE; 104 } 105 for (i = 0, enabled = 0; i < cnt; i++) { 106 if (devs[i]->enabled) 107 ++enabled; 108 } 109 if (!enabled) { 110 msgConfirm("No disks have been selected. Please visit the Partition\n" 111 "editor first to specify which disks you wish to operate on."); 112 return DITEM_FAILURE; 113 } 114 if (variable_get(VAR_NONINTERACTIVE)) 115 i = diskLabelNonInteractive(devs[0]->name); 116 else 117 i = diskLabel(devs[0]->name); 118 if (DITEM_STATUS(i) != DITEM_FAILURE) { 119 char *cp; 120 121 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 122 variable_set2(DISK_LABELLED, "yes"); 123 } 124 return i; 125} 126 127int 128diskLabelCommit(dialogMenuItem *self) 129{ 130 char *cp; 131 int i; 132 133 /* Already done? */ 134 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 135 i = DITEM_SUCCESS; 136 else if (!cp) { 137 msgConfirm("You must assign disk labels before this option can be used."); 138 i = DITEM_FAILURE; 139 } 140 /* The routine will guard against redundant writes, just as this one does */ 141 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 142 i = DITEM_FAILURE; 143 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 144 i = DITEM_FAILURE; 145 else { 146 msgInfo("All filesystem information written successfully."); 147 variable_set2(DISK_LABELLED, "written"); 148 i = DITEM_SUCCESS; 149 } 150 return i; 151} 152 153/* See if we're already using a desired partition name */ 154static Boolean 155check_conflict(char *name) 156{ 157 int i; 158 159 for (i = 0; label_chunk_info[i].c; i++) 160 if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) 161 && label_chunk_info[i].c->private_data 162 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 163 return TRUE; 164 return FALSE; 165} 166 167/* How much space is in this FreeBSD slice? */ 168static int 169space_free(struct chunk *c) 170{ 171 struct chunk *c1; 172 int sz = c->size; 173 174 for (c1 = c->part; c1; c1 = c1->next) { 175 if (c1->type != unused) 176 sz -= c1->size; 177 } 178 if (sz < 0) 179 msgFatal("Partitions are larger than actual chunk??"); 180 return sz; 181} 182 183/* Snapshot the current situation into the displayed chunks structure */ 184static void 185record_label_chunks(Device **devs) 186{ 187 int i, j, p; 188 struct chunk *c1, *c2; 189 Disk *d; 190 191 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3; 192 j = p = 0; 193 /* First buzz through and pick up the FreeBSD slices */ 194 for (i = 0; devs[i]; i++) { 195 if (!devs[i]->enabled) 196 continue; 197 d = (Disk *)devs[i]->private; 198 if (!d->chunks) 199 msgFatal("No chunk list found for %s!", d->name); 200 201 /* Put the slice entries first */ 202 for (c1 = d->chunks->part; c1; c1 = c1->next) { 203 if (c1->type == freebsd) { 204 label_chunk_info[j].type = PART_SLICE; 205 label_chunk_info[j].c = c1; 206 ++j; 207 ++ChunkPartStartRow; 208 } 209 } 210 } 211 212 /* Now run through again and get the FreeBSD partition entries */ 213 for (i = 0; devs[i]; i++) { 214 if (!devs[i]->enabled) 215 continue; 216 d = (Disk *)devs[i]->private; 217 /* Then buzz through and pick up the partitions */ 218 for (c1 = d->chunks->part; c1; c1 = c1->next) { 219 if (c1->type == freebsd) { 220 for (c2 = c1->part; c2; c2 = c2->next) { 221 if (c2->type == part) { 222 if (c2->subtype == FS_SWAP) 223 label_chunk_info[j].type = PART_SWAP; 224 else 225 label_chunk_info[j].type = PART_FILESYSTEM; 226 label_chunk_info[j].c = c2; 227 ++j; 228 } 229 } 230 } 231 else if (c1->type == fat) { 232 label_chunk_info[j].type = PART_FAT; 233 label_chunk_info[j].c = c1; 234 ++j; 235 } 236 } 237 } 238 label_chunk_info[j].c = NULL; 239 if (here >= j) { 240 here = j ? j - 1 : 0; 241 } 242 if (ChunkWin) { 243 wclear(ChunkWin); 244 wrefresh(ChunkWin); 245 } 246 else 247 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 248} 249 250/* A new partition entry */ 251static PartInfo * 252new_part(char *mpoint, Boolean newfs, u_long size) 253{ 254 PartInfo *ret; 255 256 if (!mpoint) 257 mpoint = "/change_me"; 258 259 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 260 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); 261 strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 262 ret->newfs = newfs; 263 if (!size) 264 return ret; 265 return ret; 266} 267 268/* Get the mountpoint for a partition and save it away */ 269static PartInfo * 270get_mountpoint(struct chunk *old) 271{ 272 char *val; 273 PartInfo *tmp; 274 275 if (old && old->private_data) 276 tmp = old->private_data; 277 else 278 tmp = NULL; 279 if (!old) { 280 DialogX = 14; 281 DialogY = 16; 282 } 283 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 284 DialogX = DialogY = 0; 285 if (!val || !*val) { 286 if (!old) 287 return NULL; 288 else { 289 free(old->private_data); 290 old->private_data = NULL; 291 } 292 return NULL; 293 } 294 295 /* Is it just the same value? */ 296 if (tmp && !strcmp(tmp->mountpoint, val)) 297 return NULL; 298 299 /* Did we use it already? */ 300 if (check_conflict(val)) { 301 msgConfirm("You already have a mount point for %s assigned!", val); 302 return NULL; 303 } 304 305 /* Is it bogus? */ 306 if (*val != '/') { 307 msgConfirm("Mount point must start with a / character"); 308 return NULL; 309 } 310 311 /* Is it going to be mounted on root? */ 312 if (!strcmp(val, "/")) { 313 if (old) 314 old->flags |= CHUNK_IS_ROOT; 315 } 316 else if (old) 317 old->flags &= ~CHUNK_IS_ROOT; 318 319 safe_free(tmp); 320 tmp = new_part(val, TRUE, 0); 321 if (old) { 322 old->private_data = tmp; 323 old->private_free = safe_free; 324 } 325 return tmp; 326} 327 328/* Get the type of the new partiton */ 329static PartType 330get_partition_type(void) 331{ 332 char selection[20]; 333 int i; 334 335 static unsigned char *fs_types[] = { 336 "FS", 337 "A file system", 338 "Swap", 339 "A swap partition.", 340 }; 341 DialogX = 7; 342 DialogY = 8; 343 i = dialog_menu("Please choose a partition type", 344 "If you want to use this partition for swap space, select Swap.\n" 345 "If you want to put a filesystem on it, choose FS.", 346 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 347 DialogX = DialogY = 0; 348 if (!i) { 349 if (!strcmp(selection, "FS")) 350 return PART_FILESYSTEM; 351 else if (!strcmp(selection, "Swap")) 352 return PART_SWAP; 353 } 354 return PART_NONE; 355} 356 357/* If the user wants a special newfs command for this, set it */ 358static void 359getNewfsCmd(PartInfo *p) 360{ 361 char *val; 362 363 val = msgGetInput(p->newfs_cmd, 364 "Please enter the newfs command and options you'd like to use in\n" 365 "creating this file system."); 366 if (val) 367 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 368} 369 370#define MAX_MOUNT_NAME 12 371 372#define PART_PART_COL 0 373#define PART_MOUNT_COL 8 374#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 375#define PART_NEWFS_COL (PART_SIZE_COL + 7) 376#define PART_OFF 38 377 378#define TOTAL_AVAIL_LINES (10) 379#define PSLICE_SHOWABLE (4) 380 381 382/* stick this all up on the screen */ 383static void 384print_label_chunks(void) 385{ 386 int i, j, srow, prow, pcol; 387 int sz; 388 char clrmsg[80]; 389 390 /********************************************************/ 391 /*** These values are for controling screen resources ***/ 392 /*** Each label line holds up to 2 labels, so beware! ***/ 393 /*** strategy will be to try to always make sure the ***/ 394 /*** highlighted label is in the active display area. ***/ 395 /********************************************************/ 396 int pslice_max, label_max; 397 int pslice_count, label_count, label_focus_found, pslice_focus_found; 398 399 attrset(A_REVERSE); 400 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 401 attrset(A_NORMAL); 402 403 for (i = 0; i < 2; i++) { 404 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 405 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 406 407 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 408 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 409 410 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 411 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 412 413 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 414 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 415 } 416 srow = CHUNK_SLICE_START_ROW; 417 prow = 0; 418 pcol = 0; 419 420 /*** these variables indicate that the focused item is shown currently ***/ 421 label_focus_found = 0; 422 pslice_focus_found = 0; 423 424 /*** Count the number of parition slices ***/ 425 pslice_count = 0; 426 for (i = 0; label_chunk_info[i].c ; i++) { 427 if (label_chunk_info[i].type == PART_SLICE) 428 ++pslice_count; 429 } 430 pslice_max = pslice_count; 431 432 /*** 4 line max for partition slices ***/ 433 if (pslice_max > PSLICE_SHOWABLE) 434 pslice_max = PSLICE_SHOWABLE; 435 436 /*** View partition slices modulo pslice_max ***/ 437 label_max = TOTAL_AVAIL_LINES - pslice_max; 438 439 label_count = 0; 440 pslice_count = 0; 441 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 442 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 443 444 for (i = 0; label_chunk_info[i].c; i++) { 445 /* Is it a slice entry displayed at the top? */ 446 if (label_chunk_info[i].type == PART_SLICE) { 447 /*** This causes the new pslice to replace the previous display ***/ 448 /*** focus must remain on the most recently active pslice ***/ 449 if (pslice_count == pslice_max) { 450 if (pslice_focus_found) { 451 /*** This is where we can mark the more following ***/ 452 attrset(A_BOLD); 453 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 454 attrset(A_NORMAL); 455 continue; 456 } 457 else { 458 /*** this is where we set the more previous ***/ 459 attrset(A_BOLD); 460 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 461 attrset(A_NORMAL); 462 pslice_count = 0; 463 srow = CHUNK_SLICE_START_ROW; 464 } 465 } 466 467 sz = space_free(label_chunk_info[i].c); 468 if (i == here) 469 attrset(ATTR_SELECTED); 470 if (i == pslice_focus) 471 pslice_focus_found = -1; 472 473 mvprintw(srow++, 0, 474 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 475 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, 476 sz, (sz / ONE_MEG)); 477 attrset(A_NORMAL); 478 clrtoeol(); 479 move(0, 0); 480 refresh(); 481 ++pslice_count; 482 } 483 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 484 else { 485 char onestr[PART_OFF], num[10], *mountpoint, *newfs; 486 487 /* 488 * We copy this into a blank-padded string so that it looks like 489 * a solid bar in reverse-video 490 */ 491 memset(onestr, ' ', PART_OFF - 1); 492 onestr[PART_OFF - 1] = '\0'; 493 494 /*** Track how many labels have been displayed ***/ 495 if (label_count == ((label_max - 1 ) * 2)) { 496 if (label_focus_found) { 497 continue; 498 } 499 else { 500 label_count = 0; 501 prow = 0; 502 pcol = 0; 503 } 504 } 505 506 /* Go for two columns if we've written one full columns worth */ 507 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 508 if (label_count == label_max - 1) { 509 pcol = PART_OFF; 510 prow = 0; 511 } 512 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 513 /* If it's a filesystem, display the mountpoint */ 514 if (label_chunk_info[i].c->private_data 515 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 516 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 517 else if (label_chunk_info[i].type == PART_SWAP) 518 mountpoint = "swap"; 519 else 520 mountpoint = "<none>"; 521 522 /* Now display the newfs field */ 523 if (label_chunk_info[i].type == PART_FAT) 524 newfs = "DOS"; 525 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 526 newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 527 else if (label_chunk_info[i].type == PART_SWAP) 528 newfs = "SWAP"; 529 else 530 newfs = "*"; 531 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 532 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 533 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 534 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 535 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 536 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 537 if (i == here) 538 wattrset(ChunkWin, ATTR_SELECTED); 539 if (i == label_focus) 540 label_focus_found = -1; 541 542 /*** lazy man's way of padding this string ***/ 543 while (strlen( onestr ) < 37) 544 strcat(onestr, " "); 545 546 mvwaddstr(ChunkWin, prow, pcol, onestr); 547 wattrset(ChunkWin, A_NORMAL); 548 /*** wrefresh(ChunkWin); ***/ 549 move(0, 0); 550 ++prow; 551 ++label_count; 552 } 553 } 554 555 /*** this will erase all the extra stuff ***/ 556 memset(clrmsg, ' ', 37); 557 clrmsg[37] = '\0'; 558 559 while (pslice_count < pslice_max) { 560 mvprintw(srow++, 0, clrmsg); 561 clrtoeol(); 562 ++pslice_count; 563 } 564 if (ChunkWin) { 565 while (label_count < (2 * (label_max - 1))) { 566 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 567 ++label_count; 568 if (prow == (label_max - 1)) { 569 prow = 0; 570 pcol = PART_OFF; 571 } 572 } 573 wrefresh(ChunkWin); 574 } 575} 576 577static void 578print_command_summary(void) 579{ 580 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 581 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 582 if (!RunningAsInit) 583 mvprintw(18, 47, "W = Write"); 584 mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 585 mvprintw(20, 0, "A = Auto Defaults for all!"); 586 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 587 move(0, 0); 588} 589 590static void 591clear_wins(void) 592{ 593 clear(); 594 wclear(ChunkWin); 595} 596 597static int 598diskLabel(char *str) 599{ 600 int sz, key = 0; 601 Boolean labeling; 602 char *msg = NULL; 603 PartInfo *p, *oldp; 604 PartType type; 605 Device **devs; 606 int override_focus_adjust = 0; 607 608 label_focus = 0; 609 pslice_focus = 0; 610 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 611 if (!devs) { 612 msgConfirm("No disks found!"); 613 return DITEM_FAILURE; 614 } 615 616 labeling = TRUE; 617 keypad(stdscr, TRUE); 618 record_label_chunks(devs); 619 620 clear(); 621 while (labeling) { 622 char *cp; 623 624 print_label_chunks(); 625 print_command_summary(); 626 if (msg) { 627 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 628 clrtoeol(); 629 beep(); 630 msg = NULL; 631 } 632 else { 633 move(23, 0); 634 clrtoeol(); 635 } 636 637 refresh(); 638 key = getch(); 639 switch (toupper(key)) { 640 int i; 641 static char _msg[40]; 642 643 case '\014': /* ^L */ 644 clear_wins(); 645 break; 646 647 case '\020': /* ^P */ 648 case KEY_UP: 649 case '-': 650 if (here != 0) 651 --here; 652 else 653 while (label_chunk_info[here + 1].c) 654 ++here; 655 break; 656 657 case '\016': /* ^N */ 658 case KEY_DOWN: 659 case '+': 660 case '\r': 661 case '\n': 662 if (label_chunk_info[here + 1].c) 663 ++here; 664 else 665 here = 0; 666 break; 667 668 case KEY_HOME: 669 here = 0; 670 break; 671 672 case KEY_END: 673 while (label_chunk_info[here + 1].c) 674 ++here; 675 break; 676 677 case KEY_F(1): 678 case '?': 679 systemDisplayHelp("partition"); 680 clear_wins(); 681 break; 682 683 case 'A': 684 if (label_chunk_info[here].type != PART_SLICE) { 685 msg = "You can only do this in a disk slice (at top of screen)"; 686 break; 687 } 688 sz = space_free(label_chunk_info[here].c); 689 if (sz <= FS_MIN_SIZE) 690 msg = "Not enough free space to create a new partition in the slice"; 691 else { 692 struct chunk *tmp; 693 int mib[2]; 694 int physmem; 695 size_t size, swsize; 696 char *cp; 697 Chunk *rootdev, *swapdev, *usrdev, *vardev; 698 699 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 700 if (!rootdev) { 701 cp = variable_get(VAR_ROOT_SIZE); 702 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 703 (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 704 if (!tmp) { 705 msgConfirm("Unable to create the root partition. Too big?"); 706 clear_wins(); 707 break; 708 } 709 tmp->private_data = new_part("/", TRUE, tmp->size); 710 tmp->private_free = safe_free; 711 record_label_chunks(devs); 712 } 713 714 if (!swapdev) { 715 cp = variable_get(VAR_SWAP_SIZE); 716 if (cp) 717 swsize = atoi(cp) * ONE_MEG; 718 else { 719 mib[0] = CTL_HW; 720 mib[1] = HW_PHYSMEM; 721 size = sizeof physmem; 722 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 723 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 724 } 725 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 726 swsize, part, FS_SWAP, 0); 727 if (!tmp) { 728 msgConfirm("Unable to create the swap partition. Too big?"); 729 clear_wins(); 730 break; 731 } 732 tmp->private_data = 0; 733 tmp->private_free = safe_free; 734 record_label_chunks(devs); 735 } 736 737 if (!vardev) { 738 cp = variable_get(VAR_VAR_SIZE); 739 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 740 (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 741 if (!tmp) { 742 msgConfirm("Less than %dMB free for /var - you will need to\n" 743 "partition your disk manually with a custom install!", 744 (cp ? atoi(cp) : VAR_MIN_SIZE)); 745 clear_wins(); 746 break; 747 } 748 tmp->private_data = new_part("/var", TRUE, tmp->size); 749 tmp->private_free = safe_free; 750 record_label_chunks(devs); 751 } 752 753 if (!usrdev) { 754 cp = variable_get(VAR_USR_SIZE); 755 if (cp) 756 sz = atoi(cp) * ONE_MEG; 757 else 758 sz = space_free(label_chunk_info[here].c); 759 if (sz) { 760 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 761 msgConfirm("Less than %dMB free for /usr - you will need to\n" 762 "partition your disk manually with a custom install!", USR_MIN_SIZE); 763 clear_wins(); 764 break; 765 } 766 767 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 768 label_chunk_info[here].c, 769 sz, part, FS_BSDFFS, 0); 770 if (!tmp) { 771 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 772 "You will need to partition your disk manually with a custom install!"); 773 clear_wins(); 774 break; 775 } 776 tmp->private_data = new_part("/usr", TRUE, tmp->size); 777 tmp->private_free = safe_free; 778 record_label_chunks(devs); 779 } 780 } 781 /* At this point, we're reasonably "labelled" */ 782 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 783 variable_set2(DISK_LABELLED, "yes"); 784 } 785 break; 786 787 case 'C': 788 if (label_chunk_info[here].type != PART_SLICE) { 789 msg = "You can only do this in a master partition (see top of screen)"; 790 break; 791 } 792 sz = space_free(label_chunk_info[here].c); 793 if (sz <= FS_MIN_SIZE) { 794 msg = "Not enough space to create an additional FreeBSD partition"; 795 break; 796 } 797 else { 798 char *val; 799 int size; 800 struct chunk *tmp; 801 char osize[80]; 802 u_long flags = 0; 803 804 sprintf(osize, "%d", sz); 805 DialogX = 3; 806 DialogY = 2; 807 val = msgGetInput(osize, 808 "Please specify the partition size in blocks or append a trailing M for\n" 809 "megabytes or C for cylinders. %d blocks (%dMB) are free.", 810 sz, sz / ONE_MEG); 811 DialogX = DialogY = 0; 812 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 813 clear_wins(); 814 break; 815 } 816 817 if (*cp) { 818 if (toupper(*cp) == 'M') 819 size *= ONE_MEG; 820 else if (toupper(*cp) == 'C') 821 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 822 } 823 if (size <= FS_MIN_SIZE) { 824 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 825 clear_wins(); 826 break; 827 } 828 type = get_partition_type(); 829 if (type == PART_NONE) { 830 clear_wins(); 831 beep(); 832 break; 833 } 834 835 if (type == PART_FILESYSTEM) { 836 if ((p = get_mountpoint(NULL)) == NULL) { 837 clear_wins(); 838 beep(); 839 break; 840 } 841 else if (!strcmp(p->mountpoint, "/")) 842 flags |= CHUNK_IS_ROOT; 843 else 844 flags &= ~CHUNK_IS_ROOT; 845 } 846 else 847 p = NULL; 848 849 if ((flags & CHUNK_IS_ROOT)) { 850 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 851 msgConfirm("This region cannot be used for your root partition as the\n" 852 "FreeBSD boot code cannot deal with a root partition created\n" 853 "in that location. Please choose another location or smaller\n" 854 "size for your root partition and try again!"); 855 clear_wins(); 856 break; 857 } 858 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 859 msgConfirm("Warning: This is smaller than the recommended size for a\n" 860 "root partition. For a variety of reasons, root\n" 861 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 862 } 863 } 864 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 865 label_chunk_info[here].c, 866 size, part, 867 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 868 flags); 869 if (!tmp) { 870 msgConfirm("Unable to create the partition. Too big?"); 871 clear_wins(); 872 break; 873 } 874 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 875 msgConfirm("This region cannot be used for your root partition as it starts\n" 876 "or extends past the 1024'th cylinder mark and is thus a\n" 877 "poor location to boot from. Please choose another\n" 878 "location (or smaller size) for your root partition and try again!"); 879 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 880 clear_wins(); 881 break; 882 } 883 if (type != PART_SWAP) { 884 /* This is needed to tell the newfs -u about the size */ 885 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 886 safe_free(p); 887 } 888 else 889 tmp->private_data = p; 890 tmp->private_free = safe_free; 891 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 892 variable_set2(DISK_LABELLED, "yes"); 893 record_label_chunks(devs); 894 clear_wins(); 895 /*** This is where we assign focus to new label so it shows ***/ 896 { 897 int i; 898 label_focus = -1; 899 for (i = 0; label_chunk_info[i].c; ++i) { 900 if (label_chunk_info[i].c == tmp) { 901 label_focus = i; 902 override_focus_adjust = -1; 903 break; 904 } 905 } 906 if (label_focus == -1) 907 label_focus = i - 1; 908 } 909 } 910 break; 911 912 case KEY_DC: 913 case 'D': /* delete */ 914 if (label_chunk_info[here].type == PART_SLICE) { 915 msg = MSG_NOT_APPLICABLE; 916 break; 917 } 918 else if (label_chunk_info[here].type == PART_FAT) { 919 msg = "Use the Disk Partition Editor to delete DOS partitions"; 920 break; 921 } 922 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 923 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 924 variable_set2(DISK_LABELLED, "yes"); 925 record_label_chunks(devs); 926 break; 927 928 case 'M': /* mount */ 929 switch(label_chunk_info[here].type) { 930 case PART_SLICE: 931 msg = MSG_NOT_APPLICABLE; 932 break; 933 934 case PART_SWAP: 935 msg = "You don't need to specify a mountpoint for a swap partition."; 936 break; 937 938 case PART_FAT: 939 case PART_FILESYSTEM: 940 oldp = label_chunk_info[here].c->private_data; 941 p = get_mountpoint(label_chunk_info[here].c); 942 if (p) { 943 if (!oldp) 944 p->newfs = FALSE; 945 if (label_chunk_info[here].type == PART_FAT 946 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 947 || !strcmp(p->mountpoint, "/var"))) { 948 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 949 strcpy(p->mountpoint, "/bogus"); 950 } 951 } 952 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 953 variable_set2(DISK_LABELLED, "yes"); 954 record_label_chunks(devs); 955 clear_wins(); 956 break; 957 958 default: 959 msgFatal("Bogus partition under cursor???"); 960 break; 961 } 962 break; 963 964 case 'N': /* Set newfs options */ 965 if (label_chunk_info[here].c->private_data && 966 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 967 getNewfsCmd(label_chunk_info[here].c->private_data); 968 else 969 msg = MSG_NOT_APPLICABLE; 970 clear_wins(); 971 break; 972 973 case 'T': /* Toggle newfs state */ 974 if (label_chunk_info[here].type == PART_FILESYSTEM) { 975 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 976 label_chunk_info[here].c->private_data = 977 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 978 safe_free(pi); 979 label_chunk_info[here].c->private_free = safe_free; 980 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 981 variable_set2(DISK_LABELLED, "yes"); 982 } 983 else 984 msg = MSG_NOT_APPLICABLE; 985 break; 986 987 case 'U': 988 clear(); 989 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 990 msgConfirm("You've already written out your changes -\n" 991 "it's too late to undo!"); 992 } 993 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 994 variable_unset(DISK_PARTITIONED); 995 variable_unset(DISK_LABELLED); 996 for (i = 0; devs[i]; i++) { 997 Disk *d; 998 999 if (!devs[i]->enabled) 1000 continue; 1001 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1002 Free_Disk(devs[i]->private); 1003 devs[i]->private = d; 1004 diskPartition(devs[i], d); 1005 } 1006 } 1007 record_label_chunks(devs); 1008 } 1009 clear_wins(); 1010 break; 1011 1012 case 'W': 1013 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1014 msgConfirm("You've already written out your changes - if you\n" 1015 "wish to overwrite them, you'll have to start this\n" 1016 "procedure again from the beginning."); 1017 } 1018 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 1019 "installation. If you are installing FreeBSD for the first time\n" 1020 "then you should simply type Q when you're finished here and your\n" 1021 "changes will be committed in one batch automatically at the end of\n" 1022 "these questions.\n\n" 1023 "Are you absolutely sure you want to do this now?")) { 1024 variable_set2(DISK_LABELLED, "yes"); 1025 diskLabelCommit(NULL); 1026 } 1027 clear_wins(); 1028 break; 1029 1030 case '|': 1031 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1032 "This is an entirely undocumented feature which you are not\n" 1033 "expected to understand!")) { 1034 int i; 1035 Device **devs; 1036 1037 dialog_clear(); 1038 end_dialog(); 1039 DialogActive = FALSE; 1040 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1041 if (!devs) { 1042 msgConfirm("Can't find any disk devices!"); 1043 break; 1044 } 1045 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1046 if (devs[i]->enabled) 1047 slice_wizard(((Disk *)devs[i]->private)); 1048 } 1049 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1050 variable_set2(DISK_LABELLED, "yes"); 1051 DialogActive = TRUE; 1052 record_label_chunks(devs); 1053 clear_wins(); 1054 } 1055 else 1056 msg = "A most prudent choice!"; 1057 break; 1058 1059 case '\033': /* ESC */ 1060 case 'Q': 1061 labeling = FALSE; 1062 break; 1063 1064 default: 1065 beep(); 1066 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1067 msg = _msg; 1068 break; 1069 } 1070 if (!override_focus_adjust) { 1071 if (label_chunk_info[here].type == PART_SLICE) 1072 pslice_focus = here; 1073 else 1074 label_focus = here; 1075 } 1076 } 1077 return DITEM_SUCCESS | DITEM_RESTORE; 1078} 1079 1080static int 1081diskLabelNonInteractive(char *str) 1082{ 1083 char *cp; 1084 PartType type; 1085 PartInfo *p; 1086 u_long flags = 0; 1087 int i, status; 1088 Device **devs; 1089 Disk *d; 1090 1091 status = DITEM_SUCCESS; 1092 cp = variable_get(VAR_DISK); 1093 if (!cp) { 1094 dialog_clear(); 1095 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1096 return DITEM_FAILURE; 1097 } 1098 1099 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1100 if (!devs) { 1101 msgConfirm("diskLabel: No disk device %s found!", cp); 1102 return DITEM_FAILURE; 1103 } 1104 d = devs[0]->private; 1105 1106 record_label_chunks(devs); 1107 for (i = 0; label_chunk_info[i].c; i++) { 1108 Chunk *c1 = label_chunk_info[i].c; 1109 1110 if (label_chunk_info[i].type == PART_SLICE) { 1111 char name[512]; 1112 int entries = 1; 1113 1114 while (entries) { 1115 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1116 if ((cp = variable_get(name)) != NULL) { 1117 int sz; 1118 char typ[10], mpoint[50]; 1119 1120 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 1121 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1122 status = DITEM_FAILURE; 1123 continue; 1124 } 1125 else { 1126 Chunk *tmp; 1127 1128 if (!strcmp(typ, "swap")) { 1129 type = PART_SWAP; 1130 strcpy(mpoint, "SWAP"); 1131 } 1132 else { 1133 type = PART_FILESYSTEM; 1134 if (!strcmp(mpoint, "/")) 1135 flags |= CHUNK_IS_ROOT; 1136 } 1137 if (!sz) 1138 sz = space_free(c1); 1139 if (sz > space_free(c1)) { 1140 msgConfirm("Not enough free space to create partition: %s", mpoint); 1141 status = DITEM_FAILURE; 1142 continue; 1143 } 1144 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1145 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1146 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1147 status = DITEM_FAILURE; 1148 break; 1149 } 1150 else { 1151 tmp->private_data = new_part(mpoint, TRUE, sz); 1152 tmp->private_free = safe_free; 1153 status = DITEM_SUCCESS; 1154 } 1155 } 1156 entries++; 1157 } 1158 else { 1159 /* No more matches, leave the loop */ 1160 entries = 0; 1161 } 1162 } 1163 } 1164 else { 1165 /* Must be something we can set a mountpoint for */ 1166 cp = variable_get(c1->name); 1167 if (cp) { 1168 char mpoint[50], do_newfs[8]; 1169 Boolean newfs = FALSE; 1170 1171 do_newfs[0] = '\0'; 1172 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1173 dialog_clear(); 1174 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1175 status = DITEM_FAILURE; 1176 continue; 1177 } 1178 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1179 if (c1->private_data) { 1180 p = c1->private_data; 1181 p->newfs = newfs; 1182 strcpy(p->mountpoint, mpoint); 1183 } 1184 else { 1185 c1->private_data = new_part(mpoint, newfs, 0); 1186 c1->private_free = safe_free; 1187 } 1188 if (!strcmp(mpoint, "/")) 1189 c1->flags |= CHUNK_IS_ROOT; 1190 else 1191 c1->flags &= ~CHUNK_IS_ROOT; 1192 } 1193 } 1194 } 1195 if (status == DITEM_SUCCESS) 1196 variable_set2(DISK_LABELLED, "yes"); 1197 return status; 1198} 1199