blob: 2282c28d2289047888685b03235056effe544f9b [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>
Saqib Khandcbfa042017-09-18 13:08:39 -05004#include <phosphor-logging/elog.hpp>
5#include <elog-errors.hpp>
6#include <xyz/openbmc_project/Software/Version/error.hpp>
Gunnar Millsec1b41c2017-05-02 12:20:36 -05007#include "config.h"
Gunnar Mills2ce7da22017-05-04 15:37:56 -05008#include "item_updater.hpp"
9#include "xyz/openbmc_project/Software/Version/server.hpp"
Saqib Khan35e83f32017-05-22 11:37:32 -050010#include <experimental/filesystem>
Saqib Khan705f1bf2017-06-09 23:58:38 -050011#include "version.hpp"
Saqib Khan5d532672017-08-09 10:44:50 -050012#include "serialize.hpp"
Gunnar Millsec1b41c2017-05-02 12:20:36 -050013
14namespace phosphor
15{
16namespace software
17{
18namespace updater
19{
20
Gunnar Mills2ce7da22017-05-04 15:37:56 -050021// When you see server:: you know we're referencing our base class
22namespace server = sdbusplus::xyz::openbmc_project::Software::server;
Michael Tritz0129d922017-08-10 19:33:46 -050023namespace control = sdbusplus::xyz::openbmc_project::Control::server;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050024
25using namespace phosphor::logging;
Saqib Khandcbfa042017-09-18 13:08:39 -050026using namespace sdbusplus::xyz::openbmc_project::Software::Version::Error;
Saqib Khan35e83f32017-05-22 11:37:32 -050027namespace fs = std::experimental::filesystem;
28
Gunnar Mills9a782242017-08-22 16:23:15 -050029const std::vector<std::string> bmcImages = { "image-kernel",
30 "image-rofs",
31 "image-rwfs",
32 "image-u-boot" };
Gunnar Mills2ce7da22017-05-04 15:37:56 -050033
Patrick Williamse75d10f2017-05-30 16:56:32 -050034void ItemUpdater::createActivation(sdbusplus::message::message& msg)
Gunnar Millsec1b41c2017-05-02 12:20:36 -050035{
Saqib Khan84a0e692017-06-28 17:27:01 -050036
37 using SVersion = server::Version;
38 using VersionPurpose = SVersion::VersionPurpose;
Gunnar Mills9a782242017-08-22 16:23:15 -050039 using VersionClass = phosphor::software::manager::Version;
Saqib Khan84a0e692017-06-28 17:27:01 -050040 namespace mesg = sdbusplus::message;
41 namespace variant_ns = mesg::variant_ns;
42
43 mesg::object_path objPath;
44 auto purpose = VersionPurpose::Unknown;
Saqib Khan705f1bf2017-06-09 23:58:38 -050045 std::string version;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050046 std::map<std::string,
Patrick Williamse75d10f2017-05-30 16:56:32 -050047 std::map<std::string,
Saqib Khan84a0e692017-06-28 17:27:01 -050048 mesg::variant<std::string>>> interfaces;
Patrick Williamse75d10f2017-05-30 16:56:32 -050049 msg.read(objPath, interfaces);
Gunnar Mills2ce7da22017-05-04 15:37:56 -050050 std::string path(std::move(objPath));
Saqib Khan19177d32017-06-20 08:11:49 -050051 std::string filePath;
Gunnar Mills2ce7da22017-05-04 15:37:56 -050052
53 for (const auto& intf : interfaces)
54 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050055 if (intf.first == VERSION_IFACE)
Gunnar Mills2ce7da22017-05-04 15:37:56 -050056 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050057 for (const auto& property : intf.second)
Gunnar Mills2ce7da22017-05-04 15:37:56 -050058 {
Saqib Khan705f1bf2017-06-09 23:58:38 -050059 if (property.first == "Purpose")
Gunnar Mills2ce7da22017-05-04 15:37:56 -050060 {
Saqib Khan84a0e692017-06-28 17:27:01 -050061 auto value = SVersion::convertVersionPurposeFromString(
Gunnar Mills9a782242017-08-22 16:23:15 -050062 variant_ns::get<std::string>(property.second));
Saqib Khan84a0e692017-06-28 17:27:01 -050063 if (value == VersionPurpose::BMC ||
64 value == VersionPurpose::System)
65 {
66 purpose = value;
67 }
Saqib Khan705f1bf2017-06-09 23:58:38 -050068 }
69 else if (property.first == "Version")
70 {
Saqib Khan84a0e692017-06-28 17:27:01 -050071 version = variant_ns::get<std::string>(property.second);
Gunnar Mills2ce7da22017-05-04 15:37:56 -050072 }
73 }
74 }
Saqib Khan19177d32017-06-20 08:11:49 -050075 else if (intf.first == FILEPATH_IFACE)
76 {
77 for (const auto& property : intf.second)
78 {
79 if (property.first == "Path")
80 {
Saqib Khan84a0e692017-06-28 17:27:01 -050081 filePath = variant_ns::get<std::string>(property.second);
Saqib Khan19177d32017-06-20 08:11:49 -050082 }
83 }
84 }
Gunnar Mills2ce7da22017-05-04 15:37:56 -050085 }
Saqib Khan705f1bf2017-06-09 23:58:38 -050086 if (version.empty() ||
Saqib Khan19177d32017-06-20 08:11:49 -050087 filePath.empty() ||
Saqib Khan84a0e692017-06-28 17:27:01 -050088 purpose == VersionPurpose::Unknown)
Saqib Khan705f1bf2017-06-09 23:58:38 -050089 {
90 return;
91 }
Gunnar Mills2ce7da22017-05-04 15:37:56 -050092
93 // Version id is the last item in the path
94 auto pos = path.rfind("/");
95 if (pos == std::string::npos)
96 {
97 log<level::ERR>("No version id found in object path",
98 entry("OBJPATH=%s", path));
Patrick Williamse75d10f2017-05-30 16:56:32 -050099 return;
Gunnar Mills2ce7da22017-05-04 15:37:56 -0500100 }
101
102 auto versionId = path.substr(pos + 1);
103
Patrick Williamse75d10f2017-05-30 16:56:32 -0500104 if (activations.find(versionId) == activations.end())
Gunnar Mills2ce7da22017-05-04 15:37:56 -0500105 {
Saqib Khan35e83f32017-05-22 11:37:32 -0500106 // Determine the Activation state by processing the given image dir.
107 auto activationState = server::Activation::Activations::Invalid;
Gunnar Mills9a782242017-08-22 16:23:15 -0500108 ItemUpdater::ActivationStatus result =
109 ItemUpdater::validateSquashFSImage(filePath);
Gunnar Mills43b25cd2017-09-07 13:19:34 -0500110 AssociationList associations = {};
111
Saqib Khan35e83f32017-05-22 11:37:32 -0500112 if (result == ItemUpdater::ActivationStatus::ready)
113 {
114 activationState = server::Activation::Activations::Ready;
Gunnar Mills43b25cd2017-09-07 13:19:34 -0500115 // Create an association to the BMC inventory item
116 associations.emplace_back(std::make_tuple(
117 ACTIVATION_FWD_ASSOCIATION,
118 ACTIVATION_REV_ASSOCIATION,
119 bmcInventoryPath));
Saqib Khan35e83f32017-05-22 11:37:32 -0500120 }
Gunnar Millsb60add12017-08-24 16:41:42 -0500121
Saqib Khan35e83f32017-05-22 11:37:32 -0500122 activations.insert(std::make_pair(
Saqib Khan705f1bf2017-06-09 23:58:38 -0500123 versionId,
124 std::make_unique<Activation>(
125 bus,
126 path,
Saqib Khan4c1aec02017-07-06 11:46:13 -0500127 *this,
Saqib Khan35e83f32017-05-22 11:37:32 -0500128 versionId,
Gunnar Millsb60add12017-08-24 16:41:42 -0500129 activationState,
130 associations)));
Saqib Khan705f1bf2017-06-09 23:58:38 -0500131 versions.insert(std::make_pair(
132 versionId,
Gunnar Mills9a782242017-08-22 16:23:15 -0500133 std::make_unique<VersionClass>(
Saqib Khan705f1bf2017-06-09 23:58:38 -0500134 bus,
135 path,
136 version,
137 purpose,
Eddie James9440f492017-08-30 11:34:16 -0500138 filePath)));
Gunnar Mills2ce7da22017-05-04 15:37:56 -0500139 }
Patrick Williamse75d10f2017-05-30 16:56:32 -0500140 return;
Gunnar Millsec1b41c2017-05-02 12:20:36 -0500141}
142
Saqib Khanba239882017-05-26 08:41:54 -0500143void ItemUpdater::processBMCImage()
144{
Gunnar Mills88e8a322017-09-13 11:09:28 -0500145 using VersionClass = phosphor::software::manager::Version;
146 // Read os-release from /etc/ to get the functional BMC version
147 auto functionalVersion = VersionClass::getBMCVersion(OS_RELEASE_FILE);
148
Saqib Khan1eef62d2017-08-10 15:29:34 -0500149 // Read os-release from folders under /media/ to get
150 // BMC Software Versions.
Gunnar Millsd16bcbd2017-10-08 16:50:42 -0500151 for (const auto& iter : fs::directory_iterator(MEDIA_DIR))
Saqib Khan1eef62d2017-08-10 15:29:34 -0500152 {
153 auto activationState = server::Activation::Activations::Active;
Saqib Khan6fab70d2017-09-07 00:13:50 -0500154 static const auto BMC_RO_PREFIX_LEN = strlen(BMC_ROFS_PREFIX);
Saqib Khan1eef62d2017-08-10 15:29:34 -0500155
156 // Check if the BMC_RO_PREFIXis the prefix of the iter.path
157 if (0 == iter.path().native().compare(0, BMC_RO_PREFIX_LEN,
Saqib Khan6fab70d2017-09-07 00:13:50 -0500158 BMC_ROFS_PREFIX))
Saqib Khan1eef62d2017-08-10 15:29:34 -0500159 {
Saqib Khan021c3652017-09-26 12:11:02 -0500160 // The versionId is extracted from the path
161 // for example /media/ro-2a1022fe.
162 auto id = iter.path().native().substr(BMC_RO_PREFIX_LEN);
Saqib Khan1eef62d2017-08-10 15:29:34 -0500163 auto osRelease = iter.path() / OS_RELEASE_FILE;
164 if (!fs::is_regular_file(osRelease))
165 {
Gunnar Mills2ad1b552017-10-19 15:58:52 -0500166 log<level::ERR>("Failed to read osRelease",
167 entry("FILENAME=%s", osRelease.string()));
Saqib Khan021c3652017-09-26 12:11:02 -0500168 ItemUpdater::erase(id);
169 continue;
Saqib Khan1eef62d2017-08-10 15:29:34 -0500170 }
Gunnar Mills88e8a322017-09-13 11:09:28 -0500171 auto version = VersionClass::getBMCVersion(osRelease);
Saqib Khan1eef62d2017-08-10 15:29:34 -0500172 if (version.empty())
173 {
174 log<level::ERR>("Failed to read version from osRelease",
175 entry("FILENAME=%s", osRelease.string()));
176 activationState = server::Activation::Activations::Invalid;
177 }
Saqib Khan021c3652017-09-26 12:11:02 -0500178
Saqib Khan1eef62d2017-08-10 15:29:34 -0500179 auto purpose = server::Version::VersionPurpose::BMC;
180 auto path = fs::path(SOFTWARE_OBJPATH) / id;
181
Gunnar Mills88e8a322017-09-13 11:09:28 -0500182 // Create functional association if this is the functional version
183 if (version.compare(functionalVersion) == 0)
184 {
185 createFunctionalAssociation(path);
186 }
187
Gunnar Mills43b25cd2017-09-07 13:19:34 -0500188 AssociationList associations = {};
189
190 if (activationState == server::Activation::Activations::Active)
191 {
192 // Create an association to the BMC inventory item
193 associations.emplace_back(std::make_tuple(
194 ACTIVATION_FWD_ASSOCIATION,
195 ACTIVATION_REV_ASSOCIATION,
196 bmcInventoryPath));
197
198 // Create an active association since this image is active
199 createActiveAssociation(path);
200 }
201
Adriana Kobylakee590c72017-09-26 15:16:06 -0500202 // Create Version instance for this version.
203 auto versionPtr = std::make_unique<VersionClass>(
204 bus,
205 path,
206 version,
207 purpose,
208 "");
209 auto isVersionFunctional = versionPtr->isFunctional();
210 versions.insert(std::make_pair(
211 id,
212 std::move(versionPtr)));
213
Saqib Khan1eef62d2017-08-10 15:29:34 -0500214 // Create Activation instance for this version.
215 activations.insert(std::make_pair(
216 id,
217 std::make_unique<Activation>(
218 bus,
219 path,
220 *this,
221 id,
222 server::Activation::Activations::Active,
223 associations)));
224
225 // If Active, create RedundancyPriority instance for this version.
226 if (activationState == server::Activation::Activations::Active)
227 {
228 uint8_t priority = std::numeric_limits<uint8_t>::max();
229 if (!restoreFromFile(id, priority))
230 {
Adriana Kobylakee590c72017-09-26 15:16:06 -0500231 if (isVersionFunctional)
232 {
233 priority = 0;
234 }
235 else
236 {
237 log<level::ERR>("Unable to restore priority from file.",
238 entry("VERSIONID=%s", id));
239 }
Saqib Khan1eef62d2017-08-10 15:29:34 -0500240 }
241 activations.find(id)->second->redundancyPriority =
242 std::make_unique<RedundancyPriority>(
Saqib Khanba239882017-05-26 08:41:54 -0500243 bus,
244 path,
Saqib Khan1eef62d2017-08-10 15:29:34 -0500245 *(activations.find(id)->second),
246 priority);
247 }
Saqib Khan1eef62d2017-08-10 15:29:34 -0500248 }
249 }
Saqib Khandcbfa042017-09-18 13:08:39 -0500250
251 // If there is no ubi volume for bmc version then read the /etc/os-release
252 // and create rofs-<versionId> under /media
253 if (activations.size() == 0)
254 {
Gunnar Millsd16bcbd2017-10-08 16:50:42 -0500255 auto version = VersionClass::getBMCVersion(OS_RELEASE_FILE);
Saqib Khandcbfa042017-09-18 13:08:39 -0500256 auto id = phosphor::software::manager::Version::getId(version);
257 auto versionFileDir = BMC_ROFS_PREFIX + id + "/etc/";
258 try
259 {
Gunnar Millsd16bcbd2017-10-08 16:50:42 -0500260 if (!fs::is_directory(versionFileDir))
Saqib Khandcbfa042017-09-18 13:08:39 -0500261 {
262 fs::create_directories(versionFileDir);
263 }
264 auto versionFilePath = BMC_ROFS_PREFIX + id + OS_RELEASE_FILE;
265 fs::create_directory_symlink(OS_RELEASE_FILE, versionFilePath);
266 ItemUpdater::processBMCImage();
267 }
268 catch (const std::exception& e)
269 {
270 log<level::ERR>(e.what());
271 }
272 }
Saqib Khanba239882017-05-26 08:41:54 -0500273 return;
274}
275
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500276void ItemUpdater::erase(std::string entryId)
277{
Eddie James6d873712017-09-01 11:29:07 -0500278 // Find entry in versions map
279 auto it = versions.find(entryId);
280 if (it != versions.end())
281 {
282 if (it->second->isFunctional())
283 {
284 log<level::ERR>(("Error: Version " + entryId + \
285 " is currently running on the BMC." \
286 " Unable to remove.").c_str());
Gunnar Millsd16bcbd2017-10-08 16:50:42 -0500287 return;
Eddie James6d873712017-09-01 11:29:07 -0500288 }
289
290 // Delete ReadOnly partitions if it's not active
291 removeReadOnlyPartition(entryId);
292 removeFile(entryId);
293 }
294 else
295 {
296 // Delete ReadOnly partitions even if we can't find the version
297 removeReadOnlyPartition(entryId);
298 removeFile(entryId);
299
300 log<level::ERR>(("Error: Failed to find version " + entryId + \
301 " in item updater versions map." \
302 " Unable to remove.").c_str());
303 return;
304 }
Saqib Khan1eef62d2017-08-10 15:29:34 -0500305
306 // Remove the priority environment variable.
307 auto serviceFile = "obmc-flash-bmc-setenv@" + entryId + ".service";
308 auto method = bus.new_method_call(
309 SYSTEMD_BUSNAME,
310 SYSTEMD_PATH,
311 SYSTEMD_INTERFACE,
312 "StartUnit");
313 method.append(serviceFile, "replace");
314 bus.call_noreply(method);
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500315
316 // Removing entry in versions map
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500317 this->versions.erase(entryId);
318
319 // Removing entry in activations map
320 auto ita = activations.find(entryId);
321 if (ita == activations.end())
322 {
323 log<level::ERR>(("Error: Failed to find version " + entryId + \
Gunnar Mills9a782242017-08-22 16:23:15 -0500324 " in item updater activations map." \
325 " Unable to remove.").c_str());
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500326 return;
327 }
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500328
329 this->activations.erase(entryId);
Saqib Khan49446ae2017-10-02 10:54:20 -0500330 ItemUpdater::resetUbootEnvVars();
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500331}
332
Michael Tritzbc1bf3a2017-09-18 16:38:23 -0500333void ItemUpdater::deleteAll()
334{
335 std::vector<std::string> deletableVersions;
336
337 for (const auto& versionIt : versions)
338 {
339 if (!versionIt.second->isFunctional())
340 {
341 deletableVersions.push_back(versionIt.first);
342 }
343 }
344
345 for (const auto& deletableIt : deletableVersions)
346 {
347 ItemUpdater::erase(deletableIt);
348 }
349
350 // Remove any volumes that do not match current versions.
351 auto method = bus.new_method_call(
352 SYSTEMD_BUSNAME,
353 SYSTEMD_PATH,
354 SYSTEMD_INTERFACE,
355 "StartUnit");
356 method.append("obmc-flash-bmc-cleanup.service", "replace");
357 bus.call_noreply(method);
358}
359
Saqib Khan35e83f32017-05-22 11:37:32 -0500360ItemUpdater::ActivationStatus ItemUpdater::validateSquashFSImage(
Gunnar Mills9a782242017-08-22 16:23:15 -0500361 const std::string& filePath)
Saqib Khan35e83f32017-05-22 11:37:32 -0500362{
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500363 bool invalid = false;
Saqib Khan35e83f32017-05-22 11:37:32 -0500364
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500365 for (auto& bmcImage : bmcImages)
Saqib Khan35e83f32017-05-22 11:37:32 -0500366 {
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500367 fs::path file(filePath);
368 file /= bmcImage;
369 std::ifstream efile(file.c_str());
370 if (efile.good() != 1)
371 {
372 log<level::ERR>("Failed to find the BMC image.",
Gunnar Mills9a782242017-08-22 16:23:15 -0500373 entry("IMAGE=%s", bmcImage.c_str()));
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500374 invalid = true;
375 }
Saqib Khan35e83f32017-05-22 11:37:32 -0500376 }
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500377
378 if (invalid)
Saqib Khan35e83f32017-05-22 11:37:32 -0500379 {
Saqib Khan35e83f32017-05-22 11:37:32 -0500380 return ItemUpdater::ActivationStatus::invalid;
381 }
Michael Tritzb1cfdf92017-08-14 14:33:30 -0500382
383 return ItemUpdater::ActivationStatus::ready;
Saqib Khan35e83f32017-05-22 11:37:32 -0500384}
385
Saqib Khanb9da6632017-09-13 09:48:37 -0500386void ItemUpdater::freePriority(uint8_t value, const std::string& versionId)
Saqib Khan4c1aec02017-07-06 11:46:13 -0500387{
388 //TODO openbmc/openbmc#1896 Improve the performance of this function
389 for (const auto& intf : activations)
390 {
Gunnar Mills9a782242017-08-22 16:23:15 -0500391 if (intf.second->redundancyPriority)
Saqib Khan4c1aec02017-07-06 11:46:13 -0500392 {
Saqib Khanb9da6632017-09-13 09:48:37 -0500393 if (intf.second->redundancyPriority.get()->priority() == value &&
394 intf.second->versionId != versionId)
Saqib Khan4c1aec02017-07-06 11:46:13 -0500395 {
Gunnar Mills9a782242017-08-22 16:23:15 -0500396 intf.second->redundancyPriority.get()->priority(value + 1);
Saqib Khan4c1aec02017-07-06 11:46:13 -0500397 }
398 }
399 }
400}
401
Michael Tritz37a59042017-07-12 13:44:53 -0500402void ItemUpdater::reset()
403{
404 // Mark the read-write partition for recreation upon reboot.
405 auto method = bus.new_method_call(
406 SYSTEMD_BUSNAME,
407 SYSTEMD_PATH,
408 SYSTEMD_INTERFACE,
409 "StartUnit");
Michael Tritz0129d922017-08-10 19:33:46 -0500410 method.append("obmc-flash-bmc-setenv@rwreset\\x3dtrue.service", "replace");
Michael Tritz37a59042017-07-12 13:44:53 -0500411 bus.call_noreply(method);
412
413 log<level::INFO>("BMC factory reset will take effect upon reboot.");
414
415 return;
416}
417
Leonel Gonzalez3526ef72017-07-07 14:38:25 -0500418void ItemUpdater::removeReadOnlyPartition(std::string versionId)
419{
420 auto serviceFile = "obmc-flash-bmc-ubiro-remove@" + versionId +
421 ".service";
422
423 // Remove the read-only partitions.
424 auto method = bus.new_method_call(
425 SYSTEMD_BUSNAME,
426 SYSTEMD_PATH,
427 SYSTEMD_INTERFACE,
428 "StartUnit");
429 method.append(serviceFile, "replace");
430 bus.call_noreply(method);
431}
432
Michael Tritz0129d922017-08-10 19:33:46 -0500433bool ItemUpdater::fieldModeEnabled(bool value)
434{
435 // enabling field mode is intended to be one way: false -> true
436 if (value && !control::FieldMode::fieldModeEnabled())
437 {
438 control::FieldMode::fieldModeEnabled(value);
439
440 auto method = bus.new_method_call(
441 SYSTEMD_BUSNAME,
442 SYSTEMD_PATH,
443 SYSTEMD_INTERFACE,
444 "StartUnit");
445 method.append("obmc-flash-bmc-setenv@fieldmode\\x3dtrue.service",
Gunnar Mills9a782242017-08-22 16:23:15 -0500446 "replace");
Michael Tritz0129d922017-08-10 19:33:46 -0500447 bus.call_noreply(method);
448
449 method = bus.new_method_call(
450 SYSTEMD_BUSNAME,
451 SYSTEMD_PATH,
452 SYSTEMD_INTERFACE,
453 "StopUnit");
454 method.append("usr-local.mount", "replace");
455 bus.call_noreply(method);
456
457 std::vector<std::string> usrLocal = {"usr-local.mount"};
458
459 method = bus.new_method_call(
460 SYSTEMD_BUSNAME,
461 SYSTEMD_PATH,
462 SYSTEMD_INTERFACE,
463 "MaskUnitFiles");
464 method.append(usrLocal, false, true);
465 bus.call_noreply(method);
466 }
467
468 return control::FieldMode::fieldModeEnabled();
469}
470
471void ItemUpdater::restoreFieldModeStatus()
472{
Michael Tritzff0b4212017-10-24 17:38:09 -0500473 std::ifstream input("/dev/mtd/u-boot-env");
Michael Tritz0129d922017-08-10 19:33:46 -0500474 std::string envVar;
475 std::getline(input, envVar);
476
Gunnar Mills9a782242017-08-22 16:23:15 -0500477 if (envVar.find("fieldmode=true") != std::string::npos)
Michael Tritz0129d922017-08-10 19:33:46 -0500478 {
479 ItemUpdater::fieldModeEnabled(true);
480 }
481}
482
Gunnar Millsb60add12017-08-24 16:41:42 -0500483void ItemUpdater::setBMCInventoryPath()
484{
485 //TODO: openbmc/openbmc#1786 - Get the BMC path by looking for objects
486 // that implement the BMC inventory interface
487 auto depth = 0;
488 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME,
489 MAPPER_PATH,
490 MAPPER_INTERFACE,
491 "GetSubTreePaths");
492
493 mapperCall.append(CHASSIS_INVENTORY_PATH);
494 mapperCall.append(depth);
495
496 // TODO: openbmc/openbmc#2226 - Add Inventory Item filter when
497 // mapper is fixed.
498 std::vector<std::string> filter = {};
499 mapperCall.append(filter);
500
501 auto response = bus.call(mapperCall);
502 if (response.is_method_error())
503 {
504 log<level::ERR>("Error in mapper GetSubTreePath");
505 return;
506 }
507
508 using ObjectPaths = std::vector<std::string>;
509 ObjectPaths result;
510 response.read(result);
511
512 if (result.empty())
513 {
514 log<level::ERR>("Invalid response from mapper");
515 return;
516 }
517
518 for (auto& iter : result)
519 {
520 const auto& path = iter;
521 if (path.substr(path.find_last_of('/') + 1).compare("bmc") == 0)
522 {
523 bmcInventoryPath = path;
524 return;
525 }
526 }
527}
528
Gunnar Millsf10b2322017-09-21 15:31:55 -0500529void ItemUpdater::createActiveAssociation(const std::string& path)
Gunnar Millsded875d2017-08-28 16:44:52 -0500530{
531 assocs.emplace_back(std::make_tuple(ACTIVE_FWD_ASSOCIATION,
532 ACTIVE_REV_ASSOCIATION,
533 path));
534 associations(assocs);
535}
536
Gunnar Mills88e8a322017-09-13 11:09:28 -0500537void ItemUpdater::createFunctionalAssociation(const std::string& path)
538{
539 assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
540 FUNCTIONAL_REV_ASSOCIATION,
541 path));
542 associations(assocs);
543}
544
Gunnar Millsf10b2322017-09-21 15:31:55 -0500545void ItemUpdater::removeActiveAssociation(const std::string& path)
Gunnar Millsded875d2017-08-28 16:44:52 -0500546{
547 for (auto iter = assocs.begin(); iter != assocs.end();)
548 {
Gunnar Mills88e8a322017-09-13 11:09:28 -0500549 // Since there could be multiple associations to the same path,
550 // only remove ones that have an active forward association.
551 if ((std::get<0>(*iter)).compare(ACTIVE_FWD_ASSOCIATION) == 0 &&
552 (std::get<2>(*iter)).compare(path) == 0)
Gunnar Millsded875d2017-08-28 16:44:52 -0500553 {
554 iter = assocs.erase(iter);
555 associations(assocs);
556 }
557 else
558 {
559 ++iter;
560 }
561 }
562}
563
Saqib Khanb9da6632017-09-13 09:48:37 -0500564bool ItemUpdater::isLowestPriority(uint8_t value)
565{
566 for (const auto& intf : activations)
567 {
Gunnar Millsd16bcbd2017-10-08 16:50:42 -0500568 if (intf.second->redundancyPriority)
Saqib Khanb9da6632017-09-13 09:48:37 -0500569 {
570 if (intf.second->redundancyPriority.get()->priority() < value)
571 {
572 return false;
573 }
574 }
575 }
576 return true;
577}
578
Saqib Khan49446ae2017-10-02 10:54:20 -0500579void ItemUpdater::resetUbootEnvVars()
580{
581 decltype(activations.begin()->second->redundancyPriority.get()->priority())
582 lowestPriority = std::numeric_limits<uint8_t>::max();
583 decltype(activations.begin()->second->versionId) lowestPriorityVersion;
584 for (const auto& intf : activations)
585 {
586 if (!intf.second->redundancyPriority.get())
587 {
588 // Skip this version if the redundancyPriority is not initialized.
589 continue;
590 }
591
592 if (intf.second->redundancyPriority.get()->priority()
593 <= lowestPriority)
594 {
595 lowestPriority = intf.second->redundancyPriority.get()->priority();
596 lowestPriorityVersion = intf.second->versionId;
597 }
598 }
599
Saqib Khanf0382c32017-10-24 13:36:22 -0500600 // Update the U-boot environment variable to point to the lowest priority
601 auto it = activations.find(lowestPriorityVersion);
602 it->second->updateUbootEnvVars();
Saqib Khan49446ae2017-10-02 10:54:20 -0500603}
604
Gunnar Millsec1b41c2017-05-02 12:20:36 -0500605} // namespace updater
606} // namespace software
607} // namespace phosphor