disks.c revision 34681
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.95 1998/02/13 08:01:01 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);
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, 0, "%10s %10s %10s %8s %6s %10s %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, 0, "%10ld %10lu %10lu %8s %6d %10s %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, "T = Change Type        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
174int
175diskGetSelectCount(Device ***devs)
176{
177    int i, cnt, enabled;
178    char *cp;
179    Device **dp;
180
181    cp = variable_get(VAR_DISK);
182    dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK);
183    cnt = deviceCount(dp);
184    if (!cnt)
185	return -1;
186    for (i = 0, enabled = 0; i < cnt; i++) {
187	if (dp[i]->enabled)
188	    ++enabled;
189    }
190    return enabled;
191}
192
193void
194diskPartition(Device *dev)
195{
196    char *cp, *p;
197    int rv, key = 0;
198    Boolean chunking;
199    char *msg = NULL;
200    u_char *mbrContents;
201    WINDOW *w = savescr();
202    Disk *d = (Disk *)dev->private;
203
204    chunking = TRUE;
205    keypad(stdscr, TRUE);
206
207    /* Flush both the dialog and curses library views of the screen
208       since we don't always know who called us */
209    dialog_clear_norefresh(), clear();
210    current_chunk = 0;
211
212    /* Set up the chunk array */
213    record_chunks(d);
214
215    while (chunking) {
216	char *val, geometry[80];
217
218	/* Now print our overall state */
219	if (d)
220	    print_chunks(d);
221	print_command_summary();
222	if (msg) {
223	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
224	    beep();
225	    msg = NULL;
226	}
227	else {
228	    move(23, 0);
229	    clrtoeol();
230	}
231
232	/* Get command character */
233	key = getch();
234	switch (toupper(key)) {
235	case '\014':	/* ^L (redraw) */
236	    clear();
237	    msg = NULL;
238	    break;
239
240	case '\020':	/* ^P */
241	case KEY_UP:
242	case '-':
243	    if (current_chunk != 0)
244		--current_chunk;
245	    break;
246
247	case '\016':	/* ^N */
248	case KEY_DOWN:
249	case '+':
250	case '\r':
251	case '\n':
252	    if (chunk_info[current_chunk + 1])
253		++current_chunk;
254	    break;
255
256	case KEY_HOME:
257	    current_chunk = 0;
258	    break;
259
260	case KEY_END:
261	    while (chunk_info[current_chunk + 1])
262		++current_chunk;
263	    break;
264
265	case KEY_F(1):
266	case '?':
267	    systemDisplayHelp("slice");
268	    clear();
269	    break;
270
271	case 'A':
272	    cp = variable_get(VAR_DEDICATE_DISK);
273	    if (cp && !strcasecmp(cp, "always"))
274		rv = 1;
275	    else {
276		rv = msgYesNo("Do you want to do this with a true partition entry\n"
277			      "so as to remain cooperative with any future possible\n"
278			      "operating systems on the drive(s)?\n"
279			      "(See also the section about ``dangerously dedicated''\n"
280			      "disks in the FreeBSD FAQ.)");
281		if (rv == -1)
282		    rv = 0;
283	    }
284	    All_FreeBSD(d, rv);
285	    variable_set2(DISK_PARTITIONED, "yes");
286	    record_chunks(d);
287	    clear();
288	    break;
289
290	case 'B':
291	    if (chunk_info[current_chunk]->type != freebsd)
292		msg = "Can only scan for bad blocks in FreeBSD slice.";
293	    else if (strncmp(d->name, "sd", 2) ||
294		     !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n"
295			       "Are you sure you want to do this on a SCSI disk?")) {
296		if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
297		    chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
298		else
299		    chunk_info[current_chunk]->flags |= CHUNK_BAD144;
300	    }
301	    clear();
302	    break;
303
304	case 'C':
305	    if (chunk_info[current_chunk]->type != unused)
306		msg = "Slice in use, delete it first or move to an unused one.";
307	    else {
308		char *val, tmp[20], *cp;
309		int size, subtype;
310		chunk_e partitiontype;
311
312		snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size);
313		val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n"
314				  "or append a trailing `M' for megabytes (e.g. 20M).");
315		if (val && (size = strtol(val, &cp, 0)) > 0) {
316		    if (*cp && toupper(*cp) == 'M')
317			size *= ONE_MEG;
318		    strcpy(tmp, "165");
319		    val = msgGetInput(tmp, "Enter type of partition to create:\n\n"
320				      "Pressing Enter will choose the default, a native FreeBSD\n"
321				      "slice (type 165).  You can choose other types, 6 for a\n"
322				      "DOS partition or 131 for a Linux partition, for example.\n\n"
323				      "Note:  If you choose a non-FreeBSD partition type, it will not\n"
324				      "be formatted or otherwise prepared, it will simply reserve space\n"
325				      "for you to use another tool, such as DOS FORMAT, to later format\n"
326				      "and use the partition.");
327		    if (val && (subtype = strtol(val, NULL, 0)) > 0) {
328			if (subtype == 165)
329			    partitiontype = freebsd;
330			else if (subtype == 6)
331			    partitiontype = fat;
332			else
333			    partitiontype = unknown;
334			Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype,
335				     (chunk_info[current_chunk]->flags & CHUNK_ALIGN));
336			variable_set2(DISK_PARTITIONED, "yes");
337			record_chunks(d);
338		    }
339		}
340		clear();
341	    }
342	    break;
343
344	case KEY_DC:
345	case 'D':
346	    if (chunk_info[current_chunk]->type == unused)
347		msg = "Slice is already unused!";
348	    else {
349		Delete_Chunk(d, chunk_info[current_chunk]);
350		variable_set2(DISK_PARTITIONED, "yes");
351		record_chunks(d);
352	    }
353	    break;
354
355	case 'T':
356	    if (chunk_info[current_chunk]->type == unused)
357		msg = "Slice is currently unused (use create instead)";
358	    else {
359		char *val, tmp[20];
360		int subtype;
361		chunk_e partitiontype;
362		WINDOW *save = savescr();
363
364		strcpy(tmp, "165");
365		val = msgGetInput(tmp, "New partition type:\n\n"
366				  "Pressing Enter will choose the default, a native FreeBSD\n"
367				  "slice (type 165).  Other popular values are 6 for\n"
368				  "DOS FAT partition, 131 for a Linux ext2fs partition or\n"
369				  "130 for a Linux swap partition.\n\n"
370				  "Note:  If you choose a non-FreeBSD partition type, it will not\n"
371				  "be formatted or otherwise prepared, it will simply reserve space\n"
372				  "for you to use another tool, such as DOS format, to later format\n"
373				  "and actually use the partition.");
374		if (val && (subtype = strtol(val, NULL, 0)) > 0) {
375		    if (subtype == 165)
376			partitiontype = freebsd;
377		    else if (subtype == 6)
378			partitiontype = fat;
379		    else
380			partitiontype = unknown;
381		    chunk_info[current_chunk]->type = partitiontype;
382		    chunk_info[current_chunk]->subtype = subtype;
383		}
384		restorescr(save);
385	    }
386	    break;
387
388	case 'G':
389	    snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect);
390	    val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n"
391			      "Don't forget to use the two slash (/) separator characters!\n"
392			      "It's not possible to parse the field without them.");
393	    if (val) {
394		long nc, nh, ns;
395		nc = strtol(val, &val, 0);
396		nh = strtol(val + 1, &val, 0);
397		ns = strtol(val + 1, 0, 0);
398		Set_Bios_Geom(d, nc, nh, ns);
399	    }
400	    clear();
401	    break;
402
403	case 'S':
404	    /* Set Bootable */
405	    chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
406	    break;
407
408	case 'U':
409	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
410		msgConfirm("You've already written this information out - you\n"
411			   "can't undo it.");
412	    }
413	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
414		char cp[BUFSIZ];
415
416		sstrncpy(cp, d->name, sizeof cp);
417		Free_Disk(dev->private);
418		d = Open_Disk(cp);
419		if (!d)
420		    msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp);
421		dev->private = d;
422		variable_unset(DISK_PARTITIONED);
423		variable_unset(DISK_LABELLED);
424		if (d)
425		    record_chunks(d);
426	    }
427	    clear();
428	    break;
429
430	case 'W':
431	    if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
432			       "installation.  If you are installing FreeBSD for the first time\n"
433			       "then you should simply type Q when you're finished here and your\n"
434			       "changes will be committed in one batch automatically at the end of\n"
435			       "these questions.  If you're adding a disk, you should NOT write\n"
436			       "from this screen, you should do it from the label editor.\n\n"
437			       "Are you absolutely sure you want to do this now?")) {
438		variable_set2(DISK_PARTITIONED, "yes");
439
440		/* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
441		 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
442		 * booteasy or a "standard" MBR -- both would be fatal in this case.
443		 */
444		if (!(d->chunks->part->flags & CHUNK_FORCE_ALL) && (mbrContents = getBootMgr(d->name)) != NULL)
445		    Set_Boot_Mgr(d, mbrContents);
446
447		if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS)
448		    msgConfirm("Disk partition write returned an error status!");
449		else
450		    msgConfirm("Wrote FDISK partition information out successfully.");
451	    }
452	    clear();
453	    break;
454
455	case '|':
456	    if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n"
457			  "No seat belts whatsoever are provided!")) {
458		clear();
459		refresh();
460		slice_wizard(d);
461		variable_set2(DISK_PARTITIONED, "yes");
462		record_chunks(d);
463	    }
464	    else
465		msg = "Wise choice!";
466	    clear();
467	    break;
468
469	case '\033':	/* ESC */
470	case 'Q':
471	    chunking = FALSE;
472	    /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
473	     * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
474	     * booteasy or a "standard" MBR -- both would be fatal in this case.
475	     */
476	    if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
477		&& (mbrContents = getBootMgr(d->name)) != NULL)
478		Set_Boot_Mgr(d, mbrContents);
479	    break;
480
481	default:
482	    beep();
483	    msg = "Type F1 or ? for help";
484	    break;
485	}
486    }
487    p = CheckRules(d);
488    if (p) {
489	char buf[FILENAME_MAX];
490
491	dialog_clear_norefresh();
492        use_helpline("Press F1 to read more about disk slices.");
493	use_helpfile(systemHelpFile("partition", buf));
494	if (!variable_get(VAR_NO_WARN))
495	    dialog_mesgbox("Disk slicing warning:", p, -1, -1);
496	free(p);
497    }
498    restorescr(w);
499}
500
501static int
502partitionHook(dialogMenuItem *selected)
503{
504    Device **devs = NULL;
505
506    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
507    if (!devs) {
508	msgConfirm("Unable to find disk %s!", selected->prompt);
509	return DITEM_FAILURE;
510    }
511    /* Toggle enabled status? */
512    if (!devs[0]->enabled) {
513	devs[0]->enabled = TRUE;
514	diskPartition(devs[0]);
515    }
516    else
517	devs[0]->enabled = FALSE;
518    return DITEM_SUCCESS | DITEM_RESTORE;
519}
520
521static int
522partitionCheck(dialogMenuItem *selected)
523{
524    Device **devs = NULL;
525
526    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
527    if (!devs || devs[0]->enabled == FALSE)
528	return FALSE;
529    return TRUE;
530}
531
532int
533diskPartitionEditor(dialogMenuItem *self)
534{
535    DMenu *menu;
536    Device **devs;
537    int i, cnt, devcnt;
538
539    cnt = diskGetSelectCount(&devs);
540    devcnt = deviceCount(devs);
541    if (cnt == -1) {
542	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
543		   "properly probed at boot time.  See the Hardware Guide on the\n"
544		   "Documentation menu for clues on diagnosing this type of problem.");
545	return DITEM_FAILURE;
546    }
547    else if (cnt) {
548	/* Some are already selected */
549	for (i = 0; i < devcnt; i++) {
550	    if (devs[i]->enabled) {
551		if (variable_get(VAR_NONINTERACTIVE))
552		    diskPartitionNonInteractive(devs[i]);
553		else
554		    diskPartition(devs[i]);
555	    }
556	}
557    }
558    else {
559	/* No disks are selected, fall-back case now */
560	if (devcnt == 1) {
561	    devs[0]->enabled = TRUE;
562	    if (variable_get(VAR_NONINTERACTIVE))
563		diskPartitionNonInteractive(devs[0]);
564	    else
565		diskPartition(devs[0]);
566	    return DITEM_SUCCESS;
567	}
568	else {
569	    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck);
570	    if (!menu) {
571		msgConfirm("No devices suitable for installation found!\n\n"
572			   "Please verify that your disk controller (and attached drives)\n"
573			   "were detected properly.  This can be done by pressing the\n"
574			   "[Scroll Lock] key and using the Arrow keys to move back to\n"
575			   "the boot messages.  Press [Scroll Lock] again to return.");
576		return DITEM_FAILURE;
577	    }
578	    else {
579		i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
580		free(menu);
581	    }
582	    return i | DITEM_RESTORE;
583	}
584    }
585    return DITEM_SUCCESS;
586}
587
588int
589diskPartitionWrite(dialogMenuItem *self)
590{
591    Device **devs;
592    int i;
593    char *cp;
594
595    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
596    if (!devs) {
597	msgConfirm("Unable to find any disks to write to??");
598	return DITEM_FAILURE;
599    }
600    if (isDebug())
601	msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs));
602    cp = variable_get(DISK_PARTITIONED);
603    for (i = 0; devs[i]; i++) {
604	Chunk *c1;
605	Disk *d = (Disk *)devs[i]->private;
606
607	if (!devs[i]->enabled)
608	    continue;
609
610	Set_Boot_Blocks(d, boot1, boot2);
611	msgNotify("Writing partition information to drive %s", d->name);
612	if (!Fake && Write_Disk(d)) {
613	    msgConfirm("ERROR: Unable to write data to disk %s!", d->name);
614	    return DITEM_FAILURE;
615	}
616
617	/* If we've been through here before, we don't need to do the rest */
618	if (cp && !strcmp(cp, "written"))
619	    return DITEM_SUCCESS;
620
621	/* Now scan for bad blocks, if necessary */
622	for (c1 = d->chunks->part; c1; c1 = c1->next) {
623	    if (c1->flags & CHUNK_BAD144) {
624		int ret;
625
626		msgNotify("Running bad block scan on slice %s", c1->name);
627		if (!Fake) {
628		    ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
629		    if (ret)
630			msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
631		    ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
632		    if (ret)
633			msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
634		}
635	    }
636	}
637    }
638    /* Now it's not "yes", but "written" */
639    variable_set2(DISK_PARTITIONED, "written");
640    return DITEM_SUCCESS;
641}
642
643/* Partition a disk based wholly on which variables are set */
644static void
645diskPartitionNonInteractive(Device *dev)
646{
647    char *cp;
648    int i, sz, all_disk = 0;
649    u_char *mbrContents;
650    Disk *d = (Disk *)dev->private;
651
652    record_chunks(d);
653    cp = variable_get(VAR_GEOMETRY);
654    if (cp) {
655	msgDebug("Setting geometry from script to: %s\n", cp);
656	d->bios_cyl = strtol(cp, &cp, 0);
657	d->bios_hd = strtol(cp + 1, &cp, 0);
658	d->bios_sect = strtol(cp + 1, 0, 0);
659    }
660
661    cp = variable_get(VAR_PARTITION);
662    if (cp) {
663	if (!strcmp(cp, "free")) {
664	    /* Do free disk space case */
665	    for (i = 0; chunk_info[i]; i++) {
666		/* If a chunk is at least 10MB in size, use it. */
667		if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) {
668		    Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3,
669				 (chunk_info[i]->flags & CHUNK_ALIGN));
670		    variable_set2(DISK_PARTITIONED, "yes");
671		    break;
672		}
673	    }
674	    if (!chunk_info[i]) {
675		dialog_clear();
676		msgConfirm("Unable to find any free space on this disk!");
677		return;
678	    }
679	}
680	else if (!strcmp(cp, "all")) {
681	    /* Do all disk space case */
682	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
683
684	    All_FreeBSD(d, FALSE);
685	}
686	else if (!strcmp(cp, "exclusive")) {
687	    /* Do really-all-the-disk-space case */
688	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
689
690	    All_FreeBSD(d, all_disk = TRUE);
691	}
692	else if ((sz = strtol(cp, &cp, 0))) {
693	    /* Look for sz bytes free */
694	    if (*cp && toupper(*cp) == 'M')
695		sz *= ONE_MEG;
696	    for (i = 0; chunk_info[i]; i++) {
697		/* If a chunk is at least sz MB, use it. */
698		if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) {
699		    Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN));
700		    variable_set2(DISK_PARTITIONED, "yes");
701		    break;
702		}
703	    }
704	    if (!chunk_info[i]) {
705		dialog_clear();
706		msgConfirm("Unable to find %d free blocks on this disk!", sz);
707		return;
708	    }
709	}
710	else if (!strcmp(cp, "existing")) {
711	    /* Do existing FreeBSD case */
712	    for (i = 0; chunk_info[i]; i++) {
713		if (chunk_info[i]->type == freebsd)
714		    break;
715	    }
716	    if (!chunk_info[i]) {
717		dialog_clear();
718		msgConfirm("Unable to find any existing FreeBSD partitions on this disk!");
719		return;
720	    }
721	}
722	else {
723	    dialog_clear();
724	    msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION);
725	    return;
726	}
727	if (!all_disk) {
728	    mbrContents = getBootMgr(d->name);
729	    Set_Boot_Mgr(d, mbrContents);
730	}
731	variable_set2(DISK_PARTITIONED, "yes");
732    }
733}
734