label.c revision 107565
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 107565 2002-12-03 22:25:47Z rwatson $
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
4388996Sdillon#define AUTO_HOME	0	/* do not create /home automatically */
4488996Sdillon
458549Sjkh/*
468549Sjkh * Everything to do with editing the contents of disk labels.
478549Sjkh */
488549Sjkh
498549Sjkh/* A nice message we use a lot in the disklabel editor */
508549Sjkh#define MSG_NOT_APPLICABLE	"That option is not applicable here"
518549Sjkh
528549Sjkh/* Where to start printing the freebsd slices */
538549Sjkh#define CHUNK_SLICE_START_ROW		2
548622Sjkh#define CHUNK_PART_START_ROW		11
558549Sjkh
568549Sjkh/* The smallest filesystem we're willing to create */
578702Sjkh#define FS_MIN_SIZE			ONE_MEG
588549Sjkh
5987557Sdillon/*
6087557Sdillon * Minimum partition sizes
6187557Sdillon */
62104940Sobrien#if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__)
6345127Sjkh#define ROOT_MIN_SIZE			40
6444601Sjkh#else
6545127Sjkh#define ROOT_MIN_SIZE			30
6644601Sjkh#endif
6787557Sdillon#define SWAP_MIN_SIZE			32
6887557Sdillon#define USR_MIN_SIZE			80
6987557Sdillon#define VAR_MIN_SIZE			20
7087583Sdillon#define TMP_MIN_SIZE			20
7187557Sdillon#define HOME_MIN_SIZE			20
728549Sjkh
7387557Sdillon/*
7487557Sdillon * Swap size limit for auto-partitioning (4G).
7587557Sdillon */
7687557Sdillon#define SWAP_AUTO_LIMIT_SIZE		4096
7744601Sjkh
7887557Sdillon/*
7987557Sdillon * Default partition sizes.  If we do not have sufficient disk space
8087557Sdillon * for this configuration we scale things relative to the NOM vs DEFAULT
8187557Sdillon * sizes.  If the disk is larger then /home will get any remaining space.
8287557Sdillon */
8387557Sdillon#define ROOT_DEFAULT_SIZE		128
8487557Sdillon#define USR_DEFAULT_SIZE		3072
8587557Sdillon#define VAR_DEFAULT_SIZE		256
8687583Sdillon#define TMP_DEFAULT_SIZE		256
8787557Sdillon#define HOME_DEFAULT_SIZE		USR_DEFAULT_SIZE
8812661Speter
8987557Sdillon/*
9087557Sdillon * Nominal partition sizes.  These are used to scale the default sizes down
9187557Sdillon * when we have insufficient disk space.  If this isn't sufficient we scale
9287557Sdillon * down using the MIN sizes instead.
9387557Sdillon */
9487557Sdillon#define ROOT_NOMINAL_SIZE		128
9587557Sdillon#define USR_NOMINAL_SIZE		512
9687557Sdillon#define VAR_NOMINAL_SIZE		64
9787583Sdillon#define TMP_NOMINAL_SIZE		64
9887557Sdillon#define HOME_NOMINAL_SIZE		USR_NOMINAL_SIZE
9912661Speter
10015440Sjkh/* The bottom-most row we're allowed to scribble on */
10129249Sjkh#define CHUNK_ROW_MAX			16
10215440Sjkh
10315440Sjkh
1048549Sjkh/* All the chunks currently displayed on the screen */
1058549Sjkhstatic struct {
1068549Sjkh    struct chunk *c;
1078549Sjkh    PartType type;
1088549Sjkh} label_chunk_info[MAX_CHUNKS + 1];
1098549Sjkhstatic int here;
1108549Sjkh
11129249Sjkh/*** with this value we try to track the most recently added label ***/
11229249Sjkhstatic int label_focus = 0, pslice_focus = 0;
11329249Sjkh
11430345Sjkhstatic int diskLabel(Device *dev);
11530345Sjkhstatic int diskLabelNonInteractive(Device *dev);
11687557Sdillonstatic char *try_auto_label(Device **devs, Device *dev, int perc, int *req);
11712661Speter
11830345Sjkhstatic int
11930345SjkhlabelHook(dialogMenuItem *selected)
12030345Sjkh{
12130345Sjkh    Device **devs = NULL;
12230345Sjkh
12330345Sjkh    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
12430345Sjkh    if (!devs) {
12530345Sjkh	msgConfirm("Unable to find disk %s!", selected->prompt);
12630345Sjkh	return DITEM_FAILURE;
12730345Sjkh    }
12830345Sjkh    /* Toggle enabled status? */
12930345Sjkh    if (!devs[0]->enabled) {
13030345Sjkh	devs[0]->enabled = TRUE;
13130345Sjkh	diskLabel(devs[0]);
13230345Sjkh    }
13330345Sjkh    else
13430345Sjkh	devs[0]->enabled = FALSE;
13554587Sjkh    return DITEM_SUCCESS;
13630345Sjkh}
13730345Sjkh
13830345Sjkhstatic int
13930345SjkhlabelCheck(dialogMenuItem *selected)
14030345Sjkh{
14130345Sjkh    Device **devs = NULL;
14230345Sjkh
14330345Sjkh    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
14430345Sjkh    if (!devs || devs[0]->enabled == FALSE)
14530345Sjkh	return FALSE;
14630345Sjkh    return TRUE;
14730345Sjkh}
14830345Sjkh
14912661Speterint
15015091SjkhdiskLabelEditor(dialogMenuItem *self)
15112661Speter{
15230345Sjkh    DMenu *menu;
15312661Speter    Device **devs;
15430345Sjkh    int i, cnt;
15512661Speter
15630345Sjkh    i = 0;
15730345Sjkh    cnt = diskGetSelectCount(&devs);
15830345Sjkh    if (cnt == -1) {
15912661Speter	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
16012661Speter		   "properly probed at boot time.  See the Hardware Guide on the\n"
16112661Speter		   "Documentation menu for clues on diagnosing this type of problem.");
16215242Sjkh	return DITEM_FAILURE;
16312661Speter    }
16430345Sjkh    else if (cnt) {
16530345Sjkh	/* Some are already selected */
16697667Sjhb	if (variable_get(VAR_NONINTERACTIVE) &&
16797667Sjhb	  !variable_get(VAR_DISKINTERACTIVE))
16834543Sjkh	    i = diskLabelNonInteractive(NULL);
16930381Sjkh	else
17034543Sjkh	    i = diskLabel(NULL);
17112661Speter    }
17230345Sjkh    else {
17330345Sjkh	/* No disks are selected, fall-back case now */
17430345Sjkh	cnt = deviceCount(devs);
17530345Sjkh	if (cnt == 1) {
17630345Sjkh	    devs[0]->enabled = TRUE;
17797667Sjhb	    if (variable_get(VAR_NONINTERACTIVE) &&
17897667Sjhb	      !variable_get(VAR_DISKINTERACTIVE))
17930345Sjkh		i = diskLabelNonInteractive(devs[0]);
18030345Sjkh	    else
18130345Sjkh		i = diskLabel(devs[0]);
18230345Sjkh	}
18330345Sjkh	else {
18430345Sjkh	    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck);
18530345Sjkh	    if (!menu) {
18630345Sjkh		msgConfirm("No devices suitable for installation found!\n\n"
18730345Sjkh			   "Please verify that your disk controller (and attached drives)\n"
18830345Sjkh			   "were detected properly.  This can be done by pressing the\n"
18930345Sjkh			   "[Scroll Lock] key and using the Arrow keys to move back to\n"
19030345Sjkh			   "the boot messages.  Press [Scroll Lock] again to return.");
19130345Sjkh		i = DITEM_FAILURE;
19230345Sjkh	    }
19330345Sjkh	    else {
19430345Sjkh		i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
19530345Sjkh		free(menu);
19630345Sjkh	    }
19730345Sjkh	}
19812661Speter    }
19918744Sjkh    if (DITEM_STATUS(i) != DITEM_FAILURE) {
20074156Sjkh	if (variable_cmp(DISK_LABELLED, "written"))
20143685Sjkh	    variable_set2(DISK_LABELLED, "yes", 0);
20218744Sjkh    }
20312661Speter    return i;
20412661Speter}
20512661Speter
20612661Speterint
20715091SjkhdiskLabelCommit(dialogMenuItem *self)
20812661Speter{
20912661Speter    char *cp;
21012661Speter    int i;
21112661Speter
21212661Speter    /* Already done? */
21317025Sjkh    if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
21415242Sjkh	i = DITEM_SUCCESS;
21512661Speter    else if (!cp) {
21612661Speter	msgConfirm("You must assign disk labels before this option can be used.");
21715242Sjkh	i = DITEM_FAILURE;
21812661Speter    }
21912661Speter    /* The routine will guard against redundant writes, just as this one does */
22015419Sjkh    else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
22115242Sjkh	i = DITEM_FAILURE;
22215419Sjkh    else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
22315242Sjkh	i = DITEM_FAILURE;
22412661Speter    else {
22512661Speter	msgInfo("All filesystem information written successfully.");
22643685Sjkh	variable_set2(DISK_LABELLED, "written", 0);
22715242Sjkh	i = DITEM_SUCCESS;
22812661Speter    }
22912661Speter    return i;
23012661Speter}
23112661Speter
2328549Sjkh/* See if we're already using a desired partition name */
2338549Sjkhstatic Boolean
2348549Sjkhcheck_conflict(char *name)
2358549Sjkh{
2368549Sjkh    int i;
2378549Sjkh
2388751Sjkh    for (i = 0; label_chunk_info[i].c; i++)
23923729Sjkh	if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)
24023729Sjkh	    && label_chunk_info[i].c->private_data
24114793Sjoerg	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
2428549Sjkh	    return TRUE;
2438549Sjkh    return FALSE;
2448549Sjkh}
2458549Sjkh
2468549Sjkh/* How much space is in this FreeBSD slice? */
2478549Sjkhstatic int
2488549Sjkhspace_free(struct chunk *c)
2498549Sjkh{
25012661Speter    struct chunk *c1;
2518549Sjkh    int sz = c->size;
2528549Sjkh
25312661Speter    for (c1 = c->part; c1; c1 = c1->next) {
2548549Sjkh	if (c1->type != unused)
2558549Sjkh	    sz -= c1->size;
2568549Sjkh    }
2578549Sjkh    if (sz < 0)
2588549Sjkh	msgFatal("Partitions are larger than actual chunk??");
2598549Sjkh    return sz;
2608549Sjkh}
2618549Sjkh
2628549Sjkh/* Snapshot the current situation into the displayed chunks structure */
2638549Sjkhstatic void
26430345Sjkhrecord_label_chunks(Device **devs, Device *dev)
2658549Sjkh{
2668549Sjkh    int i, j, p;
2678549Sjkh    struct chunk *c1, *c2;
2688556Sjkh    Disk *d;
2698549Sjkh
2708549Sjkh    j = p = 0;
2718556Sjkh    /* First buzz through and pick up the FreeBSD slices */
2728549Sjkh    for (i = 0; devs[i]; i++) {
27330345Sjkh	if ((dev && devs[i] != dev) || !devs[i]->enabled)
2748556Sjkh	    continue;
2758556Sjkh	d = (Disk *)devs[i]->private;
2768556Sjkh	if (!d->chunks)
2778556Sjkh	    msgFatal("No chunk list found for %s!", d->name);
2788549Sjkh
2798556Sjkh	/* Put the slice entries first */
2808556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2818549Sjkh	    if (c1->type == freebsd) {
2828549Sjkh		label_chunk_info[j].type = PART_SLICE;
2838549Sjkh		label_chunk_info[j].c = c1;
2848549Sjkh		++j;
2858549Sjkh	    }
2868549Sjkh	}
2878549Sjkh    }
28812661Speter
2898556Sjkh    /* Now run through again and get the FreeBSD partition entries */
2908556Sjkh    for (i = 0; devs[i]; i++) {
2918556Sjkh	if (!devs[i]->enabled)
2928556Sjkh	    continue;
2938556Sjkh	d = (Disk *)devs[i]->private;
2948549Sjkh	/* Then buzz through and pick up the partitions */
2958556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2968549Sjkh	    if (c1->type == freebsd) {
2978549Sjkh		for (c2 = c1->part; c2; c2 = c2->next) {
2988549Sjkh		    if (c2->type == part) {
2998549Sjkh			if (c2->subtype == FS_SWAP)
3008549Sjkh			    label_chunk_info[j].type = PART_SWAP;
3018549Sjkh			else
3028549Sjkh			    label_chunk_info[j].type = PART_FILESYSTEM;
3038549Sjkh			label_chunk_info[j].c = c2;
3048549Sjkh			++j;
3058549Sjkh		    }
3068549Sjkh		}
3078549Sjkh	    }
308106839Smarcel	    else if (c1->type == fat || c1->type == efi) {
3098549Sjkh		label_chunk_info[j].type = PART_FAT;
3108549Sjkh		label_chunk_info[j].c = c1;
3118702Sjkh		++j;
3128549Sjkh	    }
3138549Sjkh	}
3148549Sjkh    }
3158549Sjkh    label_chunk_info[j].c = NULL;
31629249Sjkh    if (here >= j) {
3178549Sjkh	here = j  ? j - 1 : 0;
31829249Sjkh    }
3198549Sjkh}
3208549Sjkh
3218549Sjkh/* A new partition entry */
3228549Sjkhstatic PartInfo *
323106826Sjhbnew_part(char *mpoint, Boolean newfs)
3248549Sjkh{
325107565Srwatson    PartInfo *pi;
3268549Sjkh
3279202Srgrimes    if (!mpoint)
3289202Srgrimes	mpoint = "/change_me";
3299202Srgrimes
330107565Srwatson    pi = (PartInfo *)safe_malloc(sizeof(PartInfo));
331107565Srwatson    sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX);
332107565Srwatson
333107565Srwatson    pi->do_newfs = newfs;
334107565Srwatson
335107565Srwatson    pi->newfs_type = NEWFS_UFS;
336107565Srwatson    strcpy(pi->newfs_data.newfs_ufs.user_options, "");
337107565Srwatson    pi->newfs_data.newfs_ufs.acls = FALSE;
338107565Srwatson    pi->newfs_data.newfs_ufs.multilabel = FALSE;
339107565Srwatson    pi->newfs_data.newfs_ufs.softupdates = strcmp(mpoint, "/");
340107565Srwatson    pi->newfs_data.newfs_ufs.ufs2 = FALSE;
341107565Srwatson
342107565Srwatson    return pi;
3438549Sjkh}
3448549Sjkh
345106885Smarcel#if defined(__ia64__)
346106885Smarcelstatic PartInfo *
347106885Smarcelnew_efi_part(char *mpoint, Boolean newfs)
348106885Smarcel{
349107565Srwatson    PartInfo *pi;
350106885Smarcel
351106885Smarcel    if (!mpoint)
352106885Smarcel	mpoint = "/efi";
353106885Smarcel
354107565Srwatson    pi = (PartInfo *)safe_malloc(sizeof(PartInfo));
355107565Srwatson    sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX);
356107565Srwatson
357107565Srwatson    pi->do_newfs = newfs;
358107565Srwatson    pi->newfs_type = NEWFS_MSDOS;
359107565Srwatson
360107565Srwatson    return pi;
361106885Smarcel}
362106885Smarcel#endif
363106885Smarcel
3648549Sjkh/* Get the mountpoint for a partition and save it away */
36512661Speterstatic PartInfo *
3668589Sjkhget_mountpoint(struct chunk *old)
3678549Sjkh{
3688549Sjkh    char *val;
3698549Sjkh    PartInfo *tmp;
370106822Sjhb    Boolean newfs;
3718549Sjkh
37214793Sjoerg    if (old && old->private_data)
37314793Sjoerg	tmp = old->private_data;
3748810Sjkh    else
3758810Sjkh	tmp = NULL;
3768810Sjkh    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
3778764Sjkh    if (!val || !*val) {
3788751Sjkh	if (!old)
3798751Sjkh	    return NULL;
3808751Sjkh	else {
38114793Sjoerg	    free(old->private_data);
38214793Sjoerg	    old->private_data = NULL;
3838751Sjkh	}
3848669Sphk	return NULL;
3858751Sjkh    }
3868669Sphk
3878669Sphk    /* Is it just the same value? */
3888810Sjkh    if (tmp && !strcmp(tmp->mountpoint, val))
3898669Sphk	return NULL;
3908810Sjkh
3918810Sjkh    /* Did we use it already? */
3928669Sphk    if (check_conflict(val)) {
3938669Sphk	msgConfirm("You already have a mount point for %s assigned!", val);
3948669Sphk	return NULL;
3958549Sjkh    }
3968810Sjkh
3978810Sjkh    /* Is it bogus? */
3988669Sphk    if (*val != '/') {
3998669Sphk	msgConfirm("Mount point must start with a / character");
4008669Sphk	return NULL;
4018669Sphk    }
4028810Sjkh
4038810Sjkh    /* Is it going to be mounted on root? */
4048669Sphk    if (!strcmp(val, "/")) {
4058669Sphk	if (old)
4068669Sphk	    old->flags |= CHUNK_IS_ROOT;
4078810Sjkh    }
4088810Sjkh    else if (old)
4098669Sphk	old->flags &= ~CHUNK_IS_ROOT;
4108810Sjkh
411106823Sjhb    newfs = TRUE;
412106822Sjhb    if (tmp) {
413107565Srwatson	newfs = tmp->do_newfs;
414106822Sjhb    	safe_free(tmp);
415106822Sjhb    }
41646615Sjkh    val = string_skipwhite(string_prune(val));
417106826Sjhb    tmp = new_part(val, newfs);
4188669Sphk    if (old) {
41914793Sjoerg	old->private_data = tmp;
4208669Sphk	old->private_free = safe_free;
4218669Sphk    }
4228669Sphk    return tmp;
4238549Sjkh}
4248549Sjkh
4258549Sjkh/* Get the type of the new partiton */
4268549Sjkhstatic PartType
4278549Sjkhget_partition_type(void)
4288549Sjkh{
4298549Sjkh    char selection[20];
4308669Sphk    int i;
4318549Sjkh    static unsigned char *fs_types[] = {
4328549Sjkh	"FS",
4338549Sjkh	"A file system",
4348549Sjkh	"Swap",
4358549Sjkh	"A swap partition.",
4368549Sjkh    };
43754587Sjkh    WINDOW *w = savescr();
43854587Sjkh
4398669Sphk    i = dialog_menu("Please choose a partition type",
44012661Speter		    "If you want to use this partition for swap space, select Swap.\n"
44112661Speter		    "If you want to put a filesystem on it, choose FS.",
44212661Speter		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
44354587Sjkh    restorescr(w);
4448669Sphk    if (!i) {
4458549Sjkh	if (!strcmp(selection, "FS"))
4468549Sjkh	    return PART_FILESYSTEM;
4478549Sjkh	else if (!strcmp(selection, "Swap"))
4488549Sjkh	    return PART_SWAP;
4498549Sjkh    }
4508549Sjkh    return PART_NONE;
4518549Sjkh}
4528549Sjkh
4538549Sjkh/* If the user wants a special newfs command for this, set it */
4548549Sjkhstatic void
4558549SjkhgetNewfsCmd(PartInfo *p)
4568549Sjkh{
457107565Srwatson    char buffer[NEWFS_CMD_ARGS_MAX];
4588549Sjkh    char *val;
4598549Sjkh
460107565Srwatson    switch (p->newfs_type) {
461107565Srwatson    case NEWFS_UFS:
462107565Srwatson	snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s %s %s %s",
463107565Srwatson	    NEWFS_UFS_CMD, p->newfs_data.newfs_ufs.softupdates ?  "-U" : "",
464107565Srwatson	    p->newfs_data.newfs_ufs.ufs2 ? "-O2" : "-O1",
465107565Srwatson	    p->newfs_data.newfs_ufs.user_options);
466107565Srwatson	break;
467107565Srwatson    case NEWFS_MSDOS:
468107565Srwatson	snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s", NEWFS_MSDOS_CMD);
469107565Srwatson	break;
470107565Srwatson    case NEWFS_CUSTOM:
471107565Srwatson	strcpy(buffer, p->newfs_data.newfs_custom.command);
472107565Srwatson	break;
473107565Srwatson    }
474107565Srwatson
475107565Srwatson    val = msgGetInput(buffer,
476107565Srwatson	"Please enter the newfs command and options you'd like to use in\n"
477107565Srwatson	"creating this file system.");
478107565Srwatson    if (val != NULL) {
479107565Srwatson	p->newfs_type = NEWFS_CUSTOM;
480107565Srwatson	strlcpy(p->newfs_data.newfs_custom.command, val, NEWFS_CMD_ARGS_MAX);
481107565Srwatson    }
4828549Sjkh}
4838549Sjkh
484107565Srwatsonstatic void
485107565SrwatsongetNewfsOptionalArguments(PartInfo *p)
486107565Srwatson{
487107565Srwatson	char buffer[NEWFS_CMD_ARGS_MAX];
488107565Srwatson	char *val;
489107565Srwatson
490107565Srwatson	/* Must be UFS, per argument checking in I/O routines. */
491107565Srwatson
492107565Srwatson	strlcpy(buffer,  p->newfs_data.newfs_ufs.user_options,
493107565Srwatson	    NEWFS_CMD_ARGS_MAX);
494107565Srwatson	val = msgGetInput(buffer,
495107565Srwatson	    "Please enter any additional UFS newfs options you'd like to\n"
496107565Srwatson	    "use in creating this file system.");
497107565Srwatson	if (val != NULL)
498107565Srwatson		strlcpy(p->newfs_data.newfs_ufs.user_options, val,
499107565Srwatson		    NEWFS_CMD_ARGS_MAX);
500107565Srwatson}
501107565Srwatson
50276299Sjkh#define MAX_MOUNT_NAME	9
5038549Sjkh
5048549Sjkh#define PART_PART_COL	0
50554014Sjkh#define PART_MOUNT_COL	10
5068549Sjkh#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
50749202Sbrian#define PART_NEWFS_COL	(PART_SIZE_COL + 8)
50876299Sjkh#define PART_OFF	38
5098549Sjkh
51029249Sjkh#define TOTAL_AVAIL_LINES       (10)
51129249Sjkh#define PSLICE_SHOWABLE          (4)
51229249Sjkh
51329249Sjkh
5148549Sjkh/* stick this all up on the screen */
5158549Sjkhstatic void
5168549Sjkhprint_label_chunks(void)
5178549Sjkh{
518107565Srwatson    int  i, j, spaces, srow, prow, pcol;
51929249Sjkh    int  sz;
52029249Sjkh    char clrmsg[80];
52129633Sjkh    int ChunkPartStartRow;
52229633Sjkh    WINDOW *ChunkWin;
5238549Sjkh
52429249Sjkh    /********************************************************/
52529249Sjkh    /*** These values are for controling screen resources ***/
52629249Sjkh    /*** Each label line holds up to 2 labels, so beware! ***/
52729249Sjkh    /*** strategy will be to try to always make sure the  ***/
52829249Sjkh    /*** highlighted label is in the active display area. ***/
52929249Sjkh    /********************************************************/
53029249Sjkh    int  pslice_max, label_max;
53129249Sjkh    int  pslice_count, label_count, label_focus_found, pslice_focus_found;
53229249Sjkh
5338549Sjkh    attrset(A_REVERSE);
5348549Sjkh    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
5358549Sjkh    attrset(A_NORMAL);
5368549Sjkh
53729633Sjkh    /*** Count the number of parition slices ***/
53829633Sjkh    pslice_count = 0;
53929633Sjkh    for (i = 0; label_chunk_info[i].c ; i++) {
54029633Sjkh        if (label_chunk_info[i].type == PART_SLICE)
54129633Sjkh            ++pslice_count;
54229633Sjkh    }
54329633Sjkh    pslice_max = pslice_count;
54429633Sjkh
54529633Sjkh    /*** 4 line max for partition slices ***/
54629633Sjkh    if (pslice_max > PSLICE_SHOWABLE) {
54729633Sjkh        pslice_max = PSLICE_SHOWABLE;
54829633Sjkh    }
54929633Sjkh    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
55029633Sjkh
55129633Sjkh    /*** View partition slices modulo pslice_max ***/
55229633Sjkh    label_max = TOTAL_AVAIL_LINES - pslice_max;
55329633Sjkh
5548549Sjkh    for (i = 0; i < 2; i++) {
55515440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
55615440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
5578549Sjkh
55815440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
55915440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
5608549Sjkh
56149202Sbrian	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
56249202Sbrian	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
5638549Sjkh
56415440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
56515440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
5668549Sjkh    }
5678549Sjkh    srow = CHUNK_SLICE_START_ROW;
56815440Sjkh    prow = 0;
5698549Sjkh    pcol = 0;
5708549Sjkh
57129249Sjkh    /*** these variables indicate that the focused item is shown currently ***/
57229249Sjkh    label_focus_found = 0;
57329249Sjkh    pslice_focus_found = 0;
57429249Sjkh
57529249Sjkh    label_count = 0;
57629249Sjkh    pslice_count = 0;
57729249Sjkh    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "          ");
57829249Sjkh    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "          ");
57929249Sjkh
58029633Sjkh    ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
58129633Sjkh
58229633Sjkh    wclear(ChunkWin);
58329633Sjkh    /*** wrefresh(ChunkWin); ***/
58429633Sjkh
5858751Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
5868549Sjkh	/* Is it a slice entry displayed at the top? */
5878549Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
58829249Sjkh            /*** This causes the new pslice to replace the previous display ***/
58929249Sjkh            /*** focus must remain on the most recently active pslice       ***/
59029249Sjkh            if (pslice_count == pslice_max) {
59129249Sjkh                if (pslice_focus_found) {
59229249Sjkh                    /*** This is where we can mark the more following ***/
59329249Sjkh                    attrset(A_BOLD);
59429249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
59529249Sjkh                    attrset(A_NORMAL);
59629249Sjkh                    continue;
59729249Sjkh                }
59829249Sjkh                else {
59929249Sjkh                    /*** this is where we set the more previous ***/
60029249Sjkh                    attrset(A_BOLD);
60129249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
60229249Sjkh                    attrset(A_NORMAL);
60329249Sjkh                    pslice_count = 0;
60429249Sjkh                    srow = CHUNK_SLICE_START_ROW;
60529249Sjkh                }
60629249Sjkh            }
60729249Sjkh
6088549Sjkh	    sz = space_free(label_chunk_info[i].c);
60915440Sjkh	    if (i == here)
61016208Sjkh		attrset(ATTR_SELECTED);
61129249Sjkh            if (i == pslice_focus)
61229249Sjkh                pslice_focus_found = -1;
61329249Sjkh
61429249Sjkh	    mvprintw(srow++, 0,
61529249Sjkh		     "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
61629249Sjkh		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name,
61729249Sjkh		     sz, (sz / ONE_MEG));
61815440Sjkh	    attrset(A_NORMAL);
61915440Sjkh	    clrtoeol();
62015440Sjkh	    move(0, 0);
62129633Sjkh	    /*** refresh(); ***/
62229249Sjkh            ++pslice_count;
6238549Sjkh	}
62415440Sjkh	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
6258549Sjkh	else {
626107565Srwatson	    char onestr[PART_OFF], num[10], *mountpoint, newfs[12];
6278549Sjkh
6288549Sjkh	    /*
6298549Sjkh	     * We copy this into a blank-padded string so that it looks like
6308549Sjkh	     * a solid bar in reverse-video
6318549Sjkh	     */
6328549Sjkh	    memset(onestr, ' ', PART_OFF - 1);
6338549Sjkh	    onestr[PART_OFF - 1] = '\0';
63429249Sjkh
63529249Sjkh            /*** Track how many labels have been displayed ***/
63629249Sjkh            if (label_count == ((label_max - 1 ) * 2)) {
63729249Sjkh                if (label_focus_found) {
63829249Sjkh                    continue;
63929249Sjkh                }
64029249Sjkh                else {
64129249Sjkh                    label_count = 0;
64229249Sjkh                    prow = 0;
64329249Sjkh                    pcol = 0;
64429249Sjkh                }
64529249Sjkh            }
64629249Sjkh
64715440Sjkh	    /* Go for two columns if we've written one full columns worth */
64829249Sjkh	    /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
64929249Sjkh            if (label_count == label_max - 1) {
6508549Sjkh		pcol = PART_OFF;
65115440Sjkh		prow = 0;
6528549Sjkh	    }
6538705Sjkh	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
6548549Sjkh	    /* If it's a filesystem, display the mountpoint */
65514793Sjoerg	    if (label_chunk_info[i].c->private_data
65610882Speter		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
65714793Sjoerg	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
65823529Sjkh	    else if (label_chunk_info[i].type == PART_SWAP)
65923529Sjkh		mountpoint = "swap";
66010882Speter	    else
66110882Speter	        mountpoint = "<none>";
66210882Speter
66310882Speter	    /* Now display the newfs field */
664106885Smarcel	    if (label_chunk_info[i].type == PART_FAT) {
665106885Smarcel		strcpy(newfs, "DOS");
666106885Smarcel#if defined(__ia64__)
667106885Smarcel		if (label_chunk_info[i].c->private_data &&
668106885Smarcel		    label_chunk_info[i].c->type == efi) {
669106885Smarcel			strcat(newfs, "  ");
670106885Smarcel			PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data;
671107565Srwatson			strcat(newfs, pi->do_newfs ? " Y" : " N");
672106885Smarcel		}
673106885Smarcel#endif
674106885Smarcel	    }
67574086Sjkh	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) {
676107565Srwatson		PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data;
677107565Srwatson
678107565Srwatson		switch (pi->newfs_type) {
679107565Srwatson		case NEWFS_UFS:
680107565Srwatson			strcpy(newfs, NEWFS_UFS_STRING);
681107565Srwatson			if (pi->newfs_data.newfs_ufs.ufs2)
682107565Srwatson				strcat(newfs, "2");
683107565Srwatson			else
684107565Srwatson				strcat(newfs, "1");
685107565Srwatson			if (pi->newfs_data.newfs_ufs.softupdates)
686107565Srwatson				strcat(newfs, "+S");
687107565Srwatson			else
688107565Srwatson				strcat(newfs, "  ");
689107565Srwatson
690107565Srwatson			break;
691107565Srwatson		case NEWFS_MSDOS:
692107565Srwatson			strcpy(newfs, "FAT");
693107565Srwatson			break;
694107565Srwatson		case NEWFS_CUSTOM:
695107565Srwatson			strcpy(newfs, "CUST");
696107565Srwatson			break;
697107565Srwatson		}
698107565Srwatson		strcat(newfs, pi->do_newfs ? " Y" : " N ");
69974086Sjkh	    }
70010882Speter	    else if (label_chunk_info[i].type == PART_SWAP)
70174086Sjkh		strcpy(newfs, "SWAP");
70210882Speter	    else
70374086Sjkh		strcpy(newfs, "*");
7048549Sjkh	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
7058549Sjkh		onestr[PART_MOUNT_COL + j] = mountpoint[j];
70649202Sbrian	    snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
7078549Sjkh	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
7088549Sjkh	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
7098549Sjkh	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
71029633Sjkh            if (i == label_focus) {
71129633Sjkh                label_focus_found = -1;
71229633Sjkh                wattrset(ChunkWin, A_BOLD);
71329633Sjkh            }
71415440Sjkh	    if (i == here)
71516208Sjkh		wattrset(ChunkWin, ATTR_SELECTED);
71629249Sjkh
71774086Sjkh            /*** lazy man's way of expensively padding this string ***/
71874086Sjkh            while (strlen(onestr) < 37)
71929249Sjkh                strcat(onestr, " ");
72029249Sjkh
72115440Sjkh	    mvwaddstr(ChunkWin, prow, pcol, onestr);
72215440Sjkh	    wattrset(ChunkWin, A_NORMAL);
72315440Sjkh	    move(0, 0);
7248549Sjkh	    ++prow;
72529249Sjkh            ++label_count;
7268549Sjkh	}
7278549Sjkh    }
72829249Sjkh
72929249Sjkh    /*** this will erase all the extra stuff ***/
73029249Sjkh    memset(clrmsg, ' ', 37);
73129249Sjkh    clrmsg[37] = '\0';
73229249Sjkh
73329249Sjkh    while (pslice_count < pslice_max) {
73429249Sjkh        mvprintw(srow++, 0, clrmsg);
73529249Sjkh        clrtoeol();
73629249Sjkh        ++pslice_count;
73729249Sjkh    }
73829633Sjkh    while (label_count < (2 * (label_max - 1))) {
73929633Sjkh        mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
74029633Sjkh	++label_count;
74129633Sjkh	if (prow == (label_max - 1)) {
74229633Sjkh	    prow = 0;
74329633Sjkh	    pcol = PART_OFF;
74429633Sjkh	}
74529249Sjkh    }
74629633Sjkh    refresh();
74729633Sjkh    wrefresh(ChunkWin);
7488549Sjkh}
7498549Sjkh
7508549Sjkhstatic void
75118619Sjkhprint_command_summary(void)
7528549Sjkh{
7538820Sjkh    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
75474086Sjkh    mvprintw(18, 0, "C = Create        D = Delete   M = Mount pt.");
75515440Sjkh    if (!RunningAsInit)
756107565Srwatson	mvprintw(18, 56, "W = Write");
757107565Srwatson    mvprintw(19, 0, "N = Newfs Opts    Q = Finish   S = Toggle SoftUpdates   Z = Custom Newfs");
758107565Srwatson    mvprintw(20, 0, "T = Toggle Newfs  U = Undo     A = Auto Defaults        R = Delete+Merge");
75915695Sjkh    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
7608549Sjkh    move(0, 0);
7618549Sjkh}
7628549Sjkh
76318619Sjkhstatic void
76418619Sjkhclear_wins(void)
76518619Sjkh{
76629633Sjkh    extern void print_label_chunks();
76718619Sjkh    clear();
76829633Sjkh    print_label_chunks();
76918619Sjkh}
77018619Sjkh
77112661Speterstatic int
77230345SjkhdiskLabel(Device *dev)
7738549Sjkh{
77418619Sjkh    int sz, key = 0;
7758549Sjkh    Boolean labeling;
7768549Sjkh    char *msg = NULL;
7779202Srgrimes    PartInfo *p, *oldp;
7788549Sjkh    PartType type;
7798824Sjkh    Device **devs;
78054587Sjkh    WINDOW *w = savescr();
7818549Sjkh
78229628Sjkh    label_focus = 0;
78329628Sjkh    pslice_focus = 0;
78429633Sjkh    here = 0;
78530345Sjkh
78612661Speter    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
78712661Speter    if (!devs) {
78812661Speter	msgConfirm("No disks found!");
78954587Sjkh	restorescr(w);
79015242Sjkh	return DITEM_FAILURE;
79112661Speter    }
7928549Sjkh    labeling = TRUE;
7938549Sjkh    keypad(stdscr, TRUE);
79430345Sjkh    record_label_chunks(devs, dev);
7958549Sjkh
79618619Sjkh    clear();
7978549Sjkh    while (labeling) {
79818744Sjkh	char *cp;
79988996Sdillon	int rflags = DELCHUNK_NORMAL;
80018744Sjkh
8018549Sjkh	print_label_chunks();
80218619Sjkh	print_command_summary();
8038549Sjkh	if (msg) {
80415695Sjkh	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
80512661Speter	    clrtoeol();
8068549Sjkh	    beep();
8078549Sjkh	    msg = NULL;
8088549Sjkh	}
80915442Sjkh	else {
81015442Sjkh	    move(23, 0);
81115442Sjkh	    clrtoeol();
81215442Sjkh	}
81318744Sjkh
81418619Sjkh	refresh();
81517397Sjkh	key = getch();
81617397Sjkh	switch (toupper(key)) {
81715440Sjkh	    int i;
81817362Sjkh	    static char _msg[40];
8198549Sjkh
8208751Sjkh	case '\014':	/* ^L */
82118619Sjkh	    clear_wins();
82218619Sjkh	    break;
8238751Sjkh
82421698Sjkh	case '\020':	/* ^P */
8258549Sjkh	case KEY_UP:
8268549Sjkh	case '-':
8278549Sjkh	    if (here != 0)
8288549Sjkh		--here;
8298751Sjkh	    else
8308751Sjkh		while (label_chunk_info[here + 1].c)
8318751Sjkh		    ++here;
8328549Sjkh	    break;
8338549Sjkh
83421698Sjkh	case '\016':	/* ^N */
8358549Sjkh	case KEY_DOWN:
8368549Sjkh	case '+':
8378549Sjkh	case '\r':
8388549Sjkh	case '\n':
8398751Sjkh	    if (label_chunk_info[here + 1].c)
8408549Sjkh		++here;
8418751Sjkh	    else
8428751Sjkh		here = 0;
8438549Sjkh	    break;
8448549Sjkh
8458549Sjkh	case KEY_HOME:
8468549Sjkh	    here = 0;
8478549Sjkh	    break;
8488549Sjkh
8498549Sjkh	case KEY_END:
8508751Sjkh	    while (label_chunk_info[here + 1].c)
8518549Sjkh		++here;
8528549Sjkh	    break;
8538549Sjkh
8548549Sjkh	case KEY_F(1):
8558549Sjkh	case '?':
85612661Speter	    systemDisplayHelp("partition");
85718619Sjkh	    clear_wins();
8588549Sjkh	    break;
8598549Sjkh
860107565Srwatson	case '2':
861107565Srwatson	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
862107565Srwatson		PartInfo *pi =
863107565Srwatson		    ((PartInfo *)label_chunk_info[here].c->private_data);
864107565Srwatson
865107565Srwatson		if ((pi != NULL) &&
866107565Srwatson		    (pi->newfs_type == NEWFS_UFS)) {
867107565Srwatson#ifdef __i386__
868107565Srwatson			if (label_chunk_info[here].c->flags & CHUNK_IS_ROOT)
869107565Srwatson				msg = MSG_NOT_APPLICABLE;
870107565Srwatson			else
871107565Srwatson#endif
872107565Srwatson				pi->newfs_data.newfs_ufs.ufs2 =
873107565Srwatson				    !pi->newfs_data.newfs_ufs.ufs2;
874107565Srwatson		} else
875107565Srwatson		    msg = MSG_NOT_APPLICABLE;
876107565Srwatson	    } else
877107565Srwatson		msg = MSG_NOT_APPLICABLE;
878107565Srwatson	    break;
879107565Srwatson		break;
880107565Srwatson
88110882Speter	case 'A':
88210882Speter	    if (label_chunk_info[here].type != PART_SLICE) {
88315440Sjkh		msg = "You can only do this in a disk slice (at top of screen)";
88410882Speter		break;
88510882Speter	    }
88687557Sdillon	    /*
88787557Sdillon	     * Generate standard partitions automatically.  If we do not
88887557Sdillon	     * have sufficient space we attempt to scale-down the size
88987557Sdillon	     * of the partitions within certain bounds.
89087557Sdillon	     */
89187557Sdillon	    {
89287557Sdillon		int perc;
89387557Sdillon		int req = 0;
89412661Speter
89587557Sdillon		for (perc = 100; perc > 0; perc -= 5) {
89687557Sdillon		    req = 0;	/* reset for each loop */
89787557Sdillon		    if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL)
89817362Sjkh			break;
89915440Sjkh		}
90087557Sdillon		if (msg) {
90187557Sdillon		    if (req) {
90287557Sdillon			msgConfirm(msg);
90318619Sjkh			clear_wins();
90487557Sdillon			msg = NULL;
90517362Sjkh		    }
90615440Sjkh		}
90710882Speter	    }
90815440Sjkh	    break;
90910882Speter
9108549Sjkh	case 'C':
9118549Sjkh	    if (label_chunk_info[here].type != PART_SLICE) {
9128549Sjkh		msg = "You can only do this in a master partition (see top of screen)";
9138549Sjkh		break;
9148549Sjkh	    }
9158549Sjkh	    sz = space_free(label_chunk_info[here].c);
9168669Sphk	    if (sz <= FS_MIN_SIZE) {
91712661Speter		msg = "Not enough space to create an additional FreeBSD partition";
9188669Sphk		break;
9198669Sphk	    }
92015440Sjkh	    else {
92118744Sjkh		char *val;
9228702Sjkh		int size;
9238702Sjkh		struct chunk *tmp;
9248820Sjkh		char osize[80];
9258702Sjkh		u_long flags = 0;
9268549Sjkh
9278820Sjkh		sprintf(osize, "%d", sz);
92818619Sjkh		val = msgGetInput(osize,
92957617Sjkh				  "Please specify the partition size in blocks or append a trailing G for\n"
93057617Sjkh				  "gigabytes, M for megabytes, or C for cylinders.\n"
93157617Sjkh				  "%d blocks (%dMB) are free.",
93218619Sjkh				  sz, sz / ONE_MEG);
93318619Sjkh		if (!val || (size = strtol(val, &cp, 0)) <= 0) {
93418619Sjkh		    clear_wins();
9358702Sjkh		    break;
93618619Sjkh		}
9378549Sjkh
9388751Sjkh		if (*cp) {
9398751Sjkh		    if (toupper(*cp) == 'M')
9408751Sjkh			size *= ONE_MEG;
94157617Sjkh		    else if (toupper(*cp) == 'G')
94257617Sjkh			size *= ONE_GIG;
9438751Sjkh		    else if (toupper(*cp) == 'C')
9448751Sjkh			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
9458751Sjkh		}
9468820Sjkh		if (size <= FS_MIN_SIZE) {
9478820Sjkh		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
94818619Sjkh		    clear_wins();
9498820Sjkh		    break;
9508820Sjkh		}
9518702Sjkh		type = get_partition_type();
95218619Sjkh		if (type == PART_NONE) {
95318619Sjkh		    clear_wins();
95418619Sjkh		    beep();
9558669Sphk		    break;
95618619Sjkh		}
9578669Sphk
9588702Sjkh		if (type == PART_FILESYSTEM) {
95918619Sjkh		    if ((p = get_mountpoint(NULL)) == NULL) {
96018619Sjkh			clear_wins();
96118619Sjkh			beep();
9628702Sjkh			break;
96318619Sjkh		    }
9648702Sjkh		    else if (!strcmp(p->mountpoint, "/"))
9658702Sjkh			flags |= CHUNK_IS_ROOT;
9668702Sjkh		    else
9678702Sjkh			flags &= ~CHUNK_IS_ROOT;
96818619Sjkh		}
96918619Sjkh		else
9708702Sjkh		    p = NULL;
9718702Sjkh
97276237Sjkh		if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) {
97376237Sjkh		    msgConfirm("Warning: This is smaller than the recommended size for a\n"
97476237Sjkh			       "root partition.  For a variety of reasons, root\n"
97576237Sjkh			       "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
9768672Sjkh		}
9778751Sjkh		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
9788702Sjkh					label_chunk_info[here].c,
9798702Sjkh					size, part,
9808702Sjkh					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
9818702Sjkh					flags);
9828702Sjkh		if (!tmp) {
9838702Sjkh		    msgConfirm("Unable to create the partition. Too big?");
98418619Sjkh		    clear_wins();
9858672Sjkh		    break;
9868672Sjkh		}
98779678Sobrien
98879678Sobrien#ifdef __alpha__
98979678Sobrien		/*
99079680Sobrien		 * SRM requires that the root partition is at the
99179678Sobrien		 * begining of the disk and cannot boot otherwise.
99279678Sobrien		 * Warn Alpha users if they are about to shoot themselves in
99379678Sobrien		 * the foot in this way.
99479678Sobrien		 *
99579678Sobrien		 * Since partitions may not start precisely at offset 0 we
99679678Sobrien		 * check for a "close to 0" instead. :-(
99779678Sobrien		 */
99879678Sobrien		if ((flags & CHUNK_IS_ROOT) && (tmp->offset > 1024)) {
99979680Sobrien		    msgConfirm("Your root partition `a' does not seem to be the first\n"
100079680Sobrien			       "partition.  The Alpha's firmware can only boot from the\n"
100179680Sobrien			       "first partition.  So it is unlikely that your current\n"
100279680Sobrien			       "disk layout will be bootable boot after installation.\n"
100379678Sobrien			       "\n"
100479678Sobrien			       "Please allocate the root partition before allocating\n"
100579678Sobrien			       "any others.\n");
100679678Sobrien		}
100779678Sobrien#endif	/* alpha */
100879678Sobrien
1009106826Sjhb		tmp->private_data = p;
10108702Sjkh		tmp->private_free = safe_free;
101174156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
101243685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
101330345Sjkh		record_label_chunks(devs, dev);
101418619Sjkh		clear_wins();
101579678Sobrien                /* This is where we assign focus to new label so it shows. */
101629249Sjkh                {
101729249Sjkh                    int i;
101829249Sjkh		    label_focus = -1;
101929249Sjkh                    for (i = 0; label_chunk_info[i].c; ++i) {
102029249Sjkh                    	if (label_chunk_info[i].c == tmp) {
102129249Sjkh			    label_focus = i;
102229249Sjkh			    break;
102329249Sjkh			}
102429249Sjkh		    }
102529249Sjkh		    if (label_focus == -1)
102629249Sjkh                    	label_focus = i - 1;
102729249Sjkh                }
10288549Sjkh	    }
10298549Sjkh	    break;
10308549Sjkh
103117397Sjkh	case KEY_DC:
103288996Sdillon	case 'R':	/* recover space (delete w/ recover) */
103388996Sdillon	    /*
103488996Sdillon	     * Delete the partition w/ space recovery.
103588996Sdillon	     */
103688996Sdillon	    rflags = DELCHUNK_RECOVER;
103788996Sdillon	    /* fall through */
10388549Sjkh	case 'D':	/* delete */
10398549Sjkh	    if (label_chunk_info[here].type == PART_SLICE) {
10408549Sjkh		msg = MSG_NOT_APPLICABLE;
10418549Sjkh		break;
10428549Sjkh	    }
10438549Sjkh	    else if (label_chunk_info[here].type == PART_FAT) {
10448705Sjkh		msg = "Use the Disk Partition Editor to delete DOS partitions";
10458549Sjkh		break;
10468549Sjkh	    }
104788996Sdillon	    Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags);
104874156Sjkh	    if (variable_cmp(DISK_LABELLED, "written"))
104943685Sjkh		variable_set2(DISK_LABELLED, "yes", 0);
105030345Sjkh	    record_label_chunks(devs, dev);
10518549Sjkh	    break;
10528549Sjkh
10538549Sjkh	case 'M':	/* mount */
10548549Sjkh	    switch(label_chunk_info[here].type) {
10558549Sjkh	    case PART_SLICE:
10568549Sjkh		msg = MSG_NOT_APPLICABLE;
10578549Sjkh		break;
10588549Sjkh
10598549Sjkh	    case PART_SWAP:
10608549Sjkh		msg = "You don't need to specify a mountpoint for a swap partition.";
10618549Sjkh		break;
10628549Sjkh
10638556Sjkh	    case PART_FAT:
10648549Sjkh	    case PART_FILESYSTEM:
106514793Sjoerg		oldp = label_chunk_info[here].c->private_data;
10668589Sjkh		p = get_mountpoint(label_chunk_info[here].c);
10678549Sjkh		if (p) {
10689202Srgrimes		    if (!oldp)
1069107565Srwatson		    	p->do_newfs = FALSE;
10708722Sjkh		    if (label_chunk_info[here].type == PART_FAT
10718722Sjkh			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
10728722Sjkh			    || !strcmp(p->mountpoint, "/var"))) {
10738722Sjkh			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
10748722Sjkh			strcpy(p->mountpoint, "/bogus");
10758722Sjkh		    }
10768549Sjkh		}
107774156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
107843685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
107930345Sjkh		record_label_chunks(devs, dev);
108018636Sjkh		clear_wins();
10818549Sjkh		break;
10828549Sjkh
10838549Sjkh	    default:
10848549Sjkh		msgFatal("Bogus partition under cursor???");
10858549Sjkh		break;
10868549Sjkh	    }
10878549Sjkh	    break;
10888549Sjkh
10898549Sjkh	case 'N':	/* Set newfs options */
109014793Sjoerg	    if (label_chunk_info[here].c->private_data &&
1091107565Srwatson		((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs)
1092107565Srwatson		getNewfsOptionalArguments(
1093107565Srwatson		    label_chunk_info[here].c->private_data);
10948549Sjkh	    else
10958549Sjkh		msg = MSG_NOT_APPLICABLE;
109618636Sjkh	    clear_wins();
10978549Sjkh	    break;
10988549Sjkh
109974086Sjkh	case 'S':	/* Toggle soft updates flag */
110074086Sjkh	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
110174086Sjkh		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1102107565Srwatson		if (pi != NULL &&
1103107565Srwatson		    pi->newfs_type == NEWFS_UFS)
1104107565Srwatson			pi->newfs_data.newfs_ufs.softupdates =
1105107565Srwatson			    !pi->newfs_data.newfs_ufs.softupdates;
110674086Sjkh		else
110774086Sjkh		    msg = MSG_NOT_APPLICABLE;
110874086Sjkh	    }
110974156Sjkh	    else
111074156Sjkh		msg = MSG_NOT_APPLICABLE;
111174086Sjkh	    break;
111274086Sjkh
11138549Sjkh	case 'T':	/* Toggle newfs state */
111489968Smurray	    if ((label_chunk_info[here].type == PART_FILESYSTEM) &&
111589968Smurray	        (label_chunk_info[here].c->private_data)) {
111623729Sjkh		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1117107565Srwatson		if (!pi->do_newfs)
111887581Sdillon		    label_chunk_info[here].c->flags |= CHUNK_NEWFS;
111987581Sdillon		else
112087581Sdillon		    label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
112187581Sdillon
112223729Sjkh		label_chunk_info[here].c->private_data =
1123107565Srwatson		    new_part(pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs
1124107565Srwatson		    : TRUE);
1125107565Srwatson		if (pi != NULL &&
1126107565Srwatson		    pi->newfs_type == NEWFS_UFS) {
1127107565Srwatson		    PartInfo *pi_new = label_chunk_info[here].c->private_data;
1128107565Srwatson
1129107565Srwatson		    pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs;
1130107565Srwatson		}
113123729Sjkh		safe_free(pi);
113223729Sjkh		label_chunk_info[here].c->private_free = safe_free;
113374156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
113443685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
113518619Sjkh	    }
1136106885Smarcel#if defined(__ia64__)
1137106885Smarcel	    else if (label_chunk_info[here].type == PART_FAT &&
1138106885Smarcel	      label_chunk_info[here].c->type == efi &&
1139106885Smarcel	      label_chunk_info[here].c->private_data) {
1140107565Srwatson		PartInfo *pi =
1141107565Srwatson		    ((PartInfo *)label_chunk_info[here].c->private_data);
1142107565Srwatson
1143107565Srwatson		if (!pi->do_newfs)
1144106885Smarcel		    label_chunk_info[here].c->flags |= CHUNK_NEWFS;
1145106885Smarcel		else
1146106885Smarcel		    label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
1147106885Smarcel
1148106885Smarcel		label_chunk_info[here].c->private_data =
1149107565Srwatson		    new_efi_part(pi->mountpoint, !pi->do_newfs);
1150106885Smarcel		safe_free(pi);
1151106885Smarcel		label_chunk_info[here].c->private_free = safe_free;
1152106885Smarcel		if (variable_cmp(DISK_LABELLED, "written"))
1153106885Smarcel		    variable_set2(DISK_LABELLED, "yes", 0);
1154106885Smarcel	    }
1155106885Smarcel#endif
11568549Sjkh	    else
11578549Sjkh		msg = MSG_NOT_APPLICABLE;
11588549Sjkh	    break;
11598549Sjkh
11608820Sjkh	case 'U':
116112661Speter	    clear();
116274156Sjkh	    if (!variable_cmp(DISK_LABELLED, "written")) {
116318744Sjkh		msgConfirm("You've already written out your changes -\n"
116418744Sjkh			   "it's too late to undo!");
116518744Sjkh	    }
116670005Sjkh	    else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
116718744Sjkh		variable_unset(DISK_PARTITIONED);
116818744Sjkh		variable_unset(DISK_LABELLED);
116918744Sjkh		for (i = 0; devs[i]; i++) {
117018744Sjkh		    Disk *d;
117112661Speter
117218744Sjkh		    if (!devs[i]->enabled)
117318744Sjkh			continue;
117418744Sjkh		    else if ((d = Open_Disk(devs[i]->name)) != NULL) {
117518744Sjkh			Free_Disk(devs[i]->private);
117618744Sjkh			devs[i]->private = d;
1177107341Sjhb#ifdef WITH_SLICES
117830345Sjkh			diskPartition(devs[i]);
1179107341Sjhb#endif
118018744Sjkh		    }
11818824Sjkh		}
118230345Sjkh		record_label_chunks(devs, dev);
11838824Sjkh	    }
118418636Sjkh	    clear_wins();
11858824Sjkh	    break;
11868820Sjkh
11878549Sjkh	case 'W':
118874156Sjkh	    if (!variable_cmp(DISK_LABELLED, "written")) {
118918744Sjkh		msgConfirm("You've already written out your changes - if you\n"
119074156Sjkh			   "wish to overwrite them, you'll have to restart\n"
119174156Sjkh			   "sysinstall first.");
119218744Sjkh	    }
119370005Sjkh	    else if (!msgNoYes("WARNING:  This should only be used when modifying an EXISTING\n"
119418687Sjkh			  "installation.  If you are installing FreeBSD for the first time\n"
119518687Sjkh			  "then you should simply type Q when you're finished here and your\n"
119618687Sjkh			  "changes will be committed in one batch automatically at the end of\n"
119718687Sjkh			  "these questions.\n\n"
119818687Sjkh			  "Are you absolutely sure you want to do this now?")) {
119943685Sjkh		variable_set2(DISK_LABELLED, "yes", 0);
120012661Speter		diskLabelCommit(NULL);
120112661Speter	    }
120218636Sjkh	    clear_wins();
120310882Speter	    break;
120410882Speter
1205107565Srwatson	case 'Z':	/* Set newfs command line */
1206107565Srwatson	    if (label_chunk_info[here].c->private_data &&
1207107565Srwatson		((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs)
1208107565Srwatson		getNewfsCmd(label_chunk_info[here].c->private_data);
1209107565Srwatson	    else
1210107565Srwatson		msg = MSG_NOT_APPLICABLE;
1211107565Srwatson	    clear_wins();
1212107565Srwatson	    break;
1213107565Srwatson
1214107565Srwatson
121510882Speter	case '|':
121670005Sjkh	    if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n"
121712661Speter			  "This is an entirely undocumented feature which you are not\n"
121812661Speter			  "expected to understand!")) {
12198549Sjkh		int i;
12208549Sjkh		Device **devs;
12218549Sjkh
12228549Sjkh		dialog_clear();
12238549Sjkh		end_dialog();
12248549Sjkh		DialogActive = FALSE;
12258549Sjkh		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
12268549Sjkh		if (!devs) {
122712661Speter		    msgConfirm("Can't find any disk devices!");
12288549Sjkh		    break;
12298549Sjkh		}
12308668Sphk		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
12318613Sjkh		    if (devs[i]->enabled)
12328613Sjkh		    	slice_wizard(((Disk *)devs[i]->private));
12338613Sjkh		}
123474156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
123543685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
12368665Sphk		DialogActive = TRUE;
123730345Sjkh		record_label_chunks(devs, dev);
123818636Sjkh		clear_wins();
12398549Sjkh	    }
12408549Sjkh	    else
12418549Sjkh		msg = "A most prudent choice!";
12428549Sjkh	    break;
12438549Sjkh
124421698Sjkh	case '\033':	/* ESC */
12459202Srgrimes	case 'Q':
12468549Sjkh	    labeling = FALSE;
12478549Sjkh	    break;
12488549Sjkh
12498549Sjkh	default:
12508549Sjkh	    beep();
125117362Sjkh	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
125217362Sjkh	    msg = _msg;
12538549Sjkh	    break;
12548549Sjkh	}
125529633Sjkh        if (label_chunk_info[here].type == PART_SLICE)
125629633Sjkh            pslice_focus = here;
125729633Sjkh        else
125829633Sjkh            label_focus = here;
12598549Sjkh    }
126054587Sjkh    restorescr(w);
126154587Sjkh    return DITEM_SUCCESS;
12628549Sjkh}
126326456Sjkh
126487557Sdillonstatic __inline int
126587557Sdillonrequested_part_size(char *varName, int nom, int def, int perc)
126687557Sdillon{
126787557Sdillon    char *cp;
126887557Sdillon    int sz;
126987557Sdillon
127098018Sjhb    if ((cp = variable_get(varName)) != NULL)
127187557Sdillon	sz = atoi(cp);
127287557Sdillon    else
127387557Sdillon	sz = nom + (def - nom) * perc / 100;
127487557Sdillon    return(sz * ONE_MEG);
127587557Sdillon}
127687557Sdillon
127787557Sdillon/*
127887557Sdillon * Attempt to auto-label the disk.  'perc' (0-100) scales
127987557Sdillon * the size of the various partitions within appropriate
128087557Sdillon * bounds (NOMINAL through DEFAULT sizes).  The procedure
128187557Sdillon * succeeds of NULL is returned.  A non-null return message
128287557Sdillon * is either a failure-status message (*req == 0), or
128387557Sdillon * a confirmation requestor (*req == 1).  *req is 0 on
128487557Sdillon * entry to this call.
128587557Sdillon *
128687583Sdillon * We autolabel the following partitions:  /, swap, /var, /tmp, /usr,
128787557Sdillon * and /home.  /home receives any extra left over disk space.
128887557Sdillon */
128987557Sdillonstatic char *
129087557Sdillontry_auto_label(Device **devs, Device *dev, int perc, int *req)
129187557Sdillon{
129287557Sdillon    int sz;
129387557Sdillon    struct chunk *root_chunk = NULL;
129487557Sdillon    struct chunk *swap_chunk = NULL;
129587557Sdillon    struct chunk *usr_chunk = NULL;
129687557Sdillon    struct chunk *var_chunk = NULL;
129787581Sdillon    struct chunk *tmp_chunk = NULL;
129887557Sdillon    struct chunk *home_chunk = NULL;
129987557Sdillon    int mib[2];
1300106348Stmm    unsigned long physmem;
130187557Sdillon    size_t size;
130287557Sdillon    Chunk *rootdev, *swapdev, *usrdev, *vardev;
130387581Sdillon    Chunk *tmpdev, *homedev;
130487557Sdillon    char *msg = NULL;
130587557Sdillon
130687557Sdillon    sz = space_free(label_chunk_info[here].c);
130787557Sdillon    if (sz <= FS_MIN_SIZE)
130887557Sdillon	return("Not enough free space to create a new partition in the slice");
130987557Sdillon
131087557Sdillon    (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev,
131187581Sdillon			&vardev, &tmpdev, &homedev);
131287557Sdillon    if (!rootdev) {
131387557Sdillon	sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc);
131487557Sdillon
131587581Sdillon	root_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
131687581Sdillon			    label_chunk_info[here].c, sz, part,
131787581Sdillon			    FS_BSDFFS,  CHUNK_IS_ROOT | CHUNK_AUTO_SIZE);
131887557Sdillon	if (!root_chunk) {
131987557Sdillon	    *req = 1;
132087557Sdillon	    msg = "Unable to create the root partition. Too big?";
132187557Sdillon	    goto done;
132287557Sdillon	}
1323106826Sjhb	root_chunk->private_data = new_part("/", TRUE);
132487557Sdillon	root_chunk->private_free = safe_free;
132587581Sdillon	root_chunk->flags |= CHUNK_NEWFS;
132687557Sdillon	record_label_chunks(devs, dev);
132787557Sdillon    }
132887557Sdillon    if (!swapdev) {
132987557Sdillon	sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc);
133087557Sdillon	if (sz == 0) {
133187557Sdillon	    int nom;
133287557Sdillon	    int def;
133387557Sdillon
133487557Sdillon	    mib[0] = CTL_HW;
133587557Sdillon	    mib[1] = HW_PHYSMEM;
133687557Sdillon	    size = sizeof physmem;
133787557Sdillon	    sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
133887557Sdillon	    def = 2 * (int)(physmem / 512);
133987557Sdillon	    if (def < SWAP_MIN_SIZE * ONE_MEG)
134087557Sdillon		def = SWAP_MIN_SIZE * ONE_MEG;
134187557Sdillon	    if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG)
134287557Sdillon		def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG;
134387557Sdillon	    nom = (int)(physmem / 512) / 2;
134487557Sdillon	    sz = nom + (def - nom) * perc / 100;
134587557Sdillon	}
134687581Sdillon	swap_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
134787581Sdillon			    label_chunk_info[here].c, sz, part,
134887581Sdillon			    FS_SWAP, CHUNK_AUTO_SIZE);
134987557Sdillon	if (!swap_chunk) {
135087557Sdillon	    *req = 1;
135187557Sdillon	    msg = "Unable to create the swap partition. Too big?";
135287557Sdillon	    goto done;
135387557Sdillon	}
135487557Sdillon	swap_chunk->private_data = 0;
135587557Sdillon	swap_chunk->private_free = safe_free;
135687557Sdillon	record_label_chunks(devs, dev);
135787557Sdillon    }
135887557Sdillon    if (!vardev) {
135987557Sdillon	sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE, VAR_DEFAULT_SIZE, perc);
136087557Sdillon
136187581Sdillon	var_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
136287581Sdillon				label_chunk_info[here].c, sz, part,
136387581Sdillon				FS_BSDFFS, CHUNK_AUTO_SIZE);
136487557Sdillon	if (!var_chunk) {
136587557Sdillon	    *req = 1;
136687557Sdillon	    msg = "Not enough free space for /var - you will need to\n"
136787557Sdillon		   "partition your disk manually with a custom install!";
136887557Sdillon	    goto done;
136987557Sdillon	}
1370106826Sjhb	var_chunk->private_data = new_part("/var", TRUE);
137187557Sdillon	var_chunk->private_free = safe_free;
137287581Sdillon	var_chunk->flags |= CHUNK_NEWFS;
137387557Sdillon	record_label_chunks(devs, dev);
137487557Sdillon    }
137587583Sdillon    if (!tmpdev && !variable_get(VAR_NO_TMP)) {
137687583Sdillon	sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc);
137787557Sdillon
137887581Sdillon	tmp_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
137987581Sdillon				label_chunk_info[here].c, sz, part,
138087581Sdillon				FS_BSDFFS, CHUNK_AUTO_SIZE);
138187581Sdillon	if (!tmp_chunk) {
138287557Sdillon	    *req = 1;
138387583Sdillon	    msg = "Not enough free space for /tmp - you will need to\n"
138487557Sdillon		   "partition your disk manually with a custom install!";
138587557Sdillon	    goto done;
138687557Sdillon	}
1387106826Sjhb	tmp_chunk->private_data = new_part("/tmp", TRUE);
138887581Sdillon	tmp_chunk->private_free = safe_free;
138987581Sdillon	tmp_chunk->flags |= CHUNK_NEWFS;
139087557Sdillon	record_label_chunks(devs, dev);
139187557Sdillon    }
139287557Sdillon    if (!usrdev && !variable_get(VAR_NO_USR)) {
139387557Sdillon	sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc);
139488996Sdillon#if AUTO_HOME == 0
139587557Sdillon	    sz = space_free(label_chunk_info[here].c);
139687557Sdillon#endif
139787557Sdillon	if (sz) {
139887557Sdillon	    if (sz < (USR_MIN_SIZE * ONE_MEG)) {
139987557Sdillon		*req = 1;
140087557Sdillon		msg = "Not enough free space for /usr - you will need to\n"
140187557Sdillon		       "partition your disk manually with a custom install!";
140287557Sdillon	    }
140387557Sdillon
140487557Sdillon	    usr_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
140587581Sdillon				    label_chunk_info[here].c, sz, part,
140687581Sdillon				    FS_BSDFFS, CHUNK_AUTO_SIZE);
140787557Sdillon	    if (!usr_chunk) {
140887557Sdillon		msg = "Unable to create the /usr partition.  Not enough space?\n"
140987557Sdillon			   "You will need to partition your disk manually with a custom install!";
141087557Sdillon		goto done;
141187557Sdillon	    }
1412106826Sjhb	    usr_chunk->private_data = new_part("/usr", TRUE);
141387557Sdillon	    usr_chunk->private_free = safe_free;
141487581Sdillon	    usr_chunk->flags |= CHUNK_NEWFS;
141587557Sdillon	    record_label_chunks(devs, dev);
141687557Sdillon	}
141787557Sdillon    }
141888996Sdillon#if AUTO_HOME == 1
141987557Sdillon    if (!homedev && !variable_get(VAR_NO_HOME)) {
142087557Sdillon	sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc);
142187557Sdillon	if (sz < space_free(label_chunk_info[here].c))
142287557Sdillon	    sz = space_free(label_chunk_info[here].c);
142387557Sdillon	if (sz) {
142487557Sdillon	    if (sz < (HOME_MIN_SIZE * ONE_MEG)) {
142587557Sdillon		*req = 1;
142687557Sdillon		msg = "Not enough free space for /home - you will need to\n"
142787557Sdillon		       "partition your disk manually with a custom install!";
142887557Sdillon		goto done;
142987557Sdillon	    }
143087557Sdillon
143187557Sdillon	    home_chunk = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
143287581Sdillon				    label_chunk_info[here].c, sz, part,
143387581Sdillon				    FS_BSDFFS, CHUNK_AUTO_SIZE);
143487557Sdillon	    if (!home_chunk) {
143587557Sdillon		msg = "Unable to create the /home partition.  Not enough space?\n"
143687557Sdillon			   "You will need to partition your disk manually with a custom install!";
143787557Sdillon		goto done;
143887557Sdillon	    }
1439106826Sjhb	    home_chunk->private_data = new_part("/home", TRUE);
144087557Sdillon	    home_chunk->private_free = safe_free;
144187581Sdillon	    home_chunk->flags |= CHUNK_NEWFS;
144287557Sdillon	    record_label_chunks(devs, dev);
144387557Sdillon	}
144487557Sdillon    }
144588996Sdillon#endif
144687557Sdillon
144787557Sdillon    /* At this point, we're reasonably "labelled" */
144887557Sdillon    if (variable_cmp(DISK_LABELLED, "written"))
144987557Sdillon	variable_set2(DISK_LABELLED, "yes", 0);
145087557Sdillon
145187557Sdillondone:
145287557Sdillon    if (msg) {
145387557Sdillon	if (root_chunk)
145487557Sdillon	    Delete_Chunk(root_chunk->disk, root_chunk);
145587557Sdillon	if (swap_chunk)
145687557Sdillon	    Delete_Chunk(swap_chunk->disk, swap_chunk);
145787557Sdillon	if (var_chunk)
145887557Sdillon	    Delete_Chunk(var_chunk->disk, var_chunk);
145987581Sdillon	if (tmp_chunk)
146087581Sdillon	    Delete_Chunk(tmp_chunk->disk, tmp_chunk);
146187557Sdillon	if (usr_chunk)
146287557Sdillon	    Delete_Chunk(usr_chunk->disk, usr_chunk);
146387557Sdillon	if (home_chunk)
146487557Sdillon	    Delete_Chunk(home_chunk->disk, home_chunk);
146587557Sdillon	record_label_chunks(devs, dev);
146687557Sdillon    }
146787557Sdillon    return(msg);
146887557Sdillon}
146987557Sdillon
147026456Sjkhstatic int
147130345SjkhdiskLabelNonInteractive(Device *dev)
147226456Sjkh{
147326456Sjkh    char *cp;
147426456Sjkh    PartType type;
147526456Sjkh    PartInfo *p;
1476106830Sjhb    u_long flags;
147726456Sjkh    int i, status;
147826456Sjkh    Device **devs;
147926456Sjkh    Disk *d;
148054587Sjkh
148126456Sjkh    status = DITEM_SUCCESS;
148226456Sjkh    cp = variable_get(VAR_DISK);
148326456Sjkh    if (!cp) {
148426456Sjkh	msgConfirm("diskLabel:  No disk selected - can't label automatically.");
148526456Sjkh	return DITEM_FAILURE;
148626456Sjkh    }
148726456Sjkh    devs = deviceFind(cp, DEVICE_TYPE_DISK);
148826456Sjkh    if (!devs) {
148926456Sjkh	msgConfirm("diskLabel: No disk device %s found!", cp);
149026456Sjkh	return DITEM_FAILURE;
149126456Sjkh    }
149230345Sjkh    if (dev)
149330345Sjkh	d = dev->private;
149430345Sjkh    else
149530345Sjkh	d = devs[0]->private;
149630345Sjkh    record_label_chunks(devs, dev);
149726456Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
149826456Sjkh	Chunk *c1 = label_chunk_info[i].c;
149926456Sjkh
150026456Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
150128075Sjkh	    char name[512];
1502106827Sjhb	    char typ[10], mpoint[50];
1503106827Sjhb	    int entries;
150426456Sjkh
1505106827Sjhb	    for (entries = 1;; entries++) {
1506106827Sjhb		int sz, soft = 0;
150728075Sjkh		snprintf(name, sizeof name, "%s-%d", c1->name, entries);
1508106827Sjhb		if ((cp = variable_get(name)) == NULL)
1509106827Sjhb		    break;
1510106827Sjhb		if (sscanf(cp, "%s %d %s %d", typ, &sz, mpoint, &soft) < 3) {
1511106827Sjhb		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s",  c1->name, cp);
1512106827Sjhb		    status = DITEM_FAILURE;
1513106827Sjhb		    break;
1514106827Sjhb		} else {
1515106827Sjhb		    Chunk *tmp;
151626456Sjkh
1517106830Sjhb		    flags = 0;
1518106827Sjhb		    if (!strcmp(typ, "swap")) {
1519106827Sjhb			type = PART_SWAP;
1520106827Sjhb			strcpy(mpoint, "SWAP");
1521106827Sjhb		    } else {
1522106827Sjhb			type = PART_FILESYSTEM;
1523106827Sjhb			if (!strcmp(mpoint, "/"))
1524106827Sjhb			    flags |= CHUNK_IS_ROOT;
1525106827Sjhb		    }
1526106827Sjhb		    if (!sz)
1527106827Sjhb			sz = space_free(c1);
1528106827Sjhb		    if (sz > space_free(c1)) {
1529106827Sjhb			msgConfirm("Not enough free space to create partition: %s", mpoint);
153026456Sjkh			status = DITEM_FAILURE;
1531106827Sjhb			break;
153226456Sjkh		    }
1533106827Sjhb		    if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
1534106827Sjhb			(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
1535106827Sjhb			msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
1536106827Sjhb			status = DITEM_FAILURE;
1537106827Sjhb			break;
1538106827Sjhb		    } else {
1539107565Srwatson			PartInfo *pi;
1540107565Srwatson			pi = tmp->private_data = new_part(mpoint, TRUE);
1541106827Sjhb			tmp->private_free = safe_free;
1542107565Srwatson			pi->newfs_data.newfs_ufs.softupdates = soft;
154326456Sjkh		    }
154426456Sjkh		}
154526456Sjkh	    }
1546106827Sjhb	} else {
154728075Sjkh	    /* Must be something we can set a mountpoint for */
154826456Sjkh	    cp = variable_get(c1->name);
154926456Sjkh	    if (cp) {
155028075Sjkh		char mpoint[50], do_newfs[8];
155126456Sjkh		Boolean newfs = FALSE;
155226456Sjkh
155328075Sjkh		do_newfs[0] = '\0';
155428075Sjkh		if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
155526456Sjkh		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
155626456Sjkh		    status = DITEM_FAILURE;
1557106828Sjhb		    break;
155826456Sjkh		}
155928075Sjkh		newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
156026456Sjkh		if (c1->private_data) {
156126456Sjkh		    p = c1->private_data;
1562107565Srwatson		    p->do_newfs = newfs;
156326456Sjkh		    strcpy(p->mountpoint, mpoint);
156426456Sjkh		}
156526456Sjkh		else {
1566106826Sjhb		    c1->private_data = new_part(mpoint, newfs);
156726456Sjkh		    c1->private_free = safe_free;
156826456Sjkh		}
156926456Sjkh		if (!strcmp(mpoint, "/"))
157026456Sjkh		    c1->flags |= CHUNK_IS_ROOT;
157126456Sjkh		else
157226456Sjkh		    c1->flags &= ~CHUNK_IS_ROOT;
157326456Sjkh	    }
157426456Sjkh	}
157526456Sjkh    }
157626456Sjkh    if (status == DITEM_SUCCESS)
157743685Sjkh	variable_set2(DISK_LABELLED, "yes", 0);
157826456Sjkh    return status;
157926456Sjkh}
1580