label.c revision 54587
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 *
750479Speter * $FreeBSD: head/usr.sbin/sysinstall/label.c 54587 1999-12-14 04:25:29Z jkh $
88549Sjkh *
98549Sjkh * Copyright (c) 1995
108549Sjkh *	Jordan Hubbard.  All rights reserved.
118549Sjkh *
128549Sjkh * Redistribution and use in source and binary forms, with or without
138549Sjkh * modification, are permitted provided that the following conditions
148549Sjkh * are met:
158549Sjkh * 1. Redistributions of source code must retain the above copyright
168881Srgrimes *    notice, this list of conditions and the following disclaimer,
178881Srgrimes *    verbatim and that no modifications are made prior to this
188549Sjkh *    point in the file.
198549Sjkh * 2. Redistributions in binary form must reproduce the above copyright
208549Sjkh *    notice, this list of conditions and the following disclaimer in the
218549Sjkh *    documentation and/or other materials provided with the distribution.
228549Sjkh *
238549Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
248549Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
258549Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
268549Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
278549Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
288549Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
298549Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
308549Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
318549Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
328549Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
338549Sjkh * SUCH DAMAGE.
348549Sjkh *
358549Sjkh */
368549Sjkh
378549Sjkh#include "sysinstall.h"
388549Sjkh#include <ctype.h>
398549Sjkh#include <sys/disklabel.h>
4010882Speter#include <sys/param.h>
4110882Speter#include <sys/sysctl.h>
428549Sjkh
438549Sjkh/*
448549Sjkh * Everything to do with editing the contents of disk labels.
458549Sjkh */
468549Sjkh
478549Sjkh/* A nice message we use a lot in the disklabel editor */
488549Sjkh#define MSG_NOT_APPLICABLE	"That option is not applicable here"
498549Sjkh
508549Sjkh/* Where to start printing the freebsd slices */
518549Sjkh#define CHUNK_SLICE_START_ROW		2
528622Sjkh#define CHUNK_PART_START_ROW		11
538549Sjkh
548549Sjkh/* The smallest filesystem we're willing to create */
558702Sjkh#define FS_MIN_SIZE			ONE_MEG
568549Sjkh
578672Sjkh/* The smallest root filesystem we're willing to create */
5844601Sjkh#ifdef __alpha__
5945127Sjkh#define ROOT_MIN_SIZE			40
6044601Sjkh#else
6145127Sjkh#define ROOT_MIN_SIZE			30
6244601Sjkh#endif
638549Sjkh
6444601Sjkh/* The default root filesystem size */
6544601Sjkh#ifdef __alpha__
6645127Sjkh#define ROOT_DEFAULT_SIZE		60
6744601Sjkh#else
6845127Sjkh#define ROOT_DEFAULT_SIZE		40
6944601Sjkh#endif
7044601Sjkh
7112661Speter/* The smallest swap partition we want to create by default */
7212661Speter#define SWAP_MIN_SIZE			16
7312661Speter
7412661Speter/* The smallest /usr partition we're willing to create by default */
7512661Speter#define USR_MIN_SIZE			80
7612661Speter
7712661Speter/* The smallest /var partition we're willing to create by default */
7845127Sjkh#define VAR_MIN_SIZE			20
7912661Speter
8015440Sjkh/* The bottom-most row we're allowed to scribble on */
8129249Sjkh#define CHUNK_ROW_MAX			16
8215440Sjkh
8315440Sjkh
848549Sjkh/* All the chunks currently displayed on the screen */
858549Sjkhstatic struct {
868549Sjkh    struct chunk *c;
878549Sjkh    PartType type;
888549Sjkh} label_chunk_info[MAX_CHUNKS + 1];
898549Sjkhstatic int here;
908549Sjkh
9129249Sjkh/*** with this value we try to track the most recently added label ***/
9229249Sjkhstatic int label_focus = 0, pslice_focus = 0;
9329249Sjkh
9430345Sjkhstatic int diskLabel(Device *dev);
9530345Sjkhstatic int diskLabelNonInteractive(Device *dev);
9612661Speter
9730345Sjkhstatic int
9830345SjkhlabelHook(dialogMenuItem *selected)
9930345Sjkh{
10030345Sjkh    Device **devs = NULL;
10130345Sjkh
10230345Sjkh    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
10330345Sjkh    if (!devs) {
10430345Sjkh	msgConfirm("Unable to find disk %s!", selected->prompt);
10530345Sjkh	return DITEM_FAILURE;
10630345Sjkh    }
10730345Sjkh    /* Toggle enabled status? */
10830345Sjkh    if (!devs[0]->enabled) {
10930345Sjkh	devs[0]->enabled = TRUE;
11030345Sjkh	diskLabel(devs[0]);
11130345Sjkh    }
11230345Sjkh    else
11330345Sjkh	devs[0]->enabled = FALSE;
11454587Sjkh    return DITEM_SUCCESS;
11530345Sjkh}
11630345Sjkh
11730345Sjkhstatic int
11830345SjkhlabelCheck(dialogMenuItem *selected)
11930345Sjkh{
12030345Sjkh    Device **devs = NULL;
12130345Sjkh
12230345Sjkh    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
12330345Sjkh    if (!devs || devs[0]->enabled == FALSE)
12430345Sjkh	return FALSE;
12530345Sjkh    return TRUE;
12630345Sjkh}
12730345Sjkh
12812661Speterint
12915091SjkhdiskLabelEditor(dialogMenuItem *self)
13012661Speter{
13130345Sjkh    DMenu *menu;
13212661Speter    Device **devs;
13330345Sjkh    int i, cnt;
13412661Speter
13530345Sjkh    i = 0;
13630345Sjkh    cnt = diskGetSelectCount(&devs);
13730345Sjkh    if (cnt == -1) {
13812661Speter	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
13912661Speter		   "properly probed at boot time.  See the Hardware Guide on the\n"
14012661Speter		   "Documentation menu for clues on diagnosing this type of problem.");
14115242Sjkh	return DITEM_FAILURE;
14212661Speter    }
14330345Sjkh    else if (cnt) {
14430345Sjkh	/* Some are already selected */
14530381Sjkh	if (variable_get(VAR_NONINTERACTIVE))
14634543Sjkh	    i = diskLabelNonInteractive(NULL);
14730381Sjkh	else
14834543Sjkh	    i = diskLabel(NULL);
14912661Speter    }
15030345Sjkh    else {
15130345Sjkh	/* No disks are selected, fall-back case now */
15230345Sjkh	cnt = deviceCount(devs);
15330345Sjkh	if (cnt == 1) {
15430345Sjkh	    devs[0]->enabled = TRUE;
15530345Sjkh	    if (variable_get(VAR_NONINTERACTIVE))
15630345Sjkh		i = diskLabelNonInteractive(devs[0]);
15730345Sjkh	    else
15830345Sjkh		i = diskLabel(devs[0]);
15930345Sjkh	}
16030345Sjkh	else {
16130345Sjkh	    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck);
16230345Sjkh	    if (!menu) {
16330345Sjkh		msgConfirm("No devices suitable for installation found!\n\n"
16430345Sjkh			   "Please verify that your disk controller (and attached drives)\n"
16530345Sjkh			   "were detected properly.  This can be done by pressing the\n"
16630345Sjkh			   "[Scroll Lock] key and using the Arrow keys to move back to\n"
16730345Sjkh			   "the boot messages.  Press [Scroll Lock] again to return.");
16830345Sjkh		i = DITEM_FAILURE;
16930345Sjkh	    }
17030345Sjkh	    else {
17130345Sjkh		i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
17230345Sjkh		free(menu);
17330345Sjkh	    }
17430345Sjkh	}
17512661Speter    }
17618744Sjkh    if (DITEM_STATUS(i) != DITEM_FAILURE) {
17718744Sjkh	char *cp;
17818744Sjkh
17918744Sjkh	if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
18043685Sjkh	    variable_set2(DISK_LABELLED, "yes", 0);
18118744Sjkh    }
18212661Speter    return i;
18312661Speter}
18412661Speter
18512661Speterint
18615091SjkhdiskLabelCommit(dialogMenuItem *self)
18712661Speter{
18812661Speter    char *cp;
18912661Speter    int i;
19012661Speter
19112661Speter    /* Already done? */
19217025Sjkh    if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
19315242Sjkh	i = DITEM_SUCCESS;
19412661Speter    else if (!cp) {
19512661Speter	msgConfirm("You must assign disk labels before this option can be used.");
19615242Sjkh	i = DITEM_FAILURE;
19712661Speter    }
19812661Speter    /* The routine will guard against redundant writes, just as this one does */
19915419Sjkh    else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
20015242Sjkh	i = DITEM_FAILURE;
20115419Sjkh    else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
20215242Sjkh	i = DITEM_FAILURE;
20312661Speter    else {
20412661Speter	msgInfo("All filesystem information written successfully.");
20543685Sjkh	variable_set2(DISK_LABELLED, "written", 0);
20615242Sjkh	i = DITEM_SUCCESS;
20712661Speter    }
20812661Speter    return i;
20912661Speter}
21012661Speter
2118549Sjkh/* See if we're already using a desired partition name */
2128549Sjkhstatic Boolean
2138549Sjkhcheck_conflict(char *name)
2148549Sjkh{
2158549Sjkh    int i;
2168549Sjkh
2178751Sjkh    for (i = 0; label_chunk_info[i].c; i++)
21823729Sjkh	if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)
21923729Sjkh	    && label_chunk_info[i].c->private_data
22014793Sjoerg	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
2218549Sjkh	    return TRUE;
2228549Sjkh    return FALSE;
2238549Sjkh}
2248549Sjkh
2258549Sjkh/* How much space is in this FreeBSD slice? */
2268549Sjkhstatic int
2278549Sjkhspace_free(struct chunk *c)
2288549Sjkh{
22912661Speter    struct chunk *c1;
2308549Sjkh    int sz = c->size;
2318549Sjkh
23212661Speter    for (c1 = c->part; c1; c1 = c1->next) {
2338549Sjkh	if (c1->type != unused)
2348549Sjkh	    sz -= c1->size;
2358549Sjkh    }
2368549Sjkh    if (sz < 0)
2378549Sjkh	msgFatal("Partitions are larger than actual chunk??");
2388549Sjkh    return sz;
2398549Sjkh}
2408549Sjkh
2418549Sjkh/* Snapshot the current situation into the displayed chunks structure */
2428549Sjkhstatic void
24330345Sjkhrecord_label_chunks(Device **devs, Device *dev)
2448549Sjkh{
2458549Sjkh    int i, j, p;
2468549Sjkh    struct chunk *c1, *c2;
2478556Sjkh    Disk *d;
2488549Sjkh
2498549Sjkh    j = p = 0;
2508556Sjkh    /* First buzz through and pick up the FreeBSD slices */
2518549Sjkh    for (i = 0; devs[i]; i++) {
25230345Sjkh	if ((dev && devs[i] != dev) || !devs[i]->enabled)
2538556Sjkh	    continue;
2548556Sjkh	d = (Disk *)devs[i]->private;
2558556Sjkh	if (!d->chunks)
2568556Sjkh	    msgFatal("No chunk list found for %s!", d->name);
2578549Sjkh
2588556Sjkh	/* Put the slice entries first */
2598556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2608549Sjkh	    if (c1->type == freebsd) {
2618549Sjkh		label_chunk_info[j].type = PART_SLICE;
2628549Sjkh		label_chunk_info[j].c = c1;
2638549Sjkh		++j;
2648549Sjkh	    }
2658549Sjkh	}
2668549Sjkh    }
26712661Speter
2688556Sjkh    /* Now run through again and get the FreeBSD partition entries */
2698556Sjkh    for (i = 0; devs[i]; i++) {
2708556Sjkh	if (!devs[i]->enabled)
2718556Sjkh	    continue;
2728556Sjkh	d = (Disk *)devs[i]->private;
2738549Sjkh	/* Then buzz through and pick up the partitions */
2748556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2758549Sjkh	    if (c1->type == freebsd) {
2768549Sjkh		for (c2 = c1->part; c2; c2 = c2->next) {
2778549Sjkh		    if (c2->type == part) {
2788549Sjkh			if (c2->subtype == FS_SWAP)
2798549Sjkh			    label_chunk_info[j].type = PART_SWAP;
2808549Sjkh			else
2818549Sjkh			    label_chunk_info[j].type = PART_FILESYSTEM;
2828549Sjkh			label_chunk_info[j].c = c2;
2838549Sjkh			++j;
2848549Sjkh		    }
2858549Sjkh		}
2868549Sjkh	    }
2878549Sjkh	    else if (c1->type == fat) {
2888549Sjkh		label_chunk_info[j].type = PART_FAT;
2898549Sjkh		label_chunk_info[j].c = c1;
2908702Sjkh		++j;
2918549Sjkh	    }
2928549Sjkh	}
2938549Sjkh    }
2948549Sjkh    label_chunk_info[j].c = NULL;
29529249Sjkh    if (here >= j) {
2968549Sjkh	here = j  ? j - 1 : 0;
29729249Sjkh    }
2988549Sjkh}
2998549Sjkh
3008549Sjkh/* A new partition entry */
3018549Sjkhstatic PartInfo *
3028665Sphknew_part(char *mpoint, Boolean newfs, u_long size)
3038549Sjkh{
3048549Sjkh    PartInfo *ret;
3058549Sjkh
3069202Srgrimes    if (!mpoint)
3079202Srgrimes	mpoint = "/change_me";
3089202Srgrimes
3098549Sjkh    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
31020247Sjkh    sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX);
31149441Sphk    strcpy(ret->newfs_cmd, "newfs ");
31249441Sphk    strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS));
3138666Sphk    ret->newfs = newfs;
3148669Sphk    if (!size)
31529249Sjkh	return ret;
3168549Sjkh    return ret;
3178549Sjkh}
3188549Sjkh
3198549Sjkh/* Get the mountpoint for a partition and save it away */
32012661Speterstatic PartInfo *
3218589Sjkhget_mountpoint(struct chunk *old)
3228549Sjkh{
3238549Sjkh    char *val;
3248549Sjkh    PartInfo *tmp;
3258549Sjkh
32614793Sjoerg    if (old && old->private_data)
32714793Sjoerg	tmp = old->private_data;
3288810Sjkh    else
3298810Sjkh	tmp = NULL;
33018619Sjkh    if (!old) {
33118621Sjkh	DialogX = 14;
33218621Sjkh	DialogY = 16;
33318619Sjkh    }
3348810Sjkh    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
33518619Sjkh    DialogX = DialogY = 0;
3368764Sjkh    if (!val || !*val) {
3378751Sjkh	if (!old)
3388751Sjkh	    return NULL;
3398751Sjkh	else {
34014793Sjoerg	    free(old->private_data);
34114793Sjoerg	    old->private_data = NULL;
3428751Sjkh	}
3438669Sphk	return NULL;
3448751Sjkh    }
3458669Sphk
3468669Sphk    /* Is it just the same value? */
3478810Sjkh    if (tmp && !strcmp(tmp->mountpoint, val))
3488669Sphk	return NULL;
3498810Sjkh
3508810Sjkh    /* Did we use it already? */
3518669Sphk    if (check_conflict(val)) {
3528669Sphk	msgConfirm("You already have a mount point for %s assigned!", val);
3538669Sphk	return NULL;
3548549Sjkh    }
3558810Sjkh
3568810Sjkh    /* Is it bogus? */
3578669Sphk    if (*val != '/') {
3588669Sphk	msgConfirm("Mount point must start with a / character");
3598669Sphk	return NULL;
3608669Sphk    }
3618810Sjkh
3628810Sjkh    /* Is it going to be mounted on root? */
3638669Sphk    if (!strcmp(val, "/")) {
3648669Sphk	if (old)
3658669Sphk	    old->flags |= CHUNK_IS_ROOT;
3668810Sjkh    }
3678810Sjkh    else if (old)
3688669Sphk	old->flags &= ~CHUNK_IS_ROOT;
3698810Sjkh
3708810Sjkh    safe_free(tmp);
37146615Sjkh    val = string_skipwhite(string_prune(val));
3728669Sphk    tmp = new_part(val, TRUE, 0);
3738669Sphk    if (old) {
37414793Sjoerg	old->private_data = tmp;
3758669Sphk	old->private_free = safe_free;
3768669Sphk    }
3778669Sphk    return tmp;
3788549Sjkh}
3798549Sjkh
3808549Sjkh/* Get the type of the new partiton */
3818549Sjkhstatic PartType
3828549Sjkhget_partition_type(void)
3838549Sjkh{
3848549Sjkh    char selection[20];
3858669Sphk    int i;
3868549Sjkh    static unsigned char *fs_types[] = {
3878549Sjkh	"FS",
3888549Sjkh	"A file system",
3898549Sjkh	"Swap",
3908549Sjkh	"A swap partition.",
3918549Sjkh    };
39254587Sjkh    WINDOW *w = savescr();
39354587Sjkh
39418619Sjkh    DialogX = 7;
39518621Sjkh    DialogY = 8;
3968669Sphk    i = dialog_menu("Please choose a partition type",
39712661Speter		    "If you want to use this partition for swap space, select Swap.\n"
39812661Speter		    "If you want to put a filesystem on it, choose FS.",
39912661Speter		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
40018619Sjkh    DialogX = DialogY = 0;
40154587Sjkh    restorescr(w);
4028669Sphk    if (!i) {
4038549Sjkh	if (!strcmp(selection, "FS"))
4048549Sjkh	    return PART_FILESYSTEM;
4058549Sjkh	else if (!strcmp(selection, "Swap"))
4068549Sjkh	    return PART_SWAP;
4078549Sjkh    }
4088549Sjkh    return PART_NONE;
4098549Sjkh}
4108549Sjkh
4118549Sjkh/* If the user wants a special newfs command for this, set it */
4128549Sjkhstatic void
4138549SjkhgetNewfsCmd(PartInfo *p)
4148549Sjkh{
4158549Sjkh    char *val;
4168549Sjkh
4178549Sjkh    val = msgGetInput(p->newfs_cmd,
41812661Speter		      "Please enter the newfs command and options you'd like to use in\n"
41912661Speter		      "creating this file system.");
4208549Sjkh    if (val)
42120247Sjkh	sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
4228549Sjkh}
4238549Sjkh
42454014Sjkh#define MAX_MOUNT_NAME	10
4258549Sjkh
4268549Sjkh#define PART_PART_COL	0
42754014Sjkh#define PART_MOUNT_COL	10
4288549Sjkh#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
42949202Sbrian#define PART_NEWFS_COL	(PART_SIZE_COL + 8)
43054473Sjkh#define PART_OFF	38
4318549Sjkh
43229249Sjkh#define TOTAL_AVAIL_LINES       (10)
43329249Sjkh#define PSLICE_SHOWABLE          (4)
43429249Sjkh
43529249Sjkh
4368549Sjkh/* stick this all up on the screen */
4378549Sjkhstatic void
4388549Sjkhprint_label_chunks(void)
4398549Sjkh{
44029249Sjkh    int  i, j, srow, prow, pcol;
44129249Sjkh    int  sz;
44229249Sjkh    char clrmsg[80];
44329633Sjkh    int ChunkPartStartRow;
44429633Sjkh    WINDOW *ChunkWin;
4458549Sjkh
44629249Sjkh    /********************************************************/
44729249Sjkh    /*** These values are for controling screen resources ***/
44829249Sjkh    /*** Each label line holds up to 2 labels, so beware! ***/
44929249Sjkh    /*** strategy will be to try to always make sure the  ***/
45029249Sjkh    /*** highlighted label is in the active display area. ***/
45129249Sjkh    /********************************************************/
45229249Sjkh    int  pslice_max, label_max;
45329249Sjkh    int  pslice_count, label_count, label_focus_found, pslice_focus_found;
45429249Sjkh
4558549Sjkh    attrset(A_REVERSE);
4568549Sjkh    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
4578549Sjkh    attrset(A_NORMAL);
4588549Sjkh
45929633Sjkh    /*** Count the number of parition slices ***/
46029633Sjkh    pslice_count = 0;
46129633Sjkh    for (i = 0; label_chunk_info[i].c ; i++) {
46229633Sjkh        if (label_chunk_info[i].type == PART_SLICE)
46329633Sjkh            ++pslice_count;
46429633Sjkh    }
46529633Sjkh    pslice_max = pslice_count;
46629633Sjkh
46729633Sjkh    /*** 4 line max for partition slices ***/
46829633Sjkh    if (pslice_max > PSLICE_SHOWABLE) {
46929633Sjkh        pslice_max = PSLICE_SHOWABLE;
47029633Sjkh    }
47129633Sjkh    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
47229633Sjkh
47329633Sjkh    /*** View partition slices modulo pslice_max ***/
47429633Sjkh    label_max = TOTAL_AVAIL_LINES - pslice_max;
47529633Sjkh
4768549Sjkh    for (i = 0; i < 2; i++) {
47715440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
47815440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
4798549Sjkh
48015440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
48115440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
4828549Sjkh
48349202Sbrian	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
48449202Sbrian	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
4858549Sjkh
48615440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
48715440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
4888549Sjkh    }
4898549Sjkh    srow = CHUNK_SLICE_START_ROW;
49015440Sjkh    prow = 0;
4918549Sjkh    pcol = 0;
4928549Sjkh
49329249Sjkh    /*** these variables indicate that the focused item is shown currently ***/
49429249Sjkh    label_focus_found = 0;
49529249Sjkh    pslice_focus_found = 0;
49629249Sjkh
49729249Sjkh    label_count = 0;
49829249Sjkh    pslice_count = 0;
49929249Sjkh    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "          ");
50029249Sjkh    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "          ");
50129249Sjkh
50229633Sjkh    ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
50329633Sjkh
50429633Sjkh    wclear(ChunkWin);
50529633Sjkh    /*** wrefresh(ChunkWin); ***/
50629633Sjkh
5078751Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
5088549Sjkh	/* Is it a slice entry displayed at the top? */
5098549Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
51029249Sjkh            /*** This causes the new pslice to replace the previous display ***/
51129249Sjkh            /*** focus must remain on the most recently active pslice       ***/
51229249Sjkh            if (pslice_count == pslice_max) {
51329249Sjkh                if (pslice_focus_found) {
51429249Sjkh                    /*** This is where we can mark the more following ***/
51529249Sjkh                    attrset(A_BOLD);
51629249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
51729249Sjkh                    attrset(A_NORMAL);
51829249Sjkh                    continue;
51929249Sjkh                }
52029249Sjkh                else {
52129249Sjkh                    /*** this is where we set the more previous ***/
52229249Sjkh                    attrset(A_BOLD);
52329249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
52429249Sjkh                    attrset(A_NORMAL);
52529249Sjkh                    pslice_count = 0;
52629249Sjkh                    srow = CHUNK_SLICE_START_ROW;
52729249Sjkh                }
52829249Sjkh            }
52929249Sjkh
5308549Sjkh	    sz = space_free(label_chunk_info[i].c);
53115440Sjkh	    if (i == here)
53216208Sjkh		attrset(ATTR_SELECTED);
53329249Sjkh            if (i == pslice_focus)
53429249Sjkh                pslice_focus_found = -1;
53529249Sjkh
53629249Sjkh	    mvprintw(srow++, 0,
53729249Sjkh		     "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
53829249Sjkh		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name,
53929249Sjkh		     sz, (sz / ONE_MEG));
54015440Sjkh	    attrset(A_NORMAL);
54115440Sjkh	    clrtoeol();
54215440Sjkh	    move(0, 0);
54329633Sjkh	    /*** refresh(); ***/
54429249Sjkh            ++pslice_count;
5458549Sjkh	}
54615440Sjkh	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
5478549Sjkh	else {
5488549Sjkh	    char onestr[PART_OFF], num[10], *mountpoint, *newfs;
5498549Sjkh
5508549Sjkh	    /*
5518549Sjkh	     * We copy this into a blank-padded string so that it looks like
5528549Sjkh	     * a solid bar in reverse-video
5538549Sjkh	     */
5548549Sjkh	    memset(onestr, ' ', PART_OFF - 1);
5558549Sjkh	    onestr[PART_OFF - 1] = '\0';
55629249Sjkh
55729249Sjkh            /*** Track how many labels have been displayed ***/
55829249Sjkh            if (label_count == ((label_max - 1 ) * 2)) {
55929249Sjkh                if (label_focus_found) {
56029249Sjkh                    continue;
56129249Sjkh                }
56229249Sjkh                else {
56329249Sjkh                    label_count = 0;
56429249Sjkh                    prow = 0;
56529249Sjkh                    pcol = 0;
56629249Sjkh                }
56729249Sjkh            }
56829249Sjkh
56915440Sjkh	    /* Go for two columns if we've written one full columns worth */
57029249Sjkh	    /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
57129249Sjkh            if (label_count == label_max - 1) {
5728549Sjkh		pcol = PART_OFF;
57315440Sjkh		prow = 0;
5748549Sjkh	    }
5758705Sjkh	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
5768549Sjkh	    /* If it's a filesystem, display the mountpoint */
57714793Sjoerg	    if (label_chunk_info[i].c->private_data
57810882Speter		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
57914793Sjoerg	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
58023529Sjkh	    else if (label_chunk_info[i].type == PART_SWAP)
58123529Sjkh		mountpoint = "swap";
58210882Speter	    else
58310882Speter	        mountpoint = "<none>";
58410882Speter
58510882Speter	    /* Now display the newfs field */
58610882Speter	    if (label_chunk_info[i].type == PART_FAT)
58710882Speter	        newfs = "DOS";
58814793Sjoerg	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM)
58914793Sjoerg		newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N";
59010882Speter	    else if (label_chunk_info[i].type == PART_SWAP)
59110882Speter		newfs = "SWAP";
59210882Speter	    else
5938549Sjkh		newfs = "*";
5948549Sjkh	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
5958549Sjkh		onestr[PART_MOUNT_COL + j] = mountpoint[j];
59649202Sbrian	    snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
5978549Sjkh	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
5988549Sjkh	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
5998549Sjkh	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
60029633Sjkh            if (i == label_focus) {
60129633Sjkh                label_focus_found = -1;
60229633Sjkh                wattrset(ChunkWin, A_BOLD);
60329633Sjkh            }
60415440Sjkh	    if (i == here)
60516208Sjkh		wattrset(ChunkWin, ATTR_SELECTED);
60629249Sjkh
60729249Sjkh            /*** lazy man's way of padding this string ***/
60829249Sjkh            while (strlen( onestr ) < 37)
60929249Sjkh                strcat(onestr, " ");
61029249Sjkh
61115440Sjkh	    mvwaddstr(ChunkWin, prow, pcol, onestr);
61215440Sjkh	    wattrset(ChunkWin, A_NORMAL);
61315440Sjkh	    move(0, 0);
6148549Sjkh	    ++prow;
61529249Sjkh            ++label_count;
6168549Sjkh	}
6178549Sjkh    }
61829249Sjkh
61929249Sjkh    /*** this will erase all the extra stuff ***/
62029249Sjkh    memset(clrmsg, ' ', 37);
62129249Sjkh    clrmsg[37] = '\0';
62229249Sjkh
62329249Sjkh    while (pslice_count < pslice_max) {
62429249Sjkh        mvprintw(srow++, 0, clrmsg);
62529249Sjkh        clrtoeol();
62629249Sjkh        ++pslice_count;
62729249Sjkh    }
62829633Sjkh    while (label_count < (2 * (label_max - 1))) {
62929633Sjkh        mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
63029633Sjkh	++label_count;
63129633Sjkh	if (prow == (label_max - 1)) {
63229633Sjkh	    prow = 0;
63329633Sjkh	    pcol = PART_OFF;
63429633Sjkh	}
63529249Sjkh    }
63629633Sjkh    refresh();
63729633Sjkh    wrefresh(ChunkWin);
6388549Sjkh}
6398549Sjkh
6408549Sjkhstatic void
64118619Sjkhprint_command_summary(void)
6428549Sjkh{
6438820Sjkh    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
64421971Sjkh    mvprintw(18, 0, "C = Create      D = Delete         M = Mount pt.");
64515440Sjkh    if (!RunningAsInit)
64630956Sobrien	mvprintw(18, 49, "W = Write");
64730956Sobrien    mvprintw(19, 0, "N = Newfs Opts  T = Newfs Toggle   U = Undo      Q = Finish");
64810882Speter    mvprintw(20, 0, "A = Auto Defaults for all!");
64915695Sjkh    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
6508549Sjkh    move(0, 0);
6518549Sjkh}
6528549Sjkh
65318619Sjkhstatic void
65418619Sjkhclear_wins(void)
65518619Sjkh{
65629633Sjkh    extern void print_label_chunks();
65718619Sjkh    clear();
65829633Sjkh    print_label_chunks();
65918619Sjkh}
66018619Sjkh
66143392Sjkh#ifdef __alpha__
66243392Sjkh
66343392Sjkh/*
66443392Sjkh * If there isn't a freebsd chunk already (i.e. there is no label),
66543392Sjkh * dedicate the disk.
66643392Sjkh */
66743392Sjkhstatic void
66843392Sjkhmaybe_dedicate(Disk* d)
66943392Sjkh{
67043392Sjkh    struct chunk *c;
67143392Sjkh
67243392Sjkh    for (c = d->chunks->part; c; c = c->next) {
67343392Sjkh	if (c->type == freebsd)
67443392Sjkh	    break;
67543392Sjkh    }
67643392Sjkh
67743392Sjkh    if (!c) {
67843392Sjkh	msgDebug("dedicating disk");
67943392Sjkh	All_FreeBSD(d, 1);
68043392Sjkh    }
68143392Sjkh}
68243392Sjkh
68343392Sjkh#endif
68443392Sjkh
68512661Speterstatic int
68630345SjkhdiskLabel(Device *dev)
6878549Sjkh{
68818619Sjkh    int sz, key = 0;
6898549Sjkh    Boolean labeling;
6908549Sjkh    char *msg = NULL;
6919202Srgrimes    PartInfo *p, *oldp;
6928549Sjkh    PartType type;
6938824Sjkh    Device **devs;
69442386Sjkh#ifdef __alpha__
69542386Sjkh    int i;
69642386Sjkh#endif
69754587Sjkh    WINDOW *w = savescr();
6988549Sjkh
69929628Sjkh    label_focus = 0;
70029628Sjkh    pslice_focus = 0;
70129633Sjkh    here = 0;
70230345Sjkh
70312661Speter    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
70412661Speter    if (!devs) {
70512661Speter	msgConfirm("No disks found!");
70654587Sjkh	restorescr(w);
70715242Sjkh	return DITEM_FAILURE;
70812661Speter    }
7098549Sjkh    labeling = TRUE;
7108549Sjkh    keypad(stdscr, TRUE);
71142386Sjkh#ifdef __alpha__
71242386Sjkh    for (i = 0; devs[i]; i++) {
71343392Sjkh	maybe_dedicate((Disk*) devs[i]->private);
71442386Sjkh    }
71542386Sjkh#endif
71630345Sjkh    record_label_chunks(devs, dev);
7178549Sjkh
71818619Sjkh    clear();
7198549Sjkh    while (labeling) {
72018744Sjkh	char *cp;
72118744Sjkh
7228549Sjkh	print_label_chunks();
72318619Sjkh	print_command_summary();
7248549Sjkh	if (msg) {
72515695Sjkh	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
72612661Speter	    clrtoeol();
7278549Sjkh	    beep();
7288549Sjkh	    msg = NULL;
7298549Sjkh	}
73015442Sjkh	else {
73115442Sjkh	    move(23, 0);
73215442Sjkh	    clrtoeol();
73315442Sjkh	}
73418744Sjkh
73518619Sjkh	refresh();
73617397Sjkh	key = getch();
73717397Sjkh	switch (toupper(key)) {
73815440Sjkh	    int i;
73917362Sjkh	    static char _msg[40];
7408549Sjkh
7418751Sjkh	case '\014':	/* ^L */
74218619Sjkh	    clear_wins();
74318619Sjkh	    break;
7448751Sjkh
74521698Sjkh	case '\020':	/* ^P */
7468549Sjkh	case KEY_UP:
7478549Sjkh	case '-':
7488549Sjkh	    if (here != 0)
7498549Sjkh		--here;
7508751Sjkh	    else
7518751Sjkh		while (label_chunk_info[here + 1].c)
7528751Sjkh		    ++here;
7538549Sjkh	    break;
7548549Sjkh
75521698Sjkh	case '\016':	/* ^N */
7568549Sjkh	case KEY_DOWN:
7578549Sjkh	case '+':
7588549Sjkh	case '\r':
7598549Sjkh	case '\n':
7608751Sjkh	    if (label_chunk_info[here + 1].c)
7618549Sjkh		++here;
7628751Sjkh	    else
7638751Sjkh		here = 0;
7648549Sjkh	    break;
7658549Sjkh
7668549Sjkh	case KEY_HOME:
7678549Sjkh	    here = 0;
7688549Sjkh	    break;
7698549Sjkh
7708549Sjkh	case KEY_END:
7718751Sjkh	    while (label_chunk_info[here + 1].c)
7728549Sjkh		++here;
7738549Sjkh	    break;
7748549Sjkh
7758549Sjkh	case KEY_F(1):
7768549Sjkh	case '?':
77712661Speter	    systemDisplayHelp("partition");
77818619Sjkh	    clear_wins();
7798549Sjkh	    break;
7808549Sjkh
78110882Speter	case 'A':
78210882Speter	    if (label_chunk_info[here].type != PART_SLICE) {
78315440Sjkh		msg = "You can only do this in a disk slice (at top of screen)";
78410882Speter		break;
78510882Speter	    }
78610882Speter	    sz = space_free(label_chunk_info[here].c);
78717362Sjkh	    if (sz <= FS_MIN_SIZE)
78815440Sjkh		msg = "Not enough free space to create a new partition in the slice";
78915440Sjkh	    else {
79015440Sjkh		struct chunk *tmp;
79115440Sjkh		int mib[2];
79215440Sjkh		int physmem;
79315440Sjkh		size_t size, swsize;
79415440Sjkh		char *cp;
79517362Sjkh		Chunk *rootdev, *swapdev, *usrdev, *vardev;
79612661Speter
79717368Sjkh		(void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev);
79817362Sjkh		if (!rootdev) {
79917362Sjkh		    cp = variable_get(VAR_ROOT_SIZE);
80017362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
80144601Sjkh					    (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS,  CHUNK_IS_ROOT);
80217362Sjkh		    if (!tmp) {
80317362Sjkh			msgConfirm("Unable to create the root partition. Too big?");
80418619Sjkh			clear_wins();
80517362Sjkh			break;
80617362Sjkh		    }
80717362Sjkh		    tmp->private_data = new_part("/", TRUE, tmp->size);
80817362Sjkh		    tmp->private_free = safe_free;
80930345Sjkh		    record_label_chunks(devs, dev);
81015440Sjkh		}
81117362Sjkh
81217362Sjkh		if (!swapdev) {
81317362Sjkh		    cp = variable_get(VAR_SWAP_SIZE);
81417362Sjkh		    if (cp)
81517362Sjkh			swsize = atoi(cp) * ONE_MEG;
81617362Sjkh		    else {
81717362Sjkh			mib[0] = CTL_HW;
81817362Sjkh			mib[1] = HW_PHYSMEM;
81917362Sjkh			size = sizeof physmem;
82017362Sjkh			sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
82117362Sjkh			swsize = 16 * ONE_MEG + (physmem * 2 / 512);
82217362Sjkh		    }
82317362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
82417362Sjkh					    swsize, part, FS_SWAP, 0);
82517362Sjkh		    if (!tmp) {
82617362Sjkh			msgConfirm("Unable to create the swap partition. Too big?");
82718619Sjkh			clear_wins();
82817362Sjkh			break;
82917362Sjkh		    }
83017362Sjkh		    tmp->private_data = 0;
83117362Sjkh		    tmp->private_free = safe_free;
83230345Sjkh		    record_label_chunks(devs, dev);
83315440Sjkh		}
83417362Sjkh
83517362Sjkh		if (!vardev) {
83617362Sjkh		    cp = variable_get(VAR_VAR_SIZE);
83737735Sjkh		    if (cp)
83837735Sjkh			sz = atoi(cp) * ONE_MEG;
83937735Sjkh		    else
84037735Sjkh			sz = variable_get(VAR_NO_USR)
84137735Sjkh				?  space_free(label_chunk_info[here].c)
84237735Sjkh				:  VAR_MIN_SIZE * ONE_MEG;
84337735Sjkh
84417362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
84537735Sjkh					    sz, part, FS_BSDFFS, 0);
84617362Sjkh		    if (!tmp) {
84717362Sjkh			msgConfirm("Less than %dMB free for /var - you will need to\n"
84817362Sjkh				   "partition your disk manually with a custom install!",
84917362Sjkh				   (cp ? atoi(cp) : VAR_MIN_SIZE));
85018619Sjkh			clear_wins();
85117362Sjkh			break;
85217362Sjkh		    }
85317362Sjkh		    tmp->private_data = new_part("/var", TRUE, tmp->size);
85417362Sjkh		    tmp->private_free = safe_free;
85530345Sjkh		    record_label_chunks(devs, dev);
85615440Sjkh		}
85712661Speter
85837735Sjkh		if (!usrdev && !variable_get(VAR_NO_USR)) {
85917362Sjkh		    cp = variable_get(VAR_USR_SIZE);
86017362Sjkh		    if (cp)
86117362Sjkh			sz = atoi(cp) * ONE_MEG;
86217362Sjkh		    else
86317362Sjkh			sz = space_free(label_chunk_info[here].c);
86429501Sjkh		    if (sz) {
86529501Sjkh			if (sz < (USR_MIN_SIZE * ONE_MEG)) {
86629501Sjkh			    msgConfirm("Less than %dMB free for /usr - you will need to\n"
86729501Sjkh				       "partition your disk manually with a custom install!", USR_MIN_SIZE);
86829501Sjkh			    clear_wins();
86929501Sjkh			    break;
87029501Sjkh			}
87117362Sjkh
87229501Sjkh			tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
87329501Sjkh						label_chunk_info[here].c,
87429501Sjkh						sz, part, FS_BSDFFS, 0);
87529501Sjkh			if (!tmp) {
87629501Sjkh			    msgConfirm("Unable to create the /usr partition.  Not enough space?\n"
87729501Sjkh				       "You will need to partition your disk manually with a custom install!");
87829501Sjkh			    clear_wins();
87929501Sjkh			    break;
88029501Sjkh			}
88129501Sjkh			tmp->private_data = new_part("/usr", TRUE, tmp->size);
88229501Sjkh			tmp->private_free = safe_free;
88330345Sjkh			record_label_chunks(devs, dev);
88417362Sjkh		    }
88515440Sjkh		}
88637735Sjkh
88715440Sjkh		/* At this point, we're reasonably "labelled" */
88818744Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
88943685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
89010882Speter	    }
89115440Sjkh	    break;
89210882Speter
8938549Sjkh	case 'C':
8948549Sjkh	    if (label_chunk_info[here].type != PART_SLICE) {
8958549Sjkh		msg = "You can only do this in a master partition (see top of screen)";
8968549Sjkh		break;
8978549Sjkh	    }
8988549Sjkh	    sz = space_free(label_chunk_info[here].c);
8998669Sphk	    if (sz <= FS_MIN_SIZE) {
90012661Speter		msg = "Not enough space to create an additional FreeBSD partition";
9018669Sphk		break;
9028669Sphk	    }
90315440Sjkh	    else {
90418744Sjkh		char *val;
9058702Sjkh		int size;
9068702Sjkh		struct chunk *tmp;
9078820Sjkh		char osize[80];
9088702Sjkh		u_long flags = 0;
9098549Sjkh
9108820Sjkh		sprintf(osize, "%d", sz);
91118619Sjkh		DialogX = 3;
91218621Sjkh		DialogY = 2;
91318619Sjkh		val = msgGetInput(osize,
91418619Sjkh				  "Please specify the partition size in blocks or append a trailing M for\n"
91518619Sjkh				  "megabytes or C for cylinders.  %d blocks (%dMB) are free.",
91618619Sjkh				  sz, sz / ONE_MEG);
91718619Sjkh		DialogX = DialogY = 0;
91818619Sjkh		if (!val || (size = strtol(val, &cp, 0)) <= 0) {
91918619Sjkh		    clear_wins();
9208702Sjkh		    break;
92118619Sjkh		}
9228549Sjkh
9238751Sjkh		if (*cp) {
9248751Sjkh		    if (toupper(*cp) == 'M')
9258751Sjkh			size *= ONE_MEG;
9268751Sjkh		    else if (toupper(*cp) == 'C')
9278751Sjkh			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
9288751Sjkh		}
9298820Sjkh		if (size <= FS_MIN_SIZE) {
9308820Sjkh		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
93118619Sjkh		    clear_wins();
9328820Sjkh		    break;
9338820Sjkh		}
9348702Sjkh		type = get_partition_type();
93518619Sjkh		if (type == PART_NONE) {
93618619Sjkh		    clear_wins();
93718619Sjkh		    beep();
9388669Sphk		    break;
93918619Sjkh		}
9408669Sphk
9418702Sjkh		if (type == PART_FILESYSTEM) {
94218619Sjkh		    if ((p = get_mountpoint(NULL)) == NULL) {
94318619Sjkh			clear_wins();
94418619Sjkh			beep();
9458702Sjkh			break;
94618619Sjkh		    }
9478702Sjkh		    else if (!strcmp(p->mountpoint, "/"))
9488702Sjkh			flags |= CHUNK_IS_ROOT;
9498702Sjkh		    else
9508702Sjkh			flags &= ~CHUNK_IS_ROOT;
95118619Sjkh		}
95218619Sjkh		else
9538702Sjkh		    p = NULL;
9548702Sjkh
9558702Sjkh		if ((flags & CHUNK_IS_ROOT)) {
9568702Sjkh		    if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
95712661Speter			msgConfirm("This region cannot be used for your root partition as the\n"
95812661Speter				   "FreeBSD boot code cannot deal with a root partition created\n"
95912661Speter				   "in that location.  Please choose another location or smaller\n"
96012661Speter				   "size for your root partition and try again!");
96118619Sjkh			clear_wins();
9628702Sjkh			break;
9638702Sjkh		    }
96412661Speter		    if (size < (ROOT_MIN_SIZE * ONE_MEG)) {
96512661Speter			msgConfirm("Warning: This is smaller than the recommended size for a\n"
96612661Speter				   "root partition.  For a variety of reasons, root\n"
96712661Speter				   "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
96812661Speter		    }
9698672Sjkh		}
9708751Sjkh		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
9718702Sjkh					label_chunk_info[here].c,
9728702Sjkh					size, part,
9738702Sjkh					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
9748702Sjkh					flags);
9758702Sjkh		if (!tmp) {
9768702Sjkh		    msgConfirm("Unable to create the partition. Too big?");
97718619Sjkh		    clear_wins();
9788672Sjkh		    break;
9798672Sjkh		}
9808702Sjkh		if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
98112661Speter		    msgConfirm("This region cannot be used for your root partition as it starts\n"
98212661Speter			       "or extends past the 1024'th cylinder mark and is thus a\n"
98312661Speter			       "poor location to boot from.  Please choose another\n"
98412661Speter			       "location (or smaller size) for your root partition and try again!");
9858751Sjkh		    Delete_Chunk(label_chunk_info[here].c->disk, tmp);
98618619Sjkh		    clear_wins();
9878669Sphk		    break;
9888702Sjkh		}
9898702Sjkh		if (type != PART_SWAP) {
9908669Sphk		    /* This is needed to tell the newfs -u about the size */
99114793Sjoerg		    tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
9928669Sphk		    safe_free(p);
99315355Sjkh		}
99415355Sjkh		else
99514793Sjoerg		    tmp->private_data = p;
9968702Sjkh		tmp->private_free = safe_free;
99718744Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
99843685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
99930345Sjkh		record_label_chunks(devs, dev);
100018619Sjkh		clear_wins();
100129249Sjkh                /*** This is where we assign focus to new label so it shows ***/
100229249Sjkh                {
100329249Sjkh                    int i;
100429249Sjkh		    label_focus = -1;
100529249Sjkh                    for (i = 0; label_chunk_info[i].c; ++i) {
100629249Sjkh                    	if (label_chunk_info[i].c == tmp) {
100729249Sjkh			    label_focus = i;
100829249Sjkh			    break;
100929249Sjkh			}
101029249Sjkh		    }
101129249Sjkh		    if (label_focus == -1)
101229249Sjkh                    	label_focus = i - 1;
101329249Sjkh                }
10148549Sjkh	    }
10158549Sjkh	    break;
10168549Sjkh
101717397Sjkh	case KEY_DC:
10188549Sjkh	case 'D':	/* delete */
10198549Sjkh	    if (label_chunk_info[here].type == PART_SLICE) {
10208549Sjkh		msg = MSG_NOT_APPLICABLE;
10218549Sjkh		break;
10228549Sjkh	    }
10238549Sjkh	    else if (label_chunk_info[here].type == PART_FAT) {
10248705Sjkh		msg = "Use the Disk Partition Editor to delete DOS partitions";
10258549Sjkh		break;
10268549Sjkh	    }
10278751Sjkh	    Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c);
102818744Sjkh	    if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
102943685Sjkh		variable_set2(DISK_LABELLED, "yes", 0);
103030345Sjkh	    record_label_chunks(devs, dev);
10318549Sjkh	    break;
10328549Sjkh
10338549Sjkh	case 'M':	/* mount */
10348549Sjkh	    switch(label_chunk_info[here].type) {
10358549Sjkh	    case PART_SLICE:
10368549Sjkh		msg = MSG_NOT_APPLICABLE;
10378549Sjkh		break;
10388549Sjkh
10398549Sjkh	    case PART_SWAP:
10408549Sjkh		msg = "You don't need to specify a mountpoint for a swap partition.";
10418549Sjkh		break;
10428549Sjkh
10438556Sjkh	    case PART_FAT:
10448549Sjkh	    case PART_FILESYSTEM:
104514793Sjoerg		oldp = label_chunk_info[here].c->private_data;
10468589Sjkh		p = get_mountpoint(label_chunk_info[here].c);
10478549Sjkh		if (p) {
10489202Srgrimes		    if (!oldp)
10499202Srgrimes		    	p->newfs = FALSE;
10508722Sjkh		    if (label_chunk_info[here].type == PART_FAT
10518722Sjkh			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
10528722Sjkh			    || !strcmp(p->mountpoint, "/var"))) {
10538722Sjkh			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
10548722Sjkh			strcpy(p->mountpoint, "/bogus");
10558722Sjkh		    }
10568549Sjkh		}
105718744Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
105843685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
105930345Sjkh		record_label_chunks(devs, dev);
106018636Sjkh		clear_wins();
10618549Sjkh		break;
10628549Sjkh
10638549Sjkh	    default:
10648549Sjkh		msgFatal("Bogus partition under cursor???");
10658549Sjkh		break;
10668549Sjkh	    }
10678549Sjkh	    break;
10688549Sjkh
10698549Sjkh	case 'N':	/* Set newfs options */
107014793Sjoerg	    if (label_chunk_info[here].c->private_data &&
107114793Sjoerg		((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
107214793Sjoerg		getNewfsCmd(label_chunk_info[here].c->private_data);
10738549Sjkh	    else
10748549Sjkh		msg = MSG_NOT_APPLICABLE;
107518636Sjkh	    clear_wins();
10768549Sjkh	    break;
10778549Sjkh
10788549Sjkh	case 'T':	/* Toggle newfs state */
10799202Srgrimes	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
108023729Sjkh		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
108123729Sjkh		label_chunk_info[here].c->private_data =
108223729Sjkh		    new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
108323729Sjkh		safe_free(pi);
108423729Sjkh		label_chunk_info[here].c->private_free = safe_free;
108523729Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
108643685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
108718619Sjkh	    }
10888549Sjkh	    else
10898549Sjkh		msg = MSG_NOT_APPLICABLE;
10908549Sjkh	    break;
10918549Sjkh
10928820Sjkh	case 'U':
109312661Speter	    clear();
109418744Sjkh	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
109518744Sjkh		msgConfirm("You've already written out your changes -\n"
109618744Sjkh			   "it's too late to undo!");
109718744Sjkh	    }
109818744Sjkh	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
109918744Sjkh		variable_unset(DISK_PARTITIONED);
110018744Sjkh		variable_unset(DISK_LABELLED);
110118744Sjkh		for (i = 0; devs[i]; i++) {
110218744Sjkh		    Disk *d;
110312661Speter
110418744Sjkh		    if (!devs[i]->enabled)
110518744Sjkh			continue;
110618744Sjkh		    else if ((d = Open_Disk(devs[i]->name)) != NULL) {
110718744Sjkh			Free_Disk(devs[i]->private);
110818744Sjkh			devs[i]->private = d;
110930345Sjkh			diskPartition(devs[i]);
111018744Sjkh		    }
11118824Sjkh		}
111230345Sjkh		record_label_chunks(devs, dev);
11138824Sjkh	    }
111418636Sjkh	    clear_wins();
11158824Sjkh	    break;
11168820Sjkh
11178549Sjkh	case 'W':
111818744Sjkh	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
111918744Sjkh		msgConfirm("You've already written out your changes - if you\n"
112018744Sjkh			   "wish to overwrite them, you'll have to start this\n"
112118744Sjkh			   "procedure again from the beginning.");
112218744Sjkh	    }
112318744Sjkh	    else if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
112418687Sjkh			  "installation.  If you are installing FreeBSD for the first time\n"
112518687Sjkh			  "then you should simply type Q when you're finished here and your\n"
112618687Sjkh			  "changes will be committed in one batch automatically at the end of\n"
112718687Sjkh			  "these questions.\n\n"
112818687Sjkh			  "Are you absolutely sure you want to do this now?")) {
112943685Sjkh		variable_set2(DISK_LABELLED, "yes", 0);
113012661Speter		diskLabelCommit(NULL);
113112661Speter	    }
113218636Sjkh	    clear_wins();
113310882Speter	    break;
113410882Speter
113510882Speter	case '|':
113612661Speter	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n"
113712661Speter			  "This is an entirely undocumented feature which you are not\n"
113812661Speter			  "expected to understand!")) {
11398549Sjkh		int i;
11408549Sjkh		Device **devs;
11418549Sjkh
11428549Sjkh		dialog_clear();
11438549Sjkh		end_dialog();
11448549Sjkh		DialogActive = FALSE;
11458549Sjkh		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
11468549Sjkh		if (!devs) {
114712661Speter		    msgConfirm("Can't find any disk devices!");
11488549Sjkh		    break;
11498549Sjkh		}
11508668Sphk		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
11518613Sjkh		    if (devs[i]->enabled)
11528613Sjkh		    	slice_wizard(((Disk *)devs[i]->private));
11538613Sjkh		}
115418744Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
115543685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
11568665Sphk		DialogActive = TRUE;
115730345Sjkh		record_label_chunks(devs, dev);
115818636Sjkh		clear_wins();
11598549Sjkh	    }
11608549Sjkh	    else
11618549Sjkh		msg = "A most prudent choice!";
11628549Sjkh	    break;
11638549Sjkh
116421698Sjkh	case '\033':	/* ESC */
11659202Srgrimes	case 'Q':
11668549Sjkh	    labeling = FALSE;
11678549Sjkh	    break;
11688549Sjkh
11698549Sjkh	default:
11708549Sjkh	    beep();
117117362Sjkh	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
117217362Sjkh	    msg = _msg;
11738549Sjkh	    break;
11748549Sjkh	}
117529633Sjkh        if (label_chunk_info[here].type == PART_SLICE)
117629633Sjkh            pslice_focus = here;
117729633Sjkh        else
117829633Sjkh            label_focus = here;
11798549Sjkh    }
118054587Sjkh    restorescr(w);
118154587Sjkh    return DITEM_SUCCESS;
11828549Sjkh}
118326456Sjkh
118426456Sjkhstatic int
118530345SjkhdiskLabelNonInteractive(Device *dev)
118626456Sjkh{
118726456Sjkh    char *cp;
118826456Sjkh    PartType type;
118926456Sjkh    PartInfo *p;
119026456Sjkh    u_long flags = 0;
119126456Sjkh    int i, status;
119226456Sjkh    Device **devs;
119326456Sjkh    Disk *d;
119454587Sjkh
119526456Sjkh    status = DITEM_SUCCESS;
119626456Sjkh    cp = variable_get(VAR_DISK);
119726456Sjkh    if (!cp) {
119826456Sjkh	msgConfirm("diskLabel:  No disk selected - can't label automatically.");
119926456Sjkh	return DITEM_FAILURE;
120026456Sjkh    }
120126456Sjkh    devs = deviceFind(cp, DEVICE_TYPE_DISK);
120226456Sjkh    if (!devs) {
120326456Sjkh	msgConfirm("diskLabel: No disk device %s found!", cp);
120426456Sjkh	return DITEM_FAILURE;
120526456Sjkh    }
120630345Sjkh    if (dev)
120730345Sjkh	d = dev->private;
120830345Sjkh    else
120930345Sjkh	d = devs[0]->private;
121042386Sjkh#ifdef __alpha__
121143392Sjkh    maybe_dedicate(d);
121242386Sjkh#endif
121330345Sjkh    record_label_chunks(devs, dev);
121426456Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
121526456Sjkh	Chunk *c1 = label_chunk_info[i].c;
121626456Sjkh
121726456Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
121828075Sjkh	    char name[512];
121928075Sjkh	    int entries = 1;
122026456Sjkh
122128075Sjkh	    while (entries) {
122228075Sjkh		snprintf(name, sizeof name, "%s-%d", c1->name, entries);
122328075Sjkh		if ((cp = variable_get(name)) != NULL) {
122428075Sjkh		    int sz;
122528075Sjkh		    char typ[10], mpoint[50];
122626456Sjkh
122728075Sjkh		    if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) {
122828075Sjkh			msgConfirm("For slice entry %s, got an invalid detail entry of: %s",  c1->name, cp);
122926456Sjkh			status = DITEM_FAILURE;
123026456Sjkh			continue;
123126456Sjkh		    }
123226456Sjkh		    else {
123328075Sjkh			Chunk *tmp;
123428075Sjkh
123528075Sjkh			if (!strcmp(typ, "swap")) {
123628075Sjkh			    type = PART_SWAP;
123728075Sjkh			    strcpy(mpoint, "SWAP");
123828075Sjkh			}
123928075Sjkh			else {
124028075Sjkh			    type = PART_FILESYSTEM;
124128075Sjkh			    if (!strcmp(mpoint, "/"))
124228075Sjkh				flags |= CHUNK_IS_ROOT;
124333132Sjkh			    else
124433132Sjkh				flags &= ~CHUNK_IS_ROOT;
124528075Sjkh			}
124628075Sjkh			if (!sz)
124728075Sjkh			    sz = space_free(c1);
124828075Sjkh			if (sz > space_free(c1)) {
124928075Sjkh			    msgConfirm("Not enough free space to create partition: %s", mpoint);
125028075Sjkh			    status = DITEM_FAILURE;
125128075Sjkh			    continue;
125228075Sjkh			}
125328075Sjkh			if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
125428075Sjkh						      (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
125528075Sjkh			    msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
125628075Sjkh			    status = DITEM_FAILURE;
125728075Sjkh			    break;
125828075Sjkh			}
125928075Sjkh			else {
126028075Sjkh			    tmp->private_data = new_part(mpoint, TRUE, sz);
126128075Sjkh			    tmp->private_free = safe_free;
126228075Sjkh			    status = DITEM_SUCCESS;
126328075Sjkh			}
126426456Sjkh		    }
126528075Sjkh		    entries++;
126626456Sjkh		}
126728075Sjkh		else {
126828075Sjkh		    /* No more matches, leave the loop */
126928075Sjkh		    entries = 0;
127028075Sjkh		}
127126456Sjkh	    }
127226456Sjkh	}
127326456Sjkh	else {
127428075Sjkh	    /* Must be something we can set a mountpoint for */
127526456Sjkh	    cp = variable_get(c1->name);
127626456Sjkh	    if (cp) {
127728075Sjkh		char mpoint[50], do_newfs[8];
127826456Sjkh		Boolean newfs = FALSE;
127926456Sjkh
128028075Sjkh		do_newfs[0] = '\0';
128128075Sjkh		if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
128226456Sjkh		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
128326456Sjkh		    status = DITEM_FAILURE;
128426456Sjkh		    continue;
128526456Sjkh		}
128628075Sjkh		newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
128726456Sjkh		if (c1->private_data) {
128826456Sjkh		    p = c1->private_data;
128926456Sjkh		    p->newfs = newfs;
129026456Sjkh		    strcpy(p->mountpoint, mpoint);
129126456Sjkh		}
129226456Sjkh		else {
129326456Sjkh		    c1->private_data = new_part(mpoint, newfs, 0);
129426456Sjkh		    c1->private_free = safe_free;
129526456Sjkh		}
129626456Sjkh		if (!strcmp(mpoint, "/"))
129726456Sjkh		    c1->flags |= CHUNK_IS_ROOT;
129826456Sjkh		else
129926456Sjkh		    c1->flags &= ~CHUNK_IS_ROOT;
130026456Sjkh	    }
130126456Sjkh	}
130226456Sjkh    }
130326456Sjkh    if (status == DITEM_SUCCESS)
130443685Sjkh	variable_set2(DISK_LABELLED, "yes", 0);
130526456Sjkh    return status;
130626456Sjkh}
1307