Create BMC functional Association

Create a functional association for the "running" BMC image.

Change-Id: Id254df06b4361b418e765cc5222b1e1ee0d348a3
Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
diff --git a/configure.ac b/configure.ac
index 408fc29..d966930 100755
--- a/configure.ac
+++ b/configure.ac
@@ -58,6 +58,9 @@
 AC_DEFINE(ACTIVE_FWD_ASSOCIATION, "active", [The name of the active's forward association.])
 AC_DEFINE(ACTIVE_REV_ASSOCIATION, "software_version", [The name of the active's reverse association.])
 
+AC_DEFINE(FUNCTIONAL_FWD_ASSOCIATION, "functional", [The name of the functional forward association.])
+AC_DEFINE(FUNCTIONAL_REV_ASSOCIATION, "software_version", [The functional reverse association.])
+
 AC_ARG_VAR(VERSION_BUSNAME, [The Dbus busname to own])
 AS_IF([test "x$VERSION_BUSNAME" == "x"], [VERSION_BUSNAME="xyz.openbmc_project.Software.Version"])
 AC_DEFINE_UNQUOTED([VERSION_BUSNAME], ["$VERSION_BUSNAME"], [The DBus busname to own])
diff --git a/item_updater.cpp b/item_updater.cpp
index 6b4ff5e..dda7a8d 100644
--- a/item_updater.cpp
+++ b/item_updater.cpp
@@ -143,6 +143,10 @@
 
 void ItemUpdater::processBMCImage()
 {
+    using VersionClass = phosphor::software::manager::Version;
+    // Read os-release from /etc/ to get the functional BMC version
+    auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE);
+
     // Read os-release from folders under /media/ to get
     // BMC Software Versions.
     for(const auto& iter : fs::directory_iterator(MEDIA_DIR))
@@ -161,9 +165,7 @@
                                 entry("FileName=%s", osRelease.string()));
                 activationState = server::Activation::Activations::Invalid;
             }
-            auto version =
-                    phosphor::software::manager::Version::
-                            getBMCVersion(osRelease);
+            auto version = VersionClass::getBMCVersion(osRelease);
             if (version.empty())
             {
                 log<level::ERR>("Failed to read version from osRelease",
@@ -176,6 +178,12 @@
             auto purpose = server::Version::VersionPurpose::BMC;
             auto path = fs::path(SOFTWARE_OBJPATH) / id;
 
+            // Create functional association if this is the functional version
+            if (version.compare(functionalVersion) == 0)
+            {
+                createFunctionalAssociation(path);
+            }
+
             AssociationList associations = {};
 
             if (activationState == server::Activation::Activations::Active)
@@ -465,11 +473,22 @@
     associations(assocs);
 }
 
+void ItemUpdater::createFunctionalAssociation(const std::string& path)
+{
+    assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
+                                        FUNCTIONAL_REV_ASSOCIATION,
+                                        path));
+    associations(assocs);
+}
+
 void ItemUpdater::removeActiveAssociation(std::string path)
 {
     for (auto iter = assocs.begin(); iter != assocs.end();)
     {
-        if ((std::get<2>(*iter)).compare(path) == 0)
+        // Since there could be multiple associations to the same path,
+        // only remove ones that have an active forward association.
+        if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 &&
+            (std::get<2>(*iter)).compare(path) == 0)
         {
             iter = assocs.erase(iter);
             associations(assocs);
diff --git a/item_updater.hpp b/item_updater.hpp
index 3489a47..09d0638 100644
--- a/item_updater.hpp
+++ b/item_updater.hpp
@@ -141,6 +141,13 @@
         /** @brief Restores field mode status on reboot. */
         void restoreFieldModeStatus();
 
+        /** @brief Creates a functional association to the
+         *  "running" BMC software image
+         *
+         * @param[in]  path - The path to create the association to.
+         */
+        void createFunctionalAssociation(const std::string& path);
+
         /** @brief Persistent sdbusplus DBus bus connection. */
         sdbusplus::bus::bus& bus;