label.c revision 15091
1178481Sjb/* 2178481Sjb * The new sysinstall program. 3178481Sjb * 4178481Sjb * This is probably the last program in the `sysinstall' line - the next 5178481Sjb * generation being essentially a complete rewrite. 6178481Sjb * 7178481Sjb * $Id: label.c,v 1.40 1996/03/24 18:57:37 joerg Exp $ 8178481Sjb * 9178481Sjb * Copyright (c) 1995 10178481Sjb * Jordan Hubbard. All rights reserved. 11178481Sjb * 12178481Sjb * Redistribution and use in source and binary forms, with or without 13178481Sjb * modification, are permitted provided that the following conditions 14178481Sjb * are met: 15178481Sjb * 1. Redistributions of source code must retain the above copyright 16178481Sjb * notice, this list of conditions and the following disclaimer, 17178481Sjb * verbatim and that no modifications are made prior to this 18178481Sjb * point in the file. 19178481Sjb * 2. Redistributions in binary form must reproduce the above copyright 20178481Sjb * notice, this list of conditions and the following disclaimer in the 21178481Sjb * documentation and/or other materials provided with the distribution. 22178481Sjb * 3. All advertising materials mentioning features or use of this software 23178481Sjb * must display the following acknowledgement: 24178481Sjb * This product includes software developed by Jordan Hubbard 25178481Sjb * for the FreeBSD Project. 26178481Sjb * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to 27178481Sjb * endorse or promote products derived from this software without specific 28178481Sjb * prior written permission. 29178481Sjb * 30178481Sjb * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 31178481Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32178481Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33178481Sjb * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 34178481Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35178481Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36178481Sjb * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 37178481Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38178481Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39178481Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40178481Sjb * SUCH DAMAGE. 41178481Sjb * 42178481Sjb */ 43178481Sjb 44178481Sjb#include "sysinstall.h" 45178481Sjb#include <ctype.h> 46178481Sjb#include <sys/disklabel.h> 47178481Sjb#include <sys/param.h> 48178481Sjb#include <sys/sysctl.h> 49178481Sjb 50178481Sjb/* 51178481Sjb * Everything to do with editing the contents of disk labels. 52178481Sjb */ 53178481Sjb 54178481Sjb/* A nice message we use a lot in the disklabel editor */ 55178481Sjb#define MSG_NOT_APPLICABLE "That option is not applicable here" 56178481Sjb 57178481Sjb/* Where to start printing the freebsd slices */ 58178481Sjb#define CHUNK_SLICE_START_ROW 2 59178481Sjb#define CHUNK_PART_START_ROW 11 60178481Sjb 61178481Sjb/* The smallest filesystem we're willing to create */ 62178481Sjb#define FS_MIN_SIZE ONE_MEG 63178481Sjb 64178481Sjb/* The smallest root filesystem we're willing to create */ 65178481Sjb#define ROOT_MIN_SIZE 20 66178481Sjb 67178481Sjb/* The smallest swap partition we want to create by default */ 68178481Sjb#define SWAP_MIN_SIZE 16 69178481Sjb 70178481Sjb/* The smallest /usr partition we're willing to create by default */ 71178481Sjb#define USR_MIN_SIZE 80 72178481Sjb 73178481Sjb/* The smallest /var partition we're willing to create by default */ 74178481Sjb#define VAR_MIN_SIZE 30 75178481Sjb 76178481Sjb/* All the chunks currently displayed on the screen */ 77178481Sjbstatic struct { 78178481Sjb struct chunk *c; 79178481Sjb PartType type; 80178481Sjb} label_chunk_info[MAX_CHUNKS + 1]; 81178481Sjbstatic int here; 82178481Sjb 83178481Sjbstatic int diskLabel(char *str); 84178481Sjb 85178481Sjbstatic int 86178481SjblabelHook(char *str) 87178481Sjb{ 88178481Sjb Device **devs = NULL; 89178481Sjb 90178481Sjb /* Clip garbage off the ends */ 91178481Sjb string_prune(str); 92178481Sjb str = string_skipwhite(str); 93178481Sjb /* Try and open all the disks */ 94178481Sjb while (str) { 95178481Sjb char *cp; 96178481Sjb 97178481Sjb cp = index(str, '\n'); 98178481Sjb if (cp) 99178481Sjb *cp++ = 0; 100178481Sjb if (!*str) { 101178481Sjb beep(); 102178481Sjb return 0; 103178481Sjb } 104178481Sjb devs = deviceFind(str, DEVICE_TYPE_DISK); 105178481Sjb if (!devs) { 106178481Sjb dialog_clear(); 107178481Sjb msgConfirm("Unable to find disk %s!", str); 108178481Sjb return 0; 109178481Sjb } 110178481Sjb devs[0]->enabled = TRUE; 111178481Sjb str = cp; 112178481Sjb } 113178481Sjb return devs ? 1 : 0; 114178481Sjb} 115178481Sjb 116178481Sjbint 117178481SjbdiskLabelEditor(dialogMenuItem *self) 118178481Sjb{ 119178481Sjb Device **devs; 120178481Sjb DMenu *menu; 121178481Sjb int i, cnt; 122178481Sjb char *cp, *str; 123178481Sjb 124178481Sjb cp = variable_get(VAR_DISK); 125178481Sjb str = variable_get(SYSTEM_STATE); 126178481Sjb devs = deviceFind(cp, DEVICE_TYPE_DISK); 127178481Sjb cnt = deviceCount(devs); 128178481Sjb if (!cnt) { 129178481Sjb dialog_clear(); 130178481Sjb msgConfirm("No disks found! Please verify that your disk controller is being\n" 131178481Sjb "properly probed at boot time. See the Hardware Guide on the\n" 132178481Sjb "Documentation menu for clues on diagnosing this type of problem."); 133178481Sjb return RET_FAIL; 134178481Sjb } 135178546Sjb else if (cnt == 1 || variable_get(DISK_SELECTED)) { 136178481Sjb if (cnt == 1) 137178481Sjb devs[0]->enabled = TRUE; 138178481Sjb i = diskLabel(str); 139178481Sjb } 140178481Sjb else { 141178481Sjb menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook); 142178481Sjb if (!menu) { 143178481Sjb dialog_clear(); 144178481Sjb msgConfirm("No devices suitable for installation found!\n\n" 145178481Sjb "Please verify that your disk controller (and attached drives)\n" 146178481Sjb "were detected properly. This can be done by pressing the\n" 147178481Sjb "[Scroll Lock] key and using the Arrow keys to move back to\n" 148178481Sjb "the boot messages. Press [Scroll Lock] again to return."); 149178481Sjb i = RET_FAIL; 150178481Sjb } 151178481Sjb else { 152178481Sjb if (!dmenuOpenSimple(menu)) 153178481Sjb i = RET_FAIL; 154178481Sjb else 155178481Sjb i = diskLabel(str); 156178481Sjb free(menu); 157178481Sjb } 158178481Sjb } 159178481Sjb return i; 160178481Sjb} 161178481Sjb 162178481Sjbint 163178481SjbdiskLabelCommit(dialogMenuItem *self) 164178481Sjb{ 165178481Sjb char *cp; 166178481Sjb int i; 167178481Sjb 168178481Sjb /* Already done? */ 169178481Sjb if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) { 170178481Sjb variable_set2(DISK_PARTITIONED, "yes"); 171178481Sjb i = RET_SUCCESS; 172178481Sjb } 173178481Sjb else if (!cp) { 174178481Sjb dialog_clear(); 175178481Sjb msgConfirm("You must assign disk labels before this option can be used."); 176178481Sjb i = RET_FAIL; 177178481Sjb } 178178481Sjb /* The routine will guard against redundant writes, just as this one does */ 179178481Sjb else if (diskPartitionWrite(self) != RET_SUCCESS) 180178481Sjb i = RET_FAIL; 181178481Sjb else if (installFilesystems(self) != RET_SUCCESS) 182178546Sjb i = RET_FAIL; 183178481Sjb else { 184178546Sjb msgInfo("All filesystem information written successfully."); 185178481Sjb variable_set2(DISK_LABELLED, "written"); 186178481Sjb i = RET_SUCCESS; 187178546Sjb } 188178481Sjb return i; 189178481Sjb} 190178481Sjb 191178481Sjb/* See if we're already using a desired partition name */ 192178481Sjbstatic Boolean 193178546Sjbcheck_conflict(char *name) 194178481Sjb{ 195178546Sjb int i; 196178546Sjb 197178481Sjb for (i = 0; label_chunk_info[i].c; i++) 198178481Sjb if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private_data 199178481Sjb && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) 200178481Sjb return TRUE; 201178481Sjb return FALSE; 202178481Sjb} 203178481Sjb 204178481Sjb/* How much space is in this FreeBSD slice? */ 205178481Sjbstatic int 206178481Sjbspace_free(struct chunk *c) 207178481Sjb{ 208178481Sjb struct chunk *c1; 209178481Sjb int sz = c->size; 210178481Sjb 211178481Sjb for (c1 = c->part; c1; c1 = c1->next) { 212178481Sjb if (c1->type != unused) 213178481Sjb sz -= c1->size; 214178481Sjb } 215178481Sjb if (sz < 0) 216178481Sjb msgFatal("Partitions are larger than actual chunk??"); 217178481Sjb return sz; 218178481Sjb} 219178546Sjb 220178481Sjb/* Snapshot the current situation into the displayed chunks structure */ 221178481Sjbstatic void 222178481Sjbrecord_label_chunks(Device **devs) 223178481Sjb{ 224178481Sjb int i, j, p; 225178481Sjb struct chunk *c1, *c2; 226178481Sjb Disk *d; 227178481Sjb 228178481Sjb j = p = 0; 229178481Sjb /* First buzz through and pick up the FreeBSD slices */ 230178481Sjb for (i = 0; devs[i]; i++) { 231178481Sjb if (!devs[i]->enabled) 232178481Sjb continue; 233178481Sjb d = (Disk *)devs[i]->private; 234178481Sjb if (!d->chunks) 235178481Sjb msgFatal("No chunk list found for %s!", d->name); 236178481Sjb 237178481Sjb /* Put the slice entries first */ 238178481Sjb for (c1 = d->chunks->part; c1; c1 = c1->next) { 239178481Sjb if (c1->type == freebsd) { 240178481Sjb label_chunk_info[j].type = PART_SLICE; 241178481Sjb label_chunk_info[j].c = c1; 242178481Sjb ++j; 243178481Sjb } 244178481Sjb } 245178481Sjb } 246178481Sjb 247178481Sjb /* Now run through again and get the FreeBSD partition entries */ 248178481Sjb for (i = 0; devs[i]; i++) { 249178481Sjb if (!devs[i]->enabled) 250178481Sjb continue; 251178481Sjb d = (Disk *)devs[i]->private; 252178481Sjb /* Then buzz through and pick up the partitions */ 253178481Sjb for (c1 = d->chunks->part; c1; c1 = c1->next) { 254178481Sjb if (c1->type == freebsd) { 255178481Sjb for (c2 = c1->part; c2; c2 = c2->next) { 256178481Sjb if (c2->type == part) { 257178481Sjb if (c2->subtype == FS_SWAP) 258178481Sjb label_chunk_info[j].type = PART_SWAP; 259178546Sjb else 260178481Sjb label_chunk_info[j].type = PART_FILESYSTEM; 261178481Sjb label_chunk_info[j].c = c2; 262178481Sjb ++j; 263178481Sjb } 264178481Sjb } 265178481Sjb } 266178481Sjb else if (c1->type == fat) { 267178481Sjb label_chunk_info[j].type = PART_FAT; 268178481Sjb label_chunk_info[j].c = c1; 269178481Sjb ++j; 270178481Sjb } 271178481Sjb } 272178481Sjb } 273178481Sjb label_chunk_info[j].c = NULL; 274178481Sjb if (here >= j) 275178481Sjb here = j ? j - 1 : 0; 276178481Sjb} 277178481Sjb 278178481Sjb/* A new partition entry */ 279178481Sjbstatic PartInfo * 280178481Sjbnew_part(char *mpoint, Boolean newfs, u_long size) 281178481Sjb{ 282178481Sjb PartInfo *ret; 283178481Sjb u_long target, divisor; 284178481Sjb 285178481Sjb if (!mpoint) 286178481Sjb mpoint = "/change_me"; 287178481Sjb 288178481Sjb ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); 289178481Sjb strncpy(ret->mountpoint, mpoint, FILENAME_MAX); 290178481Sjb strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024"); 291178481Sjb ret->newfs = newfs; 292178481Sjb if (!size) 293178481Sjb return ret; 294178481Sjb for (target = size; target; target--) { 295178481Sjb for (divisor = 4096 ; divisor > 1023; divisor--) { 296178481Sjb if (!(target % divisor)) { 297178481Sjb sprintf(ret->newfs_cmd + strlen(ret->newfs_cmd), " -u %ld",divisor); 298178481Sjb return ret; 299178481Sjb } 300178481Sjb } 301178481Sjb } 302178481Sjb return ret; 303178481Sjb} 304178481Sjb 305178481Sjb/* Get the mountpoint for a partition and save it away */ 306178481Sjbstatic PartInfo * 307178481Sjbget_mountpoint(struct chunk *old) 308178481Sjb{ 309178481Sjb char *val; 310178481Sjb PartInfo *tmp; 311178481Sjb 312178481Sjb if (old && old->private_data) 313178481Sjb tmp = old->private_data; 314178481Sjb else 315178481Sjb tmp = NULL; 316178546Sjb val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); 317178481Sjb if (!val || !*val) { 318178481Sjb if (!old) 319178481Sjb return NULL; 320178481Sjb else { 321178481Sjb free(old->private_data); 322178481Sjb old->private_data = NULL; 323178481Sjb } 324178481Sjb return NULL; 325178481Sjb } 326178481Sjb 327178481Sjb /* Is it just the same value? */ 328178481Sjb if (tmp && !strcmp(tmp->mountpoint, val)) 329178481Sjb return NULL; 330178481Sjb 331178481Sjb /* Did we use it already? */ 332178481Sjb if (check_conflict(val)) { 333178481Sjb msgConfirm("You already have a mount point for %s assigned!", val); 334178481Sjb return NULL; 335178481Sjb } 336178481Sjb 337178481Sjb /* Is it bogus? */ 338178546Sjb if (*val != '/') { 339178481Sjb msgConfirm("Mount point must start with a / character"); 340178481Sjb return NULL; 341178481Sjb } 342178481Sjb 343178481Sjb /* Is it going to be mounted on root? */ 344178481Sjb if (!strcmp(val, "/")) { 345178481Sjb if (old) 346178481Sjb old->flags |= CHUNK_IS_ROOT; 347178481Sjb } 348178481Sjb else if (old) 349178481Sjb old->flags &= ~CHUNK_IS_ROOT; 350178481Sjb 351178481Sjb safe_free(tmp); 352178481Sjb tmp = new_part(val, TRUE, 0); 353178481Sjb if (old) { 354178481Sjb old->private_data = tmp; 355178481Sjb old->private_free = safe_free; 356178481Sjb } 357178546Sjb return tmp; 358178481Sjb} 359178481Sjb 360178481Sjb/* Get the type of the new partiton */ 361178481Sjbstatic PartType 362178481Sjbget_partition_type(void) 363178481Sjb{ 364178481Sjb char selection[20]; 365178481Sjb int i; 366178481Sjb 367178481Sjb static unsigned char *fs_types[] = { 368178481Sjb "FS", 369178481Sjb "A file system", 370178481Sjb "Swap", 371178481Sjb "A swap partition.", 372178481Sjb }; 373178481Sjb i = dialog_menu("Please choose a partition type", 374178481Sjb "If you want to use this partition for swap space, select Swap.\n" 375178481Sjb "If you want to put a filesystem on it, choose FS.", 376178481Sjb -1, -1, 2, 2, fs_types, selection, NULL, NULL); 377178481Sjb if (!i) { 378178481Sjb if (!strcmp(selection, "FS")) 379178481Sjb return PART_FILESYSTEM; 380178481Sjb else if (!strcmp(selection, "Swap")) 381178481Sjb return PART_SWAP; 382178481Sjb } 383178481Sjb return PART_NONE; 384178481Sjb} 385178481Sjb 386178481Sjb/* If the user wants a special newfs command for this, set it */ 387178481Sjbstatic void 388178481SjbgetNewfsCmd(PartInfo *p) 389178481Sjb{ 390178481Sjb char *val; 391178481Sjb 392178481Sjb val = msgGetInput(p->newfs_cmd, 393178481Sjb "Please enter the newfs command and options you'd like to use in\n" 394178481Sjb "creating this file system."); 395178481Sjb if (val) 396178481Sjb strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); 397178481Sjb} 398178481Sjb 399178481Sjb#define MAX_MOUNT_NAME 12 400178481Sjb 401178481Sjb#define PART_PART_COL 0 402178481Sjb#define PART_MOUNT_COL 8 403178481Sjb#define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) 404178481Sjb#define PART_NEWFS_COL (PART_SIZE_COL + 7) 405178481Sjb#define PART_OFF 38 406178481Sjb 407178481Sjb/* How many mounted partitions to display in column before going to next */ 408178481Sjb#define CHUNK_COLUMN_MAX 5 409178481Sjb 410178481Sjb/* stick this all up on the screen */ 411178481Sjbstatic void 412178481Sjbprint_label_chunks(void) 413178481Sjb{ 414178481Sjb int i, j, srow, prow, pcol; 415178481Sjb int sz; 416178481Sjb 417178481Sjb attrset(A_REVERSE); 418178481Sjb mvaddstr(0, 25, "FreeBSD Disklabel Editor"); 419178481Sjb clrtobot(); 420178481Sjb attrset(A_NORMAL); 421178546Sjb 422178546Sjb for (i = 0; i < 2; i++) { 423178481Sjb mvaddstr(CHUNK_PART_START_ROW - 2, PART_PART_COL + (i * PART_OFF), "Part"); 424178481Sjb mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), "----"); 425178481Sjb 426178481Sjb mvaddstr(CHUNK_PART_START_ROW - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); 427178481Sjb mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); 428178481Sjb 429178481Sjb mvaddstr(CHUNK_PART_START_ROW - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size"); 430178481Sjb mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 431178481Sjb 432178481Sjb mvaddstr(CHUNK_PART_START_ROW - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); 433178546Sjb mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); 434178481Sjb } 435178481Sjb srow = CHUNK_SLICE_START_ROW; 436178481Sjb prow = CHUNK_PART_START_ROW; 437178481Sjb pcol = 0; 438178481Sjb 439178481Sjb for (i = 0; label_chunk_info[i].c; i++) { 440178481Sjb if (i == here) 441178481Sjb attrset(A_REVERSE); 442178481Sjb /* Is it a slice entry displayed at the top? */ 443178481Sjb if (label_chunk_info[i].type == PART_SLICE) { 444178481Sjb sz = space_free(label_chunk_info[i].c); 445178546Sjb mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", 446178481Sjb label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); 447178481Sjb } 448178481Sjb /* Otherwise it's a DOS, swap or filesystem entry, at the bottom */ 449178481Sjb else { 450178481Sjb char onestr[PART_OFF], num[10], *mountpoint, *newfs; 451178481Sjb 452178481Sjb /* 453178481Sjb * We copy this into a blank-padded string so that it looks like 454178481Sjb * a solid bar in reverse-video 455178481Sjb */ 456178546Sjb memset(onestr, ' ', PART_OFF - 1); 457178481Sjb onestr[PART_OFF - 1] = '\0'; 458178481Sjb /* Go for two columns */ 459178481Sjb if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) { 460178481Sjb pcol = PART_OFF; 461178481Sjb prow = CHUNK_PART_START_ROW; 462178481Sjb } 463178481Sjb memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); 464178546Sjb /* If it's a filesystem, display the mountpoint */ 465178481Sjb if (label_chunk_info[i].c->private_data 466178481Sjb && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) 467178481Sjb mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; 468178481Sjb else 469178481Sjb mountpoint = "<none>"; 470178481Sjb 471178481Sjb /* Now display the newfs field */ 472178481Sjb if (label_chunk_info[i].type == PART_FAT) 473178481Sjb newfs = "DOS"; 474178481Sjb else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) 475178481Sjb newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; 476178481Sjb else if (label_chunk_info[i].type == PART_SWAP) 477178481Sjb newfs = "SWAP"; 478178481Sjb else 479178481Sjb newfs = "*"; 480178481Sjb for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) 481178481Sjb onestr[PART_MOUNT_COL + j] = mountpoint[j]; 482178481Sjb snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); 483178481Sjb memcpy(onestr + PART_SIZE_COL, num, strlen(num)); 484178481Sjb memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); 485178546Sjb onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; 486178481Sjb mvaddstr(prow, pcol, onestr); 487178481Sjb ++prow; 488178481Sjb } 489178481Sjb if (i == here) 490178481Sjb attrset(A_NORMAL); 491178481Sjb } 492178481Sjb} 493178481Sjb 494178481Sjbstatic void 495178481Sjbprint_command_summary() 496178481Sjb{ 497178546Sjb mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); 498178481Sjb mvprintw(18, 0, "C = Create D = Delete M = Mount W = Write"); 499178481Sjb mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); 500178481Sjb mvprintw(20, 0, "A = Auto Defaults for all!"); 501178481Sjb mvprintw(22, 0, "The default target will be displayed in "); 502178481Sjb 503178481Sjb attrset(A_REVERSE); 504178481Sjb addstr("reverse"); 505178481Sjb attrset(A_NORMAL); 506178481Sjb addstr(" video."); 507178481Sjb mvprintw(23, 0, "Use F1 or ? to get more help, arrow keys to move."); 508178481Sjb move(0, 0); 509178481Sjb} 510178546Sjb 511178546Sjbstatic int 512178481SjbdiskLabel(char *str) 513178481Sjb{ 514178481Sjb int sz, key = 0; 515178481Sjb Boolean labeling; 516178481Sjb char *msg = NULL; 517178481Sjb PartInfo *p, *oldp; 518178481Sjb PartType type; 519178481Sjb Device **devs; 520178481Sjb 521178481Sjb devs = deviceFind(NULL, DEVICE_TYPE_DISK); 522178546Sjb if (!devs) { 523178546Sjb dialog_clear(); 524178546Sjb msgConfirm("No disks found!"); 525178481Sjb return RET_FAIL; 526178481Sjb } 527178481Sjb 528178546Sjb labeling = TRUE; 529178481Sjb keypad(stdscr, TRUE); 530178481Sjb record_label_chunks(devs); 531178481Sjb 532178481Sjb dialog_clear(); clear(); 533178481Sjb while (labeling) { 534178481Sjb clear(); 535178481Sjb print_label_chunks(); 536178481Sjb print_command_summary(); 537178481Sjb if (msg) { 538178481Sjb attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL); 539178481Sjb clrtoeol(); 540178481Sjb beep(); 541178481Sjb msg = NULL; 542178481Sjb } 543178481Sjb refresh(); 544178481Sjb key = toupper(getch()); 545178481Sjb switch (key) { 546178481Sjb int i, cnt; 547178481Sjb 548178481Sjb case '\014': /* ^L */ 549178481Sjb continue; 550178481Sjb 551178481Sjb case KEY_UP: 552178481Sjb case '-': 553178481Sjb if (here != 0) 554178481Sjb --here; 555178481Sjb else 556178481Sjb while (label_chunk_info[here + 1].c) 557178481Sjb ++here; 558178481Sjb break; 559178481Sjb 560178481Sjb case KEY_DOWN: 561178481Sjb case '+': 562178481Sjb case '\r': 563178481Sjb case '\n': 564178481Sjb if (label_chunk_info[here + 1].c) 565178481Sjb ++here; 566178481Sjb else 567178481Sjb here = 0; 568178481Sjb break; 569178481Sjb 570178481Sjb case KEY_HOME: 571178481Sjb here = 0; 572178481Sjb break; 573178481Sjb 574178481Sjb case KEY_END: 575178481Sjb while (label_chunk_info[here + 1].c) 576178481Sjb ++here; 577178481Sjb break; 578178481Sjb 579178481Sjb case KEY_F(1): 580178481Sjb case '?': 581178481Sjb systemDisplayHelp("partition"); 582178481Sjb break; 583178481Sjb 584178481Sjb case 'A': 585178481Sjb if (label_chunk_info[here].type != PART_SLICE) { 586178481Sjb msg = "You can only do this in a master partition (see top of screen)"; 587178481Sjb break; 588178481Sjb } 589178481Sjb 590178481Sjb cnt = i = 0; 591178481Sjb while (label_chunk_info[i].c) 592178481Sjb if (label_chunk_info[i++].type != PART_SLICE) 593178481Sjb cnt++; 594178481Sjb if (cnt == (CHUNK_COLUMN_MAX * 2) + 4) { 595178481Sjb dialog_clear(); 596178481Sjb msgConfirm("Sorry, I can't fit any more partitions on the screen! You can get around\n" 597178481Sjb "this limitation by partitioning your disks individually rather than all\n" 598178481Sjb "at once. This will be fixed just as soon as we get a scrolling partition\n" 599178481Sjb "box written. Sorry for the inconvenience!"); 600178481Sjb break; 601178481Sjb } 602178481Sjb 603178481Sjb sz = space_free(label_chunk_info[here].c); 604178481Sjb if (sz <= FS_MIN_SIZE) { 605178481Sjb msg = "Not enough space to create an additional FreeBSD partition"; 606178481Sjb break; 607178481Sjb } 608178481Sjb { 609178481Sjb struct chunk *tmp; 610178481Sjb int mib[2]; 611178481Sjb int physmem; 612178481Sjb size_t size, swsize; 613178481Sjb char *cp; 614178481Sjb 615178481Sjb cp = variable_get(VAR_ROOT_SIZE); 616178481Sjb tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 617178481Sjb label_chunk_info[here].c, 618178481Sjb (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS, 619178481Sjb CHUNK_IS_ROOT); 620178481Sjb 621178481Sjb if (!tmp) { 622178481Sjb dialog_clear(); 623178481Sjb msgConfirm("Unable to create the root partition. Too big?"); 624178481Sjb break; 625178481Sjb } 626178481Sjb tmp->private_data = new_part("/", TRUE, tmp->size); 627178481Sjb tmp->private_free = safe_free; 628178481Sjb record_label_chunks(devs); 629178481Sjb 630178481Sjb cp = variable_get(VAR_SWAP_SIZE); 631178481Sjb if (cp) 632178481Sjb swsize = atoi(cp) * ONE_MEG; 633178481Sjb else { 634178481Sjb mib[0] = CTL_HW; 635178481Sjb mib[1] = HW_PHYSMEM; 636178481Sjb size = sizeof physmem; 637178481Sjb sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); 638178481Sjb swsize = 16 * ONE_MEG + (physmem * 2 / 512); 639178481Sjb } 640178481Sjb tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 641178481Sjb label_chunk_info[here].c, 642178481Sjb swsize, 643178481Sjb part, FS_SWAP, 0); 644178481Sjb if (!tmp) { 645178481Sjb dialog_clear(); 646178481Sjb msgConfirm("Unable to create the swap partition. Too big?"); 647178481Sjb break; 648178481Sjb } 649178481Sjb 650178481Sjb tmp->private_data = 0; 651178481Sjb tmp->private_free = safe_free; 652178481Sjb record_label_chunks(devs); 653178481Sjb 654178481Sjb cp = variable_get(VAR_VAR_SIZE); 655178481Sjb tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 656178481Sjb label_chunk_info[here].c, 657178481Sjb (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0); 658178481Sjb if (!tmp) { 659178481Sjb dialog_clear(); 660178481Sjb msgConfirm("Less than %dMB free for /var - you will need to\n" 661178481Sjb "partition your disk manually with a custom install!", (cp ? atoi(cp) : VAR_MIN_SIZE)); 662178481Sjb break; 663178481Sjb } 664178481Sjb tmp->private_data = new_part("/var", TRUE, tmp->size); 665178481Sjb tmp->private_free = safe_free; 666178481Sjb record_label_chunks(devs); 667178481Sjb 668178481Sjb cp = variable_get(VAR_USR_SIZE); 669178481Sjb if (cp) 670178481Sjb sz = atoi(cp) * ONE_MEG; 671178481Sjb else 672178481Sjb sz = space_free(label_chunk_info[here].c); 673178481Sjb if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) { 674178481Sjb dialog_clear(); 675178481Sjb msgConfirm("Less than %dMB free for /usr - you will need to\n" 676178481Sjb "partition your disk manually with a custom install!", USR_MIN_SIZE); 677178481Sjb break; 678178481Sjb } 679178481Sjb 680178481Sjb tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 681178481Sjb label_chunk_info[here].c, 682178481Sjb sz, part, FS_BSDFFS, 0); 683178481Sjb if (!tmp) { 684178481Sjb dialog_clear(); 685178481Sjb msgConfirm("Unable to create the /usr partition. Not enough space?\n" 686178481Sjb "You will need to partition your disk manually with a custom install!"); 687178481Sjb break; 688178481Sjb } 689178481Sjb /* At this point, we're reasonably "labelled" */ 690178481Sjb variable_set2(DISK_LABELLED, "yes"); 691178481Sjb tmp->private_data = new_part("/usr", TRUE, tmp->size); 692178481Sjb tmp->private_free = safe_free; 693178481Sjb record_label_chunks(devs); 694178481Sjb } 695178481Sjb break; 696178481Sjb 697178481Sjb case 'C': 698178481Sjb if (label_chunk_info[here].type != PART_SLICE) { 699178481Sjb msg = "You can only do this in a master partition (see top of screen)"; 700178481Sjb break; 701178546Sjb } 702178481Sjb else { 703178481Sjb int i, cnt; 704178481Sjb 705178481Sjb cnt = i = 0; 706178481Sjb while (label_chunk_info[i].c) 707178546Sjb if (label_chunk_info[i++].type != PART_SLICE) 708178546Sjb cnt++; 709178481Sjb if (cnt == (CHUNK_COLUMN_MAX * 2)) { 710178481Sjb dialog_clear(); 711178481Sjb msgConfirm("Sorry, I can't fit any more partitions on the screen! You can get around\n" 712178481Sjb "this limitation by partitioning your disks individually rather than all\n" 713178481Sjb "at once. This will be fixed just as soon as we get a scrolling partition\n" 714178481Sjb "box written. Sorry for the inconvenience!"); 715178481Sjb break; 716178481Sjb } 717178481Sjb } 718178481Sjb sz = space_free(label_chunk_info[here].c); 719178481Sjb if (sz <= FS_MIN_SIZE) { 720178481Sjb msg = "Not enough space to create an additional FreeBSD partition"; 721178481Sjb break; 722178481Sjb } 723178481Sjb { 724178481Sjb char *val, *cp; 725178481Sjb int size; 726178481Sjb struct chunk *tmp; 727178481Sjb char osize[80]; 728178481Sjb u_long flags = 0; 729178481Sjb 730178481Sjb sprintf(osize, "%d", sz); 731178481Sjb val = msgGetInput(osize, "Please specify the size for new FreeBSD partition in blocks, or\n" 732178481Sjb "append a trailing `M' for megabytes (e.g. 20M) or `C' for cylinders.\n\n" 733178481Sjb "Space free is %d blocks (%dMB)", sz, sz / ONE_MEG); 734178546Sjb if (!val || (size = strtol(val, &cp, 0)) <= 0) 735178481Sjb break; 736178481Sjb 737178481Sjb if (*cp) { 738178481Sjb if (toupper(*cp) == 'M') 739178481Sjb size *= ONE_MEG; 740178481Sjb else if (toupper(*cp) == 'C') 741178481Sjb size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); 742178481Sjb } 743178481Sjb if (size <= FS_MIN_SIZE) { 744178481Sjb msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); 745178481Sjb break; 746178481Sjb } 747178481Sjb type = get_partition_type(); 748178481Sjb if (type == PART_NONE) 749178481Sjb break; 750178481Sjb 751178481Sjb if (type == PART_FILESYSTEM) { 752178481Sjb if ((p = get_mountpoint(NULL)) == NULL) 753178481Sjb break; 754178481Sjb else if (!strcmp(p->mountpoint, "/")) 755178481Sjb flags |= CHUNK_IS_ROOT; 756178481Sjb else 757178481Sjb flags &= ~CHUNK_IS_ROOT; 758178481Sjb } else 759178481Sjb p = NULL; 760178481Sjb 761178481Sjb if ((flags & CHUNK_IS_ROOT)) { 762178481Sjb if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { 763178481Sjb msgConfirm("This region cannot be used for your root partition as the\n" 764178481Sjb "FreeBSD boot code cannot deal with a root partition created\n" 765178481Sjb "in that location. Please choose another location or smaller\n" 766178481Sjb "size for your root partition and try again!"); 767178481Sjb break; 768178481Sjb } 769178481Sjb if (size < (ROOT_MIN_SIZE * ONE_MEG)) { 770178546Sjb msgConfirm("Warning: This is smaller than the recommended size for a\n" 771178481Sjb "root partition. For a variety of reasons, root\n" 772178481Sjb "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); 773178481Sjb } 774178481Sjb } 775178481Sjb tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, 776178481Sjb label_chunk_info[here].c, 777178481Sjb size, part, 778178481Sjb (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, 779178481Sjb flags); 780178481Sjb if (!tmp) { 781178481Sjb msgConfirm("Unable to create the partition. Too big?"); 782178481Sjb break; 783178481Sjb } 784178481Sjb if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { 785178481Sjb msgConfirm("This region cannot be used for your root partition as it starts\n" 786178481Sjb "or extends past the 1024'th cylinder mark and is thus a\n" 787178481Sjb "poor location to boot from. Please choose another\n" 788178481Sjb "location (or smaller size) for your root partition and try again!"); 789178481Sjb Delete_Chunk(label_chunk_info[here].c->disk, tmp); 790178481Sjb break; 791178481Sjb } 792178481Sjb if (type != PART_SWAP) { 793178481Sjb /* This is needed to tell the newfs -u about the size */ 794178481Sjb tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); 795178481Sjb tmp->private_free = safe_free; 796178481Sjb safe_free(p); 797178481Sjb } else { 798178481Sjb tmp->private_data = p; 799178481Sjb } 800178481Sjb tmp->private_free = safe_free; 801178481Sjb variable_set2(DISK_LABELLED, "yes"); 802178481Sjb record_label_chunks(devs); 803178481Sjb } 804178481Sjb break; 805178481Sjb 806178481Sjb case '\177': 807178481Sjb case 'D': /* delete */ 808178481Sjb if (label_chunk_info[here].type == PART_SLICE) { 809178481Sjb msg = MSG_NOT_APPLICABLE; 810178546Sjb break; 811178481Sjb } 812178481Sjb else if (label_chunk_info[here].type == PART_FAT) { 813178481Sjb msg = "Use the Disk Partition Editor to delete DOS partitions"; 814178481Sjb break; 815178481Sjb } 816178481Sjb Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); 817178481Sjb variable_set2(DISK_LABELLED, "yes"); 818178481Sjb record_label_chunks(devs); 819178481Sjb break; 820178481Sjb 821178546Sjb case 'M': /* mount */ 822178481Sjb switch(label_chunk_info[here].type) { 823178481Sjb case PART_SLICE: 824178481Sjb msg = MSG_NOT_APPLICABLE; 825178481Sjb break; 826178481Sjb 827178481Sjb case PART_SWAP: 828178481Sjb msg = "You don't need to specify a mountpoint for a swap partition."; 829178481Sjb break; 830178481Sjb 831178481Sjb case PART_FAT: 832178481Sjb case PART_FILESYSTEM: 833178481Sjb oldp = label_chunk_info[here].c->private_data; 834178481Sjb p = get_mountpoint(label_chunk_info[here].c); 835178481Sjb if (p) { 836178481Sjb if (!oldp) 837178481Sjb p->newfs = FALSE; 838178481Sjb if (label_chunk_info[here].type == PART_FAT 839178481Sjb && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") 840178481Sjb || !strcmp(p->mountpoint, "/var"))) { 841178481Sjb msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); 842178481Sjb strcpy(p->mountpoint, "/bogus"); 843178481Sjb } 844178481Sjb } 845178481Sjb variable_set2(DISK_LABELLED, "yes"); 846178481Sjb record_label_chunks(devs); 847178481Sjb break; 848178481Sjb 849178481Sjb default: 850178546Sjb msgFatal("Bogus partition under cursor???"); 851178481Sjb break; 852178481Sjb } 853178481Sjb break; 854178481Sjb 855178481Sjb case 'N': /* Set newfs options */ 856178481Sjb if (label_chunk_info[here].c->private_data && 857178481Sjb ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) 858178481Sjb getNewfsCmd(label_chunk_info[here].c->private_data); 859178481Sjb else 860178481Sjb msg = MSG_NOT_APPLICABLE; 861178481Sjb break; 862178481Sjb 863178481Sjb case 'T': /* Toggle newfs state */ 864178481Sjb if (label_chunk_info[here].type == PART_FILESYSTEM) { 865178481Sjb PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); 866178481Sjb label_chunk_info[here].c->private_data = new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); 867178481Sjb safe_free(pi); 868178481Sjb label_chunk_info[here].c->private_free = safe_free; 869178481Sjb variable_set2(DISK_LABELLED, "yes"); 870178481Sjb } 871178481Sjb else 872178481Sjb msg = MSG_NOT_APPLICABLE; 873178481Sjb break; 874178481Sjb 875178546Sjb case 'U': 876178481Sjb clear(); 877178481Sjb if (msgYesNo("Are you SURE you want to Undo everything?")) 878178481Sjb break; 879178481Sjb variable_unset(DISK_PARTITIONED); 880178481Sjb for (i = 0; devs[i]; i++) { 881178481Sjb extern void diskPartition(Device *dev, Disk *d); 882178481Sjb Disk *d; 883178481Sjb 884178481Sjb if (!devs[i]->enabled) 885178481Sjb continue; 886178481Sjb else if ((d = Open_Disk(devs[i]->name)) != NULL) { 887178481Sjb Free_Disk(devs[i]->private); 888178481Sjb devs[i]->private = d; 889178481Sjb diskPartition(devs[i], d); 890178481Sjb } 891178481Sjb } 892178481Sjb variable_unset(DISK_LABELLED); 893178481Sjb record_label_chunks(devs); 894178481Sjb break; 895178481Sjb 896178481Sjb case 'W': 897178481Sjb if (!msgYesNo("Are you SURE that you wish to make and mount all filesystems\n" 898178481Sjb "at this time? You also have the option of doing it later in\n" 899178481Sjb "one final 'commit' operation, and if you're at all unsure as\n" 900178481Sjb "to which option to chose, then PLEASE CHOSE NO! This option\n" 901178481Sjb "is DANGEROUS if you're not EXACTLY sure what you are doing!")) { 902178481Sjb variable_set2(DISK_LABELLED, "yes"); 903178481Sjb clear(); 904178481Sjb diskLabelCommit(NULL); 905178481Sjb } 906178481Sjb break; 907178481Sjb 908178481Sjb case '|': 909178481Sjb if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" 910178481Sjb "This is an entirely undocumented feature which you are not\n" 911178481Sjb "expected to understand!")) { 912178481Sjb int i; 913178546Sjb Device **devs; 914178481Sjb 915178481Sjb dialog_clear(); 916178481Sjb end_dialog(); 917178481Sjb DialogActive = FALSE; 918178481Sjb devs = deviceFind(NULL, DEVICE_TYPE_DISK); 919178481Sjb if (!devs) { 920178481Sjb dialog_clear(); 921178481Sjb msgConfirm("Can't find any disk devices!"); 922178481Sjb break; 923178481Sjb } 924178481Sjb for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { 925178481Sjb if (devs[i]->enabled) 926178481Sjb slice_wizard(((Disk *)devs[i]->private)); 927178481Sjb } 928178481Sjb variable_set2(DISK_LABELLED, "yes"); 929178481Sjb DialogActive = TRUE; 930178481Sjb dialog_clear(); 931178481Sjb record_label_chunks(devs); 932178481Sjb } 933178481Sjb else 934178481Sjb msg = "A most prudent choice!"; 935178481Sjb break; 936178481Sjb 937178481Sjb case 'Q': 938178481Sjb labeling = FALSE; 939178481Sjb break; 940178481Sjb 941178481Sjb default: 942178481Sjb beep(); 943178481Sjb msg = "Type F1 or ? for help"; 944178481Sjb break; 945178481Sjb } 946178481Sjb } 947178481Sjb dialog_clear(); 948178481Sjb return RET_SUCCESS; 949178481Sjb} 950178481Sjb