[haiku-commits] Change in haiku[master]: tools/mbrtool: A simple tool to create MBR partitions

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 30 Dec 2020 18:31:04 +0000

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

Other related posts:

  • » [haiku-commits] Change in haiku[master]: tools/mbrtool: A simple tool to create MBR partitions - Gerrit