disks.c revision 43685
195967Speter/*
295967Speter * The new sysinstall program.
3127326Smarkm *
4127326Smarkm * This is probably the last program in the `sysinstall' line - the next
5127326Smarkm * generation being essentially a complete rewrite.
6127326Smarkm *
7127326Smarkm * $Id: disks.c,v 1.108 1999/01/08 00:14:21 jkh Exp $
895967Speter *
995967Speter * Copyright (c) 1995
1095967Speter *	Jordan Hubbard.  All rights reserved.
1195967Speter *
1295967Speter * Redistribution and use in source and binary forms, with or without
1395967Speter * modification, are permitted provided that the following conditions
1495967Speter * are met:
1595967Speter * 1. Redistributions of source code must retain the above copyright
1695967Speter *    notice, this list of conditions and the following disclaimer,
1795967Speter *    verbatim and that no modifications are made prior to this
1895967Speter *    point in the file.
1995967Speter * 2. Redistributions in binary form must reproduce the above copyright
2095967Speter *    notice, this list of conditions and the following disclaimer in the
2195967Speter *    documentation and/or other materials provided with the distribution.
22127326Smarkm *
2395967Speter * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
2495967Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25127326Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26127326Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27127326Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2895967Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2995967Speter * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
3095967Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31127326Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32127326Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3395967Speter * SUCH DAMAGE.
3495967Speter *
35127326Smarkm */
3695967Speter
3795967Speter#include "sysinstall.h"
3895967Speter#include <ctype.h>
3995967Speter#include <fcntl.h>
4095967Speter#include <sys/stat.h>
4195967Speter#include <sys/disklabel.h>
4295967Speter
4395967Speter/* Where we start displaying chunk information on the screen */
4495967Speter#define CHUNK_START_ROW		5
4595967Speter
4695967Speter/* Where we keep track of MBR chunks */
4795967Speterstatic struct chunk *chunk_info[16];
4895967Speterstatic int current_chunk;
4995967Speter
5095967Speterstatic void	diskPartitionNonInteractive(Device *dev);
5195967Speter
5295967Speterstatic void
5395967Speterrecord_chunks(Disk *d)
5495967Speter{
5595967Speter    struct chunk *c1 = NULL;
5695967Speter    int i = 0;
5795967Speter    int last_free = 0;
58127326Smarkm
59127326Smarkm    if (!d->chunks)
6095967Speter	msgFatal("No chunk list found for %s!", d->name);
61127326Smarkm
6295967Speter    for (c1 = d->chunks->part; c1; c1 = c1->next) {
6395967Speter	if (c1->type == unused && c1->size > last_free) {
64127326Smarkm	    last_free = c1->size;
6595967Speter	    current_chunk = i;
6695967Speter	}
67127326Smarkm	chunk_info[i++] = c1;
6895967Speter    }
6995967Speter    chunk_info[i] = NULL;
7095967Speter    if (current_chunk >= i)
71127326Smarkm	current_chunk = i - 1;
7295967Speter}
73127326Smarkm
7495967Speterstatic int Total;
75127326Smarkm
7695967Speterstatic void
77127326Smarkmprint_chunks(Disk *d)
7895967Speter{
79127326Smarkm    int row;
8095967Speter    int i;
81127326Smarkm
82127326Smarkm    for (i = Total = 0; chunk_info[i]; i++)
8395967Speter	Total += chunk_info[i]->size;
8495967Speter    if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) {
85127326Smarkm	dialog_clear_norefresh();
8695967Speter	msgConfirm("WARNING:  A geometry of %d/%d/%d for %s is incorrect.  Using\n"
8795967Speter		   "a more likely geometry.  If this geometry is incorrect or you\n"
8895967Speter		   "are unsure as to whether or not it's correct, please consult\n"
8995967Speter		   "the Hardware Guide in the Documentation submenu or use the\n"
9095967Speter		   "(G)eometry command to change it now.\n\n"
9195967Speter		   "Remember: you need to enter whatever your BIOS thinks the\n"
9295967Speter		   "geometry is!  For IDE, it's what you were told in the BIOS\n"
9395967Speter		   "setup. For SCSI, it's the translation mode your controller is\n"
9495967Speter		   "using.  Do NOT use a ``physical geometry''.",
9595967Speter	  d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
9695967Speter	Sanitize_Bios_Geom(d);
9795967Speter    }
9895967Speter    attrset(A_NORMAL);
9995967Speter    mvaddstr(0, 0, "Disk name:\t");
10095967Speter    clrtobot();
10195967Speter    attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL);
10295967Speter    attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL);
10395967Speter    mvprintw(1, 0,
10495967Speter	     "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors",
10595967Speter	     d->bios_cyl, d->bios_hd, d->bios_sect,
10695967Speter	     d->bios_cyl * d->bios_hd * d->bios_sect);
10795967Speter    mvprintw(3, 0, "%10s %10s %10s %8s %6s %10s %8s %8s",
108127326Smarkm	     "Offset", "Size", "End", "Name", "PType", "Desc",
109127326Smarkm	     "Subtype", "Flags");
11095967Speter    for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
111127326Smarkm	if (i == current_chunk)
11295967Speter	    attrset(ATTR_SELECTED);
11395967Speter	mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s",
114127326Smarkm		 chunk_info[i]->offset, chunk_info[i]->size,
11595967Speter		 chunk_info[i]->end, chunk_info[i]->name,
11695967Speter		 chunk_info[i]->type,
117127326Smarkm		 slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype),
11895967Speter		 chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i]));
11995967Speter	if (i == current_chunk)
12095967Speter	    attrset(A_NORMAL);
121127326Smarkm    }
12295967Speter}
123127326Smarkm
12495967Speterstatic void
125127326Smarkmprint_command_summary()
12695967Speter{
127127326Smarkm    mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
12895967Speter    mvprintw(16, 0, "A = Use Entire Disk    B = Bad Block Scan       C = Create Slice");
129127326Smarkm    mvprintw(17, 0, "D = Delete Slice       G = Set Drive Geometry   S = Set Bootable");
13095967Speter    mvprintw(18, 0, "T = Change Type        U = Undo All Changes     Q = Finish");
131127326Smarkm    if (!RunningAsInit)
132127326Smarkm	mvprintw(18, 48, "W = Write Changes");
13395967Speter    mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select.");
13495967Speter    move(0, 0);
135127326Smarkm}
13695967Speter
13795967Speterstatic u_char *
13895967SpetergetBootMgr(char *dname)
13995967Speter{
14095967Speter#ifndef __alpha__	/* only meaningful on x86 */
14195967Speter    extern u_char mbr[], boot0[];
14295967Speter    char str[80];
14395967Speter    char *cp;
14495967Speter    int i = 0;
14595967Speter
14695967Speter    cp = variable_get(VAR_BOOTMGR);
14795967Speter    if (!cp) {
14895967Speter	/* Figure out what kind of MBR the user wants */
14995967Speter	sprintf(str, "Install Boot Manager for drive %s?", dname);
15095967Speter	MenuMBRType.title = str;
15195967Speter	i = dmenuOpenSimple(&MenuMBRType, FALSE);
15295967Speter    }
15395967Speter    else {
15495967Speter	if (!strncmp(cp, "boot", 4))
15595967Speter	    BootMgr = 0;
15695967Speter	else if (!strcmp(cp, "standard"))
15795967Speter	    BootMgr = 1;
158127326Smarkm	else
159127326Smarkm	    BootMgr = 2;
16095967Speter    }
161127326Smarkm    if (cp || i) {
16295967Speter	switch (BootMgr) {
16395967Speter	case 0:
164127326Smarkm	    return boot0;
16595967Speter
16695967Speter	case 1:
167127326Smarkm	    return mbr;
16895967Speter
16995967Speter	case 2:
17095967Speter	default:
171127326Smarkm	    break;
17295967Speter	}
173127326Smarkm    }
17495967Speter#endif
175127326Smarkm    return NULL;
17695967Speter}
177127326Smarkm
17895967Speterint
179127326SmarkmdiskGetSelectCount(Device ***devs)
18095967Speter{
181127326Smarkm    int i, cnt, enabled;
182127326Smarkm    char *cp;
18395967Speter    Device **dp;
18495967Speter
185127326Smarkm    cp = variable_get(VAR_DISK);
18695967Speter    dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK);
18795967Speter    cnt = deviceCount(dp);
18895967Speter    if (!cnt)
18995967Speter	return -1;
19095967Speter    for (i = 0, enabled = 0; i < cnt; i++) {
19195967Speter	if (dp[i]->enabled)
19295967Speter	    ++enabled;
19395967Speter    }
19495967Speter    return enabled;
19595967Speter}
19695967Speter
19795967Spetervoid
19895967SpeterdiskPartition(Device *dev)
19995967Speter{
20095967Speter    char *cp, *p;
20195967Speter    int rv, key = 0;
20295967Speter    Boolean chunking;
20395967Speter    char *msg = NULL;
20495967Speter    u_char *mbrContents;
20595967Speter    WINDOW *w = savescr();
20695967Speter    Disk *d = (Disk *)dev->private;
20795967Speter
208127326Smarkm    chunking = TRUE;
209127326Smarkm    keypad(stdscr, TRUE);
21095967Speter
211127326Smarkm    /* Flush both the dialog and curses library views of the screen
21295967Speter       since we don't always know who called us */
21395967Speter    dialog_clear_norefresh(), clear();
214127326Smarkm    current_chunk = 0;
21595967Speter
21695967Speter    /* Set up the chunk array */
217127326Smarkm    record_chunks(d);
21895967Speter
21995967Speter    while (chunking) {
22095967Speter	char *val, geometry[80];
221127326Smarkm
22295967Speter	/* Now print our overall state */
223127326Smarkm	if (d)
22495967Speter	    print_chunks(d);
225127326Smarkm	print_command_summary();
22695967Speter	if (msg) {
227127326Smarkm	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
22895967Speter	    beep();
229127326Smarkm	    msg = NULL;
23095967Speter	}
231127326Smarkm	else {
232127326Smarkm	    move(23, 0);
23395967Speter	    clrtoeol();
23495967Speter	}
235127326Smarkm
23695967Speter	/* Get command character */
23795967Speter	key = getch();
23895967Speter	switch (toupper(key)) {
23995967Speter	case '\014':	/* ^L (redraw) */
24095967Speter	    clear();
24195967Speter	    msg = NULL;
24295967Speter	    break;
24395967Speter
24495967Speter	case '\020':	/* ^P */
24595967Speter	case KEY_UP:
24695967Speter	case '-':
24795967Speter	    if (current_chunk != 0)
24895967Speter		--current_chunk;
24995967Speter	    break;
25095967Speter
25195967Speter	case '\016':	/* ^N */
25295967Speter	case KEY_DOWN:
25395967Speter	case '+':
25495967Speter	case '\r':
25595967Speter	case '\n':
25695967Speter	    if (chunk_info[current_chunk + 1])
25795967Speter		++current_chunk;
258127326Smarkm	    break;
259127326Smarkm
26095967Speter	case KEY_HOME:
261127326Smarkm	    current_chunk = 0;
26295967Speter	    break;
26395967Speter
264127326Smarkm	case KEY_END:
26595967Speter	    while (chunk_info[current_chunk + 1])
26695967Speter		++current_chunk;
267127326Smarkm	    break;
26895967Speter
26995967Speter	case KEY_F(1):
27095967Speter	case '?':
271127326Smarkm	    systemDisplayHelp("slice");
27295967Speter	    clear();
273127326Smarkm	    break;
27495967Speter
275127326Smarkm	case 'A':
27695967Speter#ifdef __alpha__
277127326Smarkm	    rv = 1;
27895967Speter#else	    /* The rest is only relevant on x86 */
279127326Smarkm	    cp = variable_get(VAR_DEDICATE_DISK);
28095967Speter	    if (cp && !strcasecmp(cp, "always"))
281127326Smarkm		rv = 1;
282127326Smarkm	    else {
28395967Speter		rv = msgYesNo("Do you want to do this with a true partition entry\n"
28495967Speter			      "so as to remain cooperative with any future possible\n"
285127326Smarkm			      "operating systems on the drive(s)?\n"
28695967Speter			      "(See also the section about ``dangerously dedicated''\n"
28795967Speter			      "disks in the FreeBSD FAQ.)");
28895967Speter		if (rv == -1)
28995967Speter		    rv = 0;
29095967Speter	    }
29195967Speter#endif
29295967Speter	    All_FreeBSD(d, rv);
29395967Speter	    variable_set2(DISK_PARTITIONED, "yes", 0);
29495967Speter	    record_chunks(d);
29595967Speter	    clear();
29695967Speter	    break;
29795967Speter
29895967Speter	case 'B':
29995967Speter	    if (chunk_info[current_chunk]->type != freebsd)
30095967Speter		msg = "Can only scan for bad blocks in FreeBSD slice.";
30195967Speter	    else if (strncmp(d->name, "sd", 2) ||
30295967Speter		     strncmp(d->name, "da", 2) ||
30395967Speter		     !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n"
30495967Speter			       "Are you sure you want to do this on a SCSI disk?")) {
30595967Speter		if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
30695967Speter		    chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
30795967Speter		else
308127326Smarkm		    chunk_info[current_chunk]->flags |= CHUNK_BAD144;
309127326Smarkm	    }
31095967Speter	    clear();
311127326Smarkm	    break;
31295967Speter
31395967Speter	case 'C':
314127326Smarkm	    if (chunk_info[current_chunk]->type != unused)
31595967Speter		msg = "Slice in use, delete it first or move to an unused one.";
31695967Speter	    else {
317127326Smarkm		char *val, tmp[20], *cp;
31895967Speter		int size, subtype;
31995967Speter		chunk_e partitiontype;
32095967Speter
321127326Smarkm		snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size);
32295967Speter		val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n"
323127326Smarkm				  "or append a trailing `M' for megabytes (e.g. 20M).");
32495967Speter		if (val && (size = strtol(val, &cp, 0)) > 0) {
325127326Smarkm		    if (*cp && toupper(*cp) == 'M')
32695967Speter			size *= ONE_MEG;
327127326Smarkm		    strcpy(tmp, "165");
32895967Speter		    val = msgGetInput(tmp, "Enter type of partition to create:\n\n"
329127326Smarkm				      "Pressing Enter will choose the default, a native FreeBSD\n"
33095967Speter				      "slice (type 165).  You can choose other types, 6 for a\n"
331127326Smarkm				      "DOS partition or 131 for a Linux partition, for example.\n\n"
332127326Smarkm				      "Note:  If you choose a non-FreeBSD partition type, it will not\n"
33395967Speter				      "be formatted or otherwise prepared, it will simply reserve space\n"
33495967Speter				      "for you to use another tool, such as DOS FORMAT, to later format\n"
335127326Smarkm				      "and use the partition.");
33695967Speter		    if (val && (subtype = strtol(val, NULL, 0)) > 0) {
33795967Speter			if (subtype == 165)
33895967Speter			    partitiontype = freebsd;
33995967Speter			else if (subtype == 6)
34095967Speter			    partitiontype = fat;
34195967Speter			else
34295967Speter			    partitiontype = unknown;
34395967Speter#ifdef __alpha__
34495967Speter			if (partitiontype == freebsd && size == chunk_info[current_chunk]->size)
34595967Speter			    All_FreeBSD(d, 1);
34695967Speter			else
34795967Speter#endif
34895967Speter			Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype,
34995967Speter				     (chunk_info[current_chunk]->flags & CHUNK_ALIGN));
35095967Speter			variable_set2(DISK_PARTITIONED, "yes", 0);
35195967Speter			record_chunks(d);
35295967Speter		    }
35395967Speter		}
35495967Speter		clear();
35595967Speter	    }
35695967Speter	    break;
35795967Speter
358127326Smarkm	case KEY_DC:
359127326Smarkm	case 'D':
36095967Speter	    if (chunk_info[current_chunk]->type == unused)
361127326Smarkm		msg = "Slice is already unused!";
36295967Speter	    else {
36395967Speter		Delete_Chunk(d, chunk_info[current_chunk]);
364127326Smarkm		variable_set2(DISK_PARTITIONED, "yes", 0);
36595967Speter		record_chunks(d);
36695967Speter	    }
367127326Smarkm	    break;
36895967Speter
36995967Speter	case 'T':
37095967Speter	    if (chunk_info[current_chunk]->type == unused)
371127326Smarkm		msg = "Slice is currently unused (use create instead)";
37295967Speter	    else {
373127326Smarkm		char *val, tmp[20];
37495967Speter		int subtype;
375127326Smarkm		chunk_e partitiontype;
37695967Speter		WINDOW *save = savescr();
377127326Smarkm
37895967Speter		strcpy(tmp, "165");
379127326Smarkm		val = msgGetInput(tmp, "New partition type:\n\n"
38095967Speter				  "Pressing Enter will choose the default, a native FreeBSD\n"
381127326Smarkm				  "slice (type 165).  Other popular values are 6 for\n"
382127326Smarkm				  "DOS FAT partition, 131 for a Linux ext2fs partition or\n"
38395967Speter				  "130 for a Linux swap partition.\n\n"
38495967Speter				  "Note:  If you choose a non-FreeBSD partition type, it will not\n"
385127326Smarkm				  "be formatted or otherwise prepared, it will simply reserve space\n"
38695967Speter				  "for you to use another tool, such as DOS format, to later format\n"
38795967Speter				  "and actually use the partition.");
38895967Speter		if (val && (subtype = strtol(val, NULL, 0)) > 0) {
38995967Speter		    if (subtype == 165)
39095967Speter			partitiontype = freebsd;
39195967Speter		    else if (subtype == 6)
39295967Speter			partitiontype = fat;
39395967Speter		    else
39495967Speter			partitiontype = unknown;
39595967Speter		    chunk_info[current_chunk]->type = partitiontype;
39695967Speter		    chunk_info[current_chunk]->subtype = subtype;
39795967Speter		}
39895967Speter		restorescr(save);
39995967Speter	    }
40095967Speter	    break;
40195967Speter
40295967Speter	case 'G':
40395967Speter	    snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect);
40495967Speter	    val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n"
40595967Speter			      "Don't forget to use the two slash (/) separator characters!\n"
40695967Speter			      "It's not possible to parse the field without them.");
40795967Speter	    if (val) {
408127326Smarkm		long nc, nh, ns;
409127326Smarkm		nc = strtol(val, &val, 0);
41095967Speter		nh = strtol(val + 1, &val, 0);
411127326Smarkm		ns = strtol(val + 1, 0, 0);
41295967Speter		Set_Bios_Geom(d, nc, nh, ns);
41395967Speter	    }
414127326Smarkm	    clear();
41595967Speter	    break;
41695967Speter
417127326Smarkm	case 'S':
41895967Speter	    /* Set Bootable */
41995967Speter	    chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
42095967Speter	    break;
421127326Smarkm
42295967Speter	case 'U':
423127326Smarkm	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
42495967Speter		msgConfirm("You've already written this information out - you\n"
425127326Smarkm			   "can't undo it.");
42695967Speter	    }
427127326Smarkm	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
42895967Speter		char cp[BUFSIZ];
429127326Smarkm
43095967Speter		sstrncpy(cp, d->name, sizeof cp);
431127326Smarkm		Free_Disk(dev->private);
432127326Smarkm		d = Open_Disk(cp);
43395967Speter		if (!d)
43495967Speter		    msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp);
435127326Smarkm		dev->private = d;
43695967Speter		variable_unset(DISK_PARTITIONED);
43795967Speter		variable_unset(DISK_LABELLED);
43895967Speter		if (d)
43995967Speter		    record_chunks(d);
44095967Speter	    }
44195967Speter	    clear();
44295967Speter	    break;
44395967Speter
44495967Speter	case 'W':
44595967Speter	    if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
44695967Speter			       "installation.  If you are installing FreeBSD for the first time\n"
44795967Speter			       "then you should simply type Q when you're finished here and your\n"
44895967Speter			       "changes will be committed in one batch automatically at the end of\n"
44995967Speter			       "these questions.  If you're adding a disk, you should NOT write\n"
45095967Speter			       "from this screen, you should do it from the label editor.\n\n"
45195967Speter			       "Are you absolutely sure you want to do this now?")) {
45295967Speter		variable_set2(DISK_PARTITIONED, "yes", 0);
45395967Speter
45495967Speter		/* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
45595967Speter		 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
45695967Speter		 * booteasy or a "standard" MBR -- both would be fatal in this case.
45795967Speter		 */
458127326Smarkm#if 0
459127326Smarkm		if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
46095967Speter		    && (mbrContents = getBootMgr(d->name)) != NULL)
461127326Smarkm		    Set_Boot_Mgr(d, mbrContents);
46295967Speter#else
46395967Speter		/*
464127326Smarkm		 * Don't offer to update the MBR on this disk if the first "real" chunk looks like
46595967Speter		 * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD.
46695967Speter		 */
467127326Smarkm		if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) &&
46895967Speter		    (mbrContents = getBootMgr(d->name)) != NULL)
46995967Speter		    Set_Boot_Mgr(d, mbrContents);
47095967Speter#endif
471127326Smarkm
47295967Speter		if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS)
473127326Smarkm		    msgConfirm("Disk partition write returned an error status!");
47495967Speter		else
475127326Smarkm		    msgConfirm("Wrote FDISK partition information out successfully.");
47695967Speter	    }
477127326Smarkm	    clear();
47895967Speter	    break;
479127326Smarkm
48095967Speter	case '|':
481127326Smarkm	    if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n"
482127326Smarkm			  "No seat belts whatsoever are provided!")) {
48395967Speter		clear();
48495967Speter		refresh();
485127326Smarkm		slice_wizard(d);
48695967Speter		variable_set2(DISK_PARTITIONED, "yes", 0);
48795967Speter		record_chunks(d);
48895967Speter	    }
48995967Speter	    else
49095967Speter		msg = "Wise choice!";
49195967Speter	    clear();
49295967Speter	    break;
49395967Speter
49495967Speter	case '\033':	/* ESC */
49595967Speter	case 'Q':
49695967Speter	    chunking = FALSE;
49795967Speter	    /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
49895967Speter	     * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
49995967Speter	     * booteasy or a "standard" MBR -- both would be fatal in this case.
50095967Speter	     */
50195967Speter#if 0
50295967Speter	    if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
50395967Speter		&& (mbrContents = getBootMgr(d->name)) != NULL)
50495967Speter		Set_Boot_Mgr(d, mbrContents);
50595967Speter#else
50695967Speter	    /*
50795967Speter	     * Don't offer to update the MBR on this disk if the first "real" chunk looks like
508127326Smarkm	     * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD.
509127326Smarkm	     */
51095967Speter	    if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) &&
511127326Smarkm		(mbrContents = getBootMgr(d->name)) != NULL)
51295967Speter		Set_Boot_Mgr(d, mbrContents);
51395967Speter#endif
514127326Smarkm	    break;
51595967Speter
51695967Speter	default:
517127326Smarkm	    beep();
51895967Speter	    msg = "Type F1 or ? for help";
51995967Speter	    break;
52095967Speter	}
521127326Smarkm    }
52295967Speter    p = CheckRules(d);
523127326Smarkm    if (p) {
52495967Speter	char buf[FILENAME_MAX];
525127326Smarkm
52695967Speter	dialog_clear_norefresh();
527127326Smarkm        use_helpline("Press F1 to read more about disk slices.");
52895967Speter	use_helpfile(systemHelpFile("partition", buf));
529127326Smarkm	if (!variable_get(VAR_NO_WARN))
53095967Speter	    dialog_mesgbox("Disk slicing warning:", p, -1, -1);
531127326Smarkm	free(p);
532127326Smarkm    }
53395967Speter    restorescr(w);
53495967Speter}
535127326Smarkm
53695967Speterstatic u_char *
53795967Speterbootalloc(char *name)
53895967Speter{
53995967Speter    char buf[FILENAME_MAX];
54095967Speter    struct stat sb;
54195967Speter
54295967Speter    snprintf(buf, sizeof buf, "/boot/%s", name);
54395967Speter    if (stat(buf, &sb) != -1) {
54495967Speter	int fd;
54595967Speter
54695967Speter	fd = open(buf, O_RDONLY);
54795967Speter	if (fd != -1) {
54895967Speter	    u_char *cp;
54995967Speter
55095967Speter	    cp = malloc(sb.st_size);
55195967Speter	    if (read(fd, cp, sb.st_size) != sb.st_size) {
55295967Speter		free(cp);
55395967Speter		close(fd);
55495967Speter		msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf);
55595967Speter		return NULL;
55695967Speter	    }
55795967Speter	    close(fd);
558127326Smarkm	    return cp;
559127326Smarkm	}
56095967Speter	msgDebug("bootalloc: couldn't open %s\n", buf);
561127326Smarkm    }
56295967Speter    else
56395967Speter	msgDebug("bootalloc: can't stat %s\n", buf);
564127326Smarkm    return NULL;
56595967Speter}
56695967Speter
567127326Smarkmstatic int
56895967SpeterpartitionHook(dialogMenuItem *selected)
56995967Speter{
57095967Speter    Device **devs = NULL;
571127326Smarkm
57295967Speter    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
573127326Smarkm    if (!devs) {
57495967Speter	msgConfirm("Unable to find disk %s!", selected->prompt);
575127326Smarkm	return DITEM_FAILURE;
57695967Speter    }
577127326Smarkm    /* Toggle enabled status? */
57895967Speter    if (!devs[0]->enabled) {
579127326Smarkm	devs[0]->enabled = TRUE;
58095967Speter	diskPartition(devs[0]);
581127326Smarkm    }
582127326Smarkm    else
58395967Speter	devs[0]->enabled = FALSE;
58495967Speter    return DITEM_SUCCESS | DITEM_RESTORE;
585127326Smarkm}
58695967Speter
58795967Speterstatic int
58895967SpeterpartitionCheck(dialogMenuItem *selected)
58995967Speter{
59095967Speter    Device **devs = NULL;
59195967Speter
59295967Speter    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
59395967Speter    if (!devs || devs[0]->enabled == FALSE)
59495967Speter	return FALSE;
59595967Speter    return TRUE;
59695967Speter}
59795967Speter
59895967Speterint
59995967SpeterdiskPartitionEditor(dialogMenuItem *self)
60095967Speter{
60195967Speter    DMenu *menu;
60295967Speter    Device **devs;
60395967Speter    int i, cnt, devcnt;
60495967Speter
60595967Speter    cnt = diskGetSelectCount(&devs);
60695967Speter    devcnt = deviceCount(devs);
60795967Speter    if (cnt == -1) {
608127326Smarkm	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
609127326Smarkm		   "properly probed at boot time.  See the Hardware Guide on the\n"
61095967Speter		   "Documentation menu for clues on diagnosing this type of problem.");
611127326Smarkm	return DITEM_FAILURE;
61295967Speter    }
61395967Speter    else if (cnt) {
614127326Smarkm	/* Some are already selected */
61595967Speter	for (i = 0; i < devcnt; i++) {
61695967Speter	    if (devs[i]->enabled) {
617127326Smarkm		if (variable_get(VAR_NONINTERACTIVE))
61895967Speter		    diskPartitionNonInteractive(devs[i]);
61995967Speter		else
62095967Speter		    diskPartition(devs[i]);
621127326Smarkm	    }
62295967Speter	}
623127326Smarkm    }
62495967Speter    else {
625127326Smarkm	/* No disks are selected, fall-back case now */
62695967Speter	if (devcnt == 1) {
627127326Smarkm	    devs[0]->enabled = TRUE;
62895967Speter	    if (variable_get(VAR_NONINTERACTIVE))
629127326Smarkm		diskPartitionNonInteractive(devs[0]);
63095967Speter	    else
631127326Smarkm		diskPartition(devs[0]);
632127326Smarkm	    return DITEM_SUCCESS;
63395967Speter	}
63495967Speter	else {
635127326Smarkm	    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck);
63695967Speter	    if (!menu) {
63795967Speter		msgConfirm("No devices suitable for installation found!\n\n"
63895967Speter			   "Please verify that your disk controller (and attached drives)\n"
63995967Speter			   "were detected properly.  This can be done by pressing the\n"
64095967Speter			   "[Scroll Lock] key and using the Arrow keys to move back to\n"
64195967Speter			   "the boot messages.  Press [Scroll Lock] again to return.");
64295967Speter		return DITEM_FAILURE;
64395967Speter	    }
64495967Speter	    else {
64595967Speter		i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
64695967Speter		free(menu);
64795967Speter	    }
64895967Speter	    return i | DITEM_RESTORE;
64995967Speter	}
65095967Speter    }
65195967Speter    return DITEM_SUCCESS;
65295967Speter}
65395967Speter
65495967Speterint
65595967SpeterdiskPartitionWrite(dialogMenuItem *self)
65695967Speter{
65795967Speter    Device **devs;
658127326Smarkm    int i;
659127326Smarkm    char *cp;
66095967Speter
661127326Smarkm    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
66295967Speter    if (!devs) {
66395967Speter	msgConfirm("Unable to find any disks to write to??");
664127326Smarkm	return DITEM_FAILURE;
66595967Speter    }
66695967Speter    if (isDebug())
667127326Smarkm	msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs));
66895967Speter    cp = variable_get(DISK_PARTITIONED);
66995967Speter    if (cp && !strcmp(cp, "written"))
67095967Speter	return DITEM_SUCCESS;
671127326Smarkm
67295967Speter    for (i = 0; devs[i]; i++) {
673127326Smarkm	Chunk *c1;
67495967Speter	Disk *d = (Disk *)devs[i]->private;
675127326Smarkm	static u_char *boot1;
67695967Speter#ifndef __alpha__
677127326Smarkm	static u_char *boot2;
67895967Speter#endif
679127326Smarkm
68095967Speter	if (!devs[i]->enabled)
681127326Smarkm	    continue;
682127326Smarkm
68395967Speter#ifdef __alpha__
68495967Speter	if (!boot1) boot1 = bootalloc("boot1");
685127326Smarkm	Set_Boot_Blocks(d, boot1, NULL);
68695967Speter#else
68795967Speter	if (!boot1) boot1 = bootalloc("boot1");
68895967Speter	if (!boot2) boot2 = bootalloc("boot2");
68995967Speter	Set_Boot_Blocks(d, boot1, boot2);
69095967Speter#endif
69195967Speter
69295967Speter	msgNotify("Writing partition information to drive %s", d->name);
69395967Speter	if (!Fake && Write_Disk(d)) {
69495967Speter	    msgConfirm("ERROR: Unable to write data to disk %s!", d->name);
69595967Speter	    return DITEM_FAILURE;
69695967Speter	}
69795967Speter
69895967Speter	/* If we've been through here before, we don't need to do the rest */
69995967Speter	if (cp && !strcmp(cp, "written"))
70095967Speter	    return DITEM_SUCCESS;
70195967Speter
70295967Speter	/* Now scan for bad blocks, if necessary */
70395967Speter	for (c1 = d->chunks->part; c1; c1 = c1->next) {
70495967Speter	    if (c1->flags & CHUNK_BAD144) {
70595967Speter		int ret;
70695967Speter
70795967Speter		msgNotify("Running bad block scan on slice %s", c1->name);
708127326Smarkm		if (!Fake) {
709127326Smarkm		    ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
71095967Speter		    if (ret)
711127326Smarkm			msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
71295967Speter		    ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
71395967Speter		    if (ret)
714127326Smarkm			msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
71595967Speter		}
71695967Speter	    }
717127326Smarkm	}
71895967Speter    }
71995967Speter    /* Now it's not "yes", but "written" */
72095967Speter    variable_set2(DISK_PARTITIONED, "written", 0);
721127326Smarkm    return DITEM_SUCCESS;
72295967Speter}
723127326Smarkm
72495967Speter/* Partition a disk based wholly on which variables are set */
725127326Smarkmstatic void
72695967SpeterdiskPartitionNonInteractive(Device *dev)
727127326Smarkm{
72895967Speter    char *cp;
729127326Smarkm    int i, sz, all_disk = 0;
73095967Speter    u_char *mbrContents;
731127326Smarkm    Disk *d = (Disk *)dev->private;
732127326Smarkm
73395967Speter    record_chunks(d);
73495967Speter    cp = variable_get(VAR_GEOMETRY);
735127326Smarkm    if (cp) {
73695967Speter	msgDebug("Setting geometry from script to: %s\n", cp);
73795967Speter	d->bios_cyl = strtol(cp, &cp, 0);
73895967Speter	d->bios_hd = strtol(cp + 1, &cp, 0);
73995967Speter	d->bios_sect = strtol(cp + 1, 0, 0);
74095967Speter    }
74195967Speter
74295967Speter    cp = variable_get(VAR_PARTITION);
74395967Speter    if (cp) {
74495967Speter	if (!strcmp(cp, "free")) {
74595967Speter	    /* Do free disk space case */
74695967Speter	    for (i = 0; chunk_info[i]; i++) {
74795967Speter		/* If a chunk is at least 10MB in size, use it. */
74895967Speter		if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) {
74995967Speter		    Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3,
75095967Speter				 (chunk_info[i]->flags & CHUNK_ALIGN));
75195967Speter		    variable_set2(DISK_PARTITIONED, "yes", 0);
75295967Speter		    break;
75395967Speter		}
75495967Speter	    }
75595967Speter	    if (!chunk_info[i]) {
75695967Speter		dialog_clear();
75795967Speter		msgConfirm("Unable to find any free space on this disk!");
758127326Smarkm		return;
759127326Smarkm	    }
76095967Speter	}
761127326Smarkm	else if (!strcmp(cp, "all")) {
76295967Speter	    /* Do all disk space case */
76395967Speter	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
764127326Smarkm
76595967Speter	    All_FreeBSD(d, FALSE);
76695967Speter	}
767127326Smarkm	else if (!strcmp(cp, "exclusive")) {
76895967Speter	    /* Do really-all-the-disk-space case */
76995967Speter	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
77095967Speter
771127326Smarkm	    All_FreeBSD(d, all_disk = TRUE);
77295967Speter	}
773127326Smarkm	else if ((sz = strtol(cp, &cp, 0))) {
77495967Speter	    /* Look for sz bytes free */
775127326Smarkm	    if (*cp && toupper(*cp) == 'M')
77695967Speter		sz *= ONE_MEG;
777127326Smarkm	    for (i = 0; chunk_info[i]; i++) {
77895967Speter		/* If a chunk is at least sz MB, use it. */
779127326Smarkm		if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) {
78095967Speter		    Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN));
781127326Smarkm		    variable_set2(DISK_PARTITIONED, "yes", 0);
782127326Smarkm		    break;
78395967Speter		}
78495967Speter	    }
785127326Smarkm	    if (!chunk_info[i]) {
78695967Speter		dialog_clear();
78795967Speter		msgConfirm("Unable to find %d free blocks on this disk!", sz);
78895967Speter		return;
78995967Speter	    }
79095967Speter	}
79195967Speter	else if (!strcmp(cp, "existing")) {
79295967Speter	    /* Do existing FreeBSD case */
79395967Speter	    for (i = 0; chunk_info[i]; i++) {
79495967Speter		if (chunk_info[i]->type == freebsd)
79595967Speter		    break;
79695967Speter	    }
79795967Speter	    if (!chunk_info[i]) {
79895967Speter		dialog_clear();
79995967Speter		msgConfirm("Unable to find any existing FreeBSD partitions on this disk!");
80095967Speter		return;
80195967Speter	    }
80295967Speter	}
80395967Speter	else {
80495967Speter	    dialog_clear();
80595967Speter	    msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION);
80695967Speter	    return;
80795967Speter	}
808127326Smarkm	if (!all_disk) {
809127326Smarkm	    mbrContents = getBootMgr(d->name);
81095967Speter	    Set_Boot_Mgr(d, mbrContents);
811127326Smarkm	}
81295967Speter	variable_set2(DISK_PARTITIONED, "yes", 0);
81395967Speter    }
814127326Smarkm}
81595967Speter