disks.c revision 29072
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: disks.c,v 1.88 1997/06/18 05:11:36 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
41/* Where we start displaying chunk information on the screen */
42#define CHUNK_START_ROW		5
43
44/* Where we keep track of MBR chunks */
45static struct chunk *chunk_info[16];
46static int current_chunk;
47
48static void	diskPartitionNonInteractive(Device *dev, Disk *d);
49
50static void
51record_chunks(Disk *d)
52{
53    struct chunk *c1 = NULL;
54    int i = 0;
55    int last_free = 0;
56
57    if (!d->chunks)
58	msgFatal("No chunk list found for %s!", d->name);
59
60    for (c1 = d->chunks->part; c1; c1 = c1->next) {
61	if (c1->type == unused && c1->size > last_free) {
62	    last_free = c1->size;
63	    current_chunk = i;
64	}
65	chunk_info[i++] = c1;
66    }
67    chunk_info[i] = NULL;
68    if (current_chunk >= i)
69	current_chunk = i - 1;
70}
71
72static int Total;
73
74static void
75print_chunks(Disk *d)
76{
77    int row;
78    int i;
79
80    for (i = Total = 0; chunk_info[i]; i++)
81	Total += chunk_info[i]->size;
82    if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) {
83	dialog_clear_norefresh();
84	msgConfirm("WARNING:  A geometry of %d/%d/%d for %s is incorrect.  Using\n"
85		   "a more likely geometry.  If this geometry is incorrect or you\n"
86		   "are unsure as to whether or not it's correct, please consult\n"
87		   "the Hardware Guide in the Documentation submenu or use the\n"
88		   "(G)eometry command to change it now.\n\n"
89		   "Remember: you need to enter whatever your BIOS thinks the\n"
90		   "geometry is!  For IDE, it's what you were told in the BIOS\n"
91		   "setup. For SCSI, it's the translation mode your controller is\n"
92		   "using.  Do NOT use a ``physical geometry''.",
93	  d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
94	Sanitize_Bios_Geom(d);
95    }
96    attrset(A_NORMAL);
97    mvaddstr(0, 0, "Disk name:\t");
98    clrtobot();
99    attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL);
100    attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL);
101    mvprintw(1, 0,
102	     "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors",
103	     d->bios_cyl, d->bios_hd, d->bios_sect,
104	     d->bios_cyl * d->bios_hd * d->bios_sect);
105    mvprintw(3, 1, "%10s %10s %10s %8s %8s %8s %8s %8s",
106	     "Offset", "Size", "End", "Name", "PType", "Desc",
107	     "Subtype", "Flags");
108    for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
109	if (i == current_chunk)
110	    attrset(ATTR_SELECTED);
111	mvprintw(row, 2, "%10ld %10lu %10lu %8s %8d %8s %8d\t%-6s",
112		 chunk_info[i]->offset, chunk_info[i]->size,
113		 chunk_info[i]->end, chunk_info[i]->name,
114		 chunk_info[i]->type,
115		 slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype),
116		 chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i]));
117	if (i == current_chunk)
118	    attrset(A_NORMAL);
119    }
120}
121
122static void
123print_command_summary()
124{
125    mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
126    mvprintw(16, 0, "A = Use Entire Disk    B = Bad Block Scan       C = Create Slice");
127    mvprintw(17, 0, "D = Delete Slice       G = Set Drive Geometry   S = Set Bootable");
128    mvprintw(18, 0, "U = Undo All Changes   Q = Finish");
129    if (!RunningAsInit)
130	mvprintw(18, 48, "W = Write Changes");
131    mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select.");
132    move(0, 0);
133}
134
135static u_char *
136getBootMgr(char *dname)
137{
138    extern u_char mbr[], bteasy17[];
139    char str[80];
140    char *cp;
141    int i = 0;
142
143    cp = variable_get(VAR_BOOTMGR);
144    if (!cp) {
145	/* Figure out what kind of MBR the user wants */
146	sprintf(str, "Install Boot Manager for drive %s?", dname);
147	MenuMBRType.title = str;
148	i = dmenuOpenSimple(&MenuMBRType, FALSE);
149    }
150    else {
151	if (!strncmp(cp, "boot", 4))
152	    BootMgr = 0;
153	else if (!strcmp(cp, "standard"))
154	    BootMgr = 1;
155	else
156	    BootMgr = 2;
157    }
158    if (cp || i) {
159	switch (BootMgr) {
160	case 0:
161	    return bteasy17;
162
163	case 1:
164	    return mbr;
165
166	case 2:
167	default:
168	    break;
169	}
170    }
171    return NULL;
172}
173
174void
175diskPartition(Device *dev, Disk *d)
176{
177    char *cp, *p;
178    int rv, key = 0;
179    Boolean chunking;
180    char *msg = NULL;
181    u_char *mbrContents;
182    WINDOW *w = savescr();
183
184    chunking = TRUE;
185    keypad(stdscr, TRUE);
186
187    /* Flush both the dialog and curses library views of the screen
188       since we don't always know who called us */
189    dialog_clear_norefresh(), clear();
190    current_chunk = 0;
191
192    /* Set up the chunk array */
193    record_chunks(d);
194
195    while (chunking) {
196	char *val, geometry[80];
197
198	/* Now print our overall state */
199	if (d)
200	    print_chunks(d);
201	print_command_summary();
202	if (msg) {
203	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
204	    beep();
205	    msg = NULL;
206	}
207	else {
208	    move(23, 0);
209	    clrtoeol();
210	}
211
212	/* Get command character */
213	key = getch();
214	switch (toupper(key)) {
215	case '\014':	/* ^L (redraw) */
216	    clear();
217	    msg = NULL;
218	    break;
219
220	case '\020':	/* ^P */
221	case KEY_UP:
222	case '-':
223	    if (current_chunk != 0)
224		--current_chunk;
225	    break;
226
227	case '\016':	/* ^N */
228	case KEY_DOWN:
229	case '+':
230	case '\r':
231	case '\n':
232	    if (chunk_info[current_chunk + 1])
233		++current_chunk;
234	    break;
235
236	case KEY_HOME:
237	    current_chunk = 0;
238	    break;
239
240	case KEY_END:
241	    while (chunk_info[current_chunk + 1])
242		++current_chunk;
243	    break;
244
245	case KEY_F(1):
246	case '?':
247	    systemDisplayHelp("slice");
248	    clear();
249	    break;
250
251	case 'A':
252	    cp = variable_get(VAR_DEDICATE_DISK);
253	    if (cp && !strcasecmp(cp, "always"))
254		rv = 1;
255	    else {
256		rv = msgYesNo("Do you want to do this with a true partition entry\n"
257			      "so as to remain cooperative with any future possible\n"
258			      "operating systems on the drive(s)?");
259		if (rv == -1)
260		    rv = 0;
261	    }
262	    All_FreeBSD(d, rv);
263	    variable_set2(DISK_PARTITIONED, "yes");
264	    record_chunks(d);
265	    clear();
266	    break;
267
268	case 'B':
269	    if (chunk_info[current_chunk]->type != freebsd)
270		msg = "Can only scan for bad blocks in FreeBSD slice.";
271	    else if (strncmp(d->name, "sd", 2) ||
272		     !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n"
273			       "Are you sure you want to do this on a SCSI disk?")) {
274		if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
275		    chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
276		else
277		    chunk_info[current_chunk]->flags |= CHUNK_BAD144;
278	    }
279	    clear();
280	    break;
281
282	case 'C':
283	    if (chunk_info[current_chunk]->type != unused)
284		msg = "Slice in use, delete it first or move to an unused one.";
285	    else {
286		char *val, tmp[20], *cp;
287		int size, subtype;
288		chunk_e partitiontype;
289
290		snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size);
291		val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n"
292				  "or append a trailing `M' for megabytes (e.g. 20M).");
293		if (val && (size = strtol(val, &cp, 0)) > 0) {
294		    if (*cp && toupper(*cp) == 'M')
295			size *= ONE_MEG;
296		    strcpy(tmp, "165");
297		    val = msgGetInput(tmp, "Enter type of partition to create:\n\n"
298				      "Pressing Enter will choose the default, a native FreeBSD\n"
299				      "slice (type 165).  You can choose other types, 6 for a\n"
300				      "DOS partition or 131 for a Linux partition, for example.\n\n"
301				      "Note:  If you choose a non-FreeBSD partition type, it will not\n"
302				      "be formatted or otherwise prepared, it will simply reserve space\n"
303				      "for you to use another tool, such as DOS FORMAT, to later format\n"
304				      "and use the partition.");
305		    if (val && (subtype = strtol(val, NULL, 0)) > 0) {
306			if (subtype==165)
307			    partitiontype=freebsd;
308			else if (subtype==6)
309			    partitiontype=fat;
310			else
311			    partitiontype=unknown;
312			Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype,
313				     (chunk_info[current_chunk]->flags & CHUNK_ALIGN));
314			variable_set2(DISK_PARTITIONED, "yes");
315			record_chunks(d);
316		    }
317		}
318		clear();
319	    }
320	    break;
321
322	case KEY_DC:
323	case 'D':
324	    if (chunk_info[current_chunk]->type == unused)
325		msg = "Slice is already unused!";
326	    else {
327		Delete_Chunk(d, chunk_info[current_chunk]);
328		variable_set2(DISK_PARTITIONED, "yes");
329		record_chunks(d);
330	    }
331	    break;
332
333	case 'G':
334	    snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect);
335	    val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n"
336			      "Don't forget to use the two slash (/) separator characters!\n"
337			      "It's not possible to parse the field without them.");
338	    if (val) {
339		long nc, nh, ns;
340		nc = strtol(val, &val, 0);
341		nh = strtol(val + 1, &val, 0);
342		ns = strtol(val + 1, 0, 0);
343		Set_Bios_Geom(d, nc, nh, ns);
344	    }
345	    clear();
346	    break;
347
348	case 'S':
349	    /* Set Bootable */
350	    chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
351	    break;
352
353	case 'U':
354	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
355		msgConfirm("You've already written this information out - you\n"
356			   "can't undo it.");
357	    }
358	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
359		char cp[BUFSIZ];
360
361		sstrncpy(cp, d->name, sizeof cp);
362		Free_Disk(dev->private);
363		d = Open_Disk(cp);
364		if (!d)
365		    msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp);
366		dev->private = d;
367		variable_unset(DISK_PARTITIONED);
368		variable_unset(DISK_LABELLED);
369		if (d)
370		    record_chunks(d);
371	    }
372	    clear();
373	    break;
374
375	case 'W':
376	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
377		msgConfirm("You've already written this information out - if\n"
378			   "you wish to overwrite it, you'll have to restart.");
379	    }
380	    else if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
381			       "installation.  If you are installing FreeBSD for the first time\n"
382			       "then you should simply type Q when you're finished here and your\n"
383			       "changes will be committed in one batch automatically at the end of\n"
384			       "these questions.\n\n"
385			       "Are you absolutely sure you want to do this now?")) {
386		variable_set2(DISK_PARTITIONED, "yes");
387
388		/* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
389		 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
390		 * booteasy or a "standard" MBR -- both would be fatal in this case.
391		 */
392		if (!(d->chunks->part->flags & CHUNK_FORCE_ALL) && (mbrContents = getBootMgr(d->name)) != NULL)
393		    Set_Boot_Mgr(d, mbrContents);
394
395		if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS)
396		    msgConfirm("Disk partition write returned an error status!");
397		else
398		    msgConfirm("Wrote FDISK partition information out successfully.");
399	    }
400	    clear();
401	    break;
402
403	case '|':
404	    if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n"
405			  "No seat belts whatsoever are provided!")) {
406		clear();
407		refresh();
408		slice_wizard(d);
409		variable_set2(DISK_PARTITIONED, "yes");
410		record_chunks(d);
411	    }
412	    else
413		msg = "Wise choice!";
414	    clear();
415	    break;
416
417	case '\033':	/* ESC */
418	case 'Q':
419	    chunking = FALSE;
420	    /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
421	     * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
422	     * booteasy or a "standard" MBR -- both would be fatal in this case.
423	     */
424	    if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
425		&& (mbrContents = getBootMgr(d->name)) != NULL)
426		Set_Boot_Mgr(d, mbrContents);
427	    break;
428
429	default:
430	    beep();
431	    msg = "Type F1 or ? for help";
432	    break;
433	}
434    }
435    p = CheckRules(d);
436    if (p) {
437	char buf[FILENAME_MAX];
438
439	dialog_clear_norefresh();
440        use_helpline("Press F1 to read more about disk slices.");
441	use_helpfile(systemHelpFile("partition", buf));
442	if (!variable_get(VAR_NO_WARN))
443	    dialog_mesgbox("Disk slicing warning:", p, -1, -1);
444	free(p);
445    }
446    restorescr(w);
447}
448
449static int
450partitionHook(dialogMenuItem *selected)
451{
452    Device **devs = NULL;
453
454    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
455    if (!devs) {
456	msgConfirm("Unable to find disk %s!", selected->prompt);
457	return DITEM_FAILURE;
458    }
459    /* Toggle enabled status? */
460    if (!devs[0]->enabled) {
461	devs[0]->enabled = TRUE;
462	diskPartition(devs[0], (Disk *)devs[0]->private);
463    }
464    else
465	devs[0]->enabled = FALSE;
466    return DITEM_SUCCESS | DITEM_REDRAW;
467}
468
469static int
470partitionCheck(dialogMenuItem *selected)
471{
472    Device **devs = NULL;
473
474    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
475    if (!devs || devs[0]->enabled == FALSE)
476	return FALSE;
477    return TRUE;
478}
479
480int
481diskPartitionEditor(dialogMenuItem *self)
482{
483    DMenu *menu;
484    Device **devs;
485    int i, cnt;
486    char *cp;
487
488    cp = variable_get(VAR_DISK);
489    devs = deviceFind(cp, DEVICE_TYPE_DISK);
490    cnt = deviceCount(devs);
491    if (!cnt) {
492	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
493		   "properly probed at boot time.  See the Hardware Guide on the\n"
494		   "Documentation menu for clues on diagnosing this type of problem.");
495	i = DITEM_FAILURE;
496    }
497    else if (cnt == 1) {
498	devs[0]->enabled = TRUE;
499	if (variable_get(VAR_NONINTERACTIVE))
500	    diskPartitionNonInteractive(devs[0], (Disk *)devs[0]->private);
501	else
502	    diskPartition(devs[0], (Disk *)devs[0]->private);
503	i = DITEM_SUCCESS;
504    }
505    else {
506	menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck);
507	if (!menu) {
508	    msgConfirm("No devices suitable for installation found!\n\n"
509		       "Please verify that your disk controller (and attached drives)\n"
510		       "were detected properly.  This can be done by pressing the\n"
511		       "[Scroll Lock] key and using the Arrow keys to move back to\n"
512		       "the boot messages.  Press [Scroll Lock] again to return.");
513	    i = DITEM_FAILURE;
514	}
515	else {
516	    i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
517	    free(menu);
518	}
519	i = i | DITEM_RESTORE;
520    }
521    return i;
522}
523
524int
525diskPartitionWrite(dialogMenuItem *self)
526{
527    Device **devs;
528    char *cp;
529    int i;
530
531    if ((cp = variable_get(DISK_PARTITIONED)) && strcmp(cp, "yes"))
532	return DITEM_SUCCESS;
533    else if (!cp) {
534	msgConfirm("You must partition the disk(s) before this option can be used.");
535	return DITEM_FAILURE;
536    }
537
538    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
539    if (!devs) {
540	msgConfirm("Unable to find any disks to write to??");
541	return DITEM_FAILURE;
542    }
543    if (isDebug())
544	msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs));
545
546    for (i = 0; devs[i]; i++) {
547	Chunk *c1;
548	Disk *d = (Disk *)devs[i]->private;
549
550	if (!devs[i]->enabled)
551	    continue;
552
553	Set_Boot_Blocks(d, boot1, boot2);
554	msgNotify("Writing partition information to drive %s", d->name);
555	if (!Fake && Write_Disk(d)) {
556	    msgConfirm("ERROR: Unable to write data to disk %s!", d->name);
557	    return DITEM_FAILURE;
558	}
559	/* Now scan for bad blocks, if necessary */
560	for (c1 = d->chunks->part; c1; c1 = c1->next) {
561	    if (c1->flags & CHUNK_BAD144) {
562		int ret;
563
564		msgNotify("Running bad block scan on slice %s", c1->name);
565		if (!Fake) {
566		    ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
567		    if (ret)
568			msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
569		    ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
570		    if (ret)
571			msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
572		}
573	    }
574	}
575    }
576    /* Now it's not "yes", but "written" */
577    variable_set2(DISK_PARTITIONED, "written");
578    return DITEM_SUCCESS;
579}
580
581/* Partition a disk based wholly on which variables are set */
582static void
583diskPartitionNonInteractive(Device *dev, Disk *d)
584{
585    char *cp;
586    int i, sz, all_disk = 0;
587    u_char *mbrContents;
588
589    record_chunks(d);
590    cp = variable_get(VAR_GEOMETRY);
591    if (cp) {
592	msgDebug("Setting geometry from script to: %s\n", cp);
593	d->bios_cyl = strtol(cp, &cp, 0);
594	d->bios_hd = strtol(cp + 1, &cp, 0);
595	d->bios_sect = strtol(cp + 1, 0, 0);
596    }
597
598    cp = variable_get(VAR_PARTITION);
599    if (cp) {
600	if (!strcmp(cp, "free")) {
601	    /* Do free disk space case */
602	    for (i = 0; chunk_info[i]; i++) {
603		/* If a chunk is at least 10MB in size, use it. */
604		if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) {
605		    Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3,
606				 (chunk_info[i]->flags & CHUNK_ALIGN));
607		    variable_set2(DISK_PARTITIONED, "yes");
608		    break;
609		}
610	    }
611	    if (!chunk_info[i]) {
612		dialog_clear();
613		msgConfirm("Unable to find any free space on this disk!");
614		return;
615	    }
616	}
617	else if (!strcmp(cp, "all")) {
618	    /* Do all disk space case */
619	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
620
621	    All_FreeBSD(d, FALSE);
622	}
623	else if (!strcmp(cp, "exclusive")) {
624	    /* Do really-all-the-disk-space case */
625	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
626
627	    All_FreeBSD(d, all_disk = TRUE);
628	}
629	else if ((sz = strtol(cp, &cp, 0))) {
630	    /* Look for sz bytes free */
631	    if (*cp && toupper(*cp) == 'M')
632		sz *= ONE_MEG;
633	    for (i = 0; chunk_info[i]; i++) {
634		/* If a chunk is at least sz MB, use it. */
635		if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) {
636		    Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN));
637		    variable_set2(DISK_PARTITIONED, "yes");
638		    break;
639		}
640	    }
641	    if (!chunk_info[i]) {
642		dialog_clear();
643		msgConfirm("Unable to find %d free blocks on this disk!", sz);
644		return;
645	    }
646	}
647	else if (!strcmp(cp, "existing")) {
648	    /* Do existing FreeBSD case */
649	    for (i = 0; chunk_info[i]; i++) {
650		if (chunk_info[i]->type == freebsd)
651		    break;
652	    }
653	    if (!chunk_info[i]) {
654		dialog_clear();
655		msgConfirm("Unable to find any existing FreeBSD partitions on this disk!");
656		return;
657	    }
658	}
659	else {
660	    dialog_clear();
661	    msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION);
662	    return;
663	}
664	if (!all_disk) {
665	    mbrContents = getBootMgr(d->name);
666	    Set_Boot_Mgr(d, mbrContents);
667	}
668	variable_set2(DISK_PARTITIONED, "yes");
669    }
670}
671