Activation: support updating PSU from stored image

The previous code assume the image to update is from IMG_DIR.
Now it needs to update PSU from pre-built or stored images.

This commit adds the support, by constructing the systemd unit based on
Activation's Path property instead of IMG_DIR.

Tested: Verify on Witherspoon that it is able to activate a stored
        image.

Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: I0936bb921b22c7f67aee9689e3695e6b21703a29
diff --git a/src/activation.cpp b/src/activation.cpp
index 680cdd9..efff61b 100644
--- a/src/activation.cpp
+++ b/src/activation.cpp
@@ -27,32 +27,6 @@
 using sdbusplus::exception::SdBusError;
 using SoftwareActivation = softwareServer::Activation;
 
-namespace internal
-{
-/** Construct the systemd service name */
-std::string getUpdateService(const std::string& psuInventoryPath,
-                             const std::string& versionId)
-{
-    // TODO: get image path from the related version
-    // because it could be in either IMG_DIR, or IMG_DIR_PERSIST, or
-    // IMG_DIR_BUILTIN
-    fs::path imagePath(IMG_DIR);
-    imagePath /= versionId;
-
-    // The systemd unit shall be escaped
-    std::string args = psuInventoryPath;
-    args += "\\x20";
-    args += imagePath;
-    std::replace(args.begin(), args.end(), '/', '-');
-
-    std::string service = PSU_UPDATE_SERVICE;
-    auto p = service.find('@');
-    assert(p != std::string::npos);
-    service.insert(p + 1, args);
-    return service;
-}
-
-} // namespace internal
 auto Activation::activation(Activations value) -> Activations
 {
     if (value == Status::Activating)
@@ -109,7 +83,7 @@
 bool Activation::doUpdate(const std::string& psuInventoryPath)
 {
     currentUpdatingPsu = psuInventoryPath;
-    psuUpdateUnit = internal::getUpdateService(currentUpdatingPsu, versionId);
+    psuUpdateUnit = getUpdateService(currentUpdatingPsu);
     try
     {
         auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
@@ -256,7 +230,8 @@
     }
     if (versionService.empty())
     {
-        log<level::ERR>("Error finding version service");
+        // When updating a stored image, there is no version object created by
+        // "xyz.openbmc_project.Software.Version" service, so skip it.
         return;
     }
 
@@ -301,8 +276,13 @@
 {
     // Store image in persistent dir separated by model
     // and only store the latest one by removing old ones
-    auto src = fs::path(IMG_DIR) / versionId;
+    auto src = path();
     auto dst = fs::path(IMG_DIR_PERSIST) / model;
+    if (src == dst)
+    {
+        // This happens when updating an stored image, no need to store it again
+        return;
+    }
     try
     {
         fs::remove_all(dst);
@@ -318,6 +298,23 @@
     }
 }
 
+std::string Activation::getUpdateService(const std::string& psuInventoryPath)
+{
+    fs::path imagePath(path());
+
+    // The systemd unit shall be escaped
+    std::string args = psuInventoryPath;
+    args += "\\x20";
+    args += imagePath;
+    std::replace(args.begin(), args.end(), '/', '-');
+
+    std::string service = PSU_UPDATE_SERVICE;
+    auto p = service.find('@');
+    assert(p != std::string::npos);
+    service.insert(p + 1, args);
+    return service;
+}
+
 } // namespace updater
 } // namespace software
 } // namespace phosphor