blob: 04a9eb467339c2428250843ee5267eb5f2105996 [file] [log] [blame]
Saqib Khan35e83f32017-05-22 11:37:32 -05001#include <fstream>
Gunnar Millsec1b41c2017-05-02 12:20:36 -05002#include <string>
Gunnar Mills2ce7da22017-05-04 15:37:56 -05003#include <phosphor-logging/log.hpp>
Gunnar Millsec1b41c2017-05-02 12:20:36 -05004#include "config.h"
Gunnar Mills2ce7da22017-05-04 15:37:56 -05005#include "item_updater.hpp"
6#include "xyz/openbmc_project/Software/Version/server.hpp"
Saqib Khan35e83f32017-05-22 11:37:32 -05007#include <experimental/filesystem>
Saqib Khan705f1bf2017-06-09 23:58:38 -05008#include "version.hpp"
Gunnar Millsec1b41c2017-05-02 12:20:36 -05009
10namespace phosphor
11{
12namespace software
13{
14namespace updater
15{
16
Gunnar Mills2ce7da22017-05-04 15:37:56 -050017// When you see server:: you know we're referencing our base class
18namespace server = sdbusplus::xyz::openbmc_project::Software::server;
19
20using namespace phosphor::logging;
Saqib Khan35e83f32017-05-22 11:37:32 -050021namespace fs = std::experimental::filesystem;
22
23constexpr auto bmcImage = "image-rofs";
Gunnar Mills2ce7da22017-05-04 15:37:56 -050024
Michael Tritz37a59042017-07-12 13:44:53 -050025constexpr auto SYSTEMD_BUSNAME = "org.freedesktop.systemd1";
26constexpr auto SYSTEMD_PATH = "/org/freedesktop/systemd1";
27constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
28
Patrick Williamse75d10f2017-05-30 16:56:32 -050029void ItemUpdater::createActivation(sdbusplus::message::message& msg)
Gunnar Millsec1b41c2017-05-02 12:20:36 -050030{
Saqib Khan84a0e692017-06-28 17:27:01 -050031
32 using SVersion = server::Version;
33 using VersionPurpose = SVersion::VersionPurpose;
34 namespace mesg = sdbusplus::message;
35 namespace variant_ns = mesg::variant_ns;
36
37 mesg::object_path objPath;
38 auto purpose = VersionPurpose::Unknown;
Saqib Khan705f1bf2017-06-09 23:58:38 -050039 std::string version;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050040 std::map<std::string,
Patrick Williamse75d10f2017-05-30 16:56:32 -050041 std::map<std::string,
Saqib Khan84a0e692017-06-28 17:27:01 -050042 mesg::variant<std::string>>> interfaces;
Patrick Williamse75d10f2017-05-30 16:56:32 -050043 msg.read(objPath, interfaces);
Gunnar Mills2ce7da22017-05-04 15:37:56 -050044 std::string path(std::move(objPath));
Saqib Khan19177d32017-06-20 08:11:49 -050045 std::string filePath;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050046
47 for (const auto& intf : interfaces)
48 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050049 if (intf.first == VERSION_IFACE)
Gunnar Mills2ce7da22017-05-04 15:37:56 -050050 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050051 for (const auto& property : intf.second)
Gunnar Mills2ce7da22017-05-04 15:37:56 -050052 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050053 if (property.first == "Purpose")
Gunnar Mills2ce7da22017-05-04 15:37:56 -050054 {
Saqib Khan84a0e692017-06-28 17:27:01 -050055 auto value = SVersion::convertVersionPurposeFromString(
56 variant_ns::get<std::string>(property.second));
57 if (value == VersionPurpose::BMC ||
58 value == VersionPurpose::System)
59 {
60 purpose = value;
61 }
Saqib Khan705f1bf2017-06-09 23:58:38 -050062 }
63 else if (property.first == "Version")
64 {
Saqib Khan84a0e692017-06-28 17:27:01 -050065 version = variant_ns::get<std::string>(property.second);
Gunnar Mills2ce7da22017-05-04 15:37:56 -050066 }
67 }
68 }
Saqib Khan19177d32017-06-20 08:11:49 -050069 else if (intf.first == FILEPATH_IFACE)
70 {
71 for (const auto& property : intf.second)
72 {
73 if (property.first == "Path")
74 {
Saqib Khan84a0e692017-06-28 17:27:01 -050075 filePath = variant_ns::get<std::string>(property.second);
Saqib Khan19177d32017-06-20 08:11:49 -050076 }
77 }
78 }
Gunnar Mills2ce7da22017-05-04 15:37:56 -050079 }
Saqib Khan705f1bf2017-06-09 23:58:38 -050080 if (version.empty() ||
Saqib Khan19177d32017-06-20 08:11:49 -050081 filePath.empty() ||
Saqib Khan84a0e692017-06-28 17:27:01 -050082 purpose == VersionPurpose::Unknown)
Saqib Khan705f1bf2017-06-09 23:58:38 -050083 {
84 return;
85 }
Gunnar Mills2ce7da22017-05-04 15:37:56 -050086
87 // Version id is the last item in the path
88 auto pos = path.rfind("/");
89 if (pos == std::string::npos)
90 {
91 log<level::ERR>("No version id found in object path",
92 entry("OBJPATH=%s", path));
Patrick Williamse75d10f2017-05-30 16:56:32 -050093 return;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050094 }
95
96 auto versionId = path.substr(pos + 1);
97
Patrick Williamse75d10f2017-05-30 16:56:32 -050098 if (activations.find(versionId) == activations.end())
Gunnar Mills2ce7da22017-05-04 15:37:56 -050099 {
Saqib Khan35e83f32017-05-22 11:37:32 -0500100 // Determine the Activation state by processing the given image dir.
101 auto activationState = server::Activation::Activations::Invalid;
102 ItemUpdater::ActivationStatus result = ItemUpdater::
Saqib Khan19177d32017-06-20 08:11:49 -0500103 validateSquashFSImage(filePath);
Saqib Khan35e83f32017-05-22 11:37:32 -0500104 if (result == ItemUpdater::ActivationStatus::ready)
105 {
106 activationState = server::Activation::Activations::Ready;
107 }
Saqib Khan35e83f32017-05-22 11:37:32 -0500108 activations.insert(std::make_pair(
Saqib Khan705f1bf2017-06-09 23:58:38 -0500109 versionId,
110 std::make_unique<Activation>(
111 bus,
112 path,
Saqib Khan4c1aec02017-07-06 11:46:13 -0500113 *this,
Saqib Khan35e83f32017-05-22 11:37:32 -0500114 versionId,
Saqib Khan705f1bf2017-06-09 23:58:38 -0500115 activationState)));
116 versions.insert(std::make_pair(
117 versionId,
118 std::make_unique<phosphor::software::
119 manager::Version>(
120 bus,
121 path,
122 version,
123 purpose,
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500124 filePath,
125 std::bind(&ItemUpdater::erase,
126 this,
127 std::placeholders::_1))));
Gunnar Mills2ce7da22017-05-04 15:37:56 -0500128 }
Patrick Williamse75d10f2017-05-30 16:56:32 -0500129 return;
Gunnar Millsec1b41c2017-05-02 12:20:36 -0500130}
131
Saqib Khanba239882017-05-26 08:41:54 -0500132void ItemUpdater::processBMCImage()
133{
134 auto purpose = server::Version::VersionPurpose::BMC;
135 auto version = phosphor::software::manager::Version::getBMCVersion();
136 auto id = phosphor::software::manager::Version::getId(version);
137 auto path = std::string{SOFTWARE_OBJPATH} + '/' + id;
138 activations.insert(std::make_pair(
139 id,
140 std::make_unique<Activation>(
141 bus,
142 path,
Saqib Khan4c1aec02017-07-06 11:46:13 -0500143 *this,
Saqib Khanba239882017-05-26 08:41:54 -0500144 id,
145 server::Activation::Activations::Active)));
146 versions.insert(std::make_pair(
147 id,
148 std::make_unique<phosphor::software::
149 manager::Version>(
150 bus,
151 path,
152 version,
153 purpose,
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500154 "",
155 std::bind(&ItemUpdater::erase,
156 this,
157 std::placeholders::_1))));
158
Saqib Khanba239882017-05-26 08:41:54 -0500159 return;
160}
161
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500162void ItemUpdater::erase(std::string entryId)
163{
164 // Delete ReadWrite and ReadOnly partitions
165 removeReadWritePartition(entryId);
166 removeReadOnlyPartition(entryId);
167
168 // Removing entry in versions map
169 auto it = versions.find(entryId);
170 if (it == versions.end())
171 {
172 log<level::ERR>(("Error: Failed to find version " + entryId + \
173 " in item updater versions map." \
174 " Unable to remove.").c_str());
175 return;
176 }
177 this->versions.erase(entryId);
178
179 // Removing entry in activations map
180 auto ita = activations.find(entryId);
181 if (ita == activations.end())
182 {
183 log<level::ERR>(("Error: Failed to find version " + entryId + \
184 " in item updater activations map." \
185 " Unable to remove.").c_str());
186 return;
187 }
188 // TODO: openbmc/openbmc#1986
189 // Test if this is the currently running image
190 // If not, don't continue.
191
192 this->activations.erase(entryId);
193}
194
Saqib Khan35e83f32017-05-22 11:37:32 -0500195ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage(
Saqib Khan19177d32017-06-20 08:11:49 -0500196 const std::string& filePath)
Saqib Khan35e83f32017-05-22 11:37:32 -0500197{
198
Saqib Khan19177d32017-06-20 08:11:49 -0500199 fs::path file(filePath);
Saqib Khan35e83f32017-05-22 11:37:32 -0500200 file /= bmcImage;
201 std::ifstream efile(file.c_str());
202
203 if (efile.good() == 1)
204 {
205 return ItemUpdater::ActivationStatus::ready;
206 }
207 else
208 {
Saqib Khan19177d32017-06-20 08:11:49 -0500209 log<level::ERR>("Failed to find the BMC image.");
Saqib Khan35e83f32017-05-22 11:37:32 -0500210 return ItemUpdater::ActivationStatus::invalid;
211 }
212}
213
Saqib Khan4c1aec02017-07-06 11:46:13 -0500214void ItemUpdater::freePriority(uint8_t value)
215{
216 //TODO openbmc/openbmc#1896 Improve the performance of this function
217 for (const auto& intf : activations)
218 {
219 if(intf.second->redundancyPriority)
220 {
221 if (intf.second->redundancyPriority.get()->priority() == value)
222 {
223 intf.second->redundancyPriority.get()->priority(value+1);
224 }
225 }
226 }
227}
228
Michael Tritz37a59042017-07-12 13:44:53 -0500229void ItemUpdater::reset()
230{
231 // Mark the read-write partition for recreation upon reboot.
232 auto method = bus.new_method_call(
233 SYSTEMD_BUSNAME,
234 SYSTEMD_PATH,
235 SYSTEMD_INTERFACE,
236 "StartUnit");
237 method.append("obmc-flash-bmc-setenv@rwreset=true.service", "replace");
238 bus.call_noreply(method);
239
240 log<level::INFO>("BMC factory reset will take effect upon reboot.");
241
242 return;
243}
244
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500245void ItemUpdater::removeReadOnlyPartition(std::string versionId)
246{
247 auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId +
248 ".service";
249
250 // Remove the read-only partitions.
251 auto method = bus.new_method_call(
252 SYSTEMD_BUSNAME,
253 SYSTEMD_PATH,
254 SYSTEMD_INTERFACE,
255 "StartUnit");
256 method.append(serviceFile, "replace");
257 bus.call_noreply(method);
258}
259
260void ItemUpdater::removeReadWritePartition(std::string versionId)
261{
262 auto serviceFile = "obmc-flash-bmc-ubirw-remove.service";
263
264 // Remove the read-write partitions.
265 auto method = bus.new_method_call(
266 SYSTEMD_BUSNAME,
267 SYSTEMD_PATH,
268 SYSTEMD_INTERFACE,
269 "StartUnit");
270 method.append(serviceFile, "replace");
271 bus.call_noreply(method);
272}
273
Gunnar Millsec1b41c2017-05-02 12:20:36 -0500274} // namespace updater
275} // namespace software
276} // namespace phosphor