mmc: Add update-bios-attr-table subcommand

Add the update-bios-attr-table subcommand to update the bios attribute
table with the host firmware well-known names based on system type. The
system type is provided by Entity Manager, and this new subcommand uses
some of the existing infrastructure that the process-host-firmware
subcommand has to determine the system type.

Add a new service file to run this new subcommand so that it can block
waiting for the entity manager interface to appear on D-Bus.

Subsequent commands will add parsing the JSON file to build the bios
attribute string and set the bios attribute property.

Change-Id: Iacee975e273bae562d2d42cd8b642b9d0744a121
Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
diff --git a/functions.cpp b/functions.cpp
index cad510a..3658270 100644
--- a/functions.cpp
+++ b/functions.cpp
@@ -191,6 +191,13 @@
 }
 
 /**
+ * @brief Set the bios attribute table with details of the host firmware data
+ * for this system.
+ */
+void setBiosAttr()
+{}
+
+/**
  * @brief Make callbacks on
  * xyz.openbmc_project.Configuration.IBMCompatibleSystem instances.
  *
@@ -304,6 +311,31 @@
 }
 
 /**
+ * @brief Determine system support for updating the bios attribute table.
+ *
+ * Using the provided extensionMap and
+ * xyz.openbmc_project.Configuration.IBMCompatibleSystem, determine if the bios
+ * attribute table needs to be updated.
+ *
+ * @param[in] extensionMap a map of
+ * xyz.openbmc_project.Configuration.IBMCompatibleSystem to host firmware blob
+ * file extensions.
+ * @param[in] ibmCompatibleSystem The names property of an instance of
+ * xyz.openbmc_project.Configuration.IBMCompatibleSystem
+ */
+void maybeSetBiosAttr(
+    const std::map<std::string, std::vector<std::string>>& extensionMap,
+    const std::vector<std::string>& ibmCompatibleSystem)
+{
+    std::vector<std::string> extensions;
+    if (getExtensionsForIbmCompatibleSystem(extensionMap, ibmCompatibleSystem,
+                                            extensions))
+    {
+        setBiosAttr();
+    }
+}
+
+/**
  * @brief process host firmware
  *
  * Allocate a callback context and register for DBus.ObjectManager Interfaces
@@ -431,5 +463,59 @@
     // ownership of the match callback to the caller.
     return interfacesAddedMatch;
 }
+
+/**
+ * @brief Update the Bios Attribute Table
+ *
+ * If an instance of xyz.openbmc_project.Configuration.IBMCompatibleSystem is
+ * found, update the Bios Attribute Table with the appropriate host firmware
+ * data.
+ *
+ * @param[in] bus - D-Bus client connection.
+ * @param[in] extensionMap - Map of IBMCompatibleSystem names and host firmware
+ *                           file extensions.
+ * @param[in] loop - Program event loop.
+ * @return nullptr
+ */
+std::shared_ptr<void> updateBiosAttrTable(
+    sdbusplus::bus::bus& bus,
+    std::map<std::string, std::vector<std::string>> extensionMap,
+    sdeventplus::Event& loop)
+{
+    auto pExtensionMap =
+        std::make_shared<decltype(extensionMap)>(std::move(extensionMap));
+
+    auto getManagedObjects = bus.new_method_call(
+        "xyz.openbmc_project.EntityManager", "/",
+        "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+    std::map<std::string,
+             std::map<std::string, std::variant<std::vector<std::string>>>>
+        interfacesAndProperties;
+    std::map<sdbusplus::message::object_path, decltype(interfacesAndProperties)>
+        objects;
+    try
+    {
+        auto reply = bus.call(getManagedObjects);
+        reply.read(objects);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {}
+
+    auto maybeSetAttrWithArgsBound = std::bind(
+        maybeSetBiosAttr, std::cref(*pExtensionMap), std::placeholders::_1);
+
+    for (const auto& pair : objects)
+    {
+        std::tie(std::ignore, interfacesAndProperties) = pair;
+        if (maybeCall(interfacesAndProperties, maybeSetAttrWithArgsBound))
+        {
+            break;
+        }
+    }
+
+    loop.exit(0);
+    return nullptr;
+}
+
 } // namespace process_hostfirmware
 } // namespace functions
diff --git a/functions.hpp b/functions.hpp
index f7511aa..b364393 100644
--- a/functions.hpp
+++ b/functions.hpp
@@ -45,5 +45,9 @@
 std::shared_ptr<void> processHostFirmware(
     sdbusplus::bus::bus&, std::map<std::string, std::vector<std::string>>,
     std::filesystem::path, ErrorCallbackType, sdeventplus::Event&);
