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