From bfa5a8db186641f2227e0566dd7d084f0e6748ec Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 28 Feb 2010 18:51:16 +0000 Subject: [PATCH] Adding an "anyboot" buildtool that takes a chainloading MBR, a ISO CD boot image and a Haiku image and fuses everything to a hybrid MBR/ISO image. Since it contains a valid MBR, partition table and el-torito CD boot record such an image should be pretty universally bootable. It can be written to disks, USB sticks or CDs/DVDs. Since it has a partition table in place it is also possible that it helps with the non-booting USB sticks where the BIOS (wrongly) assumes a partition table. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35667 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/tools/Jamfile | 1 + src/tools/anyboot/Jamfile | 3 + src/tools/anyboot/anyboot.cpp | 123 ++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 src/tools/anyboot/Jamfile create mode 100644 src/tools/anyboot/anyboot.cpp diff --git a/src/tools/Jamfile b/src/tools/Jamfile index 89ed1b8925..599dd20a8e 100644 --- a/src/tools/Jamfile +++ b/src/tools/Jamfile @@ -103,6 +103,7 @@ SEARCH on [ FGristFiles ] = [ FDirName $(HAIKU_TOP) src kits shared ] ; SubInclude HAIKU_TOP src tools addattr ; +SubInclude HAIKU_TOP src tools anyboot ; SubInclude HAIKU_TOP src tools bfs_shell ; SubInclude HAIKU_TOP src tools cppunit ; SubInclude HAIKU_TOP src tools docbook ; diff --git a/src/tools/anyboot/Jamfile b/src/tools/anyboot/Jamfile new file mode 100644 index 0000000000..c4713f2cea --- /dev/null +++ b/src/tools/anyboot/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src tools anyboot ; + +BuildPlatformMain anyboot : anyboot.cpp : ; diff --git a/src/tools/anyboot/anyboot.cpp b/src/tools/anyboot/anyboot.cpp new file mode 100644 index 0000000000..aa1931be47 --- /dev/null +++ b/src/tools/anyboot/anyboot.cpp @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include +#include + +static uint8_t *sCopyBuffer = NULL; +static size_t sCopyBufferSize = 2 * 1024 * 1024; + + +int +copyLoop(int from, int to, off_t position) +{ + while (true) { + ssize_t copyLength = read(from, sCopyBuffer, sCopyBufferSize); + if (copyLength <= 0) + return copyLength; + + ssize_t written = write_pos(to, position, sCopyBuffer, copyLength); + if (written != copyLength) { + if (written < 0) + return written; + else + return -1; + } + + position += copyLength; + } +} + + +void +checkError(bool failed, const char *message) +{ + if (!failed) + return; + + printf("%s: %s\n", message, strerror(errno)); + free(sCopyBuffer); + exit(1); +} + + +int +main(int argc, char *argv[]) +{ + if (argc < 5) { + printf("usage: %s \n", + argv[0]); + return 1; + } + + sCopyBuffer = (uint8_t *)malloc(sCopyBufferSize); + checkError(sCopyBuffer == NULL, "no memory for copy buffer"); + + static const size_t kBlockSize = 512; + + int outputFile = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT); + checkError(outputFile < 0, "failed to open output file"); + + int isoFile = open(argv[2], O_RDONLY); + checkError(isoFile < 0, "failed to open ISO file"); + + struct stat stat; + int result = fstat(isoFile, &stat); + checkError(result != 0, "failed to stat ISO file"); + off_t isoSize = stat.st_size; + + int mbrFile = open(argv[3], O_RDONLY); + checkError(mbrFile < 0, "failed to open MBR file"); + + int imageFile = open(argv[4], O_RDONLY); + checkError(imageFile < 0, "failed to open image file"); + + result = fstat(imageFile, &stat); + checkError(result != 0, "failed to stat image file"); + + off_t imageSize = stat.st_size; + + result = copyLoop(isoFile, outputFile, 0); + checkError(result != 0, "failed to copy iso file to output"); + + // isoSize rounded to the next full megabyte + off_t alignment = 1 * 1024 * 1024 - 1; + off_t imageOffset = (isoSize + alignment) & ~alignment; + + result = copyLoop(imageFile, outputFile, imageOffset); + checkError(result != 0, "failed to copy image file to output"); + + result = copyLoop(mbrFile, outputFile, 0); + checkError(result != 0, "failed to copy mbr to output"); + + // construct the partition table + uint8_t partition[16] = { + 0x80, // active + 0xff, 0xff, 0xff, // CHS start offset + // TODO: we enforce LBA here, maybe not a good idea? + 0xeb, // partition type (BFS) + 0xff, 0xff, 0xff, // CHS end offset + // TODO: see above + 0x00, 0x00, 0x00, 0x00, // imageOffset in blocks (written below) + 0x00, 0x00, 0x00, 0x00 // imageSize in blocks (written below) + }; + + alignment = kBlockSize - 1; + imageSize = (imageSize + alignment) & ~alignment; + + uint32_t partitionOffset = (uint32_t)(imageOffset / kBlockSize); + ((uint32_t *)partition)[2] = partitionOffset; + ((uint32_t *)partition)[3] = (uint32_t)(imageSize / kBlockSize); + ssize_t written = write_pos(outputFile, 512 - 2 - 16 * 4, partition, 16); + checkError(written != 16, "failed to write partition entry"); + + // and make the image bootable + written = write_pos(outputFile, imageOffset + 512 - 2 - 4, + &partitionOffset, 4); + checkError(written != 4, "failed to make image bootable"); + + free(sCopyBuffer); + return 0; +}