label.c revision 18687
18549Sjkh/* 28549Sjkh * The new sysinstall program. 38549Sjkh * 48549Sjkh * This is probably the last program in the `sysinstall' line - the next 58549Sjkh * generation being essentially a complete rewrite. 68549Sjkh * 718687Sjkh * $Id: label.c,v 1.61 1996/10/02 02:19:35 jkh Exp $ 88549Sjkh * 98549Sjkh * Copyright (c) 1995 108549Sjkh * Jordan Hubbard. All rights reserved. 118549Sjkh * 128549Sjkh * Redistribution and use in source and binary forms, with or without 138549Sjkh * modification, are permitted provided that the following conditions 148549Sjkh * are met: 158549Sjkh * 1. Redistributions of source code must retain the above copyright 168881Srgrimes * notice, this list of conditions and the following disclaimer, 178881Srgrimes * verbatim and that no modifications are made prior to this 188549Sjkh * point in the file. 198549Sjkh * 2. Redistributions in binary form must reproduce the above copyright 208549Sjkh * notice, this list of conditions and the following disclaimer in the 218549Sjkh * documentation and/or other materials provided with the distribution. 228549Sjkh * 238549Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 248549Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 258549Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 268549Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 278549Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 288549Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 298549Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 308549Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 318549Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 328549Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 338549Sjkh * SUCH DAMAGE. 348549Sjkh * 358549Sjkh */ 368549Sjkh 378549Sjkh#include "sysinstall.h" 388549Sjkh#include <ctype.h> 398549Sjkh#include <sys/disklabel.h> 4010882Speter#include <sys/param.h> 4110882Speter#include <sys/sysctl.h> 428549Sjkh 438549Sjkh/* 448549Sjkh * Everything to do with editing the contents of disk labels. 458549Sjkh */ 468549Sjkh 478549Sjkh/* A nice message we use a lot in the disklabel editor */ 488549Sjkh#define MSG_NOT_APPLICABLE "That option is not applicable here" 498549Sjkh 508549Sjkh/* Where to start printing the freebsd slices */ 518549Sjkh#define CHUNK_SLICE_START_ROW 2 528622Sjkh#define CHUNK_PART_START_ROW 11 538549Sjkh 548549Sjkh/* The smallest filesystem we're willing to create */ 558702Sjkh#define FS_MIN_SIZE ONE_MEG 568549Sjkh 578672Sjkh/* The smallest root filesystem we're willing to create */ 5812661Speter#define ROOT_MIN_SIZE 20 598549Sjkh 6012661Speter/* The smallest swap partition we want to create by default */ 6112661Speter#define SWAP_MIN_SIZE 16 6212661Speter 6312661Speter/* The smallest /usr partition we're willing to create by default */ 6412661Speter#define USR_MIN_SIZE 80 6512661Speter 6612661Speter/* The smallest /var partition we're willing to create by default */ 6712661Speter#define VAR_MIN_SIZE 30 6812661Speter 6915440Sjkh/* The bottom-most row we're allowed to scribble on */ 7015440Sjkh#define CHUNK_ROW_MAX 16 7115440Sjkh 7215440Sjkh 738549Sjkh/* All the chunks currently displayed on the screen */ 748549Sjkhstatic struct { 758549Sjkh struct chunk *c; 768549Sjkh PartType type; 778549Sjkh} label_chunk_info[MAX_CHUNKS + 1]; 788549Sjkhstatic int here; 798549Sjkh 8015440Sjkhstatic int ChunkPartStartRow; 8115440Sjkhstatic WINDOW *ChunkWin; 8215440Sjkh 8312661Speterstatic int diskLabel(char *str); 8412661Speter 8512661Speterint 8615091SjkhdiskLabelEditor(dialogMenuItem *self) 8712661Speter{ 8812661Speter Device **devs; 8915242Sjkh int i, cnt, enabled; 9015242Sjkh char *cp; 9112661Speter 9212661Speter cp = variable_get(VAR_DISK); 9312661Speter devs = deviceFind(cp, DEVICE_TYPE_DISK); 9412661Speter cnt = deviceCount(devs); 9512661Speter if (!cnt) { 9612661Speter msgConfirm("No disks found! Please verify that your disk controller is being\n" 9712661Speter "properly probed at boot time. See the Hardware Guide on the\n" 9812661Speter "Documentation menu for clues on diagnosing this type of problem."); 9915242Sjkh return DITEM_FAILURE; 10012661Speter } 10115242Sjkh for (i = 0, enabled = 0; i < cnt; i++) { 10215242Sjkh if (devs[i]->enabled) 10315242Sjkh ++enabled; 10412661Speter } 10515242Sjkh if (!enabled) { 10615695Sjkh msgConfirm("No disks have been selected. Please visit the Partition\n" 10715695Sjkh "editor first to specify which disks you wish to operate on."); 10815695Sjkh return DITEM_FAILURE; 10912661Speter } 11015242Sjkh i = diskLabel(devs[0]->name); 11115419Sjkh if (DITEM_STATUS(i) != DITEM_FAILURE) 11215242Sjkh variable_set2(DISK_LABELLED, "yes"); 11312661Speter return i; 11412661Speter} 11512661Speter 11612661Speterint 11715091SjkhdiskLabelCommit(dialogMenuItem *self) 11812661Speter{ 11912661Speter char *cp; 12012661Speter int i; 12112661Speter 12212661Speter /* Already done? */ 12317025Sjkh if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 12415242Sjkh i = DITEM_SUCCESS; 12512661Speter else if (!cp) { 12612661Speter msgConfirm("You must assign disk labels before this option can be used."); 12715242Sjkh i = DITEM_FAILURE; 12812661Speter } 12912661Speter /* The routine will guard against redundant writes, just as this one does */ 13015419Sjkh else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 13115242Sjkh i = DITEM_FAILURE; 13215419Sjkh else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 13315242Sjkh i = DITEM_FAILURE; 13412661Speter else { 13512661Speter msgInfo("All filesystem information written successfully."); 13612661Speter variable_set2(DISK_LABELLED, "written"); 13715242Sjkh i = DITEM_SUCCESS; 13812661Speter } 13912661Speter return i; 14012661Speter} 14112661Speter 1428549Sjkh/* See if we're already using a desired partition name */ 1438549Sjkhstatic Boolean 1448549Sjkhcheck_conflict(char *name) 1458549Sjkh{ 1468549Sjkh int i; 1478549Sjkh 1488751Sjkh for (i = 0; label_chunk_info[i].c; i++) 14914793Sjoerg if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private_data 15014793Sjoerg && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 1518549Sjkh return TRUE; 1528549Sjkh return FALSE; 1538549Sjkh} 1548549Sjkh 1558549Sjkh/* How much space is in this FreeBSD slice? */ 1568549Sjkhstatic int 1578549Sjkhspace_free(struct chunk *c) 1588549Sjkh{ 15912661Speter struct chunk *c1; 1608549Sjkh int sz = c->size; 1618549Sjkh 16212661Speter for (c1 = c->part; c1; c1 = c1->next) { 1638549Sjkh if (c1->type != unused) 1648549Sjkh sz -= c1->size; 1658549Sjkh } 1668549Sjkh if (sz < 0) 1678549Sjkh msgFatal("Partitions are larger than actual chunk??"); 1688549Sjkh return sz; 1698549Sjkh} 1708549Sjkh 1718549Sjkh/* Snapshot the current situation into the displayed chunks structure */ 1728549Sjkhstatic void 17312661Speterrecord_label_chunks(Device **devs) 1748549Sjkh{ 1758549Sjkh int i, j, p; 1768549Sjkh struct chunk *c1, *c2; 1778556Sjkh Disk *d; 1788549Sjkh 17915440Sjkh ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3; 1808549Sjkh j = p = 0; 1818556Sjkh /* First buzz through and pick up the FreeBSD slices */ 1828549Sjkh for (i = 0; devs[i]; i++) { 1838556Sjkh if (!devs[i]->enabled) 1848556Sjkh continue; 1858556Sjkh d = (Disk *)devs[i]->private; 1868556Sjkh if (!d->chunks) 1878556Sjkh msgFatal("No chunk list found for %s!", d->name); 1888549Sjkh 1898556Sjkh /* Put the slice entries first */ 1908556Sjkh for (c1 = d->chunks->part; c1; c1 = c1->next) { 1918549Sjkh if (c1->type == freebsd) { 1928549Sjkh label_chunk_info[j].type = PART_SLICE; 1938549Sjkh label_chunk_info[j].c = c1; 1948549Sjkh ++j; 19515440Sjkh ++ChunkPartStartRow; 1968549Sjkh } 1978549Sjkh } 1988549Sjkh } 19912661Speter 2008556Sjkh /* Now run through again and get the FreeBSD partition entries */ 2018556Sjkh for (i = 0; devs[i]; i++) { 2028556Sjkh if (!devs[i]->enabled) 2038556Sjkh continue; 2048556Sjkh d = (Disk *)devs[i]->private; 2058549Sjkh /* Then buzz through and pick up the partitions */ 2068556Sjkh for (c1 = d->chunks->part; c1; c1 = c1->next) { 2078549Sjkh if (c1->type == freebsd) { 2088549Sjkh for (c2 = c1->part; c2; c2 = c2->next) { 2098549Sjkh if (c2->type == part) { 2108549Sjkh if (c2->subtype == FS_SWAP) 2118549Sjkh label_chunk_info[j].type = PART_SWAP; 2128549Sjkh else 2138549Sjkh label_chunk_info[j].type = PART_FILESYSTEM; 2148549Sjkh label_chunk_info[j].c = c2; 2158549Sjkh ++j; 2168549Sjkh } 2178549Sjkh } 2188549Sjkh } 2198549Sjkh else if (c1->type == fat) { 2208549Sjkh label_chunk_info[j].type = PART_FAT; 2218549Sjkh label_chunk_info[j].c = c1; 2228702Sjkh ++j; 2238549Sjkh } 2248549Sjkh } 2258549Sjkh } 2268549Sjkh label_chunk_info[j].c = NULL; 2278549Sjkh if (here >= j) 2288549Sjkh here = j ? j - 1 : 0; 22915442Sjkh if (ChunkWin) { 23015440Sjkh wclear(ChunkWin); 23115442Sjkh wrefresh(ChunkWin); 23215442Sjkh } 23315440Sjkh else 23415440Sjkh ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 2358549Sjkh} 2368549Sjkh 2378549Sjkh/* A new partition entry */ 2388549Sjkhstatic PartInfo * 2398665Sphknew_part(char *mpoint, Boolean newfs, u_long size) 2408549Sjkh{ 2418549Sjkh PartInfo *ret; 2428549Sjkh 2439202Srgrimes if (!mpoint) 2449202Srgrimes mpoint = "/change_me"; 2459202Srgrimes 2468549Sjkh ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 2478549Sjkh strncpy(ret->mountpoint, mpoint, FILENAME_MAX); 24814335Sjkh strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 2498666Sphk ret->newfs = newfs; 2508669Sphk if (!size) 2518669Sphk return ret; 2528549Sjkh return ret; 2538549Sjkh} 2548549Sjkh 2558549Sjkh/* Get the mountpoint for a partition and save it away */ 25612661Speterstatic PartInfo * 2578589Sjkhget_mountpoint(struct chunk *old) 2588549Sjkh{ 2598549Sjkh char *val; 2608549Sjkh PartInfo *tmp; 2618549Sjkh 26214793Sjoerg if (old && old->private_data) 26314793Sjoerg tmp = old->private_data; 2648810Sjkh else 2658810Sjkh tmp = NULL; 26618619Sjkh if (!old) { 26718621Sjkh DialogX = 14; 26818621Sjkh DialogY = 16; 26918619Sjkh } 2708810Sjkh val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 27118619Sjkh DialogX = DialogY = 0; 2728764Sjkh if (!val || !*val) { 2738751Sjkh if (!old) 2748751Sjkh return NULL; 2758751Sjkh else { 27614793Sjoerg free(old->private_data); 27714793Sjoerg old->private_data = NULL; 2788751Sjkh } 2798669Sphk return NULL; 2808751Sjkh } 2818669Sphk 2828669Sphk /* Is it just the same value? */ 2838810Sjkh if (tmp && !strcmp(tmp->mountpoint, val)) 2848669Sphk return NULL; 2858810Sjkh 2868810Sjkh /* Did we use it already? */ 2878669Sphk if (check_conflict(val)) { 2888669Sphk msgConfirm("You already have a mount point for %s assigned!", val); 2898669Sphk return NULL; 2908549Sjkh } 2918810Sjkh 2928810Sjkh /* Is it bogus? */ 2938669Sphk if (*val != '/') { 2948669Sphk msgConfirm("Mount point must start with a / character"); 2958669Sphk return NULL; 2968669Sphk } 2978810Sjkh 2988810Sjkh /* Is it going to be mounted on root? */ 2998669Sphk if (!strcmp(val, "/")) { 3008669Sphk if (old) 3018669Sphk old->flags |= CHUNK_IS_ROOT; 3028810Sjkh } 3038810Sjkh else if (old) 3048669Sphk old->flags &= ~CHUNK_IS_ROOT; 3058810Sjkh 3068810Sjkh safe_free(tmp); 3078669Sphk tmp = new_part(val, TRUE, 0); 3088669Sphk if (old) { 30914793Sjoerg old->private_data = tmp; 3108669Sphk old->private_free = safe_free; 3118669Sphk } 3128669Sphk return tmp; 3138549Sjkh} 3148549Sjkh 3158549Sjkh/* Get the type of the new partiton */ 3168549Sjkhstatic PartType 3178549Sjkhget_partition_type(void) 3188549Sjkh{ 3198549Sjkh char selection[20]; 3208669Sphk int i; 3218669Sphk 3228549Sjkh static unsigned char *fs_types[] = { 3238549Sjkh "FS", 3248549Sjkh "A file system", 3258549Sjkh "Swap", 3268549Sjkh "A swap partition.", 3278549Sjkh }; 32818619Sjkh DialogX = 7; 32918621Sjkh DialogY = 8; 3308669Sphk i = dialog_menu("Please choose a partition type", 33112661Speter "If you want to use this partition for swap space, select Swap.\n" 33212661Speter "If you want to put a filesystem on it, choose FS.", 33312661Speter -1, -1, 2, 2, fs_types, selection, NULL, NULL); 33418619Sjkh DialogX = DialogY = 0; 3358669Sphk if (!i) { 3368549Sjkh if (!strcmp(selection, "FS")) 3378549Sjkh return PART_FILESYSTEM; 3388549Sjkh else if (!strcmp(selection, "Swap")) 3398549Sjkh return PART_SWAP; 3408549Sjkh } 3418549Sjkh return PART_NONE; 3428549Sjkh} 3438549Sjkh 3448549Sjkh/* If the user wants a special newfs command for this, set it */ 3458549Sjkhstatic void 3468549SjkhgetNewfsCmd(PartInfo *p) 3478549Sjkh{ 3488549Sjkh char *val; 3498549Sjkh 3508549Sjkh val = msgGetInput(p->newfs_cmd, 35112661Speter "Please enter the newfs command and options you'd like to use in\n" 35212661Speter "creating this file system."); 3538549Sjkh if (val) 3548549Sjkh strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 3558549Sjkh} 3568549Sjkh 3578549Sjkh#define MAX_MOUNT_NAME 12 3588549Sjkh 3598549Sjkh#define PART_PART_COL 0 3608549Sjkh#define PART_MOUNT_COL 8 3618549Sjkh#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 3628549Sjkh#define PART_NEWFS_COL (PART_SIZE_COL + 7) 3638549Sjkh#define PART_OFF 38 3648549Sjkh 3658549Sjkh/* stick this all up on the screen */ 3668549Sjkhstatic void 3678549Sjkhprint_label_chunks(void) 3688549Sjkh{ 3698549Sjkh int i, j, srow, prow, pcol; 3708549Sjkh int sz; 3718549Sjkh 3728549Sjkh attrset(A_REVERSE); 3738549Sjkh mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 3748549Sjkh attrset(A_NORMAL); 3758549Sjkh 3768549Sjkh for (i = 0; i < 2; i++) { 37715440Sjkh mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 37815440Sjkh mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 3798549Sjkh 38015440Sjkh mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 38115440Sjkh mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 3828549Sjkh 38315440Sjkh mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 38415440Sjkh mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 3858549Sjkh 38615440Sjkh mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 38715440Sjkh mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 3888549Sjkh } 3898549Sjkh srow = CHUNK_SLICE_START_ROW; 39015440Sjkh prow = 0; 3918549Sjkh pcol = 0; 3928549Sjkh 3938751Sjkh for (i = 0; label_chunk_info[i].c; i++) { 3948549Sjkh /* Is it a slice entry displayed at the top? */ 3958549Sjkh if (label_chunk_info[i].type == PART_SLICE) { 3968549Sjkh sz = space_free(label_chunk_info[i].c); 39715440Sjkh if (i == here) 39816208Sjkh attrset(ATTR_SELECTED); 3998751Sjkh mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 4008751Sjkh label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); 40115440Sjkh attrset(A_NORMAL); 40215440Sjkh clrtoeol(); 40315440Sjkh move(0, 0); 40415440Sjkh refresh(); 4058549Sjkh } 40615440Sjkh /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 4078549Sjkh else { 4088549Sjkh char onestr[PART_OFF], num[10], *mountpoint, *newfs; 4098549Sjkh 4108549Sjkh /* 4118549Sjkh * We copy this into a blank-padded string so that it looks like 4128549Sjkh * a solid bar in reverse-video 4138549Sjkh */ 4148549Sjkh memset(onestr, ' ', PART_OFF - 1); 4158549Sjkh onestr[PART_OFF - 1] = '\0'; 41615440Sjkh /* Go for two columns if we've written one full columns worth */ 41715440Sjkh if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) { 4188549Sjkh pcol = PART_OFF; 41915440Sjkh prow = 0; 4208549Sjkh } 4218705Sjkh memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 4228549Sjkh /* If it's a filesystem, display the mountpoint */ 42314793Sjoerg if (label_chunk_info[i].c->private_data 42410882Speter && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 42514793Sjoerg mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 42610882Speter else 42710882Speter mountpoint = "<none>"; 42810882Speter 42910882Speter /* Now display the newfs field */ 43010882Speter if (label_chunk_info[i].type == PART_FAT) 43110882Speter newfs = "DOS"; 43214793Sjoerg else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 43314793Sjoerg newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 43410882Speter else if (label_chunk_info[i].type == PART_SWAP) 43510882Speter newfs = "SWAP"; 43610882Speter else 4378549Sjkh newfs = "*"; 4388549Sjkh for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 4398549Sjkh onestr[PART_MOUNT_COL + j] = mountpoint[j]; 4408764Sjkh snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 4418549Sjkh memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 4428549Sjkh memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 4438549Sjkh onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 44415440Sjkh if (i == here) 44516208Sjkh wattrset(ChunkWin, ATTR_SELECTED); 44615440Sjkh mvwaddstr(ChunkWin, prow, pcol, onestr); 44715440Sjkh wattrset(ChunkWin, A_NORMAL); 44815440Sjkh wrefresh(ChunkWin); 44915440Sjkh move(0, 0); 4508549Sjkh ++prow; 4518549Sjkh } 4528549Sjkh } 4538549Sjkh} 4548549Sjkh 4558549Sjkhstatic void 45618619Sjkhprint_command_summary(void) 4578549Sjkh{ 4588820Sjkh mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 45915440Sjkh mvprintw(18, 0, "C = Create D = Delete M = Mount"); 46015440Sjkh if (!RunningAsInit) 46115695Sjkh mvprintw(18, 47, "W = Write"); 46210882Speter mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 46310882Speter mvprintw(20, 0, "A = Auto Defaults for all!"); 46415695Sjkh mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 4658549Sjkh move(0, 0); 4668549Sjkh} 4678549Sjkh 46818619Sjkhstatic void 46918619Sjkhclear_wins(void) 47018619Sjkh{ 47118619Sjkh clear(); 47218619Sjkh wclear(ChunkWin); 47318619Sjkh} 47418619Sjkh 47512661Speterstatic int 47612661SpeterdiskLabel(char *str) 4778549Sjkh{ 47818619Sjkh int sz, key = 0; 4798549Sjkh Boolean labeling; 4808549Sjkh char *msg = NULL; 4819202Srgrimes PartInfo *p, *oldp; 4828549Sjkh PartType type; 4838824Sjkh Device **devs; 4848549Sjkh 48512661Speter devs = deviceFind(NULL, DEVICE_TYPE_DISK); 48612661Speter if (!devs) { 48712661Speter msgConfirm("No disks found!"); 48815242Sjkh return DITEM_FAILURE; 48912661Speter } 49012661Speter 4918549Sjkh labeling = TRUE; 4928549Sjkh keypad(stdscr, TRUE); 49312661Speter record_label_chunks(devs); 4948549Sjkh 49518619Sjkh clear(); 4968549Sjkh while (labeling) { 4978549Sjkh print_label_chunks(); 49818619Sjkh print_command_summary(); 4998549Sjkh if (msg) { 50015695Sjkh attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 50112661Speter clrtoeol(); 5028549Sjkh beep(); 5038549Sjkh msg = NULL; 5048549Sjkh } 50515442Sjkh else { 50615442Sjkh move(23, 0); 50715442Sjkh clrtoeol(); 50815442Sjkh } 50918619Sjkh refresh(); 51017397Sjkh key = getch(); 51117397Sjkh switch (toupper(key)) { 51215440Sjkh int i; 51317362Sjkh static char _msg[40]; 5148549Sjkh 5158751Sjkh case '\014': /* ^L */ 51618619Sjkh clear_wins(); 51718619Sjkh break; 5188751Sjkh 5198549Sjkh case KEY_UP: 5208549Sjkh case '-': 5218549Sjkh if (here != 0) 5228549Sjkh --here; 5238751Sjkh else 5248751Sjkh while (label_chunk_info[here + 1].c) 5258751Sjkh ++here; 5268549Sjkh break; 5278549Sjkh 5288549Sjkh case KEY_DOWN: 5298549Sjkh case '+': 5308549Sjkh case '\r': 5318549Sjkh case '\n': 5328751Sjkh if (label_chunk_info[here + 1].c) 5338549Sjkh ++here; 5348751Sjkh else 5358751Sjkh here = 0; 5368549Sjkh break; 5378549Sjkh 5388549Sjkh case KEY_HOME: 5398549Sjkh here = 0; 5408549Sjkh break; 5418549Sjkh 5428549Sjkh case KEY_END: 5438751Sjkh while (label_chunk_info[here + 1].c) 5448549Sjkh ++here; 5458549Sjkh break; 5468549Sjkh 5478549Sjkh case KEY_F(1): 5488549Sjkh case '?': 54912661Speter systemDisplayHelp("partition"); 55018619Sjkh clear_wins(); 5518549Sjkh break; 5528549Sjkh 55310882Speter case 'A': 55410882Speter if (label_chunk_info[here].type != PART_SLICE) { 55515440Sjkh msg = "You can only do this in a disk slice (at top of screen)"; 55610882Speter break; 55710882Speter } 55810882Speter sz = space_free(label_chunk_info[here].c); 55917362Sjkh if (sz <= FS_MIN_SIZE) 56015440Sjkh msg = "Not enough free space to create a new partition in the slice"; 56115440Sjkh else { 56215440Sjkh struct chunk *tmp; 56315440Sjkh int mib[2]; 56415440Sjkh int physmem; 56515440Sjkh size_t size, swsize; 56615440Sjkh char *cp; 56717362Sjkh Chunk *rootdev, *swapdev, *usrdev, *vardev; 56812661Speter 56917368Sjkh (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 57017362Sjkh if (!rootdev) { 57117362Sjkh cp = variable_get(VAR_ROOT_SIZE); 57217362Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 57317362Sjkh (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 57417362Sjkh if (!tmp) { 57517362Sjkh msgConfirm("Unable to create the root partition. Too big?"); 57618619Sjkh clear_wins(); 57717362Sjkh break; 57817362Sjkh } 57917362Sjkh tmp->private_data = new_part("/", TRUE, tmp->size); 58017362Sjkh tmp->private_free = safe_free; 58117362Sjkh record_label_chunks(devs); 58215440Sjkh } 58317362Sjkh 58417362Sjkh if (!swapdev) { 58517362Sjkh cp = variable_get(VAR_SWAP_SIZE); 58617362Sjkh if (cp) 58717362Sjkh swsize = atoi(cp) * ONE_MEG; 58817362Sjkh else { 58917362Sjkh mib[0] = CTL_HW; 59017362Sjkh mib[1] = HW_PHYSMEM; 59117362Sjkh size = sizeof physmem; 59217362Sjkh sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 59317362Sjkh swsize = 16 * ONE_MEG + (physmem * 2 / 512); 59417362Sjkh } 59517362Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 59617362Sjkh swsize, part, FS_SWAP, 0); 59717362Sjkh if (!tmp) { 59817362Sjkh msgConfirm("Unable to create the swap partition. Too big?"); 59918619Sjkh clear_wins(); 60017362Sjkh break; 60117362Sjkh } 60217362Sjkh tmp->private_data = 0; 60317362Sjkh tmp->private_free = safe_free; 60417362Sjkh record_label_chunks(devs); 60515440Sjkh } 60617362Sjkh 60717362Sjkh if (!vardev) { 60817362Sjkh cp = variable_get(VAR_VAR_SIZE); 60917362Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 61017362Sjkh (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 61117362Sjkh if (!tmp) { 61217362Sjkh msgConfirm("Less than %dMB free for /var - you will need to\n" 61317362Sjkh "partition your disk manually with a custom install!", 61417362Sjkh (cp ? atoi(cp) : VAR_MIN_SIZE)); 61518619Sjkh clear_wins(); 61617362Sjkh break; 61717362Sjkh } 61817362Sjkh tmp->private_data = new_part("/var", TRUE, tmp->size); 61917362Sjkh tmp->private_free = safe_free; 62017362Sjkh record_label_chunks(devs); 62115440Sjkh } 62212661Speter 62317362Sjkh if (!usrdev) { 62417362Sjkh cp = variable_get(VAR_USR_SIZE); 62517362Sjkh if (cp) 62617362Sjkh sz = atoi(cp) * ONE_MEG; 62717362Sjkh else 62817362Sjkh sz = space_free(label_chunk_info[here].c); 62917362Sjkh if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) { 63017362Sjkh msgConfirm("Less than %dMB free for /usr - you will need to\n" 63117362Sjkh "partition your disk manually with a custom install!", USR_MIN_SIZE); 63218619Sjkh clear_wins(); 63317362Sjkh break; 63417362Sjkh } 63517362Sjkh 63617362Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 63717362Sjkh label_chunk_info[here].c, 63817362Sjkh sz, part, FS_BSDFFS, 0); 63917362Sjkh if (!tmp) { 64017362Sjkh msgConfirm("Unable to create the /usr partition. Not enough space?\n" 64117362Sjkh "You will need to partition your disk manually with a custom install!"); 64218619Sjkh clear_wins(); 64317362Sjkh break; 64417362Sjkh } 64517362Sjkh tmp->private_data = new_part("/usr", TRUE, tmp->size); 64617362Sjkh tmp->private_free = safe_free; 64717362Sjkh record_label_chunks(devs); 64815440Sjkh } 64915440Sjkh /* At this point, we're reasonably "labelled" */ 65015440Sjkh variable_set2(DISK_LABELLED, "yes"); 65110882Speter } 65215440Sjkh break; 65310882Speter 6548549Sjkh case 'C': 6558549Sjkh if (label_chunk_info[here].type != PART_SLICE) { 6568549Sjkh msg = "You can only do this in a master partition (see top of screen)"; 6578549Sjkh break; 6588549Sjkh } 6598549Sjkh sz = space_free(label_chunk_info[here].c); 6608669Sphk if (sz <= FS_MIN_SIZE) { 66112661Speter msg = "Not enough space to create an additional FreeBSD partition"; 6628669Sphk break; 6638669Sphk } 66415440Sjkh else { 6658705Sjkh char *val, *cp; 6668702Sjkh int size; 6678702Sjkh struct chunk *tmp; 6688820Sjkh char osize[80]; 6698702Sjkh u_long flags = 0; 6708549Sjkh 6718820Sjkh sprintf(osize, "%d", sz); 67218619Sjkh DialogX = 3; 67318621Sjkh DialogY = 2; 67418619Sjkh val = msgGetInput(osize, 67518619Sjkh "Please specify the partition size in blocks or append a trailing M for\n" 67618619Sjkh "megabytes or C for cylinders. %d blocks (%dMB) are free.", 67718619Sjkh sz, sz / ONE_MEG); 67818619Sjkh DialogX = DialogY = 0; 67918619Sjkh if (!val || (size = strtol(val, &cp, 0)) <= 0) { 68018619Sjkh clear_wins(); 6818702Sjkh break; 68218619Sjkh } 6838549Sjkh 6848751Sjkh if (*cp) { 6858751Sjkh if (toupper(*cp) == 'M') 6868751Sjkh size *= ONE_MEG; 6878751Sjkh else if (toupper(*cp) == 'C') 6888751Sjkh size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 6898751Sjkh } 6908820Sjkh if (size <= FS_MIN_SIZE) { 6918820Sjkh msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 69218619Sjkh clear_wins(); 6938820Sjkh break; 6948820Sjkh } 6958702Sjkh type = get_partition_type(); 69618619Sjkh if (type == PART_NONE) { 69718619Sjkh clear_wins(); 69818619Sjkh beep(); 6998669Sphk break; 70018619Sjkh } 7018669Sphk 7028702Sjkh if (type == PART_FILESYSTEM) { 70318619Sjkh if ((p = get_mountpoint(NULL)) == NULL) { 70418619Sjkh clear_wins(); 70518619Sjkh beep(); 7068702Sjkh break; 70718619Sjkh } 7088702Sjkh else if (!strcmp(p->mountpoint, "/")) 7098702Sjkh flags |= CHUNK_IS_ROOT; 7108702Sjkh else 7118702Sjkh flags &= ~CHUNK_IS_ROOT; 71218619Sjkh } 71318619Sjkh else 7148702Sjkh p = NULL; 7158702Sjkh 7168702Sjkh if ((flags & CHUNK_IS_ROOT)) { 7178702Sjkh if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 71812661Speter msgConfirm("This region cannot be used for your root partition as the\n" 71912661Speter "FreeBSD boot code cannot deal with a root partition created\n" 72012661Speter "in that location. Please choose another location or smaller\n" 72112661Speter "size for your root partition and try again!"); 72218619Sjkh clear_wins(); 7238702Sjkh break; 7248702Sjkh } 72512661Speter if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 72612661Speter msgConfirm("Warning: This is smaller than the recommended size for a\n" 72712661Speter "root partition. For a variety of reasons, root\n" 72812661Speter "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 72912661Speter } 7308672Sjkh } 7318751Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 7328702Sjkh label_chunk_info[here].c, 7338702Sjkh size, part, 7348702Sjkh (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 7358702Sjkh flags); 7368702Sjkh if (!tmp) { 7378702Sjkh msgConfirm("Unable to create the partition. Too big?"); 73818619Sjkh clear_wins(); 7398672Sjkh break; 7408672Sjkh } 7418702Sjkh if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 74212661Speter msgConfirm("This region cannot be used for your root partition as it starts\n" 74312661Speter "or extends past the 1024'th cylinder mark and is thus a\n" 74412661Speter "poor location to boot from. Please choose another\n" 74512661Speter "location (or smaller size) for your root partition and try again!"); 7468751Sjkh Delete_Chunk(label_chunk_info[here].c->disk, tmp); 74718619Sjkh clear_wins(); 7488669Sphk break; 7498702Sjkh } 7508702Sjkh if (type != PART_SWAP) { 7518669Sphk /* This is needed to tell the newfs -u about the size */ 75214793Sjoerg tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 7538669Sphk safe_free(p); 75415355Sjkh } 75515355Sjkh else 75614793Sjoerg tmp->private_data = p; 7578702Sjkh tmp->private_free = safe_free; 75812661Speter variable_set2(DISK_LABELLED, "yes"); 75912661Speter record_label_chunks(devs); 76018619Sjkh clear_wins(); 7618549Sjkh } 7628549Sjkh break; 7638549Sjkh 76417397Sjkh case KEY_DC: 7658549Sjkh case 'D': /* delete */ 7668549Sjkh if (label_chunk_info[here].type == PART_SLICE) { 7678549Sjkh msg = MSG_NOT_APPLICABLE; 7688549Sjkh break; 7698549Sjkh } 7708549Sjkh else if (label_chunk_info[here].type == PART_FAT) { 7718705Sjkh msg = "Use the Disk Partition Editor to delete DOS partitions"; 7728549Sjkh break; 7738549Sjkh } 7748751Sjkh Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 77512661Speter variable_set2(DISK_LABELLED, "yes"); 77612661Speter record_label_chunks(devs); 7778549Sjkh break; 7788549Sjkh 7798549Sjkh case 'M': /* mount */ 7808549Sjkh switch(label_chunk_info[here].type) { 7818549Sjkh case PART_SLICE: 7828549Sjkh msg = MSG_NOT_APPLICABLE; 7838549Sjkh break; 7848549Sjkh 7858549Sjkh case PART_SWAP: 7868549Sjkh msg = "You don't need to specify a mountpoint for a swap partition."; 7878549Sjkh break; 7888549Sjkh 7898556Sjkh case PART_FAT: 7908549Sjkh case PART_FILESYSTEM: 79114793Sjoerg oldp = label_chunk_info[here].c->private_data; 7928589Sjkh p = get_mountpoint(label_chunk_info[here].c); 7938549Sjkh if (p) { 7949202Srgrimes if (!oldp) 7959202Srgrimes p->newfs = FALSE; 7968722Sjkh if (label_chunk_info[here].type == PART_FAT 7978722Sjkh && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 7988722Sjkh || !strcmp(p->mountpoint, "/var"))) { 7998722Sjkh msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 8008722Sjkh strcpy(p->mountpoint, "/bogus"); 8018722Sjkh } 8028549Sjkh } 80312661Speter variable_set2(DISK_LABELLED, "yes"); 80412661Speter record_label_chunks(devs); 80518636Sjkh clear_wins(); 8068549Sjkh break; 8078549Sjkh 8088549Sjkh default: 8098549Sjkh msgFatal("Bogus partition under cursor???"); 8108549Sjkh break; 8118549Sjkh } 8128549Sjkh break; 8138549Sjkh 8148549Sjkh case 'N': /* Set newfs options */ 81514793Sjoerg if (label_chunk_info[here].c->private_data && 81614793Sjoerg ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 81714793Sjoerg getNewfsCmd(label_chunk_info[here].c->private_data); 8188549Sjkh else 8198549Sjkh msg = MSG_NOT_APPLICABLE; 82018636Sjkh clear_wins(); 8218549Sjkh break; 8228549Sjkh 8238549Sjkh case 'T': /* Toggle newfs state */ 8249202Srgrimes if (label_chunk_info[here].type == PART_FILESYSTEM) { 82514793Sjoerg PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 82615355Sjkh label_chunk_info[here].c->private_data = 82715355Sjkh new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 8288669Sphk safe_free(pi); 8298820Sjkh label_chunk_info[here].c->private_free = safe_free; 83012661Speter variable_set2(DISK_LABELLED, "yes"); 83118619Sjkh } 8328549Sjkh else 8338549Sjkh msg = MSG_NOT_APPLICABLE; 8348549Sjkh break; 8358549Sjkh 8368820Sjkh case 'U': 83712661Speter clear(); 83812661Speter if (msgYesNo("Are you SURE you want to Undo everything?")) 83912661Speter break; 84012661Speter variable_unset(DISK_PARTITIONED); 84117025Sjkh variable_unset(DISK_LABELLED); 8428824Sjkh for (i = 0; devs[i]; i++) { 84312661Speter Disk *d; 84412661Speter 8458824Sjkh if (!devs[i]->enabled) 8468824Sjkh continue; 84712661Speter else if ((d = Open_Disk(devs[i]->name)) != NULL) { 8488824Sjkh Free_Disk(devs[i]->private); 84912661Speter devs[i]->private = d; 85012661Speter diskPartition(devs[i], d); 8518824Sjkh } 8528824Sjkh } 85312661Speter record_label_chunks(devs); 85418636Sjkh clear_wins(); 8558824Sjkh break; 8568820Sjkh 8578549Sjkh case 'W': 85818687Sjkh if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 85918687Sjkh "installation. If you are installing FreeBSD for the first time\n" 86018687Sjkh "then you should simply type Q when you're finished here and your\n" 86118687Sjkh "changes will be committed in one batch automatically at the end of\n" 86218687Sjkh "these questions.\n\n" 86318687Sjkh "Are you absolutely sure you want to do this now?")) { 86412661Speter variable_set2(DISK_LABELLED, "yes"); 86512661Speter diskLabelCommit(NULL); 86612661Speter } 86718636Sjkh clear_wins(); 86810882Speter break; 86910882Speter 87010882Speter case '|': 87112661Speter if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 87212661Speter "This is an entirely undocumented feature which you are not\n" 87312661Speter "expected to understand!")) { 8748549Sjkh int i; 8758549Sjkh Device **devs; 8768549Sjkh 8778549Sjkh dialog_clear(); 8788549Sjkh end_dialog(); 8798549Sjkh DialogActive = FALSE; 8808549Sjkh devs = deviceFind(NULL, DEVICE_TYPE_DISK); 8818549Sjkh if (!devs) { 88212661Speter msgConfirm("Can't find any disk devices!"); 8838549Sjkh break; 8848549Sjkh } 8858668Sphk for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 8868613Sjkh if (devs[i]->enabled) 8878613Sjkh slice_wizard(((Disk *)devs[i]->private)); 8888613Sjkh } 88912661Speter variable_set2(DISK_LABELLED, "yes"); 8908665Sphk DialogActive = TRUE; 89112661Speter record_label_chunks(devs); 89218636Sjkh clear_wins(); 8938549Sjkh } 8948549Sjkh else 8958549Sjkh msg = "A most prudent choice!"; 8968549Sjkh break; 8978549Sjkh 8989202Srgrimes case 'Q': 8998549Sjkh labeling = FALSE; 9008549Sjkh break; 9018549Sjkh 9028549Sjkh default: 9038549Sjkh beep(); 90417362Sjkh sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 90517362Sjkh msg = _msg; 9068549Sjkh break; 9078549Sjkh } 9088549Sjkh } 90917362Sjkh return DITEM_SUCCESS | DITEM_RESTORE; 9108549Sjkh} 911