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$
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>
39127081Sjhb#include <inttypes.h>
40133040Smarcel#include <libdisk.h>
418549Sjkh#include <sys/disklabel.h>
4210882Speter#include <sys/param.h>
4310882Speter#include <sys/sysctl.h>
448549Sjkh
4588996Sdillon#define AUTO_HOME	0	/* do not create /home automatically */
4688996Sdillon
478549Sjkh/*
488549Sjkh * Everything to do with editing the contents of disk labels.
498549Sjkh */
508549Sjkh
518549Sjkh/* A nice message we use a lot in the disklabel editor */
528549Sjkh#define MSG_NOT_APPLICABLE	"That option is not applicable here"
538549Sjkh
548549Sjkh/* Where to start printing the freebsd slices */
558549Sjkh#define CHUNK_SLICE_START_ROW		2
568622Sjkh#define CHUNK_PART_START_ROW		11
578549Sjkh
588549Sjkh/* The smallest filesystem we're willing to create */
598702Sjkh#define FS_MIN_SIZE			ONE_MEG
608549Sjkh
6187557Sdillon/*
6287557Sdillon * Minimum partition sizes
6387557Sdillon */
64186075Skensmith#if defined(__ia64__) || defined(__sparc64__) || defined(__amd64__)
65209764Sbrucec#define ROOT_MIN_SIZE			280
6644601Sjkh#else
67209764Sbrucec#define ROOT_MIN_SIZE			180
6844601Sjkh#endif
6987557Sdillon#define SWAP_MIN_SIZE			32
70164717Snyan#define USR_MIN_SIZE			160
7187557Sdillon#define VAR_MIN_SIZE			20
7287583Sdillon#define TMP_MIN_SIZE			20
7387557Sdillon#define HOME_MIN_SIZE			20
748549Sjkh
7587557Sdillon/*
7687557Sdillon * Swap size limit for auto-partitioning (4G).
7787557Sdillon */
7887557Sdillon#define SWAP_AUTO_LIMIT_SIZE		4096
7944601Sjkh
8087557Sdillon/*
8187557Sdillon * Default partition sizes.  If we do not have sufficient disk space
8287557Sdillon * for this configuration we scale things relative to the NOM vs DEFAULT
8387557Sdillon * sizes.  If the disk is larger then /home will get any remaining space.
8487557Sdillon */
85209764Sbrucec#define ROOT_DEFAULT_SIZE		1024
86149136Scperciva#define USR_DEFAULT_SIZE		8192
87209764Sbrucec#define VAR_DEFAULT_SIZE		4096
88209764Sbrucec#define TMP_DEFAULT_SIZE		1024
8987557Sdillon#define HOME_DEFAULT_SIZE		USR_DEFAULT_SIZE
9012661Speter
9187557Sdillon/*
9287557Sdillon * Nominal partition sizes.  These are used to scale the default sizes down
9387557Sdillon * when we have insufficient disk space.  If this isn't sufficient we scale
9487557Sdillon * down using the MIN sizes instead.
9587557Sdillon */
96209764Sbrucec#define ROOT_NOMINAL_SIZE		512
97149136Scperciva#define USR_NOMINAL_SIZE		1536
98209764Sbrucec#define VAR_NOMINAL_SIZE		512
99149136Scperciva#define TMP_NOMINAL_SIZE		128
10087557Sdillon#define HOME_NOMINAL_SIZE		USR_NOMINAL_SIZE
10112661Speter
10215440Sjkh/* The bottom-most row we're allowed to scribble on */
10329249Sjkh#define CHUNK_ROW_MAX			16
10415440Sjkh
10515440Sjkh
1068549Sjkh/* All the chunks currently displayed on the screen */
1078549Sjkhstatic struct {
1088549Sjkh    struct chunk *c;
1098549Sjkh    PartType type;
1108549Sjkh} label_chunk_info[MAX_CHUNKS + 1];
1118549Sjkhstatic int here;
1128549Sjkh
11329249Sjkh/*** with this value we try to track the most recently added label ***/
11429249Sjkhstatic int label_focus = 0, pslice_focus = 0;
11529249Sjkh
11630345Sjkhstatic int diskLabel(Device *dev);
11730345Sjkhstatic int diskLabelNonInteractive(Device *dev);
11887557Sdillonstatic char *try_auto_label(Device **devs, Device *dev, int perc, int *req);
11912661Speter
12030345Sjkhstatic int
12130345SjkhlabelHook(dialogMenuItem *selected)
12230345Sjkh{
12330345Sjkh    Device **devs = NULL;
12430345Sjkh
12530345Sjkh    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
12630345Sjkh    if (!devs) {
12730345Sjkh	msgConfirm("Unable to find disk %s!", selected->prompt);
12830345Sjkh	return DITEM_FAILURE;
12930345Sjkh    }
13030345Sjkh    /* Toggle enabled status? */
13130345Sjkh    if (!devs[0]->enabled) {
13230345Sjkh	devs[0]->enabled = TRUE;
13330345Sjkh	diskLabel(devs[0]);
13430345Sjkh    }
13530345Sjkh    else
13630345Sjkh	devs[0]->enabled = FALSE;
13754587Sjkh    return DITEM_SUCCESS;
13830345Sjkh}
13930345Sjkh
14030345Sjkhstatic int
14130345SjkhlabelCheck(dialogMenuItem *selected)
14230345Sjkh{
14330345Sjkh    Device **devs = NULL;
14430345Sjkh
14530345Sjkh    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
14630345Sjkh    if (!devs || devs[0]->enabled == FALSE)
14730345Sjkh	return FALSE;
14830345Sjkh    return TRUE;
14930345Sjkh}
15030345Sjkh
15112661Speterint
15215091SjkhdiskLabelEditor(dialogMenuItem *self)
15312661Speter{
15430345Sjkh    DMenu *menu;
15512661Speter    Device **devs;
15630345Sjkh    int i, cnt;
15712661Speter
15830345Sjkh    i = 0;
15930345Sjkh    cnt = diskGetSelectCount(&devs);
16030345Sjkh    if (cnt == -1) {
16112661Speter	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
16212661Speter		   "properly probed at boot time.  See the Hardware Guide on the\n"
16312661Speter		   "Documentation menu for clues on diagnosing this type of problem.");
16415242Sjkh	return DITEM_FAILURE;
16512661Speter    }
16630345Sjkh    else if (cnt) {
16730345Sjkh	/* Some are already selected */
16897667Sjhb	if (variable_get(VAR_NONINTERACTIVE) &&
16997667Sjhb	  !variable_get(VAR_DISKINTERACTIVE))
17034543Sjkh	    i = diskLabelNonInteractive(NULL);
17130381Sjkh	else
17234543Sjkh	    i = diskLabel(NULL);
17312661Speter    }
17430345Sjkh    else {
17530345Sjkh	/* No disks are selected, fall-back case now */
17630345Sjkh	cnt = deviceCount(devs);
17730345Sjkh	if (cnt == 1) {
17830345Sjkh	    devs[0]->enabled = TRUE;
17997667Sjhb	    if (variable_get(VAR_NONINTERACTIVE) &&
18097667Sjhb	      !variable_get(VAR_DISKINTERACTIVE))
18130345Sjkh		i = diskLabelNonInteractive(devs[0]);
18230345Sjkh	    else
18330345Sjkh		i = diskLabel(devs[0]);
18430345Sjkh	}
18530345Sjkh	else {
18630345Sjkh	    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck);
18730345Sjkh	    if (!menu) {
18830345Sjkh		msgConfirm("No devices suitable for installation found!\n\n"
18930345Sjkh			   "Please verify that your disk controller (and attached drives)\n"
19030345Sjkh			   "were detected properly.  This can be done by pressing the\n"
19130345Sjkh			   "[Scroll Lock] key and using the Arrow keys to move back to\n"
19230345Sjkh			   "the boot messages.  Press [Scroll Lock] again to return.");
19330345Sjkh		i = DITEM_FAILURE;
19430345Sjkh	    }
19530345Sjkh	    else {
19630345Sjkh		i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
19730345Sjkh		free(menu);
19830345Sjkh	    }
19930345Sjkh	}
20012661Speter    }
20118744Sjkh    if (DITEM_STATUS(i) != DITEM_FAILURE) {
20274156Sjkh	if (variable_cmp(DISK_LABELLED, "written"))
20343685Sjkh	    variable_set2(DISK_LABELLED, "yes", 0);
20418744Sjkh    }
20512661Speter    return i;
20612661Speter}
20712661Speter
20812661Speterint
20915091SjkhdiskLabelCommit(dialogMenuItem *self)
21012661Speter{
21112661Speter    char *cp;
21212661Speter    int i;
21312661Speter
21412661Speter    /* Already done? */
21517025Sjkh    if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
21615242Sjkh	i = DITEM_SUCCESS;
21712661Speter    else if (!cp) {
21812661Speter	msgConfirm("You must assign disk labels before this option can be used.");
21915242Sjkh	i = DITEM_FAILURE;
22012661Speter    }
22112661Speter    /* The routine will guard against redundant writes, just as this one does */
22215419Sjkh    else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
22315242Sjkh	i = DITEM_FAILURE;
22415419Sjkh    else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
22515242Sjkh	i = DITEM_FAILURE;
22612661Speter    else {
22712661Speter	msgInfo("All filesystem information written successfully.");
22843685Sjkh	variable_set2(DISK_LABELLED, "written", 0);
22915242Sjkh	i = DITEM_SUCCESS;
23012661Speter    }
23112661Speter    return i;
23212661Speter}
23312661Speter
2348549Sjkh/* See if we're already using a desired partition name */
2358549Sjkhstatic Boolean
2368549Sjkhcheck_conflict(char *name)
2378549Sjkh{
2388549Sjkh    int i;
2398549Sjkh
2408751Sjkh    for (i = 0; label_chunk_info[i].c; i++)
241121890Smarcel	if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT
242121890Smarcel	    || label_chunk_info[i].type == PART_EFI) && label_chunk_info[i].c->private_data
24314793Sjoerg	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
2448549Sjkh	    return TRUE;
2458549Sjkh    return FALSE;
2468549Sjkh}
2478549Sjkh
2488549Sjkh/* How much space is in this FreeBSD slice? */
249127081Sjhbstatic daddr_t
2508549Sjkhspace_free(struct chunk *c)
2518549Sjkh{
25212661Speter    struct chunk *c1;
253127081Sjhb    daddr_t sz = c->size;
2548549Sjkh
25512661Speter    for (c1 = c->part; c1; c1 = c1->next) {
2568549Sjkh	if (c1->type != unused)
2578549Sjkh	    sz -= c1->size;
2588549Sjkh    }
2598549Sjkh    if (sz < 0)
2608549Sjkh	msgFatal("Partitions are larger than actual chunk??");
2618549Sjkh    return sz;
2628549Sjkh}
2638549Sjkh
2648549Sjkh/* Snapshot the current situation into the displayed chunks structure */
2658549Sjkhstatic void
26630345Sjkhrecord_label_chunks(Device **devs, Device *dev)
2678549Sjkh{
2688549Sjkh    int i, j, p;
2698549Sjkh    struct chunk *c1, *c2;
2708556Sjkh    Disk *d;
2718549Sjkh
2728549Sjkh    j = p = 0;
2738556Sjkh    /* First buzz through and pick up the FreeBSD slices */
2748549Sjkh    for (i = 0; devs[i]; i++) {
27530345Sjkh	if ((dev && devs[i] != dev) || !devs[i]->enabled)
2768556Sjkh	    continue;
2778556Sjkh	d = (Disk *)devs[i]->private;
2788556Sjkh	if (!d->chunks)
2798556Sjkh	    msgFatal("No chunk list found for %s!", d->name);
2808549Sjkh
281121890Smarcel#ifdef __ia64__
282121890Smarcel	label_chunk_info[j].type = PART_SLICE;
283121890Smarcel	label_chunk_info[j].c = d->chunks;
284121890Smarcel	j++;
285121890Smarcel#endif
286121890Smarcel
2878556Sjkh	/* Put the slice entries first */
2888556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2898549Sjkh	    if (c1->type == freebsd) {
2908549Sjkh		label_chunk_info[j].type = PART_SLICE;
2918549Sjkh		label_chunk_info[j].c = c1;
2928549Sjkh		++j;
2938549Sjkh	    }
294129259Sgrehan#ifdef __powerpc__
295129259Sgrehan	    if (c1->type == apple) {
296129259Sgrehan    	        label_chunk_info[j].type = PART_SLICE;
297129259Sgrehan		label_chunk_info[j].c = c1;
298129259Sgrehan		++j;
299129259Sgrehan	    }
300129259Sgrehan#endif
3018549Sjkh	}
3028549Sjkh    }
30312661Speter
3048556Sjkh    /* Now run through again and get the FreeBSD partition entries */
3058556Sjkh    for (i = 0; devs[i]; i++) {
3068556Sjkh	if (!devs[i]->enabled)
3078556Sjkh	    continue;
3088556Sjkh	d = (Disk *)devs[i]->private;
3098549Sjkh	/* Then buzz through and pick up the partitions */
3108556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
3118549Sjkh	    if (c1->type == freebsd) {
3128549Sjkh		for (c2 = c1->part; c2; c2 = c2->next) {
3138549Sjkh		    if (c2->type == part) {
3148549Sjkh			if (c2->subtype == FS_SWAP)
3158549Sjkh			    label_chunk_info[j].type = PART_SWAP;
3168549Sjkh			else
3178549Sjkh			    label_chunk_info[j].type = PART_FILESYSTEM;
3188549Sjkh			label_chunk_info[j].c = c2;
3198549Sjkh			++j;
3208549Sjkh		    }
3218549Sjkh		}
3228549Sjkh	    }
323121890Smarcel	    else if (c1->type == fat) {
3248549Sjkh		label_chunk_info[j].type = PART_FAT;
3258549Sjkh		label_chunk_info[j].c = c1;
3268702Sjkh		++j;
3278549Sjkh	    }
328121864Smarcel#ifdef __ia64__
329121890Smarcel	    else if (c1->type == efi) {
330121890Smarcel		label_chunk_info[j].type = PART_EFI;
331121890Smarcel		label_chunk_info[j].c = c1;
332121890Smarcel		++j;
333121890Smarcel	    }
334121864Smarcel	    else if (c1->type == part) {
335121864Smarcel		if (c1->subtype == FS_SWAP)
336121864Smarcel		    label_chunk_info[j].type = PART_SWAP;
337121864Smarcel		else
338121864Smarcel		    label_chunk_info[j].type = PART_FILESYSTEM;
339121864Smarcel		label_chunk_info[j].c = c1;
340121864Smarcel		++j;
341121864Smarcel	    }
342121864Smarcel#endif
343129259Sgrehan#ifdef __powerpc__
344129259Sgrehan	    else if (c1->type == apple) {
345129259Sgrehan	        for (c2 = c1->part; c2; c2 = c2->next) {
346129259Sgrehan		    if (c2->type == part) {
347129259Sgrehan		        if (c2->subtype == FS_SWAP)
348129259Sgrehan			    label_chunk_info[j].type = PART_SWAP;
349129259Sgrehan			else
350129259Sgrehan			    label_chunk_info[j].type = PART_FILESYSTEM;
351129259Sgrehan			label_chunk_info[j].c = c2;
352129259Sgrehan			++j;
353129259Sgrehan		    }
354129259Sgrehan		}
355129259Sgrehan	    }
356129259Sgrehan#endif
3578549Sjkh	}
3588549Sjkh    }
3598549Sjkh    label_chunk_info[j].c = NULL;
36029249Sjkh    if (here >= j) {
3618549Sjkh	here = j  ? j - 1 : 0;
36229249Sjkh    }
3638549Sjkh}
3648549Sjkh
3658549Sjkh/* A new partition entry */
3668549Sjkhstatic PartInfo *
367133106Smarcelnew_part(PartType type, char *mpoint, Boolean newfs)
3688549Sjkh{
369107565Srwatson    PartInfo *pi;
3708549Sjkh
3719202Srgrimes    if (!mpoint)
372133106Smarcel	mpoint = (type == PART_EFI) ? "/efi" : "/change_me";
3739202Srgrimes
374107565Srwatson    pi = (PartInfo *)safe_malloc(sizeof(PartInfo));
375107565Srwatson    sstrncpy(pi->mountpoint, mpoint, FILENAME_MAX);
376107565Srwatson
377107565Srwatson    pi->do_newfs = newfs;
378107565Srwatson
379133106Smarcel    if (type == PART_EFI) {
380133106Smarcel	pi->newfs_type = NEWFS_MSDOS;
381133106Smarcel    } else {
382133106Smarcel	pi->newfs_type = NEWFS_UFS;
383133106Smarcel	strcpy(pi->newfs_data.newfs_ufs.user_options, "");
384133106Smarcel	pi->newfs_data.newfs_ufs.acls = FALSE;
385133106Smarcel	pi->newfs_data.newfs_ufs.multilabel = FALSE;
386133106Smarcel	pi->newfs_data.newfs_ufs.softupdates = strcmp(mpoint, "/");
387133106Smarcel	pi->newfs_data.newfs_ufs.ufs1 = FALSE;
388133106Smarcel    }
389107565Srwatson
390107565Srwatson    return pi;
3918549Sjkh}
3928549Sjkh
3938549Sjkh/* Get the mountpoint for a partition and save it away */
39412661Speterstatic PartInfo *
395133106Smarcelget_mountpoint(PartType type, struct chunk *old)
3968549Sjkh{
3978549Sjkh    char *val;
3988549Sjkh    PartInfo *tmp;
399106822Sjhb    Boolean newfs;
4008549Sjkh
40114793Sjoerg    if (old && old->private_data)
40214793Sjoerg	tmp = old->private_data;
4038810Sjkh    else
4048810Sjkh	tmp = NULL;
405133106Smarcel    val = (tmp != NULL) ? tmp->mountpoint : (type == PART_EFI) ? "/efi" : NULL;
406133106Smarcel    val = msgGetInput(val, "Please specify a mount point for the partition");
4078764Sjkh    if (!val || !*val) {
4088751Sjkh	if (!old)
4098751Sjkh	    return NULL;
4108751Sjkh	else {
41114793Sjoerg	    free(old->private_data);
41214793Sjoerg	    old->private_data = NULL;
4138751Sjkh	}
4148669Sphk	return NULL;
4158751Sjkh    }
4168669Sphk
4178669Sphk    /* Is it just the same value? */
4188810Sjkh    if (tmp && !strcmp(tmp->mountpoint, val))
4198669Sphk	return NULL;
4208810Sjkh
4218810Sjkh    /* Did we use it already? */
4228669Sphk    if (check_conflict(val)) {
4238669Sphk	msgConfirm("You already have a mount point for %s assigned!", val);
4248669Sphk	return NULL;
4258549Sjkh    }
4268810Sjkh
4278810Sjkh    /* Is it bogus? */
4288669Sphk    if (*val != '/') {
4298669Sphk	msgConfirm("Mount point must start with a / character");
4308669Sphk	return NULL;
4318669Sphk    }
4328810Sjkh
4338810Sjkh    /* Is it going to be mounted on root? */
4348669Sphk    if (!strcmp(val, "/")) {
4358669Sphk	if (old)
4368669Sphk	    old->flags |= CHUNK_IS_ROOT;
4378810Sjkh    }
4388810Sjkh    else if (old)
4398669Sphk	old->flags &= ~CHUNK_IS_ROOT;
4408810Sjkh
441106823Sjhb    newfs = TRUE;
442106822Sjhb    if (tmp) {
443107565Srwatson	newfs = tmp->do_newfs;
444106822Sjhb    	safe_free(tmp);
445106822Sjhb    }
44646615Sjkh    val = string_skipwhite(string_prune(val));
447133106Smarcel    tmp = new_part(type, val, newfs);
4488669Sphk    if (old) {
44914793Sjoerg	old->private_data = tmp;
4508669Sphk	old->private_free = safe_free;
4518669Sphk    }
4528669Sphk    return tmp;
4538549Sjkh}
4548549Sjkh
4558549Sjkh/* Get the type of the new partiton */
4568549Sjkhstatic PartType
4578549Sjkhget_partition_type(void)
4588549Sjkh{
4598549Sjkh    char selection[20];
4608669Sphk    int i;
4618549Sjkh    static unsigned char *fs_types[] = {
462121890Smarcel#ifdef __ia64__
463121890Smarcel	"EFI",	"An EFI system partition",
464121890Smarcel#endif
465121890Smarcel	"FS",	"A file system",
466121890Smarcel	"Swap",	"A swap partition.",
4678549Sjkh    };
46854587Sjkh    WINDOW *w = savescr();
46954587Sjkh
4708669Sphk    i = dialog_menu("Please choose a partition type",
471121890Smarcel	"If you want to use this partition for swap space, select Swap.\n"
472121890Smarcel	"If you want to put a filesystem on it, choose FS.",
473121890Smarcel	-1, -1,
474121890Smarcel#ifdef __ia64__
475121890Smarcel	3, 3,
476121890Smarcel#else
477121890Smarcel	2, 2,
478121890Smarcel#endif
479121890Smarcel	fs_types, selection, NULL, NULL);
48054587Sjkh    restorescr(w);
4818669Sphk    if (!i) {
482121890Smarcel#ifdef __ia64__
483121890Smarcel	if (!strcmp(selection, "EFI"))
484121890Smarcel	    return PART_EFI;
485121890Smarcel#endif
4868549Sjkh	if (!strcmp(selection, "FS"))
4878549Sjkh	    return PART_FILESYSTEM;
4888549Sjkh	else if (!strcmp(selection, "Swap"))
4898549Sjkh	    return PART_SWAP;
4908549Sjkh    }
4918549Sjkh    return PART_NONE;
4928549Sjkh}
4938549Sjkh
4948549Sjkh/* If the user wants a special newfs command for this, set it */
4958549Sjkhstatic void
4968549SjkhgetNewfsCmd(PartInfo *p)
4978549Sjkh{
498107565Srwatson    char buffer[NEWFS_CMD_ARGS_MAX];
4998549Sjkh    char *val;
5008549Sjkh
501107565Srwatson    switch (p->newfs_type) {
502107565Srwatson    case NEWFS_UFS:
503107565Srwatson	snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s %s %s %s",
504107565Srwatson	    NEWFS_UFS_CMD, p->newfs_data.newfs_ufs.softupdates ?  "-U" : "",
505113751Srwatson	    p->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2",
506107565Srwatson	    p->newfs_data.newfs_ufs.user_options);
507107565Srwatson	break;
508107565Srwatson    case NEWFS_MSDOS:
509107565Srwatson	snprintf(buffer, NEWFS_CMD_ARGS_MAX, "%s", NEWFS_MSDOS_CMD);
510107565Srwatson	break;
511107565Srwatson    case NEWFS_CUSTOM:
512107565Srwatson	strcpy(buffer, p->newfs_data.newfs_custom.command);
513107565Srwatson	break;
514107565Srwatson    }
515107565Srwatson
516107565Srwatson    val = msgGetInput(buffer,
517107565Srwatson	"Please enter the newfs command and options you'd like to use in\n"
518107565Srwatson	"creating this file system.");
519107565Srwatson    if (val != NULL) {
520107565Srwatson	p->newfs_type = NEWFS_CUSTOM;
521107565Srwatson	strlcpy(p->newfs_data.newfs_custom.command, val, NEWFS_CMD_ARGS_MAX);
522107565Srwatson    }
5238549Sjkh}
5248549Sjkh
525107565Srwatsonstatic void
526107565SrwatsongetNewfsOptionalArguments(PartInfo *p)
527107565Srwatson{
528107565Srwatson	char buffer[NEWFS_CMD_ARGS_MAX];
529107565Srwatson	char *val;
530107565Srwatson
531107565Srwatson	/* Must be UFS, per argument checking in I/O routines. */
532107565Srwatson
533107565Srwatson	strlcpy(buffer,  p->newfs_data.newfs_ufs.user_options,
534107565Srwatson	    NEWFS_CMD_ARGS_MAX);
535107565Srwatson	val = msgGetInput(buffer,
536107565Srwatson	    "Please enter any additional UFS newfs options you'd like to\n"
537107565Srwatson	    "use in creating this file system.");
538107565Srwatson	if (val != NULL)
539107565Srwatson		strlcpy(p->newfs_data.newfs_ufs.user_options, val,
540107565Srwatson		    NEWFS_CMD_ARGS_MAX);
541107565Srwatson}
542107565Srwatson
54376299Sjkh#define MAX_MOUNT_NAME	9
5448549Sjkh
5458549Sjkh#define PART_PART_COL	0
54654014Sjkh#define PART_MOUNT_COL	10
5478549Sjkh#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
54849202Sbrian#define PART_NEWFS_COL	(PART_SIZE_COL + 8)
54976299Sjkh#define PART_OFF	38
5508549Sjkh
55129249Sjkh#define TOTAL_AVAIL_LINES       (10)
55229249Sjkh#define PSLICE_SHOWABLE          (4)
55329249Sjkh
55429249Sjkh
5558549Sjkh/* stick this all up on the screen */
5568549Sjkhstatic void
5578549Sjkhprint_label_chunks(void)
5588549Sjkh{
559127081Sjhb    int  i, j, srow, prow, pcol;
560127081Sjhb    daddr_t sz;
56129249Sjkh    char clrmsg[80];
56229633Sjkh    int ChunkPartStartRow;
56329633Sjkh    WINDOW *ChunkWin;
5648549Sjkh
56529249Sjkh    /********************************************************/
56629249Sjkh    /*** These values are for controling screen resources ***/
56729249Sjkh    /*** Each label line holds up to 2 labels, so beware! ***/
56829249Sjkh    /*** strategy will be to try to always make sure the  ***/
56929249Sjkh    /*** highlighted label is in the active display area. ***/
57029249Sjkh    /********************************************************/
57129249Sjkh    int  pslice_max, label_max;
57229249Sjkh    int  pslice_count, label_count, label_focus_found, pslice_focus_found;
57329249Sjkh
5748549Sjkh    attrset(A_REVERSE);
5758549Sjkh    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
5768549Sjkh    attrset(A_NORMAL);
5778549Sjkh
57829633Sjkh    /*** Count the number of parition slices ***/
57929633Sjkh    pslice_count = 0;
58029633Sjkh    for (i = 0; label_chunk_info[i].c ; i++) {
58129633Sjkh        if (label_chunk_info[i].type == PART_SLICE)
58229633Sjkh            ++pslice_count;
58329633Sjkh    }
58429633Sjkh    pslice_max = pslice_count;
585121864Smarcel
58629633Sjkh    /*** 4 line max for partition slices ***/
58729633Sjkh    if (pslice_max > PSLICE_SHOWABLE) {
58829633Sjkh        pslice_max = PSLICE_SHOWABLE;
58929633Sjkh    }
59029633Sjkh    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max;
59129633Sjkh
59229633Sjkh    /*** View partition slices modulo pslice_max ***/
59329633Sjkh    label_max = TOTAL_AVAIL_LINES - pslice_max;
59429633Sjkh
5958549Sjkh    for (i = 0; i < 2; i++) {
59615440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
59715440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
5988549Sjkh
59915440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
60015440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
6018549Sjkh
60249202Sbrian	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size");
60349202Sbrian	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----");
6048549Sjkh
60515440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
60615440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
6078549Sjkh    }
6088549Sjkh    srow = CHUNK_SLICE_START_ROW;
60915440Sjkh    prow = 0;
6108549Sjkh    pcol = 0;
6118549Sjkh
61229249Sjkh    /*** these variables indicate that the focused item is shown currently ***/
61329249Sjkh    label_focus_found = 0;
61429249Sjkh    pslice_focus_found = 0;
61529249Sjkh
61629249Sjkh    label_count = 0;
61729249Sjkh    pslice_count = 0;
61829249Sjkh    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "          ");
61929249Sjkh    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "          ");
62029249Sjkh
62129633Sjkh    ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
62229633Sjkh
62329633Sjkh    wclear(ChunkWin);
62429633Sjkh    /*** wrefresh(ChunkWin); ***/
62529633Sjkh
6268751Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
6278549Sjkh	/* Is it a slice entry displayed at the top? */
6288549Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
62929249Sjkh            /*** This causes the new pslice to replace the previous display ***/
63029249Sjkh            /*** focus must remain on the most recently active pslice       ***/
63129249Sjkh            if (pslice_count == pslice_max) {
63229249Sjkh                if (pslice_focus_found) {
63329249Sjkh                    /*** This is where we can mark the more following ***/
63429249Sjkh                    attrset(A_BOLD);
63529249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***");
63629249Sjkh                    attrset(A_NORMAL);
63729249Sjkh                    continue;
63829249Sjkh                }
63929249Sjkh                else {
64029249Sjkh                    /*** this is where we set the more previous ***/
64129249Sjkh                    attrset(A_BOLD);
64229249Sjkh                    mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***");
64329249Sjkh                    attrset(A_NORMAL);
64429249Sjkh                    pslice_count = 0;
64529249Sjkh                    srow = CHUNK_SLICE_START_ROW;
64629249Sjkh                }
64729249Sjkh            }
64829249Sjkh
6498549Sjkh	    sz = space_free(label_chunk_info[i].c);
65015440Sjkh	    if (i == here)
65116208Sjkh		attrset(ATTR_SELECTED);
65229249Sjkh            if (i == pslice_focus)
65329249Sjkh                pslice_focus_found = -1;
65429249Sjkh
655121864Smarcel	    if (label_chunk_info[i].c->type == whole) {
656121864Smarcel		if (sz >= 100 * ONE_GIG)
657121864Smarcel		    mvprintw(srow++, 0,
658127081Sjhb			"Disk: %s\t\tFree: %jd blocks (%jdGB)",
659127081Sjhb			label_chunk_info[i].c->disk->name, (intmax_t)sz,
660127081Sjhb			(intmax_t)(sz / ONE_GIG));
661121864Smarcel		else
662121864Smarcel		    mvprintw(srow++, 0,
663127081Sjhb			"Disk: %s\t\tFree: %jd blocks (%jdMB)",
664127081Sjhb			label_chunk_info[i].c->disk->name, (intmax_t)sz,
665127081Sjhb			(intmax_t)(sz / ONE_MEG));
666121864Smarcel	    } else {
667121864Smarcel		if (sz >= 100 * ONE_GIG)
668107751Sphk		    mvprintw(srow++, 0,
669127081Sjhb			"Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdGB)",
670107751Sphk			label_chunk_info[i].c->disk->name,
671107751Sphk			label_chunk_info[i].c->name,
672127081Sjhb			(intmax_t)sz, (intmax_t)(sz / ONE_GIG));
673121864Smarcel		else
674107751Sphk		    mvprintw(srow++, 0,
675127081Sjhb			"Disk: %s\tPartition name: %s\tFree: %jd blocks (%jdMB)",
676107751Sphk			label_chunk_info[i].c->disk->name,
677107751Sphk			label_chunk_info[i].c->name,
678127081Sjhb			(intmax_t)sz, (intmax_t)(sz / ONE_MEG));
679121864Smarcel	    }
68015440Sjkh	    attrset(A_NORMAL);
68115440Sjkh	    clrtoeol();
68215440Sjkh	    move(0, 0);
68329633Sjkh	    /*** refresh(); ***/
68429249Sjkh            ++pslice_count;
6858549Sjkh	}
68615440Sjkh	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
6878549Sjkh	else {
688107565Srwatson	    char onestr[PART_OFF], num[10], *mountpoint, newfs[12];
6898549Sjkh
6908549Sjkh	    /*
6918549Sjkh	     * We copy this into a blank-padded string so that it looks like
6928549Sjkh	     * a solid bar in reverse-video
6938549Sjkh	     */
6948549Sjkh	    memset(onestr, ' ', PART_OFF - 1);
6958549Sjkh	    onestr[PART_OFF - 1] = '\0';
69629249Sjkh
69729249Sjkh            /*** Track how many labels have been displayed ***/
69829249Sjkh            if (label_count == ((label_max - 1 ) * 2)) {
69929249Sjkh                if (label_focus_found) {
70029249Sjkh                    continue;
70129249Sjkh                }
70229249Sjkh                else {
70329249Sjkh                    label_count = 0;
70429249Sjkh                    prow = 0;
70529249Sjkh                    pcol = 0;
70629249Sjkh                }
70729249Sjkh            }
70829249Sjkh
70915440Sjkh	    /* Go for two columns if we've written one full columns worth */
71029249Sjkh	    /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/
71129249Sjkh            if (label_count == label_max - 1) {
7128549Sjkh		pcol = PART_OFF;
71315440Sjkh		prow = 0;
7148549Sjkh	    }
7158705Sjkh	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
7168549Sjkh	    /* If it's a filesystem, display the mountpoint */
717121890Smarcel	    if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM
718121890Smarcel		|| label_chunk_info[i].type == PART_FAT || label_chunk_info[i].type == PART_EFI))
719121890Smarcel		mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
72023529Sjkh	    else if (label_chunk_info[i].type == PART_SWAP)
72123529Sjkh		mountpoint = "swap";
72210882Speter	    else
72310882Speter	        mountpoint = "<none>";
72410882Speter
72510882Speter	    /* Now display the newfs field */
726121890Smarcel	    if (label_chunk_info[i].type == PART_FAT)
727106885Smarcel		strcpy(newfs, "DOS");
728106885Smarcel#if defined(__ia64__)
729121890Smarcel	    else if (label_chunk_info[i].type == PART_EFI) {
730121890Smarcel		strcpy(newfs, "EFI");
731121890Smarcel		if (label_chunk_info[i].c->private_data) {
732121890Smarcel		    strcat(newfs, "  ");
733121890Smarcel		    PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data;
734121890Smarcel		    strcat(newfs, pi->do_newfs ? " Y" : " N");
735106885Smarcel		}
736121890Smarcel	    }
737106885Smarcel#endif
73874086Sjkh	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) {
739107565Srwatson		PartInfo *pi = (PartInfo *)label_chunk_info[i].c->private_data;
740107565Srwatson
741107565Srwatson		switch (pi->newfs_type) {
742107565Srwatson		case NEWFS_UFS:
743107565Srwatson			strcpy(newfs, NEWFS_UFS_STRING);
744113751Srwatson			if (pi->newfs_data.newfs_ufs.ufs1)
745113751Srwatson				strcat(newfs, "1");
746113751Srwatson			else
747107565Srwatson				strcat(newfs, "2");
748107565Srwatson			if (pi->newfs_data.newfs_ufs.softupdates)
749107565Srwatson				strcat(newfs, "+S");
750107565Srwatson			else
751107565Srwatson				strcat(newfs, "  ");
752107565Srwatson
753107565Srwatson			break;
754107565Srwatson		case NEWFS_MSDOS:
755107565Srwatson			strcpy(newfs, "FAT");
756107565Srwatson			break;
757107565Srwatson		case NEWFS_CUSTOM:
758107565Srwatson			strcpy(newfs, "CUST");
759107565Srwatson			break;
760107565Srwatson		}
761107565Srwatson		strcat(newfs, pi->do_newfs ? " Y" : " N ");
76274086Sjkh	    }
76310882Speter	    else if (label_chunk_info[i].type == PART_SWAP)
76474086Sjkh		strcpy(newfs, "SWAP");
76510882Speter	    else
76674086Sjkh		strcpy(newfs, "*");
7678549Sjkh	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
7688549Sjkh		onestr[PART_MOUNT_COL + j] = mountpoint[j];
769107751Sphk	    if (label_chunk_info[i].c->size == 0)
770127081Sjhb	        snprintf(num, 10, "%5dMB", 0);
771107751Sphk	    else if (label_chunk_info[i].c->size < (100 * ONE_GIG))
772127081Sjhb		snprintf(num, 10, "%5jdMB",
773127081Sjhb		    (intmax_t)label_chunk_info[i].c->size / ONE_MEG);
774107751Sphk	    else
775127081Sjhb		snprintf(num, 10, "%5jdGB",
776127081Sjhb		    (intmax_t)label_chunk_info[i].c->size / ONE_GIG);
7778549Sjkh	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
7788549Sjkh	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
7798549Sjkh	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
78029633Sjkh            if (i == label_focus) {
78129633Sjkh                label_focus_found = -1;
78229633Sjkh                wattrset(ChunkWin, A_BOLD);
78329633Sjkh            }
78415440Sjkh	    if (i == here)
78516208Sjkh		wattrset(ChunkWin, ATTR_SELECTED);
78629249Sjkh
78774086Sjkh            /*** lazy man's way of expensively padding this string ***/
78874086Sjkh            while (strlen(onestr) < 37)
78929249Sjkh                strcat(onestr, " ");
79029249Sjkh
79115440Sjkh	    mvwaddstr(ChunkWin, prow, pcol, onestr);
79215440Sjkh	    wattrset(ChunkWin, A_NORMAL);
79315440Sjkh	    move(0, 0);
7948549Sjkh	    ++prow;
79529249Sjkh            ++label_count;
7968549Sjkh	}
7978549Sjkh    }
79829249Sjkh
79929249Sjkh    /*** this will erase all the extra stuff ***/
80029249Sjkh    memset(clrmsg, ' ', 37);
80129249Sjkh    clrmsg[37] = '\0';
80229249Sjkh
80329249Sjkh    while (pslice_count < pslice_max) {
80429249Sjkh        mvprintw(srow++, 0, clrmsg);
80529249Sjkh        clrtoeol();
80629249Sjkh        ++pslice_count;
80729249Sjkh    }
80829633Sjkh    while (label_count < (2 * (label_max - 1))) {
80929633Sjkh        mvwaddstr(ChunkWin, prow++, pcol, clrmsg);
81029633Sjkh	++label_count;
81129633Sjkh	if (prow == (label_max - 1)) {
81229633Sjkh	    prow = 0;
81329633Sjkh	    pcol = PART_OFF;
81429633Sjkh	}
81529249Sjkh    }
81629633Sjkh    refresh();
81729633Sjkh    wrefresh(ChunkWin);
8188549Sjkh}
8198549Sjkh
8208549Sjkhstatic void
82118619Sjkhprint_command_summary(void)
8228549Sjkh{
8238820Sjkh    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
82474086Sjkh    mvprintw(18, 0, "C = Create        D = Delete   M = Mount pt.");
82515440Sjkh    if (!RunningAsInit)
826107565Srwatson	mvprintw(18, 56, "W = Write");
827107565Srwatson    mvprintw(19, 0, "N = Newfs Opts    Q = Finish   S = Toggle SoftUpdates   Z = Custom Newfs");
828107565Srwatson    mvprintw(20, 0, "T = Toggle Newfs  U = Undo     A = Auto Defaults        R = Delete+Merge");
82915695Sjkh    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
8308549Sjkh    move(0, 0);
8318549Sjkh}
8328549Sjkh
83318619Sjkhstatic void
83418619Sjkhclear_wins(void)
83518619Sjkh{
83618619Sjkh    clear();
83729633Sjkh    print_label_chunks();
83818619Sjkh}
83918619Sjkh
84012661Speterstatic int
84130345SjkhdiskLabel(Device *dev)
8428549Sjkh{
843127081Sjhb    daddr_t sz;
844127081Sjhb    int  key = 0;
8458549Sjkh    Boolean labeling;
8468549Sjkh    char *msg = NULL;
8479202Srgrimes    PartInfo *p, *oldp;
8488549Sjkh    PartType type;
8498824Sjkh    Device **devs;
85054587Sjkh    WINDOW *w = savescr();
8518549Sjkh
85229628Sjkh    label_focus = 0;
85329628Sjkh    pslice_focus = 0;
85429633Sjkh    here = 0;
85530345Sjkh
85612661Speter    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
85712661Speter    if (!devs) {
85812661Speter	msgConfirm("No disks found!");
85954587Sjkh	restorescr(w);
86015242Sjkh	return DITEM_FAILURE;
86112661Speter    }
8628549Sjkh    labeling = TRUE;
8638549Sjkh    keypad(stdscr, TRUE);
86430345Sjkh    record_label_chunks(devs, dev);
8658549Sjkh
86618619Sjkh    clear();
8678549Sjkh    while (labeling) {
86818744Sjkh	char *cp;
86988996Sdillon	int rflags = DELCHUNK_NORMAL;
87018744Sjkh
8718549Sjkh	print_label_chunks();
87218619Sjkh	print_command_summary();
8738549Sjkh	if (msg) {
87415695Sjkh	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
87512661Speter	    clrtoeol();
8768549Sjkh	    beep();
8778549Sjkh	    msg = NULL;
8788549Sjkh	}
87915442Sjkh	else {
88015442Sjkh	    move(23, 0);
88115442Sjkh	    clrtoeol();
88215442Sjkh	}
88318744Sjkh
88418619Sjkh	refresh();
88517397Sjkh	key = getch();
88617397Sjkh	switch (toupper(key)) {
88715440Sjkh	    int i;
88817362Sjkh	    static char _msg[40];
8898549Sjkh
8908751Sjkh	case '\014':	/* ^L */
89118619Sjkh	    clear_wins();
89218619Sjkh	    break;
8938751Sjkh
89421698Sjkh	case '\020':	/* ^P */
8958549Sjkh	case KEY_UP:
8968549Sjkh	case '-':
8978549Sjkh	    if (here != 0)
8988549Sjkh		--here;
8998751Sjkh	    else
9008751Sjkh		while (label_chunk_info[here + 1].c)
9018751Sjkh		    ++here;
9028549Sjkh	    break;
9038549Sjkh
90421698Sjkh	case '\016':	/* ^N */
9058549Sjkh	case KEY_DOWN:
9068549Sjkh	case '+':
9078549Sjkh	case '\r':
9088549Sjkh	case '\n':
9098751Sjkh	    if (label_chunk_info[here + 1].c)
9108549Sjkh		++here;
9118751Sjkh	    else
9128751Sjkh		here = 0;
9138549Sjkh	    break;
9148549Sjkh
9158549Sjkh	case KEY_HOME:
9168549Sjkh	    here = 0;
9178549Sjkh	    break;
9188549Sjkh
9198549Sjkh	case KEY_END:
9208751Sjkh	    while (label_chunk_info[here + 1].c)
9218549Sjkh		++here;
9228549Sjkh	    break;
9238549Sjkh
9248549Sjkh	case KEY_F(1):
9258549Sjkh	case '?':
92612661Speter	    systemDisplayHelp("partition");
92718619Sjkh	    clear_wins();
9288549Sjkh	    break;
9298549Sjkh
930113751Srwatson	case '1':
931113751Srwatson	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
932113751Srwatson		PartInfo *pi =
933113751Srwatson		    ((PartInfo *)label_chunk_info[here].c->private_data);
934113751Srwatson
935113751Srwatson		if ((pi != NULL) &&
936113751Srwatson		    (pi->newfs_type == NEWFS_UFS)) {
937113751Srwatson			pi->newfs_data.newfs_ufs.ufs1 = true;
938113751Srwatson		} else
939113751Srwatson		    msg = MSG_NOT_APPLICABLE;
940113751Srwatson	    } else
941113751Srwatson		msg = MSG_NOT_APPLICABLE;
942113751Srwatson	    break;
943113751Srwatson		break;
944113751Srwatson
945107565Srwatson	case '2':
946107565Srwatson	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
947107565Srwatson		PartInfo *pi =
948107565Srwatson		    ((PartInfo *)label_chunk_info[here].c->private_data);
949107565Srwatson
950107565Srwatson		if ((pi != NULL) &&
951107565Srwatson		    (pi->newfs_type == NEWFS_UFS)) {
952113751Srwatson			pi->newfs_data.newfs_ufs.ufs1 = false;
953107565Srwatson		} else
954107565Srwatson		    msg = MSG_NOT_APPLICABLE;
955107565Srwatson	    } else
956107565Srwatson		msg = MSG_NOT_APPLICABLE;
957107565Srwatson	    break;
958107565Srwatson		break;
959107565Srwatson
96010882Speter	case 'A':
96110882Speter	    if (label_chunk_info[here].type != PART_SLICE) {
96215440Sjkh		msg = "You can only do this in a disk slice (at top of screen)";
96310882Speter		break;
96410882Speter	    }
96587557Sdillon	    /*
96687557Sdillon	     * Generate standard partitions automatically.  If we do not
96787557Sdillon	     * have sufficient space we attempt to scale-down the size
96887557Sdillon	     * of the partitions within certain bounds.
96987557Sdillon	     */
97087557Sdillon	    {
97187557Sdillon		int perc;
97287557Sdillon		int req = 0;
97312661Speter
97487557Sdillon		for (perc = 100; perc > 0; perc -= 5) {
97587557Sdillon		    req = 0;	/* reset for each loop */
97687557Sdillon		    if ((msg = try_auto_label(devs, dev, perc, &req)) == NULL)
97717362Sjkh			break;
97815440Sjkh		}
97987557Sdillon		if (msg) {
98087557Sdillon		    if (req) {
981234737Sdim			msgConfirm("%s", msg);
98218619Sjkh			clear_wins();
98387557Sdillon			msg = NULL;
98417362Sjkh		    }
98515440Sjkh		}
98610882Speter	    }
98715440Sjkh	    break;
98810882Speter
9898549Sjkh	case 'C':
9908549Sjkh	    if (label_chunk_info[here].type != PART_SLICE) {
9918549Sjkh		msg = "You can only do this in a master partition (see top of screen)";
9928549Sjkh		break;
9938549Sjkh	    }
9948549Sjkh	    sz = space_free(label_chunk_info[here].c);
9958669Sphk	    if (sz <= FS_MIN_SIZE) {
99612661Speter		msg = "Not enough space to create an additional FreeBSD partition";
9978669Sphk		break;
9988669Sphk	    }
99915440Sjkh	    else {
100018744Sjkh		char *val;
1001127081Sjhb		daddr_t size;
1002209235Sbrucec		long double dsize;
10038702Sjkh		struct chunk *tmp;
10048820Sjkh		char osize[80];
10058702Sjkh		u_long flags = 0;
10068549Sjkh
1007129259Sgrehan#ifdef __powerpc__
1008129259Sgrehan		/* Always use the maximum size for apple partitions */
1009129259Sgrehan		if (label_chunk_info[here].c->type == apple)
1010129259Sgrehan		    size = sz;
1011129259Sgrehan		else {
1012129259Sgrehan#endif
1013127081Sjhb		sprintf(osize, "%jd", (intmax_t)sz);
101418619Sjkh		val = msgGetInput(osize,
101557617Sjkh				  "Please specify the partition size in blocks or append a trailing G for\n"
1016122021Smarcel#ifdef __ia64__
1017122021Smarcel				  "gigabytes, M for megabytes.\n"
1018122021Smarcel#else
101957617Sjkh				  "gigabytes, M for megabytes, or C for cylinders.\n"
1020122021Smarcel#endif
1021127081Sjhb				  "%jd blocks (%jdMB) are free.",
1022127081Sjhb				  (intmax_t)sz, (intmax_t)sz / ONE_MEG);
1023209235Sbrucec		if (!val || (dsize = strtold(val, &cp)) <= 0) {
102418619Sjkh		    clear_wins();
10258702Sjkh		    break;
102618619Sjkh		}
10278549Sjkh
10288751Sjkh		if (*cp) {
10298751Sjkh		    if (toupper(*cp) == 'M')
1030209235Sbrucec			size = (daddr_t) (dsize * ONE_MEG);
103157617Sjkh		    else if (toupper(*cp) == 'G')
1032209235Sbrucec			size = (daddr_t) (dsize * ONE_GIG);
1033121890Smarcel#ifndef __ia64__
10348751Sjkh		    else if (toupper(*cp) == 'C')
1035209235Sbrucec			size = (daddr_t) dsize * (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
1036121890Smarcel#endif
1037209235Sbrucec		    else
1038209235Sbrucec			size = (daddr_t) dsize;
1039210381Sbrucec		} else {
1040210381Sbrucec			size = (daddr_t) dsize;
10418751Sjkh		}
1042210381Sbrucec
1043209235Sbrucec		if (size < FS_MIN_SIZE) {
10448820Sjkh		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
104518619Sjkh		    clear_wins();
10468820Sjkh		    break;
10478820Sjkh		}
1048129259Sgrehan#ifdef __powerpc__
1049129259Sgrehan		}
1050129259Sgrehan#endif
10518702Sjkh		type = get_partition_type();
105218619Sjkh		if (type == PART_NONE) {
105318619Sjkh		    clear_wins();
105418619Sjkh		    beep();
10558669Sphk		    break;
105618619Sjkh		}
10578669Sphk
1058122021Smarcel		if (type == PART_FILESYSTEM || type == PART_EFI) {
1059133106Smarcel		    if ((p = get_mountpoint(type, NULL)) == NULL) {
106018619Sjkh			clear_wins();
106118619Sjkh			beep();
10628702Sjkh			break;
106318619Sjkh		    }
1064122021Smarcel		    else if (!strcmp(p->mountpoint, "/")) {
1065122021Smarcel			if (type != PART_FILESYSTEM) {
1066122021Smarcel			    clear_wins();
1067122021Smarcel			    beep();
1068122021Smarcel			    break;
1069122021Smarcel			}
1070122021Smarcel			else
1071122021Smarcel			    flags |= CHUNK_IS_ROOT;
1072122021Smarcel		    }
10738702Sjkh		    else
10748702Sjkh			flags &= ~CHUNK_IS_ROOT;
107518619Sjkh		}
107618619Sjkh		else
10778702Sjkh		    p = NULL;
10788702Sjkh
107976237Sjkh		if ((flags & CHUNK_IS_ROOT) && (size < (ROOT_MIN_SIZE * ONE_MEG))) {
108076237Sjkh		    msgConfirm("Warning: This is smaller than the recommended size for a\n"
108176237Sjkh			       "root partition.  For a variety of reasons, root\n"
108276237Sjkh			       "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
10838672Sjkh		}
10848751Sjkh		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1085122021Smarcel		    label_chunk_info[here].c, size,
1086122021Smarcel#ifdef __ia64__
1087122021Smarcel		    (type == PART_EFI) ? efi : part,
1088122021Smarcel		    (type == PART_EFI) ? 0 : (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
1089122021Smarcel#else
1090122021Smarcel		    part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
1091122021Smarcel#endif
1092122021Smarcel		    flags);
10938702Sjkh		if (!tmp) {
10948702Sjkh		    msgConfirm("Unable to create the partition. Too big?");
109518619Sjkh		    clear_wins();
10968672Sjkh		    break;
10978672Sjkh		}
109879678Sobrien
1099106826Sjhb		tmp->private_data = p;
11008702Sjkh		tmp->private_free = safe_free;
110174156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
110243685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
110330345Sjkh		record_label_chunks(devs, dev);
110418619Sjkh		clear_wins();
110579678Sobrien                /* This is where we assign focus to new label so it shows. */
110629249Sjkh                {
110729249Sjkh                    int i;
110829249Sjkh		    label_focus = -1;
110929249Sjkh                    for (i = 0; label_chunk_info[i].c; ++i) {
111029249Sjkh                    	if (label_chunk_info[i].c == tmp) {
111129249Sjkh			    label_focus = i;
111229249Sjkh			    break;
111329249Sjkh			}
111429249Sjkh		    }
111529249Sjkh		    if (label_focus == -1)
111629249Sjkh                    	label_focus = i - 1;
111729249Sjkh                }
11188549Sjkh	    }
11198549Sjkh	    break;
11208549Sjkh
112117397Sjkh	case KEY_DC:
112288996Sdillon	case 'R':	/* recover space (delete w/ recover) */
112388996Sdillon	    /*
112488996Sdillon	     * Delete the partition w/ space recovery.
112588996Sdillon	     */
112688996Sdillon	    rflags = DELCHUNK_RECOVER;
112788996Sdillon	    /* fall through */
11288549Sjkh	case 'D':	/* delete */
11298549Sjkh	    if (label_chunk_info[here].type == PART_SLICE) {
11308549Sjkh		msg = MSG_NOT_APPLICABLE;
11318549Sjkh		break;
11328549Sjkh	    }
11338549Sjkh	    else if (label_chunk_info[here].type == PART_FAT) {
11348705Sjkh		msg = "Use the Disk Partition Editor to delete DOS partitions";
11358549Sjkh		break;
11368549Sjkh	    }
113788996Sdillon	    Delete_Chunk2(label_chunk_info[here].c->disk, label_chunk_info[here].c, rflags);
113874156Sjkh	    if (variable_cmp(DISK_LABELLED, "written"))
113943685Sjkh		variable_set2(DISK_LABELLED, "yes", 0);
114030345Sjkh	    record_label_chunks(devs, dev);
11418549Sjkh	    break;
11428549Sjkh
11438549Sjkh	case 'M':	/* mount */
11448549Sjkh	    switch(label_chunk_info[here].type) {
11458549Sjkh	    case PART_SLICE:
11468549Sjkh		msg = MSG_NOT_APPLICABLE;
11478549Sjkh		break;
11488549Sjkh
11498549Sjkh	    case PART_SWAP:
11508549Sjkh		msg = "You don't need to specify a mountpoint for a swap partition.";
11518549Sjkh		break;
11528549Sjkh
11538556Sjkh	    case PART_FAT:
1154121890Smarcel	    case PART_EFI:
11558549Sjkh	    case PART_FILESYSTEM:
115614793Sjoerg		oldp = label_chunk_info[here].c->private_data;
1157133106Smarcel		p = get_mountpoint(label_chunk_info[here].type, label_chunk_info[here].c);
11588549Sjkh		if (p) {
11599202Srgrimes		    if (!oldp)
1160107565Srwatson		    	p->do_newfs = FALSE;
1161121890Smarcel		    if ((label_chunk_info[here].type == PART_FAT ||
1162121890Smarcel			    label_chunk_info[here].type == PART_EFI) &&
1163121890Smarcel			(!strcmp(p->mountpoint, "/") ||
1164121890Smarcel			    !strcmp(p->mountpoint, "/usr") ||
1165121890Smarcel			    !strcmp(p->mountpoint, "/var"))) {
11668722Sjkh			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
11678722Sjkh			strcpy(p->mountpoint, "/bogus");
11688722Sjkh		    }
11698549Sjkh		}
117074156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
117143685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
117230345Sjkh		record_label_chunks(devs, dev);
117318636Sjkh		clear_wins();
11748549Sjkh		break;
11758549Sjkh
11768549Sjkh	    default:
11778549Sjkh		msgFatal("Bogus partition under cursor???");
11788549Sjkh		break;
11798549Sjkh	    }
11808549Sjkh	    break;
11818549Sjkh
11828549Sjkh	case 'N':	/* Set newfs options */
118314793Sjoerg	    if (label_chunk_info[here].c->private_data &&
1184107565Srwatson		((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs)
1185107565Srwatson		getNewfsOptionalArguments(
1186107565Srwatson		    label_chunk_info[here].c->private_data);
11878549Sjkh	    else
11888549Sjkh		msg = MSG_NOT_APPLICABLE;
118918636Sjkh	    clear_wins();
11908549Sjkh	    break;
11918549Sjkh
119274086Sjkh	case 'S':	/* Toggle soft updates flag */
119374086Sjkh	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
119474086Sjkh		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1195107565Srwatson		if (pi != NULL &&
1196107565Srwatson		    pi->newfs_type == NEWFS_UFS)
1197107565Srwatson			pi->newfs_data.newfs_ufs.softupdates =
1198107565Srwatson			    !pi->newfs_data.newfs_ufs.softupdates;
119974086Sjkh		else
120074086Sjkh		    msg = MSG_NOT_APPLICABLE;
120174086Sjkh	    }
120274156Sjkh	    else
120374156Sjkh		msg = MSG_NOT_APPLICABLE;
120474086Sjkh	    break;
120574086Sjkh
12068549Sjkh	case 'T':	/* Toggle newfs state */
1207133106Smarcel	    if ((label_chunk_info[here].type == PART_FILESYSTEM ||
1208133106Smarcel		 label_chunk_info[here].type == PART_EFI) &&
120989968Smurray	        (label_chunk_info[here].c->private_data)) {
121023729Sjkh		PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
1211107565Srwatson		if (!pi->do_newfs)
121287581Sdillon		    label_chunk_info[here].c->flags |= CHUNK_NEWFS;
121387581Sdillon		else
121487581Sdillon		    label_chunk_info[here].c->flags &= ~CHUNK_NEWFS;
121587581Sdillon
121623729Sjkh		label_chunk_info[here].c->private_data =
1217133106Smarcel		    new_part(label_chunk_info[here].type, pi ? pi->mountpoint : NULL, pi ? !pi->do_newfs
1218107565Srwatson		    : TRUE);
1219107565Srwatson		if (pi != NULL &&
1220107565Srwatson		    pi->newfs_type == NEWFS_UFS) {
1221107565Srwatson		    PartInfo *pi_new = label_chunk_info[here].c->private_data;
1222107565Srwatson
1223107565Srwatson		    pi_new->newfs_data.newfs_ufs = pi->newfs_data.newfs_ufs;
1224107565Srwatson		}
122523729Sjkh		safe_free(pi);
122623729Sjkh		label_chunk_info[here].c->private_free = safe_free;
122774156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
122843685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
122918619Sjkh	    }
12308549Sjkh	    else
12318549Sjkh		msg = MSG_NOT_APPLICABLE;
12328549Sjkh	    break;
12338549Sjkh
12348820Sjkh	case 'U':
123512661Speter	    clear();
123674156Sjkh	    if (!variable_cmp(DISK_LABELLED, "written")) {
123718744Sjkh		msgConfirm("You've already written out your changes -\n"
123818744Sjkh			   "it's too late to undo!");
123918744Sjkh	    }
124070005Sjkh	    else if (!msgNoYes("Are you SURE you want to Undo everything?")) {
124118744Sjkh		variable_unset(DISK_PARTITIONED);
124218744Sjkh		variable_unset(DISK_LABELLED);
124318744Sjkh		for (i = 0; devs[i]; i++) {
124418744Sjkh		    Disk *d;
124512661Speter
124618744Sjkh		    if (!devs[i]->enabled)
124718744Sjkh			continue;
124818744Sjkh		    else if ((d = Open_Disk(devs[i]->name)) != NULL) {
124918744Sjkh			Free_Disk(devs[i]->private);
125018744Sjkh			devs[i]->private = d;
1251107341Sjhb#ifdef WITH_SLICES
125230345Sjkh			diskPartition(devs[i]);
1253107341Sjhb#endif
125418744Sjkh		    }
12558824Sjkh		}
125630345Sjkh		record_label_chunks(devs, dev);
12578824Sjkh	    }
125818636Sjkh	    clear_wins();
12598824Sjkh	    break;
12608820Sjkh
12618549Sjkh	case 'W':
126274156Sjkh	    if (!variable_cmp(DISK_LABELLED, "written")) {
126318744Sjkh		msgConfirm("You've already written out your changes - if you\n"
126474156Sjkh			   "wish to overwrite them, you'll have to restart\n"
1265178946Sobrien			   "%s first.", ProgName);
126618744Sjkh	    }
126770005Sjkh	    else if (!msgNoYes("WARNING:  This should only be used when modifying an EXISTING\n"
126818687Sjkh			  "installation.  If you are installing FreeBSD for the first time\n"
126918687Sjkh			  "then you should simply type Q when you're finished here and your\n"
127018687Sjkh			  "changes will be committed in one batch automatically at the end of\n"
127118687Sjkh			  "these questions.\n\n"
127218687Sjkh			  "Are you absolutely sure you want to do this now?")) {
127343685Sjkh		variable_set2(DISK_LABELLED, "yes", 0);
127412661Speter		diskLabelCommit(NULL);
127512661Speter	    }
127618636Sjkh	    clear_wins();
127710882Speter	    break;
127810882Speter
1279107565Srwatson	case 'Z':	/* Set newfs command line */
1280107565Srwatson	    if (label_chunk_info[here].c->private_data &&
1281107565Srwatson		((PartInfo *)label_chunk_info[here].c->private_data)->do_newfs)
1282107565Srwatson		getNewfsCmd(label_chunk_info[here].c->private_data);
1283107565Srwatson	    else
1284107565Srwatson		msg = MSG_NOT_APPLICABLE;
1285107565Srwatson	    clear_wins();
1286107565Srwatson	    break;
1287107565Srwatson
1288121864Smarcel#ifndef __ia64__
128910882Speter	case '|':
1290195863Strasz	    if (!msgNoYes("Are you sure you want to go into Expert mode?\n\n"
129112661Speter			  "This is an entirely undocumented feature which you are not\n"
129212661Speter			  "expected to understand!")) {
12938549Sjkh		int i;
12948549Sjkh		Device **devs;
12958549Sjkh
12968549Sjkh		dialog_clear();
12978549Sjkh		end_dialog();
12988549Sjkh		DialogActive = FALSE;
12998549Sjkh		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
13008549Sjkh		if (!devs) {
130112661Speter		    msgConfirm("Can't find any disk devices!");
13028549Sjkh		    break;
13038549Sjkh		}
13048668Sphk		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
13058613Sjkh		    if (devs[i]->enabled)
13068613Sjkh		    	slice_wizard(((Disk *)devs[i]->private));
13078613Sjkh		}
130874156Sjkh		if (variable_cmp(DISK_LABELLED, "written"))
130943685Sjkh		    variable_set2(DISK_LABELLED, "yes", 0);
13108665Sphk		DialogActive = TRUE;
131130345Sjkh		record_label_chunks(devs, dev);
131218636Sjkh		clear_wins();
13138549Sjkh	    }
13148549Sjkh	    else
13158549Sjkh		msg = "A most prudent choice!";
13168549Sjkh	    break;
1317121864Smarcel#endif
13188549Sjkh
131921698Sjkh	case '\033':	/* ESC */
13209202Srgrimes	case 'Q':
13218549Sjkh	    labeling = FALSE;
13228549Sjkh	    break;
13238549Sjkh
13248549Sjkh	default:
13258549Sjkh	    beep();
132617362Sjkh	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
132717362Sjkh	    msg = _msg;
13288549Sjkh	    break;
13298549Sjkh	}
133029633Sjkh        if (label_chunk_info[here].type == PART_SLICE)
133129633Sjkh            pslice_focus = here;
133229633Sjkh        else
133329633Sjkh            label_focus = here;
13348549Sjkh    }
133554587Sjkh    restorescr(w);
133654587Sjkh    return DITEM_SUCCESS;
13378549Sjkh}
133826456Sjkh
1339127081Sjhbstatic __inline daddr_t
1340127081Sjhbrequested_part_size(char *varName, daddr_t nom, int def, int perc)
134187557Sdillon{
134287557Sdillon    char *cp;
1343127081Sjhb    daddr_t sz;
134487557Sdillon
134598018Sjhb    if ((cp = variable_get(varName)) != NULL)
1346127081Sjhb	sz = strtoimax(cp, NULL, 0);
134787557Sdillon    else
134887557Sdillon	sz = nom + (def - nom) * perc / 100;
134987557Sdillon    return(sz * ONE_MEG);
135087557Sdillon}
135187557Sdillon
135287557Sdillon/*
135387557Sdillon * Attempt to auto-label the disk.  'perc' (0-100) scales
135487557Sdillon * the size of the various partitions within appropriate
135587557Sdillon * bounds (NOMINAL through DEFAULT sizes).  The procedure
135687557Sdillon * succeeds of NULL is returned.  A non-null return message
135787557Sdillon * is either a failure-status message (*req == 0), or
135887557Sdillon * a confirmation requestor (*req == 1).  *req is 0 on
135987557Sdillon * entry to this call.
136087557Sdillon *
1361149136Scperciva * As a special exception to the usual sizing rules, /var is given
1362149136Scperciva * additional space equal to the amount of physical memory present
1363149136Scperciva * if perc == 100 in order to ensure that users with large hard drives
1364149136Scperciva * will have enough space to store a crashdump in /var/crash.
1365149136Scperciva *
136687583Sdillon * We autolabel the following partitions:  /, swap, /var, /tmp, /usr,
136787557Sdillon * and /home.  /home receives any extra left over disk space.
136887557Sdillon */
136987557Sdillonstatic char *
137087557Sdillontry_auto_label(Device **devs, Device *dev, int perc, int *req)
137187557Sdillon{
1372127081Sjhb    daddr_t sz;
1373133241Smarcel    Chunk *AutoHome, *AutoRoot, *AutoSwap;
1374133241Smarcel    Chunk *AutoTmp, *AutoUsr, *AutoVar;
1375133246Smarcel#ifdef __ia64__
1376133246Smarcel    Chunk *AutoEfi;
1377133246Smarcel#endif
137887557Sdillon    int mib[2];
1379106348Stmm    unsigned long physmem;
138087557Sdillon    size_t size;
138187557Sdillon    char *msg = NULL;
138287557Sdillon
138387557Sdillon    sz = space_free(label_chunk_info[here].c);
138487557Sdillon    if (sz <= FS_MIN_SIZE)
138587557Sdillon	return("Not enough free space to create a new partition in the slice");
138687557Sdillon
1387133241Smarcel    (void)checkLabels(FALSE);
1388133241Smarcel    AutoHome = AutoRoot = AutoSwap = NULL;
1389133241Smarcel    AutoTmp = AutoUsr = AutoVar = NULL;
1390133246Smarcel
1391133246Smarcel#ifdef __ia64__
1392133246Smarcel    AutoEfi = NULL;
1393133246Smarcel    if (EfiChunk == NULL) {
1394194953Sjhb	sz = 400 * ONE_MEG;
1395133246Smarcel	AutoEfi = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
1396133246Smarcel	    label_chunk_info[here].c, sz, efi, 0, 0);
1397133246Smarcel	if (AutoEfi == NULL) {
1398133246Smarcel	    *req = 1;
1399133246Smarcel	    msg = "Unable to create the EFI system partition. Too big?";
1400133246Smarcel	    goto done;
1401133246Smarcel	}
1402133246Smarcel	AutoEfi->private_data = new_part(PART_EFI, "/efi", TRUE);
1403133246Smarcel	AutoEfi->private_free = safe_free;
1404133246Smarcel	AutoEfi->flags |= CHUNK_NEWFS;
1405133246Smarcel	record_label_chunks(devs, dev);
1406133246Smarcel    }
1407133246Smarcel#endif
1408133246Smarcel
1409133241Smarcel    if (RootChunk == NULL) {
141087557Sdillon	sz = requested_part_size(VAR_ROOT_SIZE, ROOT_NOMINAL_SIZE, ROOT_DEFAULT_SIZE, perc);
141187557Sdillon
1412133241Smarcel	AutoRoot = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
141387581Sdillon			    label_chunk_info[here].c, sz, part,
141487581Sdillon			    FS_BSDFFS,  CHUNK_IS_ROOT | CHUNK_AUTO_SIZE);
1415133241Smarcel	if (!AutoRoot) {
141687557Sdillon	    *req = 1;
141787557Sdillon	    msg = "Unable to create the root partition. Too big?";
141887557Sdillon	    goto done;
141987557Sdillon	}
1420133241Smarcel	AutoRoot->private_data = new_part(PART_FILESYSTEM, "/", TRUE);
1421133241Smarcel	AutoRoot->private_free = safe_free;
1422133241Smarcel	AutoRoot->flags |= CHUNK_NEWFS;
142387557Sdillon	record_label_chunks(devs, dev);
142487557Sdillon    }
1425133241Smarcel    if (SwapChunk == NULL) {
142687557Sdillon	sz = requested_part_size(VAR_SWAP_SIZE, 0, 0, perc);
142787557Sdillon	if (sz == 0) {
1428127081Sjhb	    daddr_t nom;
1429127081Sjhb	    daddr_t def;
143087557Sdillon
143187557Sdillon	    mib[0] = CTL_HW;
143287557Sdillon	    mib[1] = HW_PHYSMEM;
143387557Sdillon	    size = sizeof physmem;
143487557Sdillon	    sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
143587557Sdillon	    def = 2 * (int)(physmem / 512);
143687557Sdillon	    if (def < SWAP_MIN_SIZE * ONE_MEG)
143787557Sdillon		def = SWAP_MIN_SIZE * ONE_MEG;
143887557Sdillon	    if (def > SWAP_AUTO_LIMIT_SIZE * ONE_MEG)
143987557Sdillon		def = SWAP_AUTO_LIMIT_SIZE * ONE_MEG;
1440109827Sdillon	    nom = (int)(physmem / 512) / 8;
144187557Sdillon	    sz = nom + (def - nom) * perc / 100;
144287557Sdillon	}
1443133241Smarcel	AutoSwap = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
144487581Sdillon			    label_chunk_info[here].c, sz, part,
144587581Sdillon			    FS_SWAP, CHUNK_AUTO_SIZE);
1446133241Smarcel	if (!AutoSwap) {
144787557Sdillon	    *req = 1;
144887557Sdillon	    msg = "Unable to create the swap partition. Too big?";
144987557Sdillon	    goto done;
145087557Sdillon	}
1451133241Smarcel	AutoSwap->private_data = 0;
1452133241Smarcel	AutoSwap->private_free = safe_free;
145387557Sdillon	record_label_chunks(devs, dev);
145487557Sdillon    }
1455133241Smarcel    if (VarChunk == NULL) {
1456149136Scperciva	/* Work out how much extra space we want for a crash dump */
1457149136Scperciva	unsigned long crashdumpsz;
145887557Sdillon
1459149136Scperciva	mib[0] = CTL_HW;
1460149136Scperciva	mib[1] = HW_PHYSMEM;
1461149136Scperciva	size = sizeof(physmem);
1462149136Scperciva	sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
1463149136Scperciva
1464149136Scperciva	if (perc == 100)
1465149136Scperciva		crashdumpsz = physmem / 1048576;
1466149136Scperciva	else
1467149136Scperciva		crashdumpsz = 0;
1468149136Scperciva
1469149136Scperciva	sz = requested_part_size(VAR_VAR_SIZE, VAR_NOMINAL_SIZE,	\
1470149136Scperciva	    VAR_DEFAULT_SIZE + crashdumpsz, perc);
1471149136Scperciva
1472133241Smarcel	AutoVar = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
147387581Sdillon				label_chunk_info[here].c, sz, part,
147487581Sdillon				FS_BSDFFS, CHUNK_AUTO_SIZE);
1475133241Smarcel	if (!AutoVar) {
147687557Sdillon	    *req = 1;
147787557Sdillon	    msg = "Not enough free space for /var - you will need to\n"
147887557Sdillon		   "partition your disk manually with a custom install!";
147987557Sdillon	    goto done;
148087557Sdillon	}
1481133241Smarcel	AutoVar->private_data = new_part(PART_FILESYSTEM, "/var", TRUE);
1482133241Smarcel	AutoVar->private_free = safe_free;
1483133241Smarcel	AutoVar->flags |= CHUNK_NEWFS;
148487557Sdillon	record_label_chunks(devs, dev);
148587557Sdillon    }
1486133241Smarcel    if (TmpChunk == NULL && !variable_get(VAR_NO_TMP)) {
148787583Sdillon	sz = requested_part_size(VAR_TMP_SIZE, TMP_NOMINAL_SIZE, TMP_DEFAULT_SIZE, perc);
148887557Sdillon
1489133241Smarcel	AutoTmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
149087581Sdillon				label_chunk_info[here].c, sz, part,
149187581Sdillon				FS_BSDFFS, CHUNK_AUTO_SIZE);
1492133241Smarcel	if (!AutoTmp) {
149387557Sdillon	    *req = 1;
149487583Sdillon	    msg = "Not enough free space for /tmp - you will need to\n"
149587557Sdillon		   "partition your disk manually with a custom install!";
149687557Sdillon	    goto done;
149787557Sdillon	}
1498133241Smarcel	AutoTmp->private_data = new_part(PART_FILESYSTEM, "/tmp", TRUE);
1499133241Smarcel	AutoTmp->private_free = safe_free;
1500133241Smarcel	AutoTmp->flags |= CHUNK_NEWFS;
150187557Sdillon	record_label_chunks(devs, dev);
150287557Sdillon    }
1503133241Smarcel    if (UsrChunk == NULL && !variable_get(VAR_NO_USR)) {
150487557Sdillon	sz = requested_part_size(VAR_USR_SIZE, USR_NOMINAL_SIZE, USR_DEFAULT_SIZE, perc);
150588996Sdillon#if AUTO_HOME == 0
1506157107Scperciva	if (sz < space_free(label_chunk_info[here].c))
150787557Sdillon	    sz = space_free(label_chunk_info[here].c);
150887557Sdillon#endif
150987557Sdillon	if (sz) {
151087557Sdillon	    if (sz < (USR_MIN_SIZE * ONE_MEG)) {
151187557Sdillon		*req = 1;
151287557Sdillon		msg = "Not enough free space for /usr - you will need to\n"
151387557Sdillon		       "partition your disk manually with a custom install!";
151487557Sdillon	    }
151587557Sdillon
1516133241Smarcel	    AutoUsr = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
151787581Sdillon				    label_chunk_info[here].c, sz, part,
151887581Sdillon				    FS_BSDFFS, CHUNK_AUTO_SIZE);
1519133241Smarcel	    if (!AutoUsr) {
152087557Sdillon		msg = "Unable to create the /usr partition.  Not enough space?\n"
152187557Sdillon			   "You will need to partition your disk manually with a custom install!";
152287557Sdillon		goto done;
152387557Sdillon	    }
1524133241Smarcel	    AutoUsr->private_data = new_part(PART_FILESYSTEM, "/usr", TRUE);
1525133241Smarcel	    AutoUsr->private_free = safe_free;
1526133241Smarcel	    AutoUsr->flags |= CHUNK_NEWFS;
152787557Sdillon	    record_label_chunks(devs, dev);
152887557Sdillon	}
152987557Sdillon    }
153088996Sdillon#if AUTO_HOME == 1
1531133241Smarcel    if (HomeChunk == NULL && !variable_get(VAR_NO_HOME)) {
153287557Sdillon	sz = requested_part_size(VAR_HOME_SIZE, HOME_NOMINAL_SIZE, HOME_DEFAULT_SIZE, perc);
153387557Sdillon	if (sz < space_free(label_chunk_info[here].c))
153487557Sdillon	    sz = space_free(label_chunk_info[here].c);
153587557Sdillon	if (sz) {
153687557Sdillon	    if (sz < (HOME_MIN_SIZE * ONE_MEG)) {
153787557Sdillon		*req = 1;
153887557Sdillon		msg = "Not enough free space for /home - you will need to\n"
153987557Sdillon		       "partition your disk manually with a custom install!";
154087557Sdillon		goto done;
154187557Sdillon	    }
154287557Sdillon
1543133241Smarcel	    AutoHome = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
154487581Sdillon				    label_chunk_info[here].c, sz, part,
154587581Sdillon				    FS_BSDFFS, CHUNK_AUTO_SIZE);
1546133241Smarcel	    if (!AutoHome) {
154787557Sdillon		msg = "Unable to create the /home partition.  Not enough space?\n"
154887557Sdillon			   "You will need to partition your disk manually with a custom install!";
154987557Sdillon		goto done;
155087557Sdillon	    }
1551133241Smarcel	    AutoHome->private_data = new_part(PART_FILESYSTEM, "/home", TRUE);
1552133241Smarcel	    AutoHome->private_free = safe_free;
1553133241Smarcel	    AutoHome->flags |= CHUNK_NEWFS;
155487557Sdillon	    record_label_chunks(devs, dev);
155587557Sdillon	}
155687557Sdillon    }
155788996Sdillon#endif
155887557Sdillon
155987557Sdillon    /* At this point, we're reasonably "labelled" */
156087557Sdillon    if (variable_cmp(DISK_LABELLED, "written"))
156187557Sdillon	variable_set2(DISK_LABELLED, "yes", 0);
156287557Sdillon
156387557Sdillondone:
156487557Sdillon    if (msg) {
1565133241Smarcel	if (AutoRoot != NULL)
1566133241Smarcel	    Delete_Chunk(AutoRoot->disk, AutoRoot);
1567133241Smarcel	if (AutoSwap != NULL)
1568133241Smarcel	    Delete_Chunk(AutoSwap->disk, AutoSwap);
1569133241Smarcel	if (AutoVar != NULL)
1570133241Smarcel	    Delete_Chunk(AutoVar->disk, AutoVar);
1571133241Smarcel	if (AutoTmp != NULL)
1572133241Smarcel	    Delete_Chunk(AutoTmp->disk, AutoTmp);
1573133241Smarcel	if (AutoUsr != NULL)
1574133241Smarcel	    Delete_Chunk(AutoUsr->disk, AutoUsr);
1575133241Smarcel	if (AutoHome != NULL)
1576133241Smarcel	    Delete_Chunk(AutoHome->disk, AutoHome);
157787557Sdillon	record_label_chunks(devs, dev);
157887557Sdillon    }
157987557Sdillon    return(msg);
158087557Sdillon}
158187557Sdillon
158226456Sjkhstatic int
158330345SjkhdiskLabelNonInteractive(Device *dev)
158426456Sjkh{
158526456Sjkh    char *cp;
158626456Sjkh    PartType type;
158726456Sjkh    PartInfo *p;
1588106830Sjhb    u_long flags;
158926456Sjkh    int i, status;
159026456Sjkh    Device **devs;
159126456Sjkh    Disk *d;
159254587Sjkh
159326456Sjkh    status = DITEM_SUCCESS;
159426456Sjkh    cp = variable_get(VAR_DISK);
159526456Sjkh    if (!cp) {
159626456Sjkh	msgConfirm("diskLabel:  No disk selected - can't label automatically.");
159726456Sjkh	return DITEM_FAILURE;
159826456Sjkh    }
159926456Sjkh    devs = deviceFind(cp, DEVICE_TYPE_DISK);
160026456Sjkh    if (!devs) {
160126456Sjkh	msgConfirm("diskLabel: No disk device %s found!", cp);
160226456Sjkh	return DITEM_FAILURE;
160326456Sjkh    }
160430345Sjkh    if (dev)
160530345Sjkh	d = dev->private;
160630345Sjkh    else
160730345Sjkh	d = devs[0]->private;
160830345Sjkh    record_label_chunks(devs, dev);
160926456Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
161026456Sjkh	Chunk *c1 = label_chunk_info[i].c;
161126456Sjkh
161226456Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
161328075Sjkh	    char name[512];
1614106827Sjhb	    char typ[10], mpoint[50];
1615106827Sjhb	    int entries;
161626456Sjkh
1617106827Sjhb	    for (entries = 1;; entries++) {
1618127081Sjhb		intmax_t sz;
1619127081Sjhb		int soft = 0;
162028075Sjkh		snprintf(name, sizeof name, "%s-%d", c1->name, entries);
1621106827Sjhb		if ((cp = variable_get(name)) == NULL)
1622106827Sjhb		    break;
1623127081Sjhb		if (sscanf(cp, "%s %jd %s %d", typ, &sz, mpoint, &soft) < 3) {
1624106827Sjhb		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s",  c1->name, cp);
1625106827Sjhb		    status = DITEM_FAILURE;
1626106827Sjhb		    break;
1627106827Sjhb		} else {
1628106827Sjhb		    Chunk *tmp;
162926456Sjkh
1630106830Sjhb		    flags = 0;
1631106827Sjhb		    if (!strcmp(typ, "swap")) {
1632106827Sjhb			type = PART_SWAP;
1633106827Sjhb			strcpy(mpoint, "SWAP");
1634106827Sjhb		    } else {
1635106827Sjhb			type = PART_FILESYSTEM;
1636106827Sjhb			if (!strcmp(mpoint, "/"))
1637106827Sjhb			    flags |= CHUNK_IS_ROOT;
1638106827Sjhb		    }
1639106827Sjhb		    if (!sz)
1640106827Sjhb			sz = space_free(c1);
1641106827Sjhb		    if (sz > space_free(c1)) {
1642106827Sjhb			msgConfirm("Not enough free space to create partition: %s", mpoint);
164326456Sjkh			status = DITEM_FAILURE;
1644106827Sjhb			break;
164526456Sjkh		    }
1646106827Sjhb		    if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part,
1647106827Sjhb			(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) {
1648106827Sjhb			msgConfirm("Unable to create from partition spec: %s. Too big?", cp);
1649106827Sjhb			status = DITEM_FAILURE;
1650106827Sjhb			break;
1651106827Sjhb		    } else {
1652107565Srwatson			PartInfo *pi;
1653133106Smarcel			pi = tmp->private_data = new_part(PART_FILESYSTEM, mpoint, TRUE);
1654106827Sjhb			tmp->private_free = safe_free;
1655107565Srwatson			pi->newfs_data.newfs_ufs.softupdates = soft;
1656218841Sbrucec			if (!strcmp(typ, "ufs1"))
1657218841Sbrucec				pi->newfs_data.newfs_ufs.ufs1 = TRUE;
165826456Sjkh		    }
165926456Sjkh		}
166026456Sjkh	    }
1661106827Sjhb	} else {
166228075Sjkh	    /* Must be something we can set a mountpoint for */
166326456Sjkh	    cp = variable_get(c1->name);
166426456Sjkh	    if (cp) {
166528075Sjkh		char mpoint[50], do_newfs[8];
166626456Sjkh		Boolean newfs = FALSE;
166726456Sjkh
166828075Sjkh		do_newfs[0] = '\0';
166928075Sjkh		if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) {
167026456Sjkh		    msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp);
167126456Sjkh		    status = DITEM_FAILURE;
1672106828Sjhb		    break;
167326456Sjkh		}
167428075Sjkh		newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE;
167526456Sjkh		if (c1->private_data) {
167626456Sjkh		    p = c1->private_data;
1677107565Srwatson		    p->do_newfs = newfs;
167826456Sjkh		    strcpy(p->mountpoint, mpoint);
167926456Sjkh		}
168026456Sjkh		else {
1681133106Smarcel		    c1->private_data = new_part(PART_FILESYSTEM, mpoint, newfs);
168226456Sjkh		    c1->private_free = safe_free;
168326456Sjkh		}
168426456Sjkh		if (!strcmp(mpoint, "/"))
168526456Sjkh		    c1->flags |= CHUNK_IS_ROOT;
168626456Sjkh		else
168726456Sjkh		    c1->flags &= ~CHUNK_IS_ROOT;
168826456Sjkh	    }
168926456Sjkh	}
169026456Sjkh    }
169126456Sjkh    if (status == DITEM_SUCCESS)
169243685Sjkh	variable_set2(DISK_LABELLED, "yes", 0);
169326456Sjkh    return status;
169426456Sjkh}
1695