label.c revision 21673
1238106Sdes/*
2238106Sdes * The new sysinstall program.
3238106Sdes *
4238106Sdes * This is probably the last program in the `sysinstall' line - the next
5238106Sdes * generation being essentially a complete rewrite.
6238106Sdes *
7238106Sdes * $FreeBSD: head/usr.sbin/sade/label.c 21673 1997-01-14 07:20:47Z jkh $
8238106Sdes *
9238106Sdes * Copyright (c) 1995
10238106Sdes *	Jordan Hubbard.  All rights reserved.
11238106Sdes *
12238106Sdes * Redistribution and use in source and binary forms, with or without
13238106Sdes * modification, are permitted provided that the following conditions
14238106Sdes * are met:
15238106Sdes * 1. Redistributions of source code must retain the above copyright
16238106Sdes *    notice, this list of conditions and the following disclaimer,
17238106Sdes *    verbatim and that no modifications are made prior to this
18238106Sdes *    point in the file.
19238106Sdes * 2. Redistributions in binary form must reproduce the above copyright
20238106Sdes *    notice, this list of conditions and the following disclaimer in the
21238106Sdes *    documentation and/or other materials provided with the distribution.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24285206Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25285206Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26238106Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27238106Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28291767Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29238106Sdes * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30238106Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31238106Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32238106Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33238106Sdes * SUCH DAMAGE.
34269257Sdes *
35269257Sdes */
36269257Sdes
37269257Sdes#include "sysinstall.h"
38269257Sdes#include <ctype.h>
39249141Sdes#include <sys/disklabel.h>
40269257Sdes#include <sys/param.h>
41294190Sdes#include <sys/sysctl.h>
42238106Sdes
43238106Sdes/*
44238106Sdes * Everything to do with editing the contents of disk labels.
45238106Sdes */
46238106Sdes
47238106Sdes/* A nice message we use a lot in the disklabel editor */
48238106Sdes#define MSG_NOT_APPLICABLE	"That option is not applicable here"
49238106Sdes
50285206Sdes/* Where to start printing the freebsd slices */
51238106Sdes#define CHUNK_SLICE_START_ROW		2
52238106Sdes#define CHUNK_PART_START_ROW		11
53238106Sdes
54238106Sdes/* The smallest filesystem we're willing to create */
55238106Sdes#define FS_MIN_SIZE			ONE_MEG
56238106Sdes
57238106Sdes/* The smallest root filesystem we're willing to create */
58238106Sdes#define ROOT_MIN_SIZE			20
59238106Sdes
60238106Sdes/* The smallest swap partition we want to create by default */
61238106Sdes#define SWAP_MIN_SIZE			16
62238106Sdes
63285206Sdes/* The smallest /usr partition we're willing to create by default */
64238106Sdes#define USR_MIN_SIZE			80
65238106Sdes
66238106Sdes/* The smallest /var partition we're willing to create by default */
67238106Sdes#define VAR_MIN_SIZE			30
68238106Sdes
69238106Sdes/* The bottom-most row we're allowed to scribble on */
70238106Sdes#define CHUNK_ROW_MAX		16
71238106Sdes
72238106Sdes
73238106Sdes/* All the chunks currently displayed on the screen */
74269257Sdesstatic struct {
75238106Sdes    struct chunk *c;
76238106Sdes    PartType type;
77285206Sdes} label_chunk_info[MAX_CHUNKS + 1];
78238106Sdesstatic int here;
79238106Sdes
80238106Sdesstatic int ChunkPartStartRow;
81238106Sdesstatic WINDOW *ChunkWin;
82269257Sdes
83285206Sdesstatic int diskLabel(char *str);
84238106Sdes
85285206Sdesint
86238106SdesdiskLabelEditor(dialogMenuItem *self)
87238106Sdes{
88238106Sdes    Device **devs;
89238106Sdes    int i, cnt, enabled;
90238106Sdes    char *cp;
91238106Sdes
92238106Sdes    cp = variable_get(VAR_DISK);
93238106Sdes    devs = deviceFind(cp, DEVICE_TYPE_DISK);
94238106Sdes    cnt = deviceCount(devs);
95238106Sdes    if (!cnt) {
96238106Sdes	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
97238106Sdes		   "properly probed at boot time.  See the Hardware Guide on the\n"
98295691Sdes		   "Documentation menu for clues on diagnosing this type of problem.");
99238106Sdes	return DITEM_FAILURE;
100238106Sdes    }
101238106Sdes    for (i = 0, enabled = 0; i < cnt; i++) {
102238106Sdes	if (devs[i]->enabled)
103238106Sdes	    ++enabled;
104238106Sdes    }
105238106Sdes    if (!enabled) {
106238106Sdes	msgConfirm("No disks have been selected.  Please visit the Partition\n"
107238106Sdes		   "editor first to specify which disks you wish to operate on.");
108238106Sdes	return DITEM_FAILURE;
109238106Sdes    }
110238106Sdes    i = diskLabel(devs[0]->name);
111238106Sdes    if (DITEM_STATUS(i) != DITEM_FAILURE) {
112238106Sdes	char *cp;
113249141Sdes
114285206Sdes	if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
115238106Sdes	    variable_set2(DISK_LABELLED, "yes");
116295691Sdes    }
117238106Sdes    return i;
118238106Sdes}
119238106Sdes
120238106Sdesint
121238106SdesdiskLabelCommit(dialogMenuItem *self)
122238106Sdes{
123238106Sdes    char *cp;
124285206Sdes    int i;
125285206Sdes
126238106Sdes    /* Already done? */
127238106Sdes    if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
128238106Sdes	i = DITEM_SUCCESS;
129238106Sdes    else if (!cp) {
130238106Sdes	msgConfirm("You must assign disk labels before this option can be used.");
131238106Sdes	i = DITEM_FAILURE;
132269257Sdes    }
133285206Sdes    /* The routine will guard against redundant writes, just as this one does */
134285206Sdes    else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
135285206Sdes	i = DITEM_FAILURE;
136294190Sdes    else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
137238106Sdes	i = DITEM_FAILURE;
138238106Sdes    else {
139285206Sdes	msgInfo("All filesystem information written successfully.");
140291767Sdes	variable_set2(DISK_LABELLED, "written");
141291767Sdes	i = DITEM_SUCCESS;
142269257Sdes    }
143269257Sdes    return i;
144238106Sdes}
145238106Sdes
146238106Sdes/* See if we're already using a desired partition name */
147269257Sdesstatic Boolean
148238106Sdescheck_conflict(char *name)
149238106Sdes{
150269257Sdes    int i;
151269257Sdes
152269257Sdes    for (i = 0; label_chunk_info[i].c; i++)
153238106Sdes	if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private_data
154238106Sdes	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
155238106Sdes	    return TRUE;
156238106Sdes    return FALSE;
157269257Sdes}
158238106Sdes
159238106Sdes/* How much space is in this FreeBSD slice? */
160238106Sdesstatic int
161269257Sdesspace_free(struct chunk *c)
162238106Sdes{
163238106Sdes    struct chunk *c1;
164238106Sdes    int sz = c->size;
165238106Sdes
166269257Sdes    for (c1 = c->part; c1; c1 = c1->next) {
167238106Sdes	if (c1->type != unused)
168238106Sdes	    sz -= c1->size;
169285206Sdes    }
170238106Sdes    if (sz < 0)
171238106Sdes	msgFatal("Partitions are larger than actual chunk??");
172291767Sdes    return sz;
173238106Sdes}
174269257Sdes
175238106Sdes/* Snapshot the current situation into the displayed chunks structure */
176238106Sdesstatic void
177238106Sdesrecord_label_chunks(Device **devs)
178269257Sdes{
179269257Sdes    int i, j, p;
180238106Sdes    struct chunk *c1, *c2;
181238106Sdes    Disk *d;
182269257Sdes
183269257Sdes    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3;
184238106Sdes    j = p = 0;
185238106Sdes    /* First buzz through and pick up the FreeBSD slices */
186285206Sdes    for (i = 0; devs[i]; i++) {
187238106Sdes	if (!devs[i]->enabled)
188238106Sdes	    continue;
189238106Sdes	d = (Disk *)devs[i]->private;
190269257Sdes	if (!d->chunks)
191238106Sdes	    msgFatal("No chunk list found for %s!", d->name);
192238106Sdes
193269257Sdes	/* Put the slice entries first */
194269257Sdes	for (c1 = d->chunks->part; c1; c1 = c1->next) {
195238106Sdes	    if (c1->type == freebsd) {
196238106Sdes		label_chunk_info[j].type = PART_SLICE;
197238106Sdes		label_chunk_info[j].c = c1;
198238106Sdes		++j;
199238106Sdes		++ChunkPartStartRow;
200269257Sdes	    }
201269257Sdes	}
202238106Sdes    }
203238106Sdes
204269257Sdes    /* Now run through again and get the FreeBSD partition entries */
205238106Sdes    for (i = 0; devs[i]; i++) {
206238106Sdes	if (!devs[i]->enabled)
207269257Sdes	    continue;
208269257Sdes	d = (Disk *)devs[i]->private;
209238106Sdes	/* Then buzz through and pick up the partitions */
210238106Sdes	for (c1 = d->chunks->part; c1; c1 = c1->next) {
211238106Sdes	    if (c1->type == freebsd) {
212269257Sdes		for (c2 = c1->part; c2; c2 = c2->next) {
213238106Sdes		    if (c2->type == part) {
214238106Sdes			if (c2->subtype == FS_SWAP)
215238106Sdes			    label_chunk_info[j].type = PART_SWAP;
216238106Sdes			else
217238106Sdes			    label_chunk_info[j].type = PART_FILESYSTEM;
218238106Sdes			label_chunk_info[j].c = c2;
219238106Sdes			++j;
220238106Sdes		    }
221238106Sdes		}
222238106Sdes	    }
223238106Sdes	    else if (c1->type == fat) {
224238106Sdes		label_chunk_info[j].type = PART_FAT;
225238106Sdes		label_chunk_info[j].c = c1;
226238106Sdes		++j;
227238106Sdes	    }
228238106Sdes	}
229238106Sdes    }
230238106Sdes    label_chunk_info[j].c = NULL;
231238106Sdes    if (here >= j)
232269257Sdes	here = j  ? j - 1 : 0;
233238106Sdes    if (ChunkWin) {
234238106Sdes	wclear(ChunkWin);
235269257Sdes	wrefresh(ChunkWin);
236238106Sdes    }
237269257Sdes    else
238238106Sdes	ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
239269257Sdes}
240238106Sdes
241238106Sdes/* A new partition entry */
242269257Sdesstatic PartInfo *
243238106Sdesnew_part(char *mpoint, Boolean newfs, u_long size)
244269257Sdes{
245238106Sdes    PartInfo *ret;
246238106Sdes
247238106Sdes    if (!mpoint)
248238106Sdes	mpoint = "/change_me";
249238106Sdes
250249141Sdes    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
251238106Sdes    sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX);
252249141Sdes    strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024");
253238106Sdes    ret->newfs = newfs;
254249141Sdes    if (!size)
255249141Sdes	    return ret;
256238106Sdes    return ret;
257238106Sdes}
258238106Sdes
259238106Sdes/* Get the mountpoint for a partition and save it away */
260238106Sdesstatic PartInfo *
261238106Sdesget_mountpoint(struct chunk *old)
262238106Sdes{
263238106Sdes    char *val;
264238106Sdes    PartInfo *tmp;
265238106Sdes
266238106Sdes    if (old && old->private_data)
267238106Sdes	tmp = old->private_data;
268238106Sdes    else
269238106Sdes	tmp = NULL;
270238106Sdes    if (!old) {
271238106Sdes	DialogX = 14;
272238106Sdes	DialogY = 16;
273238106Sdes    }
274238106Sdes    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
275238106Sdes    DialogX = DialogY = 0;
276238106Sdes    if (!val || !*val) {
277238106Sdes	if (!old)
278269257Sdes	    return NULL;
279238106Sdes	else {
280269257Sdes	    free(old->private_data);
281238106Sdes	    old->private_data = NULL;
282238106Sdes	}
283238106Sdes	return NULL;
284238106Sdes    }
285238106Sdes
286238106Sdes    /* Is it just the same value? */
287238106Sdes    if (tmp && !strcmp(tmp->mountpoint, val))
288238106Sdes	return NULL;
289238106Sdes
290238106Sdes    /* Did we use it already? */
291238106Sdes    if (check_conflict(val)) {
292238106Sdes	msgConfirm("You already have a mount point for %s assigned!", val);
293238106Sdes	return NULL;
294238106Sdes    }
295238106Sdes
296269257Sdes    /* Is it bogus? */
297238106Sdes    if (*val != '/') {
298238106Sdes	msgConfirm("Mount point must start with a / character");
299294190Sdes	return NULL;
300238106Sdes    }
301238106Sdes
302294190Sdes    /* Is it going to be mounted on root? */
303238106Sdes    if (!strcmp(val, "/")) {
304238106Sdes	if (old)
305294190Sdes	    old->flags |= CHUNK_IS_ROOT;
306238106Sdes    }
307238106Sdes    else if (old)
308294190Sdes	old->flags &= ~CHUNK_IS_ROOT;
309238106Sdes
310238106Sdes    safe_free(tmp);
311238106Sdes    tmp = new_part(val, TRUE, 0);
312238106Sdes    if (old) {
313238106Sdes	old->private_data = tmp;
314294190Sdes	old->private_free = safe_free;
315238106Sdes    }
316238106Sdes    return tmp;
317238106Sdes}
318238106Sdes
319238106Sdes/* Get the type of the new partiton */
320238106Sdesstatic PartType
321238106Sdesget_partition_type(void)
322238106Sdes{
323238106Sdes    char selection[20];
324238106Sdes    int i;
325238106Sdes
326294190Sdes    static unsigned char *fs_types[] = {
327238106Sdes	"FS",
328238106Sdes	"A file system",
329294190Sdes	"Swap",
330238106Sdes	"A swap partition.",
331238106Sdes    };
332294190Sdes    DialogX = 7;
333238106Sdes    DialogY = 8;
334238106Sdes    i = dialog_menu("Please choose a partition type",
335294190Sdes		    "If you want to use this partition for swap space, select Swap.\n"
336238106Sdes		    "If you want to put a filesystem on it, choose FS.",
337238106Sdes		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
338294190Sdes    DialogX = DialogY = 0;
339238106Sdes    if (!i) {
340238106Sdes	if (!strcmp(selection, "FS"))
341294190Sdes	    return PART_FILESYSTEM;
342238106Sdes	else if (!strcmp(selection, "Swap"))
343238106Sdes	    return PART_SWAP;
344238106Sdes    }
345238106Sdes    return PART_NONE;
346238106Sdes}
347294190Sdes
348238106Sdes/* If the user wants a special newfs command for this, set it */
349238106Sdesstatic void
350294190SdesgetNewfsCmd(PartInfo *p)
351238106Sdes{
352238106Sdes    char *val;
353294190Sdes
354238106Sdes    val = msgGetInput(p->newfs_cmd,
355269257Sdes		      "Please enter the newfs command and options you'd like to use in\n"
356294190Sdes		      "creating this file system.");
357238106Sdes    if (val)
358269257Sdes	sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
359269257Sdes}
360269257Sdes
361285206Sdes#define MAX_MOUNT_NAME	12
362285206Sdes
363238106Sdes#define PART_PART_COL	0
364238106Sdes#define PART_MOUNT_COL	8
365285206Sdes#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
366285206Sdes#define PART_NEWFS_COL	(PART_SIZE_COL + 7)
367285206Sdes#define PART_OFF	38
368285206Sdes
369285206Sdes/* stick this all up on the screen */
370285206Sdesstatic void
371285206Sdesprint_label_chunks(void)
372285206Sdes{
373285206Sdes    int i, j, srow, prow, pcol;
374285206Sdes    int sz;
375285206Sdes
376285206Sdes    attrset(A_REVERSE);
377238106Sdes    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
378238106Sdes    attrset(A_NORMAL);
379238106Sdes
380238106Sdes    for (i = 0; i < 2; i++) {
381238106Sdes	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
382238106Sdes	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
383238106Sdes
384238106Sdes	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
385238106Sdes	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
386238106Sdes
387238106Sdes	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
388238106Sdes	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
389238106Sdes
390249141Sdes	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
391238106Sdes	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
392238106Sdes    }
393238106Sdes    srow = CHUNK_SLICE_START_ROW;
394238106Sdes    prow = 0;
395269257Sdes    pcol = 0;
396269257Sdes
397238106Sdes    for (i = 0; label_chunk_info[i].c; i++) {
398291767Sdes	/* Is it a slice entry displayed at the top? */
399238106Sdes	if (label_chunk_info[i].type == PART_SLICE) {
400238106Sdes	    sz = space_free(label_chunk_info[i].c);
401238106Sdes	    if (i == here)
402285206Sdes		attrset(ATTR_SELECTED);
403238106Sdes	    mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
404238106Sdes		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG));
405238106Sdes	    attrset(A_NORMAL);
406238106Sdes	    clrtoeol();
407238106Sdes	    move(0, 0);
408238106Sdes	    refresh();
409238106Sdes	}
410238106Sdes	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
411238106Sdes	else {
412238106Sdes	    char onestr[PART_OFF], num[10], *mountpoint, *newfs;
413238106Sdes
414238106Sdes	    /*
415238106Sdes	     * We copy this into a blank-padded string so that it looks like
416238106Sdes	     * a solid bar in reverse-video
417238106Sdes	     */
418238106Sdes	    memset(onestr, ' ', PART_OFF - 1);
419269257Sdes	    onestr[PART_OFF - 1] = '\0';
420238106Sdes	    /* Go for two columns if we've written one full columns worth */
421249141Sdes	    if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) {
422238106Sdes		pcol = PART_OFF;
423238106Sdes		prow = 0;
424238106Sdes	    }
425238106Sdes	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
426238106Sdes	    /* If it's a filesystem, display the mountpoint */
427238106Sdes	    if (label_chunk_info[i].c->private_data
428249141Sdes		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
429238106Sdes	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
430238106Sdes	    else
431238106Sdes	        mountpoint = "<none>";
432238106Sdes
433238106Sdes	    /* Now display the newfs field */
434269257Sdes	    if (label_chunk_info[i].type == PART_FAT)
435238106Sdes	        newfs = "DOS";
436238106Sdes	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM)
437285206Sdes		newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N";
438238106Sdes	    else if (label_chunk_info[i].type == PART_SWAP)
439238106Sdes		newfs = "SWAP";
440238106Sdes	    else
441238106Sdes		newfs = "*";
442238106Sdes	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
443238106Sdes		onestr[PART_MOUNT_COL + j] = mountpoint[j];
444238106Sdes	    snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
445238106Sdes	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
446238106Sdes	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
447238106Sdes	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
448238106Sdes	    if (i == here)
449238106Sdes		wattrset(ChunkWin, ATTR_SELECTED);
450238106Sdes	    mvwaddstr(ChunkWin, prow, pcol, onestr);
451238106Sdes	    wattrset(ChunkWin, A_NORMAL);
452238106Sdes	    wrefresh(ChunkWin);
453238106Sdes	    move(0, 0);
454238106Sdes	    ++prow;
455238106Sdes	}
456238106Sdes    }
457238106Sdes}
458238106Sdes
459238106Sdesstatic void
460238106Sdesprint_command_summary(void)
461238106Sdes{
462238106Sdes    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
463238106Sdes    mvprintw(18, 0, "C = Create      D = Delete         M = Mount");
464285206Sdes    if (!RunningAsInit)
465285206Sdes	mvprintw(18, 47, "W = Write");
466238106Sdes    mvprintw(19, 0, "N = Newfs Opts  T = Newfs Toggle   U = Undo    Q = Finish");
467238106Sdes    mvprintw(20, 0, "A = Auto Defaults for all!");
468238106Sdes    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
469238106Sdes    move(0, 0);
470238106Sdes}
471238106Sdes
472238106Sdesstatic void
473249141Sdesclear_wins(void)
474238106Sdes{
475238106Sdes    clear();
476238106Sdes    wclear(ChunkWin);
477269257Sdes}
478269257Sdes
479269257Sdesstatic int
480269257SdesdiskLabel(char *str)
481269257Sdes{
482269257Sdes    int sz, key = 0;
483269257Sdes    Boolean labeling;
484269257Sdes    char *msg = NULL;
485269257Sdes    PartInfo *p, *oldp;
486269257Sdes    PartType type;
487269257Sdes    Device **devs;
488269257Sdes
489269257Sdes    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
490269257Sdes    if (!devs) {
491269257Sdes	msgConfirm("No disks found!");
492269257Sdes	return DITEM_FAILURE;
493269257Sdes    }
494269257Sdes
495269257Sdes    labeling = TRUE;
496269257Sdes    keypad(stdscr, TRUE);
497269257Sdes    record_label_chunks(devs);
498269257Sdes
499269257Sdes    clear();
500269257Sdes    while (labeling) {
501269257Sdes	char *cp;
502269257Sdes
503269257Sdes	print_label_chunks();
504238106Sdes	print_command_summary();
505238106Sdes	if (msg) {
506238106Sdes	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
507238106Sdes	    clrtoeol();
508238106Sdes	    beep();
509238106Sdes	    msg = NULL;
510238106Sdes	}
511238106Sdes	else {
512238106Sdes	    move(23, 0);
513238106Sdes	    clrtoeol();
514238106Sdes	}
515238106Sdes
516238106Sdes	refresh();
517269257Sdes	key = getch();
518238106Sdes	switch (toupper(key)) {
519238106Sdes	    int i;
520285206Sdes	    static char _msg[40];
521238106Sdes
522238106Sdes	case '\014':	/* ^L */
523238106Sdes	    clear_wins();
524238106Sdes	    break;
525238106Sdes
526238106Sdes	case KEY_UP:
527238106Sdes	case '-':
528238106Sdes	    if (here != 0)
529238106Sdes		--here;
530238106Sdes	    else
531269257Sdes		while (label_chunk_info[here + 1].c)
532269257Sdes		    ++here;
533269257Sdes	    break;
534269257Sdes
535238106Sdes	case KEY_DOWN:
536269257Sdes	case '+':
537238106Sdes	case '\r':
538249141Sdes	case '\n':
539249141Sdes	    if (label_chunk_info[here + 1].c)
540249141Sdes		++here;
541249141Sdes	    else
542249141Sdes		here = 0;
543249141Sdes	    break;
544249141Sdes
545249141Sdes	case KEY_HOME:
546249141Sdes	    here = 0;
547249141Sdes	    break;
548238106Sdes
549238106Sdes	case KEY_END:
550238106Sdes	    while (label_chunk_info[here + 1].c)
551238106Sdes		++here;
552238106Sdes	    break;
553238106Sdes
554238106Sdes	case KEY_F(1):
555238106Sdes	case '?':
556238106Sdes	    systemDisplayHelp("partition");
557238106Sdes	    clear_wins();
558238106Sdes	    break;
559238106Sdes
560238106Sdes	case 'A':
561238106Sdes	    if (label_chunk_info[here].type != PART_SLICE) {
562238106Sdes		msg = "You can only do this in a disk slice (at top of screen)";
563238106Sdes		break;
564238106Sdes	    }
565238106Sdes	    sz = space_free(label_chunk_info[here].c);
566238106Sdes	    if (sz <= FS_MIN_SIZE)
567238106Sdes		msg = "Not enough free space to create a new partition in the slice";
568238106Sdes	    else {
569238106Sdes		struct chunk *tmp;
570238106Sdes		int mib[2];
571238106Sdes		int physmem;
572238106Sdes		size_t size, swsize;
573238106Sdes		char *cp;
574238106Sdes		Chunk *rootdev, *swapdev, *usrdev, *vardev;
575238106Sdes
576238106Sdes		(void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev);
577238106Sdes		if (!rootdev) {
578238106Sdes		    cp = variable_get(VAR_ROOT_SIZE);
579238106Sdes		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
580238106Sdes					    (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS,  CHUNK_IS_ROOT);
581285206Sdes		    if (!tmp) {
582238106Sdes			msgConfirm("Unable to create the root partition. Too big?");
583238106Sdes			clear_wins();
584238106Sdes			break;
585238106Sdes		    }
586238106Sdes		    tmp->private_data = new_part("/", TRUE, tmp->size);
587238106Sdes		    tmp->private_free = safe_free;
588238106Sdes		    record_label_chunks(devs);
589238106Sdes		}
590238106Sdes
591238106Sdes		if (!swapdev) {
592238106Sdes		    cp = variable_get(VAR_SWAP_SIZE);
593238106Sdes		    if (cp)
594238106Sdes			swsize = atoi(cp) * ONE_MEG;
595238106Sdes		    else {
596238106Sdes			mib[0] = CTL_HW;
597238106Sdes			mib[1] = HW_PHYSMEM;
598295691Sdes			size = sizeof physmem;
599285206Sdes			sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
600285206Sdes			swsize = 16 * ONE_MEG + (physmem * 2 / 512);
601285206Sdes		    }
602285206Sdes		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
603291767Sdes					    swsize, part, FS_SWAP, 0);
604291767Sdes		    if (!tmp) {
605291767Sdes			msgConfirm("Unable to create the swap partition. Too big?");
606285206Sdes			clear_wins();
607291767Sdes			break;
608291767Sdes		    }
609291767Sdes		    tmp->private_data = 0;
610291767Sdes		    tmp->private_free = safe_free;
611291767Sdes		    record_label_chunks(devs);
612285206Sdes		}
613285206Sdes
614291767Sdes		if (!vardev) {
615285206Sdes		    cp = variable_get(VAR_VAR_SIZE);
616285206Sdes		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
617285206Sdes					    (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0);
618291767Sdes		    if (!tmp) {
619285206Sdes			msgConfirm("Less than %dMB free for /var - you will need to\n"
620285206Sdes				   "partition your disk manually with a custom install!",
621291767Sdes				   (cp ? atoi(cp) : VAR_MIN_SIZE));
622291767Sdes			clear_wins();
623291767Sdes			break;
624285206Sdes		    }
625291767Sdes		    tmp->private_data = new_part("/var", TRUE, tmp->size);
626291767Sdes		    tmp->private_free = safe_free;
627291767Sdes		    record_label_chunks(devs);
628291767Sdes		}
629285206Sdes
630285206Sdes		if (!usrdev) {
631285206Sdes		    cp = variable_get(VAR_USR_SIZE);
632291767Sdes		    if (cp)
633291767Sdes			sz = atoi(cp) * ONE_MEG;
634285206Sdes		    else
635285206Sdes			sz = space_free(label_chunk_info[here].c);
636285206Sdes		    if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) {
637291767Sdes			msgConfirm("Less than %dMB free for /usr - you will need to\n"
638285206Sdes				   "partition your disk manually with a custom install!", USR_MIN_SIZE);
639285206Sdes			clear_wins();
640285206Sdes			break;
641291767Sdes		    }
642285206Sdes
643285206Sdes		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
644285206Sdes					    label_chunk_info[here].c,
645285206Sdes					    sz, part, FS_BSDFFS, 0);
646285206Sdes		    if (!tmp) {
647285206Sdes			msgConfirm("Unable to create the /usr partition.  Not enough space?\n"
648291767Sdes				   "You will need to partition your disk manually with a custom install!");
649294190Sdes			clear_wins();
650285206Sdes			break;
651285206Sdes		    }
652285206Sdes		    tmp->private_data = new_part("/usr", TRUE, tmp->size);
653291767Sdes		    tmp->private_free = safe_free;
654285206Sdes		    record_label_chunks(devs);
655285206Sdes		}
656285206Sdes		/* At this point, we're reasonably "labelled" */
657285206Sdes		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
658285206Sdes		    variable_set2(DISK_LABELLED, "yes");
659285206Sdes	    }
660291767Sdes	    break;
661285206Sdes
662285206Sdes	case 'C':
663285206Sdes	    if (label_chunk_info[here].type != PART_SLICE) {
664291767Sdes		msg = "You can only do this in a master partition (see top of screen)";
665291767Sdes		break;
666285206Sdes	    }
667285206Sdes	    sz = space_free(label_chunk_info[here].c);
668285206Sdes	    if (sz <= FS_MIN_SIZE) {
669291767Sdes		msg = "Not enough space to create an additional FreeBSD partition";
670291767Sdes		break;
671285206Sdes	    }
672285206Sdes	    else {
673285206Sdes		char *val;
674285206Sdes		int size;
675291767Sdes		struct chunk *tmp;
676285206Sdes		char osize[80];
677285206Sdes		u_long flags = 0;
678285206Sdes
679291767Sdes		sprintf(osize, "%d", sz);
680285206Sdes		DialogX = 3;
681285206Sdes		DialogY = 2;
682291767Sdes		val = msgGetInput(osize,
683285206Sdes				  "Please specify the partition size in blocks or append a trailing M for\n"
684285206Sdes				  "megabytes or C for cylinders.  %d blocks (%dMB) are free.",
685285206Sdes				  sz, sz / ONE_MEG);
686285206Sdes		DialogX = DialogY = 0;
687291767Sdes		if (!val || (size = strtol(val, &cp, 0)) <= 0) {
688291767Sdes		    clear_wins();
689291767Sdes		    break;
690291767Sdes		}
691291767Sdes
692291767Sdes		if (*cp) {
693291767Sdes		    if (toupper(*cp) == 'M')
694291767Sdes			size *= ONE_MEG;
695291767Sdes		    else if (toupper(*cp) == 'C')
696291767Sdes			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
697285206Sdes		}
698285206Sdes		if (size <= FS_MIN_SIZE) {
699285206Sdes		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
700291767Sdes		    clear_wins();
701285206Sdes		    break;
702291767Sdes		}
703291767Sdes		type = get_partition_type();
704285206Sdes		if (type == PART_NONE) {
705285206Sdes		    clear_wins();
706295691Sdes		    beep();
707285206Sdes		    break;
708285206Sdes		}
709291767Sdes
710291767Sdes		if (type == PART_FILESYSTEM) {
711291767Sdes		    if ((p = get_mountpoint(NULL)) == NULL) {
712291767Sdes			clear_wins();
713291767Sdes			beep();
714285206Sdes			break;
715285206Sdes		    }
716285206Sdes		    else if (!strcmp(p->mountpoint, "/"))
717291767Sdes			flags |= CHUNK_IS_ROOT;
718291767Sdes		    else
719291767Sdes			flags &= ~CHUNK_IS_ROOT;
720291767Sdes		}
721285206Sdes		else
722285206Sdes		    p = NULL;
723285206Sdes
724285206Sdes		if ((flags & CHUNK_IS_ROOT)) {
725285206Sdes		    if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
726285206Sdes			msgConfirm("This region cannot be used for your root partition as the\n"
727291767Sdes				   "FreeBSD boot code cannot deal with a root partition created\n"
728291767Sdes				   "in that location.  Please choose another location or smaller\n"
729291767Sdes				   "size for your root partition and try again!");
730291767Sdes			clear_wins();
731291767Sdes			break;
732294190Sdes		    }
733285206Sdes		    if (size < (ROOT_MIN_SIZE * ONE_MEG)) {
734285206Sdes			msgConfirm("Warning: This is smaller than the recommended size for a\n"
735285206Sdes				   "root partition.  For a variety of reasons, root\n"
736291767Sdes				   "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
737285206Sdes		    }
738285206Sdes		}
739285206Sdes		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
740285206Sdes					label_chunk_info[here].c,
741291767Sdes					size, part,
742285206Sdes					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
743285206Sdes					flags);
744291767Sdes		if (!tmp) {
745291767Sdes		    msgConfirm("Unable to create the partition. Too big?");
746291767Sdes		    clear_wins();
747285206Sdes		    break;
748285206Sdes		}
749285206Sdes		if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
750285206Sdes		    msgConfirm("This region cannot be used for your root partition as it starts\n"
751285206Sdes			       "or extends past the 1024'th cylinder mark and is thus a\n"
752285206Sdes			       "poor location to boot from.  Please choose another\n"
753285206Sdes			       "location (or smaller size) for your root partition and try again!");
754291767Sdes		    Delete_Chunk(label_chunk_info[here].c->disk, tmp);
755285206Sdes		    clear_wins();
756285206Sdes		    break;
757291767Sdes		}
758291767Sdes		if (type != PART_SWAP) {
759285206Sdes		    /* This is needed to tell the newfs -u about the size */
760285206Sdes		    tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
761285206Sdes		    safe_free(p);
762291767Sdes		}
763291767Sdes		else
764291767Sdes		    tmp->private_data = p;
765285206Sdes		tmp->private_free = safe_free;
766291767Sdes		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
767285206Sdes		    variable_set2(DISK_LABELLED, "yes");
768285206Sdes		record_label_chunks(devs);
769285206Sdes		clear_wins();
770291767Sdes	    }
771285206Sdes	    break;
772285206Sdes
773285206Sdes	case KEY_DC:
774291767Sdes	case 'D':	/* delete */
775285206Sdes	    if (label_chunk_info[here].type == PART_SLICE) {
776285206Sdes		msg = MSG_NOT_APPLICABLE;
777285206Sdes		break;
778291767Sdes	    }
779291767Sdes	    else if (label_chunk_info[here].type == PART_FAT) {
780294190Sdes		msg = "Use the Disk Partition Editor to delete DOS partitions";
781285206Sdes		break;
782285206Sdes	    }
783285206Sdes	    Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c);
784291767Sdes	    if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
785294190Sdes		variable_set2(DISK_LABELLED, "yes");
786285206Sdes	    record_label_chunks(devs);
787285206Sdes	    break;
788285206Sdes
789285206Sdes	case 'M':	/* mount */
790291767Sdes	    switch(label_chunk_info[here].type) {
791285206Sdes	    case PART_SLICE:
792285206Sdes		msg = MSG_NOT_APPLICABLE;
793285206Sdes		break;
794285206Sdes
795285206Sdes	    case PART_SWAP:
796285206Sdes		msg = "You don't need to specify a mountpoint for a swap partition.";
797285206Sdes		break;
798285206Sdes
799285206Sdes	    case PART_FAT:
800285206Sdes	    case PART_FILESYSTEM:
801291767Sdes		oldp = label_chunk_info[here].c->private_data;
802285206Sdes		p = get_mountpoint(label_chunk_info[here].c);
803285206Sdes		if (p) {
804285206Sdes		    if (!oldp)
805285206Sdes		    	p->newfs = FALSE;
806285206Sdes		    if (label_chunk_info[here].type == PART_FAT
807285206Sdes			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
808285206Sdes			    || !strcmp(p->mountpoint, "/var"))) {
809291767Sdes			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
810285206Sdes			strcpy(p->mountpoint, "/bogus");
811285206Sdes		    }
812285206Sdes		}
813285206Sdes		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
814285206Sdes		    variable_set2(DISK_LABELLED, "yes");
815285206Sdes		record_label_chunks(devs);
816291767Sdes		clear_wins();
817285206Sdes		break;
818285206Sdes
819285206Sdes	    default:
820294190Sdes		msgFatal("Bogus partition under cursor???");
821285206Sdes		break;
822285206Sdes	    }
823285206Sdes	    break;
824291767Sdes
825295691Sdes	case 'N':	/* Set newfs options */
826285206Sdes	    if (label_chunk_info[here].c->private_data &&
827285206Sdes		((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
828285206Sdes		getNewfsCmd(label_chunk_info[here].c->private_data);
829291767Sdes	    else
830291767Sdes		msg = MSG_NOT_APPLICABLE;
831291767Sdes	    clear_wins();
832291767Sdes	    break;
833291767Sdes
834291767Sdes	case 'T':	/* Toggle newfs state */
835291767Sdes	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
836291767Sdes		    PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
837285206Sdes		    label_chunk_info[here].c->private_data =
838285206Sdes			new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
839285206Sdes		    safe_free(pi);
840285206Sdes		    label_chunk_info[here].c->private_free = safe_free;
841291767Sdes		    if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
842285206Sdes			variable_set2(DISK_LABELLED, "yes");
843285206Sdes	    }
844285206Sdes	    else
845294190Sdes		msg = MSG_NOT_APPLICABLE;
846294190Sdes	    break;
847294190Sdes
848294190Sdes	case 'U':
849294190Sdes	    clear();
850294190Sdes	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
851294190Sdes		msgConfirm("You've already written out your changes -\n"
852294190Sdes			   "it's too late to undo!");
853294190Sdes	    }
854294190Sdes	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
855291767Sdes		variable_unset(DISK_PARTITIONED);
856291767Sdes		variable_unset(DISK_LABELLED);
857285206Sdes		for (i = 0; devs[i]; i++) {
858291767Sdes		    Disk *d;
859285206Sdes
860285206Sdes		    if (!devs[i]->enabled)
861285206Sdes			continue;
862291767Sdes		    else if ((d = Open_Disk(devs[i]->name)) != NULL) {
863291767Sdes			Free_Disk(devs[i]->private);
864285206Sdes			devs[i]->private = d;
865285206Sdes			diskPartition(devs[i], d);
866294190Sdes		    }
867294190Sdes		}
868285206Sdes		record_label_chunks(devs);
869285206Sdes	    }
870285206Sdes	    clear_wins();
871291767Sdes	    break;
872291767Sdes
873294190Sdes	case 'W':
874294190Sdes	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
875285206Sdes		msgConfirm("You've already written out your changes - if you\n"
876285206Sdes			   "wish to overwrite them, you'll have to start this\n"
877285206Sdes			   "procedure again from the beginning.");
878291767Sdes	    }
879285206Sdes	    else if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
880285206Sdes			  "installation.  If you are installing FreeBSD for the first time\n"
881285206Sdes			  "then you should simply type Q when you're finished here and your\n"
882285206Sdes			  "changes will be committed in one batch automatically at the end of\n"
883285206Sdes			  "these questions.\n\n"
884285206Sdes			  "Are you absolutely sure you want to do this now?")) {
885291767Sdes		variable_set2(DISK_LABELLED, "yes");
886291767Sdes		diskLabelCommit(NULL);
887291767Sdes	    }
888291767Sdes	    clear_wins();
889291767Sdes	    break;
890285206Sdes
891285206Sdes	case '|':
892285206Sdes	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n"
893285206Sdes			  "This is an entirely undocumented feature which you are not\n"
894291767Sdes			  "expected to understand!")) {
895285206Sdes		int i;
896291767Sdes		Device **devs;
897291767Sdes
898285206Sdes		dialog_clear();
899285206Sdes		end_dialog();
900294190Sdes		DialogActive = FALSE;
901291767Sdes		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
902285206Sdes		if (!devs) {
903291767Sdes		    msgConfirm("Can't find any disk devices!");
904291767Sdes		    break;
905285206Sdes		}
906285206Sdes		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
907291767Sdes		    if (devs[i]->enabled)
908285206Sdes		    	slice_wizard(((Disk *)devs[i]->private));
909285206Sdes		}
910291767Sdes		if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written")))
911285206Sdes		    variable_set2(DISK_LABELLED, "yes");
912285206Sdes		DialogActive = TRUE;
913285206Sdes		record_label_chunks(devs);
914291767Sdes		clear_wins();
915285206Sdes	    }
916285206Sdes	    else
917285206Sdes		msg = "A most prudent choice!";
918285206Sdes	    break;
919285206Sdes
920285206Sdes	case 'Q':
921285206Sdes	    labeling = FALSE;
922285206Sdes	    break;
923285206Sdes
924291767Sdes	default:
925285206Sdes	    beep();
926291767Sdes	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
927291767Sdes	    msg = _msg;
928285206Sdes	    break;
929291767Sdes	}
930285206Sdes    }
931291767Sdes    return DITEM_SUCCESS | DITEM_RESTORE;
932291767Sdes}
933285206Sdes