disks.c revision 34811
1175261Sobrien/*
2175261Sobrien * The new sysinstall program.
3175261Sobrien *
4175261Sobrien * This is probably the last program in the `sysinstall' line - the next
5175261Sobrien * generation being essentially a complete rewrite.
6175261Sobrien *
7175261Sobrien * $Id: disks.c,v 1.97 1998/03/23 05:59:10 jkh Exp $
8175261Sobrien *
9175261Sobrien * Copyright (c) 1995
10175261Sobrien *	Jordan Hubbard.  All rights reserved.
11175261Sobrien *
12175261Sobrien * Redistribution and use in source and binary forms, with or without
13175261Sobrien * modification, are permitted provided that the following conditions
14175261Sobrien * are met:
1525839Speter * 1. Redistributions of source code must retain the above copyright
1625839Speter *    notice, this list of conditions and the following disclaimer,
1725839Speter *    verbatim and that no modifications are made prior to this
1825839Speter *    point in the file.
1925839Speter * 2. Redistributions in binary form must reproduce the above copyright
2025839Speter *    notice, this list of conditions and the following disclaimer in the
2125839Speter *    documentation and/or other materials provided with the distribution.
2225839Speter *
2325839Speter * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
2425839Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2525839Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2625839Speter * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
2725839Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2825839Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2925839Speter * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
3025839Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3125839Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3225839Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3325839Speter * SUCH DAMAGE.
3425839Speter *
3525839Speter */
3625839Speter
3725839Speter#include "sysinstall.h"
3825839Speter#include <ctype.h>
3925839Speter#include <sys/disklabel.h>
4025839Speter
4125839Speter/* Where we start displaying chunk information on the screen */
4225839Speter#define CHUNK_START_ROW		5
4325839Speter
4425839Speter/* Where we keep track of MBR chunks */
4525839Speterstatic struct chunk *chunk_info[16];
4625839Speterstatic int current_chunk;
4725839Speter
4825839Speterstatic void	diskPartitionNonInteractive(Device *dev);
4925839Speter
5025839Speterstatic void
5125839Speterrecord_chunks(Disk *d)
5225839Speter{
5325839Speter    struct chunk *c1 = NULL;
5425839Speter    int i = 0;
5525839Speter    int last_free = 0;
5625839Speter
5725839Speter    if (!d->chunks)
5825839Speter	msgFatal("No chunk list found for %s!", d->name);
5925839Speter
6025839Speter    for (c1 = d->chunks->part; c1; c1 = c1->next) {
6125839Speter	if (c1->type == unused && c1->size > last_free) {
6225839Speter	    last_free = c1->size;
6325839Speter	    current_chunk = i;
6425839Speter	}
6525839Speter	chunk_info[i++] = c1;
6625839Speter    }
6725839Speter    chunk_info[i] = NULL;
6825839Speter    if (current_chunk >= i)
6925839Speter	current_chunk = i - 1;
7025839Speter}
7125839Speter
7225839Speterstatic int Total;
7325839Speter
7425839Speterstatic void
7525839Speterprint_chunks(Disk *d)
7625839Speter{
7725839Speter    int row;
78102840Speter    int i;
7925839Speter
8025839Speter    for (i = Total = 0; chunk_info[i]; i++)
8125839Speter	Total += chunk_info[i]->size;
8225839Speter    if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) {
8325839Speter	dialog_clear_norefresh();
8425839Speter	msgConfirm("WARNING:  A geometry of %d/%d/%d for %s is incorrect.  Using\n"
8525839Speter		   "a more likely geometry.  If this geometry is incorrect or you\n"
8625839Speter		   "are unsure as to whether or not it's correct, please consult\n"
8725839Speter		   "the Hardware Guide in the Documentation submenu or use the\n"
8825839Speter		   "(G)eometry command to change it now.\n\n"
8925839Speter		   "Remember: you need to enter whatever your BIOS thinks the\n"
9025839Speter		   "geometry is!  For IDE, it's what you were told in the BIOS\n"
9125839Speter		   "setup. For SCSI, it's the translation mode your controller is\n"
9225839Speter		   "using.  Do NOT use a ``physical geometry''.",
9325839Speter	  d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
9425839Speter	Sanitize_Bios_Geom(d);
9525839Speter    }
9625839Speter    attrset(A_NORMAL);
9725839Speter    mvaddstr(0, 0, "Disk name:\t");
9825839Speter    clrtobot();
9925839Speter    attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL);
10025839Speter    attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL);
10125839Speter    mvprintw(1, 0,
10225839Speter	     "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors",
10325839Speter	     d->bios_cyl, d->bios_hd, d->bios_sect,
10425839Speter	     d->bios_cyl * d->bios_hd * d->bios_sect);
10525839Speter    mvprintw(3, 0, "%10s %10s %10s %8s %6s %10s %8s %8s",
10625839Speter	     "Offset", "Size", "End", "Name", "PType", "Desc",
10725839Speter	     "Subtype", "Flags");
10825839Speter    for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
10925839Speter	if (i == current_chunk)
11025839Speter	    attrset(ATTR_SELECTED);
11125839Speter	mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s",
11225839Speter		 chunk_info[i]->offset, chunk_info[i]->size,
11334461Speter		 chunk_info[i]->end, chunk_info[i]->name,
11434461Speter		 chunk_info[i]->type,
11534461Speter		 slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype),
11625839Speter		 chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i]));
11725839Speter	if (i == current_chunk)
11825839Speter	    attrset(A_NORMAL);
11925839Speter    }
12025839Speter}
12125839Speter
122102840Speterstatic void
12325839Speterprint_command_summary()
12425839Speter{
12534461Speter    mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
12625839Speter    mvprintw(16, 0, "A = Use Entire Disk    B = Bad Block Scan       C = Create Slice");
12725839Speter    mvprintw(17, 0, "D = Delete Slice       G = Set Drive Geometry   S = Set Bootable");
128102840Speter    mvprintw(18, 0, "T = Change Type        U = Undo All Changes     Q = Finish");
129107484Speter    if (!RunningAsInit)
13025839Speter	mvprintw(18, 48, "W = Write Changes");
13125839Speter    mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select.");
13232785Speter    move(0, 0);
13332785Speter}
13432785Speter
13532785Speterstatic u_char *
136128266SpetergetBootMgr(char *dname)
13725839Speter{
13825839Speter    extern u_char mbr[], bteasy17[];
13925839Speter    char str[80];
14025839Speter    char *cp;
14125839Speter    int i = 0;
14225839Speter
14325839Speter    cp = variable_get(VAR_BOOTMGR);
14425839Speter    if (!cp) {
14525839Speter	/* Figure out what kind of MBR the user wants */
14625839Speter	sprintf(str, "Install Boot Manager for drive %s?", dname);
14725839Speter	MenuMBRType.title = str;
14825839Speter	i = dmenuOpenSimple(&MenuMBRType, FALSE);
14925839Speter    }
15034461Speter    else {
15125839Speter	if (!strncmp(cp, "boot", 4))
15225839Speter	    BootMgr = 0;
15325839Speter	else if (!strcmp(cp, "standard"))
15425839Speter	    BootMgr = 1;
15525839Speter	else
15625839Speter	    BootMgr = 2;
15725839Speter    }
15825839Speter    if (cp || i) {
15925839Speter	switch (BootMgr) {
16025839Speter	case 0:
16134461Speter	    return bteasy17;
16225839Speter
16325839Speter	case 1:
16425839Speter	    return mbr;
16525839Speter
16625839Speter	case 2:
16725839Speter	default:
16825839Speter	    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		     !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n"
295			       "Are you sure you want to do this on a SCSI disk?")) {
296		if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
297		    chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
298		else
299		    chunk_info[current_chunk]->flags |= CHUNK_BAD144;
300	    }
301	    clear();
302	    break;
303
304	case 'C':
305	    if (chunk_info[current_chunk]->type != unused)
306		msg = "Slice in use, delete it first or move to an unused one.";
307	    else {
308		char *val, tmp[20], *cp;
309		int size, subtype;
310		chunk_e partitiontype;
311
312		snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size);
313		val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n"
314				  "or append a trailing `M' for megabytes (e.g. 20M).");
315		if (val && (size = strtol(val, &cp, 0)) > 0) {
316		    if (*cp && toupper(*cp) == 'M')
317			size *= ONE_MEG;
318		    strcpy(tmp, "165");
319		    val = msgGetInput(tmp, "Enter type of partition to create:\n\n"
320				      "Pressing Enter will choose the default, a native FreeBSD\n"
321				      "slice (type 165).  You can choose other types, 6 for a\n"
322				      "DOS partition or 131 for a Linux partition, for example.\n\n"
323				      "Note:  If you choose a non-FreeBSD partition type, it will not\n"
324				      "be formatted or otherwise prepared, it will simply reserve space\n"
325				      "for you to use another tool, such as DOS FORMAT, to later format\n"
326				      "and use the partition.");
327		    if (val && (subtype = strtol(val, NULL, 0)) > 0) {
328			if (subtype == 165)
329			    partitiontype = freebsd;
330			else if (subtype == 6)
331			    partitiontype = fat;
332			else
333			    partitiontype = unknown;
334			Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype,
335				     (chunk_info[current_chunk]->flags & CHUNK_ALIGN));
336			variable_set2(DISK_PARTITIONED, "yes");
337			record_chunks(d);
338		    }
339		}
340		clear();
341	    }
342	    break;
343
344	case KEY_DC:
345	case 'D':
346	    if (chunk_info[current_chunk]->type == unused)
347		msg = "Slice is already unused!";
348	    else {
349		Delete_Chunk(d, chunk_info[current_chunk]);
350		variable_set2(DISK_PARTITIONED, "yes");
351		record_chunks(d);
352	    }
353	    break;
354
355	case 'T':
356	    if (chunk_info[current_chunk]->type == unused)
357		msg = "Slice is currently unused (use create instead)";
358	    else {
359		char *val, tmp[20];
360		int subtype;
361		chunk_e partitiontype;
362		WINDOW *save = savescr();
363
364		strcpy(tmp, "165");
365		val = msgGetInput(tmp, "New partition type:\n\n"
366				  "Pressing Enter will choose the default, a native FreeBSD\n"
367				  "slice (type 165).  Other popular values are 6 for\n"
368				  "DOS FAT partition, 131 for a Linux ext2fs partition or\n"
369				  "130 for a Linux swap partition.\n\n"
370				  "Note:  If you choose a non-FreeBSD partition type, it will not\n"
371				  "be formatted or otherwise prepared, it will simply reserve space\n"
372				  "for you to use another tool, such as DOS format, to later format\n"
373				  "and actually use the partition.");
374		if (val && (subtype = strtol(val, NULL, 0)) > 0) {
375		    if (subtype == 165)
376			partitiontype = freebsd;
377		    else if (subtype == 6)
378			partitiontype = fat;
379		    else
380			partitiontype = unknown;
381		    chunk_info[current_chunk]->type = partitiontype;
382		    chunk_info[current_chunk]->subtype = subtype;
383		}
384		restorescr(save);
385	    }
386	    break;
387
388	case 'G':
389	    snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect);
390	    val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n"
391			      "Don't forget to use the two slash (/) separator characters!\n"
392			      "It's not possible to parse the field without them.");
393	    if (val) {
394		long nc, nh, ns;
395		nc = strtol(val, &val, 0);
396		nh = strtol(val + 1, &val, 0);
397		ns = strtol(val + 1, 0, 0);
398		Set_Bios_Geom(d, nc, nh, ns);
399	    }
400	    clear();
401	    break;
402
403	case 'S':
404	    /* Set Bootable */
405	    chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
406	    break;
407
408	case 'U':
409	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
410		msgConfirm("You've already written this information out - you\n"
411			   "can't undo it.");
412	    }
413	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
414		char cp[BUFSIZ];
415
416		sstrncpy(cp, d->name, sizeof cp);
417		Free_Disk(dev->private);
418		d = Open_Disk(cp);
419		if (!d)
420		    msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp);
421		dev->private = d;
422		variable_unset(DISK_PARTITIONED);
423		variable_unset(DISK_LABELLED);
424		if (d)
425		    record_chunks(d);
426	    }
427	    clear();
428	    break;
429
430	case 'W':
431	    if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
432			       "installation.  If you are installing FreeBSD for the first time\n"
433			       "then you should simply type Q when you're finished here and your\n"
434			       "changes will be committed in one batch automatically at the end of\n"
435			       "these questions.  If you're adding a disk, you should NOT write\n"
436			       "from this screen, you should do it from the label editor.\n\n"
437			       "Are you absolutely sure you want to do this now?")) {
438		variable_set2(DISK_PARTITIONED, "yes");
439
440		/* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
441		 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
442		 * booteasy or a "standard" MBR -- both would be fatal in this case.
443		 */
444#if 0
445		if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
446		    && (mbrContents = getBootMgr(d->name)) != NULL)
447		    Set_Boot_Mgr(d, mbrContents);
448#else
449		/*
450		 * Don't offer to update the MBR on this disk if the first "real" chunk looks like
451		 * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD.
452		 */
453		if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) &&
454		    (mbrContents = getBootMgr(d->name)) != NULL)
455		    Set_Boot_Mgr(d, mbrContents);
456#endif
457
458		if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS)
459		    msgConfirm("Disk partition write returned an error status!");
460		else
461		    msgConfirm("Wrote FDISK partition information out successfully.");
462	    }
463	    clear();
464	    break;
465
466	case '|':
467	    if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n"
468			  "No seat belts whatsoever are provided!")) {
469		clear();
470		refresh();
471		slice_wizard(d);
472		variable_set2(DISK_PARTITIONED, "yes");
473		record_chunks(d);
474	    }
475	    else
476		msg = "Wise choice!";
477	    clear();
478	    break;
479
480	case '\033':	/* ESC */
481	case 'Q':
482	    chunking = FALSE;
483	    /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
484	     * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
485	     * booteasy or a "standard" MBR -- both would be fatal in this case.
486	     */
487#if 0
488	    if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
489		&& (mbrContents = getBootMgr(d->name)) != NULL)
490		Set_Boot_Mgr(d, mbrContents);
491#else
492	    /*
493	     * Don't offer to update the MBR on this disk if the first "real" chunk looks like
494	     * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD.
495	     */
496	    if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) &&
497		(mbrContents = getBootMgr(d->name)) != NULL)
498		Set_Boot_Mgr(d, mbrContents);
499#endif
500	    break;
501
502	default:
503	    beep();
504	    msg = "Type F1 or ? for help";
505	    break;
506	}
507    }
508    p = CheckRules(d);
509    if (p) {
510	char buf[FILENAME_MAX];
511
512	dialog_clear_norefresh();
513        use_helpline("Press F1 to read more about disk slices.");
514	use_helpfile(systemHelpFile("partition", buf));
515	if (!variable_get(VAR_NO_WARN))
516	    dialog_mesgbox("Disk slicing warning:", p, -1, -1);
517	free(p);
518    }
519    restorescr(w);
520}
521
522static int
523partitionHook(dialogMenuItem *selected)
524{
525    Device **devs = NULL;
526
527    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
528    if (!devs) {
529	msgConfirm("Unable to find disk %s!", selected->prompt);
530	return DITEM_FAILURE;
531    }
532    /* Toggle enabled status? */
533    if (!devs[0]->enabled) {
534	devs[0]->enabled = TRUE;
535	diskPartition(devs[0]);
536    }
537    else
538	devs[0]->enabled = FALSE;
539    return DITEM_SUCCESS | DITEM_RESTORE;
540}
541
542static int
543partitionCheck(dialogMenuItem *selected)
544{
545    Device **devs = NULL;
546
547    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
548    if (!devs || devs[0]->enabled == FALSE)
549	return FALSE;
550    return TRUE;
551}
552
553int
554diskPartitionEditor(dialogMenuItem *self)
555{
556    DMenu *menu;
557    Device **devs;
558    int i, cnt, devcnt;
559
560    cnt = diskGetSelectCount(&devs);
561    devcnt = deviceCount(devs);
562    if (cnt == -1) {
563	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
564		   "properly probed at boot time.  See the Hardware Guide on the\n"
565		   "Documentation menu for clues on diagnosing this type of problem.");
566	return DITEM_FAILURE;
567    }
568    else if (cnt) {
569	/* Some are already selected */
570	for (i = 0; i < devcnt; i++) {
571	    if (devs[i]->enabled) {
572		if (variable_get(VAR_NONINTERACTIVE))
573		    diskPartitionNonInteractive(devs[i]);
574		else
575		    diskPartition(devs[i]);
576	    }
577	}
578    }
579    else {
580	/* No disks are selected, fall-back case now */
581	if (devcnt == 1) {
582	    devs[0]->enabled = TRUE;
583	    if (variable_get(VAR_NONINTERACTIVE))
584		diskPartitionNonInteractive(devs[0]);
585	    else
586		diskPartition(devs[0]);
587	    return DITEM_SUCCESS;
588	}
589	else {
590	    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck);
591	    if (!menu) {
592		msgConfirm("No devices suitable for installation found!\n\n"
593			   "Please verify that your disk controller (and attached drives)\n"
594			   "were detected properly.  This can be done by pressing the\n"
595			   "[Scroll Lock] key and using the Arrow keys to move back to\n"
596			   "the boot messages.  Press [Scroll Lock] again to return.");
597		return DITEM_FAILURE;
598	    }
599	    else {
600		i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
601		free(menu);
602	    }
603	    return i | DITEM_RESTORE;
604	}
605    }
606    return DITEM_SUCCESS;
607}
608
609int
610diskPartitionWrite(dialogMenuItem *self)
611{
612    Device **devs;
613    int i;
614    char *cp;
615
616    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
617    if (!devs) {
618	msgConfirm("Unable to find any disks to write to??");
619	return DITEM_FAILURE;
620    }
621    if (isDebug())
622	msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs));
623    cp = variable_get(DISK_PARTITIONED);
624    if (cp && !strcmp(cp, "written"))
625	return DITEM_SUCCESS;
626
627    for (i = 0; devs[i]; i++) {
628	Chunk *c1;
629	Disk *d = (Disk *)devs[i]->private;
630
631	if (!devs[i]->enabled)
632	    continue;
633
634	Set_Boot_Blocks(d, boot1, boot2);
635	msgNotify("Writing partition information to drive %s", d->name);
636	if (!Fake && Write_Disk(d)) {
637	    msgConfirm("ERROR: Unable to write data to disk %s!", d->name);
638	    return DITEM_FAILURE;
639	}
640
641	/* If we've been through here before, we don't need to do the rest */
642	if (cp && !strcmp(cp, "written"))
643	    return DITEM_SUCCESS;
644
645	/* Now scan for bad blocks, if necessary */
646	for (c1 = d->chunks->part; c1; c1 = c1->next) {
647	    if (c1->flags & CHUNK_BAD144) {
648		int ret;
649
650		msgNotify("Running bad block scan on slice %s", c1->name);
651		if (!Fake) {
652		    ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
653		    if (ret)
654			msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
655		    ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
656		    if (ret)
657			msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
658		}
659	    }
660	}
661    }
662    /* Now it's not "yes", but "written" */
663    variable_set2(DISK_PARTITIONED, "written");
664    return DITEM_SUCCESS;
665}
666
667/* Partition a disk based wholly on which variables are set */
668static void
669diskPartitionNonInteractive(Device *dev)
670{
671    char *cp;
672    int i, sz, all_disk = 0;
673    u_char *mbrContents;
674    Disk *d = (Disk *)dev->private;
675
676    record_chunks(d);
677    cp = variable_get(VAR_GEOMETRY);
678    if (cp) {
679	msgDebug("Setting geometry from script to: %s\n", cp);
680	d->bios_cyl = strtol(cp, &cp, 0);
681	d->bios_hd = strtol(cp + 1, &cp, 0);
682	d->bios_sect = strtol(cp + 1, 0, 0);
683    }
684
685    cp = variable_get(VAR_PARTITION);
686    if (cp) {
687	if (!strcmp(cp, "free")) {
688	    /* Do free disk space case */
689	    for (i = 0; chunk_info[i]; i++) {
690		/* If a chunk is at least 10MB in size, use it. */
691		if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) {
692		    Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3,
693				 (chunk_info[i]->flags & CHUNK_ALIGN));
694		    variable_set2(DISK_PARTITIONED, "yes");
695		    break;
696		}
697	    }
698	    if (!chunk_info[i]) {
699		dialog_clear();
700		msgConfirm("Unable to find any free space on this disk!");
701		return;
702	    }
703	}
704	else if (!strcmp(cp, "all")) {
705	    /* Do all disk space case */
706	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
707
708	    All_FreeBSD(d, FALSE);
709	}
710	else if (!strcmp(cp, "exclusive")) {
711	    /* Do really-all-the-disk-space case */
712	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
713
714	    All_FreeBSD(d, all_disk = TRUE);
715	}
716	else if ((sz = strtol(cp, &cp, 0))) {
717	    /* Look for sz bytes free */
718	    if (*cp && toupper(*cp) == 'M')
719		sz *= ONE_MEG;
720	    for (i = 0; chunk_info[i]; i++) {
721		/* If a chunk is at least sz MB, use it. */
722		if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) {
723		    Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN));
724		    variable_set2(DISK_PARTITIONED, "yes");
725		    break;
726		}
727	    }
728	    if (!chunk_info[i]) {
729		dialog_clear();
730		msgConfirm("Unable to find %d free blocks on this disk!", sz);
731		return;
732	    }
733	}
734	else if (!strcmp(cp, "existing")) {
735	    /* Do existing FreeBSD case */
736	    for (i = 0; chunk_info[i]; i++) {
737		if (chunk_info[i]->type == freebsd)
738		    break;
739	    }
740	    if (!chunk_info[i]) {
741		dialog_clear();
742		msgConfirm("Unable to find any existing FreeBSD partitions on this disk!");
743		return;
744	    }
745	}
746	else {
747	    dialog_clear();
748	    msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION);
749	    return;
750	}
751	if (!all_disk) {
752	    mbrContents = getBootMgr(d->name);
753	    Set_Boot_Mgr(d, mbrContents);
754	}
755	variable_set2(DISK_PARTITIONED, "yes");
756    }
757}
758