Fix IPMI firmware update programming failure

The IPMI Firmware Update sequence fails on some systems. The update
process receives the new firmware image data in the /tmp file
system. During the final update phase the image is copied into the
/tmp/images subdirectory. If /tmp and /tmp/images are not part of the
same filesystem the std::filesystem::rename() function fails.

This commit changes the update process. The rename() is still
attempted. In the event the rename() fails, a copy() operation is
performed in the belief the destination is on a separate filesystem.

Tested:
Confirmed this change works on systems with a common /tmp filesystem.
Confirmed this change works on systems with the source file and the
destination file on different filesystems.

Change-Id: I5e3da6c0f453941ea54cb829d2bcaeadda0db438
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
diff --git a/src/firmware-update.cpp b/src/firmware-update.cpp
index 82364d3..f8672fd 100644
--- a/src/firmware-update.cpp
+++ b/src/firmware-update.cpp
@@ -650,9 +650,26 @@
     // check if it is ready for activation)
     static std::unique_ptr<sdbusplus::bus::match_t> fwUpdateMatchSignal;
     postTransferCompleteHandler(fwUpdateMatchSignal);
-    std::filesystem::rename(
-        uri, "/tmp/images/" +
-                 boost::uuids::to_string(boost::uuids::random_generator()()));
+    std::string randomFname =
+        "/tmp/images/" +
+        boost::uuids::to_string(boost::uuids::random_generator()());
+    std::error_code fsError{};
+    std::filesystem::rename(uri, randomFname, fsError);
+    if (fsError)
+    {
+        // The source and destination may not be in the same
+        // filesystem.
+        std::filesystem::copy(uri, randomFname, fsError);
+        if (fsError)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "Unable to move/copy image to destination directory.",
+                phosphor::logging::entry("ERROR=%s",
+                                         fsError.message().c_str()));
+            return false;
+        }
+        std::filesystem::remove(uri);
+    }
     return true;
 }