label.c revision 12661
11541Srgrimes/* 21541Srgrimes * The new sysinstall program. 31541Srgrimes * 41541Srgrimes * This is probably the last program in the `sysinstall' line - the next 51541Srgrimes * generation being essentially a complete rewrite. 61541Srgrimes * 71541Srgrimes * $Id: label.c,v 1.33 1995/09/18 16:52:28 peter Exp $ 81541Srgrimes * 91541Srgrimes * Copyright (c) 1995 101541Srgrimes * Jordan Hubbard. All rights reserved. 111541Srgrimes * 121541Srgrimes * Redistribution and use in source and binary forms, with or without 131541Srgrimes * modification, are permitted provided that the following conditions 141541Srgrimes * are met: 151541Srgrimes * 1. Redistributions of source code must retain the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer, 171541Srgrimes * verbatim and that no modifications are made prior to this 181541Srgrimes * point in the file. 191541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 201541Srgrimes * notice, this list of conditions and the following disclaimer in the 211541Srgrimes * documentation and/or other materials provided with the distribution. 221541Srgrimes * 3. All advertising materials mentioning features or use of this software 231541Srgrimes * must display the following acknowledgement: 241541Srgrimes * This product includes software developed by Jordan Hubbard 251541Srgrimes * for the FreeBSD Project. 261541Srgrimes * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to 271541Srgrimes * endorse or promote products derived from this software without specific 281541Srgrimes * prior written permission. 291541Srgrimes * 301541Srgrimes * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 311541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 321541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 331541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 3412873Sbde * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 351541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 361541Srgrimes * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 372165Spaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 382811Sbde * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 392165Spaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 401541Srgrimes * SUCH DAMAGE. 411541Srgrimes * 421541Srgrimes */ 431541Srgrimes 441541Srgrimes#include "sysinstall.h" 451541Srgrimes#include <ctype.h> 461541Srgrimes#include <sys/disklabel.h> 471541Srgrimes#include <sys/param.h> 481541Srgrimes#include <sys/sysctl.h> 491541Srgrimes 501541Srgrimes/* 511541Srgrimes * Everything to do with editing the contents of disk labels. 521541Srgrimes */ 531541Srgrimes 541541Srgrimes/* A nice message we use a lot in the disklabel editor */ 551541Srgrimes#define MSG_NOT_APPLICABLE "That option is not applicable here" 561541Srgrimes 571541Srgrimes/* Where to start printing the freebsd slices */ 581541Srgrimes#define CHUNK_SLICE_START_ROW 2 591541Srgrimes#define CHUNK_PART_START_ROW 11 601541Srgrimes 617945Sjulian/* The smallest filesystem we're willing to create */ 621541Srgrimes#define FS_MIN_SIZE ONE_MEG 631541Srgrimes 641541Srgrimes/* The smallest root filesystem we're willing to create */ 651541Srgrimes#define ROOT_MIN_SIZE 20 661541Srgrimes 671541Srgrimes/* The smallest swap partition we want to create by default */ 681541Srgrimes#define SWAP_MIN_SIZE 16 691541Srgrimes 7012158Sbde/* The smallest /usr partition we're willing to create by default */ 7112158Sbde#define USR_MIN_SIZE 80 721541Srgrimes 731541Srgrimes/* The smallest /var partition we're willing to create by default */ 741541Srgrimes#define VAR_MIN_SIZE 30 751541Srgrimes 761541Srgrimes/* All the chunks currently displayed on the screen */ 771541Srgrimesstatic struct { 781541Srgrimes struct chunk *c; 791541Srgrimes PartType type; 8012158Sbde} label_chunk_info[MAX_CHUNKS + 1]; 811541Srgrimesstatic int here; 821541Srgrimes 831541Srgrimesstatic int diskLabel(char *str); 841541Srgrimesstatic int scriptLabel(char *str); 851541Srgrimes 861541Srgrimesstatic int 871541SrgrimeslabelHook(char *str) 881541Srgrimes{ 891541Srgrimes Device **devs = NULL; 901541Srgrimes 911541Srgrimes /* Clip garbage off the ends */ 921541Srgrimes string_prune(str); 931541Srgrimes str = string_skipwhite(str); 941541Srgrimes /* Try and open all the disks */ 951541Srgrimes while (str) { 961541Srgrimes char *cp; 971541Srgrimes 981541Srgrimes cp = index(str, '\n'); 991541Srgrimes if (cp) 1009356Sdg *cp++ = 0; 1011541Srgrimes if (!*str) { 1021541Srgrimes beep(); 1031541Srgrimes return 0; 1041541Srgrimes } 1051541Srgrimes devs = deviceFind(str, DEVICE_TYPE_DISK); 1061541Srgrimes if (!devs) { 1071541Srgrimes dialog_clear(); 1081541Srgrimes msgConfirm("Unable to find disk %s!", str); 1091541Srgrimes return 0; 1101541Srgrimes } 1111541Srgrimes else if (devs[1]) { 11212873Sbde dialog_clear(); 11312873Sbde msgConfirm("Bizarre multiple match for %s!", str); 11412873Sbde } 11512873Sbde devs[0]->enabled = TRUE; 11612873Sbde str = cp; 11712873Sbde } 11812873Sbde return devs ? 1 : 0; 11912873Sbde} 12012873Sbde 12112873Sbdeint 12212873SbdediskLabelEditor(char *str) 12312873Sbde{ 12412873Sbde Device **devs; 1251541Srgrimes DMenu *menu; 1261541Srgrimes int i, cnt; 1271541Srgrimes char *cp; 1281541Srgrimes 1291541Srgrimes cp = variable_get(VAR_DISK); 1301541Srgrimes devs = deviceFind(cp, DEVICE_TYPE_DISK); 1311541Srgrimes cnt = deviceCount(devs); 1321541Srgrimes if (!cnt) { 1331541Srgrimes dialog_clear(); 1341541Srgrimes msgConfirm("No disks found! Please verify that your disk controller is being\n" 1351541Srgrimes "properly probed at boot time. See the Hardware Guide on the\n" 1361541Srgrimes "Documentation menu for clues on diagnosing this type of problem."); 1371541Srgrimes return RET_FAIL; 1381541Srgrimes } 1391541Srgrimes else if (cnt == 1 || variable_get(DISK_SELECTED)) { 1401541Srgrimes devs[0]->enabled = TRUE; 1411541Srgrimes if (str && !strcmp(str, "script")) 1421541Srgrimes i = scriptLabel(str); 1431541Srgrimes else 1441541Srgrimes i = diskLabel(str); 1451541Srgrimes } 1461541Srgrimes else { 1471541Srgrimes menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook); 1481541Srgrimes if (!menu) { 1491541Srgrimes dialog_clear(); 1501541Srgrimes msgConfirm("No devices suitable for installation found!\n\n" 1511541Srgrimes "Please verify that your disk controller (and attached drives)\n" 1521541Srgrimes "were detected properly. This can be done by pressing the\n" 1531541Srgrimes "[Scroll Lock] key and using the Arrow keys to move back to\n" 1541541Srgrimes "the boot messages. Press [Scroll Lock] again to return."); 1551541Srgrimes i = RET_FAIL; 1561541Srgrimes } 1571541Srgrimes else { 1581541Srgrimes if (!dmenuOpenSimple(menu)) 1591541Srgrimes i = RET_FAIL; 1601541Srgrimes else 1611541Srgrimes i = diskLabel(str); 1621541Srgrimes free(menu); 1631541Srgrimes } 1641541Srgrimes } 16512873Sbde return i; 1661541Srgrimes} 1671541Srgrimes 1681541Srgrimesint 1691541SrgrimesdiskLabelCommit(char *str) 1701541Srgrimes{ 1711541Srgrimes char *cp; 1721541Srgrimes int i; 1731541Srgrimes 1741541Srgrimes /* Already done? */ 1751541Srgrimes if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 1761541Srgrimes i = RET_SUCCESS; 1771541Srgrimes else if (!cp) { 1781541Srgrimes dialog_clear(); 1791541Srgrimes msgConfirm("You must assign disk labels before this option can be used."); 1801541Srgrimes i = RET_FAIL; 1811541Srgrimes } 1821541Srgrimes /* The routine will guard against redundant writes, just as this one does */ 1831541Srgrimes else if (diskPartitionWrite(str) != RET_SUCCESS) 1841541Srgrimes i = RET_FAIL; 1851541Srgrimes else if (installFilesystems(str) != RET_SUCCESS) 1861541Srgrimes i = RET_FAIL; 1871541Srgrimes else { 1881541Srgrimes msgInfo("All filesystem information written successfully."); 1891541Srgrimes variable_set2(DISK_LABELLED, "written"); 1901541Srgrimes i = RET_SUCCESS; 1911541Srgrimes } 1921541Srgrimes return i; 1931541Srgrimes} 1941541Srgrimes 1951541Srgrimes/* See if we're already using a desired partition name */ 1961541Srgrimesstatic Boolean 1971541Srgrimescheck_conflict(char *name) 1981541Srgrimes{ 1991541Srgrimes int i; 2001541Srgrimes 2011541Srgrimes for (i = 0; label_chunk_info[i].c; i++) 2021541Srgrimes if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private 2031541Srgrimes && !strcmp(((PartInfo *)label_chunk_info[i].c->private)->mountpoint, name)) 2041541Srgrimes return TRUE; 2051541Srgrimes return FALSE; 2061541Srgrimes} 2071541Srgrimes 2081541Srgrimes/* How much space is in this FreeBSD slice? */ 2091541Srgrimesstatic int 2101541Srgrimesspace_free(struct chunk *c) 2111541Srgrimes{ 2121541Srgrimes struct chunk *c1; 2131541Srgrimes int sz = c->size; 2141541Srgrimes 2151541Srgrimes for (c1 = c->part; c1; c1 = c1->next) { 2161541Srgrimes if (c1->type != unused) 2171541Srgrimes sz -= c1->size; 2181541Srgrimes } 2191541Srgrimes if (sz < 0) 2202946Swollman msgFatal("Partitions are larger than actual chunk??"); 22112873Sbde return sz; 2222946Swollman} 22312873Sbde 2242946Swollman/* Snapshot the current situation into the displayed chunks structure */ 2252946Swollmanstatic void 2261541Srgrimesrecord_label_chunks(Device **devs) 2271541Srgrimes{ 2281541Srgrimes int i, j, p; 2291541Srgrimes struct chunk *c1, *c2; 2301541Srgrimes Disk *d; 2317090Sbde 2321541Srgrimes j = p = 0; 2331541Srgrimes /* First buzz through and pick up the FreeBSD slices */ 2341541Srgrimes for (i = 0; devs[i]; i++) { 2351541Srgrimes if (!devs[i]->enabled) 2361541Srgrimes continue; 2371541Srgrimes d = (Disk *)devs[i]->private; 2381541Srgrimes if (!d->chunks) 2391541Srgrimes msgFatal("No chunk list found for %s!", d->name); 2402997Swollman 2412997Swollman /* Put the slice entries first */ 2422997Swollman for (c1 = d->chunks->part; c1; c1 = c1->next) { 2432997Swollman if (c1->type == freebsd) { 2441541Srgrimes label_chunk_info[j].type = PART_SLICE; 2457461Sdg label_chunk_info[j].c = c1; 2461541Srgrimes ++j; 2471541Srgrimes } 2481541Srgrimes } 24912873Sbde } 25012873Sbde 2517461Sdg /* Now run through again and get the FreeBSD partition entries */ 2527461Sdg for (i = 0; devs[i]; i++) { 25312873Sbde if (!devs[i]->enabled) 2542997Swollman continue; 25512873Sbde d = (Disk *)devs[i]->private; 2562997Swollman /* Then buzz through and pick up the partitions */ 2571541Srgrimes for (c1 = d->chunks->part; c1; c1 = c1->next) { 2581541Srgrimes if (c1->type == freebsd) { 2591541Srgrimes for (c2 = c1->part; c2; c2 = c2->next) { 2601541Srgrimes if (c2->type == part) { 2611541Srgrimes if (c2->subtype == FS_SWAP) 2621541Srgrimes label_chunk_info[j].type = PART_SWAP; 2631541Srgrimes else 2641541Srgrimes label_chunk_info[j].type = PART_FILESYSTEM; 2651541Srgrimes label_chunk_info[j].c = c2; 2661541Srgrimes ++j; 2671541Srgrimes } 2681541Srgrimes } 2691541Srgrimes } 2701541Srgrimes else if (c1->type == fat) { 2711541Srgrimes label_chunk_info[j].type = PART_FAT; 2721541Srgrimes label_chunk_info[j].c = c1; 2731541Srgrimes ++j; 2741541Srgrimes } 2751541Srgrimes } 2761541Srgrimes } 2771541Srgrimes label_chunk_info[j].c = NULL; 2781541Srgrimes if (here >= j) 2791541Srgrimes here = j ? j - 1 : 0; 2801541Srgrimes} 2811541Srgrimes 2821541Srgrimes/* A new partition entry */ 2831541Srgrimesstatic PartInfo * 2841541Srgrimesnew_part(char *mpoint, Boolean newfs, u_long size) 2851541Srgrimes{ 2861541Srgrimes PartInfo *ret; 2871541Srgrimes u_long target, divisor; 2881541Srgrimes 2891541Srgrimes if (!mpoint) 2901541Srgrimes mpoint = "/change_me"; 2911541Srgrimes 2921541Srgrimes ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 2931541Srgrimes strncpy(ret->mountpoint, mpoint, FILENAME_MAX); 2941541Srgrimes strcpy(ret->newfs_cmd, "newfs -b 8192 -f 2048"); 2951541Srgrimes ret->newfs = newfs; 2961541Srgrimes if (!size) 2971541Srgrimes return ret; 2981541Srgrimes for (target = size; target; target--) { 2991541Srgrimes for (divisor = 4096 ; divisor > 1023; divisor--) { 3001541Srgrimes if (!(target % divisor)) { 3011541Srgrimes sprintf(ret->newfs_cmd + strlen(ret->newfs_cmd), " -u %ld",divisor); 3021541Srgrimes return ret; 3031541Srgrimes } 3041541Srgrimes } 3051541Srgrimes } 3061541Srgrimes return ret; 3071541Srgrimes} 3081541Srgrimes 3091541Srgrimes/* Get the mountpoint for a partition and save it away */ 3101541Srgrimesstatic PartInfo * 3111541Srgrimesget_mountpoint(struct chunk *old) 3121541Srgrimes{ 3131541Srgrimes char *val; 3141541Srgrimes PartInfo *tmp; 3151541Srgrimes 3161541Srgrimes if (old && old->private) 3171541Srgrimes tmp = old->private; 3181541Srgrimes else 3191541Srgrimes tmp = NULL; 3201541Srgrimes val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 3211541Srgrimes if (!val || !*val) { 3221541Srgrimes if (!old) 3231541Srgrimes return NULL; 3241541Srgrimes else { 3251541Srgrimes free(old->private); 3261541Srgrimes old->private = NULL; 3271541Srgrimes } 3281541Srgrimes return NULL; 3291541Srgrimes } 3301541Srgrimes 3311541Srgrimes /* Is it just the same value? */ 3321541Srgrimes if (tmp && !strcmp(tmp->mountpoint, val)) 3331541Srgrimes return NULL; 3341541Srgrimes 3351541Srgrimes /* Did we use it already? */ 3361541Srgrimes if (check_conflict(val)) { 33712158Sbde msgConfirm("You already have a mount point for %s assigned!", val); 3381541Srgrimes return NULL; 3391541Srgrimes } 3401541Srgrimes 34112158Sbde /* Is it bogus? */ 3421541Srgrimes if (*val != '/') { 3431541Srgrimes msgConfirm("Mount point must start with a / character"); 3441541Srgrimes return NULL; 3451541Srgrimes } 3461541Srgrimes 3471541Srgrimes /* Is it going to be mounted on root? */ 3481541Srgrimes if (!strcmp(val, "/")) { 3491541Srgrimes if (old) 3501541Srgrimes old->flags |= CHUNK_IS_ROOT; 3511541Srgrimes } 3521541Srgrimes else if (old) 3531541Srgrimes old->flags &= ~CHUNK_IS_ROOT; 3541541Srgrimes 3551541Srgrimes safe_free(tmp); 3561541Srgrimes tmp = new_part(val, TRUE, 0); 3571541Srgrimes if (old) { 3581541Srgrimes old->private = tmp; 3591541Srgrimes old->private_free = safe_free; 3601541Srgrimes } 3611541Srgrimes return tmp; 3621541Srgrimes} 3631541Srgrimes 3641541Srgrimes/* Get the type of the new partiton */ 3651541Srgrimesstatic PartType 3661541Srgrimesget_partition_type(void) 3671541Srgrimes{ 3681541Srgrimes char selection[20]; 3691541Srgrimes int i; 3701541Srgrimes 3711541Srgrimes static unsigned char *fs_types[] = { 3721541Srgrimes "FS", 3731541Srgrimes "A file system", 3741541Srgrimes "Swap", 3751541Srgrimes "A swap partition.", 3761541Srgrimes }; 3771541Srgrimes i = dialog_menu("Please choose a partition type", 3781541Srgrimes "If you want to use this partition for swap space, select Swap.\n" 3791541Srgrimes "If you want to put a filesystem on it, choose FS.", 3801541Srgrimes -1, -1, 2, 2, fs_types, selection, NULL, NULL); 3812811Sbde if (!i) { 3821541Srgrimes if (!strcmp(selection, "FS")) 3831541Srgrimes return PART_FILESYSTEM; 3841541Srgrimes else if (!strcmp(selection, "Swap")) 3851541Srgrimes return PART_SWAP; 3861541Srgrimes } 3871541Srgrimes return PART_NONE; 3881541Srgrimes} 3891541Srgrimes 3901541Srgrimes/* If the user wants a special newfs command for this, set it */ 3911541Srgrimesstatic void 3921541SrgrimesgetNewfsCmd(PartInfo *p) 3931541Srgrimes{ 3942811Sbde char *val; 3952811Sbde 3962811Sbde val = msgGetInput(p->newfs_cmd, 3972811Sbde "Please enter the newfs command and options you'd like to use in\n" 3982811Sbde "creating this file system."); 3992811Sbde if (val) 4003098Sphk strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 40112873Sbde} 40212873Sbde 4031541Srgrimesstatic int 40412873SbdescriptLabel(char *str) 40512873Sbde{ 4061541Srgrimes char *cp; 4071541Srgrimes PartType type; 4084465Sbde PartInfo *p; 40912873Sbde u_long flags = 0; 4101541Srgrimes int i, status; 4111541Srgrimes Device **devs; 4121541Srgrimes Disk *d; 41312873Sbde 41412873Sbde status = RET_SUCCESS; 4151541Srgrimes cp = variable_get(VAR_DISK); 4161541Srgrimes if (!cp) { 4171541Srgrimes dialog_clear(); 4181541Srgrimes msgConfirm("scriptLabel: No disk selected - can't label automatically."); 4191541Srgrimes return RET_FAIL; 4201541Srgrimes } 4211541Srgrimes 4221541Srgrimes devs = deviceFind(cp, DEVICE_TYPE_DISK); 4231541Srgrimes if (!devs) { 4241541Srgrimes dialog_clear(); 4251541Srgrimes msgConfirm("scriptLabel: No disk device %s found!", cp); 4261541Srgrimes return RET_FAIL; 42712873Sbde } 42812873Sbde d = devs[0]->private; 42912873Sbde 4301541Srgrimes record_label_chunks(devs); 43112873Sbde for (i = 0; label_chunk_info[i].c; i++) { 43212873Sbde Chunk *c1 = label_chunk_info[i].c; 4331541Srgrimes 4341541Srgrimes if (label_chunk_info[i].type == PART_SLICE) { 4351541Srgrimes if ((cp = variable_get(c1->name)) != NULL) { 4361541Srgrimes int sz; 4372165Spaul char typ[10], mpoint[50]; 4382811Sbde 439 if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { 440 dialog_clear(); 441 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 442 status = RET_FAIL; 443 continue; 444 } 445 else { 446 Chunk *tmp; 447 448 if (!strcmp(typ, "swap")) { 449 type = PART_SWAP; 450 strcpy(mpoint, "<swap>"); 451 } 452 else { 453 type = PART_FILESYSTEM; 454 if (!strcmp(mpoint, "/")) 455 flags |= CHUNK_IS_ROOT; 456 } 457 if (!sz) 458 sz = space_free(c1); 459 if (sz > space_free(c1)) { 460 dialog_clear(); 461 msgConfirm("Not enough free space to create partition: %s", mpoint); 462 status = RET_FAIL; 463 continue; 464 } 465 if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, 466 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { 467 dialog_clear(); 468 msgConfirm("Unable to create from partition spec: %s. Too big?", cp); 469 status = RET_FAIL; 470 break; 471 } 472 else { 473 tmp->private = new_part(mpoint, TRUE, sz); 474 tmp->private_free = safe_free; 475 status = RET_SUCCESS; 476 } 477 } 478 } 479 } 480 else { 481 /* Must be something we can set a mountpoint */ 482 cp = variable_get(c1->name); 483 if (cp) { 484 char mpoint[50], nwfs[8]; 485 Boolean newfs = FALSE; 486 487 nwfs[0] = '\0'; 488 if (sscanf(cp, "%s %s", mpoint, nwfs) != 2) { 489 dialog_clear(); 490 msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); 491 status = RET_FAIL; 492 continue; 493 } 494 newfs = toupper(nwfs[0]) == 'Y' ? TRUE : FALSE; 495 if (c1->private) { 496 p = c1->private; 497 p->newfs = newfs; 498 strcpy(p->mountpoint, mpoint); 499 } 500 else { 501 c1->private = new_part(mpoint, newfs, 0); 502 c1->private_free = safe_free; 503 } 504 if (!strcmp(mpoint, "/")) 505 c1->flags |= CHUNK_IS_ROOT; 506 else 507 c1->flags &= ~CHUNK_IS_ROOT; 508 } 509 } 510 } 511 if (status == RET_SUCCESS) 512 variable_set2(DISK_LABELLED, "yes"); 513 return status; 514} 515 516#define MAX_MOUNT_NAME 12 517 518#define PART_PART_COL 0 519#define PART_MOUNT_COL 8 520#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 521#define PART_NEWFS_COL (PART_SIZE_COL + 7) 522#define PART_OFF 38 523 524/* How many mounted partitions to display in column before going to next */ 525#define CHUNK_COLUMN_MAX 5 526 527/* stick this all up on the screen */ 528static void 529print_label_chunks(void) 530{ 531 int i, j, srow, prow, pcol; 532 int sz; 533 534 attrset(A_REVERSE); 535 mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 536 clrtobot(); 537 attrset(A_NORMAL); 538 539 for (i = 0; i < 2; i++) { 540 mvaddstr(CHUNK_PART_START_ROW - 2, PART_PART_COL + (i * PART_OFF), "Part"); 541 mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), "----"); 542 543 mvaddstr(CHUNK_PART_START_ROW - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 544 mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 545 546 mvaddstr(CHUNK_PART_START_ROW - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 547 mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 548 549 mvaddstr(CHUNK_PART_START_ROW - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 550 mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 551 } 552 srow = CHUNK_SLICE_START_ROW; 553 prow = CHUNK_PART_START_ROW; 554 pcol = 0; 555 556 for (i = 0; label_chunk_info[i].c; i++) { 557 if (i == here) 558 attrset(A_REVERSE); 559 /* Is it a slice entry displayed at the top? */ 560 if (label_chunk_info[i].type == PART_SLICE) { 561 sz = space_free(label_chunk_info[i].c); 562 mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 563 label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); 564 } 565 /* Otherwise it's a DOS, swap or filesystem entry, at the bottom */ 566 else { 567 char onestr[PART_OFF], num[10], *mountpoint, *newfs; 568 569 /* 570 * We copy this into a blank-padded string so that it looks like 571 * a solid bar in reverse-video 572 */ 573 memset(onestr, ' ', PART_OFF - 1); 574 onestr[PART_OFF - 1] = '\0'; 575 /* Go for two columns */ 576 if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) { 577 pcol = PART_OFF; 578 prow = CHUNK_PART_START_ROW; 579 } 580 memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 581 /* If it's a filesystem, display the mountpoint */ 582 if (label_chunk_info[i].c->private 583 && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 584 mountpoint = ((PartInfo *)label_chunk_info[i].c->private)->mountpoint; 585 else 586 mountpoint = "<none>"; 587 588 /* Now display the newfs field */ 589 if (label_chunk_info[i].type == PART_FAT) 590 newfs = "DOS"; 591 else if (label_chunk_info[i].c->private && label_chunk_info[i].type == PART_FILESYSTEM) 592 newfs = ((PartInfo *)label_chunk_info[i].c->private)->newfs ? "UFS Y" : "UFS N"; 593 else if (label_chunk_info[i].type == PART_SWAP) 594 newfs = "SWAP"; 595 else 596 newfs = "*"; 597 for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 598 onestr[PART_MOUNT_COL + j] = mountpoint[j]; 599 snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 600 memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 601 memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 602 onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 603 mvaddstr(prow, pcol, onestr); 604 ++prow; 605 } 606 if (i == here) 607 attrset(A_NORMAL); 608 } 609} 610 611static void 612print_command_summary() 613{ 614 mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 615 mvprintw(18, 0, "C = Create D = Delete M = Mount W = Write"); 616 mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 617 mvprintw(20, 0, "A = Auto Defaults for all!"); 618 mvprintw(22, 0, "The default target will be displayed in "); 619 620 attrset(A_REVERSE); 621 addstr("reverse"); 622 attrset(A_NORMAL); 623 addstr(" video."); 624 mvprintw(23, 0, "Use F1 or ? to get more help, arrow keys to move."); 625 move(0, 0); 626} 627 628static int 629diskLabel(char *str) 630{ 631 int sz, key = 0; 632 Boolean labeling; 633 char *msg = NULL; 634 PartInfo *p, *oldp; 635 PartType type; 636 Device **devs; 637 638 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 639 if (!devs) { 640 dialog_clear(); 641 msgConfirm("No disks found!"); 642 return RET_FAIL; 643 } 644 645 labeling = TRUE; 646 keypad(stdscr, TRUE); 647 record_label_chunks(devs); 648 649 dialog_clear(); clear(); 650 while (labeling) { 651 clear(); 652 print_label_chunks(); 653 print_command_summary(); 654 if (msg) { 655 attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL); 656 clrtoeol(); 657 beep(); 658 msg = NULL; 659 } 660 refresh(); 661 key = toupper(getch()); 662 switch (key) { 663 int i, cnt; 664 665 case '\014': /* ^L */ 666 continue; 667 668 case KEY_UP: 669 case '-': 670 if (here != 0) 671 --here; 672 else 673 while (label_chunk_info[here + 1].c) 674 ++here; 675 break; 676 677 case KEY_DOWN: 678 case '+': 679 case '\r': 680 case '\n': 681 if (label_chunk_info[here + 1].c) 682 ++here; 683 else 684 here = 0; 685 break; 686 687 case KEY_HOME: 688 here = 0; 689 break; 690 691 case KEY_END: 692 while (label_chunk_info[here + 1].c) 693 ++here; 694 break; 695 696 case KEY_F(1): 697 case '?': 698 systemDisplayHelp("partition"); 699 break; 700 701 case 'A': 702 if (label_chunk_info[here].type != PART_SLICE) { 703 msg = "You can only do this in a master partition (see top of screen)"; 704 break; 705 } 706 707 cnt = i = 0; 708 while (label_chunk_info[i].c) 709 if (label_chunk_info[i++].type != PART_SLICE) 710 cnt++; 711 if (cnt == (CHUNK_COLUMN_MAX * 2) + 4) { 712 dialog_clear(); 713 msgConfirm("Sorry, I can't fit any more partitions on the screen! You can get around\n" 714 "this limitation by partitioning your disks individually rather than all\n" 715 "at once. This will be fixed just as soon as we get a scrolling partition\n" 716 "box written. Sorry for the inconvenience!"); 717 break; 718 } 719 720 sz = space_free(label_chunk_info[here].c); 721 if (sz <= FS_MIN_SIZE) { 722 msg = "Not enough space to create an additional FreeBSD partition"; 723 break; 724 } 725 { 726 struct chunk *tmp; 727 int mib[2]; 728 int physmem; 729 size_t size, swsize; 730 char *cp; 731 732 cp = variable_get(VAR_ROOT_SIZE); 733 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 734 label_chunk_info[here].c, 735 (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, 736 CHUNK_IS_ROOT); 737 738 if (!tmp) { 739 dialog_clear(); 740 msgConfirm("Unable to create the root partition. Too big?"); 741 break; 742 } 743 tmp->private = new_part("/", TRUE, tmp->size); 744 tmp->private_free = safe_free; 745 record_label_chunks(devs); 746 747 cp = variable_get(VAR_SWAP_SIZE); 748 if (cp) 749 swsize = atoi(cp) * ONE_MEG; 750 else { 751 mib[0] = CTL_HW; 752 mib[1] = HW_PHYSMEM; 753 size = sizeof physmem; 754 sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 755 swsize = 16 * ONE_MEG + (physmem * 2 / 512); 756 } 757 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 758 label_chunk_info[here].c, 759 swsize, 760 part, FS_SWAP, 0); 761 if (!tmp) { 762 dialog_clear(); 763 msgConfirm("Unable to create the swap partition. Too big?"); 764 break; 765 } 766 767 tmp->private = 0; 768 tmp->private_free = safe_free; 769 record_label_chunks(devs); 770 771 cp = variable_get(VAR_VAR_SIZE); 772 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 773 label_chunk_info[here].c, 774 (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 775 if (!tmp) { 776 dialog_clear(); 777 msgConfirm("Less than %dMB free for /var - you will need to\n" 778 "partition your disk manually with a custom install!", (cp ? atoi(cp) : VAR_MIN_SIZE)); 779 break; 780 } 781 tmp->private = new_part("/var", TRUE, tmp->size); 782 tmp->private_free = safe_free; 783 record_label_chunks(devs); 784 785 cp = variable_get(VAR_USR_SIZE); 786 if (cp) 787 sz = atoi(cp) * ONE_MEG; 788 else 789 sz = space_free(label_chunk_info[here].c); 790 if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) { 791 dialog_clear(); 792 msgConfirm("Less than %dMB free for /usr - you will need to\n" 793 "partition your disk manually with a custom install!", USR_MIN_SIZE); 794 break; 795 } 796 797 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 798 label_chunk_info[here].c, 799 sz, part, FS_BSDFFS, 0); 800 if (!tmp) { 801 dialog_clear(); 802 msgConfirm("Unable to create the /usr partition. Not enough space?\n" 803 "You will need to partition your disk manually with a custom install!"); 804 break; 805 } 806 /* At this point, we're reasonably "labelled" */ 807 variable_set2(DISK_LABELLED, "yes"); 808 tmp->private = new_part("/usr", TRUE, tmp->size); 809 tmp->private_free = safe_free; 810 record_label_chunks(devs); 811 } 812 break; 813 814 case 'C': 815 if (label_chunk_info[here].type != PART_SLICE) { 816 msg = "You can only do this in a master partition (see top of screen)"; 817 break; 818 } 819 else { 820 int i, cnt; 821 822 cnt = i = 0; 823 while (label_chunk_info[i].c) 824 if (label_chunk_info[i++].type != PART_SLICE) 825 cnt++; 826 if (cnt == (CHUNK_COLUMN_MAX * 2)) { 827 dialog_clear(); 828 msgConfirm("Sorry, I can't fit any more partitions on the screen! You can get around\n" 829 "this limitation by partitioning your disks individually rather than all\n" 830 "at once. This will be fixed just as soon as we get a scrolling partition\n" 831 "box written. Sorry for the inconvenience!"); 832 break; 833 } 834 } 835 sz = space_free(label_chunk_info[here].c); 836 if (sz <= FS_MIN_SIZE) { 837 msg = "Not enough space to create an additional FreeBSD partition"; 838 break; 839 } 840 { 841 char *val, *cp; 842 int size; 843 struct chunk *tmp; 844 char osize[80]; 845 u_long flags = 0; 846 847 sprintf(osize, "%d", sz); 848 val = msgGetInput(osize, "Please specify the size for new FreeBSD partition in blocks, or\n" 849 "append a trailing `M' for megabytes (e.g. 20M) or `C' for cylinders.\n\n" 850 "Space free is %d blocks (%dMB)", sz, sz / ONE_MEG); 851 if (!val || (size = strtol(val, &cp, 0)) <= 0) 852 break; 853 854 if (*cp) { 855 if (toupper(*cp) == 'M') 856 size *= ONE_MEG; 857 else if (toupper(*cp) == 'C') 858 size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 859 } 860 if (size <= FS_MIN_SIZE) { 861 msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 862 break; 863 } 864 type = get_partition_type(); 865 if (type == PART_NONE) 866 break; 867 868 if (type == PART_FILESYSTEM) { 869 if ((p = get_mountpoint(NULL)) == NULL) 870 break; 871 else if (!strcmp(p->mountpoint, "/")) 872 flags |= CHUNK_IS_ROOT; 873 else 874 flags &= ~CHUNK_IS_ROOT; 875 } else 876 p = NULL; 877 878 if ((flags & CHUNK_IS_ROOT)) { 879 if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 880 msgConfirm("This region cannot be used for your root partition as the\n" 881 "FreeBSD boot code cannot deal with a root partition created\n" 882 "in that location. Please choose another location or smaller\n" 883 "size for your root partition and try again!"); 884 break; 885 } 886 if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 887 msgConfirm("Warning: This is smaller than the recommended size for a\n" 888 "root partition. For a variety of reasons, root\n" 889 "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 890 } 891 } 892 tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 893 label_chunk_info[here].c, 894 size, part, 895 (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 896 flags); 897 if (!tmp) { 898 msgConfirm("Unable to create the partition. Too big?"); 899 break; 900 } 901 if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 902 msgConfirm("This region cannot be used for your root partition as it starts\n" 903 "or extends past the 1024'th cylinder mark and is thus a\n" 904 "poor location to boot from. Please choose another\n" 905 "location (or smaller size) for your root partition and try again!"); 906 Delete_Chunk(label_chunk_info[here].c->disk, tmp); 907 break; 908 } 909 if (type != PART_SWAP) { 910 /* This is needed to tell the newfs -u about the size */ 911 tmp->private = new_part(p->mountpoint, p->newfs, tmp->size); 912 tmp->private_free = safe_free; 913 safe_free(p); 914 } else { 915 tmp->private = p; 916 } 917 tmp->private_free = safe_free; 918 variable_set2(DISK_LABELLED, "yes"); 919 record_label_chunks(devs); 920 } 921 break; 922 923 case 'D': /* delete */ 924 if (label_chunk_info[here].type == PART_SLICE) { 925 msg = MSG_NOT_APPLICABLE; 926 break; 927 } 928 else if (label_chunk_info[here].type == PART_FAT) { 929 msg = "Use the Disk Partition Editor to delete DOS partitions"; 930 break; 931 } 932 Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 933 variable_set2(DISK_LABELLED, "yes"); 934 record_label_chunks(devs); 935 break; 936 937 case 'M': /* mount */ 938 switch(label_chunk_info[here].type) { 939 case PART_SLICE: 940 msg = MSG_NOT_APPLICABLE; 941 break; 942 943 case PART_SWAP: 944 msg = "You don't need to specify a mountpoint for a swap partition."; 945 break; 946 947 case PART_FAT: 948 case PART_FILESYSTEM: 949 oldp = label_chunk_info[here].c->private; 950 p = get_mountpoint(label_chunk_info[here].c); 951 if (p) { 952 if (!oldp) 953 p->newfs = FALSE; 954 if (label_chunk_info[here].type == PART_FAT 955 && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 956 || !strcmp(p->mountpoint, "/var"))) { 957 msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 958 strcpy(p->mountpoint, "/bogus"); 959 } 960 } 961 variable_set2(DISK_LABELLED, "yes"); 962 record_label_chunks(devs); 963 break; 964 965 default: 966 msgFatal("Bogus partition under cursor???"); 967 break; 968 } 969 break; 970 971 case 'N': /* Set newfs options */ 972 if (label_chunk_info[here].c->private && 973 ((PartInfo *)label_chunk_info[here].c->private)->newfs) 974 getNewfsCmd(label_chunk_info[here].c->private); 975 else 976 msg = MSG_NOT_APPLICABLE; 977 break; 978 979 case 'T': /* Toggle newfs state */ 980 if (label_chunk_info[here].type == PART_FILESYSTEM) { 981 PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private); 982 label_chunk_info[here].c->private = new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 983 safe_free(pi); 984 label_chunk_info[here].c->private_free = safe_free; 985 variable_set2(DISK_LABELLED, "yes"); 986 } 987 else 988 msg = MSG_NOT_APPLICABLE; 989 break; 990 991 case 'U': 992 clear(); 993 if (msgYesNo("Are you SURE you want to Undo everything?")) 994 break; 995 variable_unset(DISK_PARTITIONED); 996 for (i = 0; devs[i]; i++) { 997 extern void diskPartition(Device *dev, Disk *d); 998 Disk *d; 999 1000 if (!devs[i]->enabled) 1001 continue; 1002 else if ((d = Open_Disk(devs[i]->name)) != NULL) { 1003 Free_Disk(devs[i]->private); 1004 devs[i]->private = d; 1005 diskPartition(devs[i], d); 1006 } 1007 } 1008 variable_unset(DISK_LABELLED); 1009 record_label_chunks(devs); 1010 break; 1011 1012 case 'W': 1013 if (!msgYesNo("Are you SURE that you wish to make and mount all filesystems\n" 1014 "at this time? You also have the option of doing it later in\n" 1015 "one final 'commit' operation, and if you're at all unsure as\n" 1016 "to which option to chose, then PLEASE CHOSE NO! This option\n" 1017 "is DANGEROUS if you're not EXACTLY sure what you are doing!")) { 1018 variable_set2(DISK_LABELLED, "yes"); 1019 clear(); 1020 diskLabelCommit(NULL); 1021 } 1022 break; 1023 1024 case '|': 1025 if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 1026 "This is an entirely undocumented feature which you are not\n" 1027 "expected to understand!")) { 1028 int i; 1029 Device **devs; 1030 1031 dialog_clear(); 1032 end_dialog(); 1033 DialogActive = FALSE; 1034 devs = deviceFind(NULL, DEVICE_TYPE_DISK); 1035 if (!devs) { 1036 dialog_clear(); 1037 msgConfirm("Can't find any disk devices!"); 1038 break; 1039 } 1040 for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 1041 if (devs[i]->enabled) 1042 slice_wizard(((Disk *)devs[i]->private)); 1043 } 1044 variable_set2(DISK_LABELLED, "yes"); 1045 DialogActive = TRUE; 1046 dialog_clear(); 1047 record_label_chunks(devs); 1048 } 1049 else 1050 msg = "A most prudent choice!"; 1051 break; 1052 1053 case 'Q': 1054 labeling = FALSE; 1055 break; 1056 1057 default: 1058 beep(); 1059 msg = "Type F1 or ? for help"; 1060 break; 1061 } 1062 } 1063 dialog_clear(); 1064 return RET_SUCCESS; 1065} 1066