121dad047SMiguel Gomez #include "config.h"
221dad047SMiguel Gomez 
321dad047SMiguel Gomez #include "msl_verify.hpp"
421dad047SMiguel Gomez 
521dad047SMiguel Gomez #include "version.hpp"
621dad047SMiguel Gomez 
7*10ec9750Szamiseck #include <phosphor-logging/elog-errors.hpp>
8*10ec9750Szamiseck #include <phosphor-logging/elog.hpp>
9c9bb6425SPatrick Williams #include <phosphor-logging/lg2.hpp>
10*10ec9750Szamiseck #include <xyz/openbmc_project/Software/Version/error.hpp>
1121dad047SMiguel Gomez 
1221dad047SMiguel Gomez #include <regex>
1321dad047SMiguel Gomez 
14c9bb6425SPatrick Williams PHOSPHOR_LOG2_USING;
1521dad047SMiguel Gomez 
1621dad047SMiguel Gomez int minimum_ship_level::compare(const Version& versionToCompare,
1721dad047SMiguel Gomez                                 const Version& mslVersion)
1821dad047SMiguel Gomez {
1921dad047SMiguel Gomez     if (versionToCompare.major > mslVersion.major)
2021dad047SMiguel Gomez         return (1);
2121dad047SMiguel Gomez     if (versionToCompare.major < mslVersion.major)
2221dad047SMiguel Gomez         return (-1);
2321dad047SMiguel Gomez 
2421dad047SMiguel Gomez     if (versionToCompare.minor > mslVersion.minor)
2521dad047SMiguel Gomez         return (1);
2621dad047SMiguel Gomez     if (versionToCompare.minor < mslVersion.minor)
2721dad047SMiguel Gomez         return (-1);
2821dad047SMiguel Gomez 
2921dad047SMiguel Gomez     if (versionToCompare.rev > mslVersion.rev)
3021dad047SMiguel Gomez         return (1);
3121dad047SMiguel Gomez     if (versionToCompare.rev < mslVersion.rev)
3221dad047SMiguel Gomez         return (-1);
3321dad047SMiguel Gomez 
3421dad047SMiguel Gomez     // Both string are equal and there is no need to make an upgrade return 0.
3521dad047SMiguel Gomez     return 0;
3621dad047SMiguel Gomez }
3721dad047SMiguel Gomez 
3821dad047SMiguel Gomez // parse Function copy  inpVersion onto outVersion in Version format
3921dad047SMiguel Gomez // {major,minor,rev}.
4021dad047SMiguel Gomez void minimum_ship_level::parse(const std::string& inpVersion,
4121dad047SMiguel Gomez                                Version& outVersion)
4221dad047SMiguel Gomez {
4321dad047SMiguel Gomez     std::smatch match;
4421dad047SMiguel Gomez     outVersion = {0, 0, 0};
4521dad047SMiguel Gomez 
4621dad047SMiguel Gomez     std::regex rx{REGEX_BMC_MSL, std::regex::extended};
4721dad047SMiguel Gomez 
4821dad047SMiguel Gomez     if (!std::regex_search(inpVersion, match, rx))
4921dad047SMiguel Gomez     {
50c9bb6425SPatrick Williams         error("Unable to parse BMC version: {VERSION}", "VERSION", inpVersion);
5121dad047SMiguel Gomez         return;
5221dad047SMiguel Gomez     }
5321dad047SMiguel Gomez 
5421dad047SMiguel Gomez     outVersion.major = std::stoi(match[2]);
5521dad047SMiguel Gomez     outVersion.minor = std::stoi(match[3]);
5621dad047SMiguel Gomez     outVersion.rev = std::stoi(match[4]);
5721dad047SMiguel Gomez }
5821dad047SMiguel Gomez 
5921dad047SMiguel Gomez bool minimum_ship_level::verify(const std::string& versionManifest)
6021dad047SMiguel Gomez {
6121dad047SMiguel Gomez 
6221dad047SMiguel Gomez     //  If there is no msl or mslRegex return upgrade is needed.
6321dad047SMiguel Gomez     std::string msl{BMC_MSL};
6421dad047SMiguel Gomez     std::string mslRegex{REGEX_BMC_MSL};
6521dad047SMiguel Gomez     if (msl.empty() || mslRegex.empty())
6621dad047SMiguel Gomez     {
6721dad047SMiguel Gomez         return true;
6821dad047SMiguel Gomez     }
6921dad047SMiguel Gomez 
7021dad047SMiguel Gomez     // Define mslVersion variable and populate in Version format
7121dad047SMiguel Gomez     // {major,minor,rev} using parse function.
7221dad047SMiguel Gomez 
7321dad047SMiguel Gomez     Version mslVersion = {0, 0, 0};
7421dad047SMiguel Gomez     parse(msl, mslVersion);
7521dad047SMiguel Gomez 
7621dad047SMiguel Gomez     // Define actualVersion variable and populate in Version format
7721dad047SMiguel Gomez     // {major,minor,rev} using parse function.
7821dad047SMiguel Gomez     std::string tmpStr{};
7921dad047SMiguel Gomez 
8021dad047SMiguel Gomez     tmpStr = versionManifest;
8121dad047SMiguel Gomez     Version actualVersion = {0, 0, 0};
8221dad047SMiguel Gomez     parse(versionManifest, actualVersion);
8321dad047SMiguel Gomez 
8421dad047SMiguel Gomez     // Compare actualVersion vs MSL.
8521dad047SMiguel Gomez     auto rc = compare(actualVersion, mslVersion);
8621dad047SMiguel Gomez     if (rc < 0)
8721dad047SMiguel Gomez     {
88*10ec9750Szamiseck         using namespace phosphor::logging;
89*10ec9750Szamiseck         using IncompatibleErr = sdbusplus::xyz::openbmc_project::Software::
90*10ec9750Szamiseck             Version::Error::Incompatible;
91*10ec9750Szamiseck         using Incompatible =
92*10ec9750Szamiseck             xyz::openbmc_project::Software::Version::Incompatible;
93*10ec9750Szamiseck         std::string purpose =
94*10ec9750Szamiseck             "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
95*10ec9750Szamiseck 
96c9bb6425SPatrick Williams         error(
97c9bb6425SPatrick Williams             "BMC Minimum Ship Level ({MIN_VERSION}) NOT met by {ACTUAL_VERSION}",
98c9bb6425SPatrick Williams             "MIN_VERSION", msl, "ACTUAL_VERSION", tmpStr, "VERSION_PURPOSE",
99c9bb6425SPatrick Williams             purpose);
100*10ec9750Szamiseck         report<IncompatibleErr>(Incompatible::MIN_VERSION(msl.c_str()),
101*10ec9750Szamiseck                                 Incompatible::ACTUAL_VERSION(tmpStr.c_str()),
102*10ec9750Szamiseck                                 Incompatible::VERSION_PURPOSE(purpose.c_str()));
10321dad047SMiguel Gomez         return false;
10421dad047SMiguel Gomez     }
10521dad047SMiguel Gomez 
10621dad047SMiguel Gomez     return true;
10721dad047SMiguel Gomez }
108