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