label.c revision 21673
1238106Sdes/* 2238106Sdes * The new sysinstall program. 3238106Sdes * 4238106Sdes * This is probably the last program in the `sysinstall' line - the next 5238106Sdes * generation being essentially a complete rewrite. 6238106Sdes * 7238106Sdes * $FreeBSD: head/usr.sbin/sade/label.c 21673 1997-01-14 07:20:47Z jkh $ 8238106Sdes * 9238106Sdes * Copyright (c) 1995 10238106Sdes * Jordan Hubbard. All rights reserved. 11238106Sdes * 12238106Sdes * Redistribution and use in source and binary forms, with or without 13238106Sdes * modification, are permitted provided that the following conditions 14238106Sdes * are met: 15238106Sdes * 1. Redistributions of source code must retain the above copyright 16238106Sdes * notice, this list of conditions and the following disclaimer, 17238106Sdes * verbatim and that no modifications are made prior to this 18238106Sdes * point in the file. 19238106Sdes * 2. Redistributions in binary form must reproduce the above copyright 20238106Sdes * notice, this list of conditions and the following disclaimer in the 21238106Sdes * documentation and/or other materials provided with the distribution. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 24285206Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25285206Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26238106Sdes * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 27238106Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28291767Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29238106Sdes * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30238106Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31238106Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32238106Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33238106Sdes * SUCH DAMAGE. 34269257Sdes * 35269257Sdes */ 36269257Sdes 37269257Sdes#include "sysinstall.h" 38269257Sdes#include <ctype.h> 39249141Sdes#include <sys/disklabel.h> 40269257Sdes#include <sys/param.h> 41294190Sdes#include <sys/sysctl.h> 42238106Sdes 43238106Sdes/* 44238106Sdes * Everything to do with editing the contents of disk labels. 45238106Sdes */ 46238106Sdes 47238106Sdes/* A nice message we use a lot in the disklabel editor */ 48238106Sdes#define MSG_NOT_APPLICABLE "That option is not applicable here" 49238106Sdes 50285206Sdes/* Where to start printing the freebsd slices */ 51238106Sdes#define CHUNK_SLICE_START_ROW 2 52238106Sdes#define CHUNK_PART_START_ROW 11 53238106Sdes 54238106Sdes/* The smallest filesystem we're willing to create */ 55238106Sdes#define FS_MIN_SIZE ONE_MEG 56238106Sdes 57238106Sdes/* The smallest root filesystem we're willing to create */ 58238106Sdes#define ROOT_MIN_SIZE 20 59238106Sdes 60238106Sdes/* The smallest swap partition we want to create by default */ 61238106Sdes#define SWAP_MIN_SIZE 16 62238106Sdes 63285206Sdes/* The smallest /usr partition we're willing to create by default */ 64238106Sdes#define USR_MIN_SIZE 80 65238106Sdes 66238106Sdes/* The smallest /var partition we're willing to create by default */ 67238106Sdes#define VAR_MIN_SIZE 30 68238106Sdes 69238106Sdes/* The bottom-most row we're allowed to scribble on */ 70238106Sdes#define CHUNK_ROW_MAX 16 71238106Sdes 72238106Sdes 73238106Sdes/* All the chunks currently displayed on the screen */ 74269257Sdesstatic struct { 75238106Sdes struct chunk *c; 76238106Sdes PartType type; 77285206Sdes} label_chunk_info[MAX_CHUNKS + 1]; 78238106Sdesstatic int here; 79238106Sdes 80238106Sdesstatic int ChunkPartStartRow; 81238106Sdesstatic WINDOW *ChunkWin; 82269257Sdes 83285206Sdesstatic int diskLabel(char *str); 84238106Sdes 85285206Sdesint 86238106SdesdiskLabelEditor(dialogMenuItem *self) 87238106Sdes{ 88238106Sdes Device **devs; 89238106Sdes int i, cnt, enabled; 90238106Sdes char *cp; 91238106Sdes 92238106Sdes cp = variable_get(VAR_DISK); 93238106Sdes devs = deviceFind(cp, DEVICE_TYPE_DISK); 94238106Sdes cnt = deviceCount(devs); 95238106Sdes if (!cnt) { 96238106Sdes msgConfirm("No disks found! Please verify that your disk controller is being\n" 97238106Sdes "properly probed at boot time. See the Hardware Guide on the\n" 98295691Sdes "Documentation menu for clues on diagnosing this type of problem."); 99238106Sdes return DITEM_FAILURE; 100238106Sdes } 101238106Sdes for (i = 0, enabled = 0; i < cnt; i++) { 102238106Sdes if (devs[i]->enabled) 103238106Sdes ++enabled; 104238106Sdes } 105238106Sdes if (!enabled) { 106238106Sdes msgConfirm("No disks have been selected. Please visit the Partition\n" 107238106Sdes "editor first to specify which disks you wish to operate on."); 108238106Sdes return DITEM_FAILURE; 109238106Sdes } 110238106Sdes i = diskLabel(devs[0]->name); 111238106Sdes if (DITEM_STATUS(i) != DITEM_FAILURE) { 112238106Sdes char *cp; 113249141Sdes 114285206Sdes if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 115238106Sdes variable_set2(DISK_LABELLED, "yes"); 116295691Sdes } 117238106Sdes return i; 118238106Sdes} 119238106Sdes 120238106Sdesint 121238106SdesdiskLabelCommit(dialogMenuItem *self) 122238106Sdes{ 123238106Sdes char *cp; 124285206Sdes int i; 125285206Sdes 126238106Sdes /* Already done? */ 127238106Sdes if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) 128238106Sdes i = DITEM_SUCCESS; 129238106Sdes else if (!cp) { 130238106Sdes msgConfirm("You must assign disk labels before this option can be used."); 131238106Sdes i = DITEM_FAILURE; 132269257Sdes } 133285206Sdes /* The routine will guard against redundant writes, just as this one does */ 134285206Sdes else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) 135285206Sdes i = DITEM_FAILURE; 136294190Sdes else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) 137238106Sdes i = DITEM_FAILURE; 138238106Sdes else { 139285206Sdes msgInfo("All filesystem information written successfully."); 140291767Sdes variable_set2(DISK_LABELLED, "written"); 141291767Sdes i = DITEM_SUCCESS; 142269257Sdes } 143269257Sdes return i; 144238106Sdes} 145238106Sdes 146238106Sdes/* See if we're already using a desired partition name */ 147269257Sdesstatic Boolean 148238106Sdescheck_conflict(char *name) 149238106Sdes{ 150269257Sdes int i; 151269257Sdes 152269257Sdes for (i = 0; label_chunk_info[i].c; i++) 153238106Sdes if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private_data 154238106Sdes && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 155238106Sdes return TRUE; 156238106Sdes return FALSE; 157269257Sdes} 158238106Sdes 159238106Sdes/* How much space is in this FreeBSD slice? */ 160238106Sdesstatic int 161269257Sdesspace_free(struct chunk *c) 162238106Sdes{ 163238106Sdes struct chunk *c1; 164238106Sdes int sz = c->size; 165238106Sdes 166269257Sdes for (c1 = c->part; c1; c1 = c1->next) { 167238106Sdes if (c1->type != unused) 168238106Sdes sz -= c1->size; 169285206Sdes } 170238106Sdes if (sz < 0) 171238106Sdes msgFatal("Partitions are larger than actual chunk??"); 172291767Sdes return sz; 173238106Sdes} 174269257Sdes 175238106Sdes/* Snapshot the current situation into the displayed chunks structure */ 176238106Sdesstatic void 177238106Sdesrecord_label_chunks(Device **devs) 178269257Sdes{ 179269257Sdes int i, j, p; 180238106Sdes struct chunk *c1, *c2; 181238106Sdes Disk *d; 182269257Sdes 183269257Sdes ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3; 184238106Sdes j = p = 0; 185238106Sdes /* First buzz through and pick up the FreeBSD slices */ 186285206Sdes for (i = 0; devs[i]; i++) { 187238106Sdes if (!devs[i]->enabled) 188238106Sdes continue; 189238106Sdes d = (Disk *)devs[i]->private; 190269257Sdes if (!d->chunks) 191238106Sdes msgFatal("No chunk list found for %s!", d->name); 192238106Sdes 193269257Sdes /* Put the slice entries first */ 194269257Sdes for (c1 = d->chunks->part; c1; c1 = c1->next) { 195238106Sdes if (c1->type == freebsd) { 196238106Sdes label_chunk_info[j].type = PART_SLICE; 197238106Sdes label_chunk_info[j].c = c1; 198238106Sdes ++j; 199238106Sdes ++ChunkPartStartRow; 200269257Sdes } 201269257Sdes } 202238106Sdes } 203238106Sdes 204269257Sdes /* Now run through again and get the FreeBSD partition entries */ 205238106Sdes for (i = 0; devs[i]; i++) { 206238106Sdes if (!devs[i]->enabled) 207269257Sdes continue; 208269257Sdes d = (Disk *)devs[i]->private; 209238106Sdes /* Then buzz through and pick up the partitions */ 210238106Sdes for (c1 = d->chunks->part; c1; c1 = c1->next) { 211238106Sdes if (c1->type == freebsd) { 212269257Sdes for (c2 = c1->part; c2; c2 = c2->next) { 213238106Sdes if (c2->type == part) { 214238106Sdes if (c2->subtype == FS_SWAP) 215238106Sdes label_chunk_info[j].type = PART_SWAP; 216238106Sdes else 217238106Sdes label_chunk_info[j].type = PART_FILESYSTEM; 218238106Sdes label_chunk_info[j].c = c2; 219238106Sdes ++j; 220238106Sdes } 221238106Sdes } 222238106Sdes } 223238106Sdes else if (c1->type == fat) { 224238106Sdes label_chunk_info[j].type = PART_FAT; 225238106Sdes label_chunk_info[j].c = c1; 226238106Sdes ++j; 227238106Sdes } 228238106Sdes } 229238106Sdes } 230238106Sdes label_chunk_info[j].c = NULL; 231238106Sdes if (here >= j) 232269257Sdes here = j ? j - 1 : 0; 233238106Sdes if (ChunkWin) { 234238106Sdes wclear(ChunkWin); 235269257Sdes wrefresh(ChunkWin); 236238106Sdes } 237269257Sdes else 238238106Sdes ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); 239269257Sdes} 240238106Sdes 241238106Sdes/* A new partition entry */ 242269257Sdesstatic PartInfo * 243238106Sdesnew_part(char *mpoint, Boolean newfs, u_long size) 244269257Sdes{ 245238106Sdes PartInfo *ret; 246238106Sdes 247238106Sdes if (!mpoint) 248238106Sdes mpoint = "/change_me"; 249238106Sdes 250249141Sdes ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 251238106Sdes sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); 252249141Sdes strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 253238106Sdes ret->newfs = newfs; 254249141Sdes if (!size) 255249141Sdes return ret; 256238106Sdes return ret; 257238106Sdes} 258238106Sdes 259238106Sdes/* Get the mountpoint for a partition and save it away */ 260238106Sdesstatic PartInfo * 261238106Sdesget_mountpoint(struct chunk *old) 262238106Sdes{ 263238106Sdes char *val; 264238106Sdes PartInfo *tmp; 265238106Sdes 266238106Sdes if (old && old->private_data) 267238106Sdes tmp = old->private_data; 268238106Sdes else 269238106Sdes tmp = NULL; 270238106Sdes if (!old) { 271238106Sdes DialogX = 14; 272238106Sdes DialogY = 16; 273238106Sdes } 274238106Sdes val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 275238106Sdes DialogX = DialogY = 0; 276238106Sdes if (!val || !*val) { 277238106Sdes if (!old) 278269257Sdes return NULL; 279238106Sdes else { 280269257Sdes free(old->private_data); 281238106Sdes old->private_data = NULL; 282238106Sdes } 283238106Sdes return NULL; 284238106Sdes } 285238106Sdes 286238106Sdes /* Is it just the same value? */ 287238106Sdes if (tmp && !strcmp(tmp->mountpoint, val)) 288238106Sdes return NULL; 289238106Sdes 290238106Sdes /* Did we use it already? */ 291238106Sdes if (check_conflict(val)) { 292238106Sdes msgConfirm("You already have a mount point for %s assigned!", val); 293238106Sdes return NULL; 294238106Sdes } 295238106Sdes 296269257Sdes /* Is it bogus? */ 297238106Sdes if (*val != '/') { 298238106Sdes msgConfirm("Mount point must start with a / character"); 299294190Sdes return NULL; 300238106Sdes } 301238106Sdes 302294190Sdes /* Is it going to be mounted on root? */ 303238106Sdes if (!strcmp(val, "/")) { 304238106Sdes if (old) 305294190Sdes old->flags |= CHUNK_IS_ROOT; 306238106Sdes } 307238106Sdes else if (old) 308294190Sdes old->flags &= ~CHUNK_IS_ROOT; 309238106Sdes 310238106Sdes safe_free(tmp); 311238106Sdes tmp = new_part(val, TRUE, 0); 312238106Sdes if (old) { 313238106Sdes old->private_data = tmp; 314294190Sdes old->private_free = safe_free; 315238106Sdes } 316238106Sdes return tmp; 317238106Sdes} 318238106Sdes 319238106Sdes/* Get the type of the new partiton */ 320238106Sdesstatic PartType 321238106Sdesget_partition_type(void) 322238106Sdes{ 323238106Sdes char selection[20]; 324238106Sdes int i; 325238106Sdes 326294190Sdes static unsigned char *fs_types[] = { 327238106Sdes "FS", 328238106Sdes "A file system", 329294190Sdes "Swap", 330238106Sdes "A swap partition.", 331238106Sdes }; 332294190Sdes DialogX = 7; 333238106Sdes DialogY = 8; 334238106Sdes i = dialog_menu("Please choose a partition type", 335294190Sdes "If you want to use this partition for swap space, select Swap.\n" 336238106Sdes "If you want to put a filesystem on it, choose FS.", 337238106Sdes -1, -1, 2, 2, fs_types, selection, NULL, NULL); 338294190Sdes DialogX = DialogY = 0; 339238106Sdes if (!i) { 340238106Sdes if (!strcmp(selection, "FS")) 341294190Sdes return PART_FILESYSTEM; 342238106Sdes else if (!strcmp(selection, "Swap")) 343238106Sdes return PART_SWAP; 344238106Sdes } 345238106Sdes return PART_NONE; 346238106Sdes} 347294190Sdes 348238106Sdes/* If the user wants a special newfs command for this, set it */ 349238106Sdesstatic void 350294190SdesgetNewfsCmd(PartInfo *p) 351238106Sdes{ 352238106Sdes char *val; 353294190Sdes 354238106Sdes val = msgGetInput(p->newfs_cmd, 355269257Sdes "Please enter the newfs command and options you'd like to use in\n" 356294190Sdes "creating this file system."); 357238106Sdes if (val) 358269257Sdes sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 359269257Sdes} 360269257Sdes 361285206Sdes#define MAX_MOUNT_NAME 12 362285206Sdes 363238106Sdes#define PART_PART_COL 0 364238106Sdes#define PART_MOUNT_COL 8 365285206Sdes#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 366285206Sdes#define PART_NEWFS_COL (PART_SIZE_COL + 7) 367285206Sdes#define PART_OFF 38 368285206Sdes 369285206Sdes/* stick this all up on the screen */ 370285206Sdesstatic void 371285206Sdesprint_label_chunks(void) 372285206Sdes{ 373285206Sdes int i, j, srow, prow, pcol; 374285206Sdes int sz; 375285206Sdes 376285206Sdes attrset(A_REVERSE); 377238106Sdes mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 378238106Sdes attrset(A_NORMAL); 379238106Sdes 380238106Sdes for (i = 0; i < 2; i++) { 381238106Sdes mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); 382238106Sdes mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); 383238106Sdes 384238106Sdes mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 385238106Sdes mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 386238106Sdes 387238106Sdes mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 388238106Sdes mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 389238106Sdes 390249141Sdes mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 391238106Sdes mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 392238106Sdes } 393238106Sdes srow = CHUNK_SLICE_START_ROW; 394238106Sdes prow = 0; 395269257Sdes pcol = 0; 396269257Sdes 397238106Sdes for (i = 0; label_chunk_info[i].c; i++) { 398291767Sdes /* Is it a slice entry displayed at the top? */ 399238106Sdes if (label_chunk_info[i].type == PART_SLICE) { 400238106Sdes sz = space_free(label_chunk_info[i].c); 401238106Sdes if (i == here) 402285206Sdes attrset(ATTR_SELECTED); 403238106Sdes mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 404238106Sdes label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); 405238106Sdes attrset(A_NORMAL); 406238106Sdes clrtoeol(); 407238106Sdes move(0, 0); 408238106Sdes refresh(); 409238106Sdes } 410238106Sdes /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ 411238106Sdes else { 412238106Sdes char onestr[PART_OFF], num[10], *mountpoint, *newfs; 413238106Sdes 414238106Sdes /* 415238106Sdes * We copy this into a blank-padded string so that it looks like 416238106Sdes * a solid bar in reverse-video 417238106Sdes */ 418238106Sdes memset(onestr, ' ', PART_OFF - 1); 419269257Sdes onestr[PART_OFF - 1] = '\0'; 420238106Sdes /* Go for two columns if we've written one full columns worth */ 421249141Sdes if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) { 422238106Sdes pcol = PART_OFF; 423238106Sdes prow = 0; 424238106Sdes } 425238106Sdes memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 426238106Sdes /* If it's a filesystem, display the mountpoint */ 427238106Sdes if (label_chunk_info[i].c->private_data 428249141Sdes && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 429238106Sdes mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 430238106Sdes else 431238106Sdes mountpoint = "<none>"; 432238106Sdes 433238106Sdes /* Now display the newfs field */ 434269257Sdes if (label_chunk_info[i].type == PART_FAT) 435238106Sdes newfs = "DOS"; 436238106Sdes else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 437285206Sdes newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 438238106Sdes else if (label_chunk_info[i].type == PART_SWAP) 439238106Sdes newfs = "SWAP"; 440238106Sdes else 441238106Sdes newfs = "*"; 442238106Sdes for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 443238106Sdes onestr[PART_MOUNT_COL + j] = mountpoint[j]; 444238106Sdes snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 445238106Sdes memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 446238106Sdes memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 447238106Sdes onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 448238106Sdes if (i == here) 449238106Sdes wattrset(ChunkWin, ATTR_SELECTED); 450238106Sdes mvwaddstr(ChunkWin, prow, pcol, onestr); 451238106Sdes wattrset(ChunkWin, A_NORMAL); 452238106Sdes wrefresh(ChunkWin); 453238106Sdes move(0, 0); 454238106Sdes ++prow; 455238106Sdes } 456238106Sdes } 457238106Sdes} 458238106Sdes 459238106Sdesstatic void 460238106Sdesprint_command_summary(void) 461238106Sdes{ 462238106Sdes mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 463238106Sdes mvprintw(18, 0, "C = Create D = Delete M = Mount"); 464285206Sdes if (!RunningAsInit) 465285206Sdes mvprintw(18, 47, "W = Write"); 466238106Sdes mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 467238106Sdes mvprintw(20, 0, "A = Auto Defaults for all!"); 468238106Sdes mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); 469238106Sdes move(0, 0); 470238106Sdes} 471238106Sdes 472238106Sdesstatic void 473249141Sdesclear_wins(void) 474238106Sdes{ 475238106Sdes clear(); 476238106Sdes wclear(ChunkWin); 477269257Sdes} 478269257Sdes 479269257Sdesstatic int 480269257SdesdiskLabel(char *str) 481269257Sdes{ 482269257Sdes int sz, key = 0; 483269257Sdes Boolean labeling; 484269257Sdes char *msg = NULL; 485269257Sdes PartInfo *p, *oldp; 486269257Sdes PartType type; 487269257Sdes Device **devs; 488269257Sdes 489269257Sdes devs = deviceFind(NULL, DEVICE_TYPE_DISK); 490269257Sdes if (!devs) { 491269257Sdes msgConfirm("No disks found!"); 492269257Sdes return DITEM_FAILURE; 493269257Sdes } 494269257Sdes 495269257Sdes labeling = TRUE; 496269257Sdes keypad(stdscr, TRUE); 497269257Sdes record_label_chunks(devs); 498269257Sdes 499269257Sdes clear(); 500269257Sdes while (labeling) { 501269257Sdes char *cp; 502269257Sdes 503269257Sdes print_label_chunks(); 504238106Sdes print_command_summary(); 505238106Sdes if (msg) { 506238106Sdes attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); 507238106Sdes clrtoeol(); 508238106Sdes beep(); 509238106Sdes msg = NULL; 510238106Sdes } 511238106Sdes else { 512238106Sdes move(23, 0); 513238106Sdes clrtoeol(); 514238106Sdes } 515238106Sdes 516238106Sdes refresh(); 517269257Sdes key = getch(); 518238106Sdes switch (toupper(key)) { 519238106Sdes int i; 520285206Sdes static char _msg[40]; 521238106Sdes 522238106Sdes case '\014': /* ^L */ 523238106Sdes clear_wins(); 524238106Sdes break; 525238106Sdes 526238106Sdes case KEY_UP: 527238106Sdes case '-': 528238106Sdes if (here != 0) 529238106Sdes --here; 530238106Sdes else 531269257Sdes while (label_chunk_info[here + 1].c) 532269257Sdes ++here; 533269257Sdes break; 534269257Sdes 535238106Sdes case KEY_DOWN: 536269257Sdes case '+': 537238106Sdes case '\r': 538249141Sdes case '\n': 539249141Sdes if (label_chunk_info[here + 1].c) 540249141Sdes ++here; 541249141Sdes else 542249141Sdes here = 0; 543249141Sdes break; 544249141Sdes 545249141Sdes case KEY_HOME: 546249141Sdes here = 0; 547249141Sdes break; 548238106Sdes 549238106Sdes case KEY_END: 550238106Sdes while (label_chunk_info[here + 1].c) 551238106Sdes ++here; 552238106Sdes break; 553238106Sdes 554238106Sdes case KEY_F(1): 555238106Sdes case '?': 556238106Sdes systemDisplayHelp("partition"); 557238106Sdes clear_wins(); 558238106Sdes break; 559238106Sdes 560238106Sdes case 'A': 561238106Sdes if (label_chunk_info[here].type != PART_SLICE) { 562238106Sdes msg = "You can only do this in a disk slice (at top of screen)"; 563238106Sdes break; 564238106Sdes } 565238106Sdes sz = space_free(label_chunk_info[here].c); 566238106Sdes if (sz <= FS_MIN_SIZE) 567238106Sdes msg = "Not enough free space to create a new partition in the slice"; 568238106Sdes else { 569238106Sdes struct chunk *tmp; 570238106Sdes int mib[2]; 571238106Sdes int physmem; 572238106Sdes size_t size, swsize; 573238106Sdes char *cp; 574238106Sdes Chunk *rootdev, *swapdev, *usrdev, *vardev; 575238106Sdes 576238106Sdes (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); 577238106Sdes if (!rootdev) { 578238106Sdes cp = variable_get(VAR_ROOT_SIZE); 579238106Sdes tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 580238106Sdes (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); 581285206Sdes if (!tmp) { 582238106Sdes msgConfirm("Unable to create the root partition. Too big?"); 583238106Sdes clear_wins(); 584238106Sdes break; 585238106Sdes } 586238106Sdes tmp->private_data = new_part("/", TRUE, tmp->size); 587238106Sdes tmp->private_free = safe_free; 588238106Sdes record_label_chunks(devs); 589238106Sdes } 590238106Sdes 591238106Sdes if (!swapdev) { 592238106Sdes cp = variable_get(VAR_SWAP_SIZE); 593238106Sdes if (cp) 594238106Sdes swsize = atoi(cp) * ONE_MEG; 595238106Sdes else { 596238106Sdes mib[0] = CTL_HW; 597238106Sdes mib[1] = HW_PHYSMEM; 598295691Sdes size = sizeof physmem; 599285206Sdes sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 600285206Sdes swsize = 16 * ONE_MEG + (physmem * 2 / 512); 601285206Sdes } 602285206Sdes tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 603291767Sdes swsize, part, FS_SWAP, 0); 604291767Sdes if (!tmp) { 605291767Sdes msgConfirm("Unable to create the swap partition. Too big?"); 606285206Sdes clear_wins(); 607291767Sdes break; 608291767Sdes } 609291767Sdes tmp->private_data = 0; 610291767Sdes tmp->private_free = safe_free; 611291767Sdes record_label_chunks(devs); 612285206Sdes } 613285206Sdes 614291767Sdes if (!vardev) { 615285206Sdes cp = variable_get(VAR_VAR_SIZE); 616285206Sdes tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, 617285206Sdes (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 618291767Sdes if (!tmp) { 619285206Sdes msgConfirm("Less than %dMB free for /var - you will need to\n" 620285206Sdes "partition your disk manually with a custom install!", 621291767Sdes (cp ? atoi(cp) : VAR_MIN_SIZE)); 622291767Sdes clear_wins(); 623291767Sdes break; 624285206Sdes } 625291767Sdes tmp->private_data = new_part("/var", TRUE, tmp->size); 626291767Sdes tmp->private_free = safe_free; 627291767Sdes record_label_chunks(devs); 628291767Sdes } 629285206Sdes 630285206Sdes if (!usrdev) { 631285206Sdes cp = variable_get(VAR_USR_SIZE); 632291767Sdes if (cp) 633291767Sdes sz = atoi(cp) * ONE_MEG; 634285206Sdes else 635285206Sdes sz = space_free(label_chunk_info[here].c); 636285206Sdes if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) { 637291767Sdes msgConfirm("Less than %dMB free for /usr - you will need to\n" 638285206Sdes "partition your disk manually with a custom install!", USR_MIN_SIZE); 639285206Sdes clear_wins(); 640285206Sdes break; 641291767Sdes } 642285206Sdes 643285206Sdes tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 644285206Sdes label_chunk_info[here].c, 645285206Sdes sz, part, FS_BSDFFS, 0); 646285206Sdes if (!tmp) { 647285206Sdes msgConfirm("Unable to create the /usr partition. Not enough space?\n" 648291767Sdes "You will need to partition your disk manually with a custom install!"); 649294190Sdes clear_wins(); 650285206Sdes break; 651285206Sdes } 652285206Sdes tmp->private_data = new_part("/usr", TRUE, tmp->size); 653291767Sdes tmp->private_free = safe_free; 654285206Sdes record_label_chunks(devs); 655285206Sdes } 656285206Sdes /* At this point, we're reasonably "labelled" */ 657285206Sdes if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 658285206Sdes variable_set2(DISK_LABELLED, "yes"); 659285206Sdes } 660291767Sdes break; 661285206Sdes 662285206Sdes case 'C': 663285206Sdes if (label_chunk_info[here].type != PART_SLICE) { 664291767Sdes msg = "You can only do this in a master partition (see top of screen)"; 665291767Sdes break; 666285206Sdes } 667285206Sdes sz = space_free(label_chunk_info[here].c); 668285206Sdes if (sz <= FS_MIN_SIZE) { 669291767Sdes msg = "Not enough space to create an additional FreeBSD partition"; 670291767Sdes break; 671285206Sdes } 672285206Sdes else { 673285206Sdes char *val; 674285206Sdes int size; 675291767Sdes struct chunk *tmp; 676285206Sdes char osize[80]; 677285206Sdes u_long flags = 0; 678285206Sdes 679291767Sdes sprintf(osize, "%d", sz); 680285206Sdes DialogX = 3; 681285206Sdes DialogY = 2; 682291767Sdes val = msgGetInput(osize, 683285206Sdes "Please specify the partition size in blocks or append a trailing M for\n" 684285206Sdes "megabytes or C for cylinders. %d blocks (%dMB) are free.", 685285206Sdes sz, sz / ONE_MEG); 686285206Sdes DialogX = DialogY = 0; 687291767Sdes if (!val || (size = strtol(val, &cp, 0)) <= 0) { 688291767Sdes clear_wins(); 689291767Sdes break; 690291767Sdes } 691291767Sdes 692291767Sdes if (*cp) { 693291767Sdes if (toupper(*cp) == 'M') 694291767Sdes size *= ONE_MEG; 695291767Sdes else if (toupper(*cp) == 'C') 696291767Sdes size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 697285206Sdes } 698285206Sdes if (size <= FS_MIN_SIZE) { 699285206Sdes msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 700291767Sdes clear_wins(); 701285206Sdes break; 702291767Sdes } 703291767Sdes type = get_partition_type(); 704285206Sdes if (type == PART_NONE) { 705285206Sdes clear_wins(); 706295691Sdes beep(); 707285206Sdes break; 708285206Sdes } 709291767Sdes 710291767Sdes if (type == PART_FILESYSTEM) { 711291767Sdes if ((p = get_mountpoint(NULL)) == NULL) { 712291767Sdes clear_wins(); 713291767Sdes beep(); 714285206Sdes break; 715285206Sdes } 716285206Sdes else if (!strcmp(p->mountpoint, "/")) 717291767Sdes flags |= CHUNK_IS_ROOT; 718291767Sdes else 719291767Sdes flags &= ~CHUNK_IS_ROOT; 720291767Sdes } 721285206Sdes else 722285206Sdes p = NULL; 723285206Sdes 724285206Sdes if ((flags & CHUNK_IS_ROOT)) { 725285206Sdes if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 726285206Sdes msgConfirm("This region cannot be used for your root partition as the\n" 727291767Sdes "FreeBSD boot code cannot deal with a root partition created\n" 728291767Sdes "in that location. Please choose another location or smaller\n" 729291767Sdes "size for your root partition and try again!"); 730291767Sdes clear_wins(); 731291767Sdes break; 732294190Sdes } 733285206Sdes if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 734285206Sdes msgConfirm("Warning: This is smaller than the recommended size for a\n" 735285206Sdes "root partition. For a variety of reasons, root\n" 736291767Sdes "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 737285206Sdes } 738285206Sdes } 739285206Sdes tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 740285206Sdes label_chunk_info[here].c, 741291767Sdes size, part, 742285206Sdes (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 743285206Sdes flags); 744291767Sdes if (!tmp) { 745291767Sdes msgConfirm("Unable to create the partition. Too big?"); 746291767Sdes clear_wins(); 747285206Sdes break; 748285206Sdes } 749285206Sdes if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 750285206Sdes msgConfirm("This region cannot be used for your root partition as it starts\n" 751285206Sdes "or extends past the 1024'th cylinder mark and is thus a\n" 752285206Sdes "poor location to boot from. Please choose another\n" 753285206Sdes "location (or smaller size) for your root partition and try again!"); 754291767Sdes Delete_Chunk(label_chunk_info[here].c->disk, tmp); 755285206Sdes clear_wins(); 756285206Sdes break; 757291767Sdes } 758291767Sdes if (type != PART_SWAP) { 759285206Sdes /* This is needed to tell the newfs -u about the size */ 760285206Sdes tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 761285206Sdes safe_free(p); 762291767Sdes } 763291767Sdes else 764291767Sdes tmp->private_data = p; 765285206Sdes tmp->private_free = safe_free; 766291767Sdes if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 767285206Sdes variable_set2(DISK_LABELLED, "yes"); 768285206Sdes record_label_chunks(devs); 769285206Sdes clear_wins(); 770291767Sdes } 771285206Sdes break; 772285206Sdes 773285206Sdes case KEY_DC: 774291767Sdes case 'D': /* delete */ 775285206Sdes if (label_chunk_info[here].type == PART_SLICE) { 776285206Sdes msg = MSG_NOT_APPLICABLE; 777285206Sdes break; 778291767Sdes } 779291767Sdes else if (label_chunk_info[here].type == PART_FAT) { 780294190Sdes msg = "Use the Disk Partition Editor to delete DOS partitions"; 781285206Sdes break; 782285206Sdes } 783285206Sdes Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 784291767Sdes if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 785294190Sdes variable_set2(DISK_LABELLED, "yes"); 786285206Sdes record_label_chunks(devs); 787285206Sdes break; 788285206Sdes 789285206Sdes case 'M': /* mount */ 790291767Sdes switch(label_chunk_info[here].type) { 791285206Sdes case PART_SLICE: 792285206Sdes msg = MSG_NOT_APPLICABLE; 793285206Sdes break; 794285206Sdes 795285206Sdes case PART_SWAP: 796285206Sdes msg = "You don't need to specify a mountpoint for a swap partition."; 797285206Sdes break; 798285206Sdes 799285206Sdes case PART_FAT: 800285206Sdes case PART_FILESYSTEM: 801291767Sdes oldp = label_chunk_info[here].c->private_data; 802285206Sdes p = get_mountpoint(label_chunk_info[here].c); 803285206Sdes if (p) { 804285206Sdes if (!oldp) 805285206Sdes p->newfs = FALSE; 806285206Sdes if (label_chunk_info[here].type == PART_FAT 807285206Sdes && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 808285206Sdes || !strcmp(p->mountpoint, "/var"))) { 809291767Sdes msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 810285206Sdes strcpy(p->mountpoint, "/bogus"); 811285206Sdes } 812285206Sdes } 813285206Sdes if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 814285206Sdes variable_set2(DISK_LABELLED, "yes"); 815285206Sdes record_label_chunks(devs); 816291767Sdes clear_wins(); 817285206Sdes break; 818285206Sdes 819285206Sdes default: 820294190Sdes msgFatal("Bogus partition under cursor???"); 821285206Sdes break; 822285206Sdes } 823285206Sdes break; 824291767Sdes 825295691Sdes case 'N': /* Set newfs options */ 826285206Sdes if (label_chunk_info[here].c->private_data && 827285206Sdes ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 828285206Sdes getNewfsCmd(label_chunk_info[here].c->private_data); 829291767Sdes else 830291767Sdes msg = MSG_NOT_APPLICABLE; 831291767Sdes clear_wins(); 832291767Sdes break; 833291767Sdes 834291767Sdes case 'T': /* Toggle newfs state */ 835291767Sdes if (label_chunk_info[here].type == PART_FILESYSTEM) { 836291767Sdes PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 837285206Sdes label_chunk_info[here].c->private_data = 838285206Sdes new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 839285206Sdes safe_free(pi); 840285206Sdes label_chunk_info[here].c->private_free = safe_free; 841291767Sdes if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 842285206Sdes variable_set2(DISK_LABELLED, "yes"); 843285206Sdes } 844285206Sdes else 845294190Sdes msg = MSG_NOT_APPLICABLE; 846294190Sdes break; 847294190Sdes 848294190Sdes case 'U': 849294190Sdes clear(); 850294190Sdes if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 851294190Sdes msgConfirm("You've already written out your changes -\n" 852294190Sdes "it's too late to undo!"); 853294190Sdes } 854294190Sdes else if (!msgYesNo("Are you SURE you want to Undo everything?")) { 855291767Sdes variable_unset(DISK_PARTITIONED); 856291767Sdes variable_unset(DISK_LABELLED); 857285206Sdes for (i = 0; devs[i]; i++) { 858291767Sdes Disk *d; 859285206Sdes 860285206Sdes if (!devs[i]->enabled) 861285206Sdes continue; 862291767Sdes else if ((d = Open_Disk(devs[i]->name)) != NULL) { 863291767Sdes Free_Disk(devs[i]->private); 864285206Sdes devs[i]->private = d; 865285206Sdes diskPartition(devs[i], d); 866294190Sdes } 867294190Sdes } 868285206Sdes record_label_chunks(devs); 869285206Sdes } 870285206Sdes clear_wins(); 871291767Sdes break; 872291767Sdes 873294190Sdes case 'W': 874294190Sdes if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { 875285206Sdes msgConfirm("You've already written out your changes - if you\n" 876285206Sdes "wish to overwrite them, you'll have to start this\n" 877285206Sdes "procedure again from the beginning."); 878291767Sdes } 879285206Sdes else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" 880285206Sdes "installation. If you are installing FreeBSD for the first time\n" 881285206Sdes "then you should simply type Q when you're finished here and your\n" 882285206Sdes "changes will be committed in one batch automatically at the end of\n" 883285206Sdes "these questions.\n\n" 884285206Sdes "Are you absolutely sure you want to do this now?")) { 885291767Sdes variable_set2(DISK_LABELLED, "yes"); 886291767Sdes diskLabelCommit(NULL); 887291767Sdes } 888291767Sdes clear_wins(); 889291767Sdes break; 890285206Sdes 891285206Sdes case '|': 892285206Sdes if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 893285206Sdes "This is an entirely undocumented feature which you are not\n" 894291767Sdes "expected to understand!")) { 895285206Sdes int i; 896291767Sdes Device **devs; 897291767Sdes 898285206Sdes dialog_clear(); 899285206Sdes end_dialog(); 900294190Sdes DialogActive = FALSE; 901291767Sdes devs = deviceFind(NULL, DEVICE_TYPE_DISK); 902285206Sdes if (!devs) { 903291767Sdes msgConfirm("Can't find any disk devices!"); 904291767Sdes break; 905285206Sdes } 906285206Sdes for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 907291767Sdes if (devs[i]->enabled) 908285206Sdes slice_wizard(((Disk *)devs[i]->private)); 909285206Sdes } 910291767Sdes if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) 911285206Sdes variable_set2(DISK_LABELLED, "yes"); 912285206Sdes DialogActive = TRUE; 913285206Sdes record_label_chunks(devs); 914291767Sdes clear_wins(); 915285206Sdes } 916285206Sdes else 917285206Sdes msg = "A most prudent choice!"; 918285206Sdes break; 919285206Sdes 920285206Sdes case 'Q': 921285206Sdes labeling = FALSE; 922285206Sdes break; 923285206Sdes 924291767Sdes default: 925285206Sdes beep(); 926291767Sdes sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); 927291767Sdes msg = _msg; 928285206Sdes break; 929291767Sdes } 930285206Sdes } 931291767Sdes return DITEM_SUCCESS | DITEM_RESTORE; 932291767Sdes} 933285206Sdes