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