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