blob: 871b9f50d60b8ea912df3e26f7a5695ebfc89b40 [file] [log] [blame]
Eddie James6d873712017-09-01 11:29:07 -05001#include "config.h"
Gunnar Millsb0ce9962018-09-07 13:39:10 -05002
Gunnar Mills392f2942017-04-12 11:04:37 -05003#include "version.hpp"
4
Gunnar Millsb0ce9962018-09-07 13:39:10 -05005#include "xyz/openbmc_project/Common/error.hpp"
6
Patrick Williams564bc902021-12-08 10:17:23 -06007#include <openssl/evp.h>
Gunnar Millsb0ce9962018-09-07 13:39:10 -05008
Gunnar Millsb0ce9962018-09-07 13:39:10 -05009#include <phosphor-logging/elog-errors.hpp>
Patrick Williamsc9bb6422021-08-27 06:18:35 -050010#include <phosphor-logging/lg2.hpp>
Adriana Kobylak58aa7502020-06-08 11:12:11 -050011
12#include <fstream>
13#include <iostream>
Gunnar Millsb0ce9962018-09-07 13:39:10 -050014#include <sstream>
15#include <stdexcept>
16#include <string>
17
Gunnar Mills392f2942017-04-12 11:04:37 -050018namespace phosphor
19{
20namespace software
21{
22namespace manager
23{
24
Patrick Williamsc9bb6422021-08-27 06:18:35 -050025PHOSPHOR_LOG2_USING;
Gunnar Mills392f2942017-04-12 11:04:37 -050026using namespace phosphor::logging;
Gunnar Millsaae1b2b2017-10-06 13:42:39 -050027using Argument = xyz::openbmc_project::Common::InvalidArgument;
28using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Gunnar Mills392f2942017-04-12 11:04:37 -050029
Gunnar Millscebd1022017-04-17 16:10:15 -050030std::string Version::getValue(const std::string& manifestFilePath,
31 std::string key)
Gunnar Mills392f2942017-04-12 11:04:37 -050032{
Gunnar Millscebd1022017-04-17 16:10:15 -050033 key = key + "=";
34 auto keySize = key.length();
Gunnar Mills392f2942017-04-12 11:04:37 -050035
36 if (manifestFilePath.empty())
37 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -050038 error("ManifestFilePath is empty.");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -050039 elog<InvalidArgument>(
Adriana Kobylak2285fe02018-02-27 15:36:59 -060040 Argument::ARGUMENT_NAME("manifestFilePath"),
41 Argument::ARGUMENT_VALUE(manifestFilePath.c_str()));
Gunnar Mills392f2942017-04-12 11:04:37 -050042 }
43
Gunnar Millscebd1022017-04-17 16:10:15 -050044 std::string value{};
Gunnar Mills392f2942017-04-12 11:04:37 -050045 std::ifstream efile;
46 std::string line;
Adriana Kobylak2285fe02018-02-27 15:36:59 -060047 efile.exceptions(std::ifstream::failbit | std::ifstream::badbit |
Gunnar Millsaae1b2b2017-10-06 13:42:39 -050048 std::ifstream::eofbit);
Gunnar Mills392f2942017-04-12 11:04:37 -050049
50 // Too many GCC bugs (53984, 66145) to do this the right way...
51 try
52 {
53 efile.open(manifestFilePath);
54 while (getline(efile, line))
55 {
Lei YU5a7363b2019-10-18 16:50:59 +080056 if (!line.empty() && line.back() == '\r')
57 {
58 // If the manifest has CRLF line terminators, e.g. is created on
59 // Windows, the line will contain \r at the end, remove it.
60 line.pop_back();
61 }
Gunnar Millscebd1022017-04-17 16:10:15 -050062 if (line.compare(0, keySize, key) == 0)
Gunnar Mills392f2942017-04-12 11:04:37 -050063 {
Gunnar Millscebd1022017-04-17 16:10:15 -050064 value = line.substr(keySize);
Gunnar Mills392f2942017-04-12 11:04:37 -050065 break;
66 }
67 }
68 efile.close();
69 }
70 catch (const std::exception& e)
71 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -050072 error("Error occurred when reading MANIFEST file: {ERROR}", "KEY", key,
73 "ERROR", e);
Gunnar Mills392f2942017-04-12 11:04:37 -050074 }
75
Gunnar Millscebd1022017-04-17 16:10:15 -050076 return value;
Gunnar Mills392f2942017-04-12 11:04:37 -050077}
78
Patrick Williams564bc902021-12-08 10:17:23 -060079using EVP_MD_CTX_Ptr =
80 std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_free)>;
81
Gunnar Mills392f2942017-04-12 11:04:37 -050082std::string Version::getId(const std::string& version)
83{
Gunnar Mills392f2942017-04-12 11:04:37 -050084
85 if (version.empty())
86 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -050087 error("Version is empty.");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -050088 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Version"),
89 Argument::ARGUMENT_VALUE(version.c_str()));
Gunnar Mills392f2942017-04-12 11:04:37 -050090 }
91
Patrick Williams564bc902021-12-08 10:17:23 -060092 std::array<unsigned char, EVP_MAX_MD_SIZE> digest{};
93 EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_new(), &::EVP_MD_CTX_free);
Saqib Khan26a960d2017-09-19 14:23:28 -050094
Patrick Williams564bc902021-12-08 10:17:23 -060095 EVP_DigestInit(ctx.get(), EVP_sha512());
96 EVP_DigestUpdate(ctx.get(), version.c_str(), strlen(version.c_str()));
97 EVP_DigestFinal(ctx.get(), digest.data(), nullptr);
98
99 // We are only using the first 8 characters.
100 char mdString[9];
101 snprintf(mdString, sizeof(mdString), "%02x%02x%02x%02x",
102 (unsigned int)digest[0], (unsigned int)digest[1],
103 (unsigned int)digest[2], (unsigned int)digest[3]);
104
105 return mdString;
Gunnar Mills392f2942017-04-12 11:04:37 -0500106}
107
Vijay Khemkab7c062e2019-09-18 17:15:57 -0700108std::string Version::getBMCMachine(const std::string& releaseFilePath)
109{
110 std::string machineKey = "OPENBMC_TARGET_MACHINE=";
111 std::string machine{};
112 std::ifstream efile(releaseFilePath);
113 std::string line;
114
115 while (getline(efile, line))
116 {
117 if (line.substr(0, machineKey.size()).find(machineKey) !=
118 std::string::npos)
119 {
120 std::size_t pos = line.find_first_of('"') + 1;
121 machine = line.substr(pos, line.find_last_of('"') - pos);
122 break;
123 }
124 }
125
126 if (machine.empty())
127 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500128 error("Unable to find OPENBMC_TARGET_MACHINE");
Vijay Khemkab7c062e2019-09-18 17:15:57 -0700129 elog<InternalFailure>();
130 }
131
132 return machine;
133}
134
Chanh Nguyen1fd6ddd2021-01-06 11:09:09 +0700135std::string Version::getBMCExtendedVersion(const std::string& releaseFilePath)
136{
137 std::string extendedVersionKey = "EXTENDED_VERSION=";
138 std::string extendedVersionValue{};
139 std::string extendedVersion{};
140 std::ifstream efile(releaseFilePath);
141 std::string line;
142
143 while (getline(efile, line))
144 {
145 if (line.substr(0, extendedVersionKey.size())
146 .find(extendedVersionKey) != std::string::npos)
147 {
148 extendedVersionValue = line.substr(extendedVersionKey.size());
149 std::size_t pos = extendedVersionValue.find_first_of('"') + 1;
150 extendedVersion = extendedVersionValue.substr(
151 pos, extendedVersionValue.find_last_of('"') - pos);
152 break;
153 }
154 }
155
156 return extendedVersion;
157}
158
Saqib Khan1eef62d2017-08-10 15:29:34 -0500159std::string Version::getBMCVersion(const std::string& releaseFilePath)
Saqib Khanba239882017-05-26 08:41:54 -0500160{
161 std::string versionKey = "VERSION_ID=";
Adriana Kobylak2a3d9f52020-05-06 10:46:32 -0500162 std::string versionValue{};
Saqib Khanba239882017-05-26 08:41:54 -0500163 std::string version{};
164 std::ifstream efile;
165 std::string line;
Saqib Khan1eef62d2017-08-10 15:29:34 -0500166 efile.open(releaseFilePath);
Saqib Khanba239882017-05-26 08:41:54 -0500167
168 while (getline(efile, line))
169 {
170 if (line.substr(0, versionKey.size()).find(versionKey) !=
171 std::string::npos)
172 {
Adriana Kobylak2a3d9f52020-05-06 10:46:32 -0500173 // Support quoted and unquoted values
174 // 1. Remove the versionKey so that we process the value only.
175 versionValue = line.substr(versionKey.size());
176
177 // 2. Look for a starting quote, then increment the position by 1 to
178 // skip the quote character. If no quote is found,
179 // find_first_of() returns npos (-1), which by adding +1 sets pos
180 // to 0 (beginning of unquoted string).
181 std::size_t pos = versionValue.find_first_of('"') + 1;
182
183 // 3. Look for ending quote, then decrease the position by pos to
184 // get the size of the string up to before the ending quote. If
185 // no quote is found, find_last_of() returns npos (-1), and pos
186 // is 0 for the unquoted case, so substr() is called with a len
187 // parameter of npos (-1) which according to the documentation
188 // indicates to use all characters until the end of the string.
189 version =
190 versionValue.substr(pos, versionValue.find_last_of('"') - pos);
Saqib Khanba239882017-05-26 08:41:54 -0500191 break;
192 }
193 }
194 efile.close();
195
196 if (version.empty())
197 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500198 error("BMC current version is empty");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -0500199 elog<InternalFailure>();
Saqib Khanba239882017-05-26 08:41:54 -0500200 }
201
202 return version;
203}
204
Eddie James6d873712017-09-01 11:29:07 -0500205bool Version::isFunctional()
206{
207 return versionStr == getBMCVersion(OS_RELEASE_FILE);
208}
209
Saqib Khanee13e832017-10-23 12:53:11 -0500210void Delete::delete_()
211{
212 if (parent.eraseCallback)
213 {
214 parent.eraseCallback(parent.getId(parent.version()));
215 }
216}
217
Gunnar Mills392f2942017-04-12 11:04:37 -0500218} // namespace manager
219} // namespace software
Gunnar Millsfa34e022018-09-04 10:05:45 -0500220} // namespace phosphor