blob: ed447f8357b5421452d2678983230297f3d63a50 [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
Patrick Williamsfc33ba82024-08-16 15:19:54 -040046std::vector<std::string> Version::getRepeatedValues(
47 const std::string& manifestFilePath, std::string key)
Justin Ledford054bb0b2022-03-15 15:46:58 -070048{
Gunnar Millscebd1022017-04-17 16:10:15 -050049 key = key + "=";
50 auto keySize = key.length();
Gunnar Mills392f2942017-04-12 11:04:37 -050051
52 if (manifestFilePath.empty())
53 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -050054 error("ManifestFilePath is empty.");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -050055 elog<InvalidArgument>(
Adriana Kobylak2285fe02018-02-27 15:36:59 -060056 Argument::ARGUMENT_NAME("manifestFilePath"),
57 Argument::ARGUMENT_VALUE(manifestFilePath.c_str()));
Gunnar Mills392f2942017-04-12 11:04:37 -050058 }
59
Justin Ledford054bb0b2022-03-15 15:46:58 -070060 std::vector<std::string> values{};
Gunnar Mills392f2942017-04-12 11:04:37 -050061 std::ifstream efile;
62 std::string line;
Justin Ledford054bb0b2022-03-15 15:46:58 -070063 efile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
Gunnar Mills392f2942017-04-12 11:04:37 -050064
65 // Too many GCC bugs (53984, 66145) to do this the right way...
66 try
67 {
68 efile.open(manifestFilePath);
69 while (getline(efile, line))
70 {
Lei YU5a7363b2019-10-18 16:50:59 +080071 if (!line.empty() && line.back() == '\r')
72 {
73 // If the manifest has CRLF line terminators, e.g. is created on
74 // Windows, the line will contain \r at the end, remove it.
75 line.pop_back();
76 }
Gunnar Millscebd1022017-04-17 16:10:15 -050077 if (line.compare(0, keySize, key) == 0)
Gunnar Mills392f2942017-04-12 11:04:37 -050078 {
Justin Ledford054bb0b2022-03-15 15:46:58 -070079 values.push_back(line.substr(keySize));
Gunnar Mills392f2942017-04-12 11:04:37 -050080 }
81 }
82 efile.close();
83 }
84 catch (const std::exception& e)
85 {
Justin Ledford054bb0b2022-03-15 15:46:58 -070086 if (!efile.eof())
87 {
88 error("Error occurred when reading MANIFEST file: {ERROR}", "KEY",
89 key, "ERROR", e);
90 }
Gunnar Mills392f2942017-04-12 11:04:37 -050091 }
92
Justin Ledford054bb0b2022-03-15 15:46:58 -070093 if (values.empty())
94 {
Adriana Kobylaka1c032e2022-06-14 18:49:48 +000095 info("No values found in MANIFEST file for key: {KEY}", "KEY", key);
Justin Ledford054bb0b2022-03-15 15:46:58 -070096 }
97
98 return values;
Gunnar Mills392f2942017-04-12 11:04:37 -050099}
100
Patrick Williams564bc902021-12-08 10:17:23 -0600101using EVP_MD_CTX_Ptr =
102 std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_free)>;
103
Gunnar Mills392f2942017-04-12 11:04:37 -0500104std::string Version::getId(const std::string& version)
105{
Gunnar Mills392f2942017-04-12 11:04:37 -0500106 if (version.empty())
107 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500108 error("Version is empty.");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -0500109 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Version"),
110 Argument::ARGUMENT_VALUE(version.c_str()));
Gunnar Mills392f2942017-04-12 11:04:37 -0500111 }
112
Patrick Williams564bc902021-12-08 10:17:23 -0600113 std::array<unsigned char, EVP_MAX_MD_SIZE> digest{};
114 EVP_MD_CTX_Ptr ctx(EVP_MD_CTX_new(), &::EVP_MD_CTX_free);
Saqib Khan26a960d2017-09-19 14:23:28 -0500115
Patrick Williams564bc902021-12-08 10:17:23 -0600116 EVP_DigestInit(ctx.get(), EVP_sha512());
117 EVP_DigestUpdate(ctx.get(), version.c_str(), strlen(version.c_str()));
118 EVP_DigestFinal(ctx.get(), digest.data(), nullptr);
119
120 // We are only using the first 8 characters.
121 char mdString[9];
122 snprintf(mdString, sizeof(mdString), "%02x%02x%02x%02x",
123 (unsigned int)digest[0], (unsigned int)digest[1],
124 (unsigned int)digest[2], (unsigned int)digest[3]);
125
126 return mdString;
Gunnar Mills392f2942017-04-12 11:04:37 -0500127}
128
Vijay Khemkab7c062e2019-09-18 17:15:57 -0700129std::string Version::getBMCMachine(const std::string& releaseFilePath)
130{
131 std::string machineKey = "OPENBMC_TARGET_MACHINE=";
132 std::string machine{};
133 std::ifstream efile(releaseFilePath);
134 std::string line;
135
136 while (getline(efile, line))
137 {
138 if (line.substr(0, machineKey.size()).find(machineKey) !=
139 std::string::npos)
140 {
141 std::size_t pos = line.find_first_of('"') + 1;
142 machine = line.substr(pos, line.find_last_of('"') - pos);
143 break;
144 }
145 }
146
147 if (machine.empty())
148 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500149 error("Unable to find OPENBMC_TARGET_MACHINE");
Vijay Khemkab7c062e2019-09-18 17:15:57 -0700150 elog<InternalFailure>();
151 }
152
153 return machine;
154}
155
Chanh Nguyen1fd6ddd2021-01-06 11:09:09 +0700156std::string Version::getBMCExtendedVersion(const std::string& releaseFilePath)
157{
158 std::string extendedVersionKey = "EXTENDED_VERSION=";
159 std::string extendedVersionValue{};
160 std::string extendedVersion{};
161 std::ifstream efile(releaseFilePath);
162 std::string line;
163
164 while (getline(efile, line))
165 {
166 if (line.substr(0, extendedVersionKey.size())
167 .find(extendedVersionKey) != std::string::npos)
168 {
169 extendedVersionValue = line.substr(extendedVersionKey.size());
170 std::size_t pos = extendedVersionValue.find_first_of('"') + 1;
171 extendedVersion = extendedVersionValue.substr(
172 pos, extendedVersionValue.find_last_of('"') - pos);
173 break;
174 }
175 }
176
177 return extendedVersion;
178}
179
Saqib Khan1eef62d2017-08-10 15:29:34 -0500180std::string Version::getBMCVersion(const std::string& releaseFilePath)
Saqib Khanba239882017-05-26 08:41:54 -0500181{
182 std::string versionKey = "VERSION_ID=";
Adriana Kobylak2a3d9f52020-05-06 10:46:32 -0500183 std::string versionValue{};
Saqib Khanba239882017-05-26 08:41:54 -0500184 std::string version{};
185 std::ifstream efile;
186 std::string line;
Saqib Khan1eef62d2017-08-10 15:29:34 -0500187 efile.open(releaseFilePath);
Saqib Khanba239882017-05-26 08:41:54 -0500188
189 while (getline(efile, line))
190 {
191 if (line.substr(0, versionKey.size()).find(versionKey) !=
192 std::string::npos)
193 {
Adriana Kobylak2a3d9f52020-05-06 10:46:32 -0500194 // Support quoted and unquoted values
195 // 1. Remove the versionKey so that we process the value only.
196 versionValue = line.substr(versionKey.size());
197
198 // 2. Look for a starting quote, then increment the position by 1 to
199 // skip the quote character. If no quote is found,
200 // find_first_of() returns npos (-1), which by adding +1 sets pos
201 // to 0 (beginning of unquoted string).
202 std::size_t pos = versionValue.find_first_of('"') + 1;
203
204 // 3. Look for ending quote, then decrease the position by pos to
205 // get the size of the string up to before the ending quote. If
206 // no quote is found, find_last_of() returns npos (-1), and pos
207 // is 0 for the unquoted case, so substr() is called with a len
208 // parameter of npos (-1) which according to the documentation
209 // indicates to use all characters until the end of the string.
Patrick Williamsfc33ba82024-08-16 15:19:54 -0400210 version =
211 versionValue.substr(pos, versionValue.find_last_of('"') - pos);
Saqib Khanba239882017-05-26 08:41:54 -0500212 break;
213 }
214 }
215 efile.close();
216
217 if (version.empty())
218 {
Patrick Williamsc9bb6422021-08-27 06:18:35 -0500219 error("BMC current version is empty");
Gunnar Millsaae1b2b2017-10-06 13:42:39 -0500220 elog<InternalFailure>();
Saqib Khanba239882017-05-26 08:41:54 -0500221 }
222
223 return version;
224}
225
Saqib Khanee13e832017-10-23 12:53:11 -0500226void Delete::delete_()
227{
228 if (parent.eraseCallback)
229 {
Adriana Kobylak59b640b2022-01-21 19:45:22 +0000230 parent.eraseCallback(parent.id);
Saqib Khanee13e832017-10-23 12:53:11 -0500231 }
232}
233
Gunnar Mills392f2942017-04-12 11:04:37 -0500234} // namespace manager
235} // namespace software
Gunnar Millsfa34e022018-09-04 10:05:45 -0500236} // namespace phosphor