From Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>:
Alexander von Gluck IV has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/3570 ;)
Change subject: tools/mbrtool: A simple tool to create MBR partitions
......................................................................
tools/mbrtool: A simple tool to create MBR partitions
Change-Id: I0f04b257ad49d07c03d630df47c4891c1fd7a954
---
M src/tools/Jamfile
A src/tools/mbrtool/Jamfile
A src/tools/mbrtool/mbrtool.cpp
3 files changed, 223 insertions(+), 0 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/70/3570/1
diff --git a/src/tools/Jamfile b/src/tools/Jamfile
index 341bbaf..4005c1b 100644
--- a/src/tools/Jamfile
+++ b/src/tools/Jamfile
@@ -106,6 +106,7 @@
SubInclude HAIKU_TOP src tools keymap ;
SubInclude HAIKU_TOP src tools locale ;
SubInclude HAIKU_TOP src tools makebootable ;
+SubInclude HAIKU_TOP src tools mbrtool ;
SubInclude HAIKU_TOP src tools opd_to_package_info ;
SubInclude HAIKU_TOP src tools package ;
SubInclude HAIKU_TOP src tools package_repo ;
diff --git a/src/tools/mbrtool/Jamfile b/src/tools/mbrtool/Jamfile
new file mode 100644
index 0000000..c3eb8c6
--- /dev/null
+++ b/src/tools/mbrtool/Jamfile
@@ -0,0 +1,3 @@
+SubDir HAIKU_TOP src tools mbrtool ;
+
+BuildPlatformMain <build>mbrtool : mbrtool.cpp : $(HOST_LIBSUPC++) ;
diff --git a/src/tools/mbrtool/mbrtool.cpp b/src/tools/mbrtool/mbrtool.cpp
new file mode 100644
index 0000000..495352f
--- /dev/null
+++ b/src/tools/mbrtool/mbrtool.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2020-2021 Haiku, Inc. All rights reserved.
+ * All rights reserved. Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
+ */
+
+
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#define EXIT_FAILURE 1
+
+
+//#define DEBUG_MBRTOOL
+#ifdef DEBUG_MBRTOOL
+# define TRACE(x...) printf("mbrtool: " x)
+#else
+# define TRACE(x...) ;
+#endif
+
+#define INFO(x...) printf("mbrtool: " x)
+
+
+// Disk sector size, 512 assumed!
+static const size_t kSectorSize = 512;
+// Gets input to KiB
+static const float kSizeMultipler = 1024 / kSectorSize;
+
+
+static void
+print_usage(bool error)
+{
+ printf("\n");
+ printf("usage: mbrtool (options) <diskImage> <id> <type> <start>
<length>\n");
+ printf(" <diskImage> Disk image to operate on\n");
+ printf(" <id> Partition ID (0-3)\n");
+ printf(" <type> Partition type id (hex)\n");
+ printf(" <start> Partition start offset (KiB)\n");
+ printf(" <length> Partition length (KiB)\n\n");
+ printf(" Options:\n");
+ printf(" -a, --active Partition boot flag\n");
+ printf("\nWarning: This tool requires precision!\n");
+ printf(" Inputs are only lightly validated!\n\n");
+ exit(error ? EXIT_FAILURE : 0);
+}
+
+
+static void
+checkError(bool failed, const char *message)
+{
+ if (!failed)
+ return;
+
+ if (errno != 0)
+ INFO("Error: %s: %s\n", message, strerror(errno));
+ else
+ INFO("Error: %s\n", message);
+
+ exit(1);
+}
+
+
+static ssize_t
+mbrWipe(int handle)
+{
+ // Blow away MBR while avoiding bootloader
+ uint8_t emptyMBR[72] = {};
+ // Disk Signature
+ emptyMBR[0] = 0x82;
+ emptyMBR[1] = 0xD4;
+ emptyMBR[2] = 0xBA;
+ emptyMBR[3] = 0x7D;
+ // End of MBR marker
+ emptyMBR[70] = 0x55;
+ emptyMBR[71] = 0xAA;
+ return pwrite(handle, emptyMBR, 72, 0x1B8);
+}
+
+
+static bool
+mbrValid(int handle)
+{
+ // TODO: this is a really basic check and ignores invalid
+ // partition table entries
+ uint8_t mbrBytes[72] = {};
+ ssize_t read = pread(handle, mbrBytes, 72, 0x1B8);
+ checkError(read < 0, "Validating MBR");
+ return (mbrBytes[0] == 0x82 && mbrBytes[1] == 0xD4
+ && mbrBytes[2] == 0xBA && mbrBytes[3] == 0x7D
+ && mbrBytes[70] == 0x55 && mbrBytes[71] == 0xAA);
+}
+
+
+static void
+createPartition(int handle, int index, bool active, uint8_t type,
+ uint32_t offset, uint32_t size)
+{
+ uint8_t bootable = active ? 0x80 : 0x0;
+ uint8_t partition[16] = {
+ bootable, // bootable
+ 0xff, 0xff, 0xff, // CHS first block (default to LBA)
+ type, // partition type
+ 0xff, 0xff, 0xff, // CHS last block (default to LBA)
+ 0x00, 0x00, 0x00, 0x00, // imageOffset in blocks (written below)
+ 0x00, 0x00, 0x00, 0x00 // imageSize in blocks (written below)
+ };
+
+ // fill in LBA values
+ uint32_t partitionOffset = (uint32_t)(offset / kSectorSize);
+ ((uint32_t *)partition)[2] = partitionOffset;
+ ((uint32_t *)partition)[3] = (uint32_t)(size / kSectorSize);
+
+ TRACE("%s: #%d %c bytes: %u-%u, sectors: %u-%u\n", __func__, index,
+ active ? 'b' : '-', offset, offset + size, partitionOffset,
+ partitionOffset + uint32_t(size / kSectorSize));
+
+ ssize_t written = pwrite(handle, partition, 16, 512 - 2 - 16 * (4 -
index));
+ checkError(written != 16, "failed to write partition entry");
+
+ if (active) {
+ // make it bootable
+ written = pwrite(handle, &partitionOffset, 4, offset + 512 - 2
- 4);
+ checkError(written != 4, "failed to make image bootable");
+ }
+ return;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ const char *imageFile = NULL;
+
+ int partType = -1;
+ int partIndex = -1;
+ int32_t partStartOffset = -1;
+ int32_t partLength = -1;
+ bool partBootable = false;
+
+ while (1) {
+ int c;
+ static struct option long_options[] = {
+ {"active", no_argument, 0, 'a'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ opterr = 1; /* don't print errors */
+ c = getopt_long(argc, argv, "+ha", long_options, NULL);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 's':
+ print_usage(false);
+ break;
+ case 'a':
+ partBootable = true;
+ break;
+ default:
+ print_usage(true);
+ }
+ }
+
+ if ((argc - optind) != 5)
+ print_usage(true);
+
+ for (int index = optind; index < argc; index++) {
+ if (imageFile == NULL)
+ imageFile = argv[index];
+ else if (partIndex < 0)
+ partIndex = atoi(argv[index]);
+ else if (partType < 0)
+ partType = (int)strtol(argv[index], NULL, 0);
+ else if (partStartOffset < 0 ) {
+ partStartOffset = atoi(argv[index])
+ * (kSectorSize * kSizeMultipler);
+ } else if (partLength < 0) {
+ partLength = atoi(argv[index])
+ * (kSectorSize * kSizeMultipler);
+ }
+ }
+
+ checkError(partIndex < 0 || partIndex > 3,
+ "Incorrect Partition Index!");
+ checkError(partType < 0, "Incorrect Partition Type!");
+
+ int imageFileHandle = open(imageFile, O_RDWR);
+ checkError(imageFileHandle < 0, "failed to open disk image file");
+
+ struct stat stat;
+ int result = fstat(imageFileHandle, &stat);
+ checkError(result != 0, "failed to stat image file");
+ off_t imageSize = stat.st_size;
+
+ if (!mbrValid(imageFileHandle)) {
+ INFO("MBR of image is invalid, creating a fresh one.\n");
+ mbrWipe(imageFileHandle);
+ }
+
+ // Just a warning. This is technically valid since MBR partition
+ // definitions are purely within the first 512 bytes
+ if (partStartOffset + partLength > imageSize * 1024)
+ INFO("Warning: Partition extends beyond end of file!\n");
+
+ createPartition(imageFileHandle, partIndex, partBootable, partType,
+ partStartOffset, partLength);
+ return 0;
+}
--
To view, visit https://review.haiku-os.org/c/haiku/+/3570
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: I0f04b257ad49d07c03d630df47c4891c1fd7a954
Gerrit-Change-Number: 3570
Gerrit-PatchSet: 1
Gerrit-Owner: Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Gerrit-MessageType: newchange