disks.c revision 29204
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.89 1997/09/03 10:47:44 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)?\n"
259			      "(See also the section about ``dangerously dedicated''\n"
260			      "disks in the FreeBSD FAQ.)");
261		if (rv == -1)
262		    rv = 0;
263	    }
264	    All_FreeBSD(d, rv);
265	    variable_set2(DISK_PARTITIONED, "yes");
266	    record_chunks(d);
267	    clear();
268	    break;
269
270	case 'B':
271	    if (chunk_info[current_chunk]->type != freebsd)
272		msg = "Can only scan for bad blocks in FreeBSD slice.";
273	    else if (strncmp(d->name, "sd", 2) ||
274		     !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n"
275			       "Are you sure you want to do this on a SCSI disk?")) {
276		if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
277		    chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
278		else
279		    chunk_info[current_chunk]->flags |= CHUNK_BAD144;
280	    }
281	    clear();
282	    break;
283
284	case 'C':
285	    if (chunk_info[current_chunk]->type != unused)
286		msg = "Slice in use, delete it first or move to an unused one.";
287	    else {
288		char *val, tmp[20], *cp;
289		int size, subtype;
290		chunk_e partitiontype;
291
292		snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size);
293		val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n"
294				  "or append a trailing `M' for megabytes (e.g. 20M).");
295		if (val && (size = strtol(val, &cp, 0)) > 0) {
296		    if (*cp && toupper(*cp) == 'M')
297			size *= ONE_MEG;
298		    strcpy(tmp, "165");
299		    val = msgGetInput(tmp, "Enter type of partition to create:\n\n"
300				      "Pressing Enter will choose the default, a native FreeBSD\n"
301				      "slice (type 165).  You can choose other types, 6 for a\n"
302				      "DOS partition or 131 for a Linux partition, for example.\n\n"
303				      "Note:  If you choose a non-FreeBSD partition type, it will not\n"
304				      "be formatted or otherwise prepared, it will simply reserve space\n"
305				      "for you to use another tool, such as DOS FORMAT, to later format\n"
306				      "and use the partition.");
307		    if (val && (subtype = strtol(val, NULL, 0)) > 0) {
308			if (subtype==165)
309			    partitiontype=freebsd;
310			else if (subtype==6)
311			    partitiontype=fat;
312			else
313			    partitiontype=unknown;
314			Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype,
315				     (chunk_info[current_chunk]->flags & CHUNK_ALIGN));
316			variable_set2(DISK_PARTITIONED, "yes");
317			record_chunks(d);
318		    }
319		}
320		clear();
321	    }
322	    break;
323
324	case KEY_DC:
325	case 'D':
326	    if (chunk_info[current_chunk]->type == unused)
327		msg = "Slice is already unused!";
328	    else {
329		Delete_Chunk(d, chunk_info[current_chunk]);
330		variable_set2(DISK_PARTITIONED, "yes");
331		record_chunks(d);
332	    }
333	    break;
334
335	case 'G':
336	    snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect);
337	    val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n"
338			      "Don't forget to use the two slash (/) separator characters!\n"
339			      "It's not possible to parse the field without them.");
340	    if (val) {
341		long nc, nh, ns;
342		nc = strtol(val, &val, 0);
343		nh = strtol(val + 1, &val, 0);
344		ns = strtol(val + 1, 0, 0);
345		Set_Bios_Geom(d, nc, nh, ns);
346	    }
347	    clear();
348	    break;
349
350	case 'S':
351	    /* Set Bootable */
352	    chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
353	    break;
354
355	case 'U':
356	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
357		msgConfirm("You've already written this information out - you\n"
358			   "can't undo it.");
359	    }
360	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
361		char cp[BUFSIZ];
362
363		sstrncpy(cp, d->name, sizeof cp);
364		Free_Disk(dev->private);
365		d = Open_Disk(cp);
366		if (!d)
367		    msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp);
368		dev->private = d;
369		variable_unset(DISK_PARTITIONED);
370		variable_unset(DISK_LABELLED);
371		if (d)
372		    record_chunks(d);
373	    }
374	    clear();
375	    break;
376
377	case 'W':
378	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
379		msgConfirm("You've already written this information out - if\n"
380			   "you wish to overwrite it, you'll have to restart.");
381	    }
382	    else if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
383			       "installation.  If you are installing FreeBSD for the first time\n"
384			       "then you should simply type Q when you're finished here and your\n"
385			       "changes will be committed in one batch automatically at the end of\n"
386			       "these questions.\n\n"
387			       "Are you absolutely sure you want to do this now?")) {
388		variable_set2(DISK_PARTITIONED, "yes");
389
390		/* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
391		 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
392		 * booteasy or a "standard" MBR -- both would be fatal in this case.
393		 */
394		if (!(d->chunks->part->flags & CHUNK_FORCE_ALL) && (mbrContents = getBootMgr(d->name)) != NULL)
395		    Set_Boot_Mgr(d, mbrContents);
396
397		if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS)
398		    msgConfirm("Disk partition write returned an error status!");
399		else
400		    msgConfirm("Wrote FDISK partition information out successfully.");
401	    }
402	    clear();
403	    break;
404
405	case '|':
406	    if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n"
407			  "No seat belts whatsoever are provided!")) {
408		clear();
409		refresh();
410		slice_wizard(d);
411		variable_set2(DISK_PARTITIONED, "yes");
412		record_chunks(d);
413	    }
414	    else
415		msg = "Wise choice!";
416	    clear();
417	    break;
418
419	case '\033':	/* ESC */
420	case 'Q':
421	    chunking = FALSE;
422	    /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
423	     * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
424	     * booteasy or a "standard" MBR -- both would be fatal in this case.
425	     */
426	    if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
427		&& (mbrContents = getBootMgr(d->name)) != NULL)
428		Set_Boot_Mgr(d, mbrContents);
429	    break;
430
431	default:
432	    beep();
433	    msg = "Type F1 or ? for help";
434	    break;
435	}
436    }
437    p = CheckRules(d);
438    if (p) {
439	char buf[FILENAME_MAX];
440
441	dialog_clear_norefresh();
442        use_helpline("Press F1 to read more about disk slices.");
443	use_helpfile(systemHelpFile("partition", buf));
444	if (!variable_get(VAR_NO_WARN))
445	    dialog_mesgbox("Disk slicing warning:", p, -1, -1);
446	free(p);
447    }
448    restorescr(w);
449}
450
451static int
452partitionHook(dialogMenuItem *selected)
453{
454    Device **devs = NULL;
455
456    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
457    if (!devs) {
458	msgConfirm("Unable to find disk %s!", selected->prompt);
459	return DITEM_FAILURE;
460    }
461    /* Toggle enabled status? */
462    if (!devs[0]->enabled) {
463	devs[0]->enabled = TRUE;
464	diskPartition(devs[0], (Disk *)devs[0]->private);
465    }
466    else
467	devs[0]->enabled = FALSE;
468    return DITEM_SUCCESS | DITEM_REDRAW;
469}
470
471static int
472partitionCheck(dialogMenuItem *selected)
473{
474    Device **devs = NULL;
475
476    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
477    if (!devs || devs[0]->enabled == FALSE)
478	return FALSE;
479    return TRUE;
480}
481
482int
483diskPartitionEditor(dialogMenuItem *self)
484{
485    DMenu *menu;
486    Device **devs;
487    int i, cnt;
488    char *cp;
489
490    cp = variable_get(VAR_DISK);
491    devs = deviceFind(cp, DEVICE_TYPE_DISK);
492    cnt = deviceCount(devs);
493    if (!cnt) {
494	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
495		   "properly probed at boot time.  See the Hardware Guide on the\n"
496		   "Documentation menu for clues on diagnosing this type of problem.");
497	i = DITEM_FAILURE;
498    }
499    else if (cnt == 1) {
500	devs[0]->enabled = TRUE;
501	if (variable_get(VAR_NONINTERACTIVE))
502	    diskPartitionNonInteractive(devs[0], (Disk *)devs[0]->private);
503	else
504	    diskPartition(devs[0], (Disk *)devs[0]->private);
505	i = DITEM_SUCCESS;
506    }
507    else {
508	menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck);
509	if (!menu) {
510	    msgConfirm("No devices suitable for installation found!\n\n"
511		       "Please verify that your disk controller (and attached drives)\n"
512		       "were detected properly.  This can be done by pressing the\n"
513		       "[Scroll Lock] key and using the Arrow keys to move back to\n"
514		       "the boot messages.  Press [Scroll Lock] again to return.");
515	    i = DITEM_FAILURE;
516	}
517	else {
518	    i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
519	    free(menu);
520	}
521	i = i | DITEM_RESTORE;
522    }
523    return i;
524}
525
526int
527diskPartitionWrite(dialogMenuItem *self)
528{
529    Device **devs;
530    char *cp;
531    int i;
532
533    if ((cp = variable_get(DISK_PARTITIONED)) && strcmp(cp, "yes"))
534	return DITEM_SUCCESS;
535    else if (!cp) {
536	msgConfirm("You must partition the disk(s) before this option can be used.");
537	return DITEM_FAILURE;
538    }
539
540    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
541    if (!devs) {
542	msgConfirm("Unable to find any disks to write to??");
543	return DITEM_FAILURE;
544    }
545    if (isDebug())
546	msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs));
547
548    for (i = 0; devs[i]; i++) {
549	Chunk *c1;
550	Disk *d = (Disk *)devs[i]->private;
551
552	if (!devs[i]->enabled)
553	    continue;
554
555	Set_Boot_Blocks(d, boot1, boot2);
556	msgNotify("Writing partition information to drive %s", d->name);
557	if (!Fake && Write_Disk(d)) {
558	    msgConfirm("ERROR: Unable to write data to disk %s!", d->name);
559	    return DITEM_FAILURE;
560	}
561	/* Now scan for bad blocks, if necessary */
562	for (c1 = d->chunks->part; c1; c1 = c1->next) {
563	    if (c1->flags & CHUNK_BAD144) {
564		int ret;
565
566		msgNotify("Running bad block scan on slice %s", c1->name);
567		if (!Fake) {
568		    ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
569		    if (ret)
570			msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
571		    ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
572		    if (ret)
573			msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
574		}
575	    }
576	}
577    }
578    /* Now it's not "yes", but "written" */
579    variable_set2(DISK_PARTITIONED, "written");
580    return DITEM_SUCCESS;
581}
582
583/* Partition a disk based wholly on which variables are set */
584static void
585diskPartitionNonInteractive(Device *dev, Disk *d)
586{
587    char *cp;
588    int i, sz, all_disk = 0;
589    u_char *mbrContents;
590
591    record_chunks(d);
592    cp = variable_get(VAR_GEOMETRY);
593    if (cp) {
594	msgDebug("Setting geometry from script to: %s\n", cp);
595	d->bios_cyl = strtol(cp, &cp, 0);
596	d->bios_hd = strtol(cp + 1, &cp, 0);
597	d->bios_sect = strtol(cp + 1, 0, 0);
598    }
599
600    cp = variable_get(VAR_PARTITION);
601    if (cp) {
602	if (!strcmp(cp, "free")) {
603	    /* Do free disk space case */
604	    for (i = 0; chunk_info[i]; i++) {
605		/* If a chunk is at least 10MB in size, use it. */
606		if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) {
607		    Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3,
608				 (chunk_info[i]->flags & CHUNK_ALIGN));
609		    variable_set2(DISK_PARTITIONED, "yes");
610		    break;
611		}
612	    }
613	    if (!chunk_info[i]) {
614		dialog_clear();
615		msgConfirm("Unable to find any free space on this disk!");
616		return;
617	    }
618	}
619	else if (!strcmp(cp, "all")) {
620	    /* Do all disk space case */
621	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
622
623	    All_FreeBSD(d, FALSE);
624	}
625	else if (!strcmp(cp, "exclusive")) {
626	    /* Do really-all-the-disk-space case */
627	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
628
629	    All_FreeBSD(d, all_disk = TRUE);
630	}
631	else if ((sz = strtol(cp, &cp, 0))) {
632	    /* Look for sz bytes free */
633	    if (*cp && toupper(*cp) == 'M')
634		sz *= ONE_MEG;
635	    for (i = 0; chunk_info[i]; i++) {
636		/* If a chunk is at least sz MB, use it. */
637		if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) {
638		    Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN));
639		    variable_set2(DISK_PARTITIONED, "yes");
640		    break;
641		}
642	    }
643	    if (!chunk_info[i]) {
644		dialog_clear();
645		msgConfirm("Unable to find %d free blocks on this disk!", sz);
646		return;
647	    }
648	}
649	else if (!strcmp(cp, "existing")) {
650	    /* Do existing FreeBSD case */
651	    for (i = 0; chunk_info[i]; i++) {
652		if (chunk_info[i]->type == freebsd)
653		    break;
654	    }
655	    if (!chunk_info[i]) {
656		dialog_clear();
657		msgConfirm("Unable to find any existing FreeBSD partitions on this disk!");
658		return;
659	    }
660	}
661	else {
662	    dialog_clear();
663	    msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION);
664	    return;
665	}
666	if (!all_disk) {
667	    mbrContents = getBootMgr(d->name);
668	    Set_Boot_Mgr(d, mbrContents);
669	}
670	variable_set2(DISK_PARTITIONED, "yes");
671    }
672}
673