Author: mmlr Date: 2010-02-28 19:51:16 +0100 (Sun, 28 Feb 2010) New Revision: 35667 Changeset: http://dev.haiku-os.org/changeset/35667/haiku Added: haiku/trunk/src/tools/anyboot/ haiku/trunk/src/tools/anyboot/Jamfile haiku/trunk/src/tools/anyboot/anyboot.cpp Modified: haiku/trunk/src/tools/Jamfile Log: 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. Modified: haiku/trunk/src/tools/Jamfile =================================================================== --- haiku/trunk/src/tools/Jamfile 2010-02-28 18:35:04 UTC (rev 35666) +++ haiku/trunk/src/tools/Jamfile 2010-02-28 18:51:16 UTC (rev 35667) @@ -103,6 +103,7 @@ ] = [ 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 ; Added: haiku/trunk/src/tools/anyboot/Jamfile =================================================================== --- haiku/trunk/src/tools/anyboot/Jamfile (rev 0) +++ haiku/trunk/src/tools/anyboot/Jamfile 2010-02-28 18:51:16 UTC (rev 35667) @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src tools anyboot ; + +BuildPlatformMain <build>anyboot : anyboot.cpp : ; Added: haiku/trunk/src/tools/anyboot/anyboot.cpp =================================================================== --- haiku/trunk/src/tools/anyboot/anyboot.cpp (rev 0) +++ haiku/trunk/src/tools/anyboot/anyboot.cpp 2010-02-28 18:51:16 UTC (rev 35667) @@ -0,0 +1,123 @@ +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +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 <outputFile> <isoFile> <mbrFile> <imageFile>\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; +}