label.c revision 8810
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 *
78810Sjkh * $Id: label.c,v 1.26 1995/05/26 11:21:46 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/* Where to start printing the freebsd slices */
568549Sjkh#define CHUNK_SLICE_START_ROW		2
578622Sjkh#define CHUNK_PART_START_ROW		11
588549Sjkh
598702Sjkh/* One MB worth of blocks */
608702Sjkh#define ONE_MEG				2048
618702Sjkh
628549Sjkh/* The smallest filesystem we're willing to create */
638702Sjkh#define FS_MIN_SIZE			ONE_MEG
648549Sjkh
658672Sjkh/* The smallest root filesystem we're willing to create */
668702Sjkh#define ROOT_MIN_SIZE			(20 * ONE_MEG)
678549Sjkh
688549Sjkh/* All the chunks currently displayed on the screen */
698549Sjkhstatic struct {
708549Sjkh    struct chunk *c;
718549Sjkh    PartType type;
728549Sjkh} label_chunk_info[MAX_CHUNKS + 1];
738549Sjkhstatic int here;
748549Sjkh
758549Sjkh/* See if we're already using a desired partition name */
768549Sjkhstatic Boolean
778549Sjkhcheck_conflict(char *name)
788549Sjkh{
798549Sjkh    int i;
808549Sjkh
818751Sjkh    for (i = 0; label_chunk_info[i].c; i++)
828549Sjkh	if (label_chunk_info[i].type == PART_FILESYSTEM
838549Sjkh	    && label_chunk_info[i].c->private
848549Sjkh	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private)->mountpoint, name))
858549Sjkh	    return TRUE;
868549Sjkh    return FALSE;
878549Sjkh}
888549Sjkh
898549Sjkh/* How much space is in this FreeBSD slice? */
908549Sjkhstatic int
918549Sjkhspace_free(struct chunk *c)
928549Sjkh{
938549Sjkh    struct chunk *c1 = c->part;
948549Sjkh    int sz = c->size;
958549Sjkh
968549Sjkh    while (c1) {
978549Sjkh	if (c1->type != unused)
988549Sjkh	    sz -= c1->size;
998549Sjkh	c1 = c1->next;
1008549Sjkh    }
1018549Sjkh    if (sz < 0)
1028549Sjkh	msgFatal("Partitions are larger than actual chunk??");
1038549Sjkh    return sz;
1048549Sjkh}
1058549Sjkh
1068549Sjkh/* Snapshot the current situation into the displayed chunks structure */
1078549Sjkhstatic void
1088549Sjkhrecord_label_chunks()
1098549Sjkh{
1108549Sjkh    int i, j, p;
1118549Sjkh    struct chunk *c1, *c2;
1128549Sjkh    Device **devs;
1138556Sjkh    Disk *d;
1148549Sjkh
1158549Sjkh    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1168549Sjkh    if (!devs) {
1178549Sjkh	msgConfirm("No disks found!");
1188549Sjkh	return;
1198549Sjkh    }
1208549Sjkh
1218549Sjkh    j = p = 0;
1228556Sjkh    /* First buzz through and pick up the FreeBSD slices */
1238549Sjkh    for (i = 0; devs[i]; i++) {
1248556Sjkh	if (!devs[i]->enabled)
1258556Sjkh	    continue;
1268556Sjkh	d = (Disk *)devs[i]->private;
1278556Sjkh	if (!d->chunks)
1288556Sjkh	    msgFatal("No chunk list found for %s!", d->name);
1298549Sjkh
1308556Sjkh	/* Put the slice entries first */
1318556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
1328549Sjkh	    if (c1->type == freebsd) {
1338549Sjkh		label_chunk_info[j].type = PART_SLICE;
1348549Sjkh		label_chunk_info[j].c = c1;
1358549Sjkh		++j;
1368549Sjkh	    }
1378549Sjkh	}
1388549Sjkh    }
1398556Sjkh    /* Now run through again and get the FreeBSD partition entries */
1408556Sjkh    for (i = 0; devs[i]; i++) {
1418556Sjkh	if (!devs[i]->enabled)
1428556Sjkh	    continue;
1438556Sjkh	d = (Disk *)devs[i]->private;
1448549Sjkh	/* Then buzz through and pick up the partitions */
1458556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
1468549Sjkh	    if (c1->type == freebsd) {
1478549Sjkh		for (c2 = c1->part; c2; c2 = c2->next) {
1488549Sjkh		    if (c2->type == part) {
1498549Sjkh			if (c2->subtype == FS_SWAP)
1508549Sjkh			    label_chunk_info[j].type = PART_SWAP;
1518549Sjkh			else
1528549Sjkh			    label_chunk_info[j].type = PART_FILESYSTEM;
1538549Sjkh			label_chunk_info[j].c = c2;
1548549Sjkh			++j;
1558549Sjkh		    }
1568549Sjkh		}
1578549Sjkh	    }
1588549Sjkh	    else if (c1->type == fat) {
1598549Sjkh		label_chunk_info[j].type = PART_FAT;
1608549Sjkh		label_chunk_info[j].c = c1;
1618702Sjkh		++j;
1628549Sjkh	    }
1638549Sjkh	}
1648549Sjkh    }
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 *
1728665Sphknew_part(char *mpoint, Boolean newfs, u_long size)
1738549Sjkh{
1748549Sjkh    PartInfo *ret;
1758666Sphk    u_long target,divisor;
1768549Sjkh
1778549Sjkh    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
1788549Sjkh    strncpy(ret->mountpoint, mpoint, FILENAME_MAX);
1798549Sjkh    strcpy(ret->newfs_cmd, "newfs");
1808666Sphk    ret->newfs = newfs;
1818669Sphk    if (!size)
1828669Sphk	    return ret;
1838666Sphk    for(target = size; target; target--) {
1848666Sphk	for(divisor = 4096 ; divisor > 1023; divisor--) {
1858666Sphk	    if (!(target % divisor)) {
1868666Sphk		sprintf(ret->newfs_cmd+strlen(ret->newfs_cmd),
1878666Sphk		    " -u %ld",divisor);
1888666Sphk		return ret;
1898666Sphk	    }
1908665Sphk	}
1918665Sphk    }
1928549Sjkh    return ret;
1938549Sjkh}
1948549Sjkh
1958549Sjkh/* Get the mountpoint for a partition and save it away */
1968549SjkhPartInfo *
1978589Sjkhget_mountpoint(struct chunk *old)
1988549Sjkh{
1998549Sjkh    char *val;
2008549Sjkh    PartInfo *tmp;
2018549Sjkh
2028810Sjkh    if (old && old->private)
2038810Sjkh	tmp = old->private;
2048810Sjkh    else
2058810Sjkh	tmp = NULL;
2068810Sjkh    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
2078764Sjkh    if (!val || !*val) {
2088751Sjkh	if (!old)
2098751Sjkh	    return NULL;
2108751Sjkh	else {
2118751Sjkh	    free(old->private);
2128751Sjkh	    old->private = NULL;
2138751Sjkh	}
2148669Sphk	return NULL;
2158751Sjkh    }
2168669Sphk
2178669Sphk    /* Is it just the same value? */
2188810Sjkh    if (tmp && !strcmp(tmp->mountpoint, val))
2198669Sphk	return NULL;
2208810Sjkh
2218810Sjkh    /* Did we use it already? */
2228669Sphk    if (check_conflict(val)) {
2238669Sphk	msgConfirm("You already have a mount point for %s assigned!", val);
2248669Sphk	return NULL;
2258549Sjkh    }
2268810Sjkh
2278810Sjkh    /* Is it bogus? */
2288669Sphk    if (*val != '/') {
2298669Sphk	msgConfirm("Mount point must start with a / character");
2308669Sphk	return NULL;
2318669Sphk    }
2328810Sjkh
2338810Sjkh    /* Is it going to be mounted on root? */
2348669Sphk    if (!strcmp(val, "/")) {
2358669Sphk	if (old)
2368669Sphk	    old->flags |= CHUNK_IS_ROOT;
2378810Sjkh    }
2388810Sjkh    else if (old)
2398669Sphk	old->flags &= ~CHUNK_IS_ROOT;
2408810Sjkh
2418810Sjkh    safe_free(tmp);
2428669Sphk    tmp = new_part(val, TRUE, 0);
2438669Sphk    if (old) {
2448669Sphk	old->private = tmp;
2458669Sphk	old->private_free = safe_free;
2468669Sphk    }
2478669Sphk    return tmp;
2488549Sjkh}
2498549Sjkh
2508549Sjkh/* Get the type of the new partiton */
2518549Sjkhstatic PartType
2528549Sjkhget_partition_type(void)
2538549Sjkh{
2548549Sjkh    char selection[20];
2558669Sphk    int i;
2568669Sphk
2578549Sjkh    static unsigned char *fs_types[] = {
2588549Sjkh	"FS",
2598549Sjkh	"A file system",
2608549Sjkh	"Swap",
2618549Sjkh	"A swap partition.",
2628549Sjkh    };
2638669Sphk    i = dialog_menu("Please choose a partition type",
2648669Sphk		    "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);
2658669Sphk    if (!i) {
2668549Sjkh	if (!strcmp(selection, "FS"))
2678549Sjkh	    return PART_FILESYSTEM;
2688549Sjkh	else if (!strcmp(selection, "Swap"))
2698549Sjkh	    return PART_SWAP;
2708549Sjkh    }
2718549Sjkh    return PART_NONE;
2728549Sjkh}
2738549Sjkh
2748549Sjkh/* If the user wants a special newfs command for this, set it */
2758549Sjkhstatic void
2768549SjkhgetNewfsCmd(PartInfo *p)
2778549Sjkh{
2788549Sjkh    char *val;
2798549Sjkh
2808549Sjkh    val = msgGetInput(p->newfs_cmd,
2818549Sjkh		      "Please enter the newfs command and options you'd like to use in\ncreating this file system.");
2828549Sjkh    if (val)
2838549Sjkh	strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
2848549Sjkh}
2858549Sjkh
2868549Sjkh
2878549Sjkh#define MAX_MOUNT_NAME	12
2888549Sjkh
2898549Sjkh#define PART_PART_COL	0
2908549Sjkh#define PART_MOUNT_COL	8
2918549Sjkh#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
2928549Sjkh#define PART_NEWFS_COL	(PART_SIZE_COL + 7)
2938549Sjkh#define PART_OFF	38
2948549Sjkh
2958549Sjkh/* How many mounted partitions to display in column before going to next */
2968622Sjkh#define CHUNK_COLUMN_MAX	5
2978549Sjkh
2988549Sjkh/* stick this all up on the screen */
2998549Sjkhstatic void
3008549Sjkhprint_label_chunks(void)
3018549Sjkh{
3028549Sjkh    int i, j, srow, prow, pcol;
3038549Sjkh    int sz;
3048549Sjkh
3058549Sjkh    attrset(A_REVERSE);
3068549Sjkh    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
3078669Sphk    clrtobot();
3088549Sjkh    attrset(A_NORMAL);
3098549Sjkh
3108549Sjkh    for (i = 0; i < 2; i++) {
3118622Sjkh	mvaddstr(CHUNK_PART_START_ROW - 2, PART_PART_COL + (i * PART_OFF), "Part");
3128622Sjkh	mvaddstr(CHUNK_PART_START_ROW - 1, PART_PART_COL + (i * PART_OFF), "----");
3138549Sjkh
3148622Sjkh	mvaddstr(CHUNK_PART_START_ROW - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
3158622Sjkh	mvaddstr(CHUNK_PART_START_ROW - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
3168549Sjkh
3178622Sjkh	mvaddstr(CHUNK_PART_START_ROW - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
3188622Sjkh	mvaddstr(CHUNK_PART_START_ROW - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
3198549Sjkh
3208622Sjkh	mvaddstr(CHUNK_PART_START_ROW - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
3218622Sjkh	mvaddstr(CHUNK_PART_START_ROW - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
3228549Sjkh    }
3238549Sjkh    srow = CHUNK_SLICE_START_ROW;
3248549Sjkh    prow = CHUNK_PART_START_ROW;
3258549Sjkh    pcol = 0;
3268549Sjkh
3278751Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
3288549Sjkh	if (i == here)
3298549Sjkh	    attrset(A_REVERSE);
3308549Sjkh	/* Is it a slice entry displayed at the top? */
3318549Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
3328549Sjkh	    sz = space_free(label_chunk_info[i].c);
3338751Sjkh	    mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
3348751Sjkh		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG));
3358549Sjkh	}
3368549Sjkh	/* Otherwise it's a DOS, swap or filesystem entry, at the bottom */
3378549Sjkh	else {
3388549Sjkh	    char onestr[PART_OFF], num[10], *mountpoint, *newfs;
3398549Sjkh
3408549Sjkh	    /*
3418549Sjkh	     * We copy this into a blank-padded string so that it looks like
3428549Sjkh	     * a solid bar in reverse-video
3438549Sjkh	     */
3448549Sjkh	    memset(onestr, ' ', PART_OFF - 1);
3458549Sjkh	    onestr[PART_OFF - 1] = '\0';
3468549Sjkh	    /* Go for two columns */
3478549Sjkh	    if (prow == (CHUNK_PART_START_ROW + CHUNK_COLUMN_MAX)) {
3488549Sjkh		pcol = PART_OFF;
3498549Sjkh		prow = CHUNK_PART_START_ROW;
3508549Sjkh	    }
3518705Sjkh	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
3528549Sjkh	    /* If it's a filesystem, display the mountpoint */
3538705Sjkh	    if (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) {
3548549Sjkh		if (label_chunk_info[i].c->private == NULL) {
3558549Sjkh		    static int mnt = 0;
3568549Sjkh		    char foo[10];
3578549Sjkh
3588549Sjkh		    /*
3598549Sjkh		     * Hmm!  A partition that must have already been here.
3608549Sjkh		     * Fill in a fake mountpoint and register it
3618549Sjkh		     */
3628549Sjkh		    sprintf(foo, "/mnt%d", mnt++);
3638705Sjkh		    label_chunk_info[i].c->private = new_part(foo, FALSE, label_chunk_info[i].c->size);
3648549Sjkh		    label_chunk_info[i].c->private_free = safe_free;
3658549Sjkh		}
3668549Sjkh		mountpoint = ((PartInfo *)label_chunk_info[i].c->private)->mountpoint;
3678705Sjkh		if (label_chunk_info[i].type == PART_FAT)
3688705Sjkh		    newfs = "DOS";
3698705Sjkh		else
3708705Sjkh		    newfs = ((PartInfo *)label_chunk_info[i].c->private)->newfs ? "Y" : "N";
3718549Sjkh	    }
3728549Sjkh	    else if (label_chunk_info[i].type == PART_SWAP) {
3738549Sjkh		mountpoint = "swap";
3748549Sjkh		newfs = " ";
3758549Sjkh	    }
3768549Sjkh	    else {
3778705Sjkh		mountpoint = "<NONE>";
3788549Sjkh		newfs = "*";
3798549Sjkh	    }
3808549Sjkh	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
3818549Sjkh		onestr[PART_MOUNT_COL + j] = mountpoint[j];
3828764Sjkh	    snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
3838549Sjkh	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
3848549Sjkh	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
3858549Sjkh	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
3868549Sjkh	    mvaddstr(prow, pcol, onestr);
3878549Sjkh	    ++prow;
3888549Sjkh	}
3898549Sjkh	if (i == here)
3908549Sjkh	    attrset(A_NORMAL);
3918549Sjkh    }
3928549Sjkh}
3938549Sjkh
3948549Sjkhstatic void
3958549Sjkhprint_command_summary()
3968549Sjkh{
3978549Sjkh    mvprintw(17, 0,
3988549Sjkh	     "The following commands are valid here (upper or lower case):");
3998549Sjkh    mvprintw(19, 0, "C = Create Partition   D = Delete Partition   M = Mount Partition");
4008556Sjkh    mvprintw(20, 0, "N = Newfs Options      T = Toggle Newfs       ESC = Exit this screen");
4018549Sjkh    mvprintw(21, 0, "The default target will be displayed in ");
4028549Sjkh
4038549Sjkh    attrset(A_REVERSE);
4048751Sjkh    addstr("reverse");
4058549Sjkh    attrset(A_NORMAL);
4068751Sjkh    addstr(" video.");
4078549Sjkh    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to move.");
4088549Sjkh    move(0, 0);
4098549Sjkh}
4108549Sjkh
4118576Sjkhint
4128549SjkhdiskLabelEditor(char *str)
4138549Sjkh{
4148549Sjkh    int sz, key = 0;
4158549Sjkh    Boolean labeling;
4168549Sjkh    char *msg = NULL;
4178549Sjkh    PartInfo *p;
4188549Sjkh    PartType type;
4198549Sjkh
4208549Sjkh    labeling = TRUE;
4218549Sjkh    keypad(stdscr, TRUE);
4228549Sjkh    record_label_chunks();
4238549Sjkh
4248576Sjkh    if (!getenv(DISK_PARTITIONED)) {
4258576Sjkh	msgConfirm("You need to partition your disk(s) before you can assign disk labels.");
4268576Sjkh	return 0;
4278576Sjkh    }
4288702Sjkh    dialog_clear(); clear();
4298549Sjkh    while (labeling) {
4308702Sjkh	clear();
4318549Sjkh	print_label_chunks();
4328549Sjkh	print_command_summary();
4338549Sjkh	if (msg) {
4348549Sjkh	    attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL);
4358549Sjkh	    beep();
4368549Sjkh	    msg = NULL;
4378549Sjkh	}
4388549Sjkh	refresh();
4398549Sjkh	key = toupper(getch());
4408549Sjkh	switch (key) {
4418549Sjkh
4428751Sjkh	case '\014':	/* ^L */
4438751Sjkh	    continue;
4448751Sjkh
4458549Sjkh	case KEY_UP:
4468549Sjkh	case '-':
4478549Sjkh	    if (here != 0)
4488549Sjkh		--here;
4498751Sjkh	    else
4508751Sjkh		while (label_chunk_info[here + 1].c)
4518751Sjkh		    ++here;
4528549Sjkh	    break;
4538549Sjkh
4548549Sjkh	case KEY_DOWN:
4558549Sjkh	case '+':
4568549Sjkh	case '\r':
4578549Sjkh	case '\n':
4588751Sjkh	    if (label_chunk_info[here + 1].c)
4598549Sjkh		++here;
4608751Sjkh	    else
4618751Sjkh		here = 0;
4628549Sjkh	    break;
4638549Sjkh
4648549Sjkh	case KEY_HOME:
4658549Sjkh	    here = 0;
4668549Sjkh	    break;
4678549Sjkh
4688549Sjkh	case KEY_END:
4698751Sjkh	    while (label_chunk_info[here + 1].c)
4708549Sjkh		++here;
4718549Sjkh	    break;
4728549Sjkh
4738549Sjkh	case KEY_F(1):
4748549Sjkh	case '?':
4758549Sjkh	    systemDisplayFile("disklabel.hlp");
4768549Sjkh	    break;
4778549Sjkh
4788549Sjkh	case 'C':
4798549Sjkh	    if (label_chunk_info[here].type != PART_SLICE) {
4808549Sjkh		msg = "You can only do this in a master partition (see top of screen)";
4818549Sjkh		break;
4828549Sjkh	    }
4838549Sjkh	    sz = space_free(label_chunk_info[here].c);
4848669Sphk	    if (sz <= FS_MIN_SIZE) {
4858549Sjkh		msg = "Not enough space to create additional FreeBSD partition";
4868669Sphk		break;
4878669Sphk	    }
4888669Sphk	    {
4898705Sjkh		char *val, *cp;
4908702Sjkh		int size;
4918702Sjkh		struct chunk *tmp;
4928702Sjkh		u_long flags = 0;
4938549Sjkh
4948751Sjkh		val = msgGetInput(NULL, "Please specify the size for new FreeBSD partition in blocks, or\nappend a trailing `M' for megabytes (e.g. 20M), `C' for cylinders\nor `%%' for a percentage of remaining space.\n\nSpace free is %d blocks (%dMB)", sz, sz / ONE_MEG);
4958702Sjkh		if (!val || (size = strtol(val, &cp, 0)) <= 0)
4968702Sjkh		    break;
4978549Sjkh
4988702Sjkh		if (sz <= FS_MIN_SIZE) {
4998702Sjkh		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
5008702Sjkh		    break;
5018702Sjkh		}
5028751Sjkh		if (*cp) {
5038751Sjkh		    if (toupper(*cp) == 'M')
5048751Sjkh			size *= ONE_MEG;
5058751Sjkh		    else if (toupper(*cp) == 'C')
5068751Sjkh			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
5078764Sjkh		    else if (*cp == '%') {
5088764Sjkh			float fsz, fsize;
5098764Sjkh
5108764Sjkh			fsz = (float)sz;
5118764Sjkh			fsize = (float)size;
5128764Sjkh			fsize *= 0.10;
5138764Sjkh			fsz *= fsize;
5148764Sjkh			size = (int)fsz;
5158764Sjkh		    }
5168751Sjkh		}
5178702Sjkh		type = get_partition_type();
5188702Sjkh		if (type == PART_NONE)
5198669Sphk		    break;
5208669Sphk
5218702Sjkh		if (type == PART_FILESYSTEM) {
5228702Sjkh		    if ((p = get_mountpoint(NULL)) == NULL)
5238702Sjkh			break;
5248702Sjkh		    else if (!strcmp(p->mountpoint, "/"))
5258702Sjkh			flags |= CHUNK_IS_ROOT;
5268702Sjkh		    else
5278702Sjkh			flags &= ~CHUNK_IS_ROOT;
5288702Sjkh		} else
5298702Sjkh		    p = NULL;
5308702Sjkh
5318702Sjkh		if ((flags & CHUNK_IS_ROOT)) {
5328702Sjkh		    if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
5338702Sjkh			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 location.  Please choose another location for your root\npartition and try again!");
5348702Sjkh			break;
5358702Sjkh		    }
5368705Sjkh		    if (size < ROOT_MIN_SIZE)
5378705Sjkh			msgConfirm("Warning: This is smaller than the recommended size for a\nroot partition.  For a variety of reasons, root\npartitions should usually be at least %dMB in size", ROOT_MIN_SIZE / ONE_MEG);
5388672Sjkh		}
5398751Sjkh		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
5408702Sjkh					label_chunk_info[here].c,
5418702Sjkh					size, part,
5428702Sjkh					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
5438702Sjkh					flags);
5448702Sjkh		if (!tmp) {
5458702Sjkh		    msgConfirm("Unable to create the partition. Too big?");
5468672Sjkh		    break;
5478672Sjkh		}
5488702Sjkh		if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
5498669Sphk		    msgConfirm("This region cannot be used for your root partition as it starts\nor extends past the 1024'th cylinder mark and is thus a\npoor location to boot from.  Please choose another\nlocation for your root partition and try again!");
5508751Sjkh		    Delete_Chunk(label_chunk_info[here].c->disk, tmp);
5518669Sphk		    break;
5528702Sjkh		}
5538702Sjkh		if (type != PART_SWAP) {
5548669Sphk		    /* This is needed to tell the newfs -u about the size */
5558669Sphk		    tmp->private = new_part(p->mountpoint,p->newfs,tmp->size);
5568669Sphk		    safe_free(p);
5578702Sjkh		} else {
5588589Sjkh		    tmp->private = p;
5598702Sjkh		}
5608702Sjkh		tmp->private_free = safe_free;
5618702Sjkh		record_label_chunks();
5628549Sjkh	    }
5638549Sjkh	    break;
5648549Sjkh
5658549Sjkh	case 'D':	/* delete */
5668549Sjkh	    if (label_chunk_info[here].type == PART_SLICE) {
5678549Sjkh		msg = MSG_NOT_APPLICABLE;
5688549Sjkh		break;
5698549Sjkh	    }
5708549Sjkh	    else if (label_chunk_info[here].type == PART_FAT) {
5718705Sjkh		msg = "Use the Disk Partition Editor to delete DOS partitions";
5728549Sjkh		break;
5738549Sjkh	    }
5748751Sjkh	    Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c);
5758549Sjkh	    record_label_chunks();
5768549Sjkh	    break;
5778549Sjkh
5788549Sjkh	case 'M':	/* mount */
5798549Sjkh	    switch(label_chunk_info[here].type) {
5808549Sjkh	    case PART_SLICE:
5818549Sjkh		msg = MSG_NOT_APPLICABLE;
5828549Sjkh		break;
5838549Sjkh
5848549Sjkh	    case PART_SWAP:
5858549Sjkh		msg = "You don't need to specify a mountpoint for a swap partition.";
5868549Sjkh		break;
5878549Sjkh
5888556Sjkh	    case PART_FAT:
5898549Sjkh	    case PART_FILESYSTEM:
5908589Sjkh		p = get_mountpoint(label_chunk_info[here].c);
5918549Sjkh		if (p) {
5928549Sjkh		    p->newfs = FALSE;
5938722Sjkh		    if (label_chunk_info[here].type == PART_FAT
5948722Sjkh			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
5958722Sjkh			    || !strcmp(p->mountpoint, "/var"))) {
5968722Sjkh			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
5978722Sjkh			strcpy(p->mountpoint, "/bogus");
5988722Sjkh		    }
5998549Sjkh		}
6008810Sjkh		record_label_chunks();
6018549Sjkh		break;
6028549Sjkh
6038549Sjkh	    default:
6048549Sjkh		msgFatal("Bogus partition under cursor???");
6058549Sjkh		break;
6068549Sjkh	    }
6078549Sjkh	    break;
6088549Sjkh
6098549Sjkh	case 'N':	/* Set newfs options */
6108549Sjkh	    if (label_chunk_info[here].c->private &&
6118549Sjkh		((PartInfo *)label_chunk_info[here].c->private)->newfs)
6128549Sjkh		getNewfsCmd(label_chunk_info[here].c->private);
6138549Sjkh	    else
6148549Sjkh		msg = MSG_NOT_APPLICABLE;
6158549Sjkh	    break;
6168549Sjkh
6178549Sjkh	case 'T':	/* Toggle newfs state */
6188549Sjkh	    if (label_chunk_info[here].type == PART_FILESYSTEM &&
6198669Sphk		label_chunk_info[here].c->private) {
6208669Sphk		    PartInfo *pi = ((PartInfo *)
6218669Sphk			label_chunk_info[here].c->private);
6228669Sphk		    label_chunk_info[here].c->private = new_part(
6238669Sphk			pi->mountpoint,
6248669Sphk			!pi->newfs,
6258669Sphk			label_chunk_info[here].c->size);
6268669Sphk		    safe_free(pi);
6278669Sphk		}
6288549Sjkh	    else
6298549Sjkh		msg = MSG_NOT_APPLICABLE;
6308549Sjkh	    break;
6318549Sjkh
6328549Sjkh	case 'W':
6338549Sjkh	    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!")) {
6348549Sjkh		int i;
6358549Sjkh		Device **devs;
6368549Sjkh
6378549Sjkh		dialog_clear();
6388549Sjkh		end_dialog();
6398549Sjkh		DialogActive = FALSE;
6408549Sjkh		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
6418549Sjkh		if (!devs) {
6428549Sjkh		    msgConfirm("Can't find any disk devicse!");
6438549Sjkh		    break;
6448549Sjkh		}
6458668Sphk		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
6468613Sjkh		    if (devs[i]->enabled)
6478613Sjkh		    	slice_wizard(((Disk *)devs[i]->private));
6488613Sjkh		}
6498665Sphk		DialogActive = TRUE;
6508549Sjkh		dialog_clear();
6518549Sjkh		record_label_chunks();
6528549Sjkh	    }
6538549Sjkh	    else
6548549Sjkh		msg = "A most prudent choice!";
6558549Sjkh	    break;
6568549Sjkh
6578549Sjkh	case 27:	/* ESC */
6588549Sjkh	    labeling = FALSE;
6598549Sjkh	    break;
6608549Sjkh
6618549Sjkh	default:
6628549Sjkh	    beep();
6638549Sjkh	    msg = "Type F1 or ? for help";
6648549Sjkh	    break;
6658549Sjkh	}
6668549Sjkh    }
6678549Sjkh    variable_set2(DISK_LABELLED, "yes");
6688581Sjkh    dialog_clear();
6698576Sjkh    return 0;
6708549Sjkh}
6718549Sjkh
6728549Sjkh
6738549Sjkh
674