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