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