blob: 36203dbf8d69b51356f1dbcc9a377f6b8af47f75 [file] [log] [blame]
Adriana Kobylak4772a942018-10-09 15:26:44 -05001#include "config.h"
2
3#include "msl_verify.hpp"
4
5#include <experimental/filesystem>
6#include <fstream>
7#include <phosphor-logging/log.hpp>
8#include <regex>
9
10namespace openpower
11{
12namespace software
13{
14namespace image
15{
16
17namespace fs = std::experimental::filesystem;
18using namespace phosphor::logging;
19
20int MinimumShipLevel::compare(const Version& a, const Version& b)
21{
22 if (a.major < b.major)
23 {
24 return -1;
25 }
26 else if (a.major > b.major)
27 {
28 return 1;
29 }
30
31 if (a.minor < b.minor)
32 {
33 return -1;
34 }
35 else if (a.minor > b.minor)
36 {
37 return 1;
38 }
39
40 if (a.rev < b.rev)
41 {
42 return -1;
43 }
44 else if (a.rev > b.rev)
45 {
46 return 1;
47 }
48
49 return 0;
50}
51
52void MinimumShipLevel::parse(const std::string& versionStr, Version& version)
53{
54 std::smatch match;
55 version = {0, 0, 0};
56
57 // Match for vX.Y.Z
58 std::regex regex{"v([0-9]+)\\.([0-9]+)\\.([0-9]+)", std::regex::extended};
59
60 if (!std::regex_search(versionStr, match, regex))
61 {
62 // Match for vX.Y
63 std::regex regexShort{"v([0-9]+)\\.([0-9]+)", std::regex::extended};
64 if (!std::regex_search(versionStr, match, regexShort))
65 {
66 log<level::ERR>("Unable to parse PNOR version",
67 entry("VERSION=%s", versionStr.c_str()));
68 return;
69 }
70 }
71 else
72 {
73 // Populate Z
74 version.rev = std::stoi(match[3]);
75 }
76 version.major = std::stoi(match[1]);
77 version.minor = std::stoi(match[2]);
78}
79
80std::string MinimumShipLevel::getFunctionalVersion()
81{
82 if (!fs::exists(PNOR_RO_ACTIVE_PATH))
83 {
84 return {};
85 }
86
87 fs::path versionPath(PNOR_RO_ACTIVE_PATH);
88 versionPath /= PNOR_VERSION_PARTITION;
89 if (!fs::is_regular_file(versionPath))
90 {
91 return {};
92 }
93
94 std::ifstream versionFile(versionPath);
95 std::string versionStr;
96 std::getline(versionFile, versionStr);
97
98 return versionStr;
99}
100
101bool MinimumShipLevel::verify()
102{
103 if (minShipLevel.empty())
104 {
105 return true;
106 }
107
108 auto actual = getFunctionalVersion();
109 if (actual.empty())
110 {
111 return true;
112 }
113
Adriana Kobylak5c33b4c2018-10-17 20:16:19 -0500114 // Multiple min versions separated by a space can be specified, parse them
115 // into a vector, then sort them in ascending order
116 std::istringstream minStream(minShipLevel);
117 std::vector<std::string> mins(std::istream_iterator<std::string>{minStream},
118 std::istream_iterator<std::string>());
119 std::sort(mins.begin(), mins.end());
Adriana Kobylak4772a942018-10-09 15:26:44 -0500120
Adriana Kobylak5c33b4c2018-10-17 20:16:19 -0500121 // In order to handle non-continuous multiple min versions, need to compare
122 // the major.minor section first, then if they're the same, compare the rev.
123 // Ex: the min versions specified are 2.0.10 and 2.2. We need to pass if
124 // actual is 2.0.11 but fail if it's 2.1.x.
125 // 1. Save off the rev number to compare later if needed.
126 // 2. Zero out the rev number to just compare major and minor.
Adriana Kobylak4772a942018-10-09 15:26:44 -0500127 Version actualVersion = {0, 0, 0};
128 parse(actual, actualVersion);
Adriana Kobylak5c33b4c2018-10-17 20:16:19 -0500129 Version actualRev = {0, 0, actualVersion.rev};
130 actualVersion.rev = 0;
Adriana Kobylak4772a942018-10-09 15:26:44 -0500131
Adriana Kobylak5c33b4c2018-10-17 20:16:19 -0500132 auto rc = 0;
133 std::string tmpMin{};
134
135 for (auto const& min : mins)
136 {
137 tmpMin = min;
138
139 Version minVersion = {0, 0, 0};
140 parse(min, minVersion);
141 Version minRev = {0, 0, minVersion.rev};
142 minVersion.rev = 0;
143
144 rc = compare(actualVersion, minVersion);
145 if (rc < 0)
146 {
147 break;
148 }
149 else if (rc == 0)
150 {
151 // Same major.minor version, compare the rev
152 rc = compare(actualRev, minRev);
153 break;
154 }
155 }
Adriana Kobylak4772a942018-10-09 15:26:44 -0500156 if (rc < 0)
157 {
158 log<level::ERR>(
159 "PNOR Mininum Ship Level NOT met",
Adriana Kobylak5c33b4c2018-10-17 20:16:19 -0500160 entry("MIN_VERSION=%s", tmpMin.c_str()),
Adriana Kobylak4772a942018-10-09 15:26:44 -0500161 entry("ACTUAL_VERSION=%s", actual.c_str()),
162 entry("VERSION_PURPOSE=%s",
163 "xyz.openbmc_project.Software.Version.VersionPurpose.Host"));
164 return false;
165 }
166
167 return true;
168}
169
170} // namespace image
171} // namespace software
172} // namespace openpower