usb: Copy image file to /tmp/images via USB

Traverse the USB mount directory, and copy the first file with
a `.tar` extension under the directory to the `/tmp/images`
directory.

Tested: Manually call the fs::copy_file app locally, test passed.

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I8e03b9c3305f5e9d9a1535dd176ecd40dbea8903
diff --git a/usb/meson.build b/usb/meson.build
index f0ac2d0..0de8e33 100644
--- a/usb/meson.build
+++ b/usb/meson.build
@@ -9,13 +9,21 @@
 
 source = [
     'usb_manager_main.cpp',
+    'usb_manager.cpp',
     ]
 
+phosphor_logging_dep = dependency(
+    'phosphor-logging',
+    fallback: ['phosphor-logging', 'phosphor_logging_dep'],
+)
+
 executable(
     'phosphor-usb-code-update',
     source,
+    include_directories: ['..'],
     dependencies: [
         CLI11_dep,
+        phosphor_logging_dep,
     ],
     install: true,
     install_dir: get_option('bindir')
diff --git a/usb/usb_manager.cpp b/usb/usb_manager.cpp
new file mode 100644
index 0000000..b002dbd
--- /dev/null
+++ b/usb/usb_manager.cpp
@@ -0,0 +1,50 @@
+#include "config.h"
+
+#include "usb_manager.hpp"
+
+namespace phosphor
+{
+namespace usb
+{
+
+bool USBManager::run()
+{
+    fs::path dir(usbPath);
+    if (!fs::exists(dir))
+    {
+        return false;
+    }
+
+    for (const auto& p : std::filesystem::directory_iterator(dir))
+    {
+        if (p.path().extension() == ".tar")
+        {
+            fs::path dstPath{IMG_UPLOAD_DIR / p.path().filename()};
+            if (fs::exists(dstPath))
+            {
+                lg2::info(
+                    "{DSTPATH} already exists in the /tmp/images directory, exit the upgrade",
+                    "DSTPATH", p.path().filename());
+
+                break;
+            }
+
+            try
+            {
+                return fs::copy_file(fs::absolute(p.path()), dstPath);
+            }
+            catch (const std::exception& e)
+            {
+                lg2::error("Error when copying {SRC} to /tmp/images: {ERROR}",
+                           "SRC", p.path(), "ERROR", e.what());
+            }
+
+            break;
+        }
+    }
+
+    return false;
+}
+
+} // namespace usb
+} // namespace phosphor
\ No newline at end of file
diff --git a/usb/usb_manager.hpp b/usb/usb_manager.hpp
new file mode 100644
index 0000000..f3323a8
--- /dev/null
+++ b/usb/usb_manager.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <phosphor-logging/lg2.hpp>
+
+#include <filesystem>
+
+namespace phosphor
+{
+namespace usb
+{
+namespace fs = std::filesystem;
+
+class USBManager
+{
+  public:
+    ~USBManager() = default;
+    USBManager() = delete;
+    USBManager(const USBManager&) = delete;
+    USBManager(USBManager&&) = default;
+    USBManager& operator=(const USBManager&) = delete;
+    USBManager& operator=(USBManager&&) = default;
+
+    explicit USBManager(const fs::path& path) : usbPath(path)
+    {}
+
+    /** @brief Find the first file with a .tar extension according to the USB
+     *         file path.
+     *
+     *  @return Success or Fail
+     */
+    bool run();
+
+  private:
+    /** The USB path detected. */
+    const fs::path& usbPath;
+};
+
+} // namespace usb
+} // namespace phosphor
diff --git a/usb/usb_manager_main.cpp b/usb/usb_manager_main.cpp
index b5a538d..143125d 100644
--- a/usb/usb_manager_main.cpp
+++ b/usb/usb_manager_main.cpp
@@ -1,14 +1,35 @@
+#include "usb_manager.hpp"
+
 #include <CLI/CLI.hpp>
+#include <phosphor-logging/lg2.hpp>
 
 int main(int argc, char** argv)
 {
+    namespace fs = std::filesystem;
+
     std::string fileName{};
 
     CLI::App app{"Update the firmware of OpenBMC via USB app"};
     app.add_option("-f,--fileName", fileName,
-                   "Get the name of the USB mount folder");
+                   "Get the name of the USB mount folder, eg: sda1, sdb1");
 
     CLI11_PARSE(app, argc, argv);
 
+    if (fileName.empty())
+    {
+        lg2::error("The file name passed in is empty.");
+        return -1;
+    }
+
+    fs::path usbPath = fs::path{"/run/media/usb"} / fileName;
+    phosphor::usb::USBManager manager(usbPath);
+
+    if (!manager.run())
+    {
+        lg2::error("Failed to FW Update via USB, usbPath:{USBPATH}", "USBPATH",
+                   usbPath);
+        return -1;
+    }
+
     return 0;
 }