label.c revision 8549
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 *
78549Sjkh * $Id: disks.c,v 1.17 1995/05/11 09:01:28 jkh Exp $
88549Sjkh *
98549Sjkh * Copyright (c) 1995
108549Sjkh *	Jordan Hubbard.  All rights reserved.
118549Sjkh *
128549Sjkh * Redistribution and use in source and binary forms, with or without
138549Sjkh * modification, are permitted provided that the following conditions
148549Sjkh * are met:
158549Sjkh * 1. Redistributions of source code must retain the above copyright
168549Sjkh *    notice, this list of conditions and the following disclaimer,
178549Sjkh *    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 * 3. All advertising materials mentioning features or use of this software
238549Sjkh *    must display the following acknowledgement:
248549Sjkh *	This product includes software developed by Jordan Hubbard
258549Sjkh *	for the FreeBSD Project.
268549Sjkh * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to
278549Sjkh *    endorse or promote products derived from this software without specific
288549Sjkh *    prior written permission.
298549Sjkh *
308549Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
318549Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
328549Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
338549Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
348549Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
358549Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
368549Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
378549Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
388549Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
398549Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
408549Sjkh * SUCH DAMAGE.
418549Sjkh *
428549Sjkh */
438549Sjkh
448549Sjkh#include "sysinstall.h"
458549Sjkh#include <ctype.h>
468549Sjkh#include <sys/disklabel.h>
478549Sjkh
488549Sjkh/*
498549Sjkh * Everything to do with editing the contents of disk labels.
508549Sjkh */
518549Sjkh
528549Sjkh/* A nice message we use a lot in the disklabel editor */
538549Sjkh#define MSG_NOT_APPLICABLE	"That option is not applicable here"
548549Sjkh
558549Sjkh/*
568549Sjkh * I make some pretty gross assumptions about having a max of 50 chunks
578549Sjkh * total - 8 slices and 42 partitions.  I can't easily display many more
588549Sjkh * than that on the screen at once!
598549Sjkh *
608549Sjkh * For 2.1 I'll revisit this and try to make it more dynamic, but since
618549Sjkh * this will catch 99.99% of all possible cases, I'm not too worried.
628549Sjkh */
638549Sjkh#define MAX_CHUNKS	50
648549Sjkh
658549Sjkh/* Where to start printing the freebsd slices */
668549Sjkh#define CHUNK_SLICE_START_ROW		2
678549Sjkh#define CHUNK_PART_START_ROW		10
688549Sjkh
698549Sjkh/* The smallest filesystem we're willing to create */
708549Sjkh#define FS_MIN_SIZE			2048
718549Sjkh
728549Sjkh
738549Sjkh/* All the chunks currently displayed on the screen */
748549Sjkhstatic struct {
758549Sjkh    struct disk *d;
768549Sjkh    struct chunk *c;
778549Sjkh    PartType type;
788549Sjkh} label_chunk_info[MAX_CHUNKS + 1];
798549Sjkhstatic int here;
808549Sjkh
818549Sjkh/* See if we're already using a desired partition name */
828549Sjkhstatic Boolean
838549Sjkhcheck_conflict(char *name)
848549Sjkh{
858549Sjkh    int i;
868549Sjkh
878549Sjkh    for (i = 0; label_chunk_info[i].d; i++)
888549Sjkh	if (label_chunk_info[i].type == PART_FILESYSTEM
898549Sjkh	    && label_chunk_info[i].c->private
908549Sjkh	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private)->mountpoint, name))
918549Sjkh	    return TRUE;
928549Sjkh    return FALSE;
938549Sjkh}
948549Sjkh
958549Sjkh/* How much space is in this FreeBSD slice? */
968549Sjkhstatic int
978549Sjkhspace_free(struct chunk *c)
988549Sjkh{
998549Sjkh    struct chunk *c1 = c->part;
1008549Sjkh    int sz = c->size;
1018549Sjkh
1028549Sjkh    while (c1) {
1038549Sjkh	if (c1->type != unused)
1048549Sjkh	    sz -= c1->size;
1058549Sjkh	c1 = c1->next;
1068549Sjkh    }
1078549Sjkh    if (sz < 0)
1088549Sjkh	msgFatal("Partitions are larger than actual chunk??");
1098549Sjkh    return sz;
1108549Sjkh}
1118549Sjkh
1128549Sjkh/* Snapshot the current situation into the displayed chunks structure */
1138549Sjkhstatic void
1148549Sjkhrecord_label_chunks()
1158549Sjkh{
1168549Sjkh    int i, j, p;
1178549Sjkh    struct chunk *c1, *c2;
1188549Sjkh    Device **devs;
1198549Sjkh
1208549Sjkh    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1218549Sjkh    if (!devs) {
1228549Sjkh	msgConfirm("No disks found!");
1238549Sjkh	return;
1248549Sjkh    }
1258549Sjkh
1268549Sjkh    j = p = 0;
1278549Sjkh    for (i = 0; devs[i]; i++) {
1288549Sjkh	if (!((Disk *)devs[i]->private)->chunks)
1298549Sjkh	    msgFatal("No chunk list found for %s!", ((Disk *)devs[i]->private)->name);
1308549Sjkh
1318549Sjkh	/* Put the freebsd chunks first */
1328549Sjkh	for (c1 = ((Disk *)devs[i]->private)->chunks->part; c1; c1 = c1->next) {
1338549Sjkh	    if (c1->type == freebsd) {
1348549Sjkh		label_chunk_info[j].type = PART_SLICE;
1358549Sjkh		label_chunk_info[j].d = ((Disk *)devs[i]->private);
1368549Sjkh		label_chunk_info[j].c = c1;
1378549Sjkh		++j;
1388549Sjkh	    }
1398549Sjkh	}
1408549Sjkh    }
1418549Sjkh    for (i = 0; ((Disk *)devs[i]->private); i++) {
1428549Sjkh	/* Then buzz through and pick up the partitions */
1438549Sjkh	for (c1 = ((Disk *)devs[i]->private)->chunks->part; c1; c1 = c1->next) {
1448549Sjkh	    if (c1->type == freebsd) {
1458549Sjkh		for (c2 = c1->part; c2; c2 = c2->next) {
1468549Sjkh		    if (c2->type == part) {
1478549Sjkh			if (c2->subtype == FS_SWAP)
1488549Sjkh			    label_chunk_info[j].type = PART_SWAP;
1498549Sjkh			else
1508549Sjkh			    label_chunk_info[j].type = PART_FILESYSTEM;
1518549Sjkh			label_chunk_info[j].d = ((Disk *)devs[i]->private);
1528549Sjkh			label_chunk_info[j].c = c2;
1538549Sjkh			++j;
1548549Sjkh		    }
1558549Sjkh		}
1568549Sjkh	    }
1578549Sjkh	    else if (c1->type == fat) {
1588549Sjkh		label_chunk_info[j].type = PART_FAT;
1598549Sjkh		label_chunk_info[j].d = ((Disk *)devs[i]->private);
1608549Sjkh		label_chunk_info[j].c = c1;
1618549Sjkh	    }
1628549Sjkh	}
1638549Sjkh    }
1648549Sjkh    label_chunk_info[j].d = NULL;
1658549Sjkh    label_chunk_info[j].c = NULL;
1668549Sjkh    if (here >= j)
1678549Sjkh	here = j  ? j - 1 : 0;
1688549Sjkh}
1698549Sjkh
1708549Sjkh/* A new partition entry */
1718549Sjkhstatic PartInfo *
1728549Sjkhnew_part(char *mpoint, Boolean newfs)
1738549Sjkh{
1748549Sjkh    PartInfo *ret;
1758549Sjkh
1768549Sjkh    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
1778549Sjkh    strncpy(ret->mountpoint, mpoint, FILENAME_MAX);
1788549Sjkh    strcpy(ret->newfs_cmd, "newfs");
1798549Sjkh    ret->newfs = newfs;
1808549Sjkh    return ret;
1818549Sjkh}
1828549Sjkh
1838549Sjkh/* Get the mountpoint for a partition and save it away */
1848549SjkhPartInfo *
1858549Sjkhget_mountpoint(struct chunk *parent, struct chunk *me)
1868549Sjkh{
1878549Sjkh    char *val;
1888549Sjkh    PartInfo *tmp;
1898549Sjkh
1908549Sjkh    val = msgGetInput(me && me->private ? ((PartInfo *)me->private)->mountpoint : NULL,
1918549Sjkh		      "Please specify a mount point for the partition");
1928549Sjkh    if (val) {
1938549Sjkh	/* Is it just the same value? */
1948549Sjkh	if (me && me->private && !strcmp(((PartInfo *)me->private)->mountpoint, val))
1958549Sjkh	    return NULL;
1968549Sjkh	if (check_conflict(val)) {
1978549Sjkh	    msgConfirm("You already have a mount point for %s assigned!", val);
1988549Sjkh	    return NULL;
1998549Sjkh	}
2008549Sjkh	else if (*val != '/') {
2018549Sjkh	    msgConfirm("Mount point must start with a / character");
2028549Sjkh	    return NULL;
2038549Sjkh	}
2048549Sjkh	else if (!strcmp(val, "/")) {
2058549Sjkh	    if (parent) {
2068549Sjkh	    	if (parent->flags & CHUNK_PAST_1024) {
2078549Sjkh		    msgConfirm("This region cannot be used for your root partition as\nit is past the 1024'th cylinder mark and the system would not be\nable to boot from it.  Please pick another location for your\nroot partition and try again!");
2088549Sjkh		    return NULL;
2098549Sjkh		}
2108549Sjkh		else if (!(parent->flags & CHUNK_BSD_COMPAT)) {
2118549Sjkh		    msgConfirm("This region cannot be used for your root partition as\nthe FreeBSD boot code cannot deal with a root partition created in\nsuch a region.  Please choose another partition for this.");
2128549Sjkh		    return NULL;
2138549Sjkh		}
2148549Sjkh	    }
2158549Sjkh	    if (me)
2168549Sjkh		me->flags |= CHUNK_IS_ROOT;
2178549Sjkh	}
2188549Sjkh	else if (me)
2198549Sjkh	    me->flags &= ~CHUNK_IS_ROOT;
2208549Sjkh	safe_free(me ? me->private : NULL);
2218549Sjkh	tmp = new_part(val, TRUE);
2228549Sjkh	if (me) {
2238549Sjkh	    me->private = tmp;
2248549Sjkh	    me->private_free = safe_free;
2258549Sjkh	}
2268549Sjkh	return tmp;
2278549Sjkh    }
2288549Sjkh    return NULL;
2298549Sjkh}
2308549Sjkh
2318549Sjkh/* Get the type of the new partiton */
2328549Sjkhstatic PartType
2338549Sjkhget_partition_type(void)
2348549Sjkh{
2358549Sjkh    char selection[20];
2368549Sjkh    static unsigned char *fs_types[] = {
2378549Sjkh	"FS",
2388549Sjkh	"A file system",
2398549Sjkh	"Swap",
2408549Sjkh	"A swap partition.",
2418549Sjkh    };
2428549Sjkh
2438549Sjkh    if (!dialog_menu("Please choose a partition type",
2448549Sjkh		    "If you want to use this partition for swap space, select Swap.\nIf you want to put a filesystem on it, choose FS.", -1, -1, 2, 2, fs_types, selection, NULL, NULL)) {
2458549Sjkh	if (!strcmp(selection, "FS"))
2468549Sjkh	    return PART_FILESYSTEM;
2478549Sjkh	else if (!strcmp(selection, "Swap"))
2488549Sjkh	    return PART_SWAP;
2498549Sjkh    }
2508549Sjkh    return PART_NONE;
2518549Sjkh}
2528549Sjkh
2538549Sjkh/* If the user wants a special newfs command for this, set it */
2548549Sjkhstatic void
2558549SjkhgetNewfsCmd(PartInfo *p)
2568549Sjkh{
2578549Sjkh    char *val;
2588549Sjkh
2598549Sjkh    val = msgGetInput(p->newfs_cmd,
2608549Sjkh		      "Please enter the newfs command and options you'd like to use in\ncreating this file system.");
2618549Sjkh    if (val)
2628549Sjkh	strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
2638549Sjkh}
2648549Sjkh
2658549Sjkh
2668549Sjkh#define MAX_MOUNT_NAME	12
2678549Sjkh
2688549Sjkh#define PART_PART_COL	0
2698549Sjkh#define PART_MOUNT_COL	8
2708549Sjkh#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
2718549Sjkh#define PART_NEWFS_COL	(PART_SIZE_COL + 7)
2728549Sjkh#define PART_OFF	38
2738549Sjkh
2748549Sjkh/* How many mounted partitions to display in column before going to next */
2758549Sjkh#define CHUNK_COLUMN_MAX	6
2768549Sjkh
2778549Sjkh/* stick this all up on the screen */
2788549Sjkhstatic void
2798549Sjkhprint_label_chunks(void)
2808549Sjkh{
2818549Sjkh    int i, j, srow, prow, pcol;
2828549Sjkh    int sz;
2838549Sjkh
2848549Sjkh    attrset(A_REVERSE);
2858549Sjkh    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
2868549Sjkh    attrset(A_NORMAL);
2878549Sjkh
2888549Sjkh    for (i = 0; i < 2; i++) {
2898549Sjkh	attrset(A_UNDERLINE);
2908549Sjkh	mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF),
2918549Sjkh		 "Part");
2928549Sjkh	attrset(A_NORMAL);
2938549Sjkh
2948549Sjkh	attrset(A_UNDERLINE);
2958549Sjkh	mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF),
2968549Sjkh		 "Mount");
2978549Sjkh	attrset(A_NORMAL);
2988549Sjkh
2998549Sjkh	attrset(A_UNDERLINE);
3008549Sjkh	mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2,
3018549Sjkh		 "Size");
3028549Sjkh	attrset(A_NORMAL);
3038549Sjkh
3048549Sjkh	attrset(A_UNDERLINE);
3058549Sjkh	mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF),
3068549Sjkh		 "Newfs");
3078549Sjkh	attrset(A_NORMAL);
3088549Sjkh    }
3098549Sjkh
3108549Sjkh    srow = CHUNK_SLICE_START_ROW;
3118549Sjkh    prow = CHUNK_PART_START_ROW;
3128549Sjkh    pcol = 0;
3138549Sjkh
3148549Sjkh    for (i = 0; label_chunk_info[i].d; i++) {
3158549Sjkh	if (i == here)
3168549Sjkh	    attrset(A_REVERSE);
3178549Sjkh	/* Is it a slice entry displayed at the top? */
3188549Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
3198549Sjkh	    sz = space_free(label_chunk_info[i].c);
3208549Sjkh	    mvprintw(srow++, 0,
3218549Sjkh		     "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
3228549Sjkh		     label_chunk_info[i].d->name,
3238549Sjkh		     label_chunk_info[i].c->name, sz, (sz / 2048));
3248549Sjkh	}
3258549Sjkh	/* Otherwise it's a DOS, swap or filesystem entry, at the bottom */
3268549Sjkh	else {
3278549Sjkh	    char onestr[PART_OFF], num[10], *mountpoint, *newfs;
3288549Sjkh
3298549Sjkh	    /*
3308549Sjkh	     * We copy this into a blank-padded string so that it looks like
3318549Sjkh	     * a solid bar in reverse-video
3328549Sjkh	     */
3338549Sjkh	    memset(onestr, ' ', PART_OFF - 1);
3348549Sjkh	    onestr[PART_OFF - 1] = '\0';
3358549Sjkh	    /* Go for two columns */
3368549Sjkh	    if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) {
3378549Sjkh		pcol = PART_OFF;
3388549Sjkh		prow = CHUNK_PART_START_ROW;
3398549Sjkh	    }
3408549Sjkh	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name,
3418549Sjkh		   strlen(label_chunk_info[i].c->name));
3428549Sjkh	    /* If it's a filesystem, display the mountpoint */
3438549Sjkh	    if (label_chunk_info[i].type == PART_FILESYSTEM) {
3448549Sjkh		if (label_chunk_info[i].c->private == NULL) {
3458549Sjkh		    static int mnt = 0;
3468549Sjkh		    char foo[10];
3478549Sjkh
3488549Sjkh		    /*
3498549Sjkh		     * Hmm!  A partition that must have already been here.
3508549Sjkh		     * Fill in a fake mountpoint and register it
3518549Sjkh		     */
3528549Sjkh		    sprintf(foo, "/mnt%d", mnt++);
3538549Sjkh		    label_chunk_info[i].c->private = new_part(foo, FALSE);
3548549Sjkh		    label_chunk_info[i].c->private_free = safe_free;
3558549Sjkh		}
3568549Sjkh		mountpoint = ((PartInfo *)label_chunk_info[i].c->private)->mountpoint;
3578549Sjkh		newfs = ((PartInfo *)label_chunk_info[i].c->private)->newfs ? "Y" : "N";
3588549Sjkh	    }
3598549Sjkh	    else if (label_chunk_info[i].type == PART_SWAP) {
3608549Sjkh		mountpoint = "swap";
3618549Sjkh		newfs = " ";
3628549Sjkh	    }
3638549Sjkh	    else if (label_chunk_info[i].type == PART_FAT) {
3648549Sjkh		mountpoint = "DOS FAT";
3658549Sjkh		newfs = "*";
3668549Sjkh	    }
3678549Sjkh	    else {
3688549Sjkh		mountpoint = "<unknown>";
3698549Sjkh		newfs = "*";
3708549Sjkh	    }
3718549Sjkh	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
3728549Sjkh		onestr[PART_MOUNT_COL + j] = mountpoint[j];
3738549Sjkh	    snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ?
3748549Sjkh		    label_chunk_info[i].c->size / 2048 : 0);
3758549Sjkh	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
3768549Sjkh	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
3778549Sjkh	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
3788549Sjkh	    mvaddstr(prow, pcol, onestr);
3798549Sjkh	    ++prow;
3808549Sjkh	}
3818549Sjkh	if (i == here)
3828549Sjkh	    attrset(A_NORMAL);
3838549Sjkh    }
3848549Sjkh}
3858549Sjkh
3868549Sjkhstatic void
3878549Sjkhprint_command_summary()
3888549Sjkh{
3898549Sjkh    mvprintw(17, 0,
3908549Sjkh	     "The following commands are valid here (upper or lower case):");
3918549Sjkh    mvprintw(19, 0, "C = Create Partition   D = Delete Partition   M = Mount Partition");
3928549Sjkh    mvprintw(20, 0, "N = Newfs Options      T = Toggle Newfs       ESC = Finish Partitioning");
3938549Sjkh    mvprintw(21, 0, "The default target will be displayed in ");
3948549Sjkh
3958549Sjkh    attrset(A_REVERSE);
3968549Sjkh    addstr("reverse video.");
3978549Sjkh    attrset(A_NORMAL);
3988549Sjkh    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to move.");
3998549Sjkh    move(0, 0);
4008549Sjkh}
4018549Sjkh
4028549Sjkhvoid
4038549SjkhdiskLabelEditor(char *str)
4048549Sjkh{
4058549Sjkh    int sz, key = 0;
4068549Sjkh    Boolean labeling;
4078549Sjkh    char *msg = NULL;
4088549Sjkh    PartInfo *p;
4098549Sjkh    PartType type;
4108549Sjkh
4118549Sjkh    dialog_clear();
4128549Sjkh    labeling = TRUE;
4138549Sjkh    keypad(stdscr, TRUE);
4148549Sjkh    record_label_chunks();
4158549Sjkh
4168549Sjkh    while (labeling) {
4178549Sjkh	clear();
4188549Sjkh	print_label_chunks();
4198549Sjkh	print_command_summary();
4208549Sjkh	if (msg) {
4218549Sjkh	    attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL);
4228549Sjkh	    beep();
4238549Sjkh	    msg = NULL;
4248549Sjkh	}
4258549Sjkh	refresh();
4268549Sjkh	key = toupper(getch());
4278549Sjkh	switch (key) {
4288549Sjkh
4298549Sjkh	case KEY_UP:
4308549Sjkh	case '-':
4318549Sjkh	    if (here != 0)
4328549Sjkh		--here;
4338549Sjkh	    break;
4348549Sjkh
4358549Sjkh	case KEY_DOWN:
4368549Sjkh	case '+':
4378549Sjkh	case '\r':
4388549Sjkh	case '\n':
4398549Sjkh	    if (label_chunk_info[here + 1].d)
4408549Sjkh		++here;
4418549Sjkh	    break;
4428549Sjkh
4438549Sjkh	case KEY_HOME:
4448549Sjkh	    here = 0;
4458549Sjkh	    break;
4468549Sjkh
4478549Sjkh	case KEY_END:
4488549Sjkh	    while (label_chunk_info[here + 1].d)
4498549Sjkh		++here;
4508549Sjkh	    break;
4518549Sjkh
4528549Sjkh	case KEY_F(1):
4538549Sjkh	case '?':
4548549Sjkh	    systemDisplayFile("disklabel.hlp");
4558549Sjkh	    break;
4568549Sjkh
4578549Sjkh	case 'C':
4588549Sjkh	    if (label_chunk_info[here].type != PART_SLICE) {
4598549Sjkh		msg = "You can only do this in a master partition (see top of screen)";
4608549Sjkh		break;
4618549Sjkh	    }
4628549Sjkh	    sz = space_free(label_chunk_info[here].c);
4638549Sjkh	    if (sz <= FS_MIN_SIZE)
4648549Sjkh		msg = "Not enough space to create additional FreeBSD partition";
4658549Sjkh	    else {
4668549Sjkh		char *val, *cp, tmp[20];
4678549Sjkh		int size;
4688549Sjkh
4698549Sjkh		snprintf(tmp, 20, "%d", sz);
4708549Sjkh		val = msgGetInput(tmp, "Please specify the size for new FreeBSD partition in blocks, or append\na trailing `M' for megabytes (e.g. 20M).");
4718549Sjkh		if (val && (size = strtol(val, &cp, 0)) > 0) {
4728549Sjkh		    struct chunk *tmp;
4738549Sjkh		    u_long flags = 0;
4748549Sjkh
4758549Sjkh		    if (*cp && toupper(*cp) == 'M')
4768549Sjkh			size *= 2048;
4778549Sjkh
4788549Sjkh		    type = get_partition_type();
4798549Sjkh		    if (type == PART_NONE)
4808549Sjkh			break;
4818549Sjkh		    else if (type == PART_FILESYSTEM) {
4828549Sjkh			if ((p = get_mountpoint(label_chunk_info[here].c, NULL)) == NULL)
4838549Sjkh			    break;
4848549Sjkh			else if (!strcmp(p->mountpoint, "/"))
4858549Sjkh			    flags |= CHUNK_IS_ROOT;
4868549Sjkh			else
4878549Sjkh			    flags &= ~CHUNK_IS_ROOT;
4888549Sjkh		    }
4898549Sjkh		    else
4908549Sjkh			p = NULL;
4918549Sjkh
4928549Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].d,
4938549Sjkh					    label_chunk_info[here].c,
4948549Sjkh					    size, part,
4958549Sjkh					    (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
4968549Sjkh					    flags);
4978549Sjkh		    if (!tmp)
4988549Sjkh			msgConfirm("Unable to create the partition. Too big?");
4998549Sjkh		    else {
5008549Sjkh			tmp->private = p;
5018549Sjkh			tmp->private_free = safe_free;
5028549Sjkh			record_label_chunks();
5038549Sjkh		    }
5048549Sjkh		}
5058549Sjkh	    }
5068549Sjkh	    break;
5078549Sjkh
5088549Sjkh	case 'D':	/* delete */
5098549Sjkh	    if (label_chunk_info[here].type == PART_SLICE) {
5108549Sjkh		msg = MSG_NOT_APPLICABLE;
5118549Sjkh		break;
5128549Sjkh	    }
5138549Sjkh	    else if (label_chunk_info[here].type == PART_FAT) {
5148549Sjkh		msg = "Use the Disk Partition Editor to delete this";
5158549Sjkh		break;
5168549Sjkh	    }
5178549Sjkh	    Delete_Chunk(label_chunk_info[here].d, label_chunk_info[here].c);
5188549Sjkh	    record_label_chunks();
5198549Sjkh	    break;
5208549Sjkh
5218549Sjkh	case 'M':	/* mount */
5228549Sjkh	    switch(label_chunk_info[here].type) {
5238549Sjkh	    case PART_SLICE:
5248549Sjkh		msg = MSG_NOT_APPLICABLE;
5258549Sjkh		break;
5268549Sjkh
5278549Sjkh	    case PART_SWAP:
5288549Sjkh		msg = "You don't need to specify a mountpoint for a swap partition.";
5298549Sjkh		break;
5308549Sjkh
5318549Sjkh	    case PART_DOS:
5328549Sjkh	    case PART_FILESYSTEM:
5338549Sjkh		p = get_mountpoint(NULL, label_chunk_info[here].c);
5348549Sjkh		if (p) {
5358549Sjkh		    p->newfs = FALSE;
5368549Sjkh		    record_label_chunks();
5378549Sjkh		}
5388549Sjkh		break;
5398549Sjkh
5408549Sjkh	    default:
5418549Sjkh		msgFatal("Bogus partition under cursor???");
5428549Sjkh		break;
5438549Sjkh	    }
5448549Sjkh	    break;
5458549Sjkh
5468549Sjkh	case 'N':	/* Set newfs options */
5478549Sjkh	    if (label_chunk_info[here].c->private &&
5488549Sjkh		((PartInfo *)label_chunk_info[here].c->private)->newfs)
5498549Sjkh		getNewfsCmd(label_chunk_info[here].c->private);
5508549Sjkh	    else
5518549Sjkh		msg = MSG_NOT_APPLICABLE;
5528549Sjkh	    break;
5538549Sjkh
5548549Sjkh	case 'T':	/* Toggle newfs state */
5558549Sjkh	    if (label_chunk_info[here].type == PART_FILESYSTEM &&
5568549Sjkh		label_chunk_info[here].c->private)
5578549Sjkh		((PartInfo *)label_chunk_info[here].c->private)->newfs =
5588549Sjkh		    !((PartInfo *)label_chunk_info[here].c->private)->newfs;
5598549Sjkh	    else
5608549Sjkh		msg = MSG_NOT_APPLICABLE;
5618549Sjkh	    break;
5628549Sjkh
5638549Sjkh	case 'W':
5648549Sjkh	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\nThis is an entirely undocumented feature which you are not\nexpected to understand!")) {
5658549Sjkh		int i;
5668549Sjkh		Device **devs;
5678549Sjkh
5688549Sjkh		clear();
5698549Sjkh		dialog_clear();
5708549Sjkh		end_dialog();
5718549Sjkh		DialogActive = FALSE;
5728549Sjkh		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
5738549Sjkh		if (!devs) {
5748549Sjkh		    msgConfirm("Can't find any disk devicse!");
5758549Sjkh		    break;
5768549Sjkh		}
5778549Sjkh		for (i = 0; ((Disk *)devs[i]->private); i++)
5788549Sjkh		    slice_wizard(((Disk *)devs[i]->private));
5798549Sjkh		clear();
5808549Sjkh		dialog_clear();
5818549Sjkh		DialogActive = TRUE;
5828549Sjkh		record_label_chunks();
5838549Sjkh	    }
5848549Sjkh	    else
5858549Sjkh		msg = "A most prudent choice!";
5868549Sjkh	    break;
5878549Sjkh
5888549Sjkh	case 27:	/* ESC */
5898549Sjkh	    labeling = FALSE;
5908549Sjkh	    break;
5918549Sjkh
5928549Sjkh	default:
5938549Sjkh	    beep();
5948549Sjkh	    msg = "Type F1 or ? for help";
5958549Sjkh	    break;
5968549Sjkh	}
5978549Sjkh    }
5988549Sjkh    variable_set2(DISK_LABELLED, "yes");
5998549Sjkh}
6008549Sjkh
6018549Sjkh
6028549Sjkh
603