blob: 8eaf21d82de75918488e4d5d5500e2425527c935 [file] [log] [blame]
Lei YU322f3f42019-02-21 16:10:41 +08001#include "config.h"
2
3#include "item_updater_static.hpp"
4
Lei YUb53425d2019-02-22 11:38:40 +08005#include "activation_static.hpp"
Lei YUdec8cf92019-02-21 17:47:05 +08006#include "version.hpp"
7
8#include <cstring>
9#include <filesystem>
10#include <fstream>
11#include <phosphor-logging/elog-errors.hpp>
12#include <phosphor-logging/log.hpp>
Lei YUa2e67162019-02-22 17:35:24 +080013#include <sstream>
Lei YUdec8cf92019-02-21 17:47:05 +080014#include <string>
15
16using namespace sdbusplus::xyz::openbmc_project::Common::Error;
17using namespace phosphor::logging;
18
19// When you see server:: you know we're referencing our base class
20namespace server = sdbusplus::xyz::openbmc_project::Software::server;
21namespace fs = std::filesystem;
22
23namespace utils
24{
25
26template <typename... Ts>
27std::string concat_string(Ts const&... ts)
28{
29 std::stringstream s;
30 ((s << ts << " "), ...) << std::endl;
31 return s.str();
32}
33
34// Helper function to run pflash command
35template <typename... Ts>
36std::string pflash(Ts const&... ts)
37{
38 std::array<char, 512> buffer;
39 std::string cmd = concat_string("pflash", ts...);
40 std::stringstream result;
41 std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"),
42 pclose);
43 if (!pipe)
44 {
45 throw std::runtime_error("popen() failed!");
46 }
47 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
48 {
49 result << buffer.data();
50 }
51 return result.str();
52}
53
54std::string getPNORVersion()
55{
56 // A signed version partition will have an extra 4K header starting with
57 // the magic number 17082011 in big endian:
58 // https://github.com/open-power/skiboot/blob/master/libstb/container.h#L47
59
60 constexpr uint8_t MAGIC[] = {0x17, 0x08, 0x20, 0x11};
61 constexpr auto MAGIC_SIZE = sizeof(MAGIC);
62 static_assert(MAGIC_SIZE == 4);
63
64 auto tmp = fs::temp_directory_path();
65 std::string tmpDir(tmp / "versionXXXXXX");
66 if (!mkdtemp(tmpDir.data()))
67 {
68 log<level::ERR>("Failed to create temp dir");
69 return {};
70 }
71
72 fs::path versionFile = tmpDir;
73 versionFile /= "version";
74
75 pflash("-P VERSION -r", versionFile.string(), "2>&1 > /dev/null");
76 std::ifstream f(versionFile.c_str(), std::ios::in | std::ios::binary);
77 uint8_t magic[MAGIC_SIZE];
78 std::string version;
79
80 f.read(reinterpret_cast<char*>(magic), MAGIC_SIZE);
81 f.seekg(0, std::ios::beg);
82 if (std::memcmp(magic, MAGIC, MAGIC_SIZE) == 0)
83 {
84 // Skip the first 4K header
85 f.ignore(4096);
86 }
87
88 getline(f, version, '\0');
89 f.close();
90
91 // Clear the temp dir
92 std::error_code ec;
93 fs::remove_all(tmpDir, ec);
94 if (ec)
95 {
96 log<level::ERR>("Failed to remove temp dir",
97 entry("DIR=%s", tmpDir.c_str()),
98 entry("ERR=%s", ec.message().c_str()));
99 }
100
101 return version;
102}
103
104} // namespace utils
105
Lei YU322f3f42019-02-21 16:10:41 +0800106namespace openpower
107{
108namespace software
109{
110namespace updater
111{
Lei YU322f3f42019-02-21 16:10:41 +0800112std::unique_ptr<Activation> ItemUpdaterStatic::createActivationObject(
113 const std::string& path, const std::string& versionId,
114 const std::string& extVersion,
115 sdbusplus::xyz::openbmc_project::Software::server::Activation::Activations
116 activationStatus,
117 AssociationList& assocs)
118{
Lei YUb53425d2019-02-22 11:38:40 +0800119 return std::make_unique<ActivationStatic>(
120 bus, path, *this, versionId, extVersion, activationStatus, assocs);
Lei YU322f3f42019-02-21 16:10:41 +0800121}
122
123std::unique_ptr<Version> ItemUpdaterStatic::createVersionObject(
124 const std::string& objPath, const std::string& versionId,
125 const std::string& versionString,
126 sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
127 versionPurpose,
128 const std::string& filePath)
129{
Lei YUb53425d2019-02-22 11:38:40 +0800130 auto version = std::make_unique<Version>(
131 bus, objPath, *this, versionId, versionString, versionPurpose, filePath,
132 std::bind(&ItemUpdaterStatic::erase, this, std::placeholders::_1));
133 version->deleteObject = std::make_unique<Delete>(bus, objPath, *version);
134 return version;
Lei YU322f3f42019-02-21 16:10:41 +0800135}
136
137bool ItemUpdaterStatic::validateImage(const std::string& path)
138{
Lei YUb53425d2019-02-22 11:38:40 +0800139 // There is no need to validate static layout pnor
Lei YU322f3f42019-02-21 16:10:41 +0800140 return true;
141}
142
143void ItemUpdaterStatic::processPNORImage()
144{
Lei YUdec8cf92019-02-21 17:47:05 +0800145 auto fullVersion = utils::getPNORVersion();
146
147 const auto& [version, extendedVersion] = Version::getVersions(fullVersion);
148 auto id = Version::getId(version);
149
150 auto activationState = server::Activation::Activations::Active;
151 if (version.empty())
152 {
153 log<level::ERR>("Failed to read version",
154 entry("VERSION=%s", fullVersion.c_str()));
155 activationState = server::Activation::Activations::Invalid;
156 }
157
158 if (extendedVersion.empty())
159 {
160 log<level::ERR>("Failed to read extendedVersion",
161 entry("VERSION=%s", fullVersion.c_str()));
162 activationState = server::Activation::Activations::Invalid;
163 }
164
165 auto purpose = server::Version::VersionPurpose::Host;
166 auto path = fs::path(SOFTWARE_OBJPATH) / id;
167 AssociationList associations = {};
168
169 if (activationState == server::Activation::Activations::Active)
170 {
171 // Create an association to the host inventory item
172 associations.emplace_back(std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
173 ACTIVATION_REV_ASSOCIATION,
174 HOST_INVENTORY_PATH));
175
176 // Create an active association since this image is active
177 createActiveAssociation(path);
178 }
179
Lei YUb53425d2019-02-22 11:38:40 +0800180 // Create Activation instance for this version.
181 activations.insert(std::make_pair(
182 id, std::make_unique<ActivationStatic>(bus, path, *this, id,
183 extendedVersion, activationState,
184 associations)));
185
186 // If Active, create RedundancyPriority instance for this version.
187 if (activationState == server::Activation::Activations::Active)
188 {
189 // For now only one PNOR is supported with static layout
190 activations.find(id)->second->redundancyPriority =
191 std::make_unique<RedundancyPriority>(
192 bus, path, *(activations.find(id)->second), 0);
193 }
194
Lei YUdec8cf92019-02-21 17:47:05 +0800195 // Create Version instance for this version.
196 auto versionPtr = std::make_unique<Version>(
197 bus, path, *this, id, version, purpose, "",
198 std::bind(&ItemUpdaterStatic::erase, this, std::placeholders::_1));
199 versionPtr->deleteObject = std::make_unique<Delete>(bus, path, *versionPtr);
200 versions.insert(std::make_pair(id, std::move(versionPtr)));
201
202 if (!id.empty())
203 {
204 updateFunctionalAssociation(id);
205 }
Lei YU322f3f42019-02-21 16:10:41 +0800206}
207
208void ItemUpdaterStatic::reset()
209{
210}
211
212bool ItemUpdaterStatic::isVersionFunctional(const std::string& versionId)
213{
Lei YUa2e67162019-02-22 17:35:24 +0800214 return versionId == functionalVersionId;
Lei YU322f3f42019-02-21 16:10:41 +0800215}
216
217void ItemUpdaterStatic::freePriority(uint8_t value,
218 const std::string& versionId)
219{
220}
221
222void ItemUpdaterStatic::deleteAll()
223{
Lei YUa2e67162019-02-22 17:35:24 +0800224 // Static layout has only one active and function pnor
225 // There is no implementation for this interface
Lei YU322f3f42019-02-21 16:10:41 +0800226}
227
228void ItemUpdaterStatic::freeSpace()
229{
Lei YUa2e67162019-02-22 17:35:24 +0800230 // For now assume static layout only has 1 active PNOR,
231 // so erase the active PNOR
232 for (const auto& iter : activations)
233 {
234 if (iter.second.get()->activation() ==
235 server::Activation::Activations::Active)
236 {
237 erase(iter.second->versionId);
238 break;
239 }
240 }
241}
242
243void ItemUpdaterStatic::updateFunctionalAssociation(
244 const std::string& versionId)
245{
246 functionalVersionId = versionId;
247 ItemUpdater::updateFunctionalAssociation(versionId);
Lei YU322f3f42019-02-21 16:10:41 +0800248}
249
250void GardReset::reset()
251{
252}
253
254} // namespace updater
255} // namespace software
256} // namespace openpower