add handler logic to handle SysCpldVersion

Add handler logic to handler for SysCpldVersion such that it splits the
true IPMI processing from the business logic.

Tested: Only ran unit-tests (added new ones).
Change-Id: I09d95d8be8fbe75648b3332af898336b00074c2f
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/cpld.cpp b/cpld.cpp
index 32c6f37..c3689cd 100644
--- a/cpld.cpp
+++ b/cpld.cpp
@@ -16,18 +16,16 @@
 
 #include "cpld.hpp"
 
+#include "errors.hpp"
+#include "handler.hpp"
 #include "main.hpp"
 
 #include <cstring>
-#include <filesystem>
-#include <fstream>
-#include <sstream>
 
 namespace google
 {
 namespace ipmi
 {
-namespace fs = std::filesystem;
 
 struct CpldRequest
 {
@@ -48,7 +46,7 @@
 // Handle reading the cpld version from the tmpfs.
 //
 ipmi_ret_t CpldVersion(const uint8_t* reqBuf, uint8_t* replyBuf,
-                       size_t* dataLen)
+                       size_t* dataLen, const HandlerInterface* handler)
 {
     struct CpldRequest request;
 
@@ -68,59 +66,27 @@
     // letter, because it does that.
     std::memcpy(&request, &reqBuf[0], sizeof(request));
 
-    std::ostringstream opath;
-    opath << "/run/cpld" << static_cast<unsigned int>(request.id) << ".version";
-    // Check for file
-
-    std::error_code ec;
-    if (!fs::exists(opath.str(), ec))
-    {
-        std::fprintf(stderr, "Path: '%s' doesn't exist.\n",
-                     opath.str().c_str());
-        return IPMI_CC_INVALID_FIELD_REQUEST;
-    }
-    // We're uninterested in the state of ec.
-
-    // If file exists, read.
-    std::ifstream ifs;
-    ifs.exceptions(std::ifstream::failbit);
-    std::string value;
     try
     {
-        ifs.open(opath.str());
-        ifs >> value;
+        auto values =
+            handler->getCpldVersion(static_cast<unsigned int>(request.id));
+
+        // Truncate if the version is too high (documented).
+        struct CpldReply reply;
+        reply.subcommand = SysCpldVersion;
+        reply.major = std::get<0>(values);
+        reply.minor = std::get<1>(values);
+        reply.point = std::get<2>(values);
+        reply.subpoint = std::get<3>(values);
+
+        std::memcpy(&replyBuf[0], &reply, sizeof(reply));
+        (*dataLen) = sizeof(reply);
+        return IPMI_CC_OK;
     }
-    catch (std::ios_base::failure& fail)
+    catch (const IpmiException& e)
     {
-        return IPMI_CC_UNSPECIFIED_ERROR;
+        return e.getIpmiError();
     }
-
-    // If value parses as expected, return version.
-    int major = 0;
-    int minor = 0;
-    int point = 0;
-    int subpoint = 0;
-
-    int num_fields =
-        sscanf(value.c_str(), "%d.%d.%d.%d", &major, &minor, &point, &subpoint);
-    if (num_fields == 0)
-    {
-        std::fprintf(stderr, "Invalid version.\n");
-        return IPMI_CC_UNSPECIFIED_ERROR;
-    }
-
-    // Truncate if the version is too high (documented).
-    struct CpldReply reply;
-    reply.subcommand = SysCpldVersion;
-    reply.major = static_cast<uint8_t>(major);
-    reply.minor = static_cast<uint8_t>(minor);
-    reply.point = static_cast<uint8_t>(point);
-    reply.subpoint = static_cast<uint8_t>(subpoint);
-
-    std::memcpy(&replyBuf[0], &reply, sizeof(reply));
-    (*dataLen) = sizeof(reply);
-
-    return IPMI_CC_OK;
 }
 
 } // namespace ipmi