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