From 04fcc147ca2ab29344fa77509b88bab29a76e2b8 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 30 Jan 2006 01:50:50 +0000 Subject: [PATCH] * Small fixes. * Added --dry-run option for paranoid ones like me. * Added support for making partition devices bootable under Linux (x86, BIOS). When specifying respective values for HAIKU_IMAGE_{DIR,NAME} ("/dev" and e.g. "sda7") a "jam haiku-image" will now replace the contents of your favorite partition with a fresh Haiku installation. BE WARNED: This is nothing for the faint of heart and I don't guarantee that my implementation is bug-free and won't mangle the contents of your hard disk even if you use it correctly. That being said, note that you'll probably have to run the "jam haiku-image" as root, if you want to access the partition devices, which is a bit annoying. Furthermore, if the build_haiku_image script fails for any reason, jam tends to remove the image file, which in this case would be a partition device node. The mknod command will be your friend in this case. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16148 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../platform/bios_ia32/makebootable.cpp | 192 ++++++++++++++---- .../makebootable/platform/bios_ia32/Jamfile | 21 +- 2 files changed, 172 insertions(+), 41 deletions(-) diff --git a/src/bin/makebootable/platform/bios_ia32/makebootable.cpp b/src/bin/makebootable/platform/bios_ia32/makebootable.cpp index 0b1205bcb9..8778556353 100644 --- a/src/bin/makebootable/platform/bios_ia32/makebootable.cpp +++ b/src/bin/makebootable/platform/bios_ia32/makebootable.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. + * Copyright 2005-2006, Ingo Weinhold, bonefish@users.sf.net. * Distributed under the terms of the MIT License. */ @@ -19,6 +19,17 @@ #include #include +// Linux support +#ifdef HAIKU_HOST_PLATFORM_LINUX +# include +# include +# include + +# include "PartitionMap.h" +# include "PartitionMapParser.h" +#endif // HAIKU_HOST_PLATFORM_LINUX + + static const char *kCommandName = "makebootable"; static const int kBootCodeSize = 1024; @@ -45,6 +56,7 @@ const char *kUsage = "\n" "Options:\n" " -h, --help - Print this help text and exit.\n" +" --dry-run - Do everything but actually writing the boot block to disk.\n" "\n" "[compatibility]\n" " -alert - Compatibility option. Ignored.\n" @@ -84,13 +96,18 @@ print_usage_and_exit(bool error) // write_boot_code_part static void write_boot_code_part(const char *fileName, int fd, const uint8 *bootCodeData, - int offset, int size) + int offset, int size, bool dryRun) { -printf("writing %d bytes at offset %d\n", size, offset); - ssize_t bytesWritten = write_pos(fd, offset, bootCodeData + offset, size); - if (bytesWritten != size) { - fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName, - strerror(bytesWritten < 0 ? errno : B_ERROR)); + printf("writing %d bytes at offset %d%s\n", size, offset, + (dryRun ? " (dry run)" : "")); + + if (!dryRun) { + ssize_t bytesWritten = write_pos(fd, offset, bootCodeData + offset, + size); + if (bytesWritten != size) { + fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName, + strerror(bytesWritten < 0 ? errno : B_ERROR)); + } } } @@ -107,6 +124,7 @@ main(int argc, const char *const *argv) // parameters const char **files = new const char*[argc]; int fileCount = 0; + bool dryRun = false; // parse arguments for (int argi = 1; argi < argc;) { @@ -115,12 +133,14 @@ main(int argc, const char *const *argv) 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, "-safe") == 0) { - fprintf(stderr, "Error: Sorry, BeOS R3 isnt't supported!\n"); + fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n"); exit(1); } else { print_usage_and_exit(true); @@ -166,7 +186,7 @@ main(int argc, const char *const *argv) if (resourceSize != (size_t)kBootCodeSize) { fprintf(stderr, "Error: Something is fishy with my resources! The boot code " - "doesn't have the correct size\n"); + "doesn't have the correct size.\n"); exit(1); } @@ -195,26 +215,27 @@ main(int argc, const char *const *argv) } 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)) { #ifdef __BEOS__ - // 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); - } + // 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; + fileName = info.device_name; #else - (void)info; - fprintf(stderr, "Error: Only image files are supported on this " - "platform!\n"); - exit(1); + (void)info; + fprintf(stderr, "Error: Specifying directories not supported " + "on this platform!\n"); + exit(1); #endif @@ -222,16 +243,103 @@ main(int argc, const char *const *argv) // a regular file: fine noPartition = true; } else if (S_ISCHR(st.st_mode)) { - // a device or partition + // character special: a device or partition under BeOS #ifndef __BEOS__ - fprintf(stderr, "Error: Only image files are supported on this " - "platform!\n"); - exit(1); + fprintf(stderr, "Error: Character special devices not " + "supported on this platform.\n"); + exit(1); + + #endif + } else if (S_ISBLK(st.st_mode)) { + // block device: a device or partition under Linux + #ifdef HAIKU_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 geometry + hd_geometry geometry; + if (ioctl(baseFD, HDIO_GETGEO, &geometry) < 0) { + fprintf(stderr, "Error: Failed to get device geometry " + "for \"%s\": %s\n", baseDeviceName, + strerror(errno)); + exit(1); + } + int64 deviceSize = (int64)geometry.heads * geometry.sectors + * geometry.cylinders * 512; + + // parse the partition map + 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); + exit(1); + } + + if (partition->IsExtended()) { + fprintf(stderr, "Error: Partition %d is an extended " + "partition.\n", partitionIndex); + exit(1); + } + + partitionOffset = partition->Offset(); + + } else { + // The given device is the base device. We'll write at + // offset 0. + } + + #else // !HAIKU_HOST_PLATFORM_LINUX + + fprintf(stderr, "Error: Block devices not supported on this " + "platform!\n"); + exit(1); #endif } else { - fprintf(stderr, "Error: File type of \"%s\" is not unsupported\n", + fprintf(stderr, "Error: File type of \"%s\" is not supported.\n", fileName); exit(1); } @@ -244,30 +352,36 @@ main(int argc, const char *const *argv) exit(1); } - // get a partition info - int64 partitionOffset = 0; - #ifdef __BEOS__ - partition_info partitionInfo; - if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) == 0) { - // hard coded sector size: 512 bytes - partitionOffset = partitionInfo.offset / 512; - } + // get a partition info + if (!noPartition) { + partition_info partitionInfo; + if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) == 0) { + // hard coded sector size: 512 bytes + partitionOffset = partitionInfo.offset / 512; + } else { + fprintf(stderr, "Error: Failed to get partition info: %s", + strerror(errno)); + exit(1); + } + } #endif // __BEOS__ - // adjust the partition offset in the boot code data + // 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); + = B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512)); // write the boot code - printf("Writing boot code to \"%s\" ...\n", fileName); + printf("Writing boot code to \"%s\" (partition offset: %lld bytes) " + "...\n", fileName, partitionOffset); write_boot_code_part(fileName, fd, bootCodeData, 0, - kFirstBootCodePartSize); + kFirstBootCodePartSize, dryRun); write_boot_code_part(fileName, fd, bootCodeData, - kSecondBootcodePartOffset, kSecondBootcodePartSize); + kSecondBootcodePartOffset, kSecondBootcodePartSize, dryRun); close(fd); } diff --git a/src/tools/makebootable/platform/bios_ia32/Jamfile b/src/tools/makebootable/platform/bios_ia32/Jamfile index f24aae427f..504651fb3f 100644 --- a/src/tools/makebootable/platform/bios_ia32/Jamfile +++ b/src/tools/makebootable/platform/bios_ia32/Jamfile @@ -1,10 +1,27 @@ SubDir HAIKU_TOP src tools makebootable platform bios_ia32 ; -SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin makebootable platform bios_ia32 ] ; +UsePrivateHeaders storage ; + +SEARCH_SOURCE + += [ FDirName $(HAIKU_TOP) src bin makebootable platform bios_ia32 ] ; USES_BE_API on makebootable = true ; +local hostPlatformSources ; +if $(HOST_PLATFORM) = linux { + hostPlatformSources = PartitionMap.cpp PartitionMapParser.cpp ; + + SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel + partitioning_systems intel ] ; + + DEFINES += _USER_MODE ; +} + # write the stage 1 boot loader into the makebootable resources AddFileDataResource makebootable : RAWT:666:BootCode : stage1.bin ; -BuildPlatformMain makebootable : makebootable.cpp : $(HOST_LIBBE) ; +BuildPlatformMain makebootable : + makebootable.cpp + $(hostPlatformSources) + : $(HOST_LIBBE) +;