home *** CD-ROM | disk | FTP | other *** search
- #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("Hard Drives", "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;
- }
-