label.c revision 79680
1263105Sgjb/* 2263105Sgjb * The new sysinstall program. 3263105Sgjb * 4263105Sgjb * This is probably the last program in the `sysinstall' line - the next 5263105Sgjb * generation being essentially a complete rewrite. 6263105Sgjb * 7263105Sgjb * $FreeBSD: head/usr.sbin/sade/label.c 79680 2001-07-13 16:45:00Z obrien $ 8263105Sgjb * 9263105Sgjb * Copyright (c) 1995 10263105Sgjb * Jordan Hubbard. All rights reserved. 11263105Sgjb * 12263105Sgjb * Redistribution and use in source and binary forms, with or without 13263105Sgjb * modification, are permitted provided that the following conditions 14263105Sgjb * are met: 15263105Sgjb * 1. Redistributions of source code must retain the above copyright 16263105Sgjb * notice, this list of conditions and the following disclaimer, 17263105Sgjb * verbatim and that no modifications are made prior to this 18263105Sgjb * point in the file. 19263105Sgjb * 2. Redistributions in binary form must reproduce the above copyright 20263105Sgjb * notice, this list of conditions and the following disclaimer in the 21263105Sgjb * documentation and/or other materials provided with the distribution. 22263105Sgjb * 23263105Sgjb * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24263105Sgjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25263105Sgjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26263105Sgjb * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27263105Sgjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28263105Sgjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29263105Sgjb * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30263105Sgjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31263105Sgjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32263105Sgjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33263105Sgjb * SUCH DAMAGE. 34263105Sgjb * 35263105Sgjb */ 36263105Sgjb 37263105Sgjb#include "sysinstall.h" 38263105Sgjb#include <ctype.h> 39263105Sgjb#include <sys/disklabel.h> 40263105Sgjb#include <sys/param.h> 41263105Sgjb#include <sys/sysctl.h> 42263105Sgjb 43263105Sgjb/* 44263105Sgjb * Everything to do with editing the contents of disk labels. 45263105Sgjb */ 46263105Sgjb 47263105Sgjb/* A nice message we use a lot in the disklabel editor */ 48263105Sgjb#define MSG_NOT_APPLICABLE "That option is not applicable here" 49263105Sgjb 50263105Sgjb/* Where to start printing the freebsd slices */ 51263105Sgjb#define CHUNK_SLICE_START_ROW 2 52263105Sgjb#define CHUNK_PART_START_ROW 11 53263105Sgjb 54263105Sgjb/* The smallest filesystem we're willing to create */ 55263105Sgjb#define FS_MIN_SIZE ONE_MEG 56263105Sgjb 57263105Sgjb/* The smallest root filesystem we're willing to create */ 58263105Sgjb#ifdef __alpha__ 59263105Sgjb#define ROOT_MIN_SIZE 40 60263105Sgjb#else 61263105Sgjb#define ROOT_MIN_SIZE 30 62263105Sgjb#endif 63263105Sgjb 64263105Sgjb/* The default root filesystem size */ 65263105Sgjb#ifdef __alpha__ 66276259Sbapt#define ROOT_DEFAULT_SIZE 120 67276259Sbapt#else 68263105Sgjb#define ROOT_DEFAULT_SIZE 100 69276259Sbapt#endif 70263105Sgjb 71263105Sgjb/* The smallest swap partition we want to create by default */ 72263105Sgjb#define SWAP_MIN_SIZE 32 73263105Sgjb 74263105Sgjb/* The smallest /usr partition we're willing to create by default */ 75263105Sgjb#define USR_MIN_SIZE 80 76263105Sgjb 77263105Sgjb/* The smallest /var partition we're willing to create by default */ 78263105Sgjb#define VAR_MIN_SIZE 20 79263105Sgjb 80263105Sgjb/* The bottom-most row we're allowed to scribble on */ 81263105Sgjb#define CHUNK_ROW_MAX 16 82263105Sgjb 83267938Sbapt 84/* All the chunks currently displayed on the screen */ 85static struct { 86 struct chunk *c; 87 PartType type; 88} label_chunk_info[MAX_CHUNKS + 1]; 89static int here; 90 91/*** with this value we try to track the most recently added label ***/ 92static int label_focus = 0, pslice_focus = 0; 93 94static int diskLabel(Device *dev); 95static int diskLabelNonInteractive(Device *dev); 96 97static int 98labelHook(dialogMenuItem *selected) 99{ 100 Device **devs = NULL; 101 102 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 103 if (!devs) { 104 msgConfirm("Unable to find disk %s!", selected->prompt); 105 return DITEM_FAILURE; 106 } 107 /* Toggle enabled status? */ 108 if (!devs[0]->enabled) { 109 devs[0]->enabled = TRUE; 110 diskLabel(devs[0]); 111 } 112 else 113 devs[0]->enabled = FALSE; 114 return DITEM_SUCCESS; 115} 116 117static int 118labelCheck(dialogMenuItem *selected) 119{ 120 Device **devs = NULL; 121 122 devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); 123 if (!devs || devs[0]->enabled == FALSE) 124 return FALSE; 125 return TRUE; 126} 127 128int 129diskLabelEditor(dialogMenuItem *self) 130{ 131 DMenu *menu; 132 Device **devs; 133 int i, cnt; 134 135 i = 0; 136 cnt = diskGetSelectCount(&devs); 137 if (cnt == -1) { 138 msgConfirm("No disks found! Please verify that your disk controller is being\n" 139 "properly probed at boot time. See the Hardware Guide on the\n" 140 "Documentation menu for clues on diagnosing this type of problem."); 141 return DITEM_FAILURE; 142 } 143 else if (cnt) { 144 /* Some are already selected */ 145 if (variable_get(VAR_NONINTERACTIVE)) 146 i = diskLabelNonInteractive(NULL); 147 else 148 i = diskLabel(NULL); 149 } 150 else { 151 /* No disks are selected, fall-back case now */ 152 cnt = deviceCount(devs); 153 if (cnt == 1) { 154 devs[0]->enabled = TRUE; 155 if (variable_get(VAR_NONINTERACTIVE)) 156 i = diskLabelNonInteractive(devs[0]); 157 else 158 i = diskLabel(devs[0]); 159 } 160 else { 161 menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); 162 if (!menu) { 163 msgConfirm("No devices suitable for installation found!\n\n" 164 "Please verify that your disk controller (and attached drives)\n" 165 "were detected properly. This can be done by pressing the\n" 166 "[Scroll Lock] key and using the Arrow keys to move back to\n" 167 "the boot messages. Press [Scroll Lock] again to return."); 168 i = DITEM_FAILURE; 169 } 170 else { 171 i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; 172 free(menu); 173 } 174 } 175 } 176 if (DITEM_STATUS(i) != DITEM_FAILURE) { 177 if (variable_cmp(DISK_LABELLED, "written")) 178 variable_set2(DISK_LABELLED, "yes", 0); 179 } 180 return i; 181} 182 183int 184diskLabelCommit(dialogMenuItem *self) 185{ 186 char *cp; 187 int i; 188 189 /* Already done? */ 190 if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 191 i = DITEM_SUCCESS; 192 else if (!cp) { 193 msgConfirm("You must assign disk labels before this option can be used."); 194 i = DITEM_FAILURE; 195 } 196 /* The routine will guard against redundant writes, just as this one does */ 197 else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 198 i = DITEM_FAILURE; 199 else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 200 i = DITEM_FAILURE; 201 else { 202 msgInfo("All filesystem information written successfully."); 203 variable_set2(DISK_LABELLED, "written", 0); 204 i = DITEM_SUCCESS; 205 } 206 return i; 207} 208 209/* See if we're already using a desired partition name */ 210static Boolean 211check_conflict(char *name) 212{ 213 int i; 214 215 for (i = 0; label_chunk_info[i].c; i++) 216 if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) 217 && label_chunk_info[i].c->private_data 218 && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 219 return TRUE; 220 return FALSE; 221} 222 223/* How much space is in this FreeBSD slice? */ 224static int 225space_free(struct chunk *c) 226{ 227 struct chunk *c1; 228 int sz = c->size; 229 230 for (c1 = c->part; c1; c1 = c1->next) { 231 if (c1->type != unused) 232 sz -= c1->size; 233 } 234 if (sz < 0) 235 msgFatal("Partitions are larger than actual chunk??"); 236 return sz; 237} 238 239/* Snapshot the current situation into the displayed chunks structure */ 240static void 241record_label_chunks(Device **devs, Device *dev) 242{ 243 int i, j, p; 244 struct chunk *c1, *c2; 245 Disk *d; 246 247 j = p = 0; 248 /* First buzz through and pick up the FreeBSD slices */ 249 for (i = 0; devs[i]; i++) { 250 if ((dev && devs[i] != dev) || !devs[i]->enabled) 251 continue; 252 d = (Disk *)devs[i]->private; 253 if (!d->chunks) 254 msgFatal("No chunk list found for %s!", d->name); 255 256 /* Put the slice entries first */ 257 for (c1 = d->chunks->part; c1; c1 = c1->next) { 258 if (c1->type == freebsd) { 259 label_chunk_info[j].type = PART_SLICE; 260 label_chunk_info[j].c = c1; 261 ++j; 262 } 263 } 264 } 265 266 /* Now run through again and get the FreeBSD partition entries */ 267 for (i = 0; devs[i]; i++) { 268 if (!devs[i]->enabled) 269 continue; 270 d = (Disk *)devs[i]->private; 271 /* Then buzz through and pick up the partitions */ 272 for (c1 = d->chunks->part; c1; c1 = c1->next) { 273 if (c1->type == freebsd) { 274 for (c2 = c1->part; c2; c2 = c2->next) { 275 if (c2->type == part) { 276 if (c2->subtype == FS_SWAP) 277 label_chunk_info[j].type = PART_SWAP; 278 else 279 label_chunk_info[j].type = PART_FILESYSTEM; 280 label_chunk_info[j].c = c2; 281 ++j; 282 } 283 } 284 } 285 else if (c1->type == fat) { 286 label_chunk_info[j].type = PART_FAT; 287 label_chunk_info[j].c = c1; 288 ++j; 289 } 290 } 291 } 292 label_chunk_info[j].c = NULL; 293 if (here >= j) { 294 here = j ? j - 1 : 0; 295 } 296} 297 298/* A new partition entry */ 299static PartInfo * 300new_part(char *mpoint, Boolean newfs, u_long size) 301{ 302 PartInfo *ret; 303 304 if (!mpoint) 305 mpoint = "/change_me"; 306 307 ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 308 sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); 309 strcpy(ret->newfs_cmd, "newfs "); 310 strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS)); 311 ret->newfs = newfs; 312 ret->soft = 0; 313 if (!size) 314 return ret; 315 return ret; 316} 317 318/* Get the mountpoint for a partition and save it away */ 319static PartInfo * 320get_mountpoint(struct chunk *old) 321{ 322 char *val; 323 PartInfo *tmp; 324 325 if (old && old->private_data) 326 tmp = old->private_data; 327 else 328 tmp = NULL; 329 val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 330 if (!val || !*val) { 331 if (!old) 332 return NULL; 333 else { 334 free(old->private_data); 335 old->private_data = NULL; 336 } 337 return NULL; 338 } 339 340 /* Is it just the same value? */ 341 if (tmp && !strcmp(tmp->mountpoint, val)) 342 return NULL; 343 344 /* Did we use it already? */ 345 if (check_conflict(val)) { 346 msgConfirm("You already have a mount point for %s assigned!", val); 347 return NULL; 348 } 349 350 /* Is it bogus? */ 351 if (*val != '/') { 352 msgConfirm("Mount point must start with a / character"); 353 return NULL; 354 } 355 356 /* Is it going to be mounted on root? */ 357 if (!strcmp(val, "/")) { 358 if (old) 359 old->flags |= CHUNK_IS_ROOT; 360 } 361 else if (old) 362 old->flags &= ~CHUNK_IS_ROOT; 363 364 safe_free(tmp); 365 val = string_skipwhite(string_prune(val)); 366 tmp = new_part(val, TRUE, 0); 367 if (old) { 368 old->private_data = tmp; 369 old->private_free = safe_free; 370 } 371 return tmp; 372} 373 374/* Get the type of the new partiton */ 375static PartType 376get_partition_type(void) 377{ 378 char selection[20]; 379 int i; 380 static unsigned char *fs_types[] = { 381 "FS", 382 "A file system", 383 "Swap", 384 "A swap partition.", 385 }; 386 WINDOW *w = savescr(); 387 388 i = dialog_menu("Please choose a partition type", 389 "If you want to use this partition for swap space, select Swap.\n" 390 "If you want to put a filesystem on it, choose FS.", 391 -1, -1, 2, 2, fs_types, selection, NULL, NULL); 392 restorescr(w); 393 if (!i) { 394 if (!strcmp(selection, "FS")) 395 return PART_FILESYSTEM; 396 else if (!strcmp(selection, "Swap")) 397 return PART_SWAP; 398 } 399 return PART_NONE; 400} 401 402/* If the user wants a special newfs command for this, set it */ 403static void 404getNewfsCmd(PartInfo *p) 405{ 406 char *val; 407 408 val = msgGetInput(p->newfs_cmd, 409 "Please enter the newfs command and options you'd like to use in\n" 410 "creating this file system."); 411 if (val) 412 sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 413} 414 415#define MAX_MOUNT_NAME 9 416 417#define PART_PART_COL 0 418#define PART_MOUNT_COL 10 419#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 420#define PART_NEWFS_COL (PART_SIZE_COL + 8) 421#define PART_OFF 38 422 423#define TOTAL_AVAIL_LINES (10) 424#define PSLICE_SHOWABLE (4) 425 426 427/* stick this all up on the screen */ 428static void 429print_label_chunks(void) 430{ 431 int i, j, srow, prow, pcol; 432 int sz; 433 char clrmsg[80]; 434 int ChunkPartStartRow; 435 WINDOW *ChunkWin; 436 437 /********************************************************/ 438 /*** These values are for controling screen resources ***/ 439 /*** Each label line holds up to 2 labels, so beware! ***/ 440 /*** strategy will be to try to always make sure the ***/ 441 /*** highlighted label is in the active display area. ***/ 442 /********************************************************/ 443 int pslice_max, label_max; 444 int pslice_count, label_count, label_focus_found, pslice_focus_found; 445 446 attrset(A_REVERSE); 447 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 448 attrset(A_NORMAL); 449 450 /*** Count the number of parition slices ***/ 451 pslice_count = 0; 452 for (i = 0; label_chunk_info[i].c ; i++) { 453 if (label_chunk_info[i].type == PART_SLICE) 454 ++pslice_count; 455 } 456 pslice_max = pslice_count; 457 458 /*** 4 line max for partition slices ***/ 459 if (pslice_max > PSLICE_SHOWABLE) { 460 pslice_max = PSLICE_SHOWABLE; 461 } 462 ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; 463 464 /*** View partition slices modulo pslice_max ***/ 465 label_max = TOTAL_AVAIL_LINES - pslice_max; 466 467 for (i = 0; i < 2; i++) { 468 mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 469 mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 470 471 mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 472 mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 473 474 mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); 475 mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); 476 477 mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 478 mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 479 } 480 srow = CHUNK_SLICE_START_ROW; 481 prow = 0; 482 pcol = 0; 483 484 /*** these variables indicate that the focused item is shown currently ***/ 485 label_focus_found = 0; 486 pslice_focus_found = 0; 487 488 label_count = 0; 489 pslice_count = 0; 490 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); 491 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); 492 493 ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 494 495 wclear(ChunkWin); 496 /*** wrefresh(ChunkWin); ***/ 497 498 for (i = 0; label_chunk_info[i].c; i++) { 499 /* Is it a slice entry displayed at the top? */ 500 if (label_chunk_info[i].type == PART_SLICE) { 501 /*** This causes the new pslice to replace the previous display ***/ 502 /*** focus must remain on the most recently active pslice ***/ 503 if (pslice_count == pslice_max) { 504 if (pslice_focus_found) { 505 /*** This is where we can mark the more following ***/ 506 attrset(A_BOLD); 507 mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); 508 attrset(A_NORMAL); 509 continue; 510 } 511 else { 512 /*** this is where we set the more previous ***/ 513 attrset(A_BOLD); 514 mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); 515 attrset(A_NORMAL); 516 pslice_count = 0; 517 srow = CHUNK_SLICE_START_ROW; 518 } 519 } 520 521 sz = space_free(label_chunk_info[i].c); 522 if (i == here) 523 attrset(ATTR_SELECTED); 524 if (i == pslice_focus) 525 pslice_focus_found = -1; 526 527 mvprintw(srow++, 0, 528 "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 529 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, 530 sz, (sz / ONE_MEG)); 531 attrset(A_NORMAL); 532 clrtoeol(); 533 move(0, 0); 534 /*** refresh(); ***/ 535 ++pslice_count; 536 } 537 /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 538 else { 539 char onestr[PART_OFF], num[10], *mountpoint, newfs[10]; 540 541 /* 542 * We copy this into a blank-padded string so that it looks like 543 * a solid bar in reverse-video 544 */ 545 memset(onestr, ' ', PART_OFF - 1); 546 onestr[PART_OFF - 1] = '\0'; 547 548 /*** Track how many labels have been displayed ***/ 549 if (label_count == ((label_max - 1 ) * 2)) { 550 if (label_focus_found) { 551 continue; 552 } 553 else { 554 label_count = 0; 555 prow = 0; 556 pcol = 0; 557 } 558 } 559 560 /* Go for two columns if we've written one full columns worth */ 561 /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ 562 if (label_count == label_max - 1) { 563 pcol = PART_OFF; 564 prow = 0; 565 } 566 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 567 /* If it's a filesystem, display the mountpoint */ 568 if (label_chunk_info[i].c->private_data 569 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 570 mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 571 else if (label_chunk_info[i].type == PART_SWAP) 572 mountpoint = "swap"; 573 else 574 mountpoint = "<none>"; 575 576 /* Now display the newfs field */ 577 if (label_chunk_info[i].type == PART_FAT) 578 strcpy(newfs, "DOS"); 579 else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) { 580 strcpy(newfs, "UFS"); 581 strcat(newfs, 582 ((PartInfo *)label_chunk_info[i].c->private_data)->soft ? 583 "+S" : " "); 584 strcat(newfs, 585 ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? 586 " Y" : " N"); 587 } 588 else if (label_chunk_info[i].type == PART_SWAP) 589 strcpy(newfs, "SWAP"); 590 else 591 strcpy(newfs, "*"); 592 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 593 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 594 snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 595 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 596 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 597 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 598 if (i == label_focus) { 599 label_focus_found = -1; 600 wattrset(ChunkWin, A_BOLD); 601 } 602 if (i == here) 603 wattrset(ChunkWin, ATTR_SELECTED); 604 605 /*** lazy man's way of expensively padding this string ***/ 606 while (strlen(onestr) < 37) 607 strcat(onestr, " "); 608 609 mvwaddstr(ChunkWin, prow, pcol, onestr); 610 wattrset(ChunkWin, A_NORMAL); 611 move(0, 0); 612 ++prow; 613 ++label_count; 614 } 615 } 616 617 /*** this will erase all the extra stuff ***/ 618 memset(clrmsg, ' ', 37); 619 clrmsg[37] = '\0'; 620 621 while (pslice_count < pslice_max) { 622 mvprintw(srow++, 0, clrmsg); 623 clrtoeol(); 624 ++pslice_count; 625 } 626 while (label_count < (2 * (label_max - 1))) { 627 mvwaddstr(ChunkWin, prow++, pcol, clrmsg); 628 ++label_count; 629 if (prow == (label_max - 1)) { 630 prow = 0; 631 pcol = PART_OFF; 632 } 633 } 634 refresh(); 635 wrefresh(ChunkWin); 636} 637 638static void 639print_command_summary(void) 640{ 641 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 642 mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 643 if (!RunningAsInit) 644 mvprintw(18, 47, "W = Write"); 645 mvprintw(19, 0, "N = Newfs Opts Q = Finish S = Toggle SoftUpdates"); 646 mvprintw(20, 0, "T = Toggle Newfs U = Undo A = Auto Defaults"); 647 mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 648 move(0, 0); 649} 650 651static void 652clear_wins(void) 653{ 654 extern void print_label_chunks(); 655 clear(); 656 print_label_chunks(); 657} 658 659#ifdef __alpha__ 660 661/* 662 * If there isn't a freebsd chunk already (i.e. there is no label), 663 * dedicate the disk. 664 */ 665static void 666maybe_dedicate(Disk* d) 667{ 668 struct chunk *c; 669 670 for (c = d->chunks->part; c; c = c->next) { 671 if (c->type == freebsd) 672 break; 673 } 674 675 if (!c) { 676 msgDebug("dedicating disk"); 677 All_FreeBSD(d, 1); 678 } 679} 680 681#endif 682 683static int 684diskLabel(Device *dev) 685{ 686 int sz, key = 0; 687 Boolean labeling; 688 char *msg = NULL; 689 PartInfo *p, *oldp; 690 PartType type; 691 Device **devs; 692#ifdef __alpha__ 693 int i; 694#endif 695 WINDOW *w = savescr(); 696 697 label_focus = 0; 698 pslice_focus = 0; 699 here = 0; 700 701 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 702 if (!devs) { 703 msgConfirm("No disks found!"); 704 restorescr(w); 705 return DITEM_FAILURE; 706 } 707 labeling = TRUE; 708 keypad(stdscr, TRUE); 709#ifdef __alpha__ 710 for (i = 0; devs[i]; i++) { 711 maybe_dedicate((Disk*) devs[i]->private); 712 } 713#endif 714 record_label_chunks(devs, dev); 715 716 clear(); 717 while (labeling) { 718 char *cp; 719 720 print_label_chunks(); 721 print_command_summary(); 722 if (msg) { 723 attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 724 clrtoeol(); 725 beep(); 726 msg = NULL; 727 } 728 else { 729 move(23, 0); 730 clrtoeol(); 731 } 732 733 refresh(); 734 key = getch(); 735 switch (toupper(key)) { 736 int i; 737 static char _msg[40]; 738 739 case '\014': /* ^L */ 740 clear_wins(); 741 break; 742 743 case '\020': /* ^P */ 744 case KEY_UP: 745 case '-': 746 if (here != 0) 747 --here; 748 else 749 while (label_chunk_info[here + 1].c) 750 ++here; 751 break; 752 753 case '\016': /* ^N */ 754 case KEY_DOWN: 755 case '+': 756 case '\r': 757 case '\n': 758 if (label_chunk_info[here + 1].c) 759 ++here; 760 else 761 here = 0; 762 break; 763 764 case KEY_HOME: 765 here = 0; 766 break; 767 768 case KEY_END: 769 while (label_chunk_info[here + 1].c) 770 ++here; 771 break; 772 773 case KEY_F(1): 774 case '?': 775 systemDisplayHelp("partition"); 776 clear_wins(); 777 break; 778 779 case 'A': 780 if (label_chunk_info[here].type != PART_SLICE) { 781 msg = "You can only do this in a disk slice (at top of screen)"; 782 break; 783 } 784 sz = space_free(label_chunk_info[here].c); 785 if (sz <= FS_MIN_SIZE) 786 msg = "Not enough free space to create a new partition in the slice"; 787 else { 788 struct chunk *tmp; 789 int mib[2]; 790 int physmem; 791 size_t size, swsize; 792 char *cp; 793 Chunk *rootdev, *swapdev, *usrdev, *vardev; 794 795 (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 796 if (!rootdev) { 797 cp = variable_get(VAR_ROOT_SIZE); 798 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 799 (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 800 if (!tmp) { 801 msgConfirm("Unable to create the root partition. Too big?"); 802 clear_wins(); 803 break; 804 } 805 tmp->private_data = new_part("/", TRUE, tmp->size); 806 tmp->private_free = safe_free; 807 record_label_chunks(devs, dev); 808 } 809 810 if (!swapdev) { 811 cp = variable_get(VAR_SWAP_SIZE); 812 if (cp) 813 swsize = atoi(cp) * ONE_MEG; 814 else { 815 mib[0] = CTL_HW; 816 mib[1] = HW_PHYSMEM; 817 size = sizeof physmem; 818 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 819 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 820 } 821 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 822 swsize, part, FS_SWAP, 0); 823 if (!tmp) { 824 msgConfirm("Unable to create the swap partition. Too big?"); 825 clear_wins(); 826 break; 827 } 828 tmp->private_data = 0; 829 tmp->private_free = safe_free; 830 record_label_chunks(devs, dev); 831 } 832 833 if (!vardev) { 834 cp = variable_get(VAR_VAR_SIZE); 835 if (cp) 836 sz = atoi(cp) * ONE_MEG; 837 else 838 sz = variable_get(VAR_NO_USR) 839 ? space_free(label_chunk_info[here].c) 840 : VAR_MIN_SIZE * ONE_MEG; 841 842 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 843 sz, part, FS_BSDFFS, 0); 844 if (!tmp) { 845 msgConfirm("Less than %dMB free for /var - you will need to\n" 846 "partition your disk manually with a custom install!", 847 (cp ? atoi(cp) : VAR_MIN_SIZE)); 848 clear_wins(); 849 break; 850 } 851 tmp->private_data = new_part("/var", TRUE, tmp->size); 852 tmp->private_free = safe_free; 853 record_label_chunks(devs, dev); 854 } 855 856 if (!usrdev && !variable_get(VAR_NO_USR)) { 857 cp = variable_get(VAR_USR_SIZE); 858 if (cp) 859 sz = atoi(cp) * ONE_MEG; 860 else 861 sz = space_free(label_chunk_info[here].c); 862 if (sz) { 863 if (sz < (USR_MIN_SIZE * ONE_MEG)) { 864 msgConfirm("Less than %dMB free for /usr - you will need to\n" 865 "partition your disk manually with a custom install!", USR_MIN_SIZE); 866 clear_wins(); 867 break; 868 } 869 870 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 871 label_chunk_info[here].c, 872 sz, part, FS_BSDFFS, 0); 873 if (!tmp) { 874 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 875 "You will need to partition your disk manually with a custom install!"); 876 clear_wins(); 877 break; 878 } 879 tmp->private_data = new_part("/usr", TRUE, tmp->size); 880 tmp->private_free = safe_free; 881 record_label_chunks(devs, dev); 882 } 883 } 884 885 /* At this point, we're reasonably "labelled" */ 886 if (variable_cmp(DISK_LABELLED, "written")) 887 variable_set2(DISK_LABELLED, "yes", 0); 888 } 889 break; 890 891 case 'C': 892 if (label_chunk_info[here].type != PART_SLICE) { 893 msg = "You can only do this in a master partition (see top of screen)"; 894 break; 895 } 896 sz = space_free(label_chunk_info[here].c); 897 if (sz <= FS_MIN_SIZE) { 898 msg = "Not enough space to create an additional FreeBSD partition"; 899 break; 900 } 901 else { 902 char *val; 903 int size; 904 struct chunk *tmp; 905 char osize[80]; 906 u_long flags = 0; 907 908 sprintf(osize, "%d", sz); 909 val = msgGetInput(osize, 910 "Please specify the partition size in blocks or append a trailing G for\n" 911 "gigabytes, M for megabytes, or C for cylinders.\n" 912 "%d blocks (%dMB) are free.", 913 sz, sz / ONE_MEG); 914 if (!val || (size = strtol(val, &cp, 0)) <= 0) { 915 clear_wins(); 916 break; 917 } 918 919 if (*cp) { 920 if (toupper(*cp) == 'M') 921 size *= ONE_MEG; 922 else if (toupper(*cp) == 'G') 923 size *= ONE_GIG; 924 else if (toupper(*cp) == 'C') 925 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 926 } 927 if (size <= FS_MIN_SIZE) { 928 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 929 clear_wins(); 930 break; 931 } 932 type = get_partition_type(); 933 if (type == PART_NONE) { 934 clear_wins(); 935 beep(); 936 break; 937 } 938 939 if (type == PART_FILESYSTEM) { 940 if ((p = get_mountpoint(NULL)) == NULL) { 941 clear_wins(); 942 beep(); 943 break; 944 } 945 else if (!strcmp(p->mountpoint, "/")) 946 flags |= CHUNK_IS_ROOT; 947 else 948 flags &= ~CHUNK_IS_ROOT; 949 } 950 else 951 p = NULL; 952 953 if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) { 954 msgConfirm("Warning: This is smaller than the recommended size for a\n" 955 "root partition. For a variety of reasons, root\n" 956 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 957 } 958 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 959 label_chunk_info[here].c, 960 size, part, 961 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 962 flags); 963 if (!tmp) { 964 msgConfirm("Unable to create the partition. Too big?"); 965 clear_wins(); 966 break; 967 } 968 969#ifdef __alpha__ 970 /* 971 * SRM requires that the root partition is at the 972 * begining of the disk and cannot boot otherwise. 973 * Warn Alpha users if they are about to shoot themselves in 974 * the foot in this way. 975 * 976 * Since partitions may not start precisely at offset 0 we 977 * check for a "close to 0" instead. :-( 978 */ 979 if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) { 980 msgConfirm("Your root partition `a' does not seem to be the first\n" 981 "partition. The Alpha's firmware can only boot from the\n" 982 "first partition. So it is unlikely that your current\n" 983 "disk layout will be bootable boot after installation.\n" 984 "\n" 985 "Please allocate the root partition before allocating\n" 986 "any others.\n"); 987 } 988#endif /* alpha */ 989 990 if (type != PART_SWAP) { 991 /* This is needed to tell the newfs -u about the size */ 992 tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 993 safe_free(p); 994 } 995 else 996 tmp->private_data = p; 997 tmp->private_free = safe_free; 998 if (variable_cmp(DISK_LABELLED, "written")) 999 variable_set2(DISK_LABELLED, "yes", 0); 1000 record_label_chunks(devs, dev); 1001 clear_wins(); 1002 /* This is where we assign focus to new label so it shows. */ 1003 { 1004 int i; 1005 label_focus = -1; 1006 for (i = 0; label_chunk_info[i].c; ++i) { 1007 if (label_chunk_info[i].c == tmp) { 1008 label_focus = i; 1009 break; 1010 } 1011 } 1012 if (label_focus == -1) 1013 label_focus = i - 1; 1014 } 1015 } 1016 break; 1017 1018 case KEY_DC: 1019 case 'D': /* delete */ 1020 if (label_chunk_info[here].type == PART_SLICE) { 1021 msg = MSG_NOT_APPLICABLE; 1022 break; 1023 } 1024 else if (label_chunk_info[here].type == PART_FAT) { 1025 msg = "Use the Disk Partition Editor to delete DOS partitions"; 1026 break; 1027 } 1028 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 1029 if (variable_cmp(DISK_LABELLED, "written")) 1030 variable_set2(DISK_LABELLED, "yes", 0); 1031 record_label_chunks(devs, dev); 1032 break; 1033 1034 case 'M': /* mount */ 1035 switch(label_chunk_info[here].type) { 1036 case PART_SLICE: 1037 msg = MSG_NOT_APPLICABLE; 1038 break; 1039 1040 case PART_SWAP: 1041 msg = "You don't need to specify a mountpoint for a swap partition."; 1042 break; 1043 1044 case PART_FAT: 1045 case PART_FILESYSTEM: 1046 oldp = label_chunk_info[here].c->private_data; 1047 p = get_mountpoint(label_chunk_info[here].c); 1048 if (p) { 1049 if (!oldp) 1050 p->newfs = FALSE; 1051 if (label_chunk_info[here].type == PART_FAT 1052 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 1053 || !strcmp(p->mountpoint, "/var"))) { 1054 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 1055 strcpy(p->mountpoint, "/bogus"); 1056 } 1057 } 1058 if (variable_cmp(DISK_LABELLED, "written")) 1059 variable_set2(DISK_LABELLED, "yes", 0); 1060 record_label_chunks(devs, dev); 1061 clear_wins(); 1062 break; 1063 1064 default: 1065 msgFatal("Bogus partition under cursor???"); 1066 break; 1067 } 1068 break; 1069 1070 case 'N': /* Set newfs options */ 1071 if (label_chunk_info[here].c->private_data && 1072 ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 1073 getNewfsCmd(label_chunk_info[here].c->private_data); 1074 else 1075 msg = MSG_NOT_APPLICABLE; 1076 clear_wins(); 1077 break; 1078 1079 case 'S': /* Toggle soft updates flag */ 1080 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1081 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1082 if (pi) 1083 pi->soft = !pi->soft; 1084 else 1085 msg = MSG_NOT_APPLICABLE; 1086 } 1087 else 1088 msg = MSG_NOT_APPLICABLE; 1089 break; 1090 1091 case 'T': /* Toggle newfs state */ 1092 if (label_chunk_info[here].type == PART_FILESYSTEM) { 1093 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 1094 label_chunk_info[here].c->private_data = 1095 new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 1096 if (pi && pi->soft) 1097 ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1; 1098 safe_free(pi); 1099 label_chunk_info[here].c->private_free = safe_free; 1100 if (variable_cmp(DISK_LABELLED, "written")) 1101 variable_set2(DISK_LABELLED, "yes", 0); 1102 } 1103 else 1104 msg = MSG_NOT_APPLICABLE; 1105 break; 1106 1107 case 'U': 1108 clear(); 1109 if (!variable_cmp(DISK_LABELLED, "written")) { 1110 msgConfirm("You've already written out your changes -\n" 1111 "it's too late to undo!"); 1112 } 1113 else if (!msgNoYes("Are you SURE you want to Undo everything?")) { 1114 variable_unset(DISK_PARTITIONED); 1115 variable_unset(DISK_LABELLED); 1116 for (i = 0; devs[i]; i++) { 1117 Disk *d; 1118 1119 if (!devs[i]->enabled) 1120 continue; 1121 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1122 Free_Disk(devs[i]->private); 1123 devs[i]->private = d; 1124 diskPartition(devs[i]); 1125 } 1126 } 1127 record_label_chunks(devs, dev); 1128 } 1129 clear_wins(); 1130 break; 1131 1132 case 'W': 1133 if (!variable_cmp(DISK_LABELLED, "written")) { 1134 msgConfirm("You've already written out your changes - if you\n" 1135 "wish to overwrite them, you'll have to restart\n" 1136 "sysinstall first."); 1137 } 1138 else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" 1139 "installation. If you are installing FreeBSD for the first time\n" 1140 "then you should simply type Q when you're finished here and your\n" 1141 "changes will be committed in one batch automatically at the end of\n" 1142 "these questions.\n\n" 1143 "Are you absolutely sure you want to do this now?")) { 1144 variable_set2(DISK_LABELLED, "yes", 0); 1145 diskLabelCommit(NULL); 1146 } 1147 clear_wins(); 1148 break; 1149 1150 case '|': 1151 if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" 1152 "This is an entirely undocumented feature which you are not\n" 1153 "expected to understand!")) { 1154 int i; 1155 Device **devs; 1156 1157 dialog_clear(); 1158 end_dialog(); 1159 DialogActive = FALSE; 1160 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1161 if (!devs) { 1162 msgConfirm("Can't find any disk devices!"); 1163 break; 1164 } 1165 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1166 if (devs[i]->enabled) 1167 slice_wizard(((Disk *)devs[i]->private)); 1168 } 1169 if (variable_cmp(DISK_LABELLED, "written")) 1170 variable_set2(DISK_LABELLED, "yes", 0); 1171 DialogActive = TRUE; 1172 record_label_chunks(devs, dev); 1173 clear_wins(); 1174 } 1175 else 1176 msg = "A most prudent choice!"; 1177 break; 1178 1179 case '\033': /* ESC */ 1180 case 'Q': 1181 labeling = FALSE; 1182 break; 1183 1184 default: 1185 beep(); 1186 sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 1187 msg = _msg; 1188 break; 1189 } 1190 if (label_chunk_info[here].type == PART_SLICE) 1191 pslice_focus = here; 1192 else 1193 label_focus = here; 1194 } 1195 restorescr(w); 1196 return DITEM_SUCCESS; 1197} 1198 1199static int 1200diskLabelNonInteractive(Device *dev) 1201{ 1202 char *cp; 1203 PartType type; 1204 PartInfo *p; 1205 u_long flags = 0; 1206 int i, status; 1207 Device **devs; 1208 Disk *d; 1209 1210 status = DITEM_SUCCESS; 1211 cp = variable_get(VAR_DISK); 1212 if (!cp) { 1213 msgConfirm("diskLabel: No disk selected - can't label automatically."); 1214 return DITEM_FAILURE; 1215 } 1216 devs = deviceFind(cp, DEVICE_TYPE_DISK); 1217 if (!devs) { 1218 msgConfirm("diskLabel: No disk device %s found!", cp); 1219 return DITEM_FAILURE; 1220 } 1221 if (dev) 1222 d = dev->private; 1223 else 1224 d = devs[0]->private; 1225#ifdef __alpha__ 1226 maybe_dedicate(d); 1227#endif 1228 record_label_chunks(devs, dev); 1229 for (i = 0; label_chunk_info[i].c; i++) { 1230 Chunk *c1 = label_chunk_info[i].c; 1231 1232 if (label_chunk_info[i].type == PART_SLICE) { 1233 char name[512]; 1234 int entries = 1; 1235 1236 while (entries) { 1237 snprintf(name, sizeof name, "%s-%d", c1->name, entries); 1238 if ((cp = variable_get(name)) != NULL) { 1239 int sz, soft = 0; 1240 char typ[10], mpoint[50]; 1241 1242 if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) { 1243 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1244 status = DITEM_FAILURE; 1245 continue; 1246 } 1247 else { 1248 Chunk *tmp; 1249 1250 if (!strcmp(typ, "swap")) { 1251 type = PART_SWAP; 1252 strcpy(mpoint, "SWAP"); 1253 } 1254 else { 1255 type = PART_FILESYSTEM; 1256 if (!strcmp(mpoint, "/")) 1257 flags |= CHUNK_IS_ROOT; 1258 else 1259 flags &= ~CHUNK_IS_ROOT; 1260 } 1261 if (!sz) 1262 sz = space_free(c1); 1263 if (sz > space_free(c1)) { 1264 msgConfirm("Not enough free space to create partition: %s", mpoint); 1265 status = DITEM_FAILURE; 1266 continue; 1267 } 1268 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 1269 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 1270 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 1271 status = DITEM_FAILURE; 1272 break; 1273 } 1274 else { 1275 tmp->private_data = new_part(mpoint, TRUE, sz); 1276 tmp->private_free = safe_free; 1277 ((PartInfo *)tmp->private_data)->soft = soft; 1278 status = DITEM_SUCCESS; 1279 } 1280 } 1281 entries++; 1282 } 1283 else { 1284 /* No more matches, leave the loop */ 1285 entries = 0; 1286 } 1287 } 1288 } 1289 else { 1290 /* Must be something we can set a mountpoint for */ 1291 cp = variable_get(c1->name); 1292 if (cp) { 1293 char mpoint[50], do_newfs[8]; 1294 Boolean newfs = FALSE; 1295 1296 do_newfs[0] = '\0'; 1297 if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { 1298 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 1299 status = DITEM_FAILURE; 1300 continue; 1301 } 1302 newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; 1303 if (c1->private_data) { 1304 p = c1->private_data; 1305 p->newfs = newfs; 1306 strcpy(p->mountpoint, mpoint); 1307 } 1308 else { 1309 c1->private_data = new_part(mpoint, newfs, 0); 1310 c1->private_free = safe_free; 1311 } 1312 if (!strcmp(mpoint, "/")) 1313 c1->flags |= CHUNK_IS_ROOT; 1314 else 1315 c1->flags &= ~CHUNK_IS_ROOT; 1316 } 1317 } 1318 } 1319 if (status == DITEM_SUCCESS) 1320 variable_set2(DISK_LABELLED, "yes", 0); 1321 return status; 1322} 1323