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