label.c revision 29249
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.72 1997/08/11 13:08:26 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 pslice_focus = here; /* VEG 09/05/97 */ 242 label_focus = here; /* VEG 09/05/97 */ 243 } 244 if (ChunkWin) { 245 wclear(ChunkWin); 246 wrefresh(ChunkWin); 247 } 248 else 249 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 250} 251 252/* A new partition entry */ 253static PartInfo * 254new_part(char *mpoint, Boolean newfs, u_long size) 255{ 256 PartInfo *ret; 257 258 if (!mpoint) 259 mpoint = "/change_me"; 260 261 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 262 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); 263 strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 264 ret->newfs = newfs; 265 if (!size) 266 return ret; 267 return ret; 268} 269 270/* Get the mountpoint for a partition and save it away */ 271static PartInfo * 272get_mountpoint(struct chunk *old) 273{ 274 char *val; 275 PartInfo *tmp; 276 277 if (old && old->private_data) 278 tmp = old->private_data; 279 else 280 tmp = NULL; 281 if (!old) { 282 DialogX = 14; 283 DialogY = 16; 284 } 285 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 286 DialogX = DialogY = 0; 287 if (!val || !*val) { 288 if (!old) 289 return NULL; 290 else { 291 free(old->private_data); 292 old->private_data = NULL; 293 } 294 return NULL; 295 } 296 297 /* Is it just the same value? */ 298 if (tmp && !strcmp(tmp->mountpoint, val)) 299 return NULL; 300 301 /* Did we use it already? */ 302 if (check_conflict(val)) { 303 msgConfirm("You already have a mount point for %s assigned!", val); 304 return NULL; 305 } 306 307 /* Is it bogus? */ 308 if (*val != '/') { 309 msgConfirm("Mount point must start with a / character"); 310 return NULL; 311 } 312 313 /* Is it going to be mounted on root? */ 314 if (!strcmp(val, "/")) { 315 if (old) 316 old->flags |= CHUNK_IS_ROOT; 317 } 318 else if (old) 319 old->flags &= ~CHUNK_IS_ROOT; 320 321 safe_free(tmp); 322 tmp = new_part(val, TRUE, 0); 323 if (old) { 324 old->private_data = tmp; 325 old->private_free = safe_free; 326 } 327 return tmp; 328} 329 330/* Get the type of the new partiton */ 331static PartType 332get_partition_type(void) 333{ 334 char selection[20]; 335 int i; 336 337 static unsigned char *fs_types[] = { 338 "FS", 339 "A file system", 340 "Swap", 341 "A swap partition.", 342 }; 343 DialogX = 7; 344 DialogY = 8; 345 i = dialog_menu("Please choose a partition type", 346 "If you want to use this partition for swap space, select Swap.\n" 347 "If you want to put a filesystem on it, choose FS.", 348 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 349 DialogX = DialogY = 0; 350 if (!i) { 351 if (!strcmp(selection, "FS")) 352 return PART_FILESYSTEM; 353 else if (!strcmp(selection, "Swap")) 354 return PART_SWAP; 355 } 356 return PART_NONE; 357} 358 359/* If the user wants a special newfs command for this, set it */ 360static void 361getNewfsCmd(PartInfo *p) 362{ 363 char *val; 364 365 val = msgGetInput(p->newfs_cmd, 366 "Please enter the newfs command and options you'd like to use in\n" 367 "creating this file system."); 368 if (val) 369 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 370} 371 372#define MAX_MOUNT_NAME 12 373 374#define PART_PART_COL 0 375#define PART_MOUNT_COL 8 376#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 377#define PART_NEWFS_COL (PART_SIZE_COL + 7) 378#define PART_OFF 38 379 380#define TOTAL_AVAIL_LINES (10) 381#define PSLICE_SHOWABLE (4) 382 383 384/* stick this all up on the screen */ 385static void 386print_label_chunks(void) 387{ 388 int i, j, srow, prow, pcol; 389 int sz; 390 char clrmsg[80]; 391 392 /********************************************************/ 393 /*** These values are for controling screen resources ***/ 394 /*** Each label line holds up to 2 labels, so beware! ***/ 395 /*** strategy will be to try to always make sure the ***/ 396 /*** highlighted label is in the active display area. ***/ 397 /********************************************************/ 398 int pslice_max, label_max; 399 int pslice_count, label_count, label_focus_found, pslice_focus_found; 400 401 attrset(A_REVERSE); 402 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 403 attrset(A_NORMAL); 404 405 for (i = 0; i < 2; i++) { 406 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 407 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 408 409 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 410 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 411 412 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 413 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 414 415 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 416 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 417 } 418 srow = CHUNK_SLICE_START_ROW; 419 prow = 0; 420 pcol = 0; 421 422 /*** these variables indicate that the focused item is shown currently ***/ 423 label_focus_found = 0; 424 pslice_focus_found = 0; 425 426 /*** Count the number of parition slices ***/ 427 pslice_count = 0; 428 for (i = 0; label_chunk_info[i].c ; i++) { 429 if (label_chunk_info[i].type == PART_SLICE) 430 ++pslice_count; 431 } 432 pslice_max = pslice_count; 433 434 /*** 4 line max for partition slices ***/ 435 if (pslice_max > PSLICE_SHOWABLE) 436 pslice_max = PSLICE_SHOWABLE; 437 438 /*** View partition slices modulo pslice_max ***/ 439 label_max = TOTAL_AVAIL_LINES - pslice_max; 440 441 label_count = 0; 442 pslice_count = 0; 443 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 444 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 445 446 for (i = 0; label_chunk_info[i].c; i++) { 447 /* Is it a slice entry displayed at the top? */ 448 if (label_chunk_info[i].type == PART_SLICE) { 449 /*** This causes the new pslice to replace the previous display ***/ 450 /*** focus must remain on the most recently active pslice ***/ 451 if (pslice_count == pslice_max) { 452 if (pslice_focus_found) { 453 /*** This is where we can mark the more following ***/ 454 attrset(A_BOLD); 455 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 456 attrset(A_NORMAL); 457 continue; 458 } 459 else { 460 /*** this is where we set the more previous ***/ 461 attrset(A_BOLD); 462 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 463 attrset(A_NORMAL); 464 pslice_count = 0; 465 srow = CHUNK_SLICE_START_ROW; 466 } 467 } 468 469 sz = space_free(label_chunk_info[i].c); 470 if (i == here) 471 attrset(ATTR_SELECTED); 472 if (i == pslice_focus) 473 pslice_focus_found = -1; 474 475 mvprintw(srow++, 0, 476 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 477 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, 478 sz, (sz / ONE_MEG)); 479 attrset(A_NORMAL); 480 clrtoeol(); 481 move(0, 0); 482 refresh(); 483 ++pslice_count; 484 } 485 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 486 else { 487 char onestr[PART_OFF], num[10], *mountpoint, *newfs; 488 489 /* 490 * We copy this into a blank-padded string so that it looks like 491 * a solid bar in reverse-video 492 */ 493 memset(onestr, ' ', PART_OFF - 1); 494 onestr[PART_OFF - 1] = '\0'; 495 496 /*** Track how many labels have been displayed ***/ 497 if (label_count == ((label_max - 1 ) * 2)) { 498 if (label_focus_found) { 499 continue; 500 } 501 else { 502 label_count = 0; 503 prow = 0; 504 pcol = 0; 505 } 506 } 507 508 /* Go for two columns if we've written one full columns worth */ 509 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 510 if (label_count == label_max - 1) { 511 pcol = PART_OFF; 512 prow = 0; 513 } 514 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 515 /* If it's a filesystem, display the mountpoint */ 516 if (label_chunk_info[i].c->private_data 517 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 518 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 519 else if (label_chunk_info[i].type == PART_SWAP) 520 mountpoint = "swap"; 521 else 522 mountpoint = "<none>"; 523 524 /* Now display the newfs field */ 525 if (label_chunk_info[i].type == PART_FAT) 526 newfs = "DOS"; 527 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 528 newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 529 else if (label_chunk_info[i].type == PART_SWAP) 530 newfs = "SWAP"; 531 else 532 newfs = "*"; 533 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 534 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 535 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 536 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 537 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 538 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 539 if (i == here) 540 wattrset(ChunkWin, ATTR_SELECTED); 541 if (i == label_focus) 542 label_focus_found = -1; 543 544 /*** lazy man's way of padding this string ***/ 545 while (strlen( onestr ) < 37) 546 strcat(onestr, " "); 547 548 mvwaddstr(ChunkWin, prow, pcol, onestr); 549 wattrset(ChunkWin, A_NORMAL); 550 /*** wrefresh(ChunkWin); ***/ 551 move(0, 0); 552 ++prow; 553 ++label_count; 554 } 555 } 556 557 /*** this will erase all the extra stuff ***/ 558 memset(clrmsg, ' ', 37); 559 clrmsg[37] = '\0'; 560 561 while (pslice_count < pslice_max) { 562 mvprintw(srow++, 0, clrmsg); 563 clrtoeol(); 564 ++pslice_count; 565 } 566 if (ChunkWin) { 567 while (label_count < (2 * (label_max - 1))) { 568 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 569 ++label_count; 570 if (prow == (label_max - 1)) { 571 prow = 0; 572 pcol = PART_OFF; 573 } 574 } 575 wrefresh(ChunkWin); 576 } 577} 578 579static void 580print_command_summary(void) 581{ 582 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 583 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 584 if (!RunningAsInit) 585 mvprintw(18, 47, "W = Write"); 586 mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 587 mvprintw(20, 0, "A = Auto Defaults for all!"); 588 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 589 move(0, 0); 590} 591 592static void 593clear_wins(void) 594{ 595 clear(); 596 wclear(ChunkWin); 597} 598 599static int 600diskLabel(char *str) 601{ 602 int sz, key = 0; 603 Boolean labeling; 604 char *msg = NULL; 605 PartInfo *p, *oldp; 606 PartType type; 607 Device **devs; 608 int override_focus_adjust = 0; 609 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 || sz < (USR_MIN_SIZE * ONE_MEG)) { 760 msgConfirm("Less than %dMB free for /usr - you will need to\n" 761 "partition your disk manually with a custom install!", USR_MIN_SIZE); 762 clear_wins(); 763 break; 764 } 765 766 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 767 label_chunk_info[here].c, 768 sz, part, FS_BSDFFS, 0); 769 if (!tmp) { 770 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 771 "You will need to partition your disk manually with a custom install!"); 772 clear_wins(); 773 break; 774 } 775 tmp->private_data = new_part("/usr", TRUE, tmp->size); 776 tmp->private_free = safe_free; 777 record_label_chunks(devs); 778 } 779 /* At this point, we're reasonably "labelled" */ 780 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 781 variable_set2(DISK_LABELLED, "yes"); 782 } 783 break; 784 785 case 'C': 786 if (label_chunk_info[here].type != PART_SLICE) { 787 msg = "You can only do this in a master partition (see top of screen)"; 788 break; 789 } 790 sz = space_free(label_chunk_info[here].c); 791 if (sz <= FS_MIN_SIZE) { 792 msg = "Not enough space to create an additional FreeBSD partition"; 793 break; 794 } 795 else { 796 char *val; 797 int size; 798 struct chunk *tmp; 799 char osize[80]; 800 u_long flags = 0; 801 802 sprintf(osize, "%d", sz); 803 DialogX = 3; 804 DialogY = 2; 805 val = msgGetInput(osize, 806 "Please specify the partition size in blocks or append a trailing M for\n" 807 "megabytes or C for cylinders. %d blocks (%dMB) are free.", 808 sz, sz / ONE_MEG); 809 DialogX = DialogY = 0; 810 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 811 clear_wins(); 812 break; 813 } 814 815 if (*cp) { 816 if (toupper(*cp) == 'M') 817 size *= ONE_MEG; 818 else if (toupper(*cp) == 'C') 819 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 820 } 821 if (size <= FS_MIN_SIZE) { 822 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 823 clear_wins(); 824 break; 825 } 826 type = get_partition_type(); 827 if (type == PART_NONE) { 828 clear_wins(); 829 beep(); 830 break; 831 } 832 833 if (type == PART_FILESYSTEM) { 834 if ((p = get_mountpoint(NULL)) == NULL) { 835 clear_wins(); 836 beep(); 837 break; 838 } 839 else if (!strcmp(p->mountpoint, "/")) 840 flags |= CHUNK_IS_ROOT; 841 else 842 flags &= ~CHUNK_IS_ROOT; 843 } 844 else 845 p = NULL; 846 847 if ((flags & CHUNK_IS_ROOT)) { 848 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 849 msgConfirm("This region cannot be used for your root partition as the\n" 850 "FreeBSD boot code cannot deal with a root partition created\n" 851 "in that location. Please choose another location or smaller\n" 852 "size for your root partition and try again!"); 853 clear_wins(); 854 break; 855 } 856 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 857 msgConfirm("Warning: This is smaller than the recommended size for a\n" 858 "root partition. For a variety of reasons, root\n" 859 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 860 } 861 } 862 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 863 label_chunk_info[here].c, 864 size, part, 865 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 866 flags); 867 if (!tmp) { 868 msgConfirm("Unable to create the partition. Too big?"); 869 clear_wins(); 870 break; 871 } 872 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 873 msgConfirm("This region cannot be used for your root partition as it starts\n" 874 "or extends past the 1024'th cylinder mark and is thus a\n" 875 "poor location to boot from. Please choose another\n" 876 "location (or smaller size) for your root partition and try again!"); 877 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 878 clear_wins(); 879 break; 880 } 881 if (type != PART_SWAP) { 882 /* This is needed to tell the newfs -u about the size */ 883 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 884 safe_free(p); 885 } 886 else 887 tmp->private_data = p; 888 tmp->private_free = safe_free; 889 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 890 variable_set2(DISK_LABELLED, "yes"); 891 record_label_chunks(devs); 892 clear_wins(); 893 /*** This is where we assign focus to new label so it shows ***/ 894 { 895 int i; 896 label_focus = -1; 897 for (i = 0; label_chunk_info[i].c; ++i) { 898 if (label_chunk_info[i].c == tmp) { 899 label_focus = i; 900 override_focus_adjust = -1; 901 break; 902 } 903 } 904 if (label_focus == -1) 905 label_focus = i - 1; 906 } 907 } 908 break; 909 910 case KEY_DC: 911 case 'D': /* delete */ 912 if (label_chunk_info[here].type == PART_SLICE) { 913 msg = MSG_NOT_APPLICABLE; 914 break; 915 } 916 else if (label_chunk_info[here].type == PART_FAT) { 917 msg = "Use the Disk Partition Editor to delete DOS partitions"; 918 break; 919 } 920 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 921 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 922 variable_set2(DISK_LABELLED, "yes"); 923 record_label_chunks(devs); 924 break; 925 926 case 'M': /* mount */ 927 switch(label_chunk_info[here].type) { 928 case PART_SLICE: 929 msg = MSG_NOT_APPLICABLE; 930 break; 931 932 case PART_SWAP: 933 msg = "You don't need to specify a mountpoint for a swap partition."; 934 break; 935 936 case PART_FAT: 937 case PART_FILESYSTEM: 938 oldp = label_chunk_info[here].c->private_data; 939 p = get_mountpoint(label_chunk_info[here].c); 940 if (p) { 941 if (!oldp) 942 p->newfs = FALSE; 943 if (label_chunk_info[here].type == PART_FAT 944 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 945 || !strcmp(p->mountpoint, "/var"))) { 946 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 947 strcpy(p->mountpoint, "/bogus"); 948 } 949 } 950 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 951 variable_set2(DISK_LABELLED, "yes"); 952 record_label_chunks(devs); 953 clear_wins(); 954 break; 955 956 default: 957 msgFatal("Bogus partition under cursor???"); 958 break; 959 } 960 break; 961 962 case 'N': /* Set newfs options */ 963 if (label_chunk_info[here].c->private_data && 964 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 965 getNewfsCmd(label_chunk_info[here].c->private_data); 966 else 967 msg = MSG_NOT_APPLICABLE; 968 clear_wins(); 969 break; 970 971 case 'T': /* Toggle newfs state */ 972 if (label_chunk_info[here].type == PART_FILESYSTEM) { 973 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 974 label_chunk_info[here].c->private_data = 975 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 976 safe_free(pi); 977 label_chunk_info[here].c->private_free = safe_free; 978 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 979 variable_set2(DISK_LABELLED, "yes"); 980 } 981 else 982 msg = MSG_NOT_APPLICABLE; 983 break; 984 985 case 'U': 986 clear(); 987 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 988 msgConfirm("You've already written out your changes -\n" 989 "it's too late to undo!"); 990 } 991 else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 992 variable_unset(DISK_PARTITIONED); 993 variable_unset(DISK_LABELLED); 994 for (i = 0; devs[i]; i++) { 995 Disk *d; 996 997 if (!devs[i]->enabled) 998 continue; 999 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1000 Free_Disk(devs[i]->private); 1001 devs[i]->private = d; 1002 diskPartition(devs[i], d); 1003 } 1004 } 1005 record_label_chunks(devs); 1006 } 1007 clear_wins(); 1008 break; 1009 1010 case 'W': 1011 if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 1012 msgConfirm("You've already written out your changes - if you\n" 1013 "wish to overwrite them, you'll have to start this\n" 1014 "procedure again from the beginning."); 1015 } 1016 else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 1017 "installation. If you are installing FreeBSD for the first time\n" 1018 "then you should simply type Q when you're finished here and your\n" 1019 "changes will be committed in one batch automatically at the end of\n" 1020 "these questions.\n\n" 1021 "Are you absolutely sure you want to do this now?")) { 1022 variable_set2(DISK_LABELLED, "yes"); 1023 diskLabelCommit(NULL); 1024 } 1025 clear_wins(); 1026 break; 1027 1028 case '|': 1029 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1030 "This is an entirely undocumented feature which you are not\n" 1031 "expected to understand!")) { 1032 int i; 1033 Device **devs; 1034 1035 dialog_clear(); 1036 end_dialog(); 1037 DialogActive = FALSE; 1038 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1039 if (!devs) { 1040 msgConfirm("Can't find any disk devices!"); 1041 break; 1042 } 1043 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1044 if (devs[i]->enabled) 1045 slice_wizard(((Disk *)devs[i]->private)); 1046 } 1047 if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 1048 variable_set2(DISK_LABELLED, "yes"); 1049 DialogActive = TRUE; 1050 record_label_chunks(devs); 1051 clear_wins(); 1052 } 1053 else 1054 msg = "A most prudent choice!"; 1055 break; 1056 1057 case '\033': /* ESC */ 1058 case 'Q': 1059 labeling = FALSE; 1060 break; 1061 1062 default: 1063 beep(); 1064 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1065 msg = _msg; 1066 break; 1067 } 1068 if (override_focus_adjust) { 1069 if (label_chunk_info[here].type == PART_SLICE) 1070 pslice_focus = here; 1071 else 1072 label_focus = here; 1073 } 1074 } 1075 return DITEM_SUCCESS | DITEM_RESTORE; 1076} 1077 1078static int 1079diskLabelNonInteractive(char *str) 1080{ 1081 char *cp; 1082 PartType type; 1083 PartInfo *p; 1084 u_long flags = 0; 1085 int i, status; 1086 Device **devs; 1087 Disk *d; 1088 1089 status = DITEM_SUCCESS; 1090 cp = variable_get(VAR_DISK); 1091 if (!cp) { 1092 dialog_clear(); 1093 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1094 return DITEM_FAILURE; 1095 } 1096 1097 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1098 if (!devs) { 1099 msgConfirm("diskLabel: No disk device %s found!", cp); 1100 return DITEM_FAILURE; 1101 } 1102 d = devs[0]->private; 1103 1104 record_label_chunks(devs); 1105 for (i = 0; label_chunk_info[i].c; i++) { 1106 Chunk *c1 = label_chunk_info[i].c; 1107 1108 if (label_chunk_info[i].type == PART_SLICE) { 1109 char name[512]; 1110 int entries = 1; 1111 1112 while (entries) { 1113 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1114 if ((cp = variable_get(name)) != NULL) { 1115 int sz; 1116 char typ[10], mpoint[50]; 1117 1118 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 1119 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1120 status = DITEM_FAILURE; 1121 continue; 1122 } 1123 else { 1124 Chunk *tmp; 1125 1126 if (!strcmp(typ, "swap")) { 1127 type = PART_SWAP; 1128 strcpy(mpoint, "SWAP"); 1129 } 1130 else { 1131 type = PART_FILESYSTEM; 1132 if (!strcmp(mpoint, "/")) 1133 flags |= CHUNK_IS_ROOT; 1134 } 1135 if (!sz) 1136 sz = space_free(c1); 1137 if (sz > space_free(c1)) { 1138 msgConfirm("Not enough free space to create partition: %s", mpoint); 1139 status = DITEM_FAILURE; 1140 continue; 1141 } 1142 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1143 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1144 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1145 status = DITEM_FAILURE; 1146 break; 1147 } 1148 else { 1149 tmp->private_data = new_part(mpoint, TRUE, sz); 1150 tmp->private_free = safe_free; 1151 status = DITEM_SUCCESS; 1152 } 1153 } 1154 entries++; 1155 } 1156 else { 1157 /* No more matches, leave the loop */ 1158 entries = 0; 1159 } 1160 } 1161 } 1162 else { 1163 /* Must be something we can set a mountpoint for */ 1164 cp = variable_get(c1->name); 1165 if (cp) { 1166 char mpoint[50], do_newfs[8]; 1167 Boolean newfs = FALSE; 1168 1169 do_newfs[0] = '\0'; 1170 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1171 dialog_clear(); 1172 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1173 status = DITEM_FAILURE; 1174 continue; 1175 } 1176 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1177 if (c1->private_data) { 1178 p = c1->private_data; 1179 p->newfs = newfs; 1180 strcpy(p->mountpoint, mpoint); 1181 } 1182 else { 1183 c1->private_data = new_part(mpoint, newfs, 0); 1184 c1->private_free = safe_free; 1185 } 1186 if (!strcmp(mpoint, "/")) 1187 c1->flags |= CHUNK_IS_ROOT; 1188 else 1189 c1->flags &= ~CHUNK_IS_ROOT; 1190 } 1191 } 1192 } 1193 if (status == DITEM_SUCCESS) 1194 variable_set2(DISK_LABELLED, "yes"); 1195 return status; 1196} 1197