label.c revision 34543
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 *
734543Sjkh * $Id: label.c,v 1.81 1998/02/06 04:35:21 jkh Exp $
88549Sjkh *
98549Sjkh * Copyright (c) 1995
108549Sjkh *	Jordan Hubbard.  All rights reserved.
118549Sjkh *
128549Sjkh * Redistribution and use in source and binary forms, with or without
138549Sjkh * modification, are permitted provided that the following conditions
148549Sjkh * are met:
158549Sjkh * 1. Redistributions of source code must retain the above copyright
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 */
5812661Speter#define ROOT_MIN_SIZE			20
598549Sjkh
6012661Speter/* The smallest swap partition we want to create by default */
6112661Speter#define SWAP_MIN_SIZE			16
6212661Speter
6312661Speter/* The smallest /usr partition we're willing to create by default */
6412661Speter#define USR_MIN_SIZE			80
6512661Speter
6612661Speter/* The smallest /var partition we're willing to create by default */
6712661Speter#define VAR_MIN_SIZE			30
6812661Speter
6915440Sjkh/* The bottom-most row we're allowed to scribble on */
7029249Sjkh#define CHUNK_ROW_MAX			16
7115440Sjkh
7215440Sjkh
738549Sjkh/* All the chunks currently displayed on the screen */
748549Sjkhstatic struct {
758549Sjkh    struct chunk *c;
768549Sjkh    PartType type;
778549Sjkh} label_chunk_info[MAX_CHUNKS + 1];
788549Sjkhstatic int here;
798549Sjkh
8029249Sjkh/*** with this value we try to track the most recently added label ***/
8129249Sjkhstatic int label_focus = 0, pslice_focus = 0;
8229249Sjkh
8330345Sjkhstatic int diskLabel(Device *dev);
8430345Sjkhstatic int diskLabelNonInteractive(Device *dev);
8512661Speter
8630345Sjkhstatic int
8730345SjkhlabelHook(dialogMenuItem *selected)
8830345Sjkh{
8930345Sjkh    Device **devs = NULL;
9030345Sjkh
9130345Sjkh    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
9230345Sjkh    if (!devs) {
9330345Sjkh	msgConfirm("Unable to find disk %s!", selected->prompt);
9430345Sjkh	return DITEM_FAILURE;
9530345Sjkh    }
9630345Sjkh    /* Toggle enabled status? */
9730345Sjkh    if (!devs[0]->enabled) {
9830345Sjkh	devs[0]->enabled = TRUE;
9930345Sjkh	diskLabel(devs[0]);
10030345Sjkh    }
10130345Sjkh    else
10230345Sjkh	devs[0]->enabled = FALSE;
10330345Sjkh    return DITEM_SUCCESS | DITEM_RESTORE;
10430345Sjkh}
10530345Sjkh
10630345Sjkhstatic int
10730345SjkhlabelCheck(dialogMenuItem *selected)
10830345Sjkh{
10930345Sjkh    Device **devs = NULL;
11030345Sjkh
11130345Sjkh    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
11230345Sjkh    if (!devs || devs[0]->enabled == FALSE)
11330345Sjkh	return FALSE;
11430345Sjkh    return TRUE;
11530345Sjkh}
11630345Sjkh
11712661Speterint
11815091SjkhdiskLabelEditor(dialogMenuItem *self)
11912661Speter{
12030345Sjkh    DMenu *menu;
12112661Speter    Device **devs;
12230345Sjkh    int i, cnt;
12312661Speter
12430345Sjkh    i = 0;
12530345Sjkh    cnt = diskGetSelectCount(&devs);
12630345Sjkh    if (cnt == -1) {
12712661Speter	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
12812661Speter		   "properly probed at boot time.  See the Hardware Guide on the\n"
12912661Speter		   "Documentation menu for clues on diagnosing this type of problem.");
13015242Sjkh	return DITEM_FAILURE;
13112661Speter    }
13230345Sjkh    else if (cnt) {
13330345Sjkh	/* Some are already selected */
13430381Sjkh	if (variable_get(VAR_NONINTERACTIVE))
13534543Sjkh	    i = diskLabelNonInteractive(NULL);
13630381Sjkh	else
13734543Sjkh	    i = diskLabel(NULL);
13812661Speter    }
13930345Sjkh    else {
14030345Sjkh	/* No disks are selected, fall-back case now */
14130345Sjkh	cnt = deviceCount(devs);
14230345Sjkh	if (cnt == 1) {
14330345Sjkh	    devs[0]->enabled = TRUE;
14430345Sjkh	    if (variable_get(VAR_NONINTERACTIVE))
14530345Sjkh		i = diskLabelNonInteractive(devs[0]);
14630345Sjkh	    else
14730345Sjkh		i = diskLabel(devs[0]);
14830345Sjkh	}
14930345Sjkh	else {
15030345Sjkh	    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck);
15130345Sjkh	    if (!menu) {
15230345Sjkh		msgConfirm("No devices suitable for installation found!\n\n"
15330345Sjkh			   "Please verify that your disk controller (and attached drives)\n"
15430345Sjkh			   "were detected properly.  This can be done by pressing the\n"
15530345Sjkh			   "[Scroll Lock] key and using the Arrow keys to move back to\n"
15630345Sjkh			   "the boot messages.  Press [Scroll Lock] again to return.");
15730345Sjkh		i = DITEM_FAILURE;
15830345Sjkh	    }
15930345Sjkh	    else {
16030345Sjkh		i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
16130345Sjkh		free(menu);
16230345Sjkh	    }
16330345Sjkh	    i |= DITEM_RESTORE;
16430345Sjkh	}
16512661Speter    }
16618744Sjkh    if (DITEM_STATUS(i) != DITEM_FAILURE) {
16718744Sjkh	char *cp;
16818744Sjkh
16918744Sjkh	if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
17018744Sjkh	    variable_set2(DISK_LABELLED, "yes");
17118744Sjkh    }
17212661Speter    return i;
17312661Speter}
17412661Speter
17512661Speterint
17615091SjkhdiskLabelCommit(dialogMenuItem *self)
17712661Speter{
17812661Speter    char *cp;
17912661Speter    int i;
18012661Speter
18112661Speter    /* Already done? */
18217025Sjkh    if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
18315242Sjkh	i = DITEM_SUCCESS;
18412661Speter    else if (!cp) {
18512661Speter	msgConfirm("You must assign disk labels before this option can be used.");
18615242Sjkh	i = DITEM_FAILURE;
18712661Speter    }
18812661Speter    /* The routine will guard against redundant writes, just as this one does */
18915419Sjkh    else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
19015242Sjkh	i = DITEM_FAILURE;
19115419Sjkh    else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
19215242Sjkh	i = DITEM_FAILURE;
19312661Speter    else {
19412661Speter	msgInfo("All filesystem information written successfully.");
19512661Speter	variable_set2(DISK_LABELLED, "written");
19615242Sjkh	i = DITEM_SUCCESS;
19712661Speter    }
19812661Speter    return i;
19912661Speter}
20012661Speter
2018549Sjkh/* See if we're already using a desired partition name */
2028549Sjkhstatic Boolean
2038549Sjkhcheck_conflict(char *name)
2048549Sjkh{
2058549Sjkh    int i;
2068549Sjkh
2078751Sjkh    for (i = 0; label_chunk_info[i].c; i++)
20823729Sjkh	if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)
20923729Sjkh	    && label_chunk_info[i].c->private_data
21014793Sjoerg	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
2118549Sjkh	    return TRUE;
2128549Sjkh    return FALSE;
2138549Sjkh}
2148549Sjkh
2158549Sjkh/* How much space is in this FreeBSD slice? */
2168549Sjkhstatic int
2178549Sjkhspace_free(struct chunk *c)
2188549Sjkh{
21912661Speter    struct chunk *c1;
2208549Sjkh    int sz = c->size;
2218549Sjkh
22212661Speter    for (c1 = c->part; c1; c1 = c1->next) {
2238549Sjkh	if (c1->type != unused)
2248549Sjkh	    sz -= c1->size;
2258549Sjkh    }
2268549Sjkh    if (sz < 0)
2278549Sjkh	msgFatal("Partitions are larger than actual chunk??");
2288549Sjkh    return sz;
2298549Sjkh}
2308549Sjkh
2318549Sjkh/* Snapshot the current situation into the displayed chunks structure */
2328549Sjkhstatic void
23330345Sjkhrecord_label_chunks(Device **devs, Device *dev)
2348549Sjkh{
2358549Sjkh    int i, j, p;
2368549Sjkh    struct chunk *c1, *c2;
2378556Sjkh    Disk *d;
2388549Sjkh
2398549Sjkh    j = p = 0;
2408556Sjkh    /* First buzz through and pick up the FreeBSD slices */
2418549Sjkh    for (i = 0; devs[i]; i++) {
24230345Sjkh	if ((dev && devs[i] != dev) || !devs[i]->enabled)
2438556Sjkh	    continue;
2448556Sjkh	d = (Disk *)devs[i]->private;
2458556Sjkh	if (!d->chunks)
2468556Sjkh	    msgFatal("No chunk list found for %s!", d->name);
2478549Sjkh
2488556Sjkh	/* Put the slice entries first */
2498556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2508549Sjkh	    if (c1->type == freebsd) {
2518549Sjkh		label_chunk_info[j].type = PART_SLICE;
2528549Sjkh		label_chunk_info[j].c = c1;
2538549Sjkh		++j;
2548549Sjkh	    }
2558549Sjkh	}
2568549Sjkh    }
25712661Speter
2588556Sjkh    /* Now run through again and get the FreeBSD partition entries */
2598556Sjkh    for (i = 0; devs[i]; i++) {
2608556Sjkh	if (!devs[i]->enabled)
2618556Sjkh	    continue;
2628556Sjkh	d = (Disk *)devs[i]->private;
2638549Sjkh	/* Then buzz through and pick up the partitions */
2648556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2658549Sjkh	    if (c1->type == freebsd) {
2668549Sjkh		for (c2 = c1->part; c2; c2 = c2->next) {
2678549Sjkh		    if (c2->type == part) {
2688549Sjkh			if (c2->subtype == FS_SWAP)
2698549Sjkh			    label_chunk_info[j].type = PART_SWAP;
2708549Sjkh			else
2718549Sjkh			    label_chunk_info[j].type = PART_FILESYSTEM;
2728549Sjkh			label_chunk_info[j].c = c2;
2738549Sjkh			++j;
2748549Sjkh		    }
2758549Sjkh		}
2768549Sjkh	    }
2778549Sjkh	    else if (c1->type == fat) {
2788549Sjkh		label_chunk_info[j].type = PART_FAT;
2798549Sjkh		label_chunk_info[j].c = c1;
2808702Sjkh		++j;
2818549Sjkh	    }
2828549Sjkh	}
2838549Sjkh    }
2848549Sjkh    label_chunk_info[j].c = NULL;
28529249Sjkh    if (here >= j) {
2868549Sjkh	here = j  ? j - 1 : 0;
28729249Sjkh    }
2888549Sjkh}
2898549Sjkh
2908549Sjkh/* A new partition entry */
2918549Sjkhstatic PartInfo *
2928665Sphknew_part(char *mpoint, Boolean newfs, u_long size)
2938549Sjkh{
2948549Sjkh    PartInfo *ret;
2958549Sjkh
2969202Srgrimes    if (!mpoint)
2979202Srgrimes	mpoint = "/change_me";
2989202Srgrimes
2998549Sjkh    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
30020247Sjkh    sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX);
30114335Sjkh    strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024");
3028666Sphk    ret->newfs = newfs;
3038669Sphk    if (!size)
30429249Sjkh	return ret;
3058549Sjkh    return ret;
3068549Sjkh}
3078549Sjkh
3088549Sjkh/* Get the mountpoint for a partition and save it away */
30912661Speterstatic PartInfo *
3108589Sjkhget_mountpoint(struct chunk *old)
3118549Sjkh{
3128549Sjkh    char *val;
3138549Sjkh    PartInfo *tmp;
3148549Sjkh
31514793Sjoerg    if (old && old->private_data)
31614793Sjoerg	tmp = old->private_data;
3178810Sjkh    else
3188810Sjkh	tmp = NULL;
31918619Sjkh    if (!old) {
32018621Sjkh	DialogX = 14;
32118621Sjkh	DialogY = 16;
32218619Sjkh    }
3238810Sjkh    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
32418619Sjkh    DialogX = DialogY = 0;
3258764Sjkh    if (!val || !*val) {
3268751Sjkh	if (!old)
3278751Sjkh	    return NULL;
3288751Sjkh	else {
32914793Sjoerg	    free(old->private_data);
33014793Sjoerg	    old->private_data = NULL;
3318751Sjkh	}
3328669Sphk	return NULL;
3338751Sjkh    }
3348669Sphk
3358669Sphk    /* Is it just the same value? */
3368810Sjkh    if (tmp && !strcmp(tmp->mountpoint, val))
3378669Sphk	return NULL;
3388810Sjkh
3398810Sjkh    /* Did we use it already? */
3408669Sphk    if (check_conflict(val)) {
3418669Sphk	msgConfirm("You already have a mount point for %s assigned!", val);
3428669Sphk	return NULL;
3438549Sjkh    }
3448810Sjkh
3458810Sjkh    /* Is it bogus? */
3468669Sphk    if (*val != '/') {
3478669Sphk	msgConfirm("Mount point must start with a / character");
3488669Sphk	return NULL;
3498669Sphk    }
3508810Sjkh
3518810Sjkh    /* Is it going to be mounted on root? */
3528669Sphk    if (!strcmp(val, "/")) {
3538669Sphk	if (old)
3548669Sphk	    old->flags |= CHUNK_IS_ROOT;
3558810Sjkh    }
3568810Sjkh    else if (old)
3578669Sphk	old->flags &= ~CHUNK_IS_ROOT;
3588810Sjkh
3598810Sjkh    safe_free(tmp);
3608669Sphk    tmp = new_part(val, TRUE, 0);
3618669Sphk    if (old) {
36214793Sjoerg	old->private_data = tmp;
3638669Sphk	old->private_free = safe_free;
3648669Sphk    }
3658669Sphk    return tmp;
3668549Sjkh}
3678549Sjkh
3688549Sjkh/* Get the type of the new partiton */
3698549Sjkhstatic PartType
3708549Sjkhget_partition_type(void)
3718549Sjkh{
3728549Sjkh    char selection[20];
3738669Sphk    int i;
3748669Sphk
3758549Sjkh    static unsigned char *fs_types[] = {
3768549Sjkh	"FS",
3778549Sjkh	"A file system",
3788549Sjkh	"Swap",
3798549Sjkh	"A swap partition.",
3808549Sjkh    };
38118619Sjkh    DialogX = 7;
38218621Sjkh    DialogY = 8;
3838669Sphk    i = dialog_menu("Please choose a partition type",
38412661Speter		    "If you want to use this partition for swap space, select Swap.\n"
38512661Speter		    "If you want to put a filesystem on it, choose FS.",
38612661Speter		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
38718619Sjkh    DialogX = DialogY = 0;
3888669Sphk    if (!i) {
3898549Sjkh	if (!strcmp(selection, "FS"))
3908549Sjkh	    return PART_FILESYSTEM;
3918549Sjkh	else if (!strcmp(selection, "Swap"))
3928549Sjkh	    return PART_SWAP;
3938549Sjkh    }
3948549Sjkh    return PART_NONE;
3958549Sjkh}
3968549Sjkh
3978549Sjkh/* If the user wants a special newfs command for this, set it */
3988549Sjkhstatic void
3998549SjkhgetNewfsCmd(PartInfo *p)
4008549Sjkh{
4018549Sjkh    char *val;
4028549Sjkh
4038549Sjkh    val = msgGetInput(p->newfs_cmd,
40412661Speter		      "Please enter the newfs command and options you'd like to use in\n"
40512661Speter		      "creating this file system.");
4068549Sjkh    if (val)
40720247Sjkh	sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
4088549Sjkh}
4098549Sjkh
4108549Sjkh#define MAX_MOUNT_NAME	12
4118549Sjkh
4128549Sjkh#define PART_PART_COL	0
4138549Sjkh#define PART_MOUNT_COL	8
4148549Sjkh#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
4158549Sjkh#define PART_NEWFS_COL	(PART_SIZE_COL + 7)
4168549Sjkh#define PART_OFF	38
4178549Sjkh
41829249Sjkh#define TOTAL_AVAIL_LINES       (10)
41929249Sjkh#define PSLICE_SHOWABLE          (4)
42029249Sjkh
42129249Sjkh
4228549Sjkh/* stick this all up on the screen */
4238549Sjkhstatic void
4248549Sjkhprint_label_chunks(void)
4258549Sjkh{
42629249Sjkh    int  i, j, srow, prow, pcol;
42729249Sjkh    int  sz;
42829249Sjkh    char clrmsg[80];
42929633Sjkh    int ChunkPartStartRow;
43029633Sjkh    WINDOW *ChunkWin;
4318549Sjkh
43229249Sjkh    /********************************************************/
43329249Sjkh    /*** These values are for controling screen resources ***/
43429249Sjkh    /*** Each label line holds up to 2 labels, so beware! ***/
43529249Sjkh    /*** strategy will be to try to always make sure the  ***/
43629249Sjkh    /*** highlighted label is in the active display area. ***/
43729249Sjkh    /********************************************************/
43829249Sjkh    int  pslice_max, label_max;
43929249Sjkh    int  pslice_count, label_count, label_focus_found, pslice_focus_found;
44029249Sjkh
4418549Sjkh    attrset(A_REVERSE);
4428549Sjkh    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
4438549Sjkh    attrset(A_NORMAL);
4448549Sjkh
44529633Sjkh    /*** Count the number of parition slices ***/
44629633Sjkh    pslice_count = 0;
44729633Sjkh    for (i = 0; label_chunk_info[i].c ; i++) {
44829633Sjkh        if (label_chunk_info[i].type == PART_SLICE)
44929633Sjkh            ++pslice_count;
45029633Sjkh    }
45129633Sjkh    pslice_max = pslice_count;
45229633Sjkh
45329633Sjkh    /*** 4 line max for partition slices ***/
45429633Sjkh    if (pslice_max > PSLICE_SHOWABLE) {
45529633Sjkh        pslice_max = PSLICE_SHOWABLE;
45629633Sjkh    }
45729633Sjkh    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
45829633Sjkh
45929633Sjkh    /*** View partition slices modulo pslice_max ***/
46029633Sjkh    label_max = TOTAL_AVAIL_LINES - pslice_max;
46129633Sjkh
4628549Sjkh    for (i = 0; i < 2; i++) {
46315440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
46415440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
4658549Sjkh
46615440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
46715440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
4688549Sjkh
46915440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
47015440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
4718549Sjkh
47215440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
47315440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
4748549Sjkh    }
4758549Sjkh    srow = CHUNK_SLICE_START_ROW;
47615440Sjkh    prow = 0;
4778549Sjkh    pcol = 0;
4788549Sjkh
47929249Sjkh    /*** these variables indicate that the focused item is shown currently ***/
48029249Sjkh    label_focus_found = 0;
48129249Sjkh    pslice_focus_found = 0;
48229249Sjkh
48329249Sjkh    label_count = 0;
48429249Sjkh    pslice_count = 0;
48529249Sjkh    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "          ");
48629249Sjkh    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "          ");
48729249Sjkh
48829633Sjkh    ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
48929633Sjkh
49029633Sjkh    wclear(ChunkWin);
49129633Sjkh    /*** wrefresh(ChunkWin); ***/
49229633Sjkh
4938751Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
4948549Sjkh	/* Is it a slice entry displayed at the top? */
4958549Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
49629249Sjkh            /*** This causes the new pslice to replace the previous display ***/
49729249Sjkh            /*** focus must remain on the most recently active pslice       ***/
49829249Sjkh            if (pslice_count == pslice_max) {
49929249Sjkh                if (pslice_focus_found) {
50029249Sjkh                    /*** This is where we can mark the more following ***/
50129249Sjkh                    attrset(A_BOLD);
50229249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
50329249Sjkh                    attrset(A_NORMAL);
50429249Sjkh                    continue;
50529249Sjkh                }
50629249Sjkh                else {
50729249Sjkh                    /*** this is where we set the more previous ***/
50829249Sjkh                    attrset(A_BOLD);
50929249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
51029249Sjkh                    attrset(A_NORMAL);
51129249Sjkh                    pslice_count = 0;
51229249Sjkh                    srow = CHUNK_SLICE_START_ROW;
51329249Sjkh                }
51429249Sjkh            }
51529249Sjkh
5168549Sjkh	    sz = space_free(label_chunk_info[i].c);
51715440Sjkh	    if (i == here)
51816208Sjkh		attrset(ATTR_SELECTED);
51929249Sjkh            if (i == pslice_focus)
52029249Sjkh                pslice_focus_found = -1;
52129249Sjkh
52229249Sjkh	    mvprintw(srow++, 0,
52329249Sjkh		     "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
52429249Sjkh		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name,
52529249Sjkh		     sz, (sz / ONE_MEG));
52615440Sjkh	    attrset(A_NORMAL);
52715440Sjkh	    clrtoeol();
52815440Sjkh	    move(0, 0);
52929633Sjkh	    /*** refresh(); ***/
53029249Sjkh            ++pslice_count;
5318549Sjkh	}
53215440Sjkh	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
5338549Sjkh	else {
5348549Sjkh	    char onestr[PART_OFF], num[10], *mountpoint, *newfs;
5358549Sjkh
5368549Sjkh	    /*
5378549Sjkh	     * We copy this into a blank-padded string so that it looks like
5388549Sjkh	     * a solid bar in reverse-video
5398549Sjkh	     */
5408549Sjkh	    memset(onestr, ' ', PART_OFF - 1);
5418549Sjkh	    onestr[PART_OFF - 1] = '\0';
54229249Sjkh
54329249Sjkh            /*** Track how many labels have been displayed ***/
54429249Sjkh            if (label_count == ((label_max - 1 ) * 2)) {
54529249Sjkh                if (label_focus_found) {
54629249Sjkh                    continue;
54729249Sjkh                }
54829249Sjkh                else {
54929249Sjkh                    label_count = 0;
55029249Sjkh                    prow = 0;
55129249Sjkh                    pcol = 0;
55229249Sjkh                }
55329249Sjkh            }
55429249Sjkh
55515440Sjkh	    /* Go for two columns if we've written one full columns worth */
55629249Sjkh	    /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
55729249Sjkh            if (label_count == label_max - 1) {
5588549Sjkh		pcol = PART_OFF;
55915440Sjkh		prow = 0;
5608549Sjkh	    }
5618705Sjkh	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
5628549Sjkh	    /* If it's a filesystem, display the mountpoint */
56314793Sjoerg	    if (label_chunk_info[i].c->private_data
56410882Speter		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
56514793Sjoerg	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
56623529Sjkh	    else if (label_chunk_info[i].type == PART_SWAP)
56723529Sjkh		mountpoint = "swap";
56810882Speter	    else
56910882Speter	        mountpoint = "<none>";
57010882Speter
57110882Speter	    /* Now display the newfs field */
57210882Speter	    if (label_chunk_info[i].type == PART_FAT)
57310882Speter	        newfs = "DOS";
57414793Sjoerg	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM)
57514793Sjoerg		newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N";
57610882Speter	    else if (label_chunk_info[i].type == PART_SWAP)
57710882Speter		newfs = "SWAP";
57810882Speter	    else
5798549Sjkh		newfs = "*";
5808549Sjkh	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
5818549Sjkh		onestr[PART_MOUNT_COL + j] = mountpoint[j];
5828764Sjkh	    snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
5838549Sjkh	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
5848549Sjkh	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
5858549Sjkh	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
58629633Sjkh            if (i == label_focus) {
58729633Sjkh                label_focus_found = -1;
58829633Sjkh                wattrset(ChunkWin, A_BOLD);
58929633Sjkh            }
59015440Sjkh	    if (i == here)
59116208Sjkh		wattrset(ChunkWin, ATTR_SELECTED);
59229249Sjkh
59329249Sjkh            /*** lazy man's way of padding this string ***/
59429249Sjkh            while (strlen( onestr ) < 37)
59529249Sjkh                strcat(onestr, " ");
59629249Sjkh
59715440Sjkh	    mvwaddstr(ChunkWin, prow, pcol, onestr);
59815440Sjkh	    wattrset(ChunkWin, A_NORMAL);
59915440Sjkh	    move(0, 0);
6008549Sjkh	    ++prow;
60129249Sjkh            ++label_count;
6028549Sjkh	}
6038549Sjkh    }
60429249Sjkh
60529249Sjkh    /*** this will erase all the extra stuff ***/
60629249Sjkh    memset(clrmsg, ' ', 37);
60729249Sjkh    clrmsg[37] = '\0';
60829249Sjkh
60929249Sjkh    while (pslice_count < pslice_max) {
61029249Sjkh        mvprintw(srow++, 0, clrmsg);
61129249Sjkh        clrtoeol();
61229249Sjkh        ++pslice_count;
61329249Sjkh    }
61429633Sjkh    while (label_count < (2 * (label_max - 1))) {
61529633Sjkh        mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
61629633Sjkh	++label_count;
61729633Sjkh	if (prow == (label_max - 1)) {
61829633Sjkh	    prow = 0;
61929633Sjkh	    pcol = PART_OFF;
62029633Sjkh	}
62129249Sjkh    }
62229633Sjkh    refresh();
62329633Sjkh    wrefresh(ChunkWin);
6248549Sjkh}
6258549Sjkh
6268549Sjkhstatic void
62718619Sjkhprint_command_summary(void)
6288549Sjkh{
6298820Sjkh    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
63021971Sjkh    mvprintw(18, 0, "C = Create      D = Delete         M = Mount pt.");
63115440Sjkh    if (!RunningAsInit)
63230956Sobrien	mvprintw(18, 49, "W = Write");
63330956Sobrien    mvprintw(19, 0, "N = Newfs Opts  T = Newfs Toggle   U = Undo      Q = Finish");
63410882Speter    mvprintw(20, 0, "A = Auto Defaults for all!");
63515695Sjkh    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
6368549Sjkh    move(0, 0);
6378549Sjkh}
6388549Sjkh
63918619Sjkhstatic void
64018619Sjkhclear_wins(void)
64118619Sjkh{
64229633Sjkh    extern void print_label_chunks();
64318619Sjkh    clear();
64429633Sjkh    print_label_chunks();
64518619Sjkh}
64618619Sjkh
64712661Speterstatic int
64830345SjkhdiskLabel(Device *dev)
6498549Sjkh{
65018619Sjkh    int sz, key = 0;
6518549Sjkh    Boolean labeling;
6528549Sjkh    char *msg = NULL;
6539202Srgrimes    PartInfo *p, *oldp;
6548549Sjkh    PartType type;
6558824Sjkh    Device **devs;
6568549Sjkh
65729628Sjkh    label_focus = 0;
65829628Sjkh    pslice_focus = 0;
65929633Sjkh    here = 0;
66030345Sjkh
66112661Speter    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
66212661Speter    if (!devs) {
66312661Speter	msgConfirm("No disks found!");
66415242Sjkh	return DITEM_FAILURE;
66512661Speter    }
6668549Sjkh    labeling = TRUE;
6678549Sjkh    keypad(stdscr, TRUE);
66830345Sjkh    record_label_chunks(devs, dev);
6698549Sjkh
67018619Sjkh    clear();
6718549Sjkh    while (labeling) {
67218744Sjkh	char *cp;
67318744Sjkh
6748549Sjkh	print_label_chunks();
67518619Sjkh	print_command_summary();
6768549Sjkh	if (msg) {
67715695Sjkh	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
67812661Speter	    clrtoeol();
6798549Sjkh	    beep();
6808549Sjkh	    msg = NULL;
6818549Sjkh	}
68215442Sjkh	else {
68315442Sjkh	    move(23, 0);
68415442Sjkh	    clrtoeol();
68515442Sjkh	}
68618744Sjkh
68718619Sjkh	refresh();
68817397Sjkh	key = getch();
68917397Sjkh	switch (toupper(key)) {
69015440Sjkh	    int i;
69117362Sjkh	    static char _msg[40];
6928549Sjkh
6938751Sjkh	case '\014':	/* ^L */
69418619Sjkh	    clear_wins();
69518619Sjkh	    break;
6968751Sjkh
69721698Sjkh	case '\020':	/* ^P */
6988549Sjkh	case KEY_UP:
6998549Sjkh	case '-':
7008549Sjkh	    if (here != 0)
7018549Sjkh		--here;
7028751Sjkh	    else
7038751Sjkh		while (label_chunk_info[here + 1].c)
7048751Sjkh		    ++here;
7058549Sjkh	    break;
7068549Sjkh
70721698Sjkh	case '\016':	/* ^N */
7088549Sjkh	case KEY_DOWN:
7098549Sjkh	case '+':
7108549Sjkh	case '\r':
7118549Sjkh	case '\n':
7128751Sjkh	    if (label_chunk_info[here + 1].c)
7138549Sjkh		++here;
7148751Sjkh	    else
7158751Sjkh		here = 0;
7168549Sjkh	    break;
7178549Sjkh
7188549Sjkh	case KEY_HOME:
7198549Sjkh	    here = 0;
7208549Sjkh	    break;
7218549Sjkh
7228549Sjkh	case KEY_END:
7238751Sjkh	    while (label_chunk_info[here + 1].c)
7248549Sjkh		++here;
7258549Sjkh	    break;
7268549Sjkh
7278549Sjkh	case KEY_F(1):
7288549Sjkh	case '?':
72912661Speter	    systemDisplayHelp("partition");
73018619Sjkh	    clear_wins();
7318549Sjkh	    break;
7328549Sjkh
73310882Speter	case 'A':
73410882Speter	    if (label_chunk_info[here].type != PART_SLICE) {
73515440Sjkh		msg = "You can only do this in a disk slice (at top of screen)";
73610882Speter		break;
73710882Speter	    }
73810882Speter	    sz = space_free(label_chunk_info[here].c);
73917362Sjkh	    if (sz <= FS_MIN_SIZE)
74015440Sjkh		msg = "Not enough free space to create a new partition in the slice";
74115440Sjkh	    else {
74215440Sjkh		struct chunk *tmp;
74315440Sjkh		int mib[2];
74415440Sjkh		int physmem;
74515440Sjkh		size_t size, swsize;
74615440Sjkh		char *cp;
74717362Sjkh		Chunk *rootdev, *swapdev, *usrdev, *vardev;
74812661Speter
74917368Sjkh		(void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev);
75017362Sjkh		if (!rootdev) {
75117362Sjkh		    cp = variable_get(VAR_ROOT_SIZE);
75217362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
75317362Sjkh					    (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS,  CHUNK_IS_ROOT);
75417362Sjkh		    if (!tmp) {
75517362Sjkh			msgConfirm("Unable to create the root partition. Too big?");
75618619Sjkh			clear_wins();
75717362Sjkh			break;
75817362Sjkh		    }
75917362Sjkh		    tmp->private_data = new_part("/", TRUE, tmp->size);
76017362Sjkh		    tmp->private_free = safe_free;
76130345Sjkh		    record_label_chunks(devs, dev);
76215440Sjkh		}
76317362Sjkh
76417362Sjkh		if (!swapdev) {
76517362Sjkh		    cp = variable_get(VAR_SWAP_SIZE);
76617362Sjkh		    if (cp)
76717362Sjkh			swsize = atoi(cp) * ONE_MEG;
76817362Sjkh		    else {
76917362Sjkh			mib[0] = CTL_HW;
77017362Sjkh			mib[1] = HW_PHYSMEM;
77117362Sjkh			size = sizeof physmem;
77217362Sjkh			sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
77317362Sjkh			swsize = 16 * ONE_MEG + (physmem * 2 / 512);
77417362Sjkh		    }
77517362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
77617362Sjkh					    swsize, part, FS_SWAP, 0);
77717362Sjkh		    if (!tmp) {
77817362Sjkh			msgConfirm("Unable to create the swap partition. Too big?");
77918619Sjkh			clear_wins();
78017362Sjkh			break;
78117362Sjkh		    }
78217362Sjkh		    tmp->private_data = 0;
78317362Sjkh		    tmp->private_free = safe_free;
78430345Sjkh		    record_label_chunks(devs, dev);
78515440Sjkh		}
78617362Sjkh
78717362Sjkh		if (!vardev) {
78817362Sjkh		    cp = variable_get(VAR_VAR_SIZE);
78917362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
79017362Sjkh					    (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0);
79117362Sjkh		    if (!tmp) {
79217362Sjkh			msgConfirm("Less than %dMB free for /var - you will need to\n"
79317362Sjkh				   "partition your disk manually with a custom install!",
79417362Sjkh				   (cp ? atoi(cp) : VAR_MIN_SIZE));
79518619Sjkh			clear_wins();
79617362Sjkh			break;
79717362Sjkh		    }
79817362Sjkh		    tmp->private_data = new_part("/var", TRUE, tmp->size);
79917362Sjkh		    tmp->private_free = safe_free;
80030345Sjkh		    record_label_chunks(devs, dev);
80115440Sjkh		}
80212661Speter
80317362Sjkh		if (!usrdev) {
80417362Sjkh		    cp = variable_get(VAR_USR_SIZE);
80517362Sjkh		    if (cp)
80617362Sjkh			sz = atoi(cp) * ONE_MEG;
80717362Sjkh		    else
80817362Sjkh			sz = space_free(label_chunk_info[here].c);
80929501Sjkh		    if (sz) {
81029501Sjkh			if (sz < (USR_MIN_SIZE * ONE_MEG)) {
81129501Sjkh			    msgConfirm("Less than %dMB free for /usr - you will need to\n"
81229501Sjkh				       "partition your disk manually with a custom install!", USR_MIN_SIZE);
81329501Sjkh			    clear_wins();
81429501Sjkh			    break;
81529501Sjkh			}
81617362Sjkh
81729501Sjkh			tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
81829501Sjkh						label_chunk_info[here].c,
81929501Sjkh						sz, part, FS_BSDFFS, 0);
82029501Sjkh			if (!tmp) {
82129501Sjkh			    msgConfirm("Unable to create the /usr partition.  Not enough space?\n"
82229501Sjkh				       "You will need to partition your disk manually with a custom install!");
82329501Sjkh			    clear_wins();
82429501Sjkh			    break;
82529501Sjkh			}
82629501Sjkh			tmp->private_data = new_part("/usr", TRUE, tmp->size);
82729501Sjkh			tmp->private_free = safe_free;
82830345Sjkh			record_label_chunks(devs, dev);
82917362Sjkh		    }
83015440Sjkh		}
83115440Sjkh		/* At this point, we're reasonably "labelled" */
83218744Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
83318744Sjkh		    variable_set2(DISK_LABELLED, "yes");
83410882Speter	    }
83515440Sjkh	    break;
83610882Speter
8378549Sjkh	case 'C':
8388549Sjkh	    if (label_chunk_info[here].type != PART_SLICE) {
8398549Sjkh		msg = "You can only do this in a master partition (see top of screen)";
8408549Sjkh		break;
8418549Sjkh	    }
8428549Sjkh	    sz = space_free(label_chunk_info[here].c);
8438669Sphk	    if (sz <= FS_MIN_SIZE) {
84412661Speter		msg = "Not enough space to create an additional FreeBSD partition";
8458669Sphk		break;
8468669Sphk	    }
84715440Sjkh	    else {
84818744Sjkh		char *val;
8498702Sjkh		int size;
8508702Sjkh		struct chunk *tmp;
8518820Sjkh		char osize[80];
8528702Sjkh		u_long flags = 0;
8538549Sjkh
8548820Sjkh		sprintf(osize, "%d", sz);
85518619Sjkh		DialogX = 3;
85618621Sjkh		DialogY = 2;
85718619Sjkh		val = msgGetInput(osize,
85818619Sjkh				  "Please specify the partition size in blocks or append a trailing M for\n"
85918619Sjkh				  "megabytes or C for cylinders.  %d blocks (%dMB) are free.",
86018619Sjkh				  sz, sz / ONE_MEG);
86118619Sjkh		DialogX = DialogY = 0;
86218619Sjkh		if (!val || (size = strtol(val, &cp, 0)) <= 0) {
86318619Sjkh		    clear_wins();
8648702Sjkh		    break;
86518619Sjkh		}
8668549Sjkh
8678751Sjkh		if (*cp) {
8688751Sjkh		    if (toupper(*cp) == 'M')
8698751Sjkh			size *= ONE_MEG;
8708751Sjkh		    else if (toupper(*cp) == 'C')
8718751Sjkh			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
8728751Sjkh		}
8738820Sjkh		if (size <= FS_MIN_SIZE) {
8748820Sjkh		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
87518619Sjkh		    clear_wins();
8768820Sjkh		    break;
8778820Sjkh		}
8788702Sjkh		type = get_partition_type();
87918619Sjkh		if (type == PART_NONE) {
88018619Sjkh		    clear_wins();
88118619Sjkh		    beep();
8828669Sphk		    break;
88318619Sjkh		}
8848669Sphk
8858702Sjkh		if (type == PART_FILESYSTEM) {
88618619Sjkh		    if ((p = get_mountpoint(NULL)) == NULL) {
88718619Sjkh			clear_wins();
88818619Sjkh			beep();
8898702Sjkh			break;
89018619Sjkh		    }
8918702Sjkh		    else if (!strcmp(p->mountpoint, "/"))
8928702Sjkh			flags |= CHUNK_IS_ROOT;
8938702Sjkh		    else
8948702Sjkh			flags &= ~CHUNK_IS_ROOT;
89518619Sjkh		}
89618619Sjkh		else
8978702Sjkh		    p = NULL;
8988702Sjkh
8998702Sjkh		if ((flags & CHUNK_IS_ROOT)) {
9008702Sjkh		    if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
90112661Speter			msgConfirm("This region cannot be used for your root partition as the\n"
90212661Speter				   "FreeBSD boot code cannot deal with a root partition created\n"
90312661Speter				   "in that location.  Please choose another location or smaller\n"
90412661Speter				   "size for your root partition and try again!");
90518619Sjkh			clear_wins();
9068702Sjkh			break;
9078702Sjkh		    }
90812661Speter		    if (size < (ROOT_MIN_SIZE * ONE_MEG)) {
90912661Speter			msgConfirm("Warning: This is smaller than the recommended size for a\n"
91012661Speter				   "root partition.  For a variety of reasons, root\n"
91112661Speter				   "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
91212661Speter		    }
9138672Sjkh		}
9148751Sjkh		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
9158702Sjkh					label_chunk_info[here].c,
9168702Sjkh					size, part,
9178702Sjkh					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
9188702Sjkh					flags);
9198702Sjkh		if (!tmp) {
9208702Sjkh		    msgConfirm("Unable to create the partition. Too big?");
92118619Sjkh		    clear_wins();
9228672Sjkh		    break;
9238672Sjkh		}
9248702Sjkh		if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
92512661Speter		    msgConfirm("This region cannot be used for your root partition as it starts\n"
92612661Speter			       "or extends past the 1024'th cylinder mark and is thus a\n"
92712661Speter			       "poor location to boot from.  Please choose another\n"
92812661Speter			       "location (or smaller size) for your root partition and try again!");
9298751Sjkh		    Delete_Chunk(label_chunk_info[here].c->disk, tmp);
93018619Sjkh		    clear_wins();
9318669Sphk		    break;
9328702Sjkh		}
9338702Sjkh		if (type != PART_SWAP) {
9348669Sphk		    /* This is needed to tell the newfs -u about the size */
93514793Sjoerg		    tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
9368669Sphk		    safe_free(p);
93715355Sjkh		}
93815355Sjkh		else
93914793Sjoerg		    tmp->private_data = p;
9408702Sjkh		tmp->private_free = safe_free;
94118744Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
94218744Sjkh		    variable_set2(DISK_LABELLED, "yes");
94330345Sjkh		record_label_chunks(devs, dev);
94418619Sjkh		clear_wins();
94529249Sjkh                /*** This is where we assign focus to new label so it shows ***/
94629249Sjkh                {
94729249Sjkh                    int i;
94829249Sjkh		    label_focus = -1;
94929249Sjkh                    for (i = 0; label_chunk_info[i].c; ++i) {
95029249Sjkh                    	if (label_chunk_info[i].c == tmp) {
95129249Sjkh			    label_focus = i;
95229249Sjkh			    break;
95329249Sjkh			}
95429249Sjkh		    }
95529249Sjkh		    if (label_focus == -1)
95629249Sjkh                    	label_focus = i - 1;
95729249Sjkh                }
9588549Sjkh	    }
9598549Sjkh	    break;
9608549Sjkh
96117397Sjkh	case KEY_DC:
9628549Sjkh	case 'D':	/* delete */
9638549Sjkh	    if (label_chunk_info[here].type == PART_SLICE) {
9648549Sjkh		msg = MSG_NOT_APPLICABLE;
9658549Sjkh		break;
9668549Sjkh	    }
9678549Sjkh	    else if (label_chunk_info[here].type == PART_FAT) {
9688705Sjkh		msg = "Use the Disk Partition Editor to delete DOS partitions";
9698549Sjkh		break;
9708549Sjkh	    }
9718751Sjkh	    Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c);
97218744Sjkh	    if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
97318744Sjkh		variable_set2(DISK_LABELLED, "yes");
97430345Sjkh	    record_label_chunks(devs, dev);
9758549Sjkh	    break;
9768549Sjkh
9778549Sjkh	case 'M':	/* mount */
9788549Sjkh	    switch(label_chunk_info[here].type) {
9798549Sjkh	    case PART_SLICE:
9808549Sjkh		msg = MSG_NOT_APPLICABLE;
9818549Sjkh		break;
9828549Sjkh
9838549Sjkh	    case PART_SWAP:
9848549Sjkh		msg = "You don't need to specify a mountpoint for a swap partition.";
9858549Sjkh		break;
9868549Sjkh
9878556Sjkh	    case PART_FAT:
9888549Sjkh	    case PART_FILESYSTEM:
98914793Sjoerg		oldp = label_chunk_info[here].c->private_data;
9908589Sjkh		p = get_mountpoint(label_chunk_info[here].c);
9918549Sjkh		if (p) {
9929202Srgrimes		    if (!oldp)
9939202Srgrimes		    	p->newfs = FALSE;
9948722Sjkh		    if (label_chunk_info[here].type == PART_FAT
9958722Sjkh			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
9968722Sjkh			    || !strcmp(p->mountpoint, "/var"))) {
9978722Sjkh			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
9988722Sjkh			strcpy(p->mountpoint, "/bogus");
9998722Sjkh		    }
10008549Sjkh		}
100118744Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
100218744Sjkh		    variable_set2(DISK_LABELLED, "yes");
100330345Sjkh		record_label_chunks(devs, dev);
100418636Sjkh		clear_wins();
10058549Sjkh		break;
10068549Sjkh
10078549Sjkh	    default:
10088549Sjkh		msgFatal("Bogus partition under cursor???");
10098549Sjkh		break;
10108549Sjkh	    }
10118549Sjkh	    break;
10128549Sjkh
10138549Sjkh	case 'N':	/* Set newfs options */
101414793Sjoerg	    if (label_chunk_info[here].c->private_data &&
101514793Sjoerg		((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
101614793Sjoerg		getNewfsCmd(label_chunk_info[here].c->private_data);
10178549Sjkh	    else
10188549Sjkh		msg = MSG_NOT_APPLICABLE;
101918636Sjkh	    clear_wins();
10208549Sjkh	    break;
10218549Sjkh
10228549Sjkh	case 'T':	/* Toggle newfs state */
10239202Srgrimes	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
102423729Sjkh		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
102523729Sjkh		label_chunk_info[here].c->private_data =
102623729Sjkh		    new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
102723729Sjkh		safe_free(pi);
102823729Sjkh		label_chunk_info[here].c->private_free = safe_free;
102923729Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
103023729Sjkh		    variable_set2(DISK_LABELLED, "yes");
103118619Sjkh	    }
10328549Sjkh	    else
10338549Sjkh		msg = MSG_NOT_APPLICABLE;
10348549Sjkh	    break;
10358549Sjkh
10368820Sjkh	case 'U':
103712661Speter	    clear();
103818744Sjkh	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
103918744Sjkh		msgConfirm("You've already written out your changes -\n"
104018744Sjkh			   "it's too late to undo!");
104118744Sjkh	    }
104218744Sjkh	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
104318744Sjkh		variable_unset(DISK_PARTITIONED);
104418744Sjkh		variable_unset(DISK_LABELLED);
104518744Sjkh		for (i = 0; devs[i]; i++) {
104618744Sjkh		    Disk *d;
104712661Speter
104818744Sjkh		    if (!devs[i]->enabled)
104918744Sjkh			continue;
105018744Sjkh		    else if ((d = Open_Disk(devs[i]->name)) != NULL) {
105118744Sjkh			Free_Disk(devs[i]->private);
105218744Sjkh			devs[i]->private = d;
105330345Sjkh			diskPartition(devs[i]);
105418744Sjkh		    }
10558824Sjkh		}
105630345Sjkh		record_label_chunks(devs, dev);
10578824Sjkh	    }
105818636Sjkh	    clear_wins();
10598824Sjkh	    break;
10608820Sjkh
10618549Sjkh	case 'W':
106218744Sjkh	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
106318744Sjkh		msgConfirm("You've already written out your changes - if you\n"
106418744Sjkh			   "wish to overwrite them, you'll have to start this\n"
106518744Sjkh			   "procedure again from the beginning.");
106618744Sjkh	    }
106718744Sjkh	    else if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
106818687Sjkh			  "installation.  If you are installing FreeBSD for the first time\n"
106918687Sjkh			  "then you should simply type Q when you're finished here and your\n"
107018687Sjkh			  "changes will be committed in one batch automatically at the end of\n"
107118687Sjkh			  "these questions.\n\n"
107218687Sjkh			  "Are you absolutely sure you want to do this now?")) {
107312661Speter		variable_set2(DISK_LABELLED, "yes");
107412661Speter		diskLabelCommit(NULL);
107512661Speter	    }
107618636Sjkh	    clear_wins();
107710882Speter	    break;
107810882Speter
107910882Speter	case '|':
108012661Speter	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n"
108112661Speter			  "This is an entirely undocumented feature which you are not\n"
108212661Speter			  "expected to understand!")) {
10838549Sjkh		int i;
10848549Sjkh		Device **devs;
10858549Sjkh
10868549Sjkh		dialog_clear();
10878549Sjkh		end_dialog();
10888549Sjkh		DialogActive = FALSE;
10898549Sjkh		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
10908549Sjkh		if (!devs) {
109112661Speter		    msgConfirm("Can't find any disk devices!");
10928549Sjkh		    break;
10938549Sjkh		}
10948668Sphk		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
10958613Sjkh		    if (devs[i]->enabled)
10968613Sjkh		    	slice_wizard(((Disk *)devs[i]->private));
10978613Sjkh		}
109818744Sjkh		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
109918744Sjkh		    variable_set2(DISK_LABELLED, "yes");
11008665Sphk		DialogActive = TRUE;
110130345Sjkh		record_label_chunks(devs, dev);
110218636Sjkh		clear_wins();
11038549Sjkh	    }
11048549Sjkh	    else
11058549Sjkh		msg = "A most prudent choice!";
11068549Sjkh	    break;
11078549Sjkh
110821698Sjkh	case '\033':	/* ESC */
11099202Srgrimes	case 'Q':
11108549Sjkh	    labeling = FALSE;
11118549Sjkh	    break;
11128549Sjkh
11138549Sjkh	default:
11148549Sjkh	    beep();
111517362Sjkh	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
111617362Sjkh	    msg = _msg;
11178549Sjkh	    break;
11188549Sjkh	}
111929633Sjkh        if (label_chunk_info[here].type == PART_SLICE)
112029633Sjkh            pslice_focus = here;
112129633Sjkh        else
112229633Sjkh            label_focus = here;
11238549Sjkh    }
112417362Sjkh    return DITEM_SUCCESS | DITEM_RESTORE;
11258549Sjkh}
112626456Sjkh
112726456Sjkhstatic int
112830345SjkhdiskLabelNonInteractive(Device *dev)
112926456Sjkh{
113026456Sjkh    char *cp;
113126456Sjkh    PartType type;
113226456Sjkh    PartInfo *p;
113326456Sjkh    u_long flags = 0;
113426456Sjkh    int i, status;
113526456Sjkh    Device **devs;
113626456Sjkh    Disk *d;
113726456Sjkh
113826456Sjkh    status = DITEM_SUCCESS;
113930345Sjkh
114026456Sjkh    cp = variable_get(VAR_DISK);
114126456Sjkh    if (!cp) {
114226456Sjkh	dialog_clear();
114326456Sjkh	msgConfirm("diskLabel:  No disk selected - can't label automatically.");
114426456Sjkh	return DITEM_FAILURE;
114526456Sjkh    }
114626456Sjkh    devs = deviceFind(cp, DEVICE_TYPE_DISK);
114726456Sjkh    if (!devs) {
114826456Sjkh	msgConfirm("diskLabel: No disk device %s found!", cp);
114926456Sjkh	return DITEM_FAILURE;
115026456Sjkh    }
115130345Sjkh    if (dev)
115230345Sjkh	d = dev->private;
115330345Sjkh    else
115430345Sjkh	d = devs[0]->private;
115530345Sjkh    record_label_chunks(devs, dev);
115626456Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
115726456Sjkh	Chunk *c1 = label_chunk_info[i].c;
115826456Sjkh
115926456Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
116028075Sjkh	    char name[512];
116128075Sjkh	    int entries = 1;
116226456Sjkh
116328075Sjkh	    while (entries) {
116428075Sjkh		snprintf(name, sizeof name, "%s-%d", c1->name, entries);
116528075Sjkh		if ((cp = variable_get(name)) != NULL) {
116628075Sjkh		    int sz;
116728075Sjkh		    char typ[10], mpoint[50];
116826456Sjkh
116928075Sjkh		    if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) {
117028075Sjkh			msgConfirm("For slice entry %s, got an invalid detail entry of: %s",  c1->name, cp);
117126456Sjkh			status = DITEM_FAILURE;
117226456Sjkh			continue;
117326456Sjkh		    }
117426456Sjkh		    else {
117528075Sjkh			Chunk *tmp;
117628075Sjkh
117728075Sjkh			if (!strcmp(typ, "swap")) {
117828075Sjkh			    type = PART_SWAP;
117928075Sjkh			    strcpy(mpoint, "SWAP");
118028075Sjkh			}
118128075Sjkh			else {
118228075Sjkh			    type = PART_FILESYSTEM;
118328075Sjkh			    if (!strcmp(mpoint, "/"))
118428075Sjkh				flags |= CHUNK_IS_ROOT;
118533132Sjkh			    else
118633132Sjkh				flags &= ~CHUNK_IS_ROOT;
118728075Sjkh			}
118828075Sjkh			if (!sz)
118928075Sjkh			    sz = space_free(c1);
119028075Sjkh			if (sz > space_free(c1)) {
119128075Sjkh			    msgConfirm("Not enough free space to create partition: %s", mpoint);
119228075Sjkh			    status = DITEM_FAILURE;
119328075Sjkh			    continue;
119428075Sjkh			}
119528075Sjkh			if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
119628075Sjkh						      (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
119728075Sjkh			    msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
119828075Sjkh			    status = DITEM_FAILURE;
119928075Sjkh			    break;
120028075Sjkh			}
120128075Sjkh			else {
120228075Sjkh			    tmp->private_data = new_part(mpoint, TRUE, sz);
120328075Sjkh			    tmp->private_free = safe_free;
120428075Sjkh			    status = DITEM_SUCCESS;
120528075Sjkh			}
120626456Sjkh		    }
120728075Sjkh		    entries++;
120826456Sjkh		}
120928075Sjkh		else {
121028075Sjkh		    /* No more matches, leave the loop */
121128075Sjkh		    entries = 0;
121228075Sjkh		}
121326456Sjkh	    }
121426456Sjkh	}
121526456Sjkh	else {
121628075Sjkh	    /* Must be something we can set a mountpoint for */
121726456Sjkh	    cp = variable_get(c1->name);
121826456Sjkh	    if (cp) {
121928075Sjkh		char mpoint[50], do_newfs[8];
122026456Sjkh		Boolean newfs = FALSE;
122126456Sjkh
122228075Sjkh		do_newfs[0] = '\0';
122328075Sjkh		if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
122426456Sjkh		    dialog_clear();
122526456Sjkh		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
122626456Sjkh		    status = DITEM_FAILURE;
122726456Sjkh		    continue;
122826456Sjkh		}
122928075Sjkh		newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
123026456Sjkh		if (c1->private_data) {
123126456Sjkh		    p = c1->private_data;
123226456Sjkh		    p->newfs = newfs;
123326456Sjkh		    strcpy(p->mountpoint, mpoint);
123426456Sjkh		}
123526456Sjkh		else {
123626456Sjkh		    c1->private_data = new_part(mpoint, newfs, 0);
123726456Sjkh		    c1->private_free = safe_free;
123826456Sjkh		}
123926456Sjkh		if (!strcmp(mpoint, "/"))
124026456Sjkh		    c1->flags |= CHUNK_IS_ROOT;
124126456Sjkh		else
124226456Sjkh		    c1->flags &= ~CHUNK_IS_ROOT;
124326456Sjkh	    }
124426456Sjkh	}
124526456Sjkh    }
124626456Sjkh    if (status == DITEM_SUCCESS)
124726456Sjkh	variable_set2(DISK_LABELLED, "yes");
124826456Sjkh    return status;
124926456Sjkh}
1250