disks.c revision 26717
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.87 1997/06/12 08:46:50 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")) && !variable_get(VAR_NO_WARN)) {
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	if (!variable_get(VAR_NO_WARN))
459	    dialog_mesgbox("Disk slicing warning:", p, -1, -1);
460	free(p);
461    }
462    restorescr(w);
463}
464
465static int
466partitionHook(dialogMenuItem *selected)
467{
468    Device **devs = NULL;
469
470    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
471    if (!devs) {
472	msgConfirm("Unable to find disk %s!", selected->prompt);
473	return DITEM_FAILURE;
474    }
475    /* Toggle enabled status? */
476    if (!devs[0]->enabled) {
477	devs[0]->enabled = TRUE;
478	diskPartition(devs[0], (Disk *)devs[0]->private);
479    }
480    else
481	devs[0]->enabled = FALSE;
482    return DITEM_SUCCESS | DITEM_REDRAW;
483}
484
485static int
486partitionCheck(dialogMenuItem *selected)
487{
488    Device **devs = NULL;
489
490    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
491    if (!devs || devs[0]->enabled == FALSE)
492	return FALSE;
493    return TRUE;
494}
495
496int
497diskPartitionEditor(dialogMenuItem *self)
498{
499    DMenu *menu;
500    Device **devs;
501    int i, cnt;
502    char *cp;
503
504    cp = variable_get(VAR_DISK);
505    devs = deviceFind(cp, DEVICE_TYPE_DISK);
506    cnt = deviceCount(devs);
507    if (!cnt) {
508	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
509		   "properly probed at boot time.  See the Hardware Guide on the\n"
510		   "Documentation menu for clues on diagnosing this type of problem.");
511	i = DITEM_FAILURE;
512    }
513    else if (cnt == 1) {
514	devs[0]->enabled = TRUE;
515	if (variable_get(VAR_NONINTERACTIVE))
516	    diskPartitionNonInteractive(devs[0], (Disk *)devs[0]->private);
517	else
518	    diskPartition(devs[0], (Disk *)devs[0]->private);
519	i = DITEM_SUCCESS;
520    }
521    else {
522	menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck);
523	if (!menu) {
524	    msgConfirm("No devices suitable for installation found!\n\n"
525		       "Please verify that your disk controller (and attached drives)\n"
526		       "were detected properly.  This can be done by pressing the\n"
527		       "[Scroll Lock] key and using the Arrow keys to move back to\n"
528		       "the boot messages.  Press [Scroll Lock] again to return.");
529	    i = DITEM_FAILURE;
530	}
531	else {
532	    i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
533	    free(menu);
534	}
535	i = i | DITEM_RESTORE;
536    }
537    return i;
538}
539
540int
541diskPartitionWrite(dialogMenuItem *self)
542{
543    Device **devs;
544    char *cp;
545    int i;
546
547    if ((cp = variable_get(DISK_PARTITIONED)) && strcmp(cp, "yes"))
548	return DITEM_SUCCESS;
549    else if (!cp) {
550	msgConfirm("You must partition the disk(s) before this option can be used.");
551	return DITEM_FAILURE;
552    }
553
554    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
555    if (!devs) {
556	msgConfirm("Unable to find any disks to write to??");
557	return DITEM_FAILURE;
558    }
559    if (isDebug())
560	msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs));
561
562    for (i = 0; devs[i]; i++) {
563	Chunk *c1;
564	Disk *d = (Disk *)devs[i]->private;
565
566	if (!devs[i]->enabled)
567	    continue;
568
569	Set_Boot_Blocks(d, boot1, boot2);
570	msgNotify("Writing partition information to drive %s", d->name);
571	if (!Fake && Write_Disk(d)) {
572	    msgConfirm("ERROR: Unable to write data to disk %s!", d->name);
573	    return DITEM_FAILURE;
574	}
575	/* Now scan for bad blocks, if necessary */
576	for (c1 = d->chunks->part; c1; c1 = c1->next) {
577	    if (c1->flags & CHUNK_BAD144) {
578		int ret;
579
580		msgNotify("Running bad block scan on slice %s", c1->name);
581		if (!Fake) {
582		    ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
583		    if (ret)
584			msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
585		    ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
586		    if (ret)
587			msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
588		}
589	    }
590	}
591    }
592    /* Now it's not "yes", but "written" */
593    variable_set2(DISK_PARTITIONED, "written");
594    return DITEM_SUCCESS;
595}
596
597/* Partition a disk based wholly on which variables are set */
598static void
599diskPartitionNonInteractive(Device *dev, Disk *d)
600{
601    char *cp;
602    int i, sz, all_disk = 0;
603    u_char *mbrContents;
604
605    record_chunks(d);
606    cp = variable_get(VAR_GEOMETRY);
607    if (cp) {
608	msgDebug("Setting geometry from script to: %s\n", cp);
609	d->bios_cyl = strtol(cp, &cp, 0);
610	d->bios_hd = strtol(cp + 1, &cp, 0);
611	d->bios_sect = strtol(cp + 1, 0, 0);
612    }
613
614    cp = variable_get(VAR_PARTITION);
615    if (cp) {
616	if (!strcmp(cp, "free")) {
617	    /* Do free disk space case */
618	    for (i = 0; chunk_info[i]; i++) {
619		/* If a chunk is at least 10MB in size, use it. */
620		if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) {
621		    Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3,
622				 (chunk_info[i]->flags & CHUNK_ALIGN));
623		    variable_set2(DISK_PARTITIONED, "yes");
624		    break;
625		}
626	    }
627	    if (!chunk_info[i]) {
628		dialog_clear();
629		msgConfirm("Unable to find any free space on this disk!");
630		return;
631	    }
632	}
633	else if (!strcmp(cp, "all")) {
634	    /* Do all disk space case */
635	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
636
637	    All_FreeBSD(d, FALSE);
638	}
639	else if (!strcmp(cp, "exclusive")) {
640	    /* Do really-all-the-disk-space case */
641	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
642
643	    All_FreeBSD(d, all_disk = TRUE);
644	}
645	else if ((sz = strtol(cp, &cp, 0))) {
646	    /* Look for sz bytes free */
647	    if (*cp && toupper(*cp) == 'M')
648		sz *= ONE_MEG;
649	    for (i = 0; chunk_info[i]; i++) {
650		/* If a chunk is at least sz MB, use it. */
651		if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) {
652		    Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN));
653		    variable_set2(DISK_PARTITIONED, "yes");
654		    break;
655		}
656	    }
657	    if (!chunk_info[i]) {
658		dialog_clear();
659		msgConfirm("Unable to find %d free blocks on this disk!", sz);
660		return;
661	    }
662	}
663	else if (!strcmp(cp, "existing")) {
664	    /* Do existing FreeBSD case */
665	    for (i = 0; chunk_info[i]; i++) {
666		if (chunk_info[i]->type == freebsd)
667		    break;
668	    }
669	    if (!chunk_info[i]) {
670		dialog_clear();
671		msgConfirm("Unable to find any existing FreeBSD partitions on this disk!");
672		return;
673	    }
674	}
675	else {
676	    dialog_clear();
677	    msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION);
678	    return;
679	}
680	if (!all_disk) {
681	    mbrContents = getBootMgr(d->name);
682	    Set_Boot_Mgr(d, mbrContents);
683	}
684	variable_set2(DISK_PARTITIONED, "yes");
685    }
686}
687