label.c revision 29501
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.73 1997/09/09 16:32:01 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) { 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