1 #include "config.h"
2 
3 #include "msl_verify.hpp"
4 
5 #include "version.hpp"
6 
7 #include <phosphor-logging/elog-errors.hpp>
8 #include <phosphor-logging/elog.hpp>
9 #include <phosphor-logging/lg2.hpp>
10 #include <xyz/openbmc_project/Software/Version/error.hpp>
11 
12 #include <regex>
13 
14 PHOSPHOR_LOG2_USING;
15 
16 int minimum_ship_level::compare(const Version& versionToCompare,
17                                 const Version& mslVersion)
18 {
19     if (versionToCompare.major > mslVersion.major)
20     {
21         return (1);
22     }
23     if (versionToCompare.major < mslVersion.major)
24     {
25         return (-1);
26     }
27 
28     if (versionToCompare.minor > mslVersion.minor)
29     {
30         return (1);
31     }
32     if (versionToCompare.minor < mslVersion.minor)
33     {
34         return (-1);
35     }
36 
37     if (versionToCompare.rev > mslVersion.rev)
38     {
39         return (1);
40     }
41     if (versionToCompare.rev < mslVersion.rev)
42     {
43         return (-1);
44     }
45 
46     // Both string are equal and there is no need to make an upgrade return 0.
47     return 0;
48 }
49 
50 // parse Function copy  inpVersion onto outVersion in Version format
51 // {major,minor,rev}.
52 void minimum_ship_level::parse(const std::string& inpVersion,
53                                Version& outVersion)
54 {
55     std::smatch match;
56     outVersion = {0, 0, 0};
57 
58     std::regex rx{REGEX_BMC_MSL, std::regex::extended};
59 
60     if (!std::regex_search(inpVersion, match, rx))
61     {
62         error("Unable to parse BMC version: {VERSION}", "VERSION", inpVersion);
63         return;
64     }
65 
66     outVersion.major = std::stoi(match[2]);
67     outVersion.minor = std::stoi(match[3]);
68     outVersion.rev = std::stoi(match[4]);
69 }
70 
71 bool minimum_ship_level::verify(const std::string& versionManifest)
72 {
73     //  If there is no msl or mslRegex return upgrade is needed.
74     if (!enabled())
75     {
76         return true;
77     }
78 
79     // Define mslVersion variable and populate in Version format
80     // {major,minor,rev} using parse function.
81 
82     std::string msl = getMinimumVersion();
83     Version mslVersion = {0, 0, 0};
84     parse(msl, mslVersion);
85 
86     // Define actualVersion variable and populate in Version format
87     // {major,minor,rev} using parse function.
88     std::string tmpStr{};
89 
90     tmpStr = versionManifest;
91     Version actualVersion = {0, 0, 0};
92     parse(versionManifest, actualVersion);
93 
94     // Compare actualVersion vs MSL.
95     auto rc = compare(actualVersion, mslVersion);
96     if (rc < 0)
97     {
98         using namespace phosphor::logging;
99         using IncompatibleErr = sdbusplus::error::xyz::openbmc_project::
100             software::version::Incompatible;
101         using Incompatible =
102             xyz::openbmc_project::software::version::Incompatible;
103         std::string purpose =
104             "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
105 
106         error(
107             "BMC Minimum Ship Level ({MIN_VERSION}) NOT met by {ACTUAL_VERSION}",
108             "MIN_VERSION", msl, "ACTUAL_VERSION", tmpStr, "VERSION_PURPOSE",
109             purpose);
110         report<IncompatibleErr>(Incompatible::MIN_VERSION(msl.c_str()),
111                                 Incompatible::ACTUAL_VERSION(tmpStr.c_str()),
112                                 Incompatible::VERSION_PURPOSE(purpose.c_str()));
113         return false;
114     }
115 
116     return true;
117 }
118 
119 bool minimum_ship_level::enabled()
120 {
121     std::string msl = getMinimumVersion();
122     std::string mslRegex{REGEX_BMC_MSL};
123     return !msl.empty() && !mslRegex.empty();
124 }
125 
126 std::string minimum_ship_level::getMinimumVersion()
127 {
128     return BMC_MSL;
129 }
130