blob: a3b1c9cd0bb7fb45b480a37803b3e7c1c1f2bea6 [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>
Gunnar Millsfedbf3d2018-01-17 11:17:31 -06004#include <queue>
Eddie James13fc66a2017-08-31 15:36:44 -05005#include <phosphor-logging/elog-errors.hpp>
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -05006#include <phosphor-logging/log.hpp>
Eddie James13fc66a2017-08-31 15:36:44 -05007#include "xyz/openbmc_project/Common/error.hpp"
Adriana Kobylakd6a549e2017-05-10 16:23:01 -05008#include <xyz/openbmc_project/Software/Version/server.hpp>
Saqib Khan167601b2017-06-18 23:33:46 -05009#include "version.hpp"
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050010#include "config.h"
11#include "item_updater.hpp"
Saqib Khana8ade7e2017-04-12 10:27:56 -050012#include "activation.hpp"
Michael Tritz60bc20f2017-07-29 23:32:21 -050013#include "serialize.hpp"
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050014
15namespace openpower
16{
17namespace software
18{
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050019namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050020{
21
Saqib Khana8ade7e2017-04-12 10:27:56 -050022// When you see server:: you know we're referencing our base class
23namespace server = sdbusplus::xyz::openbmc_project::Software::server;
Adriana Kobylak5ba6b102017-05-19 09:41:27 -050024namespace fs = std::experimental::filesystem;
Saqib Khana8ade7e2017-04-12 10:27:56 -050025
Eddie James13fc66a2017-08-31 15:36:44 -050026using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050027using namespace phosphor::logging;
28
Saqib Khana8ade7e2017-04-12 10:27:56 -050029constexpr auto squashFSImage = "pnor.xz.squashfs";
30
Michael Tritzb541f1b2017-10-15 15:10:21 -050031// TODO: Change paths once openbmc/openbmc#1663 is completed.
32constexpr auto MBOXD_INTERFACE = "org.openbmc.mboxd";
33constexpr auto MBOXD_PATH = "/org/openbmc/mboxd";
34
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;
Adriana Kobylak70dcb632018-02-27 15:46:52 -060043 std::map<std::string, std::map<std::string, msg::variant<std::string>>>
44 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(
Adriana Kobylak70dcb632018-02-27 15:46:52 -060062 variant_ns::get<std::string>(property.second));
Patrick Williamse4290942017-06-16 05:43:08 -050063
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",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -050097 entry("OBJPATH=%s", path.c_str()));
Adriana Kobylakd6a549e2017-05-10 16:23:01 -050098 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(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600113 ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
114 HOST_INVENTORY_PATH));
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -0500115 }
116
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500117 fs::path manifestPath(filePath);
118 manifestPath /= MANIFEST_FILE;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600119 std::string extendedVersion =
120 (Version::getValue(
121 manifestPath.string(),
122 std::map<std::string, std::string>{{"extended_version", ""}}))
123 .begin()
124 ->second;
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500125
Adriana Kobylakd6a549e2017-05-10 16:23:01 -0500126 activations.insert(std::make_pair(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600127 versionId, std::make_unique<Activation>(
128 bus, path, *this, versionId, extendedVersion,
129 activationState, associations)));
Michael Tritz5b756512017-10-06 16:52:01 -0500130
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500131 auto versionPtr = std::make_unique<Version>(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600132 bus, path, *this, versionId, version, purpose, filePath,
133 std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500134 versionPtr->deleteObject =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600135 std::make_unique<Delete>(bus, path, *versionPtr);
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500136 versions.insert(std::make_pair(versionId, std::move(versionPtr)));
Saqib Khan00044f42017-07-10 17:24:43 -0500137 }
Patrick Williams3accb322017-05-30 16:29:52 -0500138 return;
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500139}
140
Saqib Khan167601b2017-06-18 23:33:46 -0500141void ItemUpdater::processPNORImage()
Saqib Khan7254f0e2017-04-10 21:45:37 -0500142{
Saqib Khan4c5d7442017-07-18 00:43:52 -0500143 // Read pnor.toc from folders under /media/
144 // to get Active Software Versions.
Gunnar Mills3fa70282017-08-18 15:30:42 -0500145 for (const auto& iter : fs::directory_iterator(MEDIA_DIR))
Saqib Khan4c5d7442017-07-18 00:43:52 -0500146 {
147 auto activationState = server::Activation::Activations::Active;
148
149 static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
Saqib Khan2be9ba92017-09-26 22:44:10 -0500150 static const auto PNOR_RW_PREFIX_LEN = strlen(PNOR_RW_PREFIX);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500151
152 // Check if the PNOR_RO_PREFIX is the prefix of the iter.path
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600153 if (0 ==
154 iter.path().native().compare(0, PNOR_RO_PREFIX_LEN, PNOR_RO_PREFIX))
Saqib Khan4c5d7442017-07-18 00:43:52 -0500155 {
Saqib Khan6a522262017-09-26 12:02:50 -0500156 // The versionId is extracted from the path
157 // for example /media/pnor-ro-2a1022fe.
158 auto id = iter.path().native().substr(PNOR_RO_PREFIX_LEN);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500159 auto pnorTOC = iter.path() / PNOR_TOC_FILE;
160 if (!fs::is_regular_file(pnorTOC))
161 {
Gunnar Mills850d5f62017-10-19 17:04:38 -0500162 log<level::ERR>("Failed to read pnorTOC.",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500163 entry("FILENAME=%s", pnorTOC.c_str()));
Saqib Khan6a522262017-09-26 12:02:50 -0500164 ItemUpdater::erase(id);
165 continue;
Saqib Khan4c5d7442017-07-18 00:43:52 -0500166 }
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600167 auto keyValues = Version::getValue(
168 pnorTOC, {{"version", ""}, {"extended_version", ""}});
Saqib Khan4c5d7442017-07-18 00:43:52 -0500169 auto& version = keyValues.at("version");
170 if (version.empty())
171 {
172 log<level::ERR>("Failed to read version from pnorTOC",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500173 entry("FILENAME=%s", pnorTOC.c_str()));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500174 activationState = server::Activation::Activations::Invalid;
175 }
176
177 auto& extendedVersion = keyValues.at("extended_version");
178 if (extendedVersion.empty())
179 {
180 log<level::ERR>("Failed to read extendedVersion from pnorTOC",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500181 entry("FILENAME=%s", pnorTOC.c_str()));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500182 activationState = server::Activation::Activations::Invalid;
183 }
184
Saqib Khan4c5d7442017-07-18 00:43:52 -0500185 auto purpose = server::Version::VersionPurpose::Host;
186 auto path = fs::path(SOFTWARE_OBJPATH) / id;
Gunnar Mills3588acc2017-09-07 13:13:22 -0500187 AssociationList associations = {};
Saqib Khan4c5d7442017-07-18 00:43:52 -0500188
Gunnar Mills3588acc2017-09-07 13:13:22 -0500189 if (activationState == server::Activation::Activations::Active)
190 {
191 // Create an association to the host inventory item
192 associations.emplace_back(std::make_tuple(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600193 ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
194 HOST_INVENTORY_PATH));
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500195
Gunnar Mills3588acc2017-09-07 13:13:22 -0500196 // Create an active association since this image is active
197 createActiveAssociation(path);
198 }
Gunnar Mills3edb84b2017-08-18 15:13:15 -0500199
Saqib Khan4c5d7442017-07-18 00:43:52 -0500200 // Create Activation instance for this version.
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600201 activations.insert(
202 std::make_pair(id, std::make_unique<Activation>(
203 bus, path, *this, id, extendedVersion,
204 activationState, associations)));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500205
206 // If Active, create RedundancyPriority instance for this version.
207 if (activationState == server::Activation::Activations::Active)
208 {
Michael Tritz36417922017-08-04 14:00:29 -0500209 uint8_t priority = std::numeric_limits<uint8_t>::max();
210 if (!restoreFromFile(id, priority))
Saqib Khan4c5d7442017-07-18 00:43:52 -0500211 {
Michael Tritz36417922017-08-04 14:00:29 -0500212 log<level::ERR>("Unable to restore priority from file.",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500213 entry("VERSIONID=%s", id.c_str()));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500214 }
Michael Tritz36417922017-08-04 14:00:29 -0500215 activations.find(id)->second->redundancyPriority =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600216 std::make_unique<RedundancyPriority>(
217 bus, path, *(activations.find(id)->second), priority);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500218 }
219
220 // Create Version instance for this version.
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500221 auto versionPtr = std::make_unique<Version>(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600222 bus, path, *this, id, version, purpose, "",
223 std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500224 versionPtr->deleteObject =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600225 std::make_unique<Delete>(bus, path, *versionPtr);
226 versions.insert(std::make_pair(id, std::move(versionPtr)));
Saqib Khan4c5d7442017-07-18 00:43:52 -0500227 }
Saqib Khan2be9ba92017-09-26 22:44:10 -0500228 else if (0 == iter.path().native().compare(0, PNOR_RW_PREFIX_LEN,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600229 PNOR_RW_PREFIX))
Saqib Khan2be9ba92017-09-26 22:44:10 -0500230 {
231 auto id = iter.path().native().substr(PNOR_RW_PREFIX_LEN);
232 auto roDir = PNOR_RO_PREFIX + id;
233 if (!fs::is_directory(roDir))
234 {
235 log<level::ERR>("No corresponding read-only volume found.",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500236 entry("DIRNAME=%s", roDir.c_str()));
Saqib Khan2be9ba92017-09-26 22:44:10 -0500237 ItemUpdater::erase(id);
238 }
239 }
Saqib Khan4c5d7442017-07-18 00:43:52 -0500240 }
Gunnar Mills2badd7a2017-09-20 12:51:28 -0500241
242 // Look at the RO symlink to determine if there is a functional image
243 auto id = determineId(PNOR_RO_ACTIVE_PATH);
244 if (!id.empty())
245 {
246 updateFunctionalAssociation(std::string{SOFTWARE_OBJPATH} + '/' + id);
247 }
Saqib Khan167601b2017-06-18 23:33:46 -0500248 return;
Saqib Khan7254f0e2017-04-10 21:45:37 -0500249}
250
Adriana Kobylak5ba6b102017-05-19 09:41:27 -0500251int ItemUpdater::validateSquashFSImage(const std::string& filePath)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500252{
Saqib Khan4c5d7442017-07-18 00:43:52 -0500253 auto file = fs::path(filePath) / squashFSImage;
254 if (fs::is_regular_file(file))
Saqib Khana8ade7e2017-04-12 10:27:56 -0500255 {
256 return 0;
257 }
258 else
259 {
260 log<level::ERR>("Failed to find the SquashFS image.");
261 return -1;
262 }
263}
264
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500265void ItemUpdater::removeReadOnlyPartition(std::string versionId)
Michael Tritzdd961b62017-05-17 14:07:03 -0500266{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600267 auto serviceFile = "obmc-flash-bios-ubiumount-ro@" + versionId + ".service";
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500268
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600269 // Remove the read-only partitions.
270 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
271 SYSTEMD_INTERFACE, "StartUnit");
272 method.append(serviceFile, "replace");
273 bus.call_noreply(method);
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500274}
275
276void ItemUpdater::removeReadWritePartition(std::string versionId)
277{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600278 auto serviceFile = "obmc-flash-bios-ubiumount-rw@" + versionId + ".service";
Michael Tritzdd961b62017-05-17 14:07:03 -0500279
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600280 // Remove the read-write partitions.
281 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
282 SYSTEMD_INTERFACE, "StartUnit");
283 method.append(serviceFile, "replace");
284 bus.call_noreply(method);
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500285}
Michael Tritzdd961b62017-05-17 14:07:03 -0500286
Michael Tritzfa7aa122017-09-22 15:16:11 -0500287void ItemUpdater::reset()
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500288{
Michael Tritzbb31f022017-11-22 11:51:29 -0600289 constexpr static auto patchDir = "/usr/local/share/pnor";
290 if (fs::is_directory(patchDir))
291 {
292 for (const auto& iter : fs::directory_iterator(patchDir))
293 {
294 fs::remove_all(iter);
295 }
296 }
297
Michael Tritzfa7aa122017-09-22 15:16:11 -0500298 for (const auto& it : activations)
299 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600300 auto serviceFile =
301 "obmc-flash-bios-ubiclear@pnor-rw-" + it.first + ".service";
Michael Tritzfa7aa122017-09-22 15:16:11 -0500302
303 // Clear the read-write partitions.
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600304 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
305 SYSTEMD_INTERFACE, "StartUnit");
Michael Tritzfa7aa122017-09-22 15:16:11 -0500306 method.append(serviceFile, "replace");
307 auto reply = bus.call(method);
308
309 if (reply.is_method_error())
310 {
Marri Devender Rao795d9842017-11-07 22:52:07 -0600311 log<level::ERR>("Failed to clear read-write partitions",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500312 entry("SERVICE_FILE=%s", serviceFile.c_str()));
Michael Tritzfa7aa122017-09-22 15:16:11 -0500313 elog<InternalFailure>();
314 }
Michael Tritzfa7aa122017-09-22 15:16:11 -0500315 }
Marri Devender Rao795d9842017-11-07 22:52:07 -0600316 static constexpr auto serviceFile =
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600317 "obmc-flash-bios-ubiclear@pnor-prsv.service";
Michael Tritzfa7aa122017-09-22 15:16:11 -0500318 // Clear the preserved partition.
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600319 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
320 SYSTEMD_INTERFACE, "StartUnit");
Marri Devender Rao795d9842017-11-07 22:52:07 -0600321 method.append(serviceFile, "replace");
Michael Tritzfa7aa122017-09-22 15:16:11 -0500322 auto reply = bus.call(method);
Michael Tritzdd961b62017-05-17 14:07:03 -0500323
Michael Tritzfa7aa122017-09-22 15:16:11 -0500324 if (reply.is_method_error())
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500325 {
Marri Devender Rao795d9842017-11-07 22:52:07 -0600326 log<level::ERR>("Failed to clear preserved partition",
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600327 entry("SERVICE_FILE=%s", serviceFile));
Michael Tritzfa7aa122017-09-22 15:16:11 -0500328 elog<InternalFailure>();
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500329 }
Michael Tritzfa7aa122017-09-22 15:16:11 -0500330
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500331 return;
332}
333
Michael Tritz5b756512017-10-06 16:52:01 -0500334bool ItemUpdater::isVersionFunctional(const std::string& versionId)
Eddie James13fc66a2017-08-31 15:36:44 -0500335{
336 if (!fs::exists(PNOR_RO_ACTIVE_PATH))
337 {
338 return false;
339 }
340
341 fs::path activeRO = fs::read_symlink(PNOR_RO_ACTIVE_PATH);
342
343 if (!fs::is_directory(activeRO))
344 {
345 return false;
346 }
347
348 if (activeRO.string().find(versionId) == std::string::npos)
349 {
350 return false;
351 }
352
353 // active PNOR is the version we're checking
354 return true;
355}
356
357bool ItemUpdater::isChassisOn()
358{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600359 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
360 MAPPER_INTERFACE, "GetObject");
Eddie James13fc66a2017-08-31 15:36:44 -0500361
362 mapperCall.append(CHASSIS_STATE_PATH,
363 std::vector<std::string>({CHASSIS_STATE_OBJ}));
364 auto mapperResponseMsg = bus.call(mapperCall);
365 if (mapperResponseMsg.is_method_error())
366 {
367 log<level::ERR>("Error in Mapper call");
368 elog<InternalFailure>();
369 }
370 using MapperResponseType = std::map<std::string, std::vector<std::string>>;
371 MapperResponseType mapperResponse;
372 mapperResponseMsg.read(mapperResponse);
373 if (mapperResponse.empty())
374 {
375 log<level::ERR>("Invalid Response from mapper");
376 elog<InternalFailure>();
377 }
378
379 auto method = bus.new_method_call((mapperResponse.begin()->first).c_str(),
380 CHASSIS_STATE_PATH,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600381 SYSTEMD_PROPERTY_INTERFACE, "Get");
Eddie James13fc66a2017-08-31 15:36:44 -0500382 method.append(CHASSIS_STATE_OBJ, "CurrentPowerState");
383 auto response = bus.call(method);
384 if (response.is_method_error())
385 {
386 log<level::ERR>("Error in fetching current Chassis State",
Gunnar Mills850d5f62017-10-19 17:04:38 -0500387 entry("MAPPERRESPONSE=%s",
Eddie James13fc66a2017-08-31 15:36:44 -0500388 (mapperResponse.begin()->first).c_str()));
389 elog<InternalFailure>();
390 }
391 sdbusplus::message::variant<std::string> currentChassisState;
392 response.read(currentChassisState);
393 auto strParam =
394 sdbusplus::message::variant_ns::get<std::string>(currentChassisState);
395 return (strParam != CHASSIS_STATE_OFF);
396}
397
Saqib Khanb8e7f312017-08-12 10:24:10 -0500398void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
Saqib Khan81bac882017-06-08 12:17:01 -0500399{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600400 // TODO openbmc/openbmc#1896 Improve the performance of this function
Saqib Khan81bac882017-06-08 12:17:01 -0500401 for (const auto& intf : activations)
402 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500403 if (intf.second->redundancyPriority)
Saqib Khan81bac882017-06-08 12:17:01 -0500404 {
Saqib Khanb8e7f312017-08-12 10:24:10 -0500405 if (intf.second->redundancyPriority.get()->priority() == value &&
406 intf.second->versionId != versionId)
Saqib Khan81bac882017-06-08 12:17:01 -0500407 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500408 intf.second->redundancyPriority.get()->priority(value + 1);
Saqib Khan81bac882017-06-08 12:17:01 -0500409 }
410 }
411 }
412}
413
Saqib Khan2af5c492017-07-17 16:15:13 -0500414bool ItemUpdater::isLowestPriority(uint8_t value)
415{
416 for (const auto& intf : activations)
417 {
Gunnar Mills3fa70282017-08-18 15:30:42 -0500418 if (intf.second->redundancyPriority)
Saqib Khan2af5c492017-07-17 16:15:13 -0500419 {
420 if (intf.second->redundancyPriority.get()->priority() < value)
421 {
422 return false;
423 }
424 }
425 }
426 return true;
427}
428
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500429void ItemUpdater::erase(std::string entryId)
430{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600431 if (isVersionFunctional(entryId) && isChassisOn())
432 {
433 log<level::ERR>(("Error: Version " + entryId +
434 " is currently active and running on the host."
435 " Unable to remove.")
436 .c_str());
Eddie James13fc66a2017-08-31 15:36:44 -0500437 return;
438 }
Saqib Khanef8cd9f2017-08-16 14:20:30 -0500439 // Remove priority persistence file
440 removeFile(entryId);
441
Saqib Khan1e0aa5c2017-08-31 11:04:17 -0500442 // Removing read-only and read-write partitions
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500443 removeReadWritePartition(entryId);
444 removeReadOnlyPartition(entryId);
445
446 // Removing entry in versions map
447 auto it = versions.find(entryId);
448 if (it == versions.end())
449 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600450 log<level::ERR>(("Error: Failed to find version " + entryId +
451 " in item updater versions map."
452 " Unable to remove.")
453 .c_str());
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500454 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500455 else
456 {
457 versions.erase(entryId);
458 }
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500459
460 // Removing entry in activations map
461 auto ita = activations.find(entryId);
462 if (ita == activations.end())
463 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600464 log<level::ERR>(("Error: Failed to find version " + entryId +
465 " in item updater activations map."
466 " Unable to remove.")
467 .c_str());
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500468 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500469 else
470 {
471 activations.erase(entryId);
472 }
473 return;
Leonel Gonzalez9c8adfa2017-07-12 11:08:40 -0500474}
475
Michael Tritz234a07e2017-09-21 00:53:06 -0500476void ItemUpdater::deleteAll()
477{
Michael Tritz234a07e2017-09-21 00:53:06 -0500478 for (const auto& activationIt : activations)
479 {
480 if (!isVersionFunctional(activationIt.first))
481 {
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500482 ItemUpdater::erase(activationIt.first);
Michael Tritz234a07e2017-09-21 00:53:06 -0500483 }
484 }
485
Michael Tritz234a07e2017-09-21 00:53:06 -0500486 // Remove any remaining pnor-ro- or pnor-rw- volumes that do not match
487 // the current version.
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600488 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
489 SYSTEMD_INTERFACE, "StartUnit");
Michael Tritz234a07e2017-09-21 00:53:06 -0500490 method.append("obmc-flash-bios-cleanup.service", "replace");
491 bus.call_noreply(method);
492}
493
Saqib Khan2cbfa032017-08-17 14:52:37 -0500494// TODO: openbmc/openbmc#1402 Monitor flash usage
495void ItemUpdater::freeSpace()
496{
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600497 // Versions with the highest priority in front
498 std::priority_queue<std::pair<int, std::string>,
499 std::vector<std::pair<int, std::string>>,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600500 std::less<std::pair<int, std::string>>>
501 versionsPQ;
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600502
Saqib Khan2cbfa032017-08-17 14:52:37 -0500503 std::size_t count = 0;
Saqib Khan2cbfa032017-08-17 14:52:37 -0500504 for (const auto& iter : activations)
505 {
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600506 if (iter.second.get()->activation() ==
507 server::Activation::Activations::Active)
Saqib Khan2cbfa032017-08-17 14:52:37 -0500508 {
509 count++;
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600510 // Don't put the functional version on the queue since we can't
511 // remove the "running" PNOR version.
Adriana Kobylakee201a52017-11-09 15:05:04 -0600512 if (isVersionFunctional(iter.second->versionId))
513 {
514 continue;
515 }
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600516 versionsPQ.push(std::make_pair(
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600517 iter.second->redundancyPriority.get()->priority(),
518 iter.second->versionId));
Saqib Khan2cbfa032017-08-17 14:52:37 -0500519 }
520 }
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600521
522 // If the number of PNOR versions is over ACTIVE_PNOR_MAX_ALLOWED -1,
523 // remove the highest priority one(s).
524 while ((count >= ACTIVE_PNOR_MAX_ALLOWED) && (!versionsPQ.empty()))
Saqib Khan2cbfa032017-08-17 14:52:37 -0500525 {
Gunnar Millsfedbf3d2018-01-17 11:17:31 -0600526 erase(versionsPQ.top().second);
527 versionsPQ.pop();
528 count--;
Saqib Khan2cbfa032017-08-17 14:52:37 -0500529 }
530}
531
Gunnar Mills61010b22017-09-20 15:25:26 -0500532void ItemUpdater::createActiveAssociation(const std::string& path)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500533{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600534 assocs.emplace_back(
535 std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
Gunnar Mills9741cd12017-08-28 15:09:00 -0500536 associations(assocs);
537}
538
Gunnar Mills833e4f32017-09-14 12:30:27 -0500539void ItemUpdater::updateFunctionalAssociation(const std::string& path)
540{
541 // remove all functional associations
542 for (auto iter = assocs.begin(); iter != assocs.end();)
543 {
544 if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0)
545 {
546 iter = assocs.erase(iter);
547 }
548 else
549 {
550 ++iter;
551 }
552 }
553 assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600554 FUNCTIONAL_REV_ASSOCIATION, path));
Gunnar Mills833e4f32017-09-14 12:30:27 -0500555 associations(assocs);
556}
557
Gunnar Mills61010b22017-09-20 15:25:26 -0500558void ItemUpdater::removeActiveAssociation(const std::string& path)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500559{
560 for (auto iter = assocs.begin(); iter != assocs.end();)
561 {
Gunnar Mills833e4f32017-09-14 12:30:27 -0500562 if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 &&
563 (std::get<2>(*iter)).compare(path) == 0)
Gunnar Mills9741cd12017-08-28 15:09:00 -0500564 {
565 iter = assocs.erase(iter);
566 associations(assocs);
567 }
568 else
569 {
570 ++iter;
571 }
572 }
573}
574
Gunnar Mills2badd7a2017-09-20 12:51:28 -0500575std::string ItemUpdater::determineId(const std::string& symlinkPath)
576{
577 if (!fs::exists(symlinkPath))
578 {
579 return {};
580 }
581
582 auto target = fs::canonical(symlinkPath).string();
583
584 // check to make sure the target really exists
585 if (!fs::is_regular_file(target + "/" + PNOR_TOC_FILE))
586 {
587 return {};
588 }
589 // Get the image <id> from the symlink target
590 // for example /media/ro-2a1022fe
591 static const auto PNOR_RO_PREFIX_LEN = strlen(PNOR_RO_PREFIX);
592 return target.substr(PNOR_RO_PREFIX_LEN);
593}
594
Michael Tritzb541f1b2017-10-15 15:10:21 -0500595void GardReset::reset()
596{
597 // The GARD partition is currently misspelled "GUARD." This file path will
598 // need to be updated in the future.
599 auto path = fs::path(PNOR_PRSV_ACTIVE_PATH);
600 path /= "GUARD";
601 std::vector<uint8_t> mboxdArgs;
602
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600603 auto dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH,
604 MBOXD_INTERFACE, "cmd");
Michael Tritzb541f1b2017-10-15 15:10:21 -0500605
606 // Suspend mboxd - no args required.
607 dbusCall.append(static_cast<uint8_t>(3), mboxdArgs);
608
609 auto responseMsg = bus.call(dbusCall);
610 if (responseMsg.is_method_error())
611 {
612 log<level::ERR>("Error in mboxd suspend call");
613 elog<InternalFailure>();
614 }
615
616 if (fs::is_regular_file(path))
617 {
618 fs::remove(path);
619 }
620
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600621 dbusCall = bus.new_method_call(MBOXD_INTERFACE, MBOXD_PATH, MBOXD_INTERFACE,
622 "cmd");
Michael Tritzb541f1b2017-10-15 15:10:21 -0500623
624 // Resume mboxd with arg 1, indicating that the flash is modified.
625 mboxdArgs.push_back(1);
626 dbusCall.append(static_cast<uint8_t>(4), mboxdArgs);
627
628 responseMsg = bus.call(dbusCall);
629 if (responseMsg.is_method_error())
630 {
631 log<level::ERR>("Error in mboxd resume call");
632 elog<InternalFailure>();
633 }
634}
635
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500636} // namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500637} // namespace software
638} // namespace openpower