blob: 9e558ce297fe2e24168be631ab732740063b2e67 [file] [log] [blame]
Saqib Khan7254f0e2017-04-10 21:45:37 -05001#include <string>
Adriana Kobylak5ba6b102017-05-19 09:41:27 -05002#include <experimental/filesystem>
Saqib Khan7254f0e2017-04-10 21:45:37 -05003#include <fstream>
Eddie James13fc66a2017-08-31 15:36:44 -05004#include <phosphor-logging/elog-errors.hpp>
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -05005#include <phosphor-logging/log.hpp>
Eddie James13fc66a2017-08-31 15:36:44 -05006#include "xyz/openbmc_project/Common/error.hpp"
Adriana Kobylakd6a549e2017-05-10 16:23:01 -05007#include <xyz/openbmc_project/Software/Version/server.hpp>
Saqib Khan167601b2017-06-18 23:33:46 -05008#include "version.hpp"
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05009#include "config.h"
10#include "item_updater.hpp"
Saqib Khana8ade7e2017-04-12 10:27:56 -050011#include "activation.hpp"
Michael Tritz60bc20f2017-07-29 23:32:21 -050012#include "serialize.hpp"
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050013
14namespace openpower
15{
16namespace software
17{
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050018namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050019{
20
Saqib Khana8ade7e2017-04-12 10:27:56 -050021// When you see server:: you know we're referencing our base class
22namespace server = sdbusplus::xyz::openbmc_project::Software::server;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050023namespace fs = std::experimental::filesystem;
Saqib Khana8ade7e2017-04-12 10:27:56 -050024
Eddie James13fc66a2017-08-31 15:36:44 -050025using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050026using namespace phosphor::logging;
27
Saqib Khana8ade7e2017-04-12 10:27:56 -050028constexpr auto squashFSImage = "pnor.xz.squashfs";
Eddie James13fc66a2017-08-31 15:36:44 -050029constexpr auto CHASSIS_STATE_PATH = "/xyz/openbmc_project/state/chassis0";
30constexpr auto CHASSIS_STATE_OBJ = "xyz.openbmc_project.State.Chassis";
31constexpr auto CHASSIS_STATE_OFF =
32 "xyz.openbmc_project.State.Chassis.PowerState.Off";
33constexpr auto SYSTEMD_PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
Saqib Khana8ade7e2017-04-12 10:27:56 -050034
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050035void ItemUpdater::createActivation(sdbusplus::message::message& m)
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050036{
Patrick Williamse4290942017-06-16 05:43:08 -050037 using SVersion = server::Version;
38 using VersionPurpose = SVersion::VersionPurpose;
39 namespace msg = sdbusplus::message;
40 namespace variant_ns = msg::variant_ns;
41
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050042 sdbusplus::message::object_path objPath;
43 std::map<std::string,
Patrick Williamse4290942017-06-16 05:43:08 -050044 std::map<std::string, msg::variant<std::string>>> interfaces;
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050045 m.read(objPath, interfaces);
Patrick Williamse4290942017-06-16 05:43:08 -050046
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050047 std::string path(std::move(objPath));
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050048 std::string filePath;
Patrick Williamse4290942017-06-16 05:43:08 -050049 auto purpose = VersionPurpose::Unknown;
Saqib Khance148702017-06-11 12:01:58 -050050 std::string version;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050051
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050052 for (const auto& intf : interfaces)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050053 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050054 if (intf.first == VERSION_IFACE)
55 {
56 for (const auto& property : intf.second)
57 {
58 if (property.first == "Purpose")
59 {
60 // Only process the Host and System images
Patrick Williamse4290942017-06-16 05:43:08 -050061 auto value = SVersion::convertVersionPurposeFromString(
62 variant_ns::get<std::string>(property.second));
63
64 if (value == VersionPurpose::Host ||
65 value == VersionPurpose::System)
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050066 {
Saqib Khance148702017-06-11 12:01:58 -050067 purpose = value;
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050068 }
69 }
Saqib Khance148702017-06-11 12:01:58 -050070 else if (property.first == "Version")
71 {
Patrick Williamse4290942017-06-16 05:43:08 -050072 version = variant_ns::get<std::string>(property.second);
Saqib Khance148702017-06-11 12:01:58 -050073 }
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050074 }
75 }
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050076 else if (intf.first == FILEPATH_IFACE)
77 {
78 for (const auto& property : intf.second)
79 {
80 if (property.first == "Path")
81 {
Patrick Williamse4290942017-06-16 05:43:08 -050082 filePath = variant_ns::get<std::string>(property.second);
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050083 }
84 }
85 }
86 }
Patrick Williamse4290942017-06-16 05:43:08 -050087 if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050088 {
89 return;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050090 }
91
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050092 // Version id is the last item in the path
93 auto pos = path.rfind("/");
94 if (pos == std::string::npos)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050095 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050096 log<level::ERR>("No version id found in object path",
97 entry("OBJPATH=%s", path));
98 return;
99 }
100
101 auto versionId = path.substr(pos + 1);
102
103 if (activations.find(versionId) == activations.end())
104 {
105 // Determine the Activation state by processing the given image dir.
106 auto activationState = server::Activation::Activations::Invalid;
Gunnar Mills3588acc2017-09-07 13:13:22 -0500107 AssociationList associations = {};
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500108 if (ItemUpdater::validateSquashFSImage(filePath) == 0)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500109 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500110 activationState = server::Activation::Activations::Ready;
Gunnar Mills3588acc2017-09-07 13:13:22 -0500111 // Create an association to the host inventory item
112 associations.emplace_back(std::make_tuple(
113 ACTIVATION_FWD_ASSOCIATION,
114 ACTIVATION_REV_ASSOCIATION,
115 HOST_INVENTORY_PATH));
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500116 }
117
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500118 fs::path manifestPath(filePath);
119 manifestPath /= MANIFEST_FILE;
Saqib Khan167601b2017-06-18 23:33:46 -0500120 std::string extendedVersion = (Version::getValue(manifestPath.string(),
121 std::map<std::string, std::string>
122 {{"extended_version", ""}})).begin()->second;
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500123
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500124 activations.insert(std::make_pair(
125 versionId,
126 std::make_unique<Activation>(
127 bus,
128 path,
Saqib Khan81bac882017-06-08 12:17:01 -0500129 *this,
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500130 versionId,
131 extendedVersion,
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500132 activationState,
133 associations)));
Saqib Khance148702017-06-11 12:01:58 -0500134 versions.insert(std::make_pair(
135 versionId,
136 std::make_unique<Version>(
137 bus,
138 path,
139 version,
140 purpose,
Eddie Jamesfa5daf42017-09-01 11:51:28 -0500141 filePath)));
Saqib Khan00044f42017-07-10 17:24:43 -0500142 }
Saqib Khan3fb2d172017-08-07 12:14:03 -0500143 else
144 {
145 log<level::INFO>("Software Object with the same version already exists",
Gunnar Mills3fa70282017-08-18 15:30:42 -0500146 entry("VERSION_ID=%s", versionId));
Saqib Khan3fb2d172017-08-07 12:14:03 -0500147 }
Patrick Williams3accb322017-05-30 16:29:52 -0500148 return;
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500149}
150
Saqib Khan167601b2017-06-18 23:33:46 -0500151void ItemUpdater::processPNORImage()
Saqib Khan7254f0e2017-04-10 21:45:37 -0500152{
Saqib Khan4c5d7442017-07-18 00:43:52 -0500153 // Read pnor.toc from folders under /media/
154 // to get Active Software Versions.
Gunnar Mills3fa70282017-08-18 15:30:42 -0500155 for (const auto& iter : fs::directory_iterator(MEDIA_DIR))
Saqib Khan4c5d7442017-07-18 00:43:52 -0500156 {
157 auto activationState = server::Activation::Activations::Active;
158
159 static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
Saqib Khan2be9ba92017-09-26 22:44:10 -0500160 static const auto PNOR_RW_PREFIX_LEN = strlen(PNOR_RW_PREFIX);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500161
162 // Check if the PNOR_RO_PREFIX is the prefix of the iter.path
163 if (0 == iter.path().native().compare(0, PNOR_RO_PREFIX_LEN,
164 PNOR_RO_PREFIX))
165 {
Saqib Khan6a522262017-09-26 12:02:50 -0500166 // The versionId is extracted from the path
167 // for example /media/pnor-ro-2a1022fe.
168 auto id = iter.path().native().substr(PNOR_RO_PREFIX_LEN);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500169 auto pnorTOC = iter.path() / PNOR_TOC_FILE;
170 if (!fs::is_regular_file(pnorTOC))
171 {
Saqib Khan6a522262017-09-26 12:02:50 -0500172 log<level::ERR>("Failed to read pnorTOC.\n",
Saqib Khan4c5d7442017-07-18 00:43:52 -0500173 entry("FileName=%s", pnorTOC.string()));
Saqib Khan6a522262017-09-26 12:02:50 -0500174 ItemUpdater::erase(id);
175 continue;
Saqib Khan4c5d7442017-07-18 00:43:52 -0500176 }
177 auto keyValues =
178 Version::getValue(pnorTOC,
179 {{ "version", "" },
180 { "extended_version", "" } });
181 auto& version = keyValues.at("version");
182 if (version.empty())
183 {
184 log<level::ERR>("Failed to read version from pnorTOC",
185 entry("FILENAME=%s", pnorTOC.string()));
186 activationState = server::Activation::Activations::Invalid;
187 }
188
189 auto& extendedVersion = keyValues.at("extended_version");
190 if (extendedVersion.empty())
191 {
192 log<level::ERR>("Failed to read extendedVersion from pnorTOC",
193 entry("FILENAME=%s", pnorTOC.string()));
194 activationState = server::Activation::Activations::Invalid;
195 }
196
Saqib Khan4c5d7442017-07-18 00:43:52 -0500197 auto purpose = server::Version::VersionPurpose::Host;
198 auto path = fs::path(SOFTWARE_OBJPATH) / id;
Gunnar Mills3588acc2017-09-07 13:13:22 -0500199 AssociationList associations = {};
Saqib Khan4c5d7442017-07-18 00:43:52 -0500200
Gunnar Mills3588acc2017-09-07 13:13:22 -0500201 if (activationState == server::Activation::Activations::Active)
202 {
203 // Create an association to the host inventory item
204 associations.emplace_back(std::make_tuple(
205 ACTIVATION_FWD_ASSOCIATION,
206 ACTIVATION_REV_ASSOCIATION,
207 HOST_INVENTORY_PATH));
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500208
Gunnar Mills3588acc2017-09-07 13:13:22 -0500209 // Create an active association since this image is active
210 createActiveAssociation(path);
211 }
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500212
Saqib Khan4c5d7442017-07-18 00:43:52 -0500213 // Create Activation instance for this version.
214 activations.insert(std::make_pair(
215 id,
216 std::make_unique<Activation>(
217 bus,
218 path,
219 *this,
220 id,
221 extendedVersion,
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500222 activationState,
223 associations)));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500224
225 // If Active, create RedundancyPriority instance for this version.
226 if (activationState == server::Activation::Activations::Active)
227 {
Michael Tritz36417922017-08-04 14:00:29 -0500228 uint8_t priority = std::numeric_limits<uint8_t>::max();
229 if (!restoreFromFile(id, priority))
Saqib Khan4c5d7442017-07-18 00:43:52 -0500230 {
Michael Tritz36417922017-08-04 14:00:29 -0500231 log<level::ERR>("Unable to restore priority from file.",
Gunnar Mills3fa70282017-08-18 15:30:42 -0500232 entry("VERSIONID=%s", id));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500233 }
Michael Tritz36417922017-08-04 14:00:29 -0500234 activations.find(id)->second->redundancyPriority =
235 std::make_unique<RedundancyPriority>(
236 bus,
237 path,
238 *(activations.find(id)->second),
239 priority);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500240 }
241
242 // Create Version instance for this version.
243 versions.insert(std::make_pair(
244 id,
245 std::make_unique<Version>(
246 bus,
247 path,
248 version,
249 purpose,
Eddie Jamesfa5daf42017-09-01 11:51:28 -0500250 "")));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500251 }
Saqib Khan2be9ba92017-09-26 22:44:10 -0500252 else if (0 == iter.path().native().compare(0, PNOR_RW_PREFIX_LEN,
253 PNOR_RW_PREFIX))
254 {
255 auto id = iter.path().native().substr(PNOR_RW_PREFIX_LEN);
256 auto roDir = PNOR_RO_PREFIX + id;
257 if (!fs::is_directory(roDir))
258 {
259 log<level::ERR>("No corresponding read-only volume found.",
260 entry("DIRNAME=%s", roDir));
261 ItemUpdater::erase(id);
262 }
263 }
Saqib Khan4c5d7442017-07-18 00:43:52 -0500264 }
Gunnar Mills2badd7a2017-09-20 12:51:28 -0500265
266 // Look at the RO symlink to determine if there is a functional image
267 auto id = determineId(PNOR_RO_ACTIVE_PATH);
268 if (!id.empty())
269 {
270 updateFunctionalAssociation(std::string{SOFTWARE_OBJPATH} + '/' + id);
271 }
Saqib Khan167601b2017-06-18 23:33:46 -0500272 return;
Saqib Khan7254f0e2017-04-10 21:45:37 -0500273}
274
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500275int ItemUpdater::validateSquashFSImage(const std::string& filePath)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500276{
Saqib Khan4c5d7442017-07-18 00:43:52 -0500277 auto file = fs::path(filePath) / squashFSImage;
278 if (fs::is_regular_file(file))
Saqib Khana8ade7e2017-04-12 10:27:56 -0500279 {
280 return 0;
281 }
282 else
283 {
284 log<level::ERR>("Failed to find the SquashFS image.");
285 return -1;
286 }
287}
288
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500289void ItemUpdater::removeReadOnlyPartition(std::string versionId)
Michael Tritzdd961b62017-05-17 14:07:03 -0500290{
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500291 auto serviceFile = "obmc-flash-bios-ubiumount-ro@" + versionId +
292 ".service";
293
294 // Remove the read-only partitions.
295 auto method = bus.new_method_call(
296 SYSTEMD_BUSNAME,
297 SYSTEMD_PATH,
298 SYSTEMD_INTERFACE,
299 "StartUnit");
300 method.append(serviceFile, "replace");
301 bus.call_noreply(method);
302}
303
304void ItemUpdater::removeReadWritePartition(std::string versionId)
305{
306 auto serviceFile = "obmc-flash-bios-ubiumount-rw@" + versionId +
Michael Tritzdd961b62017-05-17 14:07:03 -0500307 ".service";
308
309 // Remove the read-write partitions.
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500310 auto method = bus.new_method_call(
Michael Tritzdd961b62017-05-17 14:07:03 -0500311 SYSTEMD_BUSNAME,
312 SYSTEMD_PATH,
313 SYSTEMD_INTERFACE,
314 "StartUnit");
315 method.append(serviceFile, "replace");
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500316 bus.call_noreply(method);
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500317}
Michael Tritzdd961b62017-05-17 14:07:03 -0500318
Michael Tritzfa7aa122017-09-22 15:16:11 -0500319void ItemUpdater::reset()
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500320{
Michael Tritzfa7aa122017-09-22 15:16:11 -0500321 for (const auto& it : activations)
322 {
323 auto serviceFile = "obmc-flash-bios-ubiclear@pnor-rw-" + it.first +
324 ".service";
325
326 // Clear the read-write partitions.
327 auto method = bus.new_method_call(
328 SYSTEMD_BUSNAME,
329 SYSTEMD_PATH,
330 SYSTEMD_INTERFACE,
331 "StartUnit");
332 method.append(serviceFile, "replace");
333 auto reply = bus.call(method);
334
335 if (reply.is_method_error())
336 {
337 elog<InternalFailure>();
338 }
339
340 removeFile(it.first);
341 }
342 // Clear the preserved partition.
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500343 auto method = bus.new_method_call(
Michael Tritzdd961b62017-05-17 14:07:03 -0500344 SYSTEMD_BUSNAME,
345 SYSTEMD_PATH,
346 SYSTEMD_INTERFACE,
347 "StartUnit");
Michael Tritzfa7aa122017-09-22 15:16:11 -0500348 method.append("obmc-flash-bios-ubiclear@pnor-prsv.service", "replace");
349 auto reply = bus.call(method);
Michael Tritzdd961b62017-05-17 14:07:03 -0500350
Michael Tritzfa7aa122017-09-22 15:16:11 -0500351 if (reply.is_method_error())
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500352 {
Michael Tritzfa7aa122017-09-22 15:16:11 -0500353 elog<InternalFailure>();
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500354 }
Michael Tritzfa7aa122017-09-22 15:16:11 -0500355
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500356 return;
357}
358
Eddie James13fc66a2017-08-31 15:36:44 -0500359bool ItemUpdater::isVersionFunctional(std::string versionId)
360{
361 if (!fs::exists(PNOR_RO_ACTIVE_PATH))
362 {
363 return false;
364 }
365
366 fs::path activeRO = fs::read_symlink(PNOR_RO_ACTIVE_PATH);
367
368 if (!fs::is_directory(activeRO))
369 {
370 return false;
371 }
372
373 if (activeRO.string().find(versionId) == std::string::npos)
374 {
375 return false;
376 }
377
378 // active PNOR is the version we're checking
379 return true;
380}
381
382bool ItemUpdater::isChassisOn()
383{
384 auto mapperCall = bus.new_method_call(
385 MAPPER_BUSNAME,
386 MAPPER_PATH,
387 MAPPER_INTERFACE,
388 "GetObject");
389
390 mapperCall.append(CHASSIS_STATE_PATH,
391 std::vector<std::string>({CHASSIS_STATE_OBJ}));
392 auto mapperResponseMsg = bus.call(mapperCall);
393 if (mapperResponseMsg.is_method_error())
394 {
395 log<level::ERR>("Error in Mapper call");
396 elog<InternalFailure>();
397 }
398 using MapperResponseType = std::map<std::string, std::vector<std::string>>;
399 MapperResponseType mapperResponse;
400 mapperResponseMsg.read(mapperResponse);
401 if (mapperResponse.empty())
402 {
403 log<level::ERR>("Invalid Response from mapper");
404 elog<InternalFailure>();
405 }
406
407 auto method = bus.new_method_call((mapperResponse.begin()->first).c_str(),
408 CHASSIS_STATE_PATH,
409 SYSTEMD_PROPERTY_INTERFACE,
410 "Get");
411 method.append(CHASSIS_STATE_OBJ, "CurrentPowerState");
412 auto response = bus.call(method);
413 if (response.is_method_error())
414 {
415 log<level::ERR>("Error in fetching current Chassis State",
416 entry("MapperResponse=%s",
417 (mapperResponse.begin()->first).c_str()));
418 elog<InternalFailure>();
419 }
420 sdbusplus::message::variant<std::string> currentChassisState;
421 response.read(currentChassisState);
422 auto strParam =
423 sdbusplus::message::variant_ns::get<std::string>(currentChassisState);
424 return (strParam != CHASSIS_STATE_OFF);
425}
426
Saqib Khanb8e7f312017-08-12 10:24:10 -0500427void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
Saqib Khan81bac882017-06-08 12:17:01 -0500428{
429 //TODO openbmc/openbmc#1896 Improve the performance of this function
430 for (const auto& intf : activations)
431 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500432 if (intf.second->redundancyPriority)
Saqib Khan81bac882017-06-08 12:17:01 -0500433 {
Saqib Khanb8e7f312017-08-12 10:24:10 -0500434 if (intf.second->redundancyPriority.get()->priority() == value &&
435 intf.second->versionId != versionId)
Saqib Khan81bac882017-06-08 12:17:01 -0500436 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500437 intf.second->redundancyPriority.get()->priority(value + 1);
Saqib Khan81bac882017-06-08 12:17:01 -0500438 }
439 }
440 }
441}
442
Saqib Khan2af5c492017-07-17 16:15:13 -0500443bool ItemUpdater::isLowestPriority(uint8_t value)
444{
445 for (const auto& intf : activations)
446 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500447 if (intf.second->redundancyPriority)
Saqib Khan2af5c492017-07-17 16:15:13 -0500448 {
449 if (intf.second->redundancyPriority.get()->priority() < value)
450 {
451 return false;
452 }
453 }
454 }
455 return true;
456}
457
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500458void ItemUpdater::erase(std::string entryId)
459{
Eddie James13fc66a2017-08-31 15:36:44 -0500460 if (isVersionFunctional(entryId) && isChassisOn()) {
461 log<level::ERR>(("Error: Version " + entryId + \
462 " is currently active and running on the host." \
463 " Unable to remove.").c_str());
464 return;
465 }
Saqib Khanef8cd9f2017-08-16 14:20:30 -0500466 // Remove priority persistence file
467 removeFile(entryId);
468
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500469 // Removing read-only and read-write partitions
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500470 removeReadWritePartition(entryId);
471 removeReadOnlyPartition(entryId);
472
473 // Removing entry in versions map
474 auto it = versions.find(entryId);
475 if (it == versions.end())
476 {
477 log<level::ERR>(("Error: Failed to find version " + entryId + \
Gunnar Mills3fa70282017-08-18 15:30:42 -0500478 " in item updater versions map." \
479 " Unable to remove.").c_str());
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500480 return;
481 }
482 versions.erase(entryId);
483
484 // Removing entry in activations map
485 auto ita = activations.find(entryId);
486 if (ita == activations.end())
487 {
488 log<level::ERR>(("Error: Failed to find version " + entryId + \
Gunnar Mills3fa70282017-08-18 15:30:42 -0500489 " in item updater activations map." \
490 " Unable to remove.").c_str());
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500491 return;
492 }
493 activations.erase(entryId);
494}
495
Michael Tritz234a07e2017-09-21 00:53:06 -0500496void ItemUpdater::deleteAll()
497{
498 std::vector<std::string> deletableActivations;
499
500 for (const auto& activationIt : activations)
501 {
502 if (!isVersionFunctional(activationIt.first))
503 {
504 deletableActivations.push_back(activationIt.first);
505 }
506 }
507
508 for (const auto& deletableIt : deletableActivations)
509 {
510 ItemUpdater::erase(deletableIt);
511 }
512
513 // Remove any remaining pnor-ro- or pnor-rw- volumes that do not match
514 // the current version.
515 auto method = bus.new_method_call(
516 SYSTEMD_BUSNAME,
517 SYSTEMD_PATH,
518 SYSTEMD_INTERFACE,
519 "StartUnit");
520 method.append("obmc-flash-bios-cleanup.service", "replace");
521 bus.call_noreply(method);
522}
523
Saqib Khan2cbfa032017-08-17 14:52:37 -0500524// TODO: openbmc/openbmc#1402 Monitor flash usage
525void ItemUpdater::freeSpace()
526{
527 std::size_t count = 0;
528 decltype(activations.begin()->second->redundancyPriority.get()->priority())
529 highestPriority = 0;
530 decltype(activations.begin()->second->versionId) highestPriorityVersion;
531 for (const auto& iter : activations)
532 {
533 if (iter.second.get()->activation() == server::Activation::Activations::Active)
534 {
535 count++;
536 if (iter.second->redundancyPriority.get()->priority() > highestPriority)
537 {
538 highestPriority = iter.second->redundancyPriority.get()->priority();
539 highestPriorityVersion = iter.second->versionId;
540 }
541 }
542 }
543 // Remove the pnor version with highest priority since the PNOR
544 // can't hold more than 2 versions.
545 if (count >= ACTIVE_PNOR_MAX_ALLOWED)
546 {
547 erase(highestPriorityVersion);
548 }
549}
550
Gunnar Mills61010b22017-09-20 15:25:26 -0500551void ItemUpdater::createActiveAssociation(const std::string& path)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500552{
553 assocs.emplace_back(std::make_tuple(ACTIVE_FWD_ASSOCIATION,
554 ACTIVE_REV_ASSOCIATION,
555 path));
556 associations(assocs);
557}
558
Gunnar Mills833e4f32017-09-14 12:30:27 -0500559void ItemUpdater::updateFunctionalAssociation(const std::string& path)
560{
561 // remove all functional associations
562 for (auto iter = assocs.begin(); iter != assocs.end();)
563 {
564 if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0)
565 {
566 iter = assocs.erase(iter);
567 }
568 else
569 {
570 ++iter;
571 }
572 }
573 assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
574 FUNCTIONAL_REV_ASSOCIATION,
575 path));
576 associations(assocs);
577}
578
Gunnar Mills61010b22017-09-20 15:25:26 -0500579void ItemUpdater::removeActiveAssociation(const std::string& path)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500580{
581 for (auto iter = assocs.begin(); iter != assocs.end();)
582 {
Gunnar Mills833e4f32017-09-14 12:30:27 -0500583 if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 &&
584 (std::get<2>(*iter)).compare(path) == 0)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500585 {
586 iter = assocs.erase(iter);
587 associations(assocs);
588 }
589 else
590 {
591 ++iter;
592 }
593 }
594}
595
Gunnar Mills2badd7a2017-09-20 12:51:28 -0500596std::string ItemUpdater::determineId(const std::string& symlinkPath)
597{
598 if (!fs::exists(symlinkPath))
599 {
600 return {};
601 }
602
603 auto target = fs::canonical(symlinkPath).string();
604
605 // check to make sure the target really exists
606 if (!fs::is_regular_file(target + "/" + PNOR_TOC_FILE))
607 {
608 return {};
609 }
610 // Get the image <id> from the symlink target
611 // for example /media/ro-2a1022fe
612 static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
613 return target.substr(PNOR_RO_PREFIX_LEN);
614}
615
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500616} // namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500617} // namespace software
618} // namespace openpower