blob: 91421b831a38072be13ae5773de4d424f4e453b0 [file] [log] [blame]
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05001#include "config.h"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05002
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05003#include "item_updater.hpp"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05004
Saqib Khana8ade7e2017-04-12 10:27:56 -05005#include "activation.hpp"
Michael Tritz60bc20f2017-07-29 23:32:21 -05006#include "serialize.hpp"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05007#include "version.hpp"
8#include "xyz/openbmc_project/Common/error.hpp"
9
10#include <experimental/filesystem>
11#include <fstream>
12#include <phosphor-logging/elog-errors.hpp>
13#include <phosphor-logging/log.hpp>
14#include <queue>
15#include <string>
16#include <xyz/openbmc_project/Software/Version/server.hpp>
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050017
18namespace openpower
19{
20namespace software
21{
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050022namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050023{
24
Saqib Khana8ade7e2017-04-12 10:27:56 -050025// When you see server:: you know we're referencing our base class
26namespace server = sdbusplus::xyz::openbmc_project::Software::server;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050027namespace fs = std::experimental::filesystem;
Saqib Khana8ade7e2017-04-12 10:27:56 -050028
Eddie James13fc66a2017-08-31 15:36:44 -050029using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050030using namespace phosphor::logging;
31
Saqib Khana8ade7e2017-04-12 10:27:56 -050032constexpr auto squashFSImage = "pnor.xz.squashfs";
33
Michael Tritzb541f1b2017-10-15 15:10:21 -050034// TODO: Change paths once openbmc/openbmc#1663 is completed.
35constexpr auto MBOXD_INTERFACE = "org.openbmc.mboxd";
36constexpr auto MBOXD_PATH = "/org/openbmc/mboxd";
37
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050038void ItemUpdater::createActivation(sdbusplus::message::message& m)
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050039{
Patrick Williamse4290942017-06-16 05:43:08 -050040 using SVersion = server::Version;
41 using VersionPurpose = SVersion::VersionPurpose;
42 namespace msg = sdbusplus::message;
43 namespace variant_ns = msg::variant_ns;
44
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050045 sdbusplus::message::object_path objPath;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060046 std::map<std::string, std::map<std::string, msg::variant<std::string>>>
47 interfaces;
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050048 m.read(objPath, interfaces);
Patrick Williamse4290942017-06-16 05:43:08 -050049
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050050 std::string path(std::move(objPath));
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050051 std::string filePath;
Patrick Williamse4290942017-06-16 05:43:08 -050052 auto purpose = VersionPurpose::Unknown;
Saqib Khance148702017-06-11 12:01:58 -050053 std::string version;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050054
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050055 for (const auto& intf : interfaces)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050056 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050057 if (intf.first == VERSION_IFACE)
58 {
59 for (const auto& property : intf.second)
60 {
61 if (property.first == "Purpose")
62 {
63 // Only process the Host and System images
Patrick Williamse4290942017-06-16 05:43:08 -050064 auto value = SVersion::convertVersionPurposeFromString(
Adriana Kobylak70dcb632018-02-27 15:46:52 -060065 variant_ns::get<std::string>(property.second));
Patrick Williamse4290942017-06-16 05:43:08 -050066
67 if (value == VersionPurpose::Host ||
68 value == VersionPurpose::System)
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050069 {
Saqib Khance148702017-06-11 12:01:58 -050070 purpose = value;
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050071 }
72 }
Saqib Khance148702017-06-11 12:01:58 -050073 else if (property.first == "Version")
74 {
Patrick Williamse4290942017-06-16 05:43:08 -050075 version = variant_ns::get<std::string>(property.second);
Saqib Khance148702017-06-11 12:01:58 -050076 }
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050077 }
78 }
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050079 else if (intf.first == FILEPATH_IFACE)
80 {
81 for (const auto& property : intf.second)
82 {
83 if (property.first == "Path")
84 {
Patrick Williamse4290942017-06-16 05:43:08 -050085 filePath = variant_ns::get<std::string>(property.second);
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050086 }
87 }
88 }
89 }
Patrick Williamse4290942017-06-16 05:43:08 -050090 if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050091 {
92 return;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050093 }
94
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050095 // Version id is the last item in the path
96 auto pos = path.rfind("/");
97 if (pos == std::string::npos)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050098 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050099 log<level::ERR>("No version id found in object path",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500100 entry("OBJPATH=%s", path.c_str()));
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500101 return;
102 }
103
104 auto versionId = path.substr(pos + 1);
105
106 if (activations.find(versionId) == activations.end())
107 {
108 // Determine the Activation state by processing the given image dir.
109 auto activationState = server::Activation::Activations::Invalid;
Gunnar Mills3588acc2017-09-07 13:13:22 -0500110 AssociationList associations = {};
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500111 if (ItemUpdater::validateSquashFSImage(filePath) == 0)
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500112 {
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500113 activationState = server::Activation::Activations::Ready;
Gunnar Mills3588acc2017-09-07 13:13:22 -0500114 // Create an association to the host inventory item
115 associations.emplace_back(std::make_tuple(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600116 ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
117 HOST_INVENTORY_PATH));
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500118 }
119
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500120 fs::path manifestPath(filePath);
121 manifestPath /= MANIFEST_FILE;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600122 std::string extendedVersion =
123 (Version::getValue(
124 manifestPath.string(),
125 std::map<std::string, std::string>{{"extended_version", ""}}))
126 .begin()
127 ->second;
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500128
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500129 activations.insert(std::make_pair(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600130 versionId, std::make_unique<Activation>(
131 bus, path, *this, versionId, extendedVersion,
132 activationState, associations)));
Michael Tritz5b756512017-10-06 16:52:01 -0500133
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500134 auto versionPtr = std::make_unique<Version>(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600135 bus, path, *this, versionId, version, purpose, filePath,
136 std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500137 versionPtr->deleteObject =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600138 std::make_unique<Delete>(bus, path, *versionPtr);
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500139 versions.insert(std::make_pair(versionId, std::move(versionPtr)));
Saqib Khan00044f42017-07-10 17:24:43 -0500140 }
Patrick Williams3accb322017-05-30 16:29:52 -0500141 return;
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500142}
143
Saqib Khan167601b2017-06-18 23:33:46 -0500144void ItemUpdater::processPNORImage()
Saqib Khan7254f0e2017-04-10 21:45:37 -0500145{
Saqib Khan4c5d7442017-07-18 00:43:52 -0500146 // Read pnor.toc from folders under /media/
147 // to get Active Software Versions.
Gunnar Mills3fa70282017-08-18 15:30:42 -0500148 for (const auto& iter : fs::directory_iterator(MEDIA_DIR))
Saqib Khan4c5d7442017-07-18 00:43:52 -0500149 {
150 auto activationState = server::Activation::Activations::Active;
151
152 static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
Saqib Khan2be9ba92017-09-26 22:44:10 -0500153 static const auto PNOR_RW_PREFIX_LEN = strlen(PNOR_RW_PREFIX);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500154
155 // Check if the PNOR_RO_PREFIX is the prefix of the iter.path
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600156 if (0 ==
157 iter.path().native().compare(0, PNOR_RO_PREFIX_LEN, PNOR_RO_PREFIX))
Saqib Khan4c5d7442017-07-18 00:43:52 -0500158 {
Saqib Khan6a522262017-09-26 12:02:50 -0500159 // The versionId is extracted from the path
160 // for example /media/pnor-ro-2a1022fe.
161 auto id = iter.path().native().substr(PNOR_RO_PREFIX_LEN);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500162 auto pnorTOC = iter.path() / PNOR_TOC_FILE;
163 if (!fs::is_regular_file(pnorTOC))
164 {
Gunnar Mills850d5f62017-10-19 17:04:38 -0500165 log<level::ERR>("Failed to read pnorTOC.",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500166 entry("FILENAME=%s", pnorTOC.c_str()));
Saqib Khan6a522262017-09-26 12:02:50 -0500167 ItemUpdater::erase(id);
168 continue;
Saqib Khan4c5d7442017-07-18 00:43:52 -0500169 }
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600170 auto keyValues = Version::getValue(
171 pnorTOC, {{"version", ""}, {"extended_version", ""}});
Saqib Khan4c5d7442017-07-18 00:43:52 -0500172 auto& version = keyValues.at("version");
173 if (version.empty())
174 {
175 log<level::ERR>("Failed to read version from pnorTOC",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500176 entry("FILENAME=%s", pnorTOC.c_str()));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500177 activationState = server::Activation::Activations::Invalid;
178 }
179
180 auto& extendedVersion = keyValues.at("extended_version");
181 if (extendedVersion.empty())
182 {
183 log<level::ERR>("Failed to read extendedVersion from pnorTOC",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500184 entry("FILENAME=%s", pnorTOC.c_str()));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500185 activationState = server::Activation::Activations::Invalid;
186 }
187
Saqib Khan4c5d7442017-07-18 00:43:52 -0500188 auto purpose = server::Version::VersionPurpose::Host;
189 auto path = fs::path(SOFTWARE_OBJPATH) / id;
Gunnar Mills3588acc2017-09-07 13:13:22 -0500190 AssociationList associations = {};
Saqib Khan4c5d7442017-07-18 00:43:52 -0500191
Gunnar Mills3588acc2017-09-07 13:13:22 -0500192 if (activationState == server::Activation::Activations::Active)
193 {
194 // Create an association to the host inventory item
195 associations.emplace_back(std::make_tuple(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600196 ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
197 HOST_INVENTORY_PATH));
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500198
Gunnar Mills3588acc2017-09-07 13:13:22 -0500199 // Create an active association since this image is active
200 createActiveAssociation(path);
201 }
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500202
Saqib Khan4c5d7442017-07-18 00:43:52 -0500203 // Create Activation instance for this version.
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600204 activations.insert(
205 std::make_pair(id, std::make_unique<Activation>(
206 bus, path, *this, id, extendedVersion,
207 activationState, associations)));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500208
209 // If Active, create RedundancyPriority instance for this version.
210 if (activationState == server::Activation::Activations::Active)
211 {
Michael Tritz36417922017-08-04 14:00:29 -0500212 uint8_t priority = std::numeric_limits<uint8_t>::max();
213 if (!restoreFromFile(id, priority))
Saqib Khan4c5d7442017-07-18 00:43:52 -0500214 {
Michael Tritz36417922017-08-04 14:00:29 -0500215 log<level::ERR>("Unable to restore priority from file.",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500216 entry("VERSIONID=%s", id.c_str()));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500217 }
Michael Tritz36417922017-08-04 14:00:29 -0500218 activations.find(id)->second->redundancyPriority =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600219 std::make_unique<RedundancyPriority>(
220 bus, path, *(activations.find(id)->second), priority);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500221 }
222
223 // Create Version instance for this version.
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500224 auto versionPtr = std::make_unique<Version>(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600225 bus, path, *this, id, version, purpose, "",
226 std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500227 versionPtr->deleteObject =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600228 std::make_unique<Delete>(bus, path, *versionPtr);
229 versions.insert(std::make_pair(id, std::move(versionPtr)));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500230 }
Saqib Khan2be9ba92017-09-26 22:44:10 -0500231 else if (0 == iter.path().native().compare(0, PNOR_RW_PREFIX_LEN,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600232 PNOR_RW_PREFIX))
Saqib Khan2be9ba92017-09-26 22:44:10 -0500233 {
234 auto id = iter.path().native().substr(PNOR_RW_PREFIX_LEN);
235 auto roDir = PNOR_RO_PREFIX + id;
236 if (!fs::is_directory(roDir))
237 {
238 log<level::ERR>("No corresponding read-only volume found.",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500239 entry("DIRNAME=%s", roDir.c_str()));
Saqib Khan2be9ba92017-09-26 22:44:10 -0500240 ItemUpdater::erase(id);
241 }
242 }
Saqib Khan4c5d7442017-07-18 00:43:52 -0500243 }
Gunnar Mills2badd7a2017-09-20 12:51:28 -0500244
245 // Look at the RO symlink to determine if there is a functional image
246 auto id = determineId(PNOR_RO_ACTIVE_PATH);
247 if (!id.empty())
248 {
249 updateFunctionalAssociation(std::string{SOFTWARE_OBJPATH} + '/' + id);
250 }
Saqib Khan167601b2017-06-18 23:33:46 -0500251 return;
Saqib Khan7254f0e2017-04-10 21:45:37 -0500252}
253
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500254int ItemUpdater::validateSquashFSImage(const std::string& filePath)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500255{
Saqib Khan4c5d7442017-07-18 00:43:52 -0500256 auto file = fs::path(filePath) / squashFSImage;
257 if (fs::is_regular_file(file))
Saqib Khana8ade7e2017-04-12 10:27:56 -0500258 {
259 return 0;
260 }
261 else
262 {
263 log<level::ERR>("Failed to find the SquashFS image.");
264 return -1;
265 }
266}
267
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500268void ItemUpdater::removeReadOnlyPartition(std::string versionId)
Michael Tritzdd961b62017-05-17 14:07:03 -0500269{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600270 auto serviceFile = "obmc-flash-bios-ubiumount-ro@" + versionId + ".service";
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500271
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600272 // Remove the read-only partitions.
273 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
274 SYSTEMD_INTERFACE, "StartUnit");
275 method.append(serviceFile, "replace");
276 bus.call_noreply(method);
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500277}
278
279void ItemUpdater::removeReadWritePartition(std::string versionId)
280{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600281 auto serviceFile = "obmc-flash-bios-ubiumount-rw@" + versionId + ".service";
Michael Tritzdd961b62017-05-17 14:07:03 -0500282
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600283 // Remove the read-write partitions.
284 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
285 SYSTEMD_INTERFACE, "StartUnit");
286 method.append(serviceFile, "replace");
287 bus.call_noreply(method);
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500288}
Michael Tritzdd961b62017-05-17 14:07:03 -0500289
Michael Tritzfa7aa122017-09-22 15:16:11 -0500290void ItemUpdater::reset()
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500291{
Adriana Kobylak0bd65052018-07-09 10:55:56 -0500292 std::vector<uint8_t> mboxdArgs;
293
294 // Suspend mboxd - no args required.
295 auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
296 MBOXD_INTERFACE, "cmd");
297
298 dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
299
300 auto responseMsg = bus.call(dbusCall);
301 if (responseMsg.is_method_error())
302 {
303 log<level::ERR>("Error in mboxd suspend call");
304 elog<InternalFailure>();
305 }
306
Michael Tritzbb31f022017-11-22 11:51:29 -0600307 constexpr static auto patchDir = "/usr/local/share/pnor";
308 if (fs::is_directory(patchDir))
309 {
310 for (const auto& iter : fs::directory_iterator(patchDir))
311 {
312 fs::remove_all(iter);
313 }
314 }
315
Adriana Kobylakca9ba062018-07-09 11:00:21 -0500316 // Clear the read-write partitions.
Michael Tritzfa7aa122017-09-22 15:16:11 -0500317 for (const auto& it : activations)
318 {
Adriana Kobylakca9ba062018-07-09 11:00:21 -0500319 auto rwDir = PNOR_RW_PREFIX + it.first;
320 if (fs::is_directory(rwDir))
Michael Tritzfa7aa122017-09-22 15:16:11 -0500321 {
Adriana Kobylakca9ba062018-07-09 11:00:21 -0500322 for (const auto& iter : fs::directory_iterator(rwDir))
323 {
324 fs::remove_all(iter);
325 }
Michael Tritzfa7aa122017-09-22 15:16:11 -0500326 }
Michael Tritzfa7aa122017-09-22 15:16:11 -0500327 }
Michael Tritzdd961b62017-05-17 14:07:03 -0500328
Adriana Kobylakca9ba062018-07-09 11:00:21 -0500329 // Clear the preserved partition.
330 if (fs::is_directory(PNOR_PRSV))
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500331 {
Adriana Kobylakca9ba062018-07-09 11:00:21 -0500332 for (const auto& iter : fs::directory_iterator(PNOR_PRSV))
333 {
334 fs::remove_all(iter);
335 }
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500336 }
Michael Tritzfa7aa122017-09-22 15:16:11 -0500337
Adriana Kobylak0bd65052018-07-09 10:55:56 -0500338 // Resume mboxd with arg 1, indicating that the flash was modified.
339 dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
340 "cmd");
341
342 mboxdArgs.push_back(1);
343 dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
344
345 responseMsg = bus.call(dbusCall);
346 if (responseMsg.is_method_error())
347 {
348 log<level::ERR>("Error in mboxd resume call");
349 elog<InternalFailure>();
350 }
351
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500352 return;
353}
354
Michael Tritz5b756512017-10-06 16:52:01 -0500355bool ItemUpdater::isVersionFunctional(const std::string& versionId)
Eddie James13fc66a2017-08-31 15:36:44 -0500356{
357 if (!fs::exists(PNOR_RO_ACTIVE_PATH))
358 {
359 return false;
360 }
361
362 fs::path activeRO = fs::read_symlink(PNOR_RO_ACTIVE_PATH);
363
364 if (!fs::is_directory(activeRO))
365 {
366 return false;
367 }
368
369 if (activeRO.string().find(versionId) == std::string::npos)
370 {
371 return false;
372 }
373
374 // active PNOR is the version we're checking
375 return true;
376}
377
378bool ItemUpdater::isChassisOn()
379{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600380 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
381 MAPPER_INTERFACE, "GetObject");
Eddie James13fc66a2017-08-31 15:36:44 -0500382
383 mapperCall.append(CHASSIS_STATE_PATH,
384 std::vector<std::string>({CHASSIS_STATE_OBJ}));
385 auto mapperResponseMsg = bus.call(mapperCall);
386 if (mapperResponseMsg.is_method_error())
387 {
388 log<level::ERR>("Error in Mapper call");
389 elog<InternalFailure>();
390 }
391 using MapperResponseType = std::map<std::string, std::vector<std::string>>;
392 MapperResponseType mapperResponse;
393 mapperResponseMsg.read(mapperResponse);
394 if (mapperResponse.empty())
395 {
396 log<level::ERR>("Invalid Response from mapper");
397 elog<InternalFailure>();
398 }
399
400 auto method = bus.new_method_call((mapperResponse.begin()->first).c_str(),
401 CHASSIS_STATE_PATH,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600402 SYSTEMD_PROPERTY_INTERFACE, "Get");
Eddie James13fc66a2017-08-31 15:36:44 -0500403 method.append(CHASSIS_STATE_OBJ, "CurrentPowerState");
404 auto response = bus.call(method);
405 if (response.is_method_error())
406 {
407 log<level::ERR>("Error in fetching current Chassis State",
Gunnar Mills850d5f62017-10-19 17:04:38 -0500408 entry("MAPPERRESPONSE=%s",
Eddie James13fc66a2017-08-31 15:36:44 -0500409 (mapperResponse.begin()->first).c_str()));
410 elog<InternalFailure>();
411 }
412 sdbusplus::message::variant<std::string> currentChassisState;
413 response.read(currentChassisState);
414 auto strParam =
415 sdbusplus::message::variant_ns::get<std::string>(currentChassisState);
416 return (strParam != CHASSIS_STATE_OFF);
417}
418
Saqib Khanb8e7f312017-08-12 10:24:10 -0500419void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
Saqib Khan81bac882017-06-08 12:17:01 -0500420{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600421 // TODO openbmc/openbmc#1896 Improve the performance of this function
Saqib Khan81bac882017-06-08 12:17:01 -0500422 for (const auto& intf : activations)
423 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500424 if (intf.second->redundancyPriority)
Saqib Khan81bac882017-06-08 12:17:01 -0500425 {
Saqib Khanb8e7f312017-08-12 10:24:10 -0500426 if (intf.second->redundancyPriority.get()->priority() == value &&
427 intf.second->versionId != versionId)
Saqib Khan81bac882017-06-08 12:17:01 -0500428 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500429 intf.second->redundancyPriority.get()->priority(value + 1);
Saqib Khan81bac882017-06-08 12:17:01 -0500430 }
431 }
432 }
433}
434
Saqib Khan2af5c492017-07-17 16:15:13 -0500435bool ItemUpdater::isLowestPriority(uint8_t value)
436{
437 for (const auto& intf : activations)
438 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500439 if (intf.second->redundancyPriority)
Saqib Khan2af5c492017-07-17 16:15:13 -0500440 {
441 if (intf.second->redundancyPriority.get()->priority() < value)
442 {
443 return false;
444 }
445 }
446 }
447 return true;
448}
449
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500450void ItemUpdater::erase(std::string entryId)
451{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600452 if (isVersionFunctional(entryId) && isChassisOn())
453 {
454 log<level::ERR>(("Error: Version " + entryId +
455 " is currently active and running on the host."
456 " Unable to remove.")
457 .c_str());
Eddie James13fc66a2017-08-31 15:36:44 -0500458 return;
459 }
Saqib Khanef8cd9f2017-08-16 14:20:30 -0500460 // Remove priority persistence file
461 removeFile(entryId);
462
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500463 // Removing read-only and read-write partitions
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500464 removeReadWritePartition(entryId);
465 removeReadOnlyPartition(entryId);
466
467 // Removing entry in versions map
468 auto it = versions.find(entryId);
469 if (it == versions.end())
470 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600471 log<level::ERR>(("Error: Failed to find version " + entryId +
472 " in item updater versions map."
473 " Unable to remove.")
474 .c_str());
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500475 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500476 else
477 {
478 versions.erase(entryId);
479 }
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500480
481 // Removing entry in activations map
482 auto ita = activations.find(entryId);
483 if (ita == activations.end())
484 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600485 log<level::ERR>(("Error: Failed to find version " + entryId +
486 " in item updater activations map."
487 " Unable to remove.")
488 .c_str());
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500489 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500490 else
491 {
492 activations.erase(entryId);
493 }
494 return;
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500495}
496
Michael Tritz234a07e2017-09-21 00:53:06 -0500497void ItemUpdater::deleteAll()
498{
Adriana Kobylakc39d9232018-07-20 11:31:27 -0500499 auto chassisOn = isChassisOn();
500
Michael Tritz234a07e2017-09-21 00:53:06 -0500501 for (const auto& activationIt : activations)
502 {
Adriana Kobylakc39d9232018-07-20 11:31:27 -0500503 if (isVersionFunctional(activationIt.first) && chassisOn)
504 {
505 continue;
506 }
507 else
Michael Tritz234a07e2017-09-21 00:53:06 -0500508 {
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500509 ItemUpdater::erase(activationIt.first);
Michael Tritz234a07e2017-09-21 00:53:06 -0500510 }
511 }
512
Michael Tritz234a07e2017-09-21 00:53:06 -0500513 // Remove any remaining pnor-ro- or pnor-rw- volumes that do not match
514 // the current version.
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600515 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
516 SYSTEMD_INTERFACE, "StartUnit");
Michael Tritz234a07e2017-09-21 00:53:06 -0500517 method.append("obmc-flash-bios-cleanup.service", "replace");
518 bus.call_noreply(method);
519}
520
Saqib Khan2cbfa032017-08-17 14:52:37 -0500521// TODO: openbmc/openbmc#1402 Monitor flash usage
522void ItemUpdater::freeSpace()
523{
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600524 // Versions with the highest priority in front
525 std::priority_queue<std::pair<int, std::string>,
526 std::vector<std::pair<int, std::string>>,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600527 std::less<std::pair<int, std::string>>>
528 versionsPQ;
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600529
Saqib Khan2cbfa032017-08-17 14:52:37 -0500530 std::size_t count = 0;
Saqib Khan2cbfa032017-08-17 14:52:37 -0500531 for (const auto& iter : activations)
532 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600533 if (iter.second.get()->activation() ==
534 server::Activation::Activations::Active)
Saqib Khan2cbfa032017-08-17 14:52:37 -0500535 {
536 count++;
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600537 // Don't put the functional version on the queue since we can't
538 // remove the "running" PNOR version.
Adriana Kobylakee201a52017-11-09 15:05:04 -0600539 if (isVersionFunctional(iter.second->versionId))
540 {
541 continue;
542 }
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600543 versionsPQ.push(std::make_pair(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600544 iter.second->redundancyPriority.get()->priority(),
545 iter.second->versionId));
Saqib Khan2cbfa032017-08-17 14:52:37 -0500546 }
547 }
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600548
549 // If the number of PNOR versions is over ACTIVE_PNOR_MAX_ALLOWED -1,
550 // remove the highest priority one(s).
551 while ((count >= ACTIVE_PNOR_MAX_ALLOWED) && (!versionsPQ.empty()))
Saqib Khan2cbfa032017-08-17 14:52:37 -0500552 {
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600553 erase(versionsPQ.top().second);
554 versionsPQ.pop();
555 count--;
Saqib Khan2cbfa032017-08-17 14:52:37 -0500556 }
557}
558
Gunnar Mills61010b22017-09-20 15:25:26 -0500559void ItemUpdater::createActiveAssociation(const std::string& path)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500560{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600561 assocs.emplace_back(
562 std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
Gunnar Mills9741cd12017-08-28 15:09:00 -0500563 associations(assocs);
564}
565
Gunnar Mills833e4f32017-09-14 12:30:27 -0500566void ItemUpdater::updateFunctionalAssociation(const std::string& path)
567{
568 // remove all functional associations
569 for (auto iter = assocs.begin(); iter != assocs.end();)
570 {
571 if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0)
572 {
573 iter = assocs.erase(iter);
574 }
575 else
576 {
577 ++iter;
578 }
579 }
580 assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600581 FUNCTIONAL_REV_ASSOCIATION, path));
Gunnar Mills833e4f32017-09-14 12:30:27 -0500582 associations(assocs);
583}
584
Gunnar Mills61010b22017-09-20 15:25:26 -0500585void ItemUpdater::removeActiveAssociation(const std::string& path)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500586{
587 for (auto iter = assocs.begin(); iter != assocs.end();)
588 {
Gunnar Mills833e4f32017-09-14 12:30:27 -0500589 if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 &&
590 (std::get<2>(*iter)).compare(path) == 0)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500591 {
592 iter = assocs.erase(iter);
593 associations(assocs);
594 }
595 else
596 {
597 ++iter;
598 }
599 }
600}
601
Gunnar Mills2badd7a2017-09-20 12:51:28 -0500602std::string ItemUpdater::determineId(const std::string& symlinkPath)
603{
604 if (!fs::exists(symlinkPath))
605 {
606 return {};
607 }
608
609 auto target = fs::canonical(symlinkPath).string();
610
611 // check to make sure the target really exists
612 if (!fs::is_regular_file(target + "/" + PNOR_TOC_FILE))
613 {
614 return {};
615 }
616 // Get the image <id> from the symlink target
617 // for example /media/ro-2a1022fe
618 static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
619 return target.substr(PNOR_RO_PREFIX_LEN);
620}
621
Michael Tritzb541f1b2017-10-15 15:10:21 -0500622void GardReset::reset()
623{
624 // The GARD partition is currently misspelled "GUARD." This file path will
625 // need to be updated in the future.
626 auto path = fs::path(PNOR_PRSV_ACTIVE_PATH);
627 path /= "GUARD";
628 std::vector<uint8_t> mboxdArgs;
629
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600630 auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
631 MBOXD_INTERFACE, "cmd");
Michael Tritzb541f1b2017-10-15 15:10:21 -0500632
633 // Suspend mboxd - no args required.
634 dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
635
636 auto responseMsg = bus.call(dbusCall);
637 if (responseMsg.is_method_error())
638 {
639 log<level::ERR>("Error in mboxd suspend call");
640 elog<InternalFailure>();
641 }
642
643 if (fs::is_regular_file(path))
644 {
645 fs::remove(path);
646 }
647
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600648 dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
649 "cmd");
Michael Tritzb541f1b2017-10-15 15:10:21 -0500650
651 // Resume mboxd with arg 1, indicating that the flash is modified.
652 mboxdArgs.push_back(1);
653 dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
654
655 responseMsg = bus.call(dbusCall);
656 if (responseMsg.is_method_error())
657 {
658 log<level::ERR>("Error in mboxd resume call");
659 elog<InternalFailure>();
660 }
661}
662
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500663} // namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500664} // namespace software
665} // namespace openpower