disks.c revision 8820
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.28 1995/05/25 18:48:23 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    attrset(A_NORMAL);
83    mvaddstr(0, 0, "Disk name:\t");
84    clrtobot();
85    attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL);
86    attrset(A_REVERSE); mvaddstr(0, 55, "Master Partition Editor"); attrset(A_NORMAL);
87    mvprintw(1, 0,
88	     "BIOS Geometry:\t%lu cyls/%lu heads/%lu sectors",
89	     d->bios_cyl, d->bios_hd, d->bios_sect);
90    mvprintw(3, 1, "%10s %10s %10s %8s %8s %8s %8s %8s",
91	     "Offset", "Size", "End", "Name", "PType", "Desc",
92	     "Subtype", "Flags");
93    for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
94	if (i == current_chunk)
95	    attrset(A_REVERSE);
96	mvprintw(row, 2, "%10ld %10lu %10lu %8s %8d %8s %8d %6lx",
97		 chunk_info[i]->offset, chunk_info[i]->size,
98		 chunk_info[i]->end, chunk_info[i]->name,
99		 chunk_info[i]->type, chunk_n[chunk_info[i]->type],
100		 chunk_info[i]->subtype, chunk_info[i]->flags);
101	if (i == current_chunk)
102	    attrset(A_NORMAL);
103    }
104}
105
106static void
107print_command_summary()
108{
109    mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
110    mvprintw(16, 0, "A = Use Entire Disk    B = Bad Block Scan     C = Create Partition");
111    mvprintw(17, 0, "D = Delete Partition   G = Set BIOS Geometry  S = Set Bootable");
112    mvprintw(18, 0, "U = Undo All Changes   ESC = Exit this screen");
113    mvprintw(20, 0, "The currently selected partition is displayed in ");
114    attrset(A_REVERSE); addstr("reverse"); attrset(A_NORMAL); addstr(" video.");
115    mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to move.");
116    move(0, 0);
117}
118
119static Disk *
120diskPartition(Disk *d)
121{
122    char *p;
123    int key = 0;
124    Boolean chunking;
125    char *msg = NULL;
126    char name[40];
127
128    chunking = TRUE;
129    strncpy(name, d->name, 40);
130    keypad(stdscr, TRUE);
131
132    clear();
133    record_chunks(d);
134    while (chunking) {
135	print_chunks(d);
136	print_command_summary();
137	if (msg) {
138	    standout(); mvprintw(23, 0, msg); standend();
139	    beep();
140	    msg = NULL;
141	}
142
143	key = toupper(getch());
144	switch (key) {
145
146	case '\014':	/* ^L */
147	    clear();
148	    continue;
149
150	case KEY_UP:
151	case '-':
152	    if (current_chunk != 0)
153		--current_chunk;
154	    break;
155
156	case KEY_DOWN:
157	case '+':
158	case '\r':
159	case '\n':
160	    if (chunk_info[current_chunk + 1])
161		++current_chunk;
162	    break;
163
164	case KEY_HOME:
165	    current_chunk = 0;
166	    break;
167
168	case KEY_END:
169	    while (chunk_info[current_chunk + 1])
170		++current_chunk;
171	    break;
172
173	case KEY_F(1):
174	case '?':
175	    systemDisplayFile("slice.hlp");
176	    break;
177
178	case 'A':
179	    All_FreeBSD(d);
180	    record_chunks(d);
181	    break;
182
183	case 'B':
184	    if (chunk_info[current_chunk]->type != freebsd)
185		msg = "Can only scan for bad blocks in FreeBSD partition.";
186	    else if (strncmp(name, "sd", 2) ||
187		     !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\nAre you sure you want to do this on a SCSI disk?"))
188		if (chunk_info[current_chunk]->flags & CHUNK_BAD144)
189		    chunk_info[current_chunk]->flags &= ~CHUNK_BAD144;
190		else
191		    chunk_info[current_chunk]->flags |= CHUNK_BAD144;
192	    break;
193
194	case 'C':
195	    if (chunk_info[current_chunk]->type != unused)
196		msg = "Partition in use, delete it first or move to an unused one.";
197	    else {
198		char *val, tmp[20], *cp;
199		int size;
200
201		snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size);
202		val = msgGetInput(tmp, "Please specify the size for new FreeBSD partition in blocks, or append\na trailing `M' for megabytes (e.g. 20M).");
203		if (val && (size = strtol(val, &cp, 0)) > 0) {
204		    if (*cp && toupper(*cp) == 'M')
205			size *= 2048;
206		    Create_Chunk(d, chunk_info[current_chunk]->offset,
207				 size,
208				 freebsd,
209				 3,
210				 (chunk_info[current_chunk]->flags &
211				  CHUNK_ALIGN));
212		    record_chunks(d);
213		}
214	    }
215	    break;
216
217	case 'D':
218	    if (chunk_info[current_chunk]->type == unused)
219		msg = "Partition is already unused!";
220	    else {
221		Delete_Chunk(d, chunk_info[current_chunk]);
222		record_chunks(d);
223	    }
224	    break;
225
226	case 'G': {
227	    char *val, geometry[80];
228
229	    snprintf(geometry, 80, "%lu/%lu/%lu",
230		     d->bios_cyl, d->bios_hd, d->bios_sect);
231	    val = msgGetInput(geometry,
232"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.");
233	    if (val) {
234		d->bios_cyl = strtol(val, &val, 0);
235		d->bios_hd = strtol(val + 1, &val, 0);
236		d->bios_sect = strtol(val + 1, 0, 0);
237	    }
238	}
239	    break;
240
241	case 'S':
242	    /* Set Bootable */
243	    chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
244	    break;
245
246	case 'U':
247	    Free_Disk(d);
248	    d = Open_Disk(name);
249	    if (!d)
250		msgFatal("Can't reopen disk %s!", name);
251	    record_chunks(d);
252	    break;
253
254	case 'W':
255	    if (!msgYesNo("Are you sure you want to go into Wizard mode?\nNo seat belts whatsoever are provided!")) {
256		dialog_clear();
257		end_dialog();
258		DialogActive = FALSE;
259		slice_wizard(d);
260		dialog_clear();
261		DialogActive = TRUE;
262		record_chunks(d);
263	    }
264	    else
265		msg = "Wise choice!";
266	    break;
267
268	case 27:	/* ESC */
269	    chunking = FALSE;
270	    break;
271
272	default:
273	    beep();
274	    msg = "Type F1 or ? for help";
275	    break;
276	}
277    }
278    p = CheckRules(d);
279    if (p) {
280	msgConfirm(p);
281	free(p);
282    }
283    dialog_clear();
284    variable_set2(DISK_PARTITIONED, "yes");
285    return d;
286}
287
288static int
289partitionHook(char *str)
290{
291    Device **devs = NULL;
292
293    /* Clip garbage off the ends */
294    string_prune(str);
295    str = string_skipwhite(str);
296    /* Try and open all the disks */
297    while (str) {
298	char *cp;
299
300	cp = index(str, '\n');
301	if (cp)
302	   *cp++ = 0;
303	if (!*str) {
304	    beep();
305	    return 0;
306	}
307	devs = deviceFind(str, DEVICE_TYPE_DISK);
308	if (!devs) {
309	    msgConfirm("Unable to find disk %s!", str);
310	    return 0;
311	}
312	else if (devs[1])
313	    msgConfirm("Bizarre multiple match for %s!", str);
314	devs[0]->private = diskPartition((Disk *)devs[0]->private);
315	devs[0]->enabled = TRUE;
316	str = cp;
317    }
318    return devs ? 1 : 0;
319}
320
321int
322diskPartitionEditor(char *str)
323{
324    DMenu *menu;
325
326    menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook);
327    if (!menu) {
328	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.");
329    }
330    else {
331	dmenuOpenSimple(menu);
332	free(menu);
333    }
334    return 0;
335}
336