#include #include #include #include #include #include #include #include #include #include #include #include #include "hd.h" #include "install.h" #include "log.h" #include "newt.h" #include "run.h" #include "windows.h" extern int testing; 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 }, { 0x82, PART_SWAP }, { 0x83, PART_EXT2 }, { 0, 0 }, }; #endif struct hd { char * device; int major, minor; }; struct hd static possibleDrives[] = { #ifndef __sparc__ { "hda", 3, 0 }, { "hdb", 3, 64 }, { "hdc", 22, 0 }, { "hdd", 22, 64 }, { "hde", 33, 0 }, { "hdf", 33, 64 }, { "hdg", 34, 0 }, { "hdh", 34, 64 }, #endif { "sda", 8, 0 }, { "sdb", 8, 16 }, { "sdc", 8, 32 }, { "sdd", 8, 48 }, { "sde", 8, 64 }, { "sdf", 8, 80 }, { "sdg", 8, 96 }, { "sdh", 8, 112 }, }; 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; 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; logMessage("found partition %s", partitions[*numPartitions].device); (*numPartitions)++; } static int findPartitions(struct hd hd, 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; unsigned int magic; unsigned int labelMagic = 0x82564557; 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 */ sprintf(devBuf, "/tmp/%s", hd.device); mknod(devBuf, S_IFBLK | 0600, makedev(hd.major, hd.minor)); fd = open(devBuf, O_RDONLY); if (fd < 0) { unlink(devBuf); return 0; } /* is this a labeled disk? */ lseek(fd, 64, SEEK_SET); if (read(fd, &magic, sizeof(magic)) == 4) labelMode = magic == labelMagic; 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(hd.device, start, numPartitions, partitions); else parseFdiskLine(hd.device, start, numPartitions, partitions); start = end + 1; } free(fdiskOutput); return 0; } int findAllPartitions(struct partitionTable * table) { int numPartitions; int i; struct partition parts[16]; struct partition * allParts = NULL; int numAllParts = 0; winStatus(30, 3, "Hard Drives", "Scanning hard drives..."); for (i = 0; i < (sizeof(possibleDrives) / sizeof(*possibleDrives)); i++) { findPartitions(possibleDrives[i], &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; } int partitionDrives(void) { int drivesPresent[sizeof(possibleDrives) / sizeof(*possibleDrives)]; int numDrivesPresent = 0; int childpid; int i, fd; int haveEdited = 0; char devBuf[20]; newtComponent cancel, done, edit, text, listbox, f, answer; struct hd_geometry geo; struct hd * currhd; char * cmd; int status; int reboot = 0; if (testing) cmd = "/sbin/fdisk"; else cmd = "/usr/bin/fdisk"; for (i = 0; i < sizeof(possibleDrives) / sizeof(*possibleDrives); i++) { sprintf(devBuf, "/tmp/%s", possibleDrives[i].device); mknod(devBuf, S_IFBLK | 0600, makedev(possibleDrives[i].major, possibleDrives[i].minor)); fd = open(devBuf, O_RDONLY); unlink(devBuf); if (fd < 0) { continue; } logMessage("successfully opened: %s", devBuf); if (possibleDrives[i].device[0] == 'h') { /* make sure this isn't an IDE CD or tape drive */ if (ioctl(fd, HDIO_GETGEO, &geo)) { logMessage("\tHDIO_GETGEO ioctl failed - probably cd or tape"); close(fd); continue; } } close(fd); drivesPresent[numDrivesPresent++] = i; } newtOpenWindow(10, 3, 60, 17, "Partition Disks"); text = newtTextbox(1, 1, 56, 5, NEWT_TEXTBOX_WRAP); 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."); listbox = newtListbox(23, 7, 5, NEWT_LISTBOX_RETURNEXIT); for (i = 0; i < numDrivesPresent; i++) { sprintf(devBuf, "/dev/%s", possibleDrives[drivesPresent[i]].device); newtListboxAddEntry(listbox, devBuf, possibleDrives + 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->device); mknod(devBuf, S_IFBLK | 0600, makedev(currhd->major, currhd->minor)); 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->device); logMessage("running fdisk on %s", devBuf); if (!(childpid = fork())) { execl(cmd, cmd, devBuf, NULL); return -1; } waitpid(childpid, &status, 0); newtResume(); newtOpenWindow(10, 3, 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", possibleDrives[drivesPresent[i]].device); mknod(devBuf, S_IFBLK | 0600, makedev(possibleDrives[drivesPresent[i]].major, possibleDrives[drivesPresent[i]].minor)); fd = open(devBuf, O_RDONLY); unlink(devBuf); if (fd < 0) reboot = 1; if (ioctl(fd, BLKRRPART, 0)) reboot = 1; close(fd); } } if (reboot) { winMessage(14, 6, 52, 12, "Reboot Needed", "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."); newtFinished(); exit(0); } if (answer == cancel) return INST_CANCEL; return 0; }