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