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