home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 February
/
CHIP_2_98.iso
/
misc
/
src
/
install
/
.#hd.c.1.29
< prev
next >
Wrap
Text File
|
1997-11-05
|
13KB
|
515 lines
#include <ctype.h>
#include <fcntl.h>
#include <linux/hdreg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/wait.h>
#include <unistd.h>
#include "hd.h"
#include "install.h"
#include "log.h"
#include "newt.h"
#include "run.h"
#include "scsi.h"
#include "windows.h"
extern int testing;
/* shame we can't get this from any header files */
#define BLKRRPART _IO(0x12,95) /* re-read partition table */
struct fdiskTag {
int tag;
int type;
} ;
#if defined(__sparc__)
const struct fdiskTag fdiskTags[] = {
{ 0x05, PART_IGNORE },
{ 0x82, PART_SWAP },
{ 0x83, PART_EXT2 },
{ 0, 0 },
};
#else
const struct fdiskTag fdiskTags[] = {
{ 0x01, PART_DOS },
{ 0x04, PART_DOS },
{ 0x05, PART_IGNORE },
{ 0x06, PART_DOS },
{ 0x07, PART_HPFS },
{ 0x0b, PART_FAT32 },
{ 0x82, PART_SWAP },
{ 0x83, PART_EXT2 },
{ 0, 0 },
};
#endif
#define MAX_NUM_DRIVES 40
static int findDrivesPresent(struct deviceInfo * drives, int * numPtr);
static void parseLabelLine(char * device, char * start, int * numPartitions,
struct partition partitions[15]) {
char * str = start;
char * chptr;
char devbuf[2];
if (*str++ != ' ') return;
if (*str++ != ' ') return;
if (*str < 'a' || *str > 'h') return;
if (*(str + 1) != ':') return;
strcpy(partitions[*numPartitions].device, device);
devbuf[0] = *str - 'a' + '1';
devbuf[1] = '\0';
strcat(partitions[*numPartitions].device, devbuf);
str += 2;
while (*str && isspace(*str)) str++;
if (!*str) return;
partitions[*numPartitions].size = strtol(str, &chptr, 10);
partitions[*numPartitions].size /= 2; /* we want 1k blocks */
if (!chptr || !isspace(*chptr)) return;
str = chptr;
while (isspace(*str)) str++;
if (!*str) return;
partitions[*numPartitions].begin = strtol(str, &chptr, 10);
if (!chptr || !isspace(*chptr)) return;
str = chptr;
partitions[*numPartitions].end = partitions[*numPartitions].size * 2 +
partitions[*numPartitions].begin;
while (isspace(*str)) str++;
if (!*str) return;
if (!strncmp(str, "ext2", 4)) {
partitions[*numPartitions].type = PART_EXT2;
strcpy(partitions[*numPartitions].tagName, "Linux native");
} else if (!strncmp(str, "swap", 4)) {
partitions[*numPartitions].type = PART_SWAP;
strcpy(partitions[*numPartitions].tagName, "Linux swap");
} else {
partitions[*numPartitions].type = PART_OTHER;
strcpy(partitions[*numPartitions].tagName, "Other");
}
partitions[*numPartitions].bootLabel = NULL;
partitions[*numPartitions].defaultBoot = 0;
logMessage("found partition %s", partitions[*numPartitions].device);
(*numPartitions)++;
}
static void parseFdiskLine(char * device, char * start, int * numPartitions,
struct partition partitions[15]) {
int tag, i;
char * str = start;
char * chptr;
if (*str != '/') return;
if (strlen(str) < 60) return;
/* grab the partition number */
str += 8;
chptr = str;
if (!isdigit(*chptr)) return;
while (*chptr && isdigit(*chptr)) chptr++;
if (!*chptr) return;
*chptr = '\0';
strcpy(partitions[*numPartitions].device, device);
strcat(partitions[*numPartitions].device, str);
str = chptr + 1;
/* go to the "Begin" field, skipping the '*' which marks a bootable
partition and the 'u|r' fields which can occur on a Sun disklabel */
while (*str && (isspace(*str) || *str == '*' || *str == 'u' ||
*str == 'r')) str++;
if (!*str) return;
/* skip the Begin: field (but make sure it's a number */
if (!isdigit(*str)) return;
while (isdigit(*str)) str++;
if (!*str || !isspace(*str)) return;
/* go to the first digit in the "Start" field */
while (isspace(*str)) str++;
if (!*str) return;
partitions[*numPartitions].begin = strtol(str, &chptr, 10);
if (!chptr || !isspace(*chptr)) return;
str = chptr;
/* go to the first digit in the "End" field */
while (isspace(*str)) str++;
if (!*str) return;
partitions[*numPartitions].end = strtol(str, &chptr, 10);
if (!chptr || !isspace(*chptr)) return;
str = chptr;
/* go to the first digit in the "Size" field */
while (isspace(*str)) str++;
if (!*str) return;
partitions[*numPartitions].size = strtol(str, &chptr, 10);
if (!chptr || (*chptr != '-' && *chptr != '+' && !isspace(*chptr)))
return;
str = chptr + 1;
/* go to the first digit in the "Tag" field */
while (isspace(*str)) str++;
if (!*str) return;
tag = strtol(str, &chptr, 16);
partitions[*numPartitions].type = PART_OTHER;
for (i = 0; fdiskTags[i].tag; i++) {
if (fdiskTags[i].tag == tag) {
partitions[*numPartitions].type = fdiskTags[i].type;
break;
}
}
str = chptr;
while (isspace(*str)) str++;
if (!*str) return;
strcpy(partitions[*numPartitions].tagName, str);
partitions[*numPartitions].bootLabel = NULL;
partitions[*numPartitions].defaultBoot = 0;
logMessage("found partition %s", partitions[*numPartitions].device);
(*numPartitions)++;
}
static int findPartitions(char * hdname, int * numPartitions,
struct partition partitions[15]) {
char devBuf[20];
int fd;
char * fdiskOutput;
char * fdiskArgs[] = { NULL, NULL, NULL };
char * start, * end;
int oldTesting;
int len;
char * cmd;
int labelMode = 0;
#if defined(__alpha__)
unsigned short magic;
unsigned int fdiskMagic = 0xAA55;
#endif
if (testing)
cmd = "/sbin/fdisk";
else
cmd = "/usr/bin/fdisk";
fdiskArgs[0] = cmd;
*numPartitions = 0;
/* don't bother with any of this if the main device doesn't exist
or doesn't look like a hard drive */
sprintf(devBuf, "/tmp/%s", hdname);
if (devMakeInode(hdname, devBuf)) {
return 0;
}
fd = open(devBuf, O_RDONLY);
if (fd < 0) {
unlink(devBuf);
return 0;
}
#if defined(__alpha__)
/* is this a labeled disk? */
/* This test used to just look for the disklabel magic, but that
got left around on fdisks drives much of the time. This check
seems more reliable */
lseek(fd, 510, SEEK_SET);
if (read(fd, &magic, sizeof(magic)) == sizeof(magic))
labelMode = (magic != fdiskMagic);
if (labelMode)
logMessage("/dev/%s is disklabeled", hdname);
else
logMessage("/dev/%s is fdisked", hdname);
#endif
close(fd);
oldTesting = testing;
testing = 0;
fdiskArgs[1] = devBuf;
if (labelMode)
runProgramIO(RUN_NOLOG, cmd, fdiskArgs, "b\np\nq\n", &fdiskOutput);
else
runProgramIO(RUN_NOLOG, cmd, fdiskArgs, "p\nq\n", &fdiskOutput);
unlink(devBuf);
testing = oldTesting;
start = fdiskOutput;
len = strlen(start);
while (((start - fdiskOutput) < len) && (end = strchr(start, '\n'))) {
*end = '\0';
if (labelMode)
parseLabelLine(hdname, start, numPartitions, partitions);
else
parseFdiskLine(hdname, start, numPartitions, partitions);
start = end + 1;
}
free(fdiskOutput);
return 0;
}
int findAllPartitions(struct deviceInfo * devices,
struct partitionTable * table) {
int numPartitions;
int i;
struct partition parts[16];
struct partition * allParts = NULL;
int numAllParts = 0;
if (!devices) {
/* FIXME: memory leak for internal structures */
devices = alloca(sizeof(*devices) * MAX_NUM_DRIVES);
if (findDrivesPresent(devices, NULL)) return INST_ERROR;
}
winStatus(30, 3, "Hard Drives", "Scanning hard drives...");
for (i = 0; devices[i].deviceName; i++) {
findPartitions(devices[i].deviceName, &numPartitions, parts);
if (!numPartitions) continue;
if (!numAllParts) {
numAllParts = numPartitions;
allParts = malloc(sizeof(*allParts) * numAllParts);
memcpy(allParts, parts, sizeof(*allParts) * numAllParts);
} else {
allParts = realloc(allParts, sizeof(*allParts) *
(numAllParts + numPartitions));
memcpy(allParts + numAllParts, parts,
sizeof(*allParts) * numPartitions);
numAllParts += numPartitions;
}
}
table->count = numAllParts;
table->parts = allParts;
newtPopWindow();
return 0;
}
static int findDrivesPresent(struct deviceInfo * drives, int * numPtr) {
struct deviceInfo * scsi = NULL, * ide = NULL;
int num = 0;
int i;
/* FIXME: this results in memory leaks via the strings inside of
the decice structures! */
if (scsiDeviceAvailable()) {
if (scsiGetDevices(&scsi)) return INST_ERROR;
}
if (ideGetDevices(&ide)) return INST_ERROR;
i = 0, num = 0;
while (ide[i].deviceName) {
if (ide[i].type == DEVICE_HD)
drives[num++] = ide[i];
i++;
}
i = 0;
while (scsi && scsi[i].deviceName) {
if (scsi[i].type == DEVICE_HD)
drives[num++] = scsi[i];
i++;
}
drives[num].deviceName = NULL;
if (numPtr) *numPtr = num;
return 0;
}
int getDriveList(char *** drives, int * num) {
struct deviceInfo drivesPresent[MAX_NUM_DRIVES];
int rc;
int i;
if ((rc = findDrivesPresent(drivesPresent, num))) return rc;
*drives = malloc(sizeof(char *) * (*num + 1));
for (i = 0; i < *num; i++) {
(*drives)[i] = drivesPresent[i].deviceName;
}
(*drives)[i] = NULL;
return 0;
}
int partitionDrives(void) {
struct deviceInfo drivesPresent[MAX_NUM_DRIVES];
int numDrivesPresent = 0;
int childpid;
int i, fd;
int haveEdited = 0;
char devBuf[100], idBuf[3];
newtComponent cancel, done, edit, text, listbox, f, answer, okay, form;
struct deviceInfo * currhd;
int status;
int reboot = 0;
char * cmd;
if (testing)
cmd = "/sbin/fdisk";
else
cmd = "/usr/bin/fdisk";
findDrivesPresent(drivesPresent, &numDrivesPresent);
if (!numDrivesPresent) {
newtWinMessage(text, "Ok", "You don't have any hard drives available! "
"You probably forgot to configure a SCSI "
"controller.");
return INST_ERROR;
}
newtCenteredWindow(60, 17, "Partition Disks");
text = newtTextbox(1, 1, 56, 5, NEWT_TEXTBOX_WRAP);
#ifdef __i386__
newtTextboxSetText(text,
"To install Red Hat Linux, you must have at least "
"one parition of 50 MB dedicated to Linux. We suggest "
"placing that partition on one of the first two hard "
"drives in your system so you can boot into Linux "
"with LILO.");
#else
newtTextboxSetText(text,
"To install Red Hat Linux, you must have at least "
"one parition of 50 MB dedicated to Linux.");
#endif
listbox = newtListbox(5, 7, numDrivesPresent < 5 ? numDrivesPresent : 5,
(numDrivesPresent <= 5 ? NEWT_FLAG_NOSCROLL : 0) |
NEWT_LISTBOX_RETURNEXIT);
for (i = 0; i < numDrivesPresent; i++) {
sprintf(devBuf, "/dev/%s", drivesPresent[i].deviceName);
if (!strncmp(drivesPresent[i].deviceName, "sd", 2)) {
sprintf(idBuf, "%d", drivesPresent[i].id);
strcat(devBuf, " - SCSI ID ");
strcat(devBuf, idBuf);
}
strcat(devBuf, " - Model ");
strcat(devBuf, drivesPresent[i].info);
/* truncate at 50 columns for now */
devBuf[50] = '\0';
newtListboxAddEntry(listbox, devBuf, drivesPresent + i);
}
done = newtButton(7, 13, "Done");
edit = newtButton(24, 13, "Edit");
cancel = newtButton(41, 13, "Cancel");
f = newtForm(NULL, NULL, 0);
newtFormAddComponents(f, text, listbox, done, edit, cancel, NULL);
newtFormSetCurrent(f, done);
do {
answer = newtRunForm(f);
if (answer == edit || answer == listbox) {
haveEdited = 1;
currhd = newtListboxGetCurrent(listbox);
sprintf(devBuf, "/tmp/%s", currhd->deviceName);
if (devMakeInode(currhd->deviceName, devBuf)) return 0;
newtPopWindow();
newtSuspend();
for (i = 0; i < 25; i++) puts("");
printf("This is the fdisk program for partitioning your drive. It "
"is running\non /dev/%s.\n\n", currhd->deviceName);
logMessage("running fdisk on %s", devBuf);
if (!(childpid = fork())) {
execl(cmd, cmd, devBuf, NULL);
return -1;
}
waitpid(childpid, &status, 0);
newtResume();
newtCenteredWindow(60, 17, "Partition Disks");
}
} while (answer != done && answer != cancel && answer != f);
newtFormDestroy(f);
newtPopWindow();
if (haveEdited) {
for (i = 0; i < numDrivesPresent; i++) {
sprintf(devBuf, "/tmp/%s", drivesPresent[i].deviceName);
if (devMakeInode(drivesPresent[i].deviceName, devBuf))
return INST_ERROR;
fd = open(devBuf, O_RDONLY);
unlink(devBuf);
if (fd < 0) reboot = 1;
if (ioctl(fd, BLKRRPART, 0)) reboot = 1;
close(fd);
}
}
if (reboot) {
newtWinMessage("Reboot Needed", "Ok",
"The kernel is unable to read your new partitioning "
"information, probably because you modified extended "
"partitions. While this is not critical, you must "
"reboot your machine before proceeding. Insert the "
"Red Hat boot disk now and press Return to reboot "
"your system.\n\n"
"If you have a ZIP or JAZ drive, make sure there is "
"a disk in the drive as an empty SCSI drive can also "
"cause this problem.");
newtFinished();
exit(0);
}
if (answer == cancel)
return INST_CANCEL;
return 0;
}