label.c revision 17397
1/*
2 * The new sysinstall program.
3 *
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
6 *
7 * $Id: label.c,v 1.56 1996/08/01 11:39:49 jkh Exp $
8 *
9 * Copyright (c) 1995
10 *	Jordan Hubbard.  All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer,
17 *    verbatim and that no modifications are made prior to this
18 *    point in the file.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36
37#include "sysinstall.h"
38#include <ctype.h>
39#include <sys/disklabel.h>
40#include <sys/param.h>
41#include <sys/sysctl.h>
42
43/*
44 * Everything to do with editing the contents of disk labels.
45 */
46
47/* A nice message we use a lot in the disklabel editor */
48#define MSG_NOT_APPLICABLE	"That option is not applicable here"
49
50/* Where to start printing the freebsd slices */
51#define CHUNK_SLICE_START_ROW		2
52#define CHUNK_PART_START_ROW		11
53
54/* The smallest filesystem we're willing to create */
55#define FS_MIN_SIZE			ONE_MEG
56
57/* The smallest root filesystem we're willing to create */
58#define ROOT_MIN_SIZE			20
59
60/* The smallest swap partition we want to create by default */
61#define SWAP_MIN_SIZE			16
62
63/* The smallest /usr partition we're willing to create by default */
64#define USR_MIN_SIZE			80
65
66/* The smallest /var partition we're willing to create by default */
67#define VAR_MIN_SIZE			30
68
69/* The bottom-most row we're allowed to scribble on */
70#define CHUNK_ROW_MAX		16
71
72
73/* All the chunks currently displayed on the screen */
74static struct {
75    struct chunk *c;
76    PartType type;
77} label_chunk_info[MAX_CHUNKS + 1];
78static int here;
79
80static int ChunkPartStartRow;
81static WINDOW *ChunkWin;
82
83static int diskLabel(char *str);
84
85int
86diskLabelEditor(dialogMenuItem *self)
87{
88    Device **devs;
89    int i, cnt, enabled;
90    char *cp;
91
92    cp = variable_get(VAR_DISK);
93    devs = deviceFind(cp, DEVICE_TYPE_DISK);
94    cnt = deviceCount(devs);
95    if (!cnt) {
96	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
97		   "properly probed at boot time.  See the Hardware Guide on the\n"
98		   "Documentation menu for clues on diagnosing this type of problem.");
99	return DITEM_FAILURE;
100    }
101    for (i = 0, enabled = 0; i < cnt; i++) {
102	if (devs[i]->enabled)
103	    ++enabled;
104    }
105    if (!enabled) {
106	msgConfirm("No disks have been selected.  Please visit the Partition\n"
107		   "editor first to specify which disks you wish to operate on.");
108	return DITEM_FAILURE;
109    }
110    i = diskLabel(devs[0]->name);
111    if (DITEM_STATUS(i) != DITEM_FAILURE)
112	variable_set2(DISK_LABELLED, "yes");
113    return i;
114}
115
116int
117diskLabelCommit(dialogMenuItem *self)
118{
119    char *cp;
120    int i;
121
122    /* Already done? */
123    if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes"))
124	i = DITEM_SUCCESS;
125    else if (!cp) {
126	msgConfirm("You must assign disk labels before this option can be used.");
127	i = DITEM_FAILURE;
128    }
129    /* The routine will guard against redundant writes, just as this one does */
130    else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS)
131	i = DITEM_FAILURE;
132    else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS)
133	i = DITEM_FAILURE;
134    else {
135	msgInfo("All filesystem information written successfully.");
136	variable_set2(DISK_LABELLED, "written");
137	i = DITEM_SUCCESS;
138    }
139    return i;
140}
141
142/* See if we're already using a desired partition name */
143static Boolean
144check_conflict(char *name)
145{
146    int i;
147
148    for (i = 0; label_chunk_info[i].c; i++)
149	if (label_chunk_info[i].type == PART_FILESYSTEM && label_chunk_info[i].c->private_data
150	    && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name))
151	    return TRUE;
152    return FALSE;
153}
154
155/* How much space is in this FreeBSD slice? */
156static int
157space_free(struct chunk *c)
158{
159    struct chunk *c1;
160    int sz = c->size;
161
162    for (c1 = c->part; c1; c1 = c1->next) {
163	if (c1->type != unused)
164	    sz -= c1->size;
165    }
166    if (sz < 0)
167	msgFatal("Partitions are larger than actual chunk??");
168    return sz;
169}
170
171/* Snapshot the current situation into the displayed chunks structure */
172static void
173record_label_chunks(Device **devs)
174{
175    int i, j, p;
176    struct chunk *c1, *c2;
177    Disk *d;
178
179    ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3;
180    j = p = 0;
181    /* First buzz through and pick up the FreeBSD slices */
182    for (i = 0; devs[i]; i++) {
183	if (!devs[i]->enabled)
184	    continue;
185	d = (Disk *)devs[i]->private;
186	if (!d->chunks)
187	    msgFatal("No chunk list found for %s!", d->name);
188
189	/* Put the slice entries first */
190	for (c1 = d->chunks->part; c1; c1 = c1->next) {
191	    if (c1->type == freebsd) {
192		label_chunk_info[j].type = PART_SLICE;
193		label_chunk_info[j].c = c1;
194		++j;
195		++ChunkPartStartRow;
196	    }
197	}
198    }
199
200    /* Now run through again and get the FreeBSD partition entries */
201    for (i = 0; devs[i]; i++) {
202	if (!devs[i]->enabled)
203	    continue;
204	d = (Disk *)devs[i]->private;
205	/* Then buzz through and pick up the partitions */
206	for (c1 = d->chunks->part; c1; c1 = c1->next) {
207	    if (c1->type == freebsd) {
208		for (c2 = c1->part; c2; c2 = c2->next) {
209		    if (c2->type == part) {
210			if (c2->subtype == FS_SWAP)
211			    label_chunk_info[j].type = PART_SWAP;
212			else
213			    label_chunk_info[j].type = PART_FILESYSTEM;
214			label_chunk_info[j].c = c2;
215			++j;
216		    }
217		}
218	    }
219	    else if (c1->type == fat) {
220		label_chunk_info[j].type = PART_FAT;
221		label_chunk_info[j].c = c1;
222		++j;
223	    }
224	}
225    }
226    label_chunk_info[j].c = NULL;
227    if (here >= j)
228	here = j  ? j - 1 : 0;
229    if (ChunkWin) {
230	wclear(ChunkWin);
231	wrefresh(ChunkWin);
232    }
233    else
234	ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0);
235}
236
237/* A new partition entry */
238static PartInfo *
239new_part(char *mpoint, Boolean newfs, u_long size)
240{
241    PartInfo *ret;
242
243    if (!mpoint)
244	mpoint = "/change_me";
245
246    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
247    strncpy(ret->mountpoint, mpoint, FILENAME_MAX);
248    strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024");
249    ret->newfs = newfs;
250    if (!size)
251	    return ret;
252    return ret;
253}
254
255/* Get the mountpoint for a partition and save it away */
256static PartInfo *
257get_mountpoint(struct chunk *old)
258{
259    char *val;
260    PartInfo *tmp;
261
262    if (old && old->private_data)
263	tmp = old->private_data;
264    else
265	tmp = NULL;
266    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
267    if (!val || !*val) {
268	if (!old)
269	    return NULL;
270	else {
271	    free(old->private_data);
272	    old->private_data = NULL;
273	}
274	return NULL;
275    }
276
277    /* Is it just the same value? */
278    if (tmp && !strcmp(tmp->mountpoint, val))
279	return NULL;
280
281    /* Did we use it already? */
282    if (check_conflict(val)) {
283	msgConfirm("You already have a mount point for %s assigned!", val);
284	return NULL;
285    }
286
287    /* Is it bogus? */
288    if (*val != '/') {
289	msgConfirm("Mount point must start with a / character");
290	return NULL;
291    }
292
293    /* Is it going to be mounted on root? */
294    if (!strcmp(val, "/")) {
295	if (old)
296	    old->flags |= CHUNK_IS_ROOT;
297    }
298    else if (old)
299	old->flags &= ~CHUNK_IS_ROOT;
300
301    safe_free(tmp);
302    tmp = new_part(val, TRUE, 0);
303    if (old) {
304	old->private_data = tmp;
305	old->private_free = safe_free;
306    }
307    return tmp;
308}
309
310/* Get the type of the new partiton */
311static PartType
312get_partition_type(void)
313{
314    char selection[20];
315    int i;
316    WINDOW *save = savescr();
317
318    static unsigned char *fs_types[] = {
319	"FS",
320	"A file system",
321	"Swap",
322	"A swap partition.",
323    };
324    dialog_clear();
325    i = dialog_menu("Please choose a partition type",
326		    "If you want to use this partition for swap space, select Swap.\n"
327		    "If you want to put a filesystem on it, choose FS.",
328		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
329    restorescr(save);
330    if (!i) {
331	if (!strcmp(selection, "FS"))
332	    return PART_FILESYSTEM;
333	else if (!strcmp(selection, "Swap"))
334	    return PART_SWAP;
335    }
336    return PART_NONE;
337}
338
339/* If the user wants a special newfs command for this, set it */
340static void
341getNewfsCmd(PartInfo *p)
342{
343    char *val;
344
345    val = msgGetInput(p->newfs_cmd,
346		      "Please enter the newfs command and options you'd like to use in\n"
347		      "creating this file system.");
348    if (val)
349	strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
350}
351
352#define MAX_MOUNT_NAME	12
353
354#define PART_PART_COL	0
355#define PART_MOUNT_COL	8
356#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
357#define PART_NEWFS_COL	(PART_SIZE_COL + 7)
358#define PART_OFF	38
359
360/* stick this all up on the screen */
361static void
362print_label_chunks(void)
363{
364    int i, j, srow, prow, pcol;
365    int sz;
366
367    attrset(A_REVERSE);
368    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
369    attrset(A_NORMAL);
370
371    for (i = 0; i < 2; i++) {
372	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
373	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
374
375	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
376	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
377
378	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
379	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
380
381	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
382	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
383    }
384    srow = CHUNK_SLICE_START_ROW;
385    prow = 0;
386    pcol = 0;
387
388    for (i = 0; label_chunk_info[i].c; i++) {
389	/* Is it a slice entry displayed at the top? */
390	if (label_chunk_info[i].type == PART_SLICE) {
391	    sz = space_free(label_chunk_info[i].c);
392	    if (i == here)
393		attrset(ATTR_SELECTED);
394	    mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
395		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG));
396	    attrset(A_NORMAL);
397	    clrtoeol();
398	    move(0, 0);
399	    refresh();
400	}
401	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
402	else {
403	    char onestr[PART_OFF], num[10], *mountpoint, *newfs;
404
405	    /*
406	     * We copy this into a blank-padded string so that it looks like
407	     * a solid bar in reverse-video
408	     */
409	    memset(onestr, ' ', PART_OFF - 1);
410	    onestr[PART_OFF - 1] = '\0';
411	    /* Go for two columns if we've written one full columns worth */
412	    if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) {
413		pcol = PART_OFF;
414		prow = 0;
415	    }
416	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
417	    /* If it's a filesystem, display the mountpoint */
418	    if (label_chunk_info[i].c->private_data
419		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
420	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
421	    else
422	        mountpoint = "<none>";
423
424	    /* Now display the newfs field */
425	    if (label_chunk_info[i].type == PART_FAT)
426	        newfs = "DOS";
427	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM)
428		newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N";
429	    else if (label_chunk_info[i].type == PART_SWAP)
430		newfs = "SWAP";
431	    else
432		newfs = "*";
433	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
434		onestr[PART_MOUNT_COL + j] = mountpoint[j];
435	    snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
436	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
437	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
438	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
439	    if (i == here)
440		wattrset(ChunkWin, ATTR_SELECTED);
441	    mvwaddstr(ChunkWin, prow, pcol, onestr);
442	    wattrset(ChunkWin, A_NORMAL);
443	    wrefresh(ChunkWin);
444	    move(0, 0);
445	    ++prow;
446	}
447    }
448}
449
450static void
451print_command_summary()
452{
453    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
454    mvprintw(18, 0, "C = Create      D = Delete         M = Mount");
455    if (!RunningAsInit)
456	mvprintw(18, 47, "W = Write");
457    mvprintw(19, 0, "N = Newfs Opts  T = Newfs Toggle   U = Undo    Q = Finish");
458    mvprintw(20, 0, "A = Auto Defaults for all!");
459    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
460    move(0, 0);
461}
462
463static int
464diskLabel(char *str)
465{
466    int sz, key = 0, first_time = 1;
467    Boolean labeling;
468    char *msg = NULL;
469    PartInfo *p, *oldp;
470    PartType type;
471    Device **devs;
472
473    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
474    if (!devs) {
475	msgConfirm("No disks found!");
476	return DITEM_FAILURE;
477    }
478
479    labeling = TRUE;
480    keypad(stdscr, TRUE);
481    record_label_chunks(devs);
482
483    dialog_clear(); clear();
484    while (labeling) {
485	print_label_chunks();
486	if (first_time) {
487	    print_command_summary();
488	    first_time = 0;
489	}
490	if (msg) {
491	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
492	    clrtoeol();
493	    beep();
494	    msg = NULL;
495	}
496	else {
497	    move(23, 0);
498	    clrtoeol();
499	}
500	key = getch();
501	switch (toupper(key)) {
502	    int i;
503	    static char _msg[40];
504
505	case '\014':	/* ^L */
506	    continue;
507
508	case KEY_UP:
509	case '-':
510	    if (here != 0)
511		--here;
512	    else
513		while (label_chunk_info[here + 1].c)
514		    ++here;
515	    break;
516
517	case KEY_DOWN:
518	case '+':
519	case '\r':
520	case '\n':
521	    if (label_chunk_info[here + 1].c)
522		++here;
523	    else
524		here = 0;
525	    break;
526
527	case KEY_HOME:
528	    here = 0;
529	    break;
530
531	case KEY_END:
532	    while (label_chunk_info[here + 1].c)
533		++here;
534	    break;
535
536	case KEY_F(1):
537	case '?':
538	    systemDisplayHelp("partition");
539	    break;
540
541	case 'A':
542	    if (label_chunk_info[here].type != PART_SLICE) {
543		msg = "You can only do this in a disk slice (at top of screen)";
544		break;
545	    }
546	    sz = space_free(label_chunk_info[here].c);
547	    if (sz <= FS_MIN_SIZE)
548		msg = "Not enough free space to create a new partition in the slice";
549	    else {
550		struct chunk *tmp;
551		int mib[2];
552		int physmem;
553		size_t size, swsize;
554		char *cp;
555		Chunk *rootdev, *swapdev, *usrdev, *vardev;
556
557		(void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev);
558		if (!rootdev) {
559		    cp = variable_get(VAR_ROOT_SIZE);
560		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
561					    (cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS,  CHUNK_IS_ROOT);
562		    if (!tmp) {
563			msgConfirm("Unable to create the root partition. Too big?");
564			break;
565		    }
566		    tmp->private_data = new_part("/", TRUE, tmp->size);
567		    tmp->private_free = safe_free;
568		    record_label_chunks(devs);
569		}
570
571		if (!swapdev) {
572		    cp = variable_get(VAR_SWAP_SIZE);
573		    if (cp)
574			swsize = atoi(cp) * ONE_MEG;
575		    else {
576			mib[0] = CTL_HW;
577			mib[1] = HW_PHYSMEM;
578			size = sizeof physmem;
579			sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
580			swsize = 16 * ONE_MEG + (physmem * 2 / 512);
581		    }
582		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
583					    swsize, part, FS_SWAP, 0);
584		    if (!tmp) {
585			msgConfirm("Unable to create the swap partition. Too big?");
586			break;
587		    }
588		    tmp->private_data = 0;
589		    tmp->private_free = safe_free;
590		    record_label_chunks(devs);
591		}
592
593		if (!vardev) {
594		    cp = variable_get(VAR_VAR_SIZE);
595		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c,
596					    (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0);
597		    if (!tmp) {
598			msgConfirm("Less than %dMB free for /var - you will need to\n"
599				   "partition your disk manually with a custom install!",
600				   (cp ? atoi(cp) : VAR_MIN_SIZE));
601			break;
602		    }
603		    tmp->private_data = new_part("/var", TRUE, tmp->size);
604		    tmp->private_free = safe_free;
605		    record_label_chunks(devs);
606		}
607
608		if (!usrdev) {
609		    cp = variable_get(VAR_USR_SIZE);
610		    if (cp)
611			sz = atoi(cp) * ONE_MEG;
612		    else
613			sz = space_free(label_chunk_info[here].c);
614		    if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) {
615			msgConfirm("Less than %dMB free for /usr - you will need to\n"
616				   "partition your disk manually with a custom install!", USR_MIN_SIZE);
617			break;
618		    }
619
620		    tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
621					    label_chunk_info[here].c,
622					    sz, part, FS_BSDFFS, 0);
623		    if (!tmp) {
624			msgConfirm("Unable to create the /usr partition.  Not enough space?\n"
625				   "You will need to partition your disk manually with a custom install!");
626			break;
627		    }
628		    tmp->private_data = new_part("/usr", TRUE, tmp->size);
629		    tmp->private_free = safe_free;
630		    record_label_chunks(devs);
631		}
632		/* At this point, we're reasonably "labelled" */
633		variable_set2(DISK_LABELLED, "yes");
634	    }
635	    break;
636
637	case 'C':
638	    if (label_chunk_info[here].type != PART_SLICE) {
639		msg = "You can only do this in a master partition (see top of screen)";
640		break;
641	    }
642	    sz = space_free(label_chunk_info[here].c);
643	    if (sz <= FS_MIN_SIZE) {
644		msg = "Not enough space to create an additional FreeBSD partition";
645		break;
646	    }
647	    else {
648		char *val, *cp;
649		int size;
650		struct chunk *tmp;
651		char osize[80];
652		u_long flags = 0;
653
654		sprintf(osize, "%d", sz);
655		val = msgGetInput(osize, "Please specify the size for new FreeBSD partition in blocks, or\n"
656				  "append a trailing `M' for megabytes (e.g. 20M) or `C' for cylinders.\n\n"
657				  "Space free is %d blocks (%dMB)", sz, sz / ONE_MEG);
658		if (!val || (size = strtol(val, &cp, 0)) <= 0)
659		    break;
660
661		if (*cp) {
662		    if (toupper(*cp) == 'M')
663			size *= ONE_MEG;
664		    else if (toupper(*cp) == 'C')
665			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
666		}
667		if (size <= FS_MIN_SIZE) {
668		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
669		    break;
670		}
671		type = get_partition_type();
672		if (type == PART_NONE)
673		    break;
674
675		if (type == PART_FILESYSTEM) {
676		    if ((p = get_mountpoint(NULL)) == NULL)
677			break;
678		    else if (!strcmp(p->mountpoint, "/"))
679			flags |= CHUNK_IS_ROOT;
680		    else
681			flags &= ~CHUNK_IS_ROOT;
682		} else
683		    p = NULL;
684
685		if ((flags & CHUNK_IS_ROOT)) {
686		    if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
687			msgConfirm("This region cannot be used for your root partition as the\n"
688				   "FreeBSD boot code cannot deal with a root partition created\n"
689				   "in that location.  Please choose another location or smaller\n"
690				   "size for your root partition and try again!");
691			break;
692		    }
693		    if (size < (ROOT_MIN_SIZE * ONE_MEG)) {
694			msgConfirm("Warning: This is smaller than the recommended size for a\n"
695				   "root partition.  For a variety of reasons, root\n"
696				   "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
697		    }
698		}
699		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
700					label_chunk_info[here].c,
701					size, part,
702					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
703					flags);
704		if (!tmp) {
705		    msgConfirm("Unable to create the partition. Too big?");
706		    break;
707		}
708		if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
709		    msgConfirm("This region cannot be used for your root partition as it starts\n"
710			       "or extends past the 1024'th cylinder mark and is thus a\n"
711			       "poor location to boot from.  Please choose another\n"
712			       "location (or smaller size) for your root partition and try again!");
713		    Delete_Chunk(label_chunk_info[here].c->disk, tmp);
714		    break;
715		}
716		if (type != PART_SWAP) {
717		    /* This is needed to tell the newfs -u about the size */
718		    tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
719		    safe_free(p);
720		}
721		else
722		    tmp->private_data = p;
723		tmp->private_free = safe_free;
724		variable_set2(DISK_LABELLED, "yes");
725		record_label_chunks(devs);
726	    }
727	    break;
728
729	case KEY_DC:
730	case 'D':	/* delete */
731	    if (label_chunk_info[here].type == PART_SLICE) {
732		msg = MSG_NOT_APPLICABLE;
733		break;
734	    }
735	    else if (label_chunk_info[here].type == PART_FAT) {
736		msg = "Use the Disk Partition Editor to delete DOS partitions";
737		break;
738	    }
739	    Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c);
740	    variable_set2(DISK_LABELLED, "yes");
741	    record_label_chunks(devs);
742	    break;
743
744	case 'M':	/* mount */
745	    switch(label_chunk_info[here].type) {
746	    case PART_SLICE:
747		msg = MSG_NOT_APPLICABLE;
748		break;
749
750	    case PART_SWAP:
751		msg = "You don't need to specify a mountpoint for a swap partition.";
752		break;
753
754	    case PART_FAT:
755	    case PART_FILESYSTEM:
756		oldp = label_chunk_info[here].c->private_data;
757		p = get_mountpoint(label_chunk_info[here].c);
758		if (p) {
759		    if (!oldp)
760		    	p->newfs = FALSE;
761		    if (label_chunk_info[here].type == PART_FAT
762			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
763			    || !strcmp(p->mountpoint, "/var"))) {
764			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
765			strcpy(p->mountpoint, "/bogus");
766		    }
767		}
768		variable_set2(DISK_LABELLED, "yes");
769		record_label_chunks(devs);
770		break;
771
772	    default:
773		msgFatal("Bogus partition under cursor???");
774		break;
775	    }
776	    break;
777
778	case 'N':	/* Set newfs options */
779	    if (label_chunk_info[here].c->private_data &&
780		((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
781		getNewfsCmd(label_chunk_info[here].c->private_data);
782	    else
783		msg = MSG_NOT_APPLICABLE;
784	    break;
785
786	case 'T':	/* Toggle newfs state */
787	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
788		    PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
789		    label_chunk_info[here].c->private_data =
790			new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
791		    safe_free(pi);
792		    label_chunk_info[here].c->private_free = safe_free;
793		    variable_set2(DISK_LABELLED, "yes");
794		}
795	    else
796		msg = MSG_NOT_APPLICABLE;
797	    break;
798
799	case 'U':
800	    clear();
801	    if (msgYesNo("Are you SURE you want to Undo everything?"))
802		break;
803	    variable_unset(DISK_PARTITIONED);
804	    variable_unset(DISK_LABELLED);
805	    for (i = 0; devs[i]; i++) {
806		Disk *d;
807
808		if (!devs[i]->enabled)
809		    continue;
810		else if ((d = Open_Disk(devs[i]->name)) != NULL) {
811		    Free_Disk(devs[i]->private);
812		    devs[i]->private = d;
813		    diskPartition(devs[i], d);
814		}
815	    }
816	    record_label_chunks(devs);
817	    break;
818
819	case 'W':
820	    if (!msgYesNo("You also have the option of doing this later in one final 'commit'\n"
821			  "operation, and it should also be noted that this option is NOT for\n"
822			  "use during new installations but rather for modifying existing ones.\n\n"
823			  "Are you absolutely SURE you want to do this now?")) {
824		WINDOW *save = savescr();
825
826		variable_set2(DISK_LABELLED, "yes");
827		diskLabelCommit(NULL);
828		restorescr(save);
829	    }
830	    break;
831
832	case '|':
833	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n"
834			  "This is an entirely undocumented feature which you are not\n"
835			  "expected to understand!")) {
836		int i;
837		Device **devs;
838		WINDOW *save = savescr();
839
840		dialog_clear();
841		end_dialog();
842		DialogActive = FALSE;
843		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
844		if (!devs) {
845		    msgConfirm("Can't find any disk devices!");
846		    break;
847		}
848		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
849		    if (devs[i]->enabled)
850		    	slice_wizard(((Disk *)devs[i]->private));
851		}
852		variable_set2(DISK_LABELLED, "yes");
853		DialogActive = TRUE;
854		dialog_clear();
855		restorescr(save);
856		record_label_chunks(devs);
857	    }
858	    else
859		msg = "A most prudent choice!";
860	    break;
861
862	case 'Q':
863	    labeling = FALSE;
864	    break;
865
866	default:
867	    beep();
868	    sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key);
869	    msg = _msg;
870	    break;
871	}
872    }
873    return DITEM_SUCCESS | DITEM_RESTORE;
874}
875