blob: 5937e13eb9a2dbd48ba0cc4c93f85b4177a71873 [file] [log] [blame]
Lei YU322f3f42019-02-21 16:10:41 +08001#include "config.h"
2
3#include "item_updater_static.hpp"
4
Lei YUdec8cf92019-02-21 17:47:05 +08005#include "activation.hpp"
6#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{
118 return {};
119}
120
121std::unique_ptr<Version> ItemUpdaterStatic::createVersionObject(
122 const std::string& objPath, const std::string& versionId,
123 const std::string& versionString,
124 sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
125 versionPurpose,
126 const std::string& filePath)
127{
128 return {};
129}
130
131bool ItemUpdaterStatic::validateImage(const std::string& path)
132{
133 return true;
134}
135
136void ItemUpdaterStatic::processPNORImage()
137{
Lei YUdec8cf92019-02-21 17:47:05 +0800138 auto fullVersion = utils::getPNORVersion();
139
140 const auto& [version, extendedVersion] = Version::getVersions(fullVersion);
141 auto id = Version::getId(version);
142
143 auto activationState = server::Activation::Activations::Active;
144 if (version.empty())
145 {
146 log<level::ERR>("Failed to read version",
147 entry("VERSION=%s", fullVersion.c_str()));
148 activationState = server::Activation::Activations::Invalid;
149 }
150
151 if (extendedVersion.empty())
152 {
153 log<level::ERR>("Failed to read extendedVersion",
154 entry("VERSION=%s", fullVersion.c_str()));
155 activationState = server::Activation::Activations::Invalid;
156 }
157
158 auto purpose = server::Version::VersionPurpose::Host;
159 auto path = fs::path(SOFTWARE_OBJPATH) / id;
160 AssociationList associations = {};
161
162 if (activationState == server::Activation::Activations::Active)
163 {
164 // Create an association to the host inventory item
165 associations.emplace_back(std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
166 ACTIVATION_REV_ASSOCIATION,
167 HOST_INVENTORY_PATH));
168
169 // Create an active association since this image is active
170 createActiveAssociation(path);
171 }
172
173 // Create Version instance for this version.
174 auto versionPtr = std::make_unique<Version>(
175 bus, path, *this, id, version, purpose, "",
176 std::bind(&ItemUpdaterStatic::erase, this, std::placeholders::_1));
177 versionPtr->deleteObject = std::make_unique<Delete>(bus, path, *versionPtr);
178 versions.insert(std::make_pair(id, std::move(versionPtr)));
179
180 if (!id.empty())
181 {
182 updateFunctionalAssociation(id);
183 }
Lei YU322f3f42019-02-21 16:10:41 +0800184}
185
186void ItemUpdaterStatic::reset()
187{
188}
189
190bool ItemUpdaterStatic::isVersionFunctional(const std::string& versionId)
191{
192 return true;
193}
194
195void ItemUpdaterStatic::freePriority(uint8_t value,
196 const std::string& versionId)
197{
198}
199
200void ItemUpdaterStatic::deleteAll()
201{
202}
203
204void ItemUpdaterStatic::freeSpace()
205{
206}
207
208void GardReset::reset()
209{
210}
211
212} // namespace updater
213} // namespace software
214} // namespace openpower