label.c revision 17025
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.50 1996/06/08 09:08:41 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    u_long target, divisor;
243
244    if (!mpoint)
245	mpoint = "/change_me";
246
247    ret = (PartInfo *)safe_malloc(sizeof(PartInfo));
248    strncpy(ret->mountpoint, mpoint, FILENAME_MAX);
249    strcpy(ret->newfs_cmd, "newfs -b 8192 -f 1024");
250    ret->newfs = newfs;
251    if (!size)
252	    return ret;
253    for (target = size; target; target--) {
254	for (divisor = 4096 ; divisor > 1023; divisor--) {
255	    if (!(target % divisor)) {
256		sprintf(ret->newfs_cmd + strlen(ret->newfs_cmd), " -u %ld",divisor);
257		return ret;
258	    }
259	}
260    }
261    return ret;
262}
263
264/* Get the mountpoint for a partition and save it away */
265static PartInfo *
266get_mountpoint(struct chunk *old)
267{
268    char *val;
269    PartInfo *tmp;
270
271    if (old && old->private_data)
272	tmp = old->private_data;
273    else
274	tmp = NULL;
275    val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition");
276    if (!val || !*val) {
277	if (!old)
278	    return NULL;
279	else {
280	    free(old->private_data);
281	    old->private_data = NULL;
282	}
283	return NULL;
284    }
285
286    /* Is it just the same value? */
287    if (tmp && !strcmp(tmp->mountpoint, val))
288	return NULL;
289
290    /* Did we use it already? */
291    if (check_conflict(val)) {
292	msgConfirm("You already have a mount point for %s assigned!", val);
293	return NULL;
294    }
295
296    /* Is it bogus? */
297    if (*val != '/') {
298	msgConfirm("Mount point must start with a / character");
299	return NULL;
300    }
301
302    /* Is it going to be mounted on root? */
303    if (!strcmp(val, "/")) {
304	if (old)
305	    old->flags |= CHUNK_IS_ROOT;
306    }
307    else if (old)
308	old->flags &= ~CHUNK_IS_ROOT;
309
310    safe_free(tmp);
311    tmp = new_part(val, TRUE, 0);
312    if (old) {
313	old->private_data = tmp;
314	old->private_free = safe_free;
315    }
316    return tmp;
317}
318
319/* Get the type of the new partiton */
320static PartType
321get_partition_type(void)
322{
323    char selection[20];
324    int i;
325    WINDOW *w = savescr();
326
327    static unsigned char *fs_types[] = {
328	"FS",
329	"A file system",
330	"Swap",
331	"A swap partition.",
332    };
333    i = dialog_menu("Please choose a partition type",
334		    "If you want to use this partition for swap space, select Swap.\n"
335		    "If you want to put a filesystem on it, choose FS.",
336		    -1, -1, 2, 2, fs_types, selection, NULL, NULL);
337    restorescr(w);
338    if (!i) {
339	if (!strcmp(selection, "FS"))
340	    return PART_FILESYSTEM;
341	else if (!strcmp(selection, "Swap"))
342	    return PART_SWAP;
343    }
344    return PART_NONE;
345}
346
347/* If the user wants a special newfs command for this, set it */
348static void
349getNewfsCmd(PartInfo *p)
350{
351    char *val;
352
353    val = msgGetInput(p->newfs_cmd,
354		      "Please enter the newfs command and options you'd like to use in\n"
355		      "creating this file system.");
356    if (val)
357	strncpy(p->newfs_cmd, val, NEWFS_CMD_MAX);
358}
359
360#define MAX_MOUNT_NAME	12
361
362#define PART_PART_COL	0
363#define PART_MOUNT_COL	8
364#define PART_SIZE_COL	(PART_MOUNT_COL + MAX_MOUNT_NAME + 3)
365#define PART_NEWFS_COL	(PART_SIZE_COL + 7)
366#define PART_OFF	38
367
368/* stick this all up on the screen */
369static void
370print_label_chunks(void)
371{
372    int i, j, srow, prow, pcol;
373    int sz;
374
375    attrset(A_REVERSE);
376    mvaddstr(0, 25, "FreeBSD Disklabel Editor");
377    attrset(A_NORMAL);
378
379    for (i = 0; i < 2; i++) {
380	mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part");
381	mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----");
382
383	mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount");
384	mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----");
385
386	mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 2, "Size");
387	mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----");
388
389	mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs");
390	mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----");
391    }
392    srow = CHUNK_SLICE_START_ROW;
393    prow = 0;
394    pcol = 0;
395
396    for (i = 0; label_chunk_info[i].c; i++) {
397	/* Is it a slice entry displayed at the top? */
398	if (label_chunk_info[i].type == PART_SLICE) {
399	    sz = space_free(label_chunk_info[i].c);
400	    if (i == here)
401		attrset(ATTR_SELECTED);
402	    mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)",
403		     label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG));
404	    attrset(A_NORMAL);
405	    clrtoeol();
406	    move(0, 0);
407	    refresh();
408	}
409	/* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */
410	else {
411	    char onestr[PART_OFF], num[10], *mountpoint, *newfs;
412
413	    /*
414	     * We copy this into a blank-padded string so that it looks like
415	     * a solid bar in reverse-video
416	     */
417	    memset(onestr, ' ', PART_OFF - 1);
418	    onestr[PART_OFF - 1] = '\0';
419	    /* Go for two columns if we've written one full columns worth */
420	    if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) {
421		pcol = PART_OFF;
422		prow = 0;
423	    }
424	    memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name));
425	    /* If it's a filesystem, display the mountpoint */
426	    if (label_chunk_info[i].c->private_data
427		&& (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT))
428	        mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint;
429	    else
430	        mountpoint = "<none>";
431
432	    /* Now display the newfs field */
433	    if (label_chunk_info[i].type == PART_FAT)
434	        newfs = "DOS";
435	    else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM)
436		newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N";
437	    else if (label_chunk_info[i].type == PART_SWAP)
438		newfs = "SWAP";
439	    else
440		newfs = "*";
441	    for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++)
442		onestr[PART_MOUNT_COL + j] = mountpoint[j];
443	    snprintf(num, 10, "%4ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0);
444	    memcpy(onestr + PART_SIZE_COL, num, strlen(num));
445	    memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs));
446	    onestr[PART_NEWFS_COL + strlen(newfs)] = '\0';
447	    if (i == here)
448		wattrset(ChunkWin, ATTR_SELECTED);
449	    mvwaddstr(ChunkWin, prow, pcol, onestr);
450	    wattrset(ChunkWin, A_NORMAL);
451	    wrefresh(ChunkWin);
452	    move(0, 0);
453	    ++prow;
454	}
455    }
456}
457
458static void
459print_command_summary()
460{
461    mvprintw(17, 0, "The following commands are valid here (upper or lower case):");
462    mvprintw(18, 0, "C = Create      D = Delete         M = Mount");
463    if (!RunningAsInit)
464	mvprintw(18, 47, "W = Write");
465    mvprintw(19, 0, "N = Newfs Opts  T = Newfs Toggle   U = Undo    Q = Finish");
466    mvprintw(20, 0, "A = Auto Defaults for all!");
467    mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select.");
468    move(0, 0);
469}
470
471static int
472diskLabel(char *str)
473{
474    int sz, key = 0, first_time = 1;
475    Boolean labeling;
476    char *msg = NULL;
477    PartInfo *p, *oldp;
478    PartType type;
479    Device **devs;
480    WINDOW *w;
481
482    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
483    if (!devs) {
484	msgConfirm("No disks found!");
485	return DITEM_FAILURE;
486    }
487
488    labeling = TRUE;
489    keypad(stdscr, TRUE);
490    record_label_chunks(devs);
491
492    w = savescr();
493    dialog_clear(); clear();
494    while (labeling) {
495	print_label_chunks();
496	if (first_time) {
497	    print_command_summary();
498	    first_time = 0;
499	}
500	if (msg) {
501	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
502	    clrtoeol();
503	    beep();
504	    msg = NULL;
505	}
506	else {
507	    move(23, 0);
508	    clrtoeol();
509	}
510	key = toupper(getch());
511	switch (key) {
512	    int i;
513
514	case '\014':	/* ^L */
515	    continue;
516
517	case KEY_UP:
518	case '-':
519	    if (here != 0)
520		--here;
521	    else
522		while (label_chunk_info[here + 1].c)
523		    ++here;
524	    break;
525
526	case KEY_DOWN:
527	case '+':
528	case '\r':
529	case '\n':
530	    if (label_chunk_info[here + 1].c)
531		++here;
532	    else
533		here = 0;
534	    break;
535
536	case KEY_HOME:
537	    here = 0;
538	    break;
539
540	case KEY_END:
541	    while (label_chunk_info[here + 1].c)
542		++here;
543	    break;
544
545	case KEY_F(1):
546	case '?':
547	    systemDisplayHelp("partition");
548	    break;
549
550	case 'A':
551	    if (label_chunk_info[here].type != PART_SLICE) {
552		msg = "You can only do this in a disk slice (at top of screen)";
553		break;
554	    }
555	    sz = space_free(label_chunk_info[here].c);
556	    if (sz <= FS_MIN_SIZE) {
557		msg = "Not enough free space to create a new partition in the slice";
558		break;
559	    }
560	    else {
561		struct chunk *tmp;
562		int mib[2];
563		int physmem;
564		size_t size, swsize;
565		char *cp;
566
567		cp = variable_get(VAR_ROOT_SIZE);
568		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
569					label_chunk_info[here].c,
570					(cp ? atoi(cp) : 32) * ONE_MEG, part, FS_BSDFFS,
571					CHUNK_IS_ROOT);
572
573		if (!tmp) {
574		    msgConfirm("Unable to create the root partition. Too big?");
575		    break;
576		}
577		tmp->private_data = new_part("/", TRUE, tmp->size);
578		tmp->private_free = safe_free;
579		record_label_chunks(devs);
580
581		cp = variable_get(VAR_SWAP_SIZE);
582		if (cp)
583		    swsize = atoi(cp) * ONE_MEG;
584		else {
585		    mib[0] = CTL_HW;
586		    mib[1] = HW_PHYSMEM;
587		    size = sizeof physmem;
588		    sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0);
589		    swsize = 16 * ONE_MEG + (physmem * 2 / 512);
590		}
591		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
592					label_chunk_info[here].c,
593					swsize,
594					part, FS_SWAP, 0);
595		if (!tmp) {
596		    msgConfirm("Unable to create the swap partition. Too big?");
597		    break;
598		}
599
600		tmp->private_data = 0;
601		tmp->private_free = safe_free;
602		record_label_chunks(devs);
603
604		cp = variable_get(VAR_VAR_SIZE);
605		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
606					label_chunk_info[here].c,
607					(cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, part, FS_BSDFFS, 0);
608		if (!tmp) {
609		    msgConfirm("Less than %dMB free for /var - you will need to\n"
610			       "partition your disk manually with a custom install!", (cp ? atoi(cp) : VAR_MIN_SIZE));
611		    break;
612		}
613		tmp->private_data = new_part("/var", TRUE, tmp->size);
614		tmp->private_free = safe_free;
615		record_label_chunks(devs);
616
617		cp = variable_get(VAR_USR_SIZE);
618		if (cp)
619		    sz = atoi(cp) * ONE_MEG;
620		else
621		    sz = space_free(label_chunk_info[here].c);
622		if (!sz || sz < (USR_MIN_SIZE * ONE_MEG)) {
623		    msgConfirm("Less than %dMB free for /usr - you will need to\n"
624			       "partition your disk manually with a custom install!", USR_MIN_SIZE);
625		    break;
626		}
627
628		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
629					label_chunk_info[here].c,
630					sz, part, FS_BSDFFS, 0);
631		if (!tmp) {
632		    msgConfirm("Unable to create the /usr partition.  Not enough space?\n"
633			       "You will need to partition your disk manually with a custom install!");
634		    break;
635		}
636		/* At this point, we're reasonably "labelled" */
637		variable_set2(DISK_LABELLED, "yes");
638		tmp->private_data = new_part("/usr", TRUE, tmp->size);
639		tmp->private_free = safe_free;
640		record_label_chunks(devs);
641	    }
642	    break;
643
644	case 'C':
645	    if (label_chunk_info[here].type != PART_SLICE) {
646		msg = "You can only do this in a master partition (see top of screen)";
647		break;
648	    }
649	    sz = space_free(label_chunk_info[here].c);
650	    if (sz <= FS_MIN_SIZE) {
651		msg = "Not enough space to create an additional FreeBSD partition";
652		break;
653	    }
654	    else {
655		char *val, *cp;
656		int size;
657		struct chunk *tmp;
658		char osize[80];
659		u_long flags = 0;
660
661		sprintf(osize, "%d", sz);
662		val = msgGetInput(osize, "Please specify the size for new FreeBSD partition in blocks, or\n"
663				  "append a trailing `M' for megabytes (e.g. 20M) or `C' for cylinders.\n\n"
664				  "Space free is %d blocks (%dMB)", sz, sz / ONE_MEG);
665		if (!val || (size = strtol(val, &cp, 0)) <= 0)
666		    break;
667
668		if (*cp) {
669		    if (toupper(*cp) == 'M')
670			size *= ONE_MEG;
671		    else if (toupper(*cp) == 'C')
672			size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect);
673		}
674		if (size <= FS_MIN_SIZE) {
675		    msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG);
676		    break;
677		}
678		type = get_partition_type();
679		if (type == PART_NONE)
680		    break;
681
682		if (type == PART_FILESYSTEM) {
683		    if ((p = get_mountpoint(NULL)) == NULL)
684			break;
685		    else if (!strcmp(p->mountpoint, "/"))
686			flags |= CHUNK_IS_ROOT;
687		    else
688			flags &= ~CHUNK_IS_ROOT;
689		} else
690		    p = NULL;
691
692		if ((flags & CHUNK_IS_ROOT)) {
693		    if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) {
694			msgConfirm("This region cannot be used for your root partition as the\n"
695				   "FreeBSD boot code cannot deal with a root partition created\n"
696				   "in that location.  Please choose another location or smaller\n"
697				   "size for your root partition and try again!");
698			break;
699		    }
700		    if (size < (ROOT_MIN_SIZE * ONE_MEG)) {
701			msgConfirm("Warning: This is smaller than the recommended size for a\n"
702				   "root partition.  For a variety of reasons, root\n"
703				   "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE);
704		    }
705		}
706		tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk,
707					label_chunk_info[here].c,
708					size, part,
709					(type == PART_SWAP) ? FS_SWAP : FS_BSDFFS,
710					flags);
711		if (!tmp) {
712		    msgConfirm("Unable to create the partition. Too big?");
713		    break;
714		}
715		if ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) {
716		    msgConfirm("This region cannot be used for your root partition as it starts\n"
717			       "or extends past the 1024'th cylinder mark and is thus a\n"
718			       "poor location to boot from.  Please choose another\n"
719			       "location (or smaller size) for your root partition and try again!");
720		    Delete_Chunk(label_chunk_info[here].c->disk, tmp);
721		    break;
722		}
723		if (type != PART_SWAP) {
724		    /* This is needed to tell the newfs -u about the size */
725		    tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size);
726		    tmp->private_free = safe_free;
727		    safe_free(p);
728		}
729		else
730		    tmp->private_data = p;
731		tmp->private_free = safe_free;
732		variable_set2(DISK_LABELLED, "yes");
733		record_label_chunks(devs);
734	    }
735	    break;
736
737	case '\177':
738	case 'D':	/* delete */
739	    if (label_chunk_info[here].type == PART_SLICE) {
740		msg = MSG_NOT_APPLICABLE;
741		break;
742	    }
743	    else if (label_chunk_info[here].type == PART_FAT) {
744		msg = "Use the Disk Partition Editor to delete DOS partitions";
745		break;
746	    }
747	    Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c);
748	    variable_set2(DISK_LABELLED, "yes");
749	    record_label_chunks(devs);
750	    break;
751
752	case 'M':	/* mount */
753	    switch(label_chunk_info[here].type) {
754	    case PART_SLICE:
755		msg = MSG_NOT_APPLICABLE;
756		break;
757
758	    case PART_SWAP:
759		msg = "You don't need to specify a mountpoint for a swap partition.";
760		break;
761
762	    case PART_FAT:
763	    case PART_FILESYSTEM:
764		oldp = label_chunk_info[here].c->private_data;
765		p = get_mountpoint(label_chunk_info[here].c);
766		if (p) {
767		    if (!oldp)
768		    	p->newfs = FALSE;
769		    if (label_chunk_info[here].type == PART_FAT
770			&& (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr")
771			    || !strcmp(p->mountpoint, "/var"))) {
772			msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint);
773			strcpy(p->mountpoint, "/bogus");
774		    }
775		}
776		variable_set2(DISK_LABELLED, "yes");
777		record_label_chunks(devs);
778		break;
779
780	    default:
781		msgFatal("Bogus partition under cursor???");
782		break;
783	    }
784	    break;
785
786	case 'N':	/* Set newfs options */
787	    if (label_chunk_info[here].c->private_data &&
788		((PartInfo *)label_chunk_info[here].c->private_data)->newfs)
789		getNewfsCmd(label_chunk_info[here].c->private_data);
790	    else
791		msg = MSG_NOT_APPLICABLE;
792	    break;
793
794	case 'T':	/* Toggle newfs state */
795	    if (label_chunk_info[here].type == PART_FILESYSTEM) {
796		    PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data);
797		    label_chunk_info[here].c->private_data =
798			new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size);
799		    safe_free(pi);
800		    label_chunk_info[here].c->private_free = safe_free;
801		    variable_set2(DISK_LABELLED, "yes");
802		}
803	    else
804		msg = MSG_NOT_APPLICABLE;
805	    break;
806
807	case 'U':
808	    clear();
809	    if (msgYesNo("Are you SURE you want to Undo everything?"))
810		break;
811	    variable_unset(DISK_PARTITIONED);
812	    variable_unset(DISK_LABELLED);
813	    for (i = 0; devs[i]; i++) {
814		Disk *d;
815
816		if (!devs[i]->enabled)
817		    continue;
818		else if ((d = Open_Disk(devs[i]->name)) != NULL) {
819		    Free_Disk(devs[i]->private);
820		    devs[i]->private = d;
821		    diskPartition(devs[i], d);
822		}
823	    }
824	    record_label_chunks(devs);
825	    break;
826
827	case 'W':
828	    if (!msgYesNo("You also have the option of doing this later in one final 'commit'\n"
829			  "operation, and it should also be noted that this option is NOT for\n"
830			  "use during new installations but rather for modifying existing ones.\n\n"
831			  "Are you absolutely SURE you want to do this now?")) {
832		WINDOW *save = savescr();
833
834		variable_set2(DISK_LABELLED, "yes");
835		diskLabelCommit(NULL);
836		restorescr(save);
837	    }
838	    break;
839
840	case '|':
841	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n"
842			  "This is an entirely undocumented feature which you are not\n"
843			  "expected to understand!")) {
844		int i;
845		Device **devs;
846		WINDOW *save = savescr();
847
848		dialog_clear();
849		end_dialog();
850		DialogActive = FALSE;
851		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
852		if (!devs) {
853		    msgConfirm("Can't find any disk devices!");
854		    break;
855		}
856		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
857		    if (devs[i]->enabled)
858		    	slice_wizard(((Disk *)devs[i]->private));
859		}
860		variable_set2(DISK_LABELLED, "yes");
861		DialogActive = TRUE;
862		dialog_clear();
863		restorescr(save);
864		record_label_chunks(devs);
865	    }
866	    else
867		msg = "A most prudent choice!";
868	    break;
869
870	case 'Q':
871	    labeling = FALSE;
872	    break;
873
874	default:
875	    beep();
876	    msg = "Type F1 or ? for help";
877	    break;
878	}
879    }
880    restorescr(w);
881    return DITEM_SUCCESS;
882}
883