Create objects for running PSUs

On service startup, create activation and version objects for running
PSUs, and set related active, functional associations.

If multiple PSUs are running with the same software version, they share
the same DBus object, and the object will be associated to multiple PSU
inventories.

Tested: Verify the software objects are created on Witherspoon, and the
        active, functional associations are created.

Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: Ia8372aba8299818baccfdf37e98fdbc99f747b7c
diff --git a/src/utils.cpp b/src/utils.cpp
index deb5eee..f80776e 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -2,6 +2,8 @@
 
 #include "utils.hpp"
 
+#include <openssl/sha.h>
+
 #include <fstream>
 
 namespace utils
@@ -28,4 +30,62 @@
     return paths;
 }
 
+std::string getService(sdbusplus::bus::bus& bus, const char* path,
+                       const char* interface)
+{
+    auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
+                                      MAPPER_INTERFACE, "GetObject");
+
+    mapper.append(path, std::vector<std::string>({interface}));
+    try
+    {
+        auto mapperResponseMsg = bus.call(mapper);
+
+        std::vector<std::pair<std::string, std::vector<std::string>>>
+            mapperResponse;
+        mapperResponseMsg.read(mapperResponse);
+        if (mapperResponse.empty())
+        {
+            log<level::ERR>("Error reading mapper response");
+            throw std::runtime_error("Error reading mapper response");
+        }
+        if (mapperResponse.size() < 1)
+        {
+            return "";
+        }
+        return mapperResponse[0].first;
+    }
+    catch (const sdbusplus::exception::SdBusError& ex)
+    {
+        log<level::ERR>("Mapper call failed", entry("METHOD=%d", "GetObject"),
+                        entry("PATH=%s", path),
+                        entry("INTERFACE=%s", interface));
+        throw std::runtime_error("Mapper call failed");
+    }
+}
+
+std::string getVersionId(const std::string& version)
+{
+    if (version.empty())
+    {
+        log<level::ERR>("Error version is empty");
+        return {};
+    }
+
+    unsigned char digest[SHA512_DIGEST_LENGTH];
+    SHA512_CTX ctx;
+    SHA512_Init(&ctx);
+    SHA512_Update(&ctx, version.c_str(), strlen(version.c_str()));
+    SHA512_Final(digest, &ctx);
+    char mdString[SHA512_DIGEST_LENGTH * 2 + 1];
+    for (int i = 0; i < SHA512_DIGEST_LENGTH; i++)
+    {
+        snprintf(&mdString[i * 2], 3, "%02x", (unsigned int)digest[i]);
+    }
+
+    // Only need 8 hex digits.
+    std::string hexId = std::string(mdString);
+    return (hexId.substr(0, 8));
+}
+
 } // namespace utils