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