disks.c revision 50479
1297627Sjmcneill/*
2297627Sjmcneill * The new sysinstall program.
3297627Sjmcneill *
4297627Sjmcneill * This is probably the last program in the `sysinstall' line - the next
5297627Sjmcneill * generation being essentially a complete rewrite.
6297627Sjmcneill *
7297627Sjmcneill * $FreeBSD: head/usr.sbin/sade/disks.c 50479 1999-08-28 01:35:59Z peter $
8297627Sjmcneill *
9297627Sjmcneill * Copyright (c) 1995
10297627Sjmcneill *	Jordan Hubbard.  All rights reserved.
11297627Sjmcneill *
12297627Sjmcneill * Redistribution and use in source and binary forms, with or without
13297627Sjmcneill * modification, are permitted provided that the following conditions
14297627Sjmcneill * are met:
15297627Sjmcneill * 1. Redistributions of source code must retain the above copyright
16297627Sjmcneill *    notice, this list of conditions and the following disclaimer,
17297627Sjmcneill *    verbatim and that no modifications are made prior to this
18297627Sjmcneill *    point in the file.
19297627Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
20297627Sjmcneill *    notice, this list of conditions and the following disclaimer in the
21297627Sjmcneill *    documentation and/or other materials provided with the distribution.
22297627Sjmcneill *
23297627Sjmcneill * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
24297627Sjmcneill * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25297627Sjmcneill * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26297627Sjmcneill * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
27297627Sjmcneill * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28297627Sjmcneill * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29297627Sjmcneill * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
30297627Sjmcneill * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31297627Sjmcneill * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32297627Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33297627Sjmcneill * SUCH DAMAGE.
34297627Sjmcneill *
35297627Sjmcneill */
36297627Sjmcneill
37297627Sjmcneill#include "sysinstall.h"
38297627Sjmcneill#include <ctype.h>
39297627Sjmcneill#include <fcntl.h>
40297627Sjmcneill#include <sys/stat.h>
41297627Sjmcneill#include <sys/disklabel.h>
42297627Sjmcneill
43297627Sjmcneill/* Where we start displaying chunk information on the screen */
44297627Sjmcneill#define CHUNK_START_ROW		5
45297627Sjmcneill
46297627Sjmcneill/* Where we keep track of MBR chunks */
47297627Sjmcneillstatic struct chunk *chunk_info[16];
48297627Sjmcneillstatic int current_chunk;
49297627Sjmcneill
50297627Sjmcneillstatic void	diskPartitionNonInteractive(Device *dev);
51297627Sjmcneill
52308274Smanustatic void
53305436Smanurecord_chunks(Disk *d)
54297627Sjmcneill{
55297627Sjmcneill    struct chunk *c1 = NULL;
56297627Sjmcneill    int i = 0;
57297627Sjmcneill    int last_free = 0;
58297627Sjmcneill
59297627Sjmcneill    if (!d->chunks)
60297627Sjmcneill	msgFatal("No chunk list found for %s!", d->name);
61297627Sjmcneill
62297627Sjmcneill    for (c1 = d->chunks->part; c1; c1 = c1->next) {
63297627Sjmcneill	if (c1->type == unused && c1->size > last_free) {
64297627Sjmcneill	    last_free = c1->size;
65297627Sjmcneill	    current_chunk = i;
66297627Sjmcneill	}
67297627Sjmcneill	chunk_info[i++] = c1;
68297627Sjmcneill    }
69297627Sjmcneill    chunk_info[i] = NULL;
70297627Sjmcneill    if (current_chunk >= i)
71297627Sjmcneill	current_chunk = i - 1;
72297627Sjmcneill}
73297627Sjmcneill
74297627Sjmcneillstatic int Total;
75297627Sjmcneill
76297627Sjmcneillstatic void
77297627Sjmcneillprint_chunks(Disk *d)
78297627Sjmcneill{
79297627Sjmcneill    int row;
80297627Sjmcneill    int i;
81297627Sjmcneill
82297627Sjmcneill    for (i = Total = 0; chunk_info[i]; i++)
83297627Sjmcneill	Total += chunk_info[i]->size;
84297627Sjmcneill    if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) {
85297627Sjmcneill	dialog_clear_norefresh();
86297627Sjmcneill	msgConfirm("WARNING:  A geometry of %d/%d/%d for %s is incorrect.  Using\n"
87297627Sjmcneill		   "a more likely geometry.  If this geometry is incorrect or you\n"
88297627Sjmcneill		   "are unsure as to whether or not it's correct, please consult\n"
89297627Sjmcneill		   "the Hardware Guide in the Documentation submenu or use the\n"
90297627Sjmcneill		   "(G)eometry command to change it now.\n\n"
91297627Sjmcneill		   "Remember: you need to enter whatever your BIOS thinks the\n"
92297627Sjmcneill		   "geometry is!  For IDE, it's what you were told in the BIOS\n"
93297627Sjmcneill		   "setup. For SCSI, it's the translation mode your controller is\n"
94297627Sjmcneill		   "using.  Do NOT use a ``physical geometry''.",
95297627Sjmcneill	  d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
96297627Sjmcneill	Sanitize_Bios_Geom(d);
97297627Sjmcneill    }
98297627Sjmcneill    attrset(A_NORMAL);
99297627Sjmcneill    mvaddstr(0, 0, "Disk name:\t");
100297627Sjmcneill    clrtobot();
101297627Sjmcneill    attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL);
102297627Sjmcneill    attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL);
103297627Sjmcneill    mvprintw(1, 0,
104297627Sjmcneill	     "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors",
105297627Sjmcneill	     d->bios_cyl, d->bios_hd, d->bios_sect,
106305436Smanu	     d->bios_cyl * d->bios_hd * d->bios_sect);
107305436Smanu    mvprintw(3, 0, "%10s %10s %10s %8s %6s %10s %8s %8s",
108305436Smanu	     "Offset", "Size", "End", "Name", "PType", "Desc",
109305436Smanu	     "Subtype", "Flags");
110305436Smanu    for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
111305436Smanu	if (i == current_chunk)
112305436Smanu	    attrset(ATTR_SELECTED);
113299688Smanu	mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s",
114299688Smanu		 chunk_info[i]->offset, chunk_info[i]->size,
115299688Smanu		 chunk_info[i]->end, chunk_info[i]->name,
116299688Smanu		 chunk_info[i]->type,
117299688Smanu		 slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype),
118299688Smanu		 chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i]));
119299688Smanu	if (i == current_chunk)
120299688Smanu	    attrset(A_NORMAL);
121299688Smanu    }
122297627Sjmcneill}
123297627Sjmcneill
124297627Sjmcneillstatic void
125297627Sjmcneillprint_command_summary()
126297627Sjmcneill{
127297627Sjmcneill    mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
128297627Sjmcneill    mvprintw(16, 0, "A = Use Entire Disk    B = Bad Block Scan       C = Create Slice");
129297627Sjmcneill    mvprintw(17, 0, "D = Delete Slice       G = Set Drive Geometry   S = Set Bootable");
130297627Sjmcneill    mvprintw(18, 0, "T = Change Type        U = Undo All Changes     Q = Finish");
131297627Sjmcneill    if (!RunningAsInit)
132297627Sjmcneill	mvprintw(18, 48, "W = Write Changes");
133297627Sjmcneill    mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select.");
134297627Sjmcneill    move(0, 0);
135297627Sjmcneill}
136297627Sjmcneill
137297627Sjmcneillstatic u_char *
138297627SjmcneillgetBootMgr(char *dname)
139297627Sjmcneill{
140297627Sjmcneill#ifndef __alpha__	/* only meaningful on x86 */
141297627Sjmcneill    extern u_char mbr[], boot0[];
142297627Sjmcneill    char str[80];
143297627Sjmcneill    char *cp;
144297627Sjmcneill    int i = 0;
145299113Sjmcneill
146299113Sjmcneill    cp = variable_get(VAR_BOOTMGR);
147299113Sjmcneill    if (!cp) {
148299113Sjmcneill	/* Figure out what kind of MBR the user wants */
149299113Sjmcneill	sprintf(str, "Install Boot Manager for drive %s?", dname);
150299113Sjmcneill	MenuMBRType.title = str;
151297627Sjmcneill	i = dmenuOpenSimple(&MenuMBRType, FALSE);
152297627Sjmcneill    }
153297627Sjmcneill    else {
154297627Sjmcneill	if (!strncmp(cp, "boot", 4))
155297627Sjmcneill	    BootMgr = 0;
156297627Sjmcneill	else if (!strcmp(cp, "standard"))
157297627Sjmcneill	    BootMgr = 1;
158297627Sjmcneill	else
159297627Sjmcneill	    BootMgr = 2;
160297627Sjmcneill    }
161297627Sjmcneill    if (cp || i) {
162297627Sjmcneill	switch (BootMgr) {
163297627Sjmcneill	case 0:
164297627Sjmcneill	    return boot0;
165297627Sjmcneill
166297627Sjmcneill	case 1:
167297627Sjmcneill	    return mbr;
168297627Sjmcneill
169297627Sjmcneill	case 2:
170297627Sjmcneill	default:
171305436Smanu	    break;
172299688Smanu	}
173297627Sjmcneill    }
174297627Sjmcneill#endif
175299113Sjmcneill    return NULL;
176297627Sjmcneill}
177297627Sjmcneill
178297627Sjmcneillint
179297627SjmcneilldiskGetSelectCount(Device ***devs)
180297627Sjmcneill{
181297627Sjmcneill    int i, cnt, enabled;
182297627Sjmcneill    char *cp;
183297627Sjmcneill    Device **dp;
184297627Sjmcneill
185297627Sjmcneill    cp = variable_get(VAR_DISK);
186297627Sjmcneill    dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK);
187297627Sjmcneill    cnt = deviceCount(dp);
188297627Sjmcneill    if (!cnt)
189297627Sjmcneill	return -1;
190297627Sjmcneill    for (i = 0, enabled = 0; i < cnt; i++) {
191297627Sjmcneill	if (dp[i]->enabled)
192297627Sjmcneill	    ++enabled;
193297627Sjmcneill    }
194297627Sjmcneill    return enabled;
195297627Sjmcneill}
196297627Sjmcneill
197297627Sjmcneillvoid
198297627SjmcneilldiskPartition(Device *dev)
199297627Sjmcneill{
200297627Sjmcneill    char *cp, *p;
201297627Sjmcneill    int rv, key = 0;
202297627Sjmcneill    Boolean chunking;
203297627Sjmcneill    char *msg = NULL;
204297627Sjmcneill    u_char *mbrContents;
205297627Sjmcneill    WINDOW *w = savescr();
206297627Sjmcneill    Disk *d = (Disk *)dev->private;
207297627Sjmcneill
208297627Sjmcneill    chunking = TRUE;
209297627Sjmcneill    keypad(stdscr, TRUE);
210297627Sjmcneill
211297627Sjmcneill    /* Flush both the dialog and curses library views of the screen
212297627Sjmcneill       since we don't always know who called us */
213297627Sjmcneill    dialog_clear_norefresh(), clear();
214297627Sjmcneill    current_chunk = 0;
215297627Sjmcneill
216297627Sjmcneill    /* Set up the chunk array */
217297627Sjmcneill    record_chunks(d);
218297627Sjmcneill
219297627Sjmcneill    while (chunking) {
220297627Sjmcneill	char *val, geometry[80];
221297627Sjmcneill
222297627Sjmcneill	/* Now print our overall state */
223297627Sjmcneill	if (d)
224297627Sjmcneill	    print_chunks(d);
225297627Sjmcneill	print_command_summary();
226297627Sjmcneill	if (msg) {
227297627Sjmcneill	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
228297627Sjmcneill	    beep();
229297627Sjmcneill	    msg = NULL;
230297627Sjmcneill	}
231297627Sjmcneill	else {
232297627Sjmcneill	    move(23, 0);
233297627Sjmcneill	    clrtoeol();
234297627Sjmcneill	}
235297627Sjmcneill
236297627Sjmcneill	/* Get command character */
237297627Sjmcneill	key = getch();
238297627Sjmcneill	switch (toupper(key)) {
239297627Sjmcneill	case '\014':	/* ^L (redraw) */
240297627Sjmcneill	    clear();
241297627Sjmcneill	    msg = NULL;
242297627Sjmcneill	    break;
243297627Sjmcneill
244297627Sjmcneill	case '\020':	/* ^P */
245297627Sjmcneill	case KEY_UP:
246297627Sjmcneill	case '-':
247297627Sjmcneill	    if (current_chunk != 0)
248297627Sjmcneill		--current_chunk;
249297627Sjmcneill	    break;
250297627Sjmcneill
251297627Sjmcneill	case '\016':	/* ^N */
252297627Sjmcneill	case KEY_DOWN:
253297627Sjmcneill	case '+':
254297627Sjmcneill	case '\r':
255297627Sjmcneill	case '\n':
256297627Sjmcneill	    if (chunk_info[current_chunk + 1])
257297627Sjmcneill		++current_chunk;
258297627Sjmcneill	    break;
259297627Sjmcneill
260297627Sjmcneill	case KEY_HOME:
261297627Sjmcneill	    current_chunk = 0;
262297627Sjmcneill	    break;
263297627Sjmcneill
264297627Sjmcneill	case KEY_END:
265297627Sjmcneill	    while (chunk_info[current_chunk + 1])
266297627Sjmcneill		++current_chunk;
267297627Sjmcneill	    break;
268297627Sjmcneill
269297627Sjmcneill	case KEY_F(1):
270297627Sjmcneill	case '?':
271297627Sjmcneill	    systemDisplayHelp("slice");
272297627Sjmcneill	    clear();
273297627Sjmcneill	    break;
274297627Sjmcneill
275297627Sjmcneill	case 'A':
276297627Sjmcneill#ifdef __alpha__
277297627Sjmcneill	    rv = 1;
278297627Sjmcneill#else	    /* The rest is only relevant on x86 */
279297627Sjmcneill	    cp = variable_get(VAR_DEDICATE_DISK);
280297627Sjmcneill	    if (cp && !strcasecmp(cp, "always"))
281297627Sjmcneill		rv = 1;
282297627Sjmcneill	    else {
283297627Sjmcneill		rv = msgYesNo("Do you want to do this with a true partition entry\n"
284297627Sjmcneill			      "so as to remain cooperative with any future possible\n"
285297627Sjmcneill			      "operating systems on the drive(s)?\n"
286297627Sjmcneill			      "(See also the section about ``dangerously dedicated''\n"
287297627Sjmcneill			      "disks in the FreeBSD FAQ.)");
288297627Sjmcneill		if (rv == -1)
289297627Sjmcneill		    rv = 0;
290297627Sjmcneill	    }
291297627Sjmcneill#endif
292297627Sjmcneill	    All_FreeBSD(d, rv);
293297627Sjmcneill	    variable_set2(DISK_PARTITIONED, "yes", 0);
294297627Sjmcneill	    record_chunks(d);
295297627Sjmcneill	    clear();
296297627Sjmcneill	    break;
297297627Sjmcneill
298297627Sjmcneill	case 'B':
299297627Sjmcneill	    if (chunk_info[current_chunk]->type != freebsd)
300297627Sjmcneill		msg = "Can only scan for bad blocks in FreeBSD slice.";
301297627Sjmcneill	    else if (strncmp(d->name, "sd", 2) ||
302297627Sjmcneill		     strncmp(d->name, "da", 2) ||
303297627Sjmcneill		     !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n"
304297627Sjmcneill			       "Are you sure you want to do this on a SCSI disk?")) {
305297627Sjmcneill		if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
306297627Sjmcneill		    chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
307297627Sjmcneill		else
308297627Sjmcneill		    chunk_info[current_chunk]->flags |= CHUNK_BAD144;
309297627Sjmcneill	    }
310297627Sjmcneill	    clear();
311297627Sjmcneill	    break;
312297627Sjmcneill
313297627Sjmcneill	case 'C':
314297627Sjmcneill	    if (chunk_info[current_chunk]->type != unused)
315297627Sjmcneill		msg = "Slice in use, delete it first or move to an unused one.";
316297627Sjmcneill	    else {
317297627Sjmcneill		char *val, tmp[20], *cp;
318297627Sjmcneill		int size, subtype;
319297627Sjmcneill		chunk_e partitiontype;
320297627Sjmcneill
321297627Sjmcneill		snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size);
322297627Sjmcneill		val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n"
323297627Sjmcneill				  "or append a trailing `M' for megabytes (e.g. 20M).");
324297627Sjmcneill		if (val && (size = strtol(val, &cp, 0)) > 0) {
325297627Sjmcneill		    if (*cp && toupper(*cp) == 'M')
326297627Sjmcneill			size *= ONE_MEG;
327297627Sjmcneill		    strcpy(tmp, "165");
328297627Sjmcneill		    val = msgGetInput(tmp, "Enter type of partition to create:\n\n"
329297627Sjmcneill				      "Pressing Enter will choose the default, a native FreeBSD\n"
330297627Sjmcneill				      "slice (type 165).  You can choose other types, 6 for a\n"
331297627Sjmcneill				      "DOS partition or 131 for a Linux partition, for example.\n\n"
332297627Sjmcneill				      "Note:  If you choose a non-FreeBSD partition type, it will not\n"
333297627Sjmcneill				      "be formatted or otherwise prepared, it will simply reserve space\n"
334297627Sjmcneill				      "for you to use another tool, such as DOS FORMAT, to later format\n"
335297627Sjmcneill				      "and use the partition.");
336297627Sjmcneill		    if (val && (subtype = strtol(val, NULL, 0)) > 0) {
337297627Sjmcneill			if (subtype == 165)
338297627Sjmcneill			    partitiontype = freebsd;
339297627Sjmcneill			else if (subtype == 6)
340297627Sjmcneill			    partitiontype = fat;
341297627Sjmcneill			else
342297627Sjmcneill			    partitiontype = unknown;
343297627Sjmcneill#ifdef __alpha__
344297627Sjmcneill			if (partitiontype == freebsd && size == chunk_info[current_chunk]->size)
345297627Sjmcneill			    All_FreeBSD(d, 1);
346297627Sjmcneill			else
347297627Sjmcneill#endif
348297627Sjmcneill			Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype,
349297627Sjmcneill				     (chunk_info[current_chunk]->flags & CHUNK_ALIGN));
350297627Sjmcneill			variable_set2(DISK_PARTITIONED, "yes", 0);
351297627Sjmcneill			record_chunks(d);
352297627Sjmcneill		    }
353297627Sjmcneill		}
354297627Sjmcneill		clear();
355297627Sjmcneill	    }
356297627Sjmcneill	    break;
357297627Sjmcneill
358297627Sjmcneill	case KEY_DC:
359297627Sjmcneill	case 'D':
360297627Sjmcneill	    if (chunk_info[current_chunk]->type == unused)
361297627Sjmcneill		msg = "Slice is already unused!";
362297627Sjmcneill	    else {
363297627Sjmcneill		Delete_Chunk(d, chunk_info[current_chunk]);
364297627Sjmcneill		variable_set2(DISK_PARTITIONED, "yes", 0);
365297627Sjmcneill		record_chunks(d);
366297627Sjmcneill	    }
367297627Sjmcneill	    break;
368297627Sjmcneill
369297627Sjmcneill	case 'T':
370297627Sjmcneill	    if (chunk_info[current_chunk]->type == unused)
371297627Sjmcneill		msg = "Slice is currently unused (use create instead)";
372297627Sjmcneill	    else {
373297627Sjmcneill		char *val, tmp[20];
374297627Sjmcneill		int subtype;
375297627Sjmcneill		chunk_e partitiontype;
376297627Sjmcneill		WINDOW *save = savescr();
377297627Sjmcneill
378297627Sjmcneill		strcpy(tmp, "165");
379297627Sjmcneill		val = msgGetInput(tmp, "New partition type:\n\n"
380297627Sjmcneill				  "Pressing Enter will choose the default, a native FreeBSD\n"
381297627Sjmcneill				  "slice (type 165).  Other popular values are 6 for\n"
382297627Sjmcneill				  "DOS FAT partition, 131 for a Linux ext2fs partition or\n"
383297627Sjmcneill				  "130 for a Linux swap partition.\n\n"
384297627Sjmcneill				  "Note:  If you choose a non-FreeBSD partition type, it will not\n"
385297627Sjmcneill				  "be formatted or otherwise prepared, it will simply reserve space\n"
386297627Sjmcneill				  "for you to use another tool, such as DOS format, to later format\n"
387297627Sjmcneill				  "and actually use the partition.");
388297627Sjmcneill		if (val && (subtype = strtol(val, NULL, 0)) > 0) {
389297627Sjmcneill		    if (subtype == 165)
390297627Sjmcneill			partitiontype = freebsd;
391297627Sjmcneill		    else if (subtype == 6)
392297627Sjmcneill			partitiontype = fat;
393297627Sjmcneill		    else
394297627Sjmcneill			partitiontype = unknown;
395297627Sjmcneill		    chunk_info[current_chunk]->type = partitiontype;
396297627Sjmcneill		    chunk_info[current_chunk]->subtype = subtype;
397297627Sjmcneill		}
398297627Sjmcneill		restorescr(save);
399297627Sjmcneill	    }
400297627Sjmcneill	    break;
401297627Sjmcneill
402297627Sjmcneill	case 'G':
403297627Sjmcneill	    snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect);
404297627Sjmcneill	    val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n"
405297627Sjmcneill			      "Don't forget to use the two slash (/) separator characters!\n"
406297627Sjmcneill			      "It's not possible to parse the field without them.");
407297627Sjmcneill	    if (val) {
408297627Sjmcneill		long nc, nh, ns;
409297627Sjmcneill		nc = strtol(val, &val, 0);
410297627Sjmcneill		nh = strtol(val + 1, &val, 0);
411297627Sjmcneill		ns = strtol(val + 1, 0, 0);
412297627Sjmcneill		Set_Bios_Geom(d, nc, nh, ns);
413297627Sjmcneill	    }
414297627Sjmcneill	    clear();
415297627Sjmcneill	    break;
416297627Sjmcneill
417297627Sjmcneill	case 'S':
418297627Sjmcneill	    /* Set Bootable */
419297627Sjmcneill	    chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
420297627Sjmcneill	    break;
421297627Sjmcneill
422297627Sjmcneill	case 'U':
423297627Sjmcneill	    if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) {
424297627Sjmcneill		msgConfirm("You've already written this information out - you\n"
425297627Sjmcneill			   "can't undo it.");
426297627Sjmcneill	    }
427297627Sjmcneill	    else if (!msgYesNo("Are you SURE you want to Undo everything?")) {
428297627Sjmcneill		char cp[BUFSIZ];
429297627Sjmcneill
430297627Sjmcneill		sstrncpy(cp, d->name, sizeof cp);
431297627Sjmcneill		Free_Disk(dev->private);
432297627Sjmcneill		d = Open_Disk(cp);
433297627Sjmcneill		if (!d)
434297627Sjmcneill		    msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp);
435297627Sjmcneill		dev->private = d;
436297627Sjmcneill		variable_unset(DISK_PARTITIONED);
437297627Sjmcneill		variable_unset(DISK_LABELLED);
438297627Sjmcneill		if (d)
439297627Sjmcneill		    record_chunks(d);
440297627Sjmcneill	    }
441297627Sjmcneill	    clear();
442297627Sjmcneill	    break;
443297627Sjmcneill
444297627Sjmcneill	case 'W':
445297627Sjmcneill	    if (!msgYesNo("WARNING:  This should only be used when modifying an EXISTING\n"
446297627Sjmcneill			       "installation.  If you are installing FreeBSD for the first time\n"
447297627Sjmcneill			       "then you should simply type Q when you're finished here and your\n"
448297627Sjmcneill			       "changes will be committed in one batch automatically at the end of\n"
449297627Sjmcneill			       "these questions.  If you're adding a disk, you should NOT write\n"
450297627Sjmcneill			       "from this screen, you should do it from the label editor.\n\n"
451297627Sjmcneill			       "Are you absolutely sure you want to do this now?")) {
452297627Sjmcneill		variable_set2(DISK_PARTITIONED, "yes", 0);
453297627Sjmcneill
454297627Sjmcneill		/* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
455297627Sjmcneill		 * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
456297627Sjmcneill		 * booteasy or a "standard" MBR -- both would be fatal in this case.
457297627Sjmcneill		 */
458297627Sjmcneill#if 0
459297627Sjmcneill		if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
460297627Sjmcneill		    && (mbrContents = getBootMgr(d->name)) != NULL)
461297627Sjmcneill		    Set_Boot_Mgr(d, mbrContents);
462297627Sjmcneill#else
463297627Sjmcneill		/*
464297627Sjmcneill		 * Don't offer to update the MBR on this disk if the first "real" chunk looks like
465297627Sjmcneill		 * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD.
466297627Sjmcneill		 */
467297627Sjmcneill		if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) &&
468297627Sjmcneill		    (mbrContents = getBootMgr(d->name)) != NULL)
469297627Sjmcneill		    Set_Boot_Mgr(d, mbrContents);
470297627Sjmcneill#endif
471297627Sjmcneill
472297627Sjmcneill		if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS)
473297627Sjmcneill		    msgConfirm("Disk partition write returned an error status!");
474297627Sjmcneill		else
475305436Smanu		    msgConfirm("Wrote FDISK partition information out successfully.");
476305436Smanu	    }
477305436Smanu	    clear();
478305436Smanu	    break;
479305436Smanu
480305436Smanu	case '|':
481305436Smanu	    if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n"
482305436Smanu			  "No seat belts whatsoever are provided!")) {
483305436Smanu		clear();
484305436Smanu		refresh();
485305436Smanu		slice_wizard(d);
486305436Smanu		variable_set2(DISK_PARTITIONED, "yes", 0);
487305436Smanu		record_chunks(d);
488305436Smanu	    }
489305436Smanu	    else
490305436Smanu		msg = "Wise choice!";
491305436Smanu	    clear();
492305436Smanu	    break;
493305436Smanu
494305436Smanu	case '\033':	/* ESC */
495305436Smanu	case 'Q':
496305436Smanu	    chunking = FALSE;
497305436Smanu	    /* Don't trash the MBR if the first (and therefore only) chunk is marked for a truly dedicated
498305436Smanu	     * disk (i.e., the disklabel starts at sector 0), even in cases where the user has requested
499305436Smanu	     * booteasy or a "standard" MBR -- both would be fatal in this case.
500305436Smanu	     */
501305436Smanu#if 0
502305436Smanu	    if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL
503305436Smanu		&& (mbrContents = getBootMgr(d->name)) != NULL)
504305436Smanu		Set_Boot_Mgr(d, mbrContents);
505305436Smanu#else
506305436Smanu	    /*
507305436Smanu	     * Don't offer to update the MBR on this disk if the first "real" chunk looks like
508305436Smanu	     * a FreeBSD "all disk" partition, or the disk is entirely FreeBSD.
509305436Smanu	     */
510305436Smanu	    if (((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) &&
511305436Smanu		(mbrContents = getBootMgr(d->name)) != NULL)
512305436Smanu		Set_Boot_Mgr(d, mbrContents);
513305436Smanu#endif
514305436Smanu	    break;
515305436Smanu
516305436Smanu	default:
517305436Smanu	    beep();
518305436Smanu	    msg = "Type F1 or ? for help";
519305436Smanu	    break;
520305436Smanu	}
521305436Smanu    }
522305436Smanu    p = CheckRules(d);
523305436Smanu    if (p) {
524305436Smanu	char buf[FILENAME_MAX];
525305436Smanu
526305436Smanu	dialog_clear_norefresh();
527305436Smanu        use_helpline("Press F1 to read more about disk slices.");
528305436Smanu	use_helpfile(systemHelpFile("partition", buf));
529305436Smanu	if (!variable_get(VAR_NO_WARN))
530305436Smanu	    dialog_mesgbox("Disk slicing warning:", p, -1, -1);
531305436Smanu	free(p);
532305436Smanu    }
533305436Smanu    restorescr(w);
534305436Smanu}
535305436Smanu
536305436Smanustatic u_char *
537305436Smanubootalloc(char *name)
538305436Smanu{
539305436Smanu    char buf[FILENAME_MAX];
540305436Smanu    struct stat sb;
541305436Smanu
542305436Smanu    snprintf(buf, sizeof buf, "/boot/%s", name);
543305436Smanu    if (stat(buf, &sb) != -1) {
544305436Smanu	int fd;
545305436Smanu
546305436Smanu	fd = open(buf, O_RDONLY);
547305436Smanu	if (fd != -1) {
548305436Smanu	    u_char *cp;
549305436Smanu
550299688Smanu	    cp = malloc(sb.st_size);
551299688Smanu	    if (read(fd, cp, sb.st_size) != sb.st_size) {
552299688Smanu		free(cp);
553299688Smanu		close(fd);
554299688Smanu		msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf);
555299688Smanu		return NULL;
556299688Smanu	    }
557299688Smanu	    close(fd);
558299688Smanu	    return cp;
559299688Smanu	}
560299688Smanu	msgDebug("bootalloc: couldn't open %s\n", buf);
561299688Smanu    }
562299688Smanu    else
563299688Smanu	msgDebug("bootalloc: can't stat %s\n", buf);
564299688Smanu    return NULL;
565299688Smanu}
566299688Smanu
567299688Smanustatic int
568299688SmanupartitionHook(dialogMenuItem *selected)
569297627Sjmcneill{
570297627Sjmcneill    Device **devs = NULL;
571297627Sjmcneill
572297627Sjmcneill    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
573297627Sjmcneill    if (!devs) {
574297627Sjmcneill	msgConfirm("Unable to find disk %s!", selected->prompt);
575297627Sjmcneill	return DITEM_FAILURE;
576297627Sjmcneill    }
577297627Sjmcneill    /* Toggle enabled status? */
578297627Sjmcneill    if (!devs[0]->enabled) {
579297627Sjmcneill	devs[0]->enabled = TRUE;
580297627Sjmcneill	diskPartition(devs[0]);
581297627Sjmcneill    }
582297627Sjmcneill    else
583297627Sjmcneill	devs[0]->enabled = FALSE;
584297627Sjmcneill    return DITEM_SUCCESS | DITEM_RESTORE;
585297627Sjmcneill}
586297627Sjmcneill
587297627Sjmcneillstatic int
588297627SjmcneillpartitionCheck(dialogMenuItem *selected)
589297627Sjmcneill{
590297627Sjmcneill    Device **devs = NULL;
591297627Sjmcneill
592297627Sjmcneill    devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK);
593297627Sjmcneill    if (!devs || devs[0]->enabled == FALSE)
594297627Sjmcneill	return FALSE;
595297627Sjmcneill    return TRUE;
596297627Sjmcneill}
597297627Sjmcneill
598297627Sjmcneillint
599297627SjmcneilldiskPartitionEditor(dialogMenuItem *self)
600297627Sjmcneill{
601297627Sjmcneill    DMenu *menu;
602297627Sjmcneill    Device **devs;
603297627Sjmcneill    int i, cnt, devcnt;
604297627Sjmcneill
605297627Sjmcneill    cnt = diskGetSelectCount(&devs);
606297627Sjmcneill    devcnt = deviceCount(devs);
607297627Sjmcneill    if (cnt == -1) {
608297627Sjmcneill	msgConfirm("No disks found!  Please verify that your disk controller is being\n"
609297627Sjmcneill		   "properly probed at boot time.  See the Hardware Guide on the\n"
610297627Sjmcneill		   "Documentation menu for clues on diagnosing this type of problem.");
611297627Sjmcneill	return DITEM_FAILURE;
612297627Sjmcneill    }
613297627Sjmcneill    else if (cnt) {
614297627Sjmcneill	/* Some are already selected */
615297627Sjmcneill	for (i = 0; i < devcnt; i++) {
616297627Sjmcneill	    if (devs[i]->enabled) {
617297627Sjmcneill		if (variable_get(VAR_NONINTERACTIVE))
618297627Sjmcneill		    diskPartitionNonInteractive(devs[i]);
619297627Sjmcneill		else
620297627Sjmcneill		    diskPartition(devs[i]);
621297627Sjmcneill	    }
622297627Sjmcneill	}
623297627Sjmcneill    }
624297627Sjmcneill    else {
625297627Sjmcneill	/* No disks are selected, fall-back case now */
626297627Sjmcneill	if (devcnt == 1) {
627297627Sjmcneill	    devs[0]->enabled = TRUE;
628297627Sjmcneill	    if (variable_get(VAR_NONINTERACTIVE))
629297627Sjmcneill		diskPartitionNonInteractive(devs[0]);
630297627Sjmcneill	    else
631297627Sjmcneill		diskPartition(devs[0]);
632297627Sjmcneill	    return DITEM_SUCCESS;
633297627Sjmcneill	}
634297627Sjmcneill	else {
635297627Sjmcneill	    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck);
636297627Sjmcneill	    if (!menu) {
637297627Sjmcneill		msgConfirm("No devices suitable for installation found!\n\n"
638297627Sjmcneill			   "Please verify that your disk controller (and attached drives)\n"
639297627Sjmcneill			   "were detected properly.  This can be done by pressing the\n"
640297627Sjmcneill			   "[Scroll Lock] key and using the Arrow keys to move back to\n"
641297627Sjmcneill			   "the boot messages.  Press [Scroll Lock] again to return.");
642297627Sjmcneill		return DITEM_FAILURE;
643297627Sjmcneill	    }
644297627Sjmcneill	    else {
645297627Sjmcneill		i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE;
646297627Sjmcneill		free(menu);
647297627Sjmcneill	    }
648299113Sjmcneill	    return i | DITEM_RESTORE;
649299113Sjmcneill	}
650299113Sjmcneill    }
651299113Sjmcneill    return DITEM_SUCCESS;
652299113Sjmcneill}
653299113Sjmcneill
654299113Sjmcneillint
655299113SjmcneilldiskPartitionWrite(dialogMenuItem *self)
656299113Sjmcneill{
657299113Sjmcneill    Device **devs;
658299113Sjmcneill    int i;
659299113Sjmcneill    char *cp;
660299113Sjmcneill
661299113Sjmcneill    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
662299113Sjmcneill    if (!devs) {
663299113Sjmcneill	msgConfirm("Unable to find any disks to write to??");
664299113Sjmcneill	return DITEM_FAILURE;
665299113Sjmcneill    }
666297627Sjmcneill    if (isDebug())
667297627Sjmcneill	msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs));
668297627Sjmcneill    cp = variable_get(DISK_PARTITIONED);
669297627Sjmcneill    if (cp && !strcmp(cp, "written"))
670297627Sjmcneill	return DITEM_SUCCESS;
671297627Sjmcneill
672297627Sjmcneill    for (i = 0; devs[i]; i++) {
673297627Sjmcneill	Chunk *c1;
674297627Sjmcneill	Disk *d = (Disk *)devs[i]->private;
675297627Sjmcneill	static u_char *boot1;
676297627Sjmcneill#ifndef __alpha__
677297627Sjmcneill	static u_char *boot2;
678297627Sjmcneill#endif
679305436Smanu
680299688Smanu	if (!devs[i]->enabled)
681297627Sjmcneill	    continue;
682297627Sjmcneill
683299113Sjmcneill#ifdef __alpha__
684297627Sjmcneill	if (!boot1) boot1 = bootalloc("boot1");
685297627Sjmcneill	Set_Boot_Blocks(d, boot1, NULL);
686297627Sjmcneill#else
687297627Sjmcneill	if (!boot1) boot1 = bootalloc("boot1");
688297627Sjmcneill	if (!boot2) boot2 = bootalloc("boot2");
689297627Sjmcneill	Set_Boot_Blocks(d, boot1, boot2);
690297627Sjmcneill#endif
691297627Sjmcneill
692305436Smanu	msgNotify("Writing partition information to drive %s", d->name);
693297627Sjmcneill	if (!Fake && Write_Disk(d)) {
694297627Sjmcneill	    msgConfirm("ERROR: Unable to write data to disk %s!", d->name);
695299688Smanu	    return DITEM_FAILURE;
696299113Sjmcneill	}
697297627Sjmcneill
698297627Sjmcneill	/* If we've been through here before, we don't need to do the rest */
699297627Sjmcneill	if (cp && !strcmp(cp, "written"))
700297627Sjmcneill	    return DITEM_SUCCESS;
701297627Sjmcneill
702297627Sjmcneill	/* Now scan for bad blocks, if necessary */
703297627Sjmcneill	for (c1 = d->chunks->part; c1; c1 = c1->next) {
704297627Sjmcneill	    if (c1->flags & CHUNK_BAD144) {
705297627Sjmcneill		int ret;
706297627Sjmcneill
707297627Sjmcneill		msgNotify("Running bad block scan on slice %s", c1->name);
708297627Sjmcneill		if (!Fake) {
709297627Sjmcneill		    ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
710297627Sjmcneill		    if (ret)
711297627Sjmcneill			msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
712297627Sjmcneill		    ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
713297627Sjmcneill		    if (ret)
714297627Sjmcneill			msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
715297627Sjmcneill		}
716297627Sjmcneill	    }
717297627Sjmcneill	}
718297627Sjmcneill    }
719297627Sjmcneill    /* Now it's not "yes", but "written" */
720297627Sjmcneill    variable_set2(DISK_PARTITIONED, "written", 0);
721297627Sjmcneill    return DITEM_SUCCESS;
722297627Sjmcneill}
723297627Sjmcneill
724297627Sjmcneill/* Partition a disk based wholly on which variables are set */
725297627Sjmcneillstatic void
726297627SjmcneilldiskPartitionNonInteractive(Device *dev)
727297627Sjmcneill{
728297627Sjmcneill    char *cp;
729297627Sjmcneill    int i, sz, all_disk = 0;
730297627Sjmcneill    u_char *mbrContents;
731297627Sjmcneill    Disk *d = (Disk *)dev->private;
732297627Sjmcneill
733297627Sjmcneill    record_chunks(d);
734297627Sjmcneill    cp = variable_get(VAR_GEOMETRY);
735297627Sjmcneill    if (cp) {
736297627Sjmcneill	msgDebug("Setting geometry from script to: %s\n", cp);
737297627Sjmcneill	d->bios_cyl = strtol(cp, &cp, 0);
738297627Sjmcneill	d->bios_hd = strtol(cp + 1, &cp, 0);
739297627Sjmcneill	d->bios_sect = strtol(cp + 1, 0, 0);
740297627Sjmcneill    }
741297627Sjmcneill
742297627Sjmcneill    cp = variable_get(VAR_PARTITION);
743297627Sjmcneill    if (cp) {
744297627Sjmcneill	if (!strcmp(cp, "free")) {
745297627Sjmcneill	    /* Do free disk space case */
746297627Sjmcneill	    for (i = 0; chunk_info[i]; i++) {
747297627Sjmcneill		/* If a chunk is at least 10MB in size, use it. */
748297627Sjmcneill		if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) {
749297627Sjmcneill		    Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3,
750297627Sjmcneill				 (chunk_info[i]->flags & CHUNK_ALIGN));
751297627Sjmcneill		    variable_set2(DISK_PARTITIONED, "yes", 0);
752297627Sjmcneill		    break;
753297627Sjmcneill		}
754297627Sjmcneill	    }
755297627Sjmcneill	    if (!chunk_info[i]) {
756297627Sjmcneill		dialog_clear();
757297627Sjmcneill		msgConfirm("Unable to find any free space on this disk!");
758297627Sjmcneill		return;
759297627Sjmcneill	    }
760297627Sjmcneill	}
761297627Sjmcneill	else if (!strcmp(cp, "all")) {
762297627Sjmcneill	    /* Do all disk space case */
763297627Sjmcneill	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
764297627Sjmcneill
765297627Sjmcneill	    All_FreeBSD(d, FALSE);
766297627Sjmcneill	}
767297627Sjmcneill	else if (!strcmp(cp, "exclusive")) {
768297627Sjmcneill	    /* Do really-all-the-disk-space case */
769297627Sjmcneill	    msgDebug("Warning:  Devoting all of disk %s to FreeBSD.\n", d->name);
770297627Sjmcneill
771297627Sjmcneill	    All_FreeBSD(d, all_disk = TRUE);
772297627Sjmcneill	}
773297627Sjmcneill	else if ((sz = strtol(cp, &cp, 0))) {
774297627Sjmcneill	    /* Look for sz bytes free */
775297627Sjmcneill	    if (*cp && toupper(*cp) == 'M')
776297627Sjmcneill		sz *= ONE_MEG;
777297627Sjmcneill	    for (i = 0; chunk_info[i]; i++) {
778297627Sjmcneill		/* If a chunk is at least sz MB, use it. */
779297627Sjmcneill		if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) {
780297627Sjmcneill		    Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN));
781297627Sjmcneill		    variable_set2(DISK_PARTITIONED, "yes", 0);
782297627Sjmcneill		    break;
783297627Sjmcneill		}
784297627Sjmcneill	    }
785297627Sjmcneill	    if (!chunk_info[i]) {
786297627Sjmcneill		dialog_clear();
787297627Sjmcneill		msgConfirm("Unable to find %d free blocks on this disk!", sz);
788297627Sjmcneill		return;
789297627Sjmcneill	    }
790297627Sjmcneill	}
791297627Sjmcneill	else if (!strcmp(cp, "existing")) {
792297627Sjmcneill	    /* Do existing FreeBSD case */
793297627Sjmcneill	    for (i = 0; chunk_info[i]; i++) {
794297627Sjmcneill		if (chunk_info[i]->type == freebsd)
795297627Sjmcneill		    break;
796297627Sjmcneill	    }
797297627Sjmcneill	    if (!chunk_info[i]) {
798297627Sjmcneill		dialog_clear();
799297627Sjmcneill		msgConfirm("Unable to find any existing FreeBSD partitions on this disk!");
800297627Sjmcneill		return;
801297627Sjmcneill	    }
802297627Sjmcneill	}
803297627Sjmcneill	else {
804297627Sjmcneill	    dialog_clear();
805297627Sjmcneill	    msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION);
806297627Sjmcneill	    return;
807297627Sjmcneill	}
808297627Sjmcneill	if (!all_disk) {
809297627Sjmcneill	    mbrContents = getBootMgr(d->name);
810297627Sjmcneill	    Set_Boot_Mgr(d, mbrContents);
811297627Sjmcneill	}
812297627Sjmcneill	variable_set2(DISK_PARTITIONED, "yes", 0);
813299703Sgonzo    }
814297627Sjmcneill}
815297627Sjmcneill