label.c revision 76299
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 76299 2001-05-06 02:52:45Z 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__
6675250Sobrien#define ROOT_DEFAULT_SIZE		120
6772122Sobrien#else
6872124Sobrien#define ROOT_DEFAULT_SIZE		100
6944601Sjkh#endif
7044601Sjkh
7112661Speter/* The smallest swap partition we want to create by default */
7254716Sjkh#define SWAP_MIN_SIZE			32
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) {
17774156Sjkh	if (variable_cmp(DISK_LABELLED, "written"))
17843685Sjkh	    variable_set2(DISK_LABELLED, "yes", 0);
17918744Sjkh    }
18012661Speter    return i;
18112661Speter}
18212661Speter
18312661Speterint
18415091SjkhdiskLabelCommit(dialogMenuItem *self)
18512661Speter{
18612661Speter    char *cp;
18712661Speter    int i;
18812661Speter
18912661Speter    /* Already done? */
19017025Sjkh    if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
19115242Sjkh	i = DITEM_SUCCESS;
19212661Speter    else if (!cp) {
19312661Speter	msgConfirm("You must assign disk labels before this option can be used.");
19415242Sjkh	i = DITEM_FAILURE;
19512661Speter    }
19612661Speter    /* The routine will guard against redundant writes, just as this one does */
19715419Sjkh    else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
19815242Sjkh	i = DITEM_FAILURE;
19915419Sjkh    else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
20015242Sjkh	i = DITEM_FAILURE;
20112661Speter    else {
20212661Speter	msgInfo("All filesystem information written successfully.");
20343685Sjkh	variable_set2(DISK_LABELLED, "written", 0);
20415242Sjkh	i = DITEM_SUCCESS;
20512661Speter    }
20612661Speter    return i;
20712661Speter}
20812661Speter
2098549Sjkh/* See if we're already using a desired partition name */
2108549Sjkhstatic Boolean
2118549Sjkhcheck_conflict(char *name)
2128549Sjkh{
2138549Sjkh    int i;
2148549Sjkh
2158751Sjkh    for (i = 0; label_chunk_info[i].c; i++)
21623729Sjkh	if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)
21723729Sjkh	    && label_chunk_info[i].c->private_data
21814793Sjoerg	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
2198549Sjkh	    return TRUE;
2208549Sjkh    return FALSE;
2218549Sjkh}
2228549Sjkh
2238549Sjkh/* How much space is in this FreeBSD slice? */
2248549Sjkhstatic int
2258549Sjkhspace_free(struct chunk *c)
2268549Sjkh{
22712661Speter    struct chunk *c1;
2288549Sjkh    int sz = c->size;
2298549Sjkh
23012661Speter    for (c1 = c->part; c1; c1 = c1->next) {
2318549Sjkh	if (c1->type != unused)
2328549Sjkh	    sz -= c1->size;
2338549Sjkh    }
2348549Sjkh    if (sz < 0)
2358549Sjkh	msgFatal("Partitions are larger than actual chunk??");
2368549Sjkh    return sz;
2378549Sjkh}
2388549Sjkh
2398549Sjkh/* Snapshot the current situation into the displayed chunks structure */
2408549Sjkhstatic void
24130345Sjkhrecord_label_chunks(Device **devs, Device *dev)
2428549Sjkh{
2438549Sjkh    int i, j, p;
2448549Sjkh    struct chunk *c1, *c2;
2458556Sjkh    Disk *d;
2468549Sjkh
2478549Sjkh    j = p = 0;
2488556Sjkh    /* First buzz through and pick up the FreeBSD slices */
2498549Sjkh    for (i = 0; devs[i]; i++) {
25030345Sjkh	if ((dev && devs[i] != dev) || !devs[i]->enabled)
2518556Sjkh	    continue;
2528556Sjkh	d = (Disk *)devs[i]->private;
2538556Sjkh	if (!d->chunks)
2548556Sjkh	    msgFatal("No chunk list found for %s!", d->name);
2558549Sjkh
2568556Sjkh	/* Put the slice entries first */
2578556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2588549Sjkh	    if (c1->type == freebsd) {
2598549Sjkh		label_chunk_info[j].type = PART_SLICE;
2608549Sjkh		label_chunk_info[j].c = c1;
2618549Sjkh		++j;
2628549Sjkh	    }
2638549Sjkh	}
2648549Sjkh    }
26512661Speter
2668556Sjkh    /* Now run through again and get the FreeBSD partition entries */
2678556Sjkh    for (i = 0; devs[i]; i++) {
2688556Sjkh	if (!devs[i]->enabled)
2698556Sjkh	    continue;
2708556Sjkh	d = (Disk *)devs[i]->private;
2718549Sjkh	/* Then buzz through and pick up the partitions */
2728556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2738549Sjkh	    if (c1->type == freebsd) {
2748549Sjkh		for (c2 = c1->part; c2; c2 = c2->next) {
2758549Sjkh		    if (c2->type == part) {
2768549Sjkh			if (c2->subtype == FS_SWAP)
2778549Sjkh			    label_chunk_info[j].type = PART_SWAP;
2788549Sjkh			else
2798549Sjkh			    label_chunk_info[j].type = PART_FILESYSTEM;
2808549Sjkh			label_chunk_info[j].c = c2;
2818549Sjkh			++j;
2828549Sjkh		    }
2838549Sjkh		}
2848549Sjkh	    }
2858549Sjkh	    else if (c1->type == fat) {
2868549Sjkh		label_chunk_info[j].type = PART_FAT;
2878549Sjkh		label_chunk_info[j].c = c1;
2888702Sjkh		++j;
2898549Sjkh	    }
2908549Sjkh	}
2918549Sjkh    }
2928549Sjkh    label_chunk_info[j].c = NULL;
29329249Sjkh    if (here >= j) {
2948549Sjkh	here = j  ? j - 1 : 0;
29529249Sjkh    }
2968549Sjkh}
2978549Sjkh
2988549Sjkh/* A new partition entry */
2998549Sjkhstatic PartInfo *
3008665Sphknew_part(char *mpoint, Boolean newfs, u_long size)
3018549Sjkh{
3028549Sjkh    PartInfo *ret;
3038549Sjkh
3049202Srgrimes    if (!mpoint)
3059202Srgrimes	mpoint = "/change_me";
3069202Srgrimes
3078549Sjkh    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
30820247Sjkh    sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX);
30949441Sphk    strcpy(ret->newfs_cmd, "newfs ");
31049441Sphk    strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS));
3118666Sphk    ret->newfs = newfs;
31274086Sjkh    ret->soft = 0;
3138669Sphk    if (!size)
31429249Sjkh	return ret;
3158549Sjkh    return ret;
3168549Sjkh}
3178549Sjkh
3188549Sjkh/* Get the mountpoint for a partition and save it away */
31912661Speterstatic PartInfo *
3208589Sjkhget_mountpoint(struct chunk *old)
3218549Sjkh{
3228549Sjkh    char *val;
3238549Sjkh    PartInfo *tmp;
3248549Sjkh
32514793Sjoerg    if (old && old->private_data)
32614793Sjoerg	tmp = old->private_data;
3278810Sjkh    else
3288810Sjkh	tmp = NULL;
3298810Sjkh    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
3308764Sjkh    if (!val || !*val) {
3318751Sjkh	if (!old)
3328751Sjkh	    return NULL;
3338751Sjkh	else {
33414793Sjoerg	    free(old->private_data);
33514793Sjoerg	    old->private_data = NULL;
3368751Sjkh	}
3378669Sphk	return NULL;
3388751Sjkh    }
3398669Sphk
3408669Sphk    /* Is it just the same value? */
3418810Sjkh    if (tmp && !strcmp(tmp->mountpoint, val))
3428669Sphk	return NULL;
3438810Sjkh
3448810Sjkh    /* Did we use it already? */
3458669Sphk    if (check_conflict(val)) {
3468669Sphk	msgConfirm("You already have a mount point for %s assigned!", val);
3478669Sphk	return NULL;
3488549Sjkh    }
3498810Sjkh
3508810Sjkh    /* Is it bogus? */
3518669Sphk    if (*val != '/') {
3528669Sphk	msgConfirm("Mount point must start with a / character");
3538669Sphk	return NULL;
3548669Sphk    }
3558810Sjkh
3568810Sjkh    /* Is it going to be mounted on root? */
3578669Sphk    if (!strcmp(val, "/")) {
3588669Sphk	if (old)
3598669Sphk	    old->flags |= CHUNK_IS_ROOT;
3608810Sjkh    }
3618810Sjkh    else if (old)
3628669Sphk	old->flags &= ~CHUNK_IS_ROOT;
3638810Sjkh
3648810Sjkh    safe_free(tmp);
36546615Sjkh    val = string_skipwhite(string_prune(val));
3668669Sphk    tmp = new_part(val, TRUE, 0);
3678669Sphk    if (old) {
36814793Sjoerg	old->private_data = tmp;
3698669Sphk	old->private_free = safe_free;
3708669Sphk    }
3718669Sphk    return tmp;
3728549Sjkh}
3738549Sjkh
3748549Sjkh/* Get the type of the new partiton */
3758549Sjkhstatic PartType
3768549Sjkhget_partition_type(void)
3778549Sjkh{
3788549Sjkh    char selection[20];
3798669Sphk    int i;
3808549Sjkh    static unsigned char *fs_types[] = {
3818549Sjkh	"FS",
3828549Sjkh	"A file system",
3838549Sjkh	"Swap",
3848549Sjkh	"A swap partition.",
3858549Sjkh    };
38654587Sjkh    WINDOW *w = savescr();
38754587Sjkh
3888669Sphk    i = dialog_menu("Please choose a partition type",
38912661Speter		    "If you want to use this partition for swap space, select Swap.\n"
39012661Speter		    "If you want to put a filesystem on it, choose FS.",
39112661Speter		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
39254587Sjkh    restorescr(w);
3938669Sphk    if (!i) {
3948549Sjkh	if (!strcmp(selection, "FS"))
3958549Sjkh	    return PART_FILESYSTEM;
3968549Sjkh	else if (!strcmp(selection, "Swap"))
3978549Sjkh	    return PART_SWAP;
3988549Sjkh    }
3998549Sjkh    return PART_NONE;
4008549Sjkh}
4018549Sjkh
4028549Sjkh/* If the user wants a special newfs command for this, set it */
4038549Sjkhstatic void
4048549SjkhgetNewfsCmd(PartInfo *p)
4058549Sjkh{
4068549Sjkh    char *val;
4078549Sjkh
4088549Sjkh    val = msgGetInput(p->newfs_cmd,
40912661Speter		      "Please enter the newfs command and options you'd like to use in\n"
41012661Speter		      "creating this file system.");
4118549Sjkh    if (val)
41220247Sjkh	sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
4138549Sjkh}
4148549Sjkh
41576299Sjkh#define MAX_MOUNT_NAME	9
4168549Sjkh
4178549Sjkh#define PART_PART_COL	0
41854014Sjkh#define PART_MOUNT_COL	10
4198549Sjkh#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
42049202Sbrian#define PART_NEWFS_COL	(PART_SIZE_COL + 8)
42176299Sjkh#define PART_OFF	38
4228549Sjkh
42329249Sjkh#define TOTAL_AVAIL_LINES       (10)
42429249Sjkh#define PSLICE_SHOWABLE          (4)
42529249Sjkh
42629249Sjkh
4278549Sjkh/* stick this all up on the screen */
4288549Sjkhstatic void
4298549Sjkhprint_label_chunks(void)
4308549Sjkh{
43129249Sjkh    int  i, j, srow, prow, pcol;
43229249Sjkh    int  sz;
43329249Sjkh    char clrmsg[80];
43429633Sjkh    int ChunkPartStartRow;
43529633Sjkh    WINDOW *ChunkWin;
4368549Sjkh
43729249Sjkh    /********************************************************/
43829249Sjkh    /*** These values are for controling screen resources ***/
43929249Sjkh    /*** Each label line holds up to 2 labels, so beware! ***/
44029249Sjkh    /*** strategy will be to try to always make sure the  ***/
44129249Sjkh    /*** highlighted label is in the active display area. ***/
44229249Sjkh    /********************************************************/
44329249Sjkh    int  pslice_max, label_max;
44429249Sjkh    int  pslice_count, label_count, label_focus_found, pslice_focus_found;
44529249Sjkh
4468549Sjkh    attrset(A_REVERSE);
4478549Sjkh    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
4488549Sjkh    attrset(A_NORMAL);
4498549Sjkh
45029633Sjkh    /*** Count the number of parition slices ***/
45129633Sjkh    pslice_count = 0;
45229633Sjkh    for (i = 0; label_chunk_info[i].c ; i++) {
45329633Sjkh        if (label_chunk_info[i].type == PART_SLICE)
45429633Sjkh            ++pslice_count;
45529633Sjkh    }
45629633Sjkh    pslice_max = pslice_count;
45729633Sjkh
45829633Sjkh    /*** 4 line max for partition slices ***/
45929633Sjkh    if (pslice_max > PSLICE_SHOWABLE) {
46029633Sjkh        pslice_max = PSLICE_SHOWABLE;
46129633Sjkh    }
46229633Sjkh    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
46329633Sjkh
46429633Sjkh    /*** View partition slices modulo pslice_max ***/
46529633Sjkh    label_max = TOTAL_AVAIL_LINES - pslice_max;
46629633Sjkh
4678549Sjkh    for (i = 0; i < 2; i++) {
46815440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
46915440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
4708549Sjkh
47115440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
47215440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
4738549Sjkh
47449202Sbrian	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
47549202Sbrian	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
4768549Sjkh
47715440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
47815440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
4798549Sjkh    }
4808549Sjkh    srow = CHUNK_SLICE_START_ROW;
48115440Sjkh    prow = 0;
4828549Sjkh    pcol = 0;
4838549Sjkh
48429249Sjkh    /*** these variables indicate that the focused item is shown currently ***/
48529249Sjkh    label_focus_found = 0;
48629249Sjkh    pslice_focus_found = 0;
48729249Sjkh
48829249Sjkh    label_count = 0;
48929249Sjkh    pslice_count = 0;
49029249Sjkh    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "          ");
49129249Sjkh    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "          ");
49229249Sjkh
49329633Sjkh    ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
49429633Sjkh
49529633Sjkh    wclear(ChunkWin);
49629633Sjkh    /*** wrefresh(ChunkWin); ***/
49729633Sjkh
4988751Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
4998549Sjkh	/* Is it a slice entry displayed at the top? */
5008549Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
50129249Sjkh            /*** This causes the new pslice to replace the previous display ***/
50229249Sjkh            /*** focus must remain on the most recently active pslice       ***/
50329249Sjkh            if (pslice_count == pslice_max) {
50429249Sjkh                if (pslice_focus_found) {
50529249Sjkh                    /*** This is where we can mark the more following ***/
50629249Sjkh                    attrset(A_BOLD);
50729249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
50829249Sjkh                    attrset(A_NORMAL);
50929249Sjkh                    continue;
51029249Sjkh                }
51129249Sjkh                else {
51229249Sjkh                    /*** this is where we set the more previous ***/
51329249Sjkh                    attrset(A_BOLD);
51429249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
51529249Sjkh                    attrset(A_NORMAL);
51629249Sjkh                    pslice_count = 0;
51729249Sjkh                    srow = CHUNK_SLICE_START_ROW;
51829249Sjkh                }
51929249Sjkh            }
52029249Sjkh
5218549Sjkh	    sz = space_free(label_chunk_info[i].c);
52215440Sjkh	    if (i == here)
52316208Sjkh		attrset(ATTR_SELECTED);
52429249Sjkh            if (i == pslice_focus)
52529249Sjkh                pslice_focus_found = -1;
52629249Sjkh
52729249Sjkh	    mvprintw(srow++, 0,
52829249Sjkh		     "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
52929249Sjkh		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name,
53029249Sjkh		     sz, (sz / ONE_MEG));
53115440Sjkh	    attrset(A_NORMAL);
53215440Sjkh	    clrtoeol();
53315440Sjkh	    move(0, 0);
53429633Sjkh	    /*** refresh(); ***/
53529249Sjkh            ++pslice_count;
5368549Sjkh	}
53715440Sjkh	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
5388549Sjkh	else {
53974086Sjkh	    char onestr[PART_OFF], num[10], *mountpoint, newfs[10];
5408549Sjkh
5418549Sjkh	    /*
5428549Sjkh	     * We copy this into a blank-padded string so that it looks like
5438549Sjkh	     * a solid bar in reverse-video
5448549Sjkh	     */
5458549Sjkh	    memset(onestr, ' ', PART_OFF - 1);
5468549Sjkh	    onestr[PART_OFF - 1] = '\0';
54729249Sjkh
54829249Sjkh            /*** Track how many labels have been displayed ***/
54929249Sjkh            if (label_count == ((label_max - 1 ) * 2)) {
55029249Sjkh                if (label_focus_found) {
55129249Sjkh                    continue;
55229249Sjkh                }
55329249Sjkh                else {
55429249Sjkh                    label_count = 0;
55529249Sjkh                    prow = 0;
55629249Sjkh                    pcol = 0;
55729249Sjkh                }
55829249Sjkh            }
55929249Sjkh
56015440Sjkh	    /* Go for two columns if we've written one full columns worth */
56129249Sjkh	    /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
56229249Sjkh            if (label_count == label_max - 1) {
5638549Sjkh		pcol = PART_OFF;
56415440Sjkh		prow = 0;
5658549Sjkh	    }
5668705Sjkh	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
5678549Sjkh	    /* If it's a filesystem, display the mountpoint */
56814793Sjoerg	    if (label_chunk_info[i].c->private_data
56910882Speter		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
57014793Sjoerg	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
57123529Sjkh	    else if (label_chunk_info[i].type == PART_SWAP)
57223529Sjkh		mountpoint = "swap";
57310882Speter	    else
57410882Speter	        mountpoint = "<none>";
57510882Speter
57610882Speter	    /* Now display the newfs field */
57710882Speter	    if (label_chunk_info[i].type == PART_FAT)
57874086Sjkh	        strcpy(newfs, "DOS");
57974086Sjkh	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) {
58074086Sjkh		strcpy(newfs, "UFS");
58176299Sjkh		strcat(newfs,
58276299Sjkh		    ((PartInfo *)label_chunk_info[i].c->private_data)->soft ?
58376299Sjkh		      "+S" : "  ");
58476299Sjkh		strcat(newfs,
58576299Sjkh		    ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ?
58676299Sjkh		      " Y" : " N");
58774086Sjkh	    }
58810882Speter	    else if (label_chunk_info[i].type == PART_SWAP)
58974086Sjkh		strcpy(newfs, "SWAP");
59010882Speter	    else
59174086Sjkh		strcpy(newfs, "*");
5928549Sjkh	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
5938549Sjkh		onestr[PART_MOUNT_COL + j] = mountpoint[j];
59449202Sbrian	    snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
5958549Sjkh	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
5968549Sjkh	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
5978549Sjkh	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
59829633Sjkh            if (i == label_focus) {
59929633Sjkh                label_focus_found = -1;
60029633Sjkh                wattrset(ChunkWin, A_BOLD);
60129633Sjkh            }
60215440Sjkh	    if (i == here)
60316208Sjkh		wattrset(ChunkWin, ATTR_SELECTED);
60429249Sjkh
60574086Sjkh            /*** lazy man's way of expensively padding this string ***/
60674086Sjkh            while (strlen(onestr) < 37)
60729249Sjkh                strcat(onestr, " ");
60829249Sjkh
60915440Sjkh	    mvwaddstr(ChunkWin, prow, pcol, onestr);
61015440Sjkh	    wattrset(ChunkWin, A_NORMAL);
61115440Sjkh	    move(0, 0);
6128549Sjkh	    ++prow;
61329249Sjkh            ++label_count;
6148549Sjkh	}
6158549Sjkh    }
61629249Sjkh
61729249Sjkh    /*** this will erase all the extra stuff ***/
61829249Sjkh    memset(clrmsg, ' ', 37);
61929249Sjkh    clrmsg[37] = '\0';
62029249Sjkh
62129249Sjkh    while (pslice_count < pslice_max) {
62229249Sjkh        mvprintw(srow++, 0, clrmsg);
62329249Sjkh        clrtoeol();
62429249Sjkh        ++pslice_count;
62529249Sjkh    }
62629633Sjkh    while (label_count < (2 * (label_max - 1))) {
62729633Sjkh        mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
62829633Sjkh	++label_count;
62929633Sjkh	if (prow == (label_max - 1)) {
63029633Sjkh	    prow = 0;
63129633Sjkh	    pcol = PART_OFF;
63229633Sjkh	}
63329249Sjkh    }
63429633Sjkh    refresh();
63529633Sjkh    wrefresh(ChunkWin);
6368549Sjkh}
6378549Sjkh
6388549Sjkhstatic void
63918619Sjkhprint_command_summary(void)
6408549Sjkh{
6418820Sjkh    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
64274086Sjkh    mvprintw(18, 0, "C = Create        D = Delete   M = Mount pt.");
64315440Sjkh    if (!RunningAsInit)
64474086Sjkh	mvprintw(18, 47, "W = Write");
64574086Sjkh    mvprintw(19, 0, "N = Newfs Opts    Q = Finish   S = Toggle SoftUpdates");
64674086Sjkh    mvprintw(20, 0, "T = Toggle Newfs  U = Undo     A = Auto Defaults");
64715695Sjkh    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
6488549Sjkh    move(0, 0);
6498549Sjkh}
6508549Sjkh
65118619Sjkhstatic void
65218619Sjkhclear_wins(void)
65318619Sjkh{
65429633Sjkh    extern void print_label_chunks();
65518619Sjkh    clear();
65629633Sjkh    print_label_chunks();
65718619Sjkh}
65818619Sjkh
65943392Sjkh#ifdef __alpha__
66043392Sjkh
66143392Sjkh/*
66243392Sjkh * If there isn't a freebsd chunk already (i.e. there is no label),
66343392Sjkh * dedicate the disk.
66443392Sjkh */
66543392Sjkhstatic void
66643392Sjkhmaybe_dedicate(Disk* d)
66743392Sjkh{
66843392Sjkh    struct chunk *c;
66943392Sjkh
67043392Sjkh    for (c = d->chunks->part; c; c = c->next) {
67143392Sjkh	if (c->type == freebsd)
67243392Sjkh	    break;
67343392Sjkh    }
67443392Sjkh
67543392Sjkh    if (!c) {
67643392Sjkh	msgDebug("dedicating disk");
67743392Sjkh	All_FreeBSD(d, 1);
67843392Sjkh    }
67943392Sjkh}
68043392Sjkh
68143392Sjkh#endif
68243392Sjkh
68312661Speterstatic int
68430345SjkhdiskLabel(Device *dev)
6858549Sjkh{
68618619Sjkh    int sz, key = 0;
6878549Sjkh    Boolean labeling;
6888549Sjkh    char *msg = NULL;
6899202Srgrimes    PartInfo *p, *oldp;
6908549Sjkh    PartType type;
6918824Sjkh    Device **devs;
69242386Sjkh#ifdef __alpha__
69342386Sjkh    int i;
69442386Sjkh#endif
69554587Sjkh    WINDOW *w = savescr();
6968549Sjkh
69729628Sjkh    label_focus = 0;
69829628Sjkh    pslice_focus = 0;
69929633Sjkh    here = 0;
70030345Sjkh
70112661Speter    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
70212661Speter    if (!devs) {
70312661Speter	msgConfirm("No disks found!");
70454587Sjkh	restorescr(w);
70515242Sjkh	return DITEM_FAILURE;
70612661Speter    }
7078549Sjkh    labeling = TRUE;
7088549Sjkh    keypad(stdscr, TRUE);
70942386Sjkh#ifdef __alpha__
71042386Sjkh    for (i = 0; devs[i]; i++) {
71143392Sjkh	maybe_dedicate((Disk*) devs[i]->private);
71242386Sjkh    }
71342386Sjkh#endif
71430345Sjkh    record_label_chunks(devs, dev);
7158549Sjkh
71618619Sjkh    clear();
7178549Sjkh    while (labeling) {
71818744Sjkh	char *cp;
71918744Sjkh
7208549Sjkh	print_label_chunks();
72118619Sjkh	print_command_summary();
7228549Sjkh	if (msg) {
72315695Sjkh	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
72412661Speter	    clrtoeol();
7258549Sjkh	    beep();
7268549Sjkh	    msg = NULL;
7278549Sjkh	}
72815442Sjkh	else {
72915442Sjkh	    move(23, 0);
73015442Sjkh	    clrtoeol();
73115442Sjkh	}
73218744Sjkh
73318619Sjkh	refresh();
73417397Sjkh	key = getch();
73517397Sjkh	switch (toupper(key)) {
73615440Sjkh	    int i;
73717362Sjkh	    static char _msg[40];
7388549Sjkh
7398751Sjkh	case '\014':	/* ^L */
74018619Sjkh	    clear_wins();
74118619Sjkh	    break;
7428751Sjkh
74321698Sjkh	case '\020':	/* ^P */
7448549Sjkh	case KEY_UP:
7458549Sjkh	case '-':
7468549Sjkh	    if (here != 0)
7478549Sjkh		--here;
7488751Sjkh	    else
7498751Sjkh		while (label_chunk_info[here + 1].c)
7508751Sjkh		    ++here;
7518549Sjkh	    break;
7528549Sjkh
75321698Sjkh	case '\016':	/* ^N */
7548549Sjkh	case KEY_DOWN:
7558549Sjkh	case '+':
7568549Sjkh	case '\r':
7578549Sjkh	case '\n':
7588751Sjkh	    if (label_chunk_info[here + 1].c)
7598549Sjkh		++here;
7608751Sjkh	    else
7618751Sjkh		here = 0;
7628549Sjkh	    break;
7638549Sjkh
7648549Sjkh	case KEY_HOME:
7658549Sjkh	    here = 0;
7668549Sjkh	    break;
7678549Sjkh
7688549Sjkh	case KEY_END:
7698751Sjkh	    while (label_chunk_info[here + 1].c)
7708549Sjkh		++here;
7718549Sjkh	    break;
7728549Sjkh
7738549Sjkh	case KEY_F(1):
7748549Sjkh	case '?':
77512661Speter	    systemDisplayHelp("partition");
77618619Sjkh	    clear_wins();
7778549Sjkh	    break;
7788549Sjkh
77910882Speter	case 'A':
78010882Speter	    if (label_chunk_info[here].type != PART_SLICE) {
78115440Sjkh		msg = "You can only do this in a disk slice (at top of screen)";
78210882Speter		break;
78310882Speter	    }
78410882Speter	    sz = space_free(label_chunk_info[here].c);
78517362Sjkh	    if (sz <= FS_MIN_SIZE)
78615440Sjkh		msg = "Not enough free space to create a new partition in the slice";
78715440Sjkh	    else {
78815440Sjkh		struct chunk *tmp;
78915440Sjkh		int mib[2];
79015440Sjkh		int physmem;
79115440Sjkh		size_t size, swsize;
79215440Sjkh		char *cp;
79317362Sjkh		Chunk *rootdev, *swapdev, *usrdev, *vardev;
79412661Speter
79517368Sjkh		(void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev);
79617362Sjkh		if (!rootdev) {
79717362Sjkh		    cp = variable_get(VAR_ROOT_SIZE);
79817362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
79944601Sjkh					    (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS,  CHUNK_IS_ROOT);
80017362Sjkh		    if (!tmp) {
80117362Sjkh			msgConfirm("Unable to create the root partition. Too big?");
80218619Sjkh			clear_wins();
80317362Sjkh			break;
80417362Sjkh		    }
80517362Sjkh		    tmp->private_data = new_part("/", TRUE, tmp->size);
80617362Sjkh		    tmp->private_free = safe_free;
80730345Sjkh		    record_label_chunks(devs, dev);
80815440Sjkh		}
80917362Sjkh
81017362Sjkh		if (!swapdev) {
81117362Sjkh		    cp = variable_get(VAR_SWAP_SIZE);
81217362Sjkh		    if (cp)
81317362Sjkh			swsize = atoi(cp) * ONE_MEG;
81417362Sjkh		    else {
81517362Sjkh			mib[0] = CTL_HW;
81617362Sjkh			mib[1] = HW_PHYSMEM;
81717362Sjkh			size = sizeof physmem;
81817362Sjkh			sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
81917362Sjkh			swsize = 16 * ONE_MEG + (physmem * 2 / 512);
82017362Sjkh		    }
82117362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
82217362Sjkh					    swsize, part, FS_SWAP, 0);
82317362Sjkh		    if (!tmp) {
82417362Sjkh			msgConfirm("Unable to create the swap partition. Too big?");
82518619Sjkh			clear_wins();
82617362Sjkh			break;
82717362Sjkh		    }
82817362Sjkh		    tmp->private_data = 0;
82917362Sjkh		    tmp->private_free = safe_free;
83030345Sjkh		    record_label_chunks(devs, dev);
83115440Sjkh		}
83217362Sjkh
83317362Sjkh		if (!vardev) {
83417362Sjkh		    cp = variable_get(VAR_VAR_SIZE);
83537735Sjkh		    if (cp)
83637735Sjkh			sz = atoi(cp) * ONE_MEG;
83737735Sjkh		    else
83837735Sjkh			sz = variable_get(VAR_NO_USR)
83937735Sjkh				?  space_free(label_chunk_info[here].c)
84037735Sjkh				:  VAR_MIN_SIZE * ONE_MEG;
84137735Sjkh
84217362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
84337735Sjkh					    sz, part, FS_BSDFFS, 0);
84417362Sjkh		    if (!tmp) {
84517362Sjkh			msgConfirm("Less than %dMB free for /var - you will need to\n"
84617362Sjkh				   "partition your disk manually with a custom install!",
84717362Sjkh				   (cp ? atoi(cp) : VAR_MIN_SIZE));
84818619Sjkh			clear_wins();
84917362Sjkh			break;
85017362Sjkh		    }
85117362Sjkh		    tmp->private_data = new_part("/var", TRUE, tmp->size);
85217362Sjkh		    tmp->private_free = safe_free;
85330345Sjkh		    record_label_chunks(devs, dev);
85415440Sjkh		}
85512661Speter
85637735Sjkh		if (!usrdev && !variable_get(VAR_NO_USR)) {
85717362Sjkh		    cp = variable_get(VAR_USR_SIZE);
85817362Sjkh		    if (cp)
85917362Sjkh			sz = atoi(cp) * ONE_MEG;
86017362Sjkh		    else
86117362Sjkh			sz = space_free(label_chunk_info[here].c);
86229501Sjkh		    if (sz) {
86329501Sjkh			if (sz < (USR_MIN_SIZE * ONE_MEG)) {
86429501Sjkh			    msgConfirm("Less than %dMB free for /usr - you will need to\n"
86529501Sjkh				       "partition your disk manually with a custom install!", USR_MIN_SIZE);
86629501Sjkh			    clear_wins();
86729501Sjkh			    break;
86829501Sjkh			}
86917362Sjkh
87029501Sjkh			tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
87129501Sjkh						label_chunk_info[here].c,
87229501Sjkh						sz, part, FS_BSDFFS, 0);
87329501Sjkh			if (!tmp) {
87429501Sjkh			    msgConfirm("Unable to create the /usr partition.  Not enough space?\n"
87529501Sjkh				       "You will need to partition your disk manually with a custom install!");
87629501Sjkh			    clear_wins();
87729501Sjkh			    break;
87829501Sjkh			}
87929501Sjkh			tmp->private_data = new_part("/usr", TRUE, tmp->size);
88029501Sjkh			tmp->private_free = safe_free;
88130345Sjkh			record_label_chunks(devs, dev);
88217362Sjkh		    }
88315440Sjkh		}
88437735Sjkh
88515440Sjkh		/* At this point, we're reasonably "labelled" */
88674156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
88743685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
88810882Speter	    }
88915440Sjkh	    break;
89010882Speter
8918549Sjkh	case 'C':
8928549Sjkh	    if (label_chunk_info[here].type != PART_SLICE) {
8938549Sjkh		msg = "You can only do this in a master partition (see top of screen)";
8948549Sjkh		break;
8958549Sjkh	    }
8968549Sjkh	    sz = space_free(label_chunk_info[here].c);
8978669Sphk	    if (sz <= FS_MIN_SIZE) {
89812661Speter		msg = "Not enough space to create an additional FreeBSD partition";
8998669Sphk		break;
9008669Sphk	    }
90115440Sjkh	    else {
90218744Sjkh		char *val;
9038702Sjkh		int size;
9048702Sjkh		struct chunk *tmp;
9058820Sjkh		char osize[80];
9068702Sjkh		u_long flags = 0;
9078549Sjkh
9088820Sjkh		sprintf(osize, "%d", sz);
90918619Sjkh		val = msgGetInput(osize,
91057617Sjkh				  "Please specify the partition size in blocks or append a trailing G for\n"
91157617Sjkh				  "gigabytes, M for megabytes, or C for cylinders.\n"
91257617Sjkh				  "%d blocks (%dMB) are free.",
91318619Sjkh				  sz, sz / ONE_MEG);
91418619Sjkh		if (!val || (size = strtol(val, &cp, 0)) <= 0) {
91518619Sjkh		    clear_wins();
9168702Sjkh		    break;
91718619Sjkh		}
9188549Sjkh
9198751Sjkh		if (*cp) {
9208751Sjkh		    if (toupper(*cp) == 'M')
9218751Sjkh			size *= ONE_MEG;
92257617Sjkh		    else if (toupper(*cp) == 'G')
92357617Sjkh			size *= ONE_GIG;
9248751Sjkh		    else if (toupper(*cp) == 'C')
9258751Sjkh			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
9268751Sjkh		}
9278820Sjkh		if (size <= FS_MIN_SIZE) {
9288820Sjkh		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
92918619Sjkh		    clear_wins();
9308820Sjkh		    break;
9318820Sjkh		}
9328702Sjkh		type = get_partition_type();
93318619Sjkh		if (type == PART_NONE) {
93418619Sjkh		    clear_wins();
93518619Sjkh		    beep();
9368669Sphk		    break;
93718619Sjkh		}
9388669Sphk
9398702Sjkh		if (type == PART_FILESYSTEM) {
94018619Sjkh		    if ((p = get_mountpoint(NULL)) == NULL) {
94118619Sjkh			clear_wins();
94218619Sjkh			beep();
9438702Sjkh			break;
94418619Sjkh		    }
9458702Sjkh		    else if (!strcmp(p->mountpoint, "/"))
9468702Sjkh			flags |= CHUNK_IS_ROOT;
9478702Sjkh		    else
9488702Sjkh			flags &= ~CHUNK_IS_ROOT;
94918619Sjkh		}
95018619Sjkh		else
9518702Sjkh		    p = NULL;
9528702Sjkh
95376237Sjkh		if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) {
95476237Sjkh		    msgConfirm("Warning: This is smaller than the recommended size for a\n"
95576237Sjkh			       "root partition.  For a variety of reasons, root\n"
95676237Sjkh			       "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
9578672Sjkh		}
9588751Sjkh		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
9598702Sjkh					label_chunk_info[here].c,
9608702Sjkh					size, part,
9618702Sjkh					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
9628702Sjkh					flags);
9638702Sjkh		if (!tmp) {
9648702Sjkh		    msgConfirm("Unable to create the partition. Too big?");
96518619Sjkh		    clear_wins();
9668672Sjkh		    break;
9678672Sjkh		}
9688702Sjkh		if (type != PART_SWAP) {
9698669Sphk		    /* This is needed to tell the newfs -u about the size */
97014793Sjoerg		    tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
9718669Sphk		    safe_free(p);
97215355Sjkh		}
97315355Sjkh		else
97414793Sjoerg		    tmp->private_data = p;
9758702Sjkh		tmp->private_free = safe_free;
97674156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
97743685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
97830345Sjkh		record_label_chunks(devs, dev);
97918619Sjkh		clear_wins();
98029249Sjkh                /*** This is where we assign focus to new label so it shows ***/
98129249Sjkh                {
98229249Sjkh                    int i;
98329249Sjkh		    label_focus = -1;
98429249Sjkh                    for (i = 0; label_chunk_info[i].c; ++i) {
98529249Sjkh                    	if (label_chunk_info[i].c == tmp) {
98629249Sjkh			    label_focus = i;
98729249Sjkh			    break;
98829249Sjkh			}
98929249Sjkh		    }
99029249Sjkh		    if (label_focus == -1)
99129249Sjkh                    	label_focus = i - 1;
99229249Sjkh                }
9938549Sjkh	    }
9948549Sjkh	    break;
9958549Sjkh
99617397Sjkh	case KEY_DC:
9978549Sjkh	case 'D':	/* delete */
9988549Sjkh	    if (label_chunk_info[here].type == PART_SLICE) {
9998549Sjkh		msg = MSG_NOT_APPLICABLE;
10008549Sjkh		break;
10018549Sjkh	    }
10028549Sjkh	    else if (label_chunk_info[here].type == PART_FAT) {
10038705Sjkh		msg = "Use the Disk Partition Editor to delete DOS partitions";
10048549Sjkh		break;
10058549Sjkh	    }
10068751Sjkh	    Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c);
100774156Sjkh	    if (variable_cmp(DISK_LABELLED, "written"))
100843685Sjkh		variable_set2(DISK_LABELLED, "yes", 0);
100930345Sjkh	    record_label_chunks(devs, dev);
10108549Sjkh	    break;
10118549Sjkh
10128549Sjkh	case 'M':	/* mount */
10138549Sjkh	    switch(label_chunk_info[here].type) {
10148549Sjkh	    case PART_SLICE:
10158549Sjkh		msg = MSG_NOT_APPLICABLE;
10168549Sjkh		break;
10178549Sjkh
10188549Sjkh	    case PART_SWAP:
10198549Sjkh		msg = "You don't need to specify a mountpoint for a swap partition.";
10208549Sjkh		break;
10218549Sjkh
10228556Sjkh	    case PART_FAT:
10238549Sjkh	    case PART_FILESYSTEM:
102414793Sjoerg		oldp = label_chunk_info[here].c->private_data;
10258589Sjkh		p = get_mountpoint(label_chunk_info[here].c);
10268549Sjkh		if (p) {
10279202Srgrimes		    if (!oldp)
10289202Srgrimes		    	p->newfs = FALSE;
10298722Sjkh		    if (label_chunk_info[here].type == PART_FAT
10308722Sjkh			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
10318722Sjkh			    || !strcmp(p->mountpoint, "/var"))) {
10328722Sjkh			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
10338722Sjkh			strcpy(p->mountpoint, "/bogus");
10348722Sjkh		    }
10358549Sjkh		}
103674156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
103743685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
103830345Sjkh		record_label_chunks(devs, dev);
103918636Sjkh		clear_wins();
10408549Sjkh		break;
10418549Sjkh
10428549Sjkh	    default:
10438549Sjkh		msgFatal("Bogus partition under cursor???");
10448549Sjkh		break;
10458549Sjkh	    }
10468549Sjkh	    break;
10478549Sjkh
10488549Sjkh	case 'N':	/* Set newfs options */
104914793Sjoerg	    if (label_chunk_info[here].c->private_data &&
105014793Sjoerg		((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
105114793Sjoerg		getNewfsCmd(label_chunk_info[here].c->private_data);
10528549Sjkh	    else
10538549Sjkh		msg = MSG_NOT_APPLICABLE;
105418636Sjkh	    clear_wins();
10558549Sjkh	    break;
10568549Sjkh
105774086Sjkh	case 'S':	/* Toggle soft updates flag */
105874086Sjkh	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
105974086Sjkh		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
106074086Sjkh		if (pi)
106174086Sjkh		    pi->soft = !pi->soft;
106274086Sjkh		else
106374086Sjkh		    msg = MSG_NOT_APPLICABLE;
106474086Sjkh	    }
106574156Sjkh	    else
106674156Sjkh		msg = MSG_NOT_APPLICABLE;
106774086Sjkh	    break;
106874086Sjkh
10698549Sjkh	case 'T':	/* Toggle newfs state */
10709202Srgrimes	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
107123729Sjkh		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
107223729Sjkh		label_chunk_info[here].c->private_data =
107323729Sjkh		    new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
107474156Sjkh		if (pi && pi->soft)
107574156Sjkh		    ((PartInfo *)label_chunk_info[here].c->private_data)->soft = 1;
107623729Sjkh		safe_free(pi);
107723729Sjkh		label_chunk_info[here].c->private_free = safe_free;
107874156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
107943685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
108018619Sjkh	    }
10818549Sjkh	    else
10828549Sjkh		msg = MSG_NOT_APPLICABLE;
10838549Sjkh	    break;
10848549Sjkh
10858820Sjkh	case 'U':
108612661Speter	    clear();
108774156Sjkh	    if (!variable_cmp(DISK_LABELLED, "written")) {
108818744Sjkh		msgConfirm("You've already written out your changes -\n"
108918744Sjkh			   "it's too late to undo!");
109018744Sjkh	    }
109170005Sjkh	    else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
109218744Sjkh		variable_unset(DISK_PARTITIONED);
109318744Sjkh		variable_unset(DISK_LABELLED);
109418744Sjkh		for (i = 0; devs[i]; i++) {
109518744Sjkh		    Disk *d;
109612661Speter
109718744Sjkh		    if (!devs[i]->enabled)
109818744Sjkh			continue;
109918744Sjkh		    else if ((d = Open_Disk(devs[i]->name)) != NULL) {
110018744Sjkh			Free_Disk(devs[i]->private);
110118744Sjkh			devs[i]->private = d;
110230345Sjkh			diskPartition(devs[i]);
110318744Sjkh		    }
11048824Sjkh		}
110530345Sjkh		record_label_chunks(devs, dev);
11068824Sjkh	    }
110718636Sjkh	    clear_wins();
11088824Sjkh	    break;
11098820Sjkh
11108549Sjkh	case 'W':
111174156Sjkh	    if (!variable_cmp(DISK_LABELLED, "written")) {
111218744Sjkh		msgConfirm("You've already written out your changes - if you\n"
111374156Sjkh			   "wish to overwrite them, you'll have to restart\n"
111474156Sjkh			   "sysinstall first.");
111518744Sjkh	    }
111670005Sjkh	    else if (!msgNoYes("WARNING:  This should only be used when modifying an EXISTING\n"
111718687Sjkh			  "installation.  If you are installing FreeBSD for the first time\n"
111818687Sjkh			  "then you should simply type Q when you're finished here and your\n"
111918687Sjkh			  "changes will be committed in one batch automatically at the end of\n"
112018687Sjkh			  "these questions.\n\n"
112118687Sjkh			  "Are you absolutely sure you want to do this now?")) {
112243685Sjkh		variable_set2(DISK_LABELLED, "yes", 0);
112312661Speter		diskLabelCommit(NULL);
112412661Speter	    }
112518636Sjkh	    clear_wins();
112610882Speter	    break;
112710882Speter
112810882Speter	case '|':
112970005Sjkh	    if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n"
113012661Speter			  "This is an entirely undocumented feature which you are not\n"
113112661Speter			  "expected to understand!")) {
11328549Sjkh		int i;
11338549Sjkh		Device **devs;
11348549Sjkh
11358549Sjkh		dialog_clear();
11368549Sjkh		end_dialog();
11378549Sjkh		DialogActive = FALSE;
11388549Sjkh		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
11398549Sjkh		if (!devs) {
114012661Speter		    msgConfirm("Can't find any disk devices!");
11418549Sjkh		    break;
11428549Sjkh		}
11438668Sphk		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
11448613Sjkh		    if (devs[i]->enabled)
11458613Sjkh		    	slice_wizard(((Disk *)devs[i]->private));
11468613Sjkh		}
114774156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
114843685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
11498665Sphk		DialogActive = TRUE;
115030345Sjkh		record_label_chunks(devs, dev);
115118636Sjkh		clear_wins();
11528549Sjkh	    }
11538549Sjkh	    else
11548549Sjkh		msg = "A most prudent choice!";
11558549Sjkh	    break;
11568549Sjkh
115721698Sjkh	case '\033':	/* ESC */
11589202Srgrimes	case 'Q':
11598549Sjkh	    labeling = FALSE;
11608549Sjkh	    break;
11618549Sjkh
11628549Sjkh	default:
11638549Sjkh	    beep();
116417362Sjkh	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
116517362Sjkh	    msg = _msg;
11668549Sjkh	    break;
11678549Sjkh	}
116829633Sjkh        if (label_chunk_info[here].type == PART_SLICE)
116929633Sjkh            pslice_focus = here;
117029633Sjkh        else
117129633Sjkh            label_focus = here;
11728549Sjkh    }
117354587Sjkh    restorescr(w);
117454587Sjkh    return DITEM_SUCCESS;
11758549Sjkh}
117626456Sjkh
117726456Sjkhstatic int
117830345SjkhdiskLabelNonInteractive(Device *dev)
117926456Sjkh{
118026456Sjkh    char *cp;
118126456Sjkh    PartType type;
118226456Sjkh    PartInfo *p;
118326456Sjkh    u_long flags = 0;
118426456Sjkh    int i, status;
118526456Sjkh    Device **devs;
118626456Sjkh    Disk *d;
118754587Sjkh
118826456Sjkh    status = DITEM_SUCCESS;
118926456Sjkh    cp = variable_get(VAR_DISK);
119026456Sjkh    if (!cp) {
119126456Sjkh	msgConfirm("diskLabel:  No disk selected - can't label automatically.");
119226456Sjkh	return DITEM_FAILURE;
119326456Sjkh    }
119426456Sjkh    devs = deviceFind(cp, DEVICE_TYPE_DISK);
119526456Sjkh    if (!devs) {
119626456Sjkh	msgConfirm("diskLabel: No disk device %s found!", cp);
119726456Sjkh	return DITEM_FAILURE;
119826456Sjkh    }
119930345Sjkh    if (dev)
120030345Sjkh	d = dev->private;
120130345Sjkh    else
120230345Sjkh	d = devs[0]->private;
120342386Sjkh#ifdef __alpha__
120443392Sjkh    maybe_dedicate(d);
120542386Sjkh#endif
120630345Sjkh    record_label_chunks(devs, dev);
120726456Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
120826456Sjkh	Chunk *c1 = label_chunk_info[i].c;
120926456Sjkh
121026456Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
121128075Sjkh	    char name[512];
121274674Sjkh	    int entries = 1;
121326456Sjkh
121428075Sjkh	    while (entries) {
121528075Sjkh		snprintf(name, sizeof name, "%s-%d", c1->name, entries);
121628075Sjkh		if ((cp = variable_get(name)) != NULL) {
121774674Sjkh		    int sz, soft = 0;
121828075Sjkh		    char typ[10], mpoint[50];
121926456Sjkh
122074156Sjkh		    if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) {
122128075Sjkh			msgConfirm("For slice entry %s, got an invalid detail entry of: %s",  c1->name, cp);
122226456Sjkh			status = DITEM_FAILURE;
122326456Sjkh			continue;
122426456Sjkh		    }
122526456Sjkh		    else {
122628075Sjkh			Chunk *tmp;
122728075Sjkh
122828075Sjkh			if (!strcmp(typ, "swap")) {
122928075Sjkh			    type = PART_SWAP;
123028075Sjkh			    strcpy(mpoint, "SWAP");
123128075Sjkh			}
123228075Sjkh			else {
123328075Sjkh			    type = PART_FILESYSTEM;
123428075Sjkh			    if (!strcmp(mpoint, "/"))
123528075Sjkh				flags |= CHUNK_IS_ROOT;
123633132Sjkh			    else
123733132Sjkh				flags &= ~CHUNK_IS_ROOT;
123828075Sjkh			}
123928075Sjkh			if (!sz)
124028075Sjkh			    sz = space_free(c1);
124128075Sjkh			if (sz > space_free(c1)) {
124228075Sjkh			    msgConfirm("Not enough free space to create partition: %s", mpoint);
124328075Sjkh			    status = DITEM_FAILURE;
124428075Sjkh			    continue;
124528075Sjkh			}
124628075Sjkh			if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
124728075Sjkh						      (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
124828075Sjkh			    msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
124928075Sjkh			    status = DITEM_FAILURE;
125028075Sjkh			    break;
125128075Sjkh			}
125228075Sjkh			else {
125328075Sjkh			    tmp->private_data = new_part(mpoint, TRUE, sz);
125428075Sjkh			    tmp->private_free = safe_free;
125574674Sjkh			    ((PartInfo *)tmp->private_data)->soft = soft;
125628075Sjkh			    status = DITEM_SUCCESS;
125728075Sjkh			}
125826456Sjkh		    }
125928075Sjkh		    entries++;
126026456Sjkh		}
126128075Sjkh		else {
126228075Sjkh		    /* No more matches, leave the loop */
126328075Sjkh		    entries = 0;
126428075Sjkh		}
126526456Sjkh	    }
126626456Sjkh	}
126726456Sjkh	else {
126828075Sjkh	    /* Must be something we can set a mountpoint for */
126926456Sjkh	    cp = variable_get(c1->name);
127026456Sjkh	    if (cp) {
127128075Sjkh		char mpoint[50], do_newfs[8];
127226456Sjkh		Boolean newfs = FALSE;
127326456Sjkh
127428075Sjkh		do_newfs[0] = '\0';
127528075Sjkh		if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
127626456Sjkh		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
127726456Sjkh		    status = DITEM_FAILURE;
127826456Sjkh		    continue;
127926456Sjkh		}
128028075Sjkh		newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
128126456Sjkh		if (c1->private_data) {
128226456Sjkh		    p = c1->private_data;
128326456Sjkh		    p->newfs = newfs;
128426456Sjkh		    strcpy(p->mountpoint, mpoint);
128526456Sjkh		}
128626456Sjkh		else {
128726456Sjkh		    c1->private_data = new_part(mpoint, newfs, 0);
128826456Sjkh		    c1->private_free = safe_free;
128926456Sjkh		}
129026456Sjkh		if (!strcmp(mpoint, "/"))
129126456Sjkh		    c1->flags |= CHUNK_IS_ROOT;
129226456Sjkh		else
129326456Sjkh		    c1->flags &= ~CHUNK_IS_ROOT;
129426456Sjkh	    }
129526456Sjkh	}
129626456Sjkh    }
129726456Sjkh    if (status == DITEM_SUCCESS)
129843685Sjkh	variable_set2(DISK_LABELLED, "yes", 0);
129926456Sjkh    return status;
130026456Sjkh}
1301