bm_instance: Create a new handler

This OEM handler will get properties from tmpfs to serve over IPMI.

Tested:
~# cat /run/bm-instance/asset-tag
12345
~# ipmitool raw 0x2e 0x32 0x79 0x2b 0x00 0x17 0x00
 79 2b 00 17 05 31 32 33 34 35
...
...
(Verified this works for all 7 sub commands)

Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: I191b6f4994d91ada49a3332a8e93a3a305561904
diff --git a/handler.cpp b/handler.cpp
index d4a8897..bc6323d 100644
--- a/handler.cpp
+++ b/handler.cpp
@@ -16,6 +16,7 @@
 
 #include "bm_config.h"
 
+#include "bm_instance.hpp"
 #include "bmc_mode_enum.hpp"
 #include "errors.hpp"
 #include "handler_impl.hpp"
@@ -39,6 +40,7 @@
 #include <cstdio>
 #include <filesystem>
 #include <fstream>
+#include <iomanip>
 #include <map>
 #include <sstream>
 #include <string>
@@ -767,5 +769,48 @@
 
     return static_cast<uint16_t>(std::get<double>(value));
 }
+
+std::string Handler::getBMInstanceProperty(uint8_t propertyType) const
+{
+    std::string propertyTypeString;
+    if (auto it = bmInstanceTypeStringMap.find(propertyType);
+        it == bmInstanceTypeStringMap.end())
+    {
+        stdplus::print(stderr, "PropertyType: '{}' is invalid.\n",
+                       propertyType);
+        throw IpmiException(::ipmi::ccInvalidFieldRequest);
+    }
+    else
+    {
+        propertyTypeString = it->second;
+    }
+    std::string opath = std::format("/run/bm-instance/{}", propertyTypeString);
+    // Check for file
+
+    std::error_code ec;
+    // TODO(brandonkim@google.com): Fix this to use stdplus::ManagedFd
+    if (!this->getFs()->exists(opath, ec))
+    {
+        stdplus::print(stderr, "Path: '{}' doesn't exist.\n", opath);
+        throw IpmiException(::ipmi::ccInvalidFieldRequest);
+    }
+
+    // If file exists, read up to 64 bytes (normally shouldn't be more than 32)
+    std::ifstream ifs;
+    ifs.exceptions(std::ifstream::failbit);
+    std::string property;
+    try
+    {
+        ifs.open(opath);
+        ifs >> std::setw(64) >> property;
+    }
+    catch (std::ios_base::failure& fail)
+    {
+        stdplus::print(stderr, "Failed to read: '{}'.\n", opath);
+        throw IpmiException(::ipmi::ccUnspecifiedError);
+    }
+    return property;
+}
+
 } // namespace ipmi
 } // namespace google