blob: 12f818b5d90b8c628c1f281d957609ccfdaa3140 [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"
Saqib Khan5d532672017-08-09 10:44:50 -05009#include "serialize.hpp"
Gunnar Millsec1b41c2017-05-02 12:20:36 -050010
11namespace phosphor
12{
13namespace software
14{
15namespace updater
16{
17
Gunnar Mills2ce7da22017-05-04 15:37:56 -050018// When you see server:: you know we're referencing our base class
19namespace server = sdbusplus::xyz::openbmc_project::Software::server;
20
21using namespace phosphor::logging;
Saqib Khan35e83f32017-05-22 11:37:32 -050022namespace fs = std::experimental::filesystem;
23
Michael Tritzb1cfdf92017-08-14 14:33:30 -050024const std::vector<std::string> bmcImages = {"image-kernel",
25 "image-rofs",
26 "image-rwfs",
27 "image-u-boot"};
Gunnar Mills2ce7da22017-05-04 15:37:56 -050028
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 }
Saqib Khan7b5010f2017-08-09 10:03:11 -0500129 else
130 {
131 log<level::INFO>("Software Object with the same version already exists",
132 entry("VERSION_ID=%s", versionId));
133 }
Patrick Williamse75d10f2017-05-30 16:56:32 -0500134 return;
Gunnar Millsec1b41c2017-05-02 12:20:36 -0500135}
136
Saqib Khanba239882017-05-26 08:41:54 -0500137void ItemUpdater::processBMCImage()
138{
139 auto purpose = server::Version::VersionPurpose::BMC;
140 auto version = phosphor::software::manager::Version::getBMCVersion();
141 auto id = phosphor::software::manager::Version::getId(version);
142 auto path = std::string{SOFTWARE_OBJPATH} + '/' + id;
143 activations.insert(std::make_pair(
144 id,
145 std::make_unique<Activation>(
146 bus,
147 path,
Saqib Khan4c1aec02017-07-06 11:46:13 -0500148 *this,
Saqib Khanba239882017-05-26 08:41:54 -0500149 id,
150 server::Activation::Activations::Active)));
151 versions.insert(std::make_pair(
152 id,
153 std::make_unique<phosphor::software::
154 manager::Version>(
155 bus,
156 path,
157 version,
158 purpose,
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500159 "",
160 std::bind(&ItemUpdater::erase,
161 this,
162 std::placeholders::_1))));
163
Saqib Khanba239882017-05-26 08:41:54 -0500164 return;
165}
166
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500167void ItemUpdater::erase(std::string entryId)
168{
169 // Delete ReadWrite and ReadOnly partitions
170 removeReadWritePartition(entryId);
171 removeReadOnlyPartition(entryId);
172
173 // Removing entry in versions map
174 auto it = versions.find(entryId);
175 if (it == versions.end())
176 {
177 log<level::ERR>(("Error: Failed to find version " + entryId + \
178 " in item updater versions map." \
179 " Unable to remove.").c_str());
180 return;
181 }
182 this->versions.erase(entryId);
183
184 // Removing entry in activations map
185 auto ita = activations.find(entryId);
186 if (ita == activations.end())
187 {
188 log<level::ERR>(("Error: Failed to find version " + entryId + \
189 " in item updater activations map." \
190 " Unable to remove.").c_str());
191 return;
192 }
193 // TODO: openbmc/openbmc#1986
194 // Test if this is the currently running image
195 // If not, don't continue.
196
197 this->activations.erase(entryId);
Saqib Khan5d532672017-08-09 10:44:50 -0500198 removeFile(entryId);
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500199}
200
Saqib Khan35e83f32017-05-22 11:37:32 -0500201ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage(
Saqib Khan19177d32017-06-20 08:11:49 -0500202 const std::string& filePath)
Saqib Khan35e83f32017-05-22 11:37:32 -0500203{
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500204 bool invalid = false;
Saqib Khan35e83f32017-05-22 11:37:32 -0500205
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500206 for (auto& bmcImage : bmcImages)
Saqib Khan35e83f32017-05-22 11:37:32 -0500207 {
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500208 fs::path file(filePath);
209 file /= bmcImage;
210 std::ifstream efile(file.c_str());
211 if (efile.good() != 1)
212 {
213 log<level::ERR>("Failed to find the BMC image.",
214 entry("IMAGE=%s", bmcImage.c_str()));
215 invalid = true;
216 }
Saqib Khan35e83f32017-05-22 11:37:32 -0500217 }
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500218
219 if (invalid)
Saqib Khan35e83f32017-05-22 11:37:32 -0500220 {
Saqib Khan35e83f32017-05-22 11:37:32 -0500221 return ItemUpdater::ActivationStatus::invalid;
222 }
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500223
224 return ItemUpdater::ActivationStatus::ready;
Saqib Khan35e83f32017-05-22 11:37:32 -0500225}
226
Saqib Khan4c1aec02017-07-06 11:46:13 -0500227void ItemUpdater::freePriority(uint8_t value)
228{
229 //TODO openbmc/openbmc#1896 Improve the performance of this function
230 for (const auto& intf : activations)
231 {
232 if(intf.second->redundancyPriority)
233 {
234 if (intf.second->redundancyPriority.get()->priority() == value)
235 {
236 intf.second->redundancyPriority.get()->priority(value+1);
237 }
238 }
239 }
240}
241
Michael Tritz37a59042017-07-12 13:44:53 -0500242void ItemUpdater::reset()
243{
244 // Mark the read-write partition for recreation upon reboot.
245 auto method = bus.new_method_call(
246 SYSTEMD_BUSNAME,
247 SYSTEMD_PATH,
248 SYSTEMD_INTERFACE,
249 "StartUnit");
250 method.append("obmc-flash-bmc-setenv@rwreset=true.service", "replace");
251 bus.call_noreply(method);
252
253 log<level::INFO>("BMC factory reset will take effect upon reboot.");
254
255 return;
256}
257
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500258void ItemUpdater::removeReadOnlyPartition(std::string versionId)
259{
260 auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId +
261 ".service";
262
263 // Remove the read-only partitions.
264 auto method = bus.new_method_call(
265 SYSTEMD_BUSNAME,
266 SYSTEMD_PATH,
267 SYSTEMD_INTERFACE,
268 "StartUnit");
269 method.append(serviceFile, "replace");
270 bus.call_noreply(method);
271}
272
273void ItemUpdater::removeReadWritePartition(std::string versionId)
274{
275 auto serviceFile = "obmc-flash-bmc-ubirw-remove.service";
276
277 // Remove the read-write partitions.
278 auto method = bus.new_method_call(
279 SYSTEMD_BUSNAME,
280 SYSTEMD_PATH,
281 SYSTEMD_INTERFACE,
282 "StartUnit");
283 method.append(serviceFile, "replace");
284 bus.call_noreply(method);
285}
286
Gunnar Millsec1b41c2017-05-02 12:20:36 -0500287} // namespace updater
288} // namespace software
289} // namespace phosphor