Refactor MDRV2 class to allow more than one

Refactored the main MDRV2 class to allow more than one object of this
class to exist at the same time. All hardcoded paths have been made
parameters to the constructor, so that they can be varied at runtime as
needed, to avoid overlap.

Also did some necessary internal cleanups to facilitate this.

Tested: Created multiple copies of the MDRV2 object at the same time,
it worked, all appeared on D-Bus, under distinct object paths and
inventory paths. Destructed the MDRV2 object, it disappeared from
D-Bus, constructed it again, it came back.

https://gist.github.com/Krellan/6930bc2ed1ac16b93afcc3a12c02e545

Change-Id: Icd1ebf50086b526cf0cff149eb8ddc59da78f0a9
Signed-off-by: Josh Lehan <krellan@google.com>
diff --git a/include/mdrv2.hpp b/include/mdrv2.hpp
index c2cf038..4e431f4 100644
--- a/include/mdrv2.hpp
+++ b/include/mdrv2.hpp
@@ -36,29 +36,46 @@
 #include <sdbusplus/timer.hpp>
 #include <xyz/openbmc_project/Smbios/MDR_V2/server.hpp>
 
-sdbusplus::asio::object_server& getObjectServer(void);
+#include <filesystem>
+#include <memory>
 
-using RecordVariant =
-    std::variant<std::string, uint64_t, uint32_t, uint16_t, uint8_t>;
 namespace phosphor
 {
 namespace smbios
 {
 
-static constexpr const char* mdrV2Path = "/xyz/openbmc_project/Smbios/MDR_V2";
-static constexpr const char* smbiosPath = "/xyz/openbmc_project/Smbios";
+using RecordVariant =
+    std::variant<std::string, uint64_t, uint32_t, uint16_t, uint8_t>;
+
+static constexpr const char* defaultObjectPath =
+    "/xyz/openbmc_project/Smbios/MDR_V2";
 static constexpr const char* smbiosInterfaceName =
     "xyz.openbmc_project.Smbios.GetRecordType";
 static constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
 static constexpr const char* mapperPath = "/xyz/openbmc_project/object_mapper";
 static constexpr const char* mapperInterface =
     "xyz.openbmc_project.ObjectMapper";
-static constexpr const char* systemInterfacePath =
+static constexpr const char* defaultInventoryPath =
     "/xyz/openbmc_project/inventory/system";
 static constexpr const char* systemInterface =
     "xyz.openbmc_project.Inventory.Item.System";
 constexpr const int limitEntryLen = 0xff;
 
+// Avoid putting multiple interfaces with same name on same object
+static std::string placeGetRecordType(const std::string& objectPath)
+{
+    if (objectPath != defaultObjectPath)
+    {
+        // Place GetRecordType interface on object itself, not parent
+        return objectPath;
+    }
+
+    std::filesystem::path path(objectPath);
+
+    // As there is only one default, safe to place it on the common parent
+    return path.parent_path().string();
+}
+
 class MDRV2 :
     sdbusplus::server::object_t<
         sdbusplus::server::xyz::openbmc_project::smbios::MDRV2>
@@ -69,15 +86,38 @@
     MDRV2& operator=(const MDRV2&) = delete;
     MDRV2(MDRV2&&) = delete;
     MDRV2& operator=(MDRV2&&) = delete;
-    ~MDRV2() = default;
 
-    MDRV2(sdbusplus::bus_t& bus, const char* path,
-          boost::asio::io_context& io) :
-        sdbusplus::server::object_t<
-            sdbusplus::server::xyz::openbmc_project::smbios::MDRV2>(bus, path),
-        timer(io), bus(bus), smbiosInterface(getObjectServer().add_interface(
-                                 smbiosPath, smbiosInterfaceName))
+    virtual ~MDRV2()
     {
+        if (smbiosInterface)
+        {
+            if (objServer)
+            {
+                // Must manually undo add_interface()
+                objServer->remove_interface(smbiosInterface);
+            }
+        }
+    }
+
+    MDRV2(std::shared_ptr<boost::asio::io_context> io,
+          std::shared_ptr<sdbusplus::asio::connection> conn,
+          std::shared_ptr<sdbusplus::asio::object_server> obj,
+          std::string filePath, std::string objectPath,
+          std::string inventoryPath) :
+        sdbusplus::server::object_t<
+            sdbusplus::server::xyz::openbmc_project::smbios::MDRV2>(
+            *conn, objectPath.c_str()),
+        timer(*io), bus(conn), objServer(std::move(obj)),
+        smbiosInterface(objServer->add_interface(placeGetRecordType(objectPath),
+                                                 smbiosInterfaceName)),
+        smbiosFilePath(std::move(filePath)),
+        smbiosObjectPath(std::move(objectPath)),
+        smbiosInventoryPath(std::move(inventoryPath))
+    {
+        lg2::info("SMBIOS data file path: {F}", "F", smbiosFilePath);
+        lg2::info("SMBIOS control object: {O}", "O", smbiosObjectPath);
+        lg2::info("SMBIOS inventory path: {I}", "I", smbiosInventoryPath);
+
         smbiosDir.agentVersion = smbiosAgentVersion;
         smbiosDir.dirVersion = smbiosDirVersion;
         smbiosDir.dirEntries = 1;
@@ -127,7 +167,8 @@
   private:
     boost::asio::steady_timer timer;
 
-    sdbusplus::bus_t& bus;
+    std::shared_ptr<sdbusplus::asio::connection> bus;
+    std::shared_ptr<sdbusplus::asio::object_server> objServer;
 
     Mdr2DirStruct smbiosDir;
 
@@ -151,6 +192,11 @@
     std::vector<std::unique_ptr<Pcie>> pcies;
     std::unique_ptr<System> system;
     std::shared_ptr<sdbusplus::asio::dbus_interface> smbiosInterface;
+
+    std::string smbiosFilePath;
+    std::string smbiosObjectPath;
+    std::string smbiosInventoryPath;
+    std::unique_ptr<sdbusplus::bus::match_t> motherboardConfigMatch;
 };
 
 } // namespace smbios