1 #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 10 namespace openpower 11 { 12 namespace software 13 { 14 namespace image 15 { 16 17 namespace fs = std::experimental::filesystem; 18 using namespace phosphor::logging; 19 20 int 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 52 void 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 80 std::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 101 bool 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 114 Version minVersion = {0, 0, 0}; 115 parse(minShipLevel, minVersion); 116 117 Version actualVersion = {0, 0, 0}; 118 parse(actual, actualVersion); 119 120 auto rc = compare(actualVersion, minVersion); 121 if (rc < 0) 122 { 123 log<level::ERR>( 124 "PNOR Mininum Ship Level NOT met", 125 entry("MIN_VERSION=%s", minShipLevel.c_str()), 126 entry("ACTUAL_VERSION=%s", actual.c_str()), 127 entry("VERSION_PURPOSE=%s", 128 "xyz.openbmc_project.Software.Version.VersionPurpose.Host")); 129 return false; 130 } 131 132 return true; 133 } 134 135 } // namespace image 136 } // namespace software 137 } // namespace openpower 138