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