blob: 54b8c27a711b286ec7d6636772e07f398b596183 [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;
Adriana Kobylakce82de52024-01-16 13:56:38 -060027using Argument = xyz::openbmc_project::common::InvalidArgument;
28using namespace sdbusplus::error::xyz::openbmc_project::common;
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 {
Adriana Kobylaka1c032e2022-06-14 18:49:48 +000096 info("No values found in MANIFEST file for key: {KEY}", "KEY", key);
Justin Ledford054bb0b2022-03-15 15:46:58 -070097 }
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 if (version.empty())
108 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500109 error("Version is empty.");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -0500110 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Version"),
111 Argument::ARGUMENT_VALUE(version.c_str()));
Gunnar Mills392f2942017-04-12 11:04:37 -0500112 }
113
Patrick Williams564bc902021-12-08 10:17:23 -0600114 std::array<unsigned char, EVP_MAX_MD_SIZE> digest{};
115 EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_new(), &::EVP_MD_CTX_free);
Saqib Khan26a960d2017-09-19 14:23:28 -0500116
Patrick Williams564bc902021-12-08 10:17:23 -0600117 EVP_DigestInit(ctx.get(), EVP_sha512());
118 EVP_DigestUpdate(ctx.get(), version.c_str(), strlen(version.c_str()));
119 EVP_DigestFinal(ctx.get(), digest.data(), nullptr);
120
121 // We are only using the first 8 characters.
122 char mdString[9];
123 snprintf(mdString, sizeof(mdString), "%02x%02x%02x%02x",
124 (unsigned int)digest[0], (unsigned int)digest[1],
125 (unsigned int)digest[2], (unsigned int)digest[3]);
126
127 return mdString;
Gunnar Mills392f2942017-04-12 11:04:37 -0500128}
129
Vijay Khemkab7c062e2019-09-18 17:15:57 -0700130std::string Version::getBMCMachine(const std::string& releaseFilePath)
131{
132 std::string machineKey = "OPENBMC_TARGET_MACHINE=";
133 std::string machine{};
134 std::ifstream efile(releaseFilePath);
135 std::string line;
136
137 while (getline(efile, line))
138 {
139 if (line.substr(0, machineKey.size()).find(machineKey) !=
140 std::string::npos)
141 {
142 std::size_t pos = line.find_first_of('"') + 1;
143 machine = line.substr(pos, line.find_last_of('"') - pos);
144 break;
145 }
146 }
147
148 if (machine.empty())
149 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500150 error("Unable to find OPENBMC_TARGET_MACHINE");
Vijay Khemkab7c062e2019-09-18 17:15:57 -0700151 elog<InternalFailure>();
152 }
153
154 return machine;
155}
156
Chanh Nguyen1fd6ddd2021-01-06 11:09:09 +0700157std::string Version::getBMCExtendedVersion(const std::string& releaseFilePath)
158{
159 std::string extendedVersionKey = "EXTENDED_VERSION=";
160 std::string extendedVersionValue{};
161 std::string extendedVersion{};
162 std::ifstream efile(releaseFilePath);
163 std::string line;
164
165 while (getline(efile, line))
166 {
167 if (line.substr(0, extendedVersionKey.size())
168 .find(extendedVersionKey) != std::string::npos)
169 {
170 extendedVersionValue = line.substr(extendedVersionKey.size());
171 std::size_t pos = extendedVersionValue.find_first_of('"') + 1;
172 extendedVersion = extendedVersionValue.substr(
173 pos, extendedVersionValue.find_last_of('"') - pos);
174 break;
175 }
176 }
177
178 return extendedVersion;
179}
180
Saqib Khan1eef62d2017-08-10 15:29:34 -0500181std::string Version::getBMCVersion(const std::string& releaseFilePath)
Saqib Khanba239882017-05-26 08:41:54 -0500182{
183 std::string versionKey = "VERSION_ID=";
Adriana Kobylak2a3d9f52020-05-06 10:46:32 -0500184 std::string versionValue{};
Saqib Khanba239882017-05-26 08:41:54 -0500185 std::string version{};
186 std::ifstream efile;
187 std::string line;
Saqib Khan1eef62d2017-08-10 15:29:34 -0500188 efile.open(releaseFilePath);
Saqib Khanba239882017-05-26 08:41:54 -0500189
190 while (getline(efile, line))
191 {
192 if (line.substr(0, versionKey.size()).find(versionKey) !=
193 std::string::npos)
194 {
Adriana Kobylak2a3d9f52020-05-06 10:46:32 -0500195 // Support quoted and unquoted values
196 // 1. Remove the versionKey so that we process the value only.
197 versionValue = line.substr(versionKey.size());
198
199 // 2. Look for a starting quote, then increment the position by 1 to
200 // skip the quote character. If no quote is found,
201 // find_first_of() returns npos (-1), which by adding +1 sets pos
202 // to 0 (beginning of unquoted string).
203 std::size_t pos = versionValue.find_first_of('"') + 1;
204
205 // 3. Look for ending quote, then decrease the position by pos to
206 // get the size of the string up to before the ending quote. If
207 // no quote is found, find_last_of() returns npos (-1), and pos
208 // is 0 for the unquoted case, so substr() is called with a len
209 // parameter of npos (-1) which according to the documentation
210 // indicates to use all characters until the end of the string.
Patrick Williamsd5e8e732023-05-10 07:50:18 -0500211 version = versionValue.substr(pos,
212 versionValue.find_last_of('"') - pos);
Saqib Khanba239882017-05-26 08:41:54 -0500213 break;
214 }
215 }
216 efile.close();
217
218 if (version.empty())
219 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500220 error("BMC current version is empty");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -0500221 elog<InternalFailure>();
Saqib Khanba239882017-05-26 08:41:54 -0500222 }
223
224 return version;
225}
226
Saqib Khanee13e832017-10-23 12:53:11 -0500227void Delete::delete_()
228{
229 if (parent.eraseCallback)
230 {
Adriana Kobylak59b640b2022-01-21 19:45:22 +0000231 parent.eraseCallback(parent.id);
Saqib Khanee13e832017-10-23 12:53:11 -0500232 }
233}
234
Gunnar Mills392f2942017-04-12 11:04:37 -0500235} // namespace manager
236} // namespace software
Gunnar Millsfa34e022018-09-04 10:05:45 -0500237} // namespace phosphor