label.c revision 21971
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 * 721673Sjkh * $FreeBSD: head/usr.sbin/sysinstall/label.c 21971 1997-01-24 07:47:17Z jkh $ 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); 11118744Sjkh if (DITEM_STATUS(i) != DITEM_FAILURE) { 11218744Sjkh char *cp; 11318744Sjkh 11418744Sjkh if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 11518744Sjkh variable_set2(DISK_LABELLED, "yes"); 11618744Sjkh } 11712661Speter return i; 11812661Speter} 11912661Speter 12012661Speterint 12115091SjkhdiskLabelCommit(dialogMenuItem *self) 12212661Speter{ 12312661Speter char *cp; 12412661Speter int i; 12512661Speter 12612661Speter /* Already done? */ 12717025Sjkh if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 12815242Sjkh i = DITEM_SUCCESS; 12912661Speter else if (!cp) { 13012661Speter msgConfirm("You must assign disk labels before this option can be used."); 13115242Sjkh i = DITEM_FAILURE; 13212661Speter } 13312661Speter /* The routine will guard against redundant writes, just as this one does */ 13415419Sjkh else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 13515242Sjkh i = DITEM_FAILURE; 13615419Sjkh else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 13715242Sjkh i = DITEM_FAILURE; 13812661Speter else { 13912661Speter msgInfo("All filesystem information written successfully."); 14012661Speter variable_set2(DISK_LABELLED, "written"); 14115242Sjkh i = DITEM_SUCCESS; 14212661Speter } 14312661Speter return i; 14412661Speter} 14512661Speter 1468549Sjkh/* See if we're already using a desired partition name */ 1478549Sjkhstatic Boolean 1488549Sjkhcheck_conflict(char *name) 1498549Sjkh{ 1508549Sjkh int i; 1518549Sjkh 1528751Sjkh for (i = 0; label_chunk_info[i].c; i++) 15314793Sjoerg if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private_data 15414793Sjoerg && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 1558549Sjkh return TRUE; 1568549Sjkh return FALSE; 1578549Sjkh} 1588549Sjkh 1598549Sjkh/* How much space is in this FreeBSD slice? */ 1608549Sjkhstatic int 1618549Sjkhspace_free(struct chunk *c) 1628549Sjkh{ 16312661Speter struct chunk *c1; 1648549Sjkh int sz = c->size; 1658549Sjkh 16612661Speter for (c1 = c->part; c1; c1 = c1->next) { 1678549Sjkh if (c1->type != unused) 1688549Sjkh sz -= c1->size; 1698549Sjkh } 1708549Sjkh if (sz < 0) 1718549Sjkh msgFatal("Partitions are larger than actual chunk??"); 1728549Sjkh return sz; 1738549Sjkh} 1748549Sjkh 1758549Sjkh/* Snapshot the current situation into the displayed chunks structure */ 1768549Sjkhstatic void 17712661Speterrecord_label_chunks(Device **devs) 1788549Sjkh{ 1798549Sjkh int i, j, p; 1808549Sjkh struct chunk *c1, *c2; 1818556Sjkh Disk *d; 1828549Sjkh 18315440Sjkh ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3; 1848549Sjkh j = p = 0; 1858556Sjkh /* First buzz through and pick up the FreeBSD slices */ 1868549Sjkh for (i = 0; devs[i]; i++) { 1878556Sjkh if (!devs[i]->enabled) 1888556Sjkh continue; 1898556Sjkh d = (Disk *)devs[i]->private; 1908556Sjkh if (!d->chunks) 1918556Sjkh msgFatal("No chunk list found for %s!", d->name); 1928549Sjkh 1938556Sjkh /* Put the slice entries first */ 1948556Sjkh for (c1 = d->chunks->part; c1; c1 = c1->next) { 1958549Sjkh if (c1->type == freebsd) { 1968549Sjkh label_chunk_info[j].type = PART_SLICE; 1978549Sjkh label_chunk_info[j].c = c1; 1988549Sjkh ++j; 19915440Sjkh ++ChunkPartStartRow; 2008549Sjkh } 2018549Sjkh } 2028549Sjkh } 20312661Speter 2048556Sjkh /* Now run through again and get the FreeBSD partition entries */ 2058556Sjkh for (i = 0; devs[i]; i++) { 2068556Sjkh if (!devs[i]->enabled) 2078556Sjkh continue; 2088556Sjkh d = (Disk *)devs[i]->private; 2098549Sjkh /* Then buzz through and pick up the partitions */ 2108556Sjkh for (c1 = d->chunks->part; c1; c1 = c1->next) { 2118549Sjkh if (c1->type == freebsd) { 2128549Sjkh for (c2 = c1->part; c2; c2 = c2->next) { 2138549Sjkh if (c2->type == part) { 2148549Sjkh if (c2->subtype == FS_SWAP) 2158549Sjkh label_chunk_info[j].type = PART_SWAP; 2168549Sjkh else 2178549Sjkh label_chunk_info[j].type = PART_FILESYSTEM; 2188549Sjkh label_chunk_info[j].c = c2; 2198549Sjkh ++j; 2208549Sjkh } 2218549Sjkh } 2228549Sjkh } 2238549Sjkh else if (c1->type == fat) { 2248549Sjkh label_chunk_info[j].type = PART_FAT; 2258549Sjkh label_chunk_info[j].c = c1; 2268702Sjkh ++j; 2278549Sjkh } 2288549Sjkh } 2298549Sjkh } 2308549Sjkh label_chunk_info[j].c = NULL; 2318549Sjkh if (here >= j) 2328549Sjkh here = j ? j - 1 : 0; 23315442Sjkh if (ChunkWin) { 23415440Sjkh wclear(ChunkWin); 23515442Sjkh wrefresh(ChunkWin); 23615442Sjkh } 23715440Sjkh else 23815440Sjkh ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 2398549Sjkh} 2408549Sjkh 2418549Sjkh/* A new partition entry */ 2428549Sjkhstatic PartInfo * 2438665Sphknew_part(char *mpoint, Boolean newfs, u_long size) 2448549Sjkh{ 2458549Sjkh PartInfo *ret; 2468549Sjkh 2479202Srgrimes if (!mpoint) 2489202Srgrimes mpoint = "/change_me"; 2499202Srgrimes 2508549Sjkh ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 25120247Sjkh sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); 25214335Sjkh strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 2538666Sphk ret->newfs = newfs; 2548669Sphk if (!size) 2558669Sphk return ret; 2568549Sjkh return ret; 2578549Sjkh} 2588549Sjkh 2598549Sjkh/* Get the mountpoint for a partition and save it away */ 26012661Speterstatic PartInfo * 2618589Sjkhget_mountpoint(struct chunk *old) 2628549Sjkh{ 2638549Sjkh char *val; 2648549Sjkh PartInfo *tmp; 2658549Sjkh 26614793Sjoerg if (old && old->private_data) 26714793Sjoerg tmp = old->private_data; 2688810Sjkh else 2698810Sjkh tmp = NULL; 27018619Sjkh if (!old) { 27118621Sjkh DialogX = 14; 27218621Sjkh DialogY = 16; 27318619Sjkh } 2748810Sjkh val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 27518619Sjkh DialogX = DialogY = 0; 2768764Sjkh if (!val || !*val) { 2778751Sjkh if (!old) 2788751Sjkh return NULL; 2798751Sjkh else { 28014793Sjoerg free(old->private_data); 28114793Sjoerg old->private_data = NULL; 2828751Sjkh } 2838669Sphk return NULL; 2848751Sjkh } 2858669Sphk 2868669Sphk /* Is it just the same value? */ 2878810Sjkh if (tmp && !strcmp(tmp->mountpoint, val)) 2888669Sphk return NULL; 2898810Sjkh 2908810Sjkh /* Did we use it already? */ 2918669Sphk if (check_conflict(val)) { 2928669Sphk msgConfirm("You already have a mount point for %s assigned!", val); 2938669Sphk return NULL; 2948549Sjkh } 2958810Sjkh 2968810Sjkh /* Is it bogus? */ 2978669Sphk if (*val != '/') { 2988669Sphk msgConfirm("Mount point must start with a / character"); 2998669Sphk return NULL; 3008669Sphk } 3018810Sjkh 3028810Sjkh /* Is it going to be mounted on root? */ 3038669Sphk if (!strcmp(val, "/")) { 3048669Sphk if (old) 3058669Sphk old->flags |= CHUNK_IS_ROOT; 3068810Sjkh } 3078810Sjkh else if (old) 3088669Sphk old->flags &= ~CHUNK_IS_ROOT; 3098810Sjkh 3108810Sjkh safe_free(tmp); 3118669Sphk tmp = new_part(val, TRUE, 0); 3128669Sphk if (old) { 31314793Sjoerg old->private_data = tmp; 3148669Sphk old->private_free = safe_free; 3158669Sphk } 3168669Sphk return tmp; 3178549Sjkh} 3188549Sjkh 3198549Sjkh/* Get the type of the new partiton */ 3208549Sjkhstatic PartType 3218549Sjkhget_partition_type(void) 3228549Sjkh{ 3238549Sjkh char selection[20]; 3248669Sphk int i; 3258669Sphk 3268549Sjkh static unsigned char *fs_types[] = { 3278549Sjkh "FS", 3288549Sjkh "A file system", 3298549Sjkh "Swap", 3308549Sjkh "A swap partition.", 3318549Sjkh }; 33218619Sjkh DialogX = 7; 33318621Sjkh DialogY = 8; 3348669Sphk i = dialog_menu("Please choose a partition type", 33512661Speter "If you want to use this partition for swap space, select Swap.\n" 33612661Speter "If you want to put a filesystem on it, choose FS.", 33712661Speter -1, -1, 2, 2, fs_types, selection, NULL, NULL); 33818619Sjkh DialogX = DialogY = 0; 3398669Sphk if (!i) { 3408549Sjkh if (!strcmp(selection, "FS")) 3418549Sjkh return PART_FILESYSTEM; 3428549Sjkh else if (!strcmp(selection, "Swap")) 3438549Sjkh return PART_SWAP; 3448549Sjkh } 3458549Sjkh return PART_NONE; 3468549Sjkh} 3478549Sjkh 3488549Sjkh/* If the user wants a special newfs command for this, set it */ 3498549Sjkhstatic void 3508549SjkhgetNewfsCmd(PartInfo *p) 3518549Sjkh{ 3528549Sjkh char *val; 3538549Sjkh 3548549Sjkh val = msgGetInput(p->newfs_cmd, 35512661Speter "Please enter the newfs command and options you'd like to use in\n" 35612661Speter "creating this file system."); 3578549Sjkh if (val) 35820247Sjkh sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 3598549Sjkh} 3608549Sjkh 3618549Sjkh#define MAX_MOUNT_NAME 12 3628549Sjkh 3638549Sjkh#define PART_PART_COL 0 3648549Sjkh#define PART_MOUNT_COL 8 3658549Sjkh#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 3668549Sjkh#define PART_NEWFS_COL (PART_SIZE_COL + 7) 3678549Sjkh#define PART_OFF 38 3688549Sjkh 3698549Sjkh/* stick this all up on the screen */ 3708549Sjkhstatic void 3718549Sjkhprint_label_chunks(void) 3728549Sjkh{ 3738549Sjkh int i, j, srow, prow, pcol; 3748549Sjkh int sz; 3758549Sjkh 3768549Sjkh attrset(A_REVERSE); 3778549Sjkh mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 3788549Sjkh attrset(A_NORMAL); 3798549Sjkh 3808549Sjkh for (i = 0; i < 2; i++) { 38115440Sjkh mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 38215440Sjkh mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 3838549Sjkh 38415440Sjkh mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 38515440Sjkh mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 3868549Sjkh 38715440Sjkh mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 38815440Sjkh mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 3898549Sjkh 39015440Sjkh mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 39115440Sjkh mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 3928549Sjkh } 3938549Sjkh srow = CHUNK_SLICE_START_ROW; 39415440Sjkh prow = 0; 3958549Sjkh pcol = 0; 3968549Sjkh 3978751Sjkh for (i = 0; label_chunk_info[i].c; i++) { 3988549Sjkh /* Is it a slice entry displayed at the top? */ 3998549Sjkh if (label_chunk_info[i].type == PART_SLICE) { 4008549Sjkh sz = space_free(label_chunk_info[i].c); 40115440Sjkh if (i == here) 40216208Sjkh attrset(ATTR_SELECTED); 4038751Sjkh mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 4048751Sjkh label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); 40515440Sjkh attrset(A_NORMAL); 40615440Sjkh clrtoeol(); 40715440Sjkh move(0, 0); 40815440Sjkh refresh(); 4098549Sjkh } 41015440Sjkh /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 4118549Sjkh else { 4128549Sjkh char onestr[PART_OFF], num[10], *mountpoint, *newfs; 4138549Sjkh 4148549Sjkh /* 4158549Sjkh * We copy this into a blank-padded string so that it looks like 4168549Sjkh * a solid bar in reverse-video 4178549Sjkh */ 4188549Sjkh memset(onestr, ' ', PART_OFF - 1); 4198549Sjkh onestr[PART_OFF - 1] = '\0'; 42015440Sjkh /* Go for two columns if we've written one full columns worth */ 42115440Sjkh if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) { 4228549Sjkh pcol = PART_OFF; 42315440Sjkh prow = 0; 4248549Sjkh } 4258705Sjkh memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 4268549Sjkh /* If it's a filesystem, display the mountpoint */ 42714793Sjoerg if (label_chunk_info[i].c->private_data 42810882Speter && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 42914793Sjoerg mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 43010882Speter else 43110882Speter mountpoint = "<none>"; 43210882Speter 43310882Speter /* Now display the newfs field */ 43410882Speter if (label_chunk_info[i].type == PART_FAT) 43510882Speter newfs = "DOS"; 43614793Sjoerg else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 43714793Sjoerg newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 43810882Speter else if (label_chunk_info[i].type == PART_SWAP) 43910882Speter newfs = "SWAP"; 44010882Speter else 4418549Sjkh newfs = "*"; 4428549Sjkh for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 4438549Sjkh onestr[PART_MOUNT_COL + j] = mountpoint[j]; 4448764Sjkh snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 4458549Sjkh memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 4468549Sjkh memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 4478549Sjkh onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 44815440Sjkh if (i == here) 44916208Sjkh wattrset(ChunkWin, ATTR_SELECTED); 45015440Sjkh mvwaddstr(ChunkWin, prow, pcol, onestr); 45115440Sjkh wattrset(ChunkWin, A_NORMAL); 45215440Sjkh wrefresh(ChunkWin); 45315440Sjkh move(0, 0); 4548549Sjkh ++prow; 4558549Sjkh } 4568549Sjkh } 4578549Sjkh} 4588549Sjkh 4598549Sjkhstatic void 46018619Sjkhprint_command_summary(void) 4618549Sjkh{ 4628820Sjkh mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 46321971Sjkh mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); 46415440Sjkh if (!RunningAsInit) 46515695Sjkh mvprintw(18, 47, "W = Write"); 46610882Speter mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 46710882Speter mvprintw(20, 0, "A = Auto Defaults for all!"); 46815695Sjkh mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 4698549Sjkh move(0, 0); 4708549Sjkh} 4718549Sjkh 47218619Sjkhstatic void 47318619Sjkhclear_wins(void) 47418619Sjkh{ 47518619Sjkh clear(); 47618619Sjkh wclear(ChunkWin); 47718619Sjkh} 47818619Sjkh 47912661Speterstatic int 48012661SpeterdiskLabel(char *str) 4818549Sjkh{ 48218619Sjkh int sz, key = 0; 4838549Sjkh Boolean labeling; 4848549Sjkh char *msg = NULL; 4859202Srgrimes PartInfo *p, *oldp; 4868549Sjkh PartType type; 4878824Sjkh Device **devs; 4888549Sjkh 48912661Speter devs = deviceFind(NULL, DEVICE_TYPE_DISK); 49012661Speter if (!devs) { 49112661Speter msgConfirm("No disks found!"); 49215242Sjkh return DITEM_FAILURE; 49312661Speter } 49412661Speter 4958549Sjkh labeling = TRUE; 4968549Sjkh keypad(stdscr, TRUE); 49712661Speter record_label_chunks(devs); 4988549Sjkh 49918619Sjkh clear(); 5008549Sjkh while (labeling) { 50118744Sjkh char *cp; 50218744Sjkh 5038549Sjkh print_label_chunks(); 50418619Sjkh print_command_summary(); 5058549Sjkh if (msg) { 50615695Sjkh attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 50712661Speter clrtoeol(); 5088549Sjkh beep(); 5098549Sjkh msg = NULL; 5108549Sjkh } 51115442Sjkh else { 51215442Sjkh move(23, 0); 51315442Sjkh clrtoeol(); 51415442Sjkh } 51518744Sjkh 51618619Sjkh refresh(); 51717397Sjkh key = getch(); 51817397Sjkh switch (toupper(key)) { 51915440Sjkh int i; 52017362Sjkh static char _msg[40]; 5218549Sjkh 5228751Sjkh case '\014': /* ^L */ 52318619Sjkh clear_wins(); 52418619Sjkh break; 5258751Sjkh 52621698Sjkh case '\020': /* ^P */ 5278549Sjkh case KEY_UP: 5288549Sjkh case '-': 5298549Sjkh if (here != 0) 5308549Sjkh --here; 5318751Sjkh else 5328751Sjkh while (label_chunk_info[here + 1].c) 5338751Sjkh ++here; 5348549Sjkh break; 5358549Sjkh 53621698Sjkh case '\016': /* ^N */ 5378549Sjkh case KEY_DOWN: 5388549Sjkh case '+': 5398549Sjkh case '\r': 5408549Sjkh case '\n': 5418751Sjkh if (label_chunk_info[here + 1].c) 5428549Sjkh ++here; 5438751Sjkh else 5448751Sjkh here = 0; 5458549Sjkh break; 5468549Sjkh 5478549Sjkh case KEY_HOME: 5488549Sjkh here = 0; 5498549Sjkh break; 5508549Sjkh 5518549Sjkh case KEY_END: 5528751Sjkh while (label_chunk_info[here + 1].c) 5538549Sjkh ++here; 5548549Sjkh break; 5558549Sjkh 5568549Sjkh case KEY_F(1): 5578549Sjkh case '?': 55812661Speter systemDisplayHelp("partition"); 55918619Sjkh clear_wins(); 5608549Sjkh break; 5618549Sjkh 56210882Speter case 'A': 56310882Speter if (label_chunk_info[here].type != PART_SLICE) { 56415440Sjkh msg = "You can only do this in a disk slice (at top of screen)"; 56510882Speter break; 56610882Speter } 56710882Speter sz = space_free(label_chunk_info[here].c); 56817362Sjkh if (sz <= FS_MIN_SIZE) 56915440Sjkh msg = "Not enough free space to create a new partition in the slice"; 57015440Sjkh else { 57115440Sjkh struct chunk *tmp; 57215440Sjkh int mib[2]; 57315440Sjkh int physmem; 57415440Sjkh size_t size, swsize; 57515440Sjkh char *cp; 57617362Sjkh Chunk *rootdev, *swapdev, *usrdev, *vardev; 57712661Speter 57817368Sjkh (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 57917362Sjkh if (!rootdev) { 58017362Sjkh cp = variable_get(VAR_ROOT_SIZE); 58117362Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 58217362Sjkh (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 58317362Sjkh if (!tmp) { 58417362Sjkh msgConfirm("Unable to create the root partition. Too big?"); 58518619Sjkh clear_wins(); 58617362Sjkh break; 58717362Sjkh } 58817362Sjkh tmp->private_data = new_part("/", TRUE, tmp->size); 58917362Sjkh tmp->private_free = safe_free; 59017362Sjkh record_label_chunks(devs); 59115440Sjkh } 59217362Sjkh 59317362Sjkh if (!swapdev) { 59417362Sjkh cp = variable_get(VAR_SWAP_SIZE); 59517362Sjkh if (cp) 59617362Sjkh swsize = atoi(cp) * ONE_MEG; 59717362Sjkh else { 59817362Sjkh mib[0] = CTL_HW; 59917362Sjkh mib[1] = HW_PHYSMEM; 60017362Sjkh size = sizeof physmem; 60117362Sjkh sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 60217362Sjkh swsize = 16 * ONE_MEG + (physmem * 2 / 512); 60317362Sjkh } 60417362Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 60517362Sjkh swsize, part, FS_SWAP, 0); 60617362Sjkh if (!tmp) { 60717362Sjkh msgConfirm("Unable to create the swap partition. Too big?"); 60818619Sjkh clear_wins(); 60917362Sjkh break; 61017362Sjkh } 61117362Sjkh tmp->private_data = 0; 61217362Sjkh tmp->private_free = safe_free; 61317362Sjkh record_label_chunks(devs); 61415440Sjkh } 61517362Sjkh 61617362Sjkh if (!vardev) { 61717362Sjkh cp = variable_get(VAR_VAR_SIZE); 61817362Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 61917362Sjkh (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 62017362Sjkh if (!tmp) { 62117362Sjkh msgConfirm("Less than %dMB free for /var - you will need to\n" 62217362Sjkh "partition your disk manually with a custom install!", 62317362Sjkh (cp ? atoi(cp) : VAR_MIN_SIZE)); 62418619Sjkh clear_wins(); 62517362Sjkh break; 62617362Sjkh } 62717362Sjkh tmp->private_data = new_part("/var", TRUE, tmp->size); 62817362Sjkh tmp->private_free = safe_free; 62917362Sjkh record_label_chunks(devs); 63015440Sjkh } 63112661Speter 63217362Sjkh if (!usrdev) { 63317362Sjkh cp = variable_get(VAR_USR_SIZE); 63417362Sjkh if (cp) 63517362Sjkh sz = atoi(cp) * ONE_MEG; 63617362Sjkh else 63717362Sjkh sz = space_free(label_chunk_info[here].c); 63817362Sjkh if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) { 63917362Sjkh msgConfirm("Less than %dMB free for /usr - you will need to\n" 64017362Sjkh "partition your disk manually with a custom install!", USR_MIN_SIZE); 64118619Sjkh clear_wins(); 64217362Sjkh break; 64317362Sjkh } 64417362Sjkh 64517362Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 64617362Sjkh label_chunk_info[here].c, 64717362Sjkh sz, part, FS_BSDFFS, 0); 64817362Sjkh if (!tmp) { 64917362Sjkh msgConfirm("Unable to create the /usr partition. Not enough space?\n" 65017362Sjkh "You will need to partition your disk manually with a custom install!"); 65118619Sjkh clear_wins(); 65217362Sjkh break; 65317362Sjkh } 65417362Sjkh tmp->private_data = new_part("/usr", TRUE, tmp->size); 65517362Sjkh tmp->private_free = safe_free; 65617362Sjkh record_label_chunks(devs); 65715440Sjkh } 65815440Sjkh /* At this point, we're reasonably "labelled" */ 65918744Sjkh if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 66018744Sjkh variable_set2(DISK_LABELLED, "yes"); 66110882Speter } 66215440Sjkh break; 66310882Speter 6648549Sjkh case 'C': 6658549Sjkh if (label_chunk_info[here].type != PART_SLICE) { 6668549Sjkh msg = "You can only do this in a master partition (see top of screen)"; 6678549Sjkh break; 6688549Sjkh } 6698549Sjkh sz = space_free(label_chunk_info[here].c); 6708669Sphk if (sz <= FS_MIN_SIZE) { 67112661Speter msg = "Not enough space to create an additional FreeBSD partition"; 6728669Sphk break; 6738669Sphk } 67415440Sjkh else { 67518744Sjkh char *val; 6768702Sjkh int size; 6778702Sjkh struct chunk *tmp; 6788820Sjkh char osize[80]; 6798702Sjkh u_long flags = 0; 6808549Sjkh 6818820Sjkh sprintf(osize, "%d", sz); 68218619Sjkh DialogX = 3; 68318621Sjkh DialogY = 2; 68418619Sjkh val = msgGetInput(osize, 68518619Sjkh "Please specify the partition size in blocks or append a trailing M for\n" 68618619Sjkh "megabytes or C for cylinders. %d blocks (%dMB) are free.", 68718619Sjkh sz, sz / ONE_MEG); 68818619Sjkh DialogX = DialogY = 0; 68918619Sjkh if (!val || (size = strtol(val, &cp, 0)) <= 0) { 69018619Sjkh clear_wins(); 6918702Sjkh break; 69218619Sjkh } 6938549Sjkh 6948751Sjkh if (*cp) { 6958751Sjkh if (toupper(*cp) == 'M') 6968751Sjkh size *= ONE_MEG; 6978751Sjkh else if (toupper(*cp) == 'C') 6988751Sjkh size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 6998751Sjkh } 7008820Sjkh if (size <= FS_MIN_SIZE) { 7018820Sjkh msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 70218619Sjkh clear_wins(); 7038820Sjkh break; 7048820Sjkh } 7058702Sjkh type = get_partition_type(); 70618619Sjkh if (type == PART_NONE) { 70718619Sjkh clear_wins(); 70818619Sjkh beep(); 7098669Sphk break; 71018619Sjkh } 7118669Sphk 7128702Sjkh if (type == PART_FILESYSTEM) { 71318619Sjkh if ((p = get_mountpoint(NULL)) == NULL) { 71418619Sjkh clear_wins(); 71518619Sjkh beep(); 7168702Sjkh break; 71718619Sjkh } 7188702Sjkh else if (!strcmp(p->mountpoint, "/")) 7198702Sjkh flags |= CHUNK_IS_ROOT; 7208702Sjkh else 7218702Sjkh flags &= ~CHUNK_IS_ROOT; 72218619Sjkh } 72318619Sjkh else 7248702Sjkh p = NULL; 7258702Sjkh 7268702Sjkh if ((flags & CHUNK_IS_ROOT)) { 7278702Sjkh if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 72812661Speter msgConfirm("This region cannot be used for your root partition as the\n" 72912661Speter "FreeBSD boot code cannot deal with a root partition created\n" 73012661Speter "in that location. Please choose another location or smaller\n" 73112661Speter "size for your root partition and try again!"); 73218619Sjkh clear_wins(); 7338702Sjkh break; 7348702Sjkh } 73512661Speter if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 73612661Speter msgConfirm("Warning: This is smaller than the recommended size for a\n" 73712661Speter "root partition. For a variety of reasons, root\n" 73812661Speter "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 73912661Speter } 7408672Sjkh } 7418751Sjkh tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 7428702Sjkh label_chunk_info[here].c, 7438702Sjkh size, part, 7448702Sjkh (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 7458702Sjkh flags); 7468702Sjkh if (!tmp) { 7478702Sjkh msgConfirm("Unable to create the partition. Too big?"); 74818619Sjkh clear_wins(); 7498672Sjkh break; 7508672Sjkh } 7518702Sjkh if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 75212661Speter msgConfirm("This region cannot be used for your root partition as it starts\n" 75312661Speter "or extends past the 1024'th cylinder mark and is thus a\n" 75412661Speter "poor location to boot from. Please choose another\n" 75512661Speter "location (or smaller size) for your root partition and try again!"); 7568751Sjkh Delete_Chunk(label_chunk_info[here].c->disk, tmp); 75718619Sjkh clear_wins(); 7588669Sphk break; 7598702Sjkh } 7608702Sjkh if (type != PART_SWAP) { 7618669Sphk /* This is needed to tell the newfs -u about the size */ 76214793Sjoerg tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 7638669Sphk safe_free(p); 76415355Sjkh } 76515355Sjkh else 76614793Sjoerg tmp->private_data = p; 7678702Sjkh tmp->private_free = safe_free; 76818744Sjkh if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 76918744Sjkh variable_set2(DISK_LABELLED, "yes"); 77012661Speter record_label_chunks(devs); 77118619Sjkh clear_wins(); 7728549Sjkh } 7738549Sjkh break; 7748549Sjkh 77517397Sjkh case KEY_DC: 7768549Sjkh case 'D': /* delete */ 7778549Sjkh if (label_chunk_info[here].type == PART_SLICE) { 7788549Sjkh msg = MSG_NOT_APPLICABLE; 7798549Sjkh break; 7808549Sjkh } 7818549Sjkh else if (label_chunk_info[here].type == PART_FAT) { 7828705Sjkh msg = "Use the Disk Partition Editor to delete DOS partitions"; 7838549Sjkh break; 7848549Sjkh } 7858751Sjkh Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 78618744Sjkh if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 78718744Sjkh variable_set2(DISK_LABELLED, "yes"); 78812661Speter record_label_chunks(devs); 7898549Sjkh break; 7908549Sjkh 7918549Sjkh case 'M': /* mount */ 7928549Sjkh switch(label_chunk_info[here].type) { 7938549Sjkh case PART_SLICE: 7948549Sjkh msg = MSG_NOT_APPLICABLE; 7958549Sjkh break; 7968549Sjkh 7978549Sjkh case PART_SWAP: 7988549Sjkh msg = "You don't need to specify a mountpoint for a swap partition."; 7998549Sjkh break; 8008549Sjkh 8018556Sjkh case PART_FAT: 8028549Sjkh case PART_FILESYSTEM: 80314793Sjoerg oldp = label_chunk_info[here].c->private_data; 8048589Sjkh p = get_mountpoint(label_chunk_info[here].c); 8058549Sjkh if (p) { 8069202Srgrimes if (!oldp) 8079202Srgrimes p->newfs = FALSE; 8088722Sjkh if (label_chunk_info[here].type == PART_FAT 8098722Sjkh && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 8108722Sjkh || !strcmp(p->mountpoint, "/var"))) { 8118722Sjkh msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 8128722Sjkh strcpy(p->mountpoint, "/bogus"); 8138722Sjkh } 8148549Sjkh } 81518744Sjkh if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 81618744Sjkh variable_set2(DISK_LABELLED, "yes"); 81712661Speter record_label_chunks(devs); 81818636Sjkh clear_wins(); 8198549Sjkh break; 8208549Sjkh 8218549Sjkh default: 8228549Sjkh msgFatal("Bogus partition under cursor???"); 8238549Sjkh break; 8248549Sjkh } 8258549Sjkh break; 8268549Sjkh 8278549Sjkh case 'N': /* Set newfs options */ 82814793Sjoerg if (label_chunk_info[here].c->private_data && 82914793Sjoerg ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 83014793Sjoerg getNewfsCmd(label_chunk_info[here].c->private_data); 8318549Sjkh else 8328549Sjkh msg = MSG_NOT_APPLICABLE; 83318636Sjkh clear_wins(); 8348549Sjkh break; 8358549Sjkh 8368549Sjkh case 'T': /* Toggle newfs state */ 8379202Srgrimes if (label_chunk_info[here].type == PART_FILESYSTEM) { 83814793Sjoerg PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 83915355Sjkh label_chunk_info[here].c->private_data = 84015355Sjkh new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 8418669Sphk safe_free(pi); 8428820Sjkh label_chunk_info[here].c->private_free = safe_free; 84318744Sjkh if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 84418744Sjkh variable_set2(DISK_LABELLED, "yes"); 84518619Sjkh } 8468549Sjkh else 8478549Sjkh msg = MSG_NOT_APPLICABLE; 8488549Sjkh break; 8498549Sjkh 8508820Sjkh case 'U': 85112661Speter clear(); 85218744Sjkh if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 85318744Sjkh msgConfirm("You've already written out your changes -\n" 85418744Sjkh "it's too late to undo!"); 85518744Sjkh } 85618744Sjkh else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 85718744Sjkh variable_unset(DISK_PARTITIONED); 85818744Sjkh variable_unset(DISK_LABELLED); 85918744Sjkh for (i = 0; devs[i]; i++) { 86018744Sjkh Disk *d; 86112661Speter 86218744Sjkh if (!devs[i]->enabled) 86318744Sjkh continue; 86418744Sjkh else if ((d = Open_Disk(devs[i]->name)) != NULL) { 86518744Sjkh Free_Disk(devs[i]->private); 86618744Sjkh devs[i]->private = d; 86718744Sjkh diskPartition(devs[i], d); 86818744Sjkh } 8698824Sjkh } 87018744Sjkh record_label_chunks(devs); 8718824Sjkh } 87218636Sjkh clear_wins(); 8738824Sjkh break; 8748820Sjkh 8758549Sjkh case 'W': 87618744Sjkh if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 87718744Sjkh msgConfirm("You've already written out your changes - if you\n" 87818744Sjkh "wish to overwrite them, you'll have to start this\n" 87918744Sjkh "procedure again from the beginning."); 88018744Sjkh } 88118744Sjkh else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 88218687Sjkh "installation. If you are installing FreeBSD for the first time\n" 88318687Sjkh "then you should simply type Q when you're finished here and your\n" 88418687Sjkh "changes will be committed in one batch automatically at the end of\n" 88518687Sjkh "these questions.\n\n" 88618687Sjkh "Are you absolutely sure you want to do this now?")) { 88712661Speter variable_set2(DISK_LABELLED, "yes"); 88812661Speter diskLabelCommit(NULL); 88912661Speter } 89018636Sjkh clear_wins(); 89110882Speter break; 89210882Speter 89310882Speter case '|': 89412661Speter if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 89512661Speter "This is an entirely undocumented feature which you are not\n" 89612661Speter "expected to understand!")) { 8978549Sjkh int i; 8988549Sjkh Device **devs; 8998549Sjkh 9008549Sjkh dialog_clear(); 9018549Sjkh end_dialog(); 9028549Sjkh DialogActive = FALSE; 9038549Sjkh devs = deviceFind(NULL, DEVICE_TYPE_DISK); 9048549Sjkh if (!devs) { 90512661Speter msgConfirm("Can't find any disk devices!"); 9068549Sjkh break; 9078549Sjkh } 9088668Sphk for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 9098613Sjkh if (devs[i]->enabled) 9108613Sjkh slice_wizard(((Disk *)devs[i]->private)); 9118613Sjkh } 91218744Sjkh if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 91318744Sjkh variable_set2(DISK_LABELLED, "yes"); 9148665Sphk DialogActive = TRUE; 91512661Speter record_label_chunks(devs); 91618636Sjkh clear_wins(); 9178549Sjkh } 9188549Sjkh else 9198549Sjkh msg = "A most prudent choice!"; 9208549Sjkh break; 9218549Sjkh 92221698Sjkh case '\033': /* ESC */ 9239202Srgrimes case 'Q': 9248549Sjkh labeling = FALSE; 9258549Sjkh break; 9268549Sjkh 9278549Sjkh default: 9288549Sjkh beep(); 92917362Sjkh sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 93017362Sjkh msg = _msg; 9318549Sjkh break; 9328549Sjkh } 9338549Sjkh } 93417362Sjkh return DITEM_SUCCESS | DITEM_RESTORE; 9358549Sjkh} 936