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