label.c revision 15440
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.45 1996/04/28 03:27:08 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	devs[0]->enabled = TRUE;
107	if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE)
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    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(A_REVERSE);
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, A_REVERSE);
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, 48, "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, "The default target will be displayed in ");
468
469    attrset(A_REVERSE);
470    addstr("reverse");
471    attrset(A_NORMAL);
472    addstr(" video.");
473    mvprintw(23, 0, "Use F1 or ? to get more help, arrow keys to move.");
474    move(0, 0);
475}
476
477static int
478diskLabel(char *str)
479{
480    int sz, key = 0, first_time = 1;
481    Boolean labeling;
482    char *msg = NULL;
483    PartInfo *p, *oldp;
484    PartType type;
485    Device **devs;
486    WINDOW *w;
487
488    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
489    if (!devs) {
490	msgConfirm("No disks found!");
491	return DITEM_FAILURE;
492    }
493
494    labeling = TRUE;
495    keypad(stdscr, TRUE);
496    record_label_chunks(devs);
497
498    w = savescr();
499    dialog_clear(); clear();
500    while (labeling) {
501	print_label_chunks();
502	if (first_time) {
503	    print_command_summary();
504	    first_time = 0;
505	}
506	if (msg) {
507	    attrset(A_REVERSE); mvprintw(23, 0, msg); attrset(A_NORMAL);
508	    clrtoeol();
509	    beep();
510	    msg = NULL;
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		variable_set2(DISK_LABELLED, "yes");
835		diskLabelCommit(NULL);
836	    }
837	    break;
838
839	case '|':
840	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n"
841			  "This is an entirely undocumented feature which you are not\n"
842			  "expected to understand!")) {
843		int i;
844		Device **devs;
845		WINDOW *save = savescr();
846
847		dialog_clear();
848		end_dialog();
849		DialogActive = FALSE;
850		devs = deviceFind(NULL, DEVICE_TYPE_DISK);
851		if (!devs) {
852		    msgConfirm("Can't find any disk devices!");
853		    break;
854		}
855		for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) {
856		    if (devs[i]->enabled)
857		    	slice_wizard(((Disk *)devs[i]->private));
858		}
859		variable_set2(DISK_LABELLED, "yes");
860		DialogActive = TRUE;
861		dialog_clear();
862		restorescr(save);
863		record_label_chunks(devs);
864	    }
865	    else
866		msg = "A most prudent choice!";
867	    break;
868
869	case 'Q':
870	    labeling = FALSE;
871	    break;
872
873	default:
874	    beep();
875	    msg = "Type F1 or ? for help";
876	    break;
877	}
878    }
879    restorescr(w);
880    return DITEM_SUCCESS;
881}
882