121dad047SMiguel Gomez #include "config.h"
221dad047SMiguel Gomez 
321dad047SMiguel Gomez #include "msl_verify.hpp"
421dad047SMiguel Gomez 
521dad047SMiguel Gomez #include "version.hpp"
621dad047SMiguel Gomez 
710ec9750Szamiseck #include <phosphor-logging/elog-errors.hpp>
810ec9750Szamiseck #include <phosphor-logging/elog.hpp>
9c9bb6425SPatrick Williams #include <phosphor-logging/lg2.hpp>
1010ec9750Szamiseck #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)
20*ce9a5c9aSPavithra Barithaya     {
2121dad047SMiguel Gomez         return (1);
22*ce9a5c9aSPavithra Barithaya     }
2321dad047SMiguel Gomez     if (versionToCompare.major < mslVersion.major)
24*ce9a5c9aSPavithra Barithaya     {
2521dad047SMiguel Gomez         return (-1);
26*ce9a5c9aSPavithra Barithaya     }
2721dad047SMiguel Gomez 
2821dad047SMiguel Gomez     if (versionToCompare.minor > mslVersion.minor)
29*ce9a5c9aSPavithra Barithaya     {
3021dad047SMiguel Gomez         return (1);
31*ce9a5c9aSPavithra Barithaya     }
3221dad047SMiguel Gomez     if (versionToCompare.minor < mslVersion.minor)
33*ce9a5c9aSPavithra Barithaya     {
3421dad047SMiguel Gomez         return (-1);
35*ce9a5c9aSPavithra Barithaya     }
3621dad047SMiguel Gomez 
3721dad047SMiguel Gomez     if (versionToCompare.rev > mslVersion.rev)
38*ce9a5c9aSPavithra Barithaya     {
3921dad047SMiguel Gomez         return (1);
40*ce9a5c9aSPavithra Barithaya     }
4121dad047SMiguel Gomez     if (versionToCompare.rev < mslVersion.rev)
42*ce9a5c9aSPavithra Barithaya     {
4321dad047SMiguel Gomez         return (-1);
44*ce9a5c9aSPavithra Barithaya     }
4521dad047SMiguel Gomez 
4621dad047SMiguel Gomez     // Both string are equal and there is no need to make an upgrade return 0.
4721dad047SMiguel Gomez     return 0;
4821dad047SMiguel Gomez }
4921dad047SMiguel Gomez 
5021dad047SMiguel Gomez // parse Function copy  inpVersion onto outVersion in Version format
5121dad047SMiguel Gomez // {major,minor,rev}.
5221dad047SMiguel Gomez void minimum_ship_level::parse(const std::string& inpVersion,
5321dad047SMiguel Gomez                                Version& outVersion)
5421dad047SMiguel Gomez {
5521dad047SMiguel Gomez     std::smatch match;
5621dad047SMiguel Gomez     outVersion = {0, 0, 0};
5721dad047SMiguel Gomez 
5821dad047SMiguel Gomez     std::regex rx{REGEX_BMC_MSL, std::regex::extended};
5921dad047SMiguel Gomez 
6021dad047SMiguel Gomez     if (!std::regex_search(inpVersion, match, rx))
6121dad047SMiguel Gomez     {
62c9bb6425SPatrick Williams         error("Unable to parse BMC version: {VERSION}", "VERSION", inpVersion);
6321dad047SMiguel Gomez         return;
6421dad047SMiguel Gomez     }
6521dad047SMiguel Gomez 
6621dad047SMiguel Gomez     outVersion.major = std::stoi(match[2]);
6721dad047SMiguel Gomez     outVersion.minor = std::stoi(match[3]);
6821dad047SMiguel Gomez     outVersion.rev = std::stoi(match[4]);
6921dad047SMiguel Gomez }
7021dad047SMiguel Gomez 
7121dad047SMiguel Gomez bool minimum_ship_level::verify(const std::string& versionManifest)
7221dad047SMiguel Gomez {
7321dad047SMiguel Gomez     //  If there is no msl or mslRegex return upgrade is needed.
7430352a66SAdriana Kobylak     if (!enabled())
7521dad047SMiguel Gomez     {
7621dad047SMiguel Gomez         return true;
7721dad047SMiguel Gomez     }
7821dad047SMiguel Gomez 
7921dad047SMiguel Gomez     // Define mslVersion variable and populate in Version format
8021dad047SMiguel Gomez     // {major,minor,rev} using parse function.
8121dad047SMiguel Gomez 
8230352a66SAdriana Kobylak     std::string msl = getMinimumVersion();
8321dad047SMiguel Gomez     Version mslVersion = {0, 0, 0};
8421dad047SMiguel Gomez     parse(msl, mslVersion);
8521dad047SMiguel Gomez 
8621dad047SMiguel Gomez     // Define actualVersion variable and populate in Version format
8721dad047SMiguel Gomez     // {major,minor,rev} using parse function.
8821dad047SMiguel Gomez     std::string tmpStr{};
8921dad047SMiguel Gomez 
9021dad047SMiguel Gomez     tmpStr = versionManifest;
9121dad047SMiguel Gomez     Version actualVersion = {0, 0, 0};
9221dad047SMiguel Gomez     parse(versionManifest, actualVersion);
9321dad047SMiguel Gomez 
9421dad047SMiguel Gomez     // Compare actualVersion vs MSL.
9521dad047SMiguel Gomez     auto rc = compare(actualVersion, mslVersion);
9621dad047SMiguel Gomez     if (rc < 0)
9721dad047SMiguel Gomez     {
9810ec9750Szamiseck         using namespace phosphor::logging;
99ce82de51SAdriana Kobylak         using IncompatibleErr = sdbusplus::error::xyz::openbmc_project::
100ce82de51SAdriana Kobylak             software::version::Incompatible;
10110ec9750Szamiseck         using Incompatible =
102ce82de51SAdriana Kobylak             xyz::openbmc_project::software::version::Incompatible;
10310ec9750Szamiseck         std::string purpose =
10410ec9750Szamiseck             "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
10510ec9750Szamiseck 
106c9bb6425SPatrick Williams         error(
107c9bb6425SPatrick Williams             "BMC Minimum Ship Level ({MIN_VERSION}) NOT met by {ACTUAL_VERSION}",
108c9bb6425SPatrick Williams             "MIN_VERSION", msl, "ACTUAL_VERSION", tmpStr, "VERSION_PURPOSE",
109c9bb6425SPatrick Williams             purpose);
11010ec9750Szamiseck         report<IncompatibleErr>(Incompatible::MIN_VERSION(msl.c_str()),
11110ec9750Szamiseck                                 Incompatible::ACTUAL_VERSION(tmpStr.c_str()),
11210ec9750Szamiseck                                 Incompatible::VERSION_PURPOSE(purpose.c_str()));
11321dad047SMiguel Gomez         return false;
11421dad047SMiguel Gomez     }
11521dad047SMiguel Gomez 
11621dad047SMiguel Gomez     return true;
11721dad047SMiguel Gomez }
11830352a66SAdriana Kobylak 
11930352a66SAdriana Kobylak bool minimum_ship_level::enabled()
12030352a66SAdriana Kobylak {
12130352a66SAdriana Kobylak     std::string msl = getMinimumVersion();
12230352a66SAdriana Kobylak     std::string mslRegex{REGEX_BMC_MSL};
12330352a66SAdriana Kobylak     if (!msl.empty() && !mslRegex.empty())
12430352a66SAdriana Kobylak     {
12530352a66SAdriana Kobylak         return true;
12630352a66SAdriana Kobylak     }
12730352a66SAdriana Kobylak     return false;
12830352a66SAdriana Kobylak }
12930352a66SAdriana Kobylak 
13030352a66SAdriana Kobylak std::string minimum_ship_level::getMinimumVersion()
13130352a66SAdriana Kobylak {
13230352a66SAdriana Kobylak     return BMC_MSL;
13330352a66SAdriana Kobylak }
134