label.c revision 18687
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 *
718687Sjkh * $Id: label.c,v 1.61 1996/10/02 02:19:35 jkh Exp $
88549Sjkh *
98549Sjkh * Copyright (c) 1995
108549Sjkh *	Jordan Hubbard.  All rights reserved.
118549Sjkh *
128549Sjkh * Redistribution and use in source and binary forms, with or without
138549Sjkh * modification, are permitted provided that the following conditions
148549Sjkh * are met:
158549Sjkh * 1. Redistributions of source code must retain the above copyright
168881Srgrimes *    notice, this list of conditions and the following disclaimer,
178881Srgrimes *    verbatim and that no modifications are made prior to this
188549Sjkh *    point in the file.
198549Sjkh * 2. Redistributions in binary form must reproduce the above copyright
208549Sjkh *    notice, this list of conditions and the following disclaimer in the
218549Sjkh *    documentation and/or other materials provided with the distribution.
228549Sjkh *
238549Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
248549Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
258549Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
268549Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
278549Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
288549Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
298549Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
308549Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
318549Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
328549Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
338549Sjkh * SUCH DAMAGE.
348549Sjkh *
358549Sjkh */
368549Sjkh
378549Sjkh#include "sysinstall.h"
388549Sjkh#include <ctype.h>
398549Sjkh#include <sys/disklabel.h>
4010882Speter#include <sys/param.h>
4110882Speter#include <sys/sysctl.h>
428549Sjkh
438549Sjkh/*
448549Sjkh * Everything to do with editing the contents of disk labels.
458549Sjkh */
468549Sjkh
478549Sjkh/* A nice message we use a lot in the disklabel editor */
488549Sjkh#define MSG_NOT_APPLICABLE	"That option is not applicable here"
498549Sjkh
508549Sjkh/* Where to start printing the freebsd slices */
518549Sjkh#define CHUNK_SLICE_START_ROW		2
528622Sjkh#define CHUNK_PART_START_ROW		11
538549Sjkh
548549Sjkh/* The smallest filesystem we're willing to create */
558702Sjkh#define FS_MIN_SIZE			ONE_MEG
568549Sjkh
578672Sjkh/* The smallest root filesystem we're willing to create */
5812661Speter#define ROOT_MIN_SIZE			20
598549Sjkh
6012661Speter/* The smallest swap partition we want to create by default */
6112661Speter#define SWAP_MIN_SIZE			16
6212661Speter
6312661Speter/* The smallest /usr partition we're willing to create by default */
6412661Speter#define USR_MIN_SIZE			80
6512661Speter
6612661Speter/* The smallest /var partition we're willing to create by default */
6712661Speter#define VAR_MIN_SIZE			30
6812661Speter
6915440Sjkh/* The bottom-most row we're allowed to scribble on */
7015440Sjkh#define CHUNK_ROW_MAX		16
7115440Sjkh
7215440Sjkh
738549Sjkh/* All the chunks currently displayed on the screen */
748549Sjkhstatic struct {
758549Sjkh    struct chunk *c;
768549Sjkh    PartType type;
778549Sjkh} label_chunk_info[MAX_CHUNKS + 1];
788549Sjkhstatic int here;
798549Sjkh
8015440Sjkhstatic int ChunkPartStartRow;
8115440Sjkhstatic WINDOW *ChunkWin;
8215440Sjkh
8312661Speterstatic int diskLabel(char *str);
8412661Speter
8512661Speterint
8615091SjkhdiskLabelEditor(dialogMenuItem *self)
8712661Speter{
8812661Speter    Device **devs;
8915242Sjkh    int i, cnt, enabled;
9015242Sjkh    char *cp;
9112661Speter
9212661Speter    cp = variable_get(VAR_DISK);
9312661Speter    devs = deviceFind(cp, DEVICE_TYPE_DISK);
9412661Speter    cnt = deviceCount(devs);
9512661Speter    if (!cnt) {
9612661Speter	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
9712661Speter		   "properly probed at boot time.  See the Hardware Guide on the\n"
9812661Speter		   "Documentation menu for clues on diagnosing this type of problem.");
9915242Sjkh	return DITEM_FAILURE;
10012661Speter    }
10115242Sjkh    for (i = 0, enabled = 0; i < cnt; i++) {
10215242Sjkh	if (devs[i]->enabled)
10315242Sjkh	    ++enabled;
10412661Speter    }
10515242Sjkh    if (!enabled) {
10615695Sjkh	msgConfirm("No disks have been selected.  Please visit the Partition\n"
10715695Sjkh		   "editor first to specify which disks you wish to operate on.");
10815695Sjkh	return DITEM_FAILURE;
10912661Speter    }
11015242Sjkh    i = diskLabel(devs[0]->name);
11115419Sjkh    if (DITEM_STATUS(i) != DITEM_FAILURE)
11215242Sjkh	variable_set2(DISK_LABELLED, "yes");
11312661Speter    return i;
11412661Speter}
11512661Speter
11612661Speterint
11715091SjkhdiskLabelCommit(dialogMenuItem *self)
11812661Speter{
11912661Speter    char *cp;
12012661Speter    int i;
12112661Speter
12212661Speter    /* Already done? */
12317025Sjkh    if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
12415242Sjkh	i = DITEM_SUCCESS;
12512661Speter    else if (!cp) {
12612661Speter	msgConfirm("You must assign disk labels before this option can be used.");
12715242Sjkh	i = DITEM_FAILURE;
12812661Speter    }
12912661Speter    /* The routine will guard against redundant writes, just as this one does */
13015419Sjkh    else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
13115242Sjkh	i = DITEM_FAILURE;
13215419Sjkh    else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
13315242Sjkh	i = DITEM_FAILURE;
13412661Speter    else {
13512661Speter	msgInfo("All filesystem information written successfully.");
13612661Speter	variable_set2(DISK_LABELLED, "written");
13715242Sjkh	i = DITEM_SUCCESS;
13812661Speter    }
13912661Speter    return i;
14012661Speter}
14112661Speter
1428549Sjkh/* See if we're already using a desired partition name */
1438549Sjkhstatic Boolean
1448549Sjkhcheck_conflict(char *name)
1458549Sjkh{
1468549Sjkh    int i;
1478549Sjkh
1488751Sjkh    for (i = 0; label_chunk_info[i].c; i++)
14914793Sjoerg	if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private_data
15014793Sjoerg	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
1518549Sjkh	    return TRUE;
1528549Sjkh    return FALSE;
1538549Sjkh}
1548549Sjkh
1558549Sjkh/* How much space is in this FreeBSD slice? */
1568549Sjkhstatic int
1578549Sjkhspace_free(struct chunk *c)
1588549Sjkh{
15912661Speter    struct chunk *c1;
1608549Sjkh    int sz = c->size;
1618549Sjkh
16212661Speter    for (c1 = c->part; c1; c1 = c1->next) {
1638549Sjkh	if (c1->type != unused)
1648549Sjkh	    sz -= c1->size;
1658549Sjkh    }
1668549Sjkh    if (sz < 0)
1678549Sjkh	msgFatal("Partitions are larger than actual chunk??");
1688549Sjkh    return sz;
1698549Sjkh}
1708549Sjkh
1718549Sjkh/* Snapshot the current situation into the displayed chunks structure */
1728549Sjkhstatic void
17312661Speterrecord_label_chunks(Device **devs)
1748549Sjkh{
1758549Sjkh    int i, j, p;
1768549Sjkh    struct chunk *c1, *c2;
1778556Sjkh    Disk *d;
1788549Sjkh
17915440Sjkh    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3;
1808549Sjkh    j = p = 0;
1818556Sjkh    /* First buzz through and pick up the FreeBSD slices */
1828549Sjkh    for (i = 0; devs[i]; i++) {
1838556Sjkh	if (!devs[i]->enabled)
1848556Sjkh	    continue;
1858556Sjkh	d = (Disk *)devs[i]->private;
1868556Sjkh	if (!d->chunks)
1878556Sjkh	    msgFatal("No chunk list found for %s!", d->name);
1888549Sjkh
1898556Sjkh	/* Put the slice entries first */
1908556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
1918549Sjkh	    if (c1->type == freebsd) {
1928549Sjkh		label_chunk_info[j].type = PART_SLICE;
1938549Sjkh		label_chunk_info[j].c = c1;
1948549Sjkh		++j;
19515440Sjkh		++ChunkPartStartRow;
1968549Sjkh	    }
1978549Sjkh	}
1988549Sjkh    }
19912661Speter
2008556Sjkh    /* Now run through again and get the FreeBSD partition entries */
2018556Sjkh    for (i = 0; devs[i]; i++) {
2028556Sjkh	if (!devs[i]->enabled)
2038556Sjkh	    continue;
2048556Sjkh	d = (Disk *)devs[i]->private;
2058549Sjkh	/* Then buzz through and pick up the partitions */
2068556Sjkh	for (c1 = d->chunks->part; c1; c1 = c1->next) {
2078549Sjkh	    if (c1->type == freebsd) {
2088549Sjkh		for (c2 = c1->part; c2; c2 = c2->next) {
2098549Sjkh		    if (c2->type == part) {
2108549Sjkh			if (c2->subtype == FS_SWAP)
2118549Sjkh			    label_chunk_info[j].type = PART_SWAP;
2128549Sjkh			else
2138549Sjkh			    label_chunk_info[j].type = PART_FILESYSTEM;
2148549Sjkh			label_chunk_info[j].c = c2;
2158549Sjkh			++j;
2168549Sjkh		    }
2178549Sjkh		}
2188549Sjkh	    }
2198549Sjkh	    else if (c1->type == fat) {
2208549Sjkh		label_chunk_info[j].type = PART_FAT;
2218549Sjkh		label_chunk_info[j].c = c1;
2228702Sjkh		++j;
2238549Sjkh	    }
2248549Sjkh	}
2258549Sjkh    }
2268549Sjkh    label_chunk_info[j].c = NULL;
2278549Sjkh    if (here >= j)
2288549Sjkh	here = j  ? j - 1 : 0;
22915442Sjkh    if (ChunkWin) {
23015440Sjkh	wclear(ChunkWin);
23115442Sjkh	wrefresh(ChunkWin);
23215442Sjkh    }
23315440Sjkh    else
23415440Sjkh	ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
2358549Sjkh}
2368549Sjkh
2378549Sjkh/* A new partition entry */
2388549Sjkhstatic PartInfo *
2398665Sphknew_part(char *mpoint, Boolean newfs, u_long size)
2408549Sjkh{
2418549Sjkh    PartInfo *ret;
2428549Sjkh
2439202Srgrimes    if (!mpoint)
2449202Srgrimes	mpoint = "/change_me";
2459202Srgrimes
2468549Sjkh    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
2478549Sjkh    strncpy(ret->mountpoint, mpoint, FILENAME_MAX);
24814335Sjkh    strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024");
2498666Sphk    ret->newfs = newfs;
2508669Sphk    if (!size)
2518669Sphk	    return ret;
2528549Sjkh    return ret;
2538549Sjkh}
2548549Sjkh
2558549Sjkh/* Get the mountpoint for a partition and save it away */
25612661Speterstatic PartInfo *
2578589Sjkhget_mountpoint(struct chunk *old)
2588549Sjkh{
2598549Sjkh    char *val;
2608549Sjkh    PartInfo *tmp;
2618549Sjkh
26214793Sjoerg    if (old && old->private_data)
26314793Sjoerg	tmp = old->private_data;
2648810Sjkh    else
2658810Sjkh	tmp = NULL;
26618619Sjkh    if (!old) {
26718621Sjkh	DialogX = 14;
26818621Sjkh	DialogY = 16;
26918619Sjkh    }
2708810Sjkh    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
27118619Sjkh    DialogX = DialogY = 0;
2728764Sjkh    if (!val || !*val) {
2738751Sjkh	if (!old)
2748751Sjkh	    return NULL;
2758751Sjkh	else {
27614793Sjoerg	    free(old->private_data);
27714793Sjoerg	    old->private_data = NULL;
2788751Sjkh	}
2798669Sphk	return NULL;
2808751Sjkh    }
2818669Sphk
2828669Sphk    /* Is it just the same value? */
2838810Sjkh    if (tmp && !strcmp(tmp->mountpoint, val))
2848669Sphk	return NULL;
2858810Sjkh
2868810Sjkh    /* Did we use it already? */
2878669Sphk    if (check_conflict(val)) {
2888669Sphk	msgConfirm("You already have a mount point for %s assigned!", val);
2898669Sphk	return NULL;
2908549Sjkh    }
2918810Sjkh
2928810Sjkh    /* Is it bogus? */
2938669Sphk    if (*val != '/') {
2948669Sphk	msgConfirm("Mount point must start with a / character");
2958669Sphk	return NULL;
2968669Sphk    }
2978810Sjkh
2988810Sjkh    /* Is it going to be mounted on root? */
2998669Sphk    if (!strcmp(val, "/")) {
3008669Sphk	if (old)
3018669Sphk	    old->flags |= CHUNK_IS_ROOT;
3028810Sjkh    }
3038810Sjkh    else if (old)
3048669Sphk	old->flags &= ~CHUNK_IS_ROOT;
3058810Sjkh
3068810Sjkh    safe_free(tmp);
3078669Sphk    tmp = new_part(val, TRUE, 0);
3088669Sphk    if (old) {
30914793Sjoerg	old->private_data = tmp;
3108669Sphk	old->private_free = safe_free;
3118669Sphk    }
3128669Sphk    return tmp;
3138549Sjkh}
3148549Sjkh
3158549Sjkh/* Get the type of the new partiton */
3168549Sjkhstatic PartType
3178549Sjkhget_partition_type(void)
3188549Sjkh{
3198549Sjkh    char selection[20];
3208669Sphk    int i;
3218669Sphk
3228549Sjkh    static unsigned char *fs_types[] = {
3238549Sjkh	"FS",
3248549Sjkh	"A file system",
3258549Sjkh	"Swap",
3268549Sjkh	"A swap partition.",
3278549Sjkh    };
32818619Sjkh    DialogX = 7;
32918621Sjkh    DialogY = 8;
3308669Sphk    i = dialog_menu("Please choose a partition type",
33112661Speter		    "If you want to use this partition for swap space, select Swap.\n"
33212661Speter		    "If you want to put a filesystem on it, choose FS.",
33312661Speter		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
33418619Sjkh    DialogX = DialogY = 0;
3358669Sphk    if (!i) {
3368549Sjkh	if (!strcmp(selection, "FS"))
3378549Sjkh	    return PART_FILESYSTEM;
3388549Sjkh	else if (!strcmp(selection, "Swap"))
3398549Sjkh	    return PART_SWAP;
3408549Sjkh    }
3418549Sjkh    return PART_NONE;
3428549Sjkh}
3438549Sjkh
3448549Sjkh/* If the user wants a special newfs command for this, set it */
3458549Sjkhstatic void
3468549SjkhgetNewfsCmd(PartInfo *p)
3478549Sjkh{
3488549Sjkh    char *val;
3498549Sjkh
3508549Sjkh    val = msgGetInput(p->newfs_cmd,
35112661Speter		      "Please enter the newfs command and options you'd like to use in\n"
35212661Speter		      "creating this file system.");
3538549Sjkh    if (val)
3548549Sjkh	strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
3558549Sjkh}
3568549Sjkh
3578549Sjkh#define MAX_MOUNT_NAME	12
3588549Sjkh
3598549Sjkh#define PART_PART_COL	0
3608549Sjkh#define PART_MOUNT_COL	8
3618549Sjkh#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
3628549Sjkh#define PART_NEWFS_COL	(PART_SIZE_COL + 7)
3638549Sjkh#define PART_OFF	38
3648549Sjkh
3658549Sjkh/* stick this all up on the screen */
3668549Sjkhstatic void
3678549Sjkhprint_label_chunks(void)
3688549Sjkh{
3698549Sjkh    int i, j, srow, prow, pcol;
3708549Sjkh    int sz;
3718549Sjkh
3728549Sjkh    attrset(A_REVERSE);
3738549Sjkh    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
3748549Sjkh    attrset(A_NORMAL);
3758549Sjkh
3768549Sjkh    for (i = 0; i < 2; i++) {
37715440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
37815440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
3798549Sjkh
38015440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
38115440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
3828549Sjkh
38315440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
38415440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
3858549Sjkh
38615440Sjkh	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
38715440Sjkh	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
3888549Sjkh    }
3898549Sjkh    srow = CHUNK_SLICE_START_ROW;
39015440Sjkh    prow = 0;
3918549Sjkh    pcol = 0;
3928549Sjkh
3938751Sjkh    for (i = 0; label_chunk_info[i].c; i++) {
3948549Sjkh	/* Is it a slice entry displayed at the top? */
3958549Sjkh	if (label_chunk_info[i].type == PART_SLICE) {
3968549Sjkh	    sz = space_free(label_chunk_info[i].c);
39715440Sjkh	    if (i == here)
39816208Sjkh		attrset(ATTR_SELECTED);
3998751Sjkh	    mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
4008751Sjkh		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG));
40115440Sjkh	    attrset(A_NORMAL);
40215440Sjkh	    clrtoeol();
40315440Sjkh	    move(0, 0);
40415440Sjkh	    refresh();
4058549Sjkh	}
40615440Sjkh	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
4078549Sjkh	else {
4088549Sjkh	    char onestr[PART_OFF], num[10], *mountpoint, *newfs;
4098549Sjkh
4108549Sjkh	    /*
4118549Sjkh	     * We copy this into a blank-padded string so that it looks like
4128549Sjkh	     * a solid bar in reverse-video
4138549Sjkh	     */
4148549Sjkh	    memset(onestr, ' ', PART_OFF - 1);
4158549Sjkh	    onestr[PART_OFF - 1] = '\0';
41615440Sjkh	    /* Go for two columns if we've written one full columns worth */
41715440Sjkh	    if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) {
4188549Sjkh		pcol = PART_OFF;
41915440Sjkh		prow = 0;
4208549Sjkh	    }
4218705Sjkh	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
4228549Sjkh	    /* If it's a filesystem, display the mountpoint */
42314793Sjoerg	    if (label_chunk_info[i].c->private_data
42410882Speter		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
42514793Sjoerg	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
42610882Speter	    else
42710882Speter	        mountpoint = "<none>";
42810882Speter
42910882Speter	    /* Now display the newfs field */
43010882Speter	    if (label_chunk_info[i].type == PART_FAT)
43110882Speter	        newfs = "DOS";
43214793Sjoerg	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM)
43314793Sjoerg		newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N";
43410882Speter	    else if (label_chunk_info[i].type == PART_SWAP)
43510882Speter		newfs = "SWAP";
43610882Speter	    else
4378549Sjkh		newfs = "*";
4388549Sjkh	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
4398549Sjkh		onestr[PART_MOUNT_COL + j] = mountpoint[j];
4408764Sjkh	    snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
4418549Sjkh	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
4428549Sjkh	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
4438549Sjkh	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
44415440Sjkh	    if (i == here)
44516208Sjkh		wattrset(ChunkWin, ATTR_SELECTED);
44615440Sjkh	    mvwaddstr(ChunkWin, prow, pcol, onestr);
44715440Sjkh	    wattrset(ChunkWin, A_NORMAL);
44815440Sjkh	    wrefresh(ChunkWin);
44915440Sjkh	    move(0, 0);
4508549Sjkh	    ++prow;
4518549Sjkh	}
4528549Sjkh    }
4538549Sjkh}
4548549Sjkh
4558549Sjkhstatic void
45618619Sjkhprint_command_summary(void)
4578549Sjkh{
4588820Sjkh    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
45915440Sjkh    mvprintw(18, 0, "C = Create      D = Delete         M = Mount");
46015440Sjkh    if (!RunningAsInit)
46115695Sjkh	mvprintw(18, 47, "W = Write");
46210882Speter    mvprintw(19, 0, "N = Newfs Opts  T = Newfs Toggle   U = Undo    Q = Finish");
46310882Speter    mvprintw(20, 0, "A = Auto Defaults for all!");
46415695Sjkh    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
4658549Sjkh    move(0, 0);
4668549Sjkh}
4678549Sjkh
46818619Sjkhstatic void
46918619Sjkhclear_wins(void)
47018619Sjkh{
47118619Sjkh    clear();
47218619Sjkh    wclear(ChunkWin);
47318619Sjkh}
47418619Sjkh
47512661Speterstatic int
47612661SpeterdiskLabel(char *str)
4778549Sjkh{
47818619Sjkh    int sz, key = 0;
4798549Sjkh    Boolean labeling;
4808549Sjkh    char *msg = NULL;
4819202Srgrimes    PartInfo *p, *oldp;
4828549Sjkh    PartType type;
4838824Sjkh    Device **devs;
4848549Sjkh
48512661Speter    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
48612661Speter    if (!devs) {
48712661Speter	msgConfirm("No disks found!");
48815242Sjkh	return DITEM_FAILURE;
48912661Speter    }
49012661Speter
4918549Sjkh    labeling = TRUE;
4928549Sjkh    keypad(stdscr, TRUE);
49312661Speter    record_label_chunks(devs);
4948549Sjkh
49518619Sjkh    clear();
4968549Sjkh    while (labeling) {
4978549Sjkh	print_label_chunks();
49818619Sjkh	print_command_summary();
4998549Sjkh	if (msg) {
50015695Sjkh	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
50112661Speter	    clrtoeol();
5028549Sjkh	    beep();
5038549Sjkh	    msg = NULL;
5048549Sjkh	}
50515442Sjkh	else {
50615442Sjkh	    move(23, 0);
50715442Sjkh	    clrtoeol();
50815442Sjkh	}
50918619Sjkh	refresh();
51017397Sjkh	key = getch();
51117397Sjkh	switch (toupper(key)) {
51215440Sjkh	    int i;
51317362Sjkh	    static char _msg[40];
5148549Sjkh
5158751Sjkh	case '\014':	/* ^L */
51618619Sjkh	    clear_wins();
51718619Sjkh	    break;
5188751Sjkh
5198549Sjkh	case KEY_UP:
5208549Sjkh	case '-':
5218549Sjkh	    if (here != 0)
5228549Sjkh		--here;
5238751Sjkh	    else
5248751Sjkh		while (label_chunk_info[here + 1].c)
5258751Sjkh		    ++here;
5268549Sjkh	    break;
5278549Sjkh
5288549Sjkh	case KEY_DOWN:
5298549Sjkh	case '+':
5308549Sjkh	case '\r':
5318549Sjkh	case '\n':
5328751Sjkh	    if (label_chunk_info[here + 1].c)
5338549Sjkh		++here;
5348751Sjkh	    else
5358751Sjkh		here = 0;
5368549Sjkh	    break;
5378549Sjkh
5388549Sjkh	case KEY_HOME:
5398549Sjkh	    here = 0;
5408549Sjkh	    break;
5418549Sjkh
5428549Sjkh	case KEY_END:
5438751Sjkh	    while (label_chunk_info[here + 1].c)
5448549Sjkh		++here;
5458549Sjkh	    break;
5468549Sjkh
5478549Sjkh	case KEY_F(1):
5488549Sjkh	case '?':
54912661Speter	    systemDisplayHelp("partition");
55018619Sjkh	    clear_wins();
5518549Sjkh	    break;
5528549Sjkh
55310882Speter	case 'A':
55410882Speter	    if (label_chunk_info[here].type != PART_SLICE) {
55515440Sjkh		msg = "You can only do this in a disk slice (at top of screen)";
55610882Speter		break;
55710882Speter	    }
55810882Speter	    sz = space_free(label_chunk_info[here].c);
55917362Sjkh	    if (sz <= FS_MIN_SIZE)
56015440Sjkh		msg = "Not enough free space to create a new partition in the slice";
56115440Sjkh	    else {
56215440Sjkh		struct chunk *tmp;
56315440Sjkh		int mib[2];
56415440Sjkh		int physmem;
56515440Sjkh		size_t size, swsize;
56615440Sjkh		char *cp;
56717362Sjkh		Chunk *rootdev, *swapdev, *usrdev, *vardev;
56812661Speter
56917368Sjkh		(void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev);
57017362Sjkh		if (!rootdev) {
57117362Sjkh		    cp = variable_get(VAR_ROOT_SIZE);
57217362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
57317362Sjkh					    (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS,  CHUNK_IS_ROOT);
57417362Sjkh		    if (!tmp) {
57517362Sjkh			msgConfirm("Unable to create the root partition. Too big?");
57618619Sjkh			clear_wins();
57717362Sjkh			break;
57817362Sjkh		    }
57917362Sjkh		    tmp->private_data = new_part("/", TRUE, tmp->size);
58017362Sjkh		    tmp->private_free = safe_free;
58117362Sjkh		    record_label_chunks(devs);
58215440Sjkh		}
58317362Sjkh
58417362Sjkh		if (!swapdev) {
58517362Sjkh		    cp = variable_get(VAR_SWAP_SIZE);
58617362Sjkh		    if (cp)
58717362Sjkh			swsize = atoi(cp) * ONE_MEG;
58817362Sjkh		    else {
58917362Sjkh			mib[0] = CTL_HW;
59017362Sjkh			mib[1] = HW_PHYSMEM;
59117362Sjkh			size = sizeof physmem;
59217362Sjkh			sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
59317362Sjkh			swsize = 16 * ONE_MEG + (physmem * 2 / 512);
59417362Sjkh		    }
59517362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
59617362Sjkh					    swsize, part, FS_SWAP, 0);
59717362Sjkh		    if (!tmp) {
59817362Sjkh			msgConfirm("Unable to create the swap partition. Too big?");
59918619Sjkh			clear_wins();
60017362Sjkh			break;
60117362Sjkh		    }
60217362Sjkh		    tmp->private_data = 0;
60317362Sjkh		    tmp->private_free = safe_free;
60417362Sjkh		    record_label_chunks(devs);
60515440Sjkh		}
60617362Sjkh
60717362Sjkh		if (!vardev) {
60817362Sjkh		    cp = variable_get(VAR_VAR_SIZE);
60917362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
61017362Sjkh					    (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0);
61117362Sjkh		    if (!tmp) {
61217362Sjkh			msgConfirm("Less than %dMB free for /var - you will need to\n"
61317362Sjkh				   "partition your disk manually with a custom install!",
61417362Sjkh				   (cp ? atoi(cp) : VAR_MIN_SIZE));
61518619Sjkh			clear_wins();
61617362Sjkh			break;
61717362Sjkh		    }
61817362Sjkh		    tmp->private_data = new_part("/var", TRUE, tmp->size);
61917362Sjkh		    tmp->private_free = safe_free;
62017362Sjkh		    record_label_chunks(devs);
62115440Sjkh		}
62212661Speter
62317362Sjkh		if (!usrdev) {
62417362Sjkh		    cp = variable_get(VAR_USR_SIZE);
62517362Sjkh		    if (cp)
62617362Sjkh			sz = atoi(cp) * ONE_MEG;
62717362Sjkh		    else
62817362Sjkh			sz = space_free(label_chunk_info[here].c);
62917362Sjkh		    if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) {
63017362Sjkh			msgConfirm("Less than %dMB free for /usr - you will need to\n"
63117362Sjkh				   "partition your disk manually with a custom install!", USR_MIN_SIZE);
63218619Sjkh			clear_wins();
63317362Sjkh			break;
63417362Sjkh		    }
63517362Sjkh
63617362Sjkh		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
63717362Sjkh					    label_chunk_info[here].c,
63817362Sjkh					    sz, part, FS_BSDFFS, 0);
63917362Sjkh		    if (!tmp) {
64017362Sjkh			msgConfirm("Unable to create the /usr partition.  Not enough space?\n"
64117362Sjkh				   "You will need to partition your disk manually with a custom install!");
64218619Sjkh			clear_wins();
64317362Sjkh			break;
64417362Sjkh		    }
64517362Sjkh		    tmp->private_data = new_part("/usr", TRUE, tmp->size);
64617362Sjkh		    tmp->private_free = safe_free;
64717362Sjkh		    record_label_chunks(devs);
64815440Sjkh		}
64915440Sjkh		/* At this point, we're reasonably "labelled" */
65015440Sjkh		variable_set2(DISK_LABELLED, "yes");
65110882Speter	    }
65215440Sjkh	    break;
65310882Speter
6548549Sjkh	case 'C':
6558549Sjkh	    if (label_chunk_info[here].type != PART_SLICE) {
6568549Sjkh		msg = "You can only do this in a master partition (see top of screen)";
6578549Sjkh		break;
6588549Sjkh	    }
6598549Sjkh	    sz = space_free(label_chunk_info[here].c);
6608669Sphk	    if (sz <= FS_MIN_SIZE) {
66112661Speter		msg = "Not enough space to create an additional FreeBSD partition";
6628669Sphk		break;
6638669Sphk	    }
66415440Sjkh	    else {
6658705Sjkh		char *val, *cp;
6668702Sjkh		int size;
6678702Sjkh		struct chunk *tmp;
6688820Sjkh		char osize[80];
6698702Sjkh		u_long flags = 0;
6708549Sjkh
6718820Sjkh		sprintf(osize, "%d", sz);
67218619Sjkh		DialogX = 3;
67318621Sjkh		DialogY = 2;
67418619Sjkh		val = msgGetInput(osize,
67518619Sjkh				  "Please specify the partition size in blocks or append a trailing M for\n"
67618619Sjkh				  "megabytes or C for cylinders.  %d blocks (%dMB) are free.",
67718619Sjkh				  sz, sz / ONE_MEG);
67818619Sjkh		DialogX = DialogY = 0;
67918619Sjkh		if (!val || (size = strtol(val, &cp, 0)) <= 0) {
68018619Sjkh		    clear_wins();
6818702Sjkh		    break;
68218619Sjkh		}
6838549Sjkh
6848751Sjkh		if (*cp) {
6858751Sjkh		    if (toupper(*cp) == 'M')
6868751Sjkh			size *= ONE_MEG;
6878751Sjkh		    else if (toupper(*cp) == 'C')
6888751Sjkh			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
6898751Sjkh		}
6908820Sjkh		if (size <= FS_MIN_SIZE) {
6918820Sjkh		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
69218619Sjkh		    clear_wins();
6938820Sjkh		    break;
6948820Sjkh		}
6958702Sjkh		type = get_partition_type();
69618619Sjkh		if (type == PART_NONE) {
69718619Sjkh		    clear_wins();
69818619Sjkh		    beep();
6998669Sphk		    break;
70018619Sjkh		}
7018669Sphk
7028702Sjkh		if (type == PART_FILESYSTEM) {
70318619Sjkh		    if ((p = get_mountpoint(NULL)) == NULL) {
70418619Sjkh			clear_wins();
70518619Sjkh			beep();
7068702Sjkh			break;
70718619Sjkh		    }
7088702Sjkh		    else if (!strcmp(p->mountpoint, "/"))
7098702Sjkh			flags |= CHUNK_IS_ROOT;
7108702Sjkh		    else
7118702Sjkh			flags &= ~CHUNK_IS_ROOT;
71218619Sjkh		}
71318619Sjkh		else
7148702Sjkh		    p = NULL;
7158702Sjkh
7168702Sjkh		if ((flags & CHUNK_IS_ROOT)) {
7178702Sjkh		    if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
71812661Speter			msgConfirm("This region cannot be used for your root partition as the\n"
71912661Speter				   "FreeBSD boot code cannot deal with a root partition created\n"
72012661Speter				   "in that location.  Please choose another location or smaller\n"
72112661Speter				   "size for your root partition and try again!");
72218619Sjkh			clear_wins();
7238702Sjkh			break;
7248702Sjkh		    }
72512661Speter		    if (size < (ROOT_MIN_SIZE * ONE_MEG)) {
72612661Speter			msgConfirm("Warning: This is smaller than the recommended size for a\n"
72712661Speter				   "root partition.  For a variety of reasons, root\n"
72812661Speter				   "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
72912661Speter		    }
7308672Sjkh		}
7318751Sjkh		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
7328702Sjkh					label_chunk_info[here].c,
7338702Sjkh					size, part,
7348702Sjkh					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
7358702Sjkh					flags);
7368702Sjkh		if (!tmp) {
7378702Sjkh		    msgConfirm("Unable to create the partition. Too big?");
73818619Sjkh		    clear_wins();
7398672Sjkh		    break;
7408672Sjkh		}
7418702Sjkh		if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
74212661Speter		    msgConfirm("This region cannot be used for your root partition as it starts\n"
74312661Speter			       "or extends past the 1024'th cylinder mark and is thus a\n"
74412661Speter			       "poor location to boot from.  Please choose another\n"
74512661Speter			       "location (or smaller size) for your root partition and try again!");
7468751Sjkh		    Delete_Chunk(label_chunk_info[here].c->disk, tmp);
74718619Sjkh		    clear_wins();
7488669Sphk		    break;
7498702Sjkh		}
7508702Sjkh		if (type != PART_SWAP) {
7518669Sphk		    /* This is needed to tell the newfs -u about the size */
75214793Sjoerg		    tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
7538669Sphk		    safe_free(p);
75415355Sjkh		}
75515355Sjkh		else
75614793Sjoerg		    tmp->private_data = p;
7578702Sjkh		tmp->private_free = safe_free;
75812661Speter		variable_set2(DISK_LABELLED, "yes");
75912661Speter		record_label_chunks(devs);
76018619Sjkh		clear_wins();
7618549Sjkh	    }
7628549Sjkh	    break;
7638549Sjkh
76417397Sjkh	case KEY_DC:
7658549Sjkh	case 'D':	/* delete */
7668549Sjkh	    if (label_chunk_info[here].type == PART_SLICE) {
7678549Sjkh		msg = MSG_NOT_APPLICABLE;
7688549Sjkh		break;
7698549Sjkh	    }
7708549Sjkh	    else if (label_chunk_info[here].type == PART_FAT) {
7718705Sjkh		msg = "Use the Disk Partition Editor to delete DOS partitions";
7728549Sjkh		break;
7738549Sjkh	    }
7748751Sjkh	    Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c);
77512661Speter	    variable_set2(DISK_LABELLED, "yes");
77612661Speter	    record_label_chunks(devs);
7778549Sjkh	    break;
7788549Sjkh
7798549Sjkh	case 'M':	/* mount */
7808549Sjkh	    switch(label_chunk_info[here].type) {
7818549Sjkh	    case PART_SLICE:
7828549Sjkh		msg = MSG_NOT_APPLICABLE;
7838549Sjkh		break;
7848549Sjkh
7858549Sjkh	    case PART_SWAP:
7868549Sjkh		msg = "You don't need to specify a mountpoint for a swap partition.";
7878549Sjkh		break;
7888549Sjkh
7898556Sjkh	    case PART_FAT:
7908549Sjkh	    case PART_FILESYSTEM:
79114793Sjoerg		oldp = label_chunk_info[here].c->private_data;
7928589Sjkh		p = get_mountpoint(label_chunk_info[here].c);
7938549Sjkh		if (p) {
7949202Srgrimes		    if (!oldp)
7959202Srgrimes		    	p->newfs = FALSE;
7968722Sjkh		    if (label_chunk_info[here].type == PART_FAT
7978722Sjkh			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
7988722Sjkh			    || !strcmp(p->mountpoint, "/var"))) {
7998722Sjkh			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
8008722Sjkh			strcpy(p->mountpoint, "/bogus");
8018722Sjkh		    }
8028549Sjkh		}
80312661Speter		variable_set2(DISK_LABELLED, "yes");
80412661Speter		record_label_chunks(devs);
80518636Sjkh		clear_wins();
8068549Sjkh		break;
8078549Sjkh
8088549Sjkh	    default:
8098549Sjkh		msgFatal("Bogus partition under cursor???");
8108549Sjkh		break;
8118549Sjkh	    }
8128549Sjkh	    break;
8138549Sjkh
8148549Sjkh	case 'N':	/* Set newfs options */
81514793Sjoerg	    if (label_chunk_info[here].c->private_data &&
81614793Sjoerg		((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
81714793Sjoerg		getNewfsCmd(label_chunk_info[here].c->private_data);
8188549Sjkh	    else
8198549Sjkh		msg = MSG_NOT_APPLICABLE;
82018636Sjkh	    clear_wins();
8218549Sjkh	    break;
8228549Sjkh
8238549Sjkh	case 'T':	/* Toggle newfs state */
8249202Srgrimes	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
82514793Sjoerg		    PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
82615355Sjkh		    label_chunk_info[here].c->private_data =
82715355Sjkh			new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
8288669Sphk		    safe_free(pi);
8298820Sjkh		    label_chunk_info[here].c->private_free = safe_free;
83012661Speter		    variable_set2(DISK_LABELLED, "yes");
83118619Sjkh	    }
8328549Sjkh	    else
8338549Sjkh		msg = MSG_NOT_APPLICABLE;
8348549Sjkh	    break;
8358549Sjkh
8368820Sjkh	case 'U':
83712661Speter	    clear();
83812661Speter	    if (msgYesNo("Are you SURE you want to Undo everything?"))
83912661Speter		break;
84012661Speter	    variable_unset(DISK_PARTITIONED);
84117025Sjkh	    variable_unset(DISK_LABELLED);
8428824Sjkh	    for (i = 0; devs[i]; i++) {
84312661Speter		Disk *d;
84412661Speter
8458824Sjkh		if (!devs[i]->enabled)
8468824Sjkh		    continue;
84712661Speter		else if ((d = Open_Disk(devs[i]->name)) != NULL) {
8488824Sjkh		    Free_Disk(devs[i]->private);
84912661Speter		    devs[i]->private = d;
85012661Speter		    diskPartition(devs[i], d);
8518824Sjkh		}
8528824Sjkh	    }
85312661Speter	    record_label_chunks(devs);
85418636Sjkh	    clear_wins();
8558824Sjkh	    break;
8568820Sjkh
8578549Sjkh	case 'W':
85818687Sjkh	    if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
85918687Sjkh			  "installation.  If you are installing FreeBSD for the first time\n"
86018687Sjkh			  "then you should simply type Q when you're finished here and your\n"
86118687Sjkh			  "changes will be committed in one batch automatically at the end of\n"
86218687Sjkh			  "these questions.\n\n"
86318687Sjkh			  "Are you absolutely sure you want to do this now?")) {
86412661Speter		variable_set2(DISK_LABELLED, "yes");
86512661Speter		diskLabelCommit(NULL);
86612661Speter	    }
86718636Sjkh	    clear_wins();
86810882Speter	    break;
86910882Speter
87010882Speter	case '|':
87112661Speter	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n"
87212661Speter			  "This is an entirely undocumented feature which you are not\n"
87312661Speter			  "expected to understand!")) {
8748549Sjkh		int i;
8758549Sjkh		Device **devs;
8768549Sjkh
8778549Sjkh		dialog_clear();
8788549Sjkh		end_dialog();
8798549Sjkh		DialogActive = FALSE;
8808549Sjkh		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
8818549Sjkh		if (!devs) {
88212661Speter		    msgConfirm("Can't find any disk devices!");
8838549Sjkh		    break;
8848549Sjkh		}
8858668Sphk		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
8868613Sjkh		    if (devs[i]->enabled)
8878613Sjkh		    	slice_wizard(((Disk *)devs[i]->private));
8888613Sjkh		}
88912661Speter		variable_set2(DISK_LABELLED, "yes");
8908665Sphk		DialogActive = TRUE;
89112661Speter		record_label_chunks(devs);
89218636Sjkh		clear_wins();
8938549Sjkh	    }
8948549Sjkh	    else
8958549Sjkh		msg = "A most prudent choice!";
8968549Sjkh	    break;
8978549Sjkh
8989202Srgrimes	case 'Q':
8998549Sjkh	    labeling = FALSE;
9008549Sjkh	    break;
9018549Sjkh
9028549Sjkh	default:
9038549Sjkh	    beep();
90417362Sjkh	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
90517362Sjkh	    msg = _msg;
9068549Sjkh	    break;
9078549Sjkh	}
9088549Sjkh    }
90917362Sjkh    return DITEM_SUCCESS | DITEM_RESTORE;
9108549Sjkh}
911