#include #include #include #include #include #include #include #include #include #include #include #include #include #include "hd.h" #include "install.h" #include "intl.h" #include "libfdisk/libfdisk.h" #include "log.h" #include "newt.h" #include "run.h" #include "scsi.h" #include "windows.h" extern int testing; char *default_boot_hd = NULL; #ifndef BLKRRPART /* shame we can't get this from any header files */ #define BLKRRPART _IO(0x12,95) /* re-read partition table */ #endif struct fdiskTag { int tag; int type; char * tagName; } ; #if defined(__sparc__) const struct fdiskTag fdiskTags[] = { { 0x05, PART_IGNORE, N_("Whole disk") }, { 0x82, PART_SWAP, N_("Linux swap") }, { 0x83, PART_EXT2, N_("Linux native") }, { 0, 0 }, }; #else const struct fdiskTag fdiskTags[] = { { 0x01, PART_DOS, N_("DOS 12-bit FAT") }, { 0x04, PART_DOS, N_("DOS 16-bit <32M") }, { 0x05, PART_IGNORE, "Extended" }, { 0x06, PART_DOS, N_("DOS 16-bit >=32") }, { 0x07, PART_HPFS, N_("OS/2 HPFS") }, { 0x0b, PART_FAT32, N_("Win95 FAT32") }, { 0x0c, PART_FAT32, N_("Win95 FAT32") }, { 0x0e, PART_FAT32, N_("Win95 FAT32") }, { 0x82, PART_SWAP, N_("Linux swap") }, { 0x83, PART_EXT2, N_("Linux native") }, { 0, 0 }, }; #endif #define MAX_NUM_DRIVES 100 static int findDrivesPresent(struct deviceInfo * drives, int * numPtr); static int findPartitions(char * hdname, int * numPartitions, struct partition partitions[15]) { char devBuf[20]; int j, i; int status; HardDrive * hd = NULL; PartitionSpec spec; char *ptr; *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; } status = fdiskOpenDevice(devBuf, 0, &hd); if (status != FDISK_SUCCESS) { unlink(devBuf); return 0; } if ((ptr = strstr(hd->name, "tmp/"))) { strcpy(hd->prefix, ptr + 4); } /* for RAID arrays of format c0d0p1 */ if (strstr(ptr + 4, "rd/") || strstr(ptr + 4, "ida/")) strcat(hd->prefix, "p"); status = fdiskReadPartitions(hd); if (status != FDISK_SUCCESS) { fdiskCloseDevice(hd); unlink(devBuf); return 0; } /* Translate into a PartitionSpec */ memset(&spec, 0, sizeof(PartitionSpec)); fdiskSetupPartitionSpec(&hd, 1, &spec ); *numPartitions = spec.num; for (i = 0; i < spec.num; i++) { memset(partitions + i, 0, sizeof(*partitions)); sprintf(partitions[i].device, "%s%d", hd->prefix, spec.entry[i].partition.num.current); /* the /2 converts from 512 byte sectors to 1k blocks */ partitions[i].size = spec.entry[i].partition.size.current / 2; partitions[i].begin = spec.entry[i].partition.start.current; partitions[i].end = spec.entry[i].partition.endcyl.current; for (j = 0; fdiskTags[j].tag; j++) { if (fdiskTags[j].tag == spec.entry[i].partition.type.current) { partitions[i].type = fdiskTags[j].type; strcpy(partitions[i].tagName, fdiskTags[j].tagName); break; } } #ifdef __sparc__ #define UFS_SUPER_MAGIC 0x00011954 if (!partitions[i].type && !devMakeInode(partitions[i].device, devBuf)) { int fd = open(devBuf, O_RDONLY), magic; if (fd >= 0) { if (lseek (fd, 8192 + 0x55c, SEEK_SET) == 8192 + 0x55c && read (fd, &magic, sizeof(magic)) == sizeof(magic) && magic == UFS_SUPER_MAGIC) { partitions[i].type = PART_UFS; strcpy(partitions[i].tagName, "Solaris/SunOS UFS"); } close(fd); } unlink(devBuf); } #endif } fdiskCloseDevice(hd); unlink(devBuf); 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, *dac960 = NULL, *cpq = NULL; int num = 0; int i; static int first = 1; /* 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; if (dac960GetDevices(&dac960)) return INST_ERROR; if (CompaqSmartArrayDeviceAvailable()) { if (CompaqSmartArrayGetDevices(&cpq)) return INST_ERROR; } /* default boot detection from hjl@gnu.org */ /* Detect the default BIOS boot harddrive is kind of tricky. We may have IDE, SCSI and RAID devices on the same machine. From what I see so far, the default BIOS boot harddrive will be 1. The first IDE device if IDE exists. Or 2. The first SCSI device if SCSI exists. Or 3. The first RAID device if RAID exists. This code tries to set "default_boot_hd" to the default BIOS boot harddrive. */ i = 0, num = 0; while (ide[i].deviceName) { if (ide[i].type == DEVICE_HD) { drives[num++] = ide[i]; if (!default_boot_hd) default_boot_hd = ide[i].deviceName; } i++; } i = 0; while (scsi && scsi[i].deviceName) { if (scsi[i].type == DEVICE_HD) { drives[num++] = scsi[i]; if (!default_boot_hd) default_boot_hd = scsi[i].deviceName; } i++; } i = 0; while (dac960 && dac960[i].deviceName) { drives[num++] = dac960[i]; if (!default_boot_hd) default_boot_hd = dac960[i].deviceName; i++; } i = 0; while (cpq && cpq[i].deviceName) { drives[num++] = cpq[i]; if (!default_boot_hd) default_boot_hd = cpq[i].deviceName; 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]; char * driveText[50]; struct deviceInfo * currhd; int status; int reboot = 0; char * cmd; char * text; int rc, driveNum = 0; if (!access("/sbin/fdisk", X_OK)) 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; } #ifdef __i386__ text = _("To install Red Hat Linux, you must have at least one partition " "of 150 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 text = _("To install Red Hat Linux, you must have at least one partition " "of 150 MB dedicated to Linux."); #endif 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); if (drivesPresent[i].deviceName[0] == 'c' && drivesPresent[i].deviceName[2] == 'd') { strcat(devBuf, " - "); strcat(devBuf, drivesPresent[i].info); strcat(devBuf, " array"); } else { strcat(devBuf, " - Model "); strcat(devBuf, drivesPresent[i].info); } /* truncate at 50 columns for now */ devBuf[50] = '\0'; driveText[i] = alloca(strlen(devBuf) + 1); strcpy(driveText[i], devBuf); } driveText[i] = NULL; do { rc = newtWinMenu(_("Partition Disks"), text, 56, 5, 6, 5, driveText, &driveNum, _("Done"), _("Edit"), _("Back"), NULL); if (rc == 2 || rc == 0) { haveEdited = 1; currhd = drivesPresent + driveNum; sprintf(devBuf, "/tmp/%s", currhd->deviceName); if (devMakeInode(currhd->deviceName, devBuf)) return 0; 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; } signal(SIGINT, SIG_IGN); waitpid(childpid, &status, 0); signal(SIGINT, SIG_DFL); newtResume(); } } while (rc == 2 || rc == 0); 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) needReboot(); if (rc == 3) return INST_CANCEL; return 0; } void needReboot(void) { 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); }