+std::shared_ptr<void>
+    updateBiosAttrTable(sdbusplus::bus::bus&,
+                        std::map<std::string, std::vector<std::string>>,
+                        sdeventplus::Event&);
 } // namespace process_hostfirmware
 } // namespace functions
diff --git a/item_updater_main.cpp b/item_updater_main.cpp
index c563cbe..21164e9 100644
--- a/item_updater_main.cpp
+++ b/item_updater_main.cpp
@@ -60,32 +60,42 @@
 
     CLI::App app{"OpenPOWER host firmware manager"};
 
+    using namespace std::string_literals;
+    std::map<std::string, std::vector<std::string>> extensionMap{{
+        {"ibm,everest"s, {".EVEREST_XML"s, ".P10"s}},
+        {"ibm,rainier-2u"s, {".RAINIER_2U_XML"s, ".P10"s}},
+        {"ibm,rainier-4u"s, {".RAINIER_4U_XML"s, ".P10"s}},
+        {"ibm,rainier-1s4u"s, {".RAINIER_4U_XML"s, ".P10"s}},
+    }};
+
     // subcommandContext allows program subcommand callbacks to add loop event
     // callbacks (e.g. reception of a dbus signal) and then return to main,
     // without the loop event callback being destroyed until the loop event
     // callback has a chance to run and instruct the loop to exit.
-    std::shared_ptr<void> subcommandContext;
+    std::vector<std::shared_ptr<void>> subcommandContext;
     static_cast<void>(
         app.add_subcommand("process-host-firmware",
                            "Point the host firmware at its data.")
-            ->callback([&bus, &loop, &subcommandContext]() {
-                using namespace std::string_literals;
-                std::map<std::string, std::vector<std::string>> extensionMap{{
-                    {"ibm,everest"s, {".EVEREST_XML"s, ".P10"s}},
-                    {"ibm,rainier-2u"s, {".RAINIER_2U_XML"s, ".P10"s}},
-                    {"ibm,rainier-4u"s, {".RAINIER_4U_XML"s, ".P10"s}},
-                    {"ibm,rainier-1s4u"s, {".RAINIER_4U_XML"s, ".P10"s}},
-                }};
+            ->callback([&bus, &loop, &subcommandContext, extensionMap]() {
                 auto hostFirmwareDirectory = "/media/hostfw/running"s;
                 auto logCallback = [](const auto& path, auto& ec) {
                     std::cerr << path << ": " << ec.message() << "\n";
                 };
-                subcommandContext =
+                subcommandContext.push_back(
                     functions::process_hostfirmware::processHostFirmware(
-                        bus, std::move(extensionMap),
-                        std::move(hostFirmwareDirectory),
-                        std::move(logCallback), loop);
+                        bus, extensionMap, std::move(hostFirmwareDirectory),
+                        std::move(logCallback), loop));
             }));
+    static_cast<void>(
+        app.add_subcommand("update-bios-attr-table",
+                           "Update the bios attribute table with the host "
+                           "firmware data details.")
+            ->callback([&bus, &loop, &subcommandContext, extensionMap]() {
+                subcommandContext.push_back(
+                    functions::process_hostfirmware::updateBiosAttrTable(
+                        bus, extensionMap, loop));
+            }));
+
     CLI11_PARSE(app, argc, argv);
 
     if (app.get_subcommands().size() == 0)
diff --git a/meson.build b/meson.build
index 1b654b2..aa2ce5a 100644
--- a/meson.build
+++ b/meson.build
@@ -125,6 +125,7 @@
         'mmc/obmc-flash-bios-init.service',
         'mmc/obmc-flash-bios-patch.service',
         'mmc/openpower-process-host-firmware.service',
+        'mmc/openpower-update-bios-attr-table.service',
     ]
 endif
 
diff --git a/mmc/openpower-update-bios-attr-table.service b/mmc/openpower-update-bios-attr-table.service
new file mode 100644
index 0000000..4509389
--- /dev/null
+++ b/mmc/openpower-update-bios-attr-table.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Update BIOS attr table with host firmware well-known names
+After=org.open_power.Software.Host.Updater.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=/usr/bin/openpower-update-manager update-bios-attr-table
+
+[Install]
+WantedBy=org.open_power.Software.Host.Updater.service