blob: f7fbd2b4729d13b6002bf0e3518519e2d89e0a2c [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{
Justin Ledford054bb0b2022-03-15 15:46:58 -070033 std::vector<std::string> values = getRepeatedValues(manifestFilePath, key);
34 if (values.empty())
35 {
36 return std::string{};
37 }
38 if (values.size() > 1)
39 {
40 error("Multiple values found in MANIFEST file for key: {KEY}", "KEY",
41 key);
42 }
43 return values.at(0);
44}
45
46std::vector<std::string>
47 Version::getRepeatedValues(const std::string& manifestFilePath,
48 std::string key)
49{
Gunnar Millscebd1022017-04-17 16:10:15 -050050 key = key + "=";
51 auto keySize = key.length();
Gunnar Mills392f2942017-04-12 11:04:37 -050052
53 if (manifestFilePath.empty())
54 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -050055 error("ManifestFilePath is empty.");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -050056 elog<InvalidArgument>(
Adriana Kobylak2285fe02018-02-27 15:36:59 -060057 Argument::ARGUMENT_NAME("manifestFilePath"),
58 Argument::ARGUMENT_VALUE(manifestFilePath.c_str()));
Gunnar Mills392f2942017-04-12 11:04:37 -050059 }
60
Justin Ledford054bb0b2022-03-15 15:46:58 -070061 std::vector<std::string> values{};
Gunnar Mills392f2942017-04-12 11:04:37 -050062 std::ifstream efile;
63 std::string line;
Justin Ledford054bb0b2022-03-15 15:46:58 -070064 efile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
Gunnar Mills392f2942017-04-12 11:04:37 -050065
66 // Too many GCC bugs (53984, 66145) to do this the right way...
67 try
68 {
69 efile.open(manifestFilePath);
70 while (getline(efile, line))
71 {
Lei YU5a7363b2019-10-18 16:50:59 +080072 if (!line.empty() && line.back() == '\r')
73 {
74 // If the manifest has CRLF line terminators, e.g. is created on
75 // Windows, the line will contain \r at the end, remove it.
76 line.pop_back();
77 }
Gunnar Millscebd1022017-04-17 16:10:15 -050078 if (line.compare(0, keySize, key) == 0)
Gunnar Mills392f2942017-04-12 11:04:37 -050079 {
Justin Ledford054bb0b2022-03-15 15:46:58 -070080 values.push_back(line.substr(keySize));
Gunnar Mills392f2942017-04-12 11:04:37 -050081 }
82 }
83 efile.close();
84 }
85 catch (const std::exception& e)
86 {
Justin Ledford054bb0b2022-03-15 15:46:58 -070087 if (!efile.eof())
88 {
89 error("Error occurred when reading MANIFEST file: {ERROR}", "KEY",
90 key, "ERROR", e);
91 }
Gunnar Mills392f2942017-04-12 11:04:37 -050092 }
93
Justin Ledford054bb0b2022-03-15 15:46:58 -070094 if (values.empty())
95 {
96 error("No values found in MANIFEST file for key: {KEY}", "KEY", key);
97 }
98
99 return values;
Gunnar Mills392f2942017-04-12 11:04:37 -0500100}
101
Patrick Williams564bc902021-12-08 10:17:23 -0600102using EVP_MD_CTX_Ptr =
103 std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_free)>;
104
Gunnar Mills392f2942017-04-12 11:04:37 -0500105std::string Version::getId(const std::string& version)
106{
Gunnar Mills392f2942017-04-12 11:04:37 -0500107
108 if (version.empty())
109 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500110 error("Version is empty.");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -0500111 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Version"),
112 Argument::ARGUMENT_VALUE(version.c_str()));
Gunnar Mills392f2942017-04-12 11:04:37 -0500113 }
114
Patrick Williams564bc902021-12-08 10:17:23 -0600115 std::array<unsigned char, EVP_MAX_MD_SIZE> digest{};
116 EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_new(), &::EVP_MD_CTX_free);
Saqib Khan26a960d2017-09-19 14:23:28 -0500117
Patrick Williams564bc902021-12-08 10:17:23 -0600118 EVP_DigestInit(ctx.get(), EVP_sha512());
119 EVP_DigestUpdate(ctx.get(), version.c_str(), strlen(version.c_str()));
120 EVP_DigestFinal(ctx.get(), digest.data(), nullptr);
121
122 // We are only using the first 8 characters.
123 char mdString[9];
124 snprintf(mdString, sizeof(mdString), "%02x%02x%02x%02x",
125 (unsigned int)digest[0], (unsigned int)digest[1],
126 (unsigned int)digest[2], (unsigned int)digest[3]);
127
128 return mdString;
Gunnar Mills392f2942017-04-12 11:04:37 -0500129}
130
Vijay Khemkab7c062e2019-09-18 17:15:57 -0700131std::string Version::getBMCMachine(const std::string& releaseFilePath)
132{
133 std::string machineKey = "OPENBMC_TARGET_MACHINE=";
134 std::string machine{};
135 std::ifstream efile(releaseFilePath);
136 std::string line;
137
138 while (getline(efile, line))
139 {
140 if (line.substr(0, machineKey.size()).find(machineKey) !=
141 std::string::npos)
142 {
143 std::size_t pos = line.find_first_of('"') + 1;
144 machine = line.substr(pos, line.find_last_of('"') - pos);
145 break;
146 }
147 }
148
149 if (machine.empty())
150 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500151 error("Unable to find OPENBMC_TARGET_MACHINE");
Vijay Khemkab7c062e2019-09-18 17:15:57 -0700152 elog<InternalFailure>();
153 }
154
155 return machine;
156}
157
Chanh Nguyen1fd6ddd2021-01-06 11:09:09 +0700158std::string Version::getBMCExtendedVersion(const std::string& releaseFilePath)
159{
160 std::string extendedVersionKey = "EXTENDED_VERSION=";
161 std::string extendedVersionValue{};
162 std::string extendedVersion{};
163 std::ifstream efile(releaseFilePath);
164 std::string line;
165
166 while (getline(efile, line))
167 {
168 if (line.substr(0, extendedVersionKey.size())
169 .find(extendedVersionKey) != std::string::npos)
170 {
171 extendedVersionValue = line.substr(extendedVersionKey.size());
172 std::size_t pos = extendedVersionValue.find_first_of('"') + 1;
173 extendedVersion = extendedVersionValue.substr(
174 pos, extendedVersionValue.find_last_of('"') - pos);
175 break;
176 }
177 }
178
179 return extendedVersion;
180}
181
Saqib Khan1eef62d2017-08-10 15:29:34 -0500182std::string Version::getBMCVersion(const std::string& releaseFilePath)
Saqib Khanba239882017-05-26 08:41:54 -0500183{
184 std::string versionKey = "VERSION_ID=";
Adriana Kobylak2a3d9f52020-05-06 10:46:32 -0500185 std::string versionValue{};
Saqib Khanba239882017-05-26 08:41:54 -0500186 std::string version{};
187 std::ifstream efile;
188 std::string line;
Saqib Khan1eef62d2017-08-10 15:29:34 -0500189 efile.open(releaseFilePath);
Saqib Khanba239882017-05-26 08:41:54 -0500190
191 while (getline(efile, line))
192 {
193 if (line.substr(0, versionKey.size()).find(versionKey) !=
194 std::string::npos)
195 {
Adriana Kobylak2a3d9f52020-05-06 10:46:32 -0500196 // Support quoted and unquoted values
197 // 1. Remove the versionKey so that we process the value only.
198 versionValue = line.substr(versionKey.size());
199
200 // 2. Look for a starting quote, then increment the position by 1 to
201 // skip the quote character. If no quote is found,
202 // find_first_of() returns npos (-1), which by adding +1 sets pos
203 // to 0 (beginning of unquoted string).
204 std::size_t pos = versionValue.find_first_of('"') + 1;
205
206 // 3. Look for ending quote, then decrease the position by pos to
207 // get the size of the string up to before the ending quote. If
208 // no quote is found, find_last_of() returns npos (-1), and pos
209 // is 0 for the unquoted case, so substr() is called with a len
210 // parameter of npos (-1) which according to the documentation
211 // indicates to use all characters until the end of the string.
212 version =
213 versionValue.substr(pos, versionValue.find_last_of('"') - pos);
Saqib Khanba239882017-05-26 08:41:54 -0500214 break;
215 }
216 }
217 efile.close();
218
219 if (version.empty())
220 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500221 error("BMC current version is empty");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -0500222 elog<InternalFailure>();
Saqib Khanba239882017-05-26 08:41:54 -0500223 }
224
225 return version;
226}
227
Saqib Khanee13e832017-10-23 12:53:11 -0500228void Delete::delete_()
229{
230 if (parent.eraseCallback)
231 {
Adriana Kobylak59b640b2022-01-21 19:45:22 +0000232 parent.eraseCallback(parent.id);
Saqib Khanee13e832017-10-23 12:53:11 -0500233 }
234}
235
Gunnar Mills392f2942017-04-12 11:04:37 -0500236} // namespace manager
237} // namespace software
Gunnar Millsfa34e022018-09-04 10:05:45 -0500238} // namespace phosphor