BMC Minimum ship Level

This code compares the BMC_MSL defined at compile time,
It will parse the new fw (explicit at MANIFEST file) and use regex to
evaluate it  and compare BMC_MSL against version from MANIFEST.
If newer or equal  it will apply, otherwise it will fail,
preventing activation  operation.

Tested:
 regex-bmc-msl="([a-z]+[0-9]{2})+([0-9]+).([0-9]+).([0-9]+)"
 fw-package="version=fw1010.00-28.4-0-ge611abca21"
 bmc-msl="fw1010.00-27"  proceeds with activation...
 bmc-msl="fw1010.00-29"  returns:

Jul 15 20:35:45 tacoma1z-w81 phosphor-image-updater[766]:
BMC Minimum Ship Level NOT met

Jul 15 20:35:45 tacoma1z-w81 phosphor-image-updater[766]:
A system component has a software version that is incompatible as
determined by the implementation and needs to be updated....

Signed-off-by: Miguel Gomez <mgomez@mx1.ibm.com>
Change-Id: I0ab0eba7c7c89f38ca698aa3e369aa50797edb07
diff --git a/msl_verify.cpp b/msl_verify.cpp
new file mode 100644
index 0000000..3cd2278
--- /dev/null
+++ b/msl_verify.cpp
@@ -0,0 +1,96 @@
+#include "config.h"

+

+#include "msl_verify.hpp"

+

+#include "version.hpp"

+

+#include <phosphor-logging/log.hpp>

+

+#include <regex>

+

+using namespace phosphor::logging;

+

+int minimum_ship_level::compare(const Version& versionToCompare,

+                                const Version& mslVersion)

+{

+    if (versionToCompare.major > mslVersion.major)

+        return (1);

+    if (versionToCompare.major < mslVersion.major)

+        return (-1);

+

+    if (versionToCompare.minor > mslVersion.minor)

+        return (1);

+    if (versionToCompare.minor < mslVersion.minor)

+        return (-1);

+

+    if (versionToCompare.rev > mslVersion.rev)

+        return (1);

+    if (versionToCompare.rev < mslVersion.rev)

+        return (-1);

+

+    // Both string are equal and there is no need to make an upgrade return 0.

+    return 0;

+}

+

+// parse Function copy  inpVersion onto outVersion in Version format

+// {major,minor,rev}.

+void minimum_ship_level::parse(const std::string& inpVersion,

+                               Version& outVersion)

+{

+    std::smatch match;

+    outVersion = {0, 0, 0};

+

+    std::regex rx{REGEX_BMC_MSL, std::regex::extended};

+

+    if (!std::regex_search(inpVersion, match, rx))

+    {

+        log<level::ERR>("Unable to parse BMC version",

+                        entry("VERSION=%s", inpVersion.c_str()));

+        return;

+    }

+

+    outVersion.major = std::stoi(match[2]);

+    outVersion.minor = std::stoi(match[3]);

+    outVersion.rev = std::stoi(match[4]);

+}

+

+bool minimum_ship_level::verify(const std::string& versionManifest)

+{

+

+    //  If there is no msl or mslRegex return upgrade is needed.

+    std::string msl{BMC_MSL};

+    std::string mslRegex{REGEX_BMC_MSL};

+    if (msl.empty() || mslRegex.empty())

+    {

+        return true;

+    }

+

+    // Define mslVersion variable and populate in Version format

+    // {major,minor,rev} using parse function.

+

+    Version mslVersion = {0, 0, 0};

+    parse(msl, mslVersion);

+

+    // Define actualVersion variable and populate in Version format

+    // {major,minor,rev} using parse function.

+    std::string tmpStr{};

+

+    tmpStr = versionManifest;

+    Version actualVersion = {0, 0, 0};

+    parse(versionManifest, actualVersion);

+

+    // Compare actualVersion vs MSL.

+    auto rc = compare(actualVersion, mslVersion);

+    if (rc < 0)

+    {

+        log<level::ERR>(

+            "BMC Minimum Ship Level NOT met",

+            entry("MIN_VERSION=%s", msl.c_str()),

+            entry("ACTUAL_VERSION=%s", tmpStr.c_str()),

+            entry("VERSION_PURPOSE=%s",

+                  "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"));

+        return false;

+    }

+

+    return true;

+}