disks.c revision 9202
1/*
2 * The new sysinstall program.
3 *
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
6 *
7 * $Id: disks.c,v 1.30.2.7 1995/06/08 09:48:31 jkh Exp $
8 *
9 * Copyright (c) 1995
10 *	Jordan Hubbard.  All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer,
17 *    verbatim and that no modifications are made prior to this
18 *    point in the file.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 *    must display the following acknowledgement:
24 *	This product includes software developed by Jordan Hubbard
25 *	for the FreeBSD Project.
26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to
27 *    endorse or promote products derived from this software without specific
28 *    prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 */
43
44#include "sysinstall.h"
45#include <ctype.h>
46#include <sys/disklabel.h>
47
48/* Where we start displaying chunk information on the screen */
49#define CHUNK_START_ROW		5
50
51/* Where we keep track of MBR chunks */
52static struct chunk *chunk_info[10];
53static int current_chunk;
54
55static void
56record_chunks(Disk *d)
57{
58    struct chunk *c1;
59    int i = 0;
60    int last_free = 0;
61    if (!d->chunks)
62	msgFatal("No chunk list found for %s!", d->name);
63    c1 = d->chunks->part;
64    current_chunk = 0;
65    while (c1) {
66	if (c1->type == unused && c1->size > last_free) {
67	    last_free = c1->size;
68	    current_chunk = i;
69	}
70	chunk_info[i++] = c1;
71	c1 = c1->next;
72    }
73    chunk_info[i] = NULL;
74}
75
76static void
77print_chunks(Disk *d)
78{
79    int row;
80    int i;
81
82    if ((!d->bios_cyl || d->bios_cyl > 65536) || (!d->bios_hd || d->bios_hd > 256) || (!d->bios_sect || d->bios_sect >= 64))
83	msgConfirm("WARNING:  The detected geometry is incorrect!  Please adjust it to\nthe correct values manually with the (G)eometry command.  If you are\nunsure about the correct geometry (which may be \"translated\"), please\nconsult the Hardware Guide in the Documentation submenu.");
84
85    attrset(A_NORMAL);
86    mvaddstr(0, 0, "Disk name:\t");
87    clrtobot();
88    attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL);
89    attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL);
90    mvprintw(1, 0,
91	     "BIOS Geometry:\t%lu cyls/%lu heads/%lu sectors",
92	     d->bios_cyl, d->bios_hd, d->bios_sect);
93    mvprintw(3, 1, "%10s %10s %10s %8s %8s %8s %8s %8s",
94	     "Offset", "Size", "End", "Name", "PType", "Desc",
95	     "Subtype", "Flags");
96    for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
97	if (i == current_chunk)
98	    attrset(A_REVERSE);
99	mvprintw(row, 2, "%10ld %10lu %10lu %8s %8d %8s %8d\t%-6s",
100		 chunk_info[i]->offset, chunk_info[i]->size,
101		 chunk_info[i]->end, chunk_info[i]->name,
102		 chunk_info[i]->type, chunk_n[chunk_info[i]->type],
103		 chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i]));
104	if (i == current_chunk)
105	    attrset(A_NORMAL);
106    }
107}
108
109static void
110print_command_summary()
111{
112    mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
113    mvprintw(16, 0, "A = Use Entire Disk    B = Bad Block Scan     C = Create Partition");
114    mvprintw(17, 0, "D = Delete Partition   G = Set BIOS Geometry  S = Set Bootable");
115    mvprintw(18, 0, "U = Undo All Changes   Q = Finish");
116    mvprintw(20, 0, "The currently selected partition is displayed in ");
117    attrset(A_REVERSE); addstr("reverse"); attrset(A_NORMAL); addstr(" video.");
118    mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to move.");
119    move(0, 0);
120}
121
122static Disk *
123diskPartition(Disk *d)
124{
125    char *p;
126    int key = 0;
127    Boolean chunking;
128    char *msg = NULL;
129    char name[40];
130
131    chunking = TRUE;
132    strncpy(name, d->name, 40);
133    keypad(stdscr, TRUE);
134
135    clear();
136    record_chunks(d);
137    while (chunking) {
138	print_chunks(d);
139	print_command_summary();
140	if (msg) {
141	    standout(); mvprintw(23, 0, msg); standend();
142	    beep();
143	    msg = NULL;
144	}
145
146	key = toupper(getch());
147	switch (key) {
148
149	case '\014':	/* ^L */
150	    clear();
151	    continue;
152
153	case KEY_UP:
154	case '-':
155	    if (current_chunk != 0)
156		--current_chunk;
157	    break;
158
159	case KEY_DOWN:
160	case '+':
161	case '\r':
162	case '\n':
163	    if (chunk_info[current_chunk + 1])
164		++current_chunk;
165	    break;
166
167	case KEY_HOME:
168	    current_chunk = 0;
169	    break;
170
171	case KEY_END:
172	    while (chunk_info[current_chunk + 1])
173		++current_chunk;
174	    break;
175
176	case KEY_F(1):
177	case '?':
178	    systemDisplayFile("slice.hlp");
179	    break;
180
181	case 'A':
182	    All_FreeBSD(d);
183	    record_chunks(d);
184	    break;
185
186	case 'B':
187	    if (chunk_info[current_chunk]->type != freebsd)
188		msg = "Can only scan for bad blocks in FreeBSD partition.";
189	    else if (strncmp(name, "sd", 2) ||
190		     !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\nAre you sure you want to do this on a SCSI disk?"))
191		if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
192		    chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
193		else
194		    chunk_info[current_chunk]->flags |= CHUNK_BAD144;
195	    break;
196
197	case 'C':
198	    if (chunk_info[current_chunk]->type != unused)
199		msg = "Partition in use, delete it first or move to an unused one.";
200	    else {
201		char *val, tmp[20], *cp;
202		int size;
203
204		snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size);
205		val = msgGetInput(tmp, "Please specify the size for new FreeBSD partition in blocks, or append\na trailing `M' for megabytes (e.g. 20M).");
206		if (val && (size = strtol(val, &cp, 0)) > 0) {
207		    if (*cp && toupper(*cp) == 'M')
208			size *= 2048;
209		    Create_Chunk(d, chunk_info[current_chunk]->offset,
210				 size,
211				 freebsd,
212				 3,
213				 (chunk_info[current_chunk]->flags &
214				  CHUNK_ALIGN));
215		    record_chunks(d);
216		}
217	    }
218	    break;
219
220	case 'D':
221	    if (chunk_info[current_chunk]->type == unused)
222		msg = "Partition is already unused!";
223	    else {
224		Delete_Chunk(d, chunk_info[current_chunk]);
225		record_chunks(d);
226	    }
227	    break;
228
229	case 'G': {
230	    char *val, geometry[80];
231
232	    snprintf(geometry, 80, "%lu/%lu/%lu",
233		     d->bios_cyl, d->bios_hd, d->bios_sect);
234	    val = msgGetInput(geometry,
235"Please specify the new geometry in cyl/hd/sect format.\nDon't forget to use the two slash (/) separator characters!\nIt's not possible to parse the field without them.");
236	    if (val) {
237		d->bios_cyl = strtol(val, &val, 0);
238		d->bios_hd = strtol(val + 1, &val, 0);
239		d->bios_sect = strtol(val + 1, 0, 0);
240	    }
241	}
242	    break;
243
244	case 'S':
245	    /* Set Bootable */
246	    chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
247	    break;
248
249	case 'U':
250	    Free_Disk(d);
251	    d = Open_Disk(name);
252	    if (!d)
253		msgFatal("Can't reopen disk %s!", name);
254	    record_chunks(d);
255	    break;
256
257	case 'W':
258	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\nNo seat belts whatsoever are provided!")) {
259		dialog_clear();
260		end_dialog();
261		DialogActive = FALSE;
262		slice_wizard(d);
263		dialog_clear();
264		DialogActive = TRUE;
265		record_chunks(d);
266	    }
267	    else
268		msg = "Wise choice!";
269	    break;
270
271	case 'Q':
272	    chunking = FALSE;
273	    break;
274
275	default:
276	    beep();
277	    msg = "Type F1 or ? for help";
278	    break;
279	}
280    }
281    p = CheckRules(d);
282    if (p) {
283	msgConfirm(p);
284	free(p);
285    }
286    dialog_clear();
287    variable_set2(DISK_PARTITIONED, "yes");
288    return d;
289}
290
291static int
292partitionHook(char *str)
293{
294    Device **devs = NULL;
295
296    /* Clip garbage off the ends */
297    string_prune(str);
298    str = string_skipwhite(str);
299    /* Try and open all the disks */
300    while (str) {
301	char *cp;
302
303	cp = index(str, '\n');
304	if (cp)
305	   *cp++ = 0;
306	if (!*str) {
307	    beep();
308	    return 0;
309	}
310	devs = deviceFind(str, DEVICE_TYPE_DISK);
311	if (!devs) {
312	    msgConfirm("Unable to find disk %s!", str);
313	    return 0;
314	}
315	else if (devs[1])
316	    msgConfirm("Bizarre multiple match for %s!", str);
317	devs[0]->private = diskPartition((Disk *)devs[0]->private);
318	devs[0]->enabled = TRUE;
319	str = cp;
320    }
321    return devs ? 1 : 0;
322}
323
324int
325diskPartitionEditor(char *str)
326{
327    DMenu *menu;
328    Device **devs;
329    int cnt;
330
331    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
332    cnt = deviceCount(devs);
333    if (!cnt) {
334	msgConfirm("No disks found!  Please verify that your disk controller is being\nproperly probed at boot time.  See the Hardware Guide on the Documentation menu\nfor clues on diagnosing this type of problem.");
335	return 0;
336    }
337    else if (cnt == 1) {
338	devs[0]->private = diskPartition((Disk *)devs[0]->private);
339	devs[0]->enabled = TRUE;
340    }
341    else {
342	menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook);
343	if (!menu)
344	    msgConfirm("No devices suitable for installation found!\n\nPlease verify that your disk controller (and attached drives) were detected properly.  This can be done by selecting the ``Bootmsg'' option on the main menu and reviewing the boot messages carefully.");
345	else {
346	    dmenuOpenSimple(menu);
347	    free(menu);
348	}
349    }
350    return 0;
351}
352