mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-23 11:18:54 +00:00
372 lines
10 KiB
C
372 lines
10 KiB
C
/*
|
|
* The new sysinstall program.
|
|
*
|
|
* This is probably the last program in the `sysinstall' line - the next
|
|
* generation being essentially a complete rewrite.
|
|
*
|
|
* $Id: devices.c,v 1.13 1995/05/11 06:10:45 jkh Exp $
|
|
*
|
|
* Copyright (c) 1995
|
|
* Jordan Hubbard. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer,
|
|
* verbatim and that no modifications are made prior to this
|
|
* point in the file.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Jordan Hubbard
|
|
* for the FreeBSD Project.
|
|
* 4. The name of Jordan Hubbard or the FreeBSD project may not be used to
|
|
* endorse or promote products derived from this software without specific
|
|
* prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#include "sysinstall.h"
|
|
#include <sys/fcntl.h>
|
|
#include <ctype.h>
|
|
|
|
/* Where we start displaying chunk information on the screen */
|
|
#define CHUNK_START_ROW 5
|
|
|
|
static char *cdrom_table[] = {
|
|
"cd0a", "cd1a", /* SCSI */
|
|
"mcd0a", "mcd1a", /* Mitsumi (old model) */
|
|
"scd0a", "scd1a", /* Sony CDROM */
|
|
"matcd0a", "matcd1a", /* Matsushita (SB) */
|
|
NULL,
|
|
};
|
|
|
|
/* Get all device information for a given device class */
|
|
static Device *
|
|
device_get_all(DeviceType which, int *ndevs)
|
|
{
|
|
char **names;
|
|
Device *devs = NULL;
|
|
|
|
*ndevs = 0;
|
|
if (which == DEVICE_TYPE_DISK || which == DEVICE_TYPE_ANY) {
|
|
if ((names = Disk_Names()) != NULL) {
|
|
int i;
|
|
|
|
for (i = 0; names[i]; i++)
|
|
++*ndevs;
|
|
devs = safe_malloc(sizeof(Device) * (*ndevs + 1));
|
|
for (i = 0; names[i]; i++) {
|
|
strcpy(devs[i].name, names[i]);
|
|
devs[i].type = DEVICE_TYPE_DISK;
|
|
}
|
|
free(names);
|
|
}
|
|
}
|
|
if (which == DEVICE_TYPE_CDROM || which == DEVICE_TYPE_ANY) {
|
|
char try[FILENAME_MAX];
|
|
int i, fd;
|
|
|
|
for (i = 0; cdrom_table[i]; i++) {
|
|
snprintf(try, FILENAME_MAX, "/mnt/dev/%s", cdrom_table[i]);
|
|
fd = open(try, O_RDWR);
|
|
if (fd > 0) {
|
|
close(fd);
|
|
devs = safe_realloc(devs, sizeof(Device) * (*ndevs + 2));
|
|
strcpy(devs[*ndevs].name, cdrom_table[i]);
|
|
devs[(*ndevs)++].type = DEVICE_TYPE_CDROM;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* Terminate the devices array */
|
|
devs[*ndevs].name[0] = '\0';
|
|
return devs;
|
|
}
|
|
|
|
static struct chunk *chunk_info[10];
|
|
static int current_chunk;
|
|
|
|
static void
|
|
record_chunks(struct disk *d)
|
|
{
|
|
struct chunk *c1;
|
|
int i = 0;
|
|
int last_free = 0;
|
|
if (!d->chunks)
|
|
msgFatal("No chunk list found for %s!", d->name);
|
|
c1 = d->chunks->part;
|
|
current_chunk = 0;
|
|
while (c1) {
|
|
if (c1->type == unused && c1->size > last_free) {
|
|
last_free = c1->size;
|
|
current_chunk = i;
|
|
}
|
|
chunk_info[i++] = c1;
|
|
c1 = c1->next;
|
|
}
|
|
chunk_info[i] = NULL;
|
|
}
|
|
|
|
static void
|
|
print_chunks(struct disk *d)
|
|
{
|
|
int row;
|
|
int i;
|
|
|
|
attrset(A_NORMAL);
|
|
mvaddstr(0, 0, "Disk name:\t");
|
|
attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL);
|
|
attrset(A_REVERSE); mvaddstr(0, 55, "Master Partition Editor"); attrset(A_NORMAL);
|
|
mvprintw(1, 0,
|
|
"BIOS Geometry:\t%lu cyls/%lu heads/%lu sectors",
|
|
d->bios_cyl, d->bios_hd, d->bios_sect);
|
|
mvprintw(3, 1, "%10s %10s %10s %8s %8s %8s %8s %8s",
|
|
"Offset", "Size", "End", "Name", "PType", "Desc",
|
|
"Subtype", "Flags");
|
|
for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
|
|
if (i == current_chunk)
|
|
attrset(A_REVERSE);
|
|
mvprintw(row, 2, "%10lu %10lu %10lu %8s %8d %8s %8d %6lx",
|
|
chunk_info[i]->offset, chunk_info[i]->size,
|
|
chunk_info[i]->end, chunk_info[i]->name,
|
|
chunk_info[i]->type, chunk_n[chunk_info[i]->type],
|
|
chunk_info[i]->subtype, chunk_info[i]->flags);
|
|
if (i == current_chunk)
|
|
attrset(A_NORMAL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_command_summary()
|
|
{
|
|
mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
|
|
mvprintw(16, 0, "A = Use Entire Disk B = Bad Block Scan C = Create Partition");
|
|
mvprintw(17, 0, "D = Delete Partition G = Set BIOS Geometry S = Set Bootable");
|
|
mvprintw(18, 0, "U = Undo All Changes W = `Wizard' Mode ESC = Proceed to next screen");
|
|
mvprintw(20, 0, "The currently selected partition is displayed in ");
|
|
attrset(A_REVERSE); addstr("reverse video."); attrset(A_NORMAL);
|
|
mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to move.");
|
|
move(0, 0);
|
|
}
|
|
|
|
struct disk *
|
|
device_slice_disk(struct disk *d)
|
|
{
|
|
char *p;
|
|
int key = 0;
|
|
Boolean chunking;
|
|
char *msg = NULL;
|
|
char name[40];
|
|
|
|
dialog_clear();
|
|
chunking = TRUE;
|
|
strncpy(name, d->name, 40);
|
|
keypad(stdscr, TRUE);
|
|
|
|
record_chunks(d);
|
|
while (chunking) {
|
|
clear();
|
|
print_chunks(d);
|
|
print_command_summary();
|
|
if (msg) {
|
|
standout(); mvprintw(23, 0, msg); standend();
|
|
beep();
|
|
msg = NULL;
|
|
}
|
|
refresh();
|
|
|
|
key = toupper(getch());
|
|
switch (key) {
|
|
case KEY_UP:
|
|
case '-':
|
|
if (current_chunk != 0)
|
|
--current_chunk;
|
|
break;
|
|
|
|
case KEY_DOWN:
|
|
case '+':
|
|
case '\r':
|
|
case '\n':
|
|
if (chunk_info[current_chunk + 1])
|
|
++current_chunk;
|
|
break;
|
|
|
|
case KEY_HOME:
|
|
current_chunk = 0;
|
|
break;
|
|
|
|
case KEY_END:
|
|
while (chunk_info[current_chunk + 1])
|
|
++current_chunk;
|
|
break;
|
|
|
|
case KEY_F(1):
|
|
case '?':
|
|
systemDisplayFile("slice.hlp");
|
|
break;
|
|
|
|
case 'A':
|
|
All_FreeBSD(d);
|
|
record_chunks(d);
|
|
break;
|
|
|
|
case 'B':
|
|
if (chunk_info[current_chunk]->type != freebsd)
|
|
msg = "Can only scan for bad blocks in FreeBSD partition.";
|
|
else if (strncmp(name, "sd", 2) ||
|
|
!msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\nAre you sure you want to do this on a SCSI disk?"))
|
|
chunk_info[current_chunk]->flags |= CHUNK_BAD144;
|
|
break;
|
|
|
|
case 'C':
|
|
if (chunk_info[current_chunk]->type != unused)
|
|
msg = "Partition in use, delete it first or move to an unused one.";
|
|
else {
|
|
char *val, tmp[20];
|
|
int size;
|
|
|
|
snprintf(tmp, 20, "%d", chunk_info[current_chunk]->size);
|
|
val = msgGetInput(tmp, "Please specify size for new FreeBSD partition");
|
|
if (val && (size = strtol(val, 0, 0)) > 0) {
|
|
Create_Chunk(d, chunk_info[current_chunk]->offset,
|
|
size,
|
|
freebsd,
|
|
3,
|
|
(chunk_info[current_chunk]->flags &
|
|
CHUNK_ALIGN));
|
|
record_chunks(d);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
if (chunk_info[current_chunk]->type == unused)
|
|
msg = "Partition is already unused!";
|
|
else {
|
|
Delete_Chunk(d, chunk_info[current_chunk]);
|
|
record_chunks(d);
|
|
}
|
|
break;
|
|
|
|
case 'G': {
|
|
char *val, geometry[80];
|
|
|
|
snprintf(geometry, 80, "%lu/%lu/%lu",
|
|
d->bios_cyl, d->bios_hd, d->bios_sect);
|
|
val = msgGetInput(geometry,
|
|
"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.");
|
|
if (val) {
|
|
d->bios_cyl = strtol(val, &val, 0);
|
|
d->bios_hd = strtol(val + 1, &val, 0);
|
|
d->bios_sect = strtol(val + 1, 0, 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
/* Set Bootable */
|
|
chunk_info[current_chunk]->flags |= CHUNK_ACTIVE;
|
|
break;
|
|
|
|
case 'U':
|
|
Free_Disk(d);
|
|
d = Open_Disk(name);
|
|
if (!d)
|
|
msgFatal("Can't reopen disk %s!", name);
|
|
record_chunks(d);
|
|
break;
|
|
|
|
case 'W':
|
|
if (!msgYesNo("Are you sure you want to go into Wizard mode?\nNo seat belts whatsoever are provided!")) {
|
|
clear();
|
|
dialog_clear();
|
|
end_dialog();
|
|
DialogActive = FALSE;
|
|
slice_wizard(d);
|
|
clear();
|
|
dialog_clear();
|
|
DialogActive = TRUE;
|
|
record_chunks(d);
|
|
}
|
|
else
|
|
msg = "Wise choice!";
|
|
break;
|
|
|
|
case 27: /* ESC */
|
|
chunking = FALSE;
|
|
break;
|
|
|
|
default:
|
|
beep();
|
|
msg = "Type F1 or ? for help";
|
|
break;
|
|
}
|
|
}
|
|
p = CheckRules(d);
|
|
if (p) {
|
|
msgConfirm(p);
|
|
free(p);
|
|
}
|
|
clear();
|
|
refresh();
|
|
return d;
|
|
}
|
|
|
|
/*
|
|
* Create a menu listing all the devices in the system. The pass-in menu
|
|
* is expected to be a "prototype" from which the new menu is cloned.
|
|
*/
|
|
DMenu *
|
|
device_create_disk_menu(DMenu *menu, Device **rdevs, int (*hook)())
|
|
{
|
|
Device *devices;
|
|
int numdevs;
|
|
|
|
devices = device_get_all(DEVICE_TYPE_DISK, &numdevs);
|
|
*rdevs = devices;
|
|
if (!devices) {
|
|
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.");
|
|
return NULL;
|
|
}
|
|
else {
|
|
Device *start;
|
|
DMenu *tmp;
|
|
int i;
|
|
|
|
tmp = (DMenu *)safe_malloc(sizeof(DMenu) +
|
|
(sizeof(DMenuItem) * (numdevs + 1)));
|
|
bcopy(menu, tmp, sizeof(DMenu));
|
|
for (start = devices, i = 0; start->name[0]; start++, i++) {
|
|
tmp->items[i].title = start->name;
|
|
if (!strncmp(start->name, "sd", 2))
|
|
tmp->items[i].prompt = "SCSI disk";
|
|
else if (!strncmp(start->name, "wd", 2))
|
|
tmp->items[i].prompt = "IDE/ESDI/MFM/ST506 disk";
|
|
else
|
|
msgFatal("Unknown disk type: %s!", start->name);
|
|
tmp->items[i].type = DMENU_CALL;
|
|
tmp->items[i].ptr = hook;
|
|
tmp->items[i].disabled = FALSE;
|
|
}
|
|
tmp->items[i].type = DMENU_NOP;
|
|
tmp->items[i].title = NULL;
|
|
return tmp;
|
|
}
|
|
}
|