bool PartitionMap::Check(off_t sessionSize) const { int32 partitionCount = CountPartitions(); // 1. check partition locations for (int32 i = 0; i < partitionCount; i++) { if (!PartitionAt(i)->CheckLocation(sessionSize)) return false; } // 2. check overlapping of partitions and location of partition tables bool result = true; Partition** byOffset = new(nothrow) Partition*[partitionCount]; off_t* tableOffsets = new(nothrow) off_t[partitionCount - 3]; if (byOffset && tableOffsets) { // fill the arrays int32 byOffsetCount = 0; int32 tableOffsetCount = 1; // primary partition table tableOffsets[0] = 0; for (int32 i = 0; i < partitionCount; i++) { Partition* partition = (Partition*)PartitionAt(i); if (!partition->IsExtended()) byOffset[byOffsetCount++] = partition; // add only logical partition partition table locations if (i >= 4) { tableOffsets[tableOffsetCount++] = partition->PartitionTableOffset(); } } // sort the arrays qsort(byOffset, byOffsetCount, sizeof(Partition*), cmp_partition_offset); qsort(tableOffsets, tableOffsetCount, sizeof(off_t), cmp_offset); // check for overlappings off_t nextOffset = 0; for (int32 i = 0; i < byOffsetCount; i++) { Partition* partition = byOffset[i]; if (partition->Offset() < nextOffset && i > 0) { Partition* previousPartition = byOffset[i - 1]; off_t previousSize = previousPartition->Size() - (nextOffset - partition->Offset()); TRACE(("intel: PartitionMap::Check(): ")); if (previousSize == 0) { previousPartition->Unset(); TRACE(("partition offset hides previous partition." " Removing previous partition from disk layout.\n")); } else { TRACE(("overlapping partitions! Setting partition %ld " "size to %lld\n", i - 1, previousSize)); previousPartition->SetSize(previousSize); } } nextOffset = partition->Offset() + partition->Size(); } // check uniqueness of partition table offsets and whether they lie // outside of the non-extended partitions if (result) { for (int32 i = 0; i < tableOffsetCount; i++) { if (i > 0 && tableOffsets[i] == tableOffsets[i - 1]) { TRACE(("intel: PartitionMap::Check(): same partition table " "for different extended partitions!\n")); result = false; break; } else if (is_inside_partitions(tableOffsets[i], (const Partition**)byOffset, byOffsetCount)) { TRACE(("intel: PartitionMap::Check(): a partition table " "lies inside a non-extended partition!\n")); result = false; break; } } } } else result = false; // no memory: assume failure // cleanup delete[] byOffset; delete[] tableOffsets; return result; }
// main int main(int argc, const char *const *argv) { kArgc = argc; kArgv = argv; if (argc < 2) print_usage_and_exit(true); // parameters const char **files = new const char*[argc]; int fileCount = 0; bool dryRun = false; off_t startOffset = 0; // parse arguments for (int argi = 1; argi < argc;) { const char *arg = argv[argi++]; if (arg[0] == '-') { if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { print_usage_and_exit(false); } else if (strcmp(arg, "--dry-run") == 0) { dryRun = true; } else if (strcmp(arg, "-alert") == 0) { // ignore } else if (strcmp(arg, "-full") == 0) { // ignore } else if (strcmp(arg, "--start-offset") == 0) { if (argi >= argc) print_usage_and_exit(true); startOffset = strtoll(argv[argi++], NULL, 0); } else if (strcmp(arg, "-safe") == 0) { fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n"); exit(1); } else { print_usage_and_exit(true); } } else { files[fileCount++] = arg; } } // we need at least one file if (fileCount == 0) print_usage_and_exit(true); // read the boot code uint8 *bootCodeData = NULL; #ifndef __ANTARES__ bootCodeData = read_boot_code_data(argv[0]); #else image_info info; if (find_own_image(&info) == B_OK) bootCodeData = read_boot_code_data(info.name); #endif if (!bootCodeData) { fprintf(stderr, "Error: Failed to read \n"); exit(1); } // iterate through the files and make them bootable status_t error; for (int i = 0; i < fileCount; i++) { const char *fileName = files[i]; BEntry entry; error = entry.SetTo(fileName, true); if (error != B_OK) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(error)); exit(1); } // get stat to check the type of the file struct stat st; error = entry.GetStat(&st); if (error != B_OK) { fprintf(stderr, "Error: Failed to stat \"%s\": %s\n", fileName, strerror(error)); exit(1); } bool noPartition = false; int64 partitionOffset = 0; fs_info info; // needs to be here (we use the device name later) if (S_ISDIR(st.st_mode)) { #if defined(__BEOS__) || defined(__ANTARES__) // a directory: get the device error = fs_stat_dev(st.st_dev, &info); if (error != B_OK) { fprintf(stderr, "Error: Failed to determine device for " "\"%s\": %s\n", fileName, strerror(error)); exit(1); } fileName = info.device_name; #else (void)info; fprintf(stderr, "Error: Specifying directories not supported " "on this platform!\n"); exit(1); #endif } else if (S_ISREG(st.st_mode)) { // a regular file: fine noPartition = true; } else if (S_ISCHR(st.st_mode)) { // character special: a device or partition under BeOS // or under FreeBSD #if !(defined(__BEOS__) || defined(__ANTARES__)) && !defined(ANTARES_HOST_PLATFORM_FREEBSD) fprintf(stderr, "Error: Character special devices not " "supported on this platform.\n"); exit(1); #endif #ifdef ANTARES_HOST_PLATFORM_FREEBSD // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = -1; for (int k = fileNameLen - 1; k >= 0; k--) { if (!isdigit(fileName[k])) { baseNameLen = k + 1; break; } } // Remove de 's' from 'ad2s2' slice device (partition for DOS // users) to get 'ad2' base device baseNameLen--; if (baseNameLen < 0) { // only digits? fprintf(stderr, "Error: Failed to get base device name.\n"); exit(1); } if (baseNameLen < fileNameLen) { // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen + 1); // Don't forget the 's' of slice :) memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size int64 deviceSize; if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) { fprintf(stderr, "Error: Failed to get device geometry " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // parse the partition map // TODO: block size! PartitionMapParser parser(baseFD, 0, deviceSize, 512); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); } else { // The given device is the base device. We'll write at // offset 0. } #endif // ANTARES_HOST_PLATFORM_FREEBSD } else if (S_ISBLK(st.st_mode)) { // block device: a device or partition under Linux or Darwin #ifdef ANTARES_HOST_PLATFORM_LINUX // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = -1; for (int k = fileNameLen - 1; k >= 0; k--) { if (!isdigit(fileName[k])) { baseNameLen = k + 1; break; } } if (baseNameLen < 0) { // only digits? fprintf(stderr, "Error: Failed to get base device name.\n"); exit(1); } if (baseNameLen < fileNameLen) { // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen); memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size -- try BLKGETSIZE64, but, if it doesn't // work, fall back to the obsolete HDIO_GETGEO int64 deviceSize; hd_geometry geometry; if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0 && deviceSize > 0) { // looks good } else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) { deviceSize = (int64)geometry.heads * geometry.sectors * geometry.cylinders * 512; } else { fprintf(stderr, "Error: Failed to get device geometry " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // parse the partition map // TODO: block size! PartitionMapParser parser(baseFD, 0, deviceSize, 512); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); } else { // The given device is the base device. We'll write at // offset 0. } #elif defined(ANTARES_HOST_PLATFORM_DARWIN) // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = fileNameLen - 2; // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen + 1); memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size int64 blockSize; int64 blockCount; int64 deviceSize; if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) { fprintf(stderr, "Error: Failed to get block size " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) { fprintf(stderr, "Error: Failed to get block count " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } deviceSize = blockSize * blockCount; // parse the partition map PartitionMapParser parser(baseFD, 0, deviceSize, blockSize); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); #else // partitions are block devices under Antares, but not under BeOS #ifndef __ANTARES__ fprintf(stderr, "Error: Block devices not supported on this " "platform!\n"); exit(1); #endif // __ANTARES__ #endif } else { fprintf(stderr, "Error: File type of \"%s\" is not supported.\n", fileName); exit(1); } // open the file int fd = open(fileName, O_RDWR); if (fd < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(errno)); exit(1); } #if (defined(__BEOS__) || defined(__ANTARES__)) // get a partition info if (!noPartition && strlen(fileName) >= 3 && strncmp("raw", fileName + strlen(fileName) - 3, 3)) { partition_info partitionInfo; if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo, sizeof(partitionInfo)) == 0) { partitionOffset = partitionInfo.offset; } else { fprintf(stderr, "Error: Failed to get partition info: %s\n", strerror(errno)); exit(1); } } #endif // __BEOS__ // adjust the partition offset in the boot code data // hard coded sector size: 512 bytes *(uint32*)(bootCodeData + kPartitionOffsetOffset) = B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512)); // write the boot code printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64 " bytes, start offset = %" B_PRIdOFF ") " "...\n", fileName, partitionOffset, startOffset); write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0, kFirstBootCodePartSize, dryRun); write_boot_code_part(fileName, fd, startOffset, bootCodeData, kSecondBootCodePartOffset, kSecondBootCodePartSize, dryRun); #ifdef __ANTARES__ // check if this partition is mounted BDiskDeviceRoster roster; BPartition* partition; BDiskDevice device; status_t status = roster.GetPartitionForPath(fileName, &device, &partition); if (status != B_OK) { status = roster.GetFileDeviceForPath(fileName, &device); if (status == B_OK) partition = &device; } if (status == B_OK && partition->IsMounted() && !dryRun) { // This partition is mounted, we need to tell BFS to update its // boot block (we are using part of the same logical block). BPath path; status = partition->GetMountPoint(&path); if (status == B_OK) { update_boot_block update; update.offset = kSecondBootCodePartOffset - 512; update.data = bootCodeData + kSecondBootCodePartOffset; update.length = kSecondBootCodePartSize; int mountFD = open(path.Path(), O_RDONLY); if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update, sizeof(update_boot_block)) != 0) { fprintf(stderr, "Could not update BFS boot block: %s\n", strerror(errno)); } close(mountFD); } else { fprintf(stderr, "Could not update BFS boot code while the " "partition is mounted!\n"); } } #endif // __ANTARES__ close(fd); } return 0; }