blob: 0c188219893306ad86b7edfab0dbeaf85fb9065f [file] [log] [blame]
Saqib Khanb0774702017-05-23 16:02:41 -05001#include "activation.hpp"
Gunnar Millsb0ce9962018-09-07 13:39:10 -05002
Lei YU1be8d502018-06-20 11:48:36 +08003#include "images.hpp"
Saqib Khan4c1aec02017-07-06 11:46:13 -05004#include "item_updater.hpp"
Saqib Khan5d532672017-08-09 10:44:50 -05005#include "serialize.hpp"
Gunnar Millsb0ce9962018-09-07 13:39:10 -05006
Jayashankar Padatha0135602019-04-22 16:22:58 +05307#include <phosphor-logging/elog-errors.hpp>
8#include <phosphor-logging/elog.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -05009#include <phosphor-logging/log.hpp>
Adriana Kobylakaea48f22018-07-10 10:20:56 -050010#include <sdbusplus/exception.hpp>
Jayashankar Padatha0135602019-04-22 16:22:58 +053011#include <xyz/openbmc_project/Common/error.hpp>
Saqib Khanb9da6632017-09-13 09:48:37 -050012
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060013#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060014#include "image_verify.hpp"
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060015#endif
16
Saqib Khanb0774702017-05-23 16:02:41 -050017namespace phosphor
18{
19namespace software
20{
21namespace updater
22{
23
24namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
25
Saqib Khanb9da6632017-09-13 09:48:37 -050026using namespace phosphor::logging;
Adriana Kobylakaea48f22018-07-10 10:20:56 -050027using sdbusplus::exception::SdBusError;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060028using InternalFailure =
29 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayashankar Padatha0135602019-04-22 16:22:58 +053030
31#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -050032namespace control = sdbusplus::xyz::openbmc_project::Control::server;
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -060033#endif
34
Michael Tritzbed88af2017-07-19 16:00:06 -050035void Activation::subscribeToSystemdSignals()
36{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060037 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
38 SYSTEMD_INTERFACE, "Subscribe");
Adriana Kobylakaea48f22018-07-10 10:20:56 -050039 try
40 {
41 this->bus.call_noreply(method);
42 }
43 catch (const SdBusError& e)
44 {
45 if (e.name() != nullptr &&
46 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
47 {
48 // If an Activation attempt fails, the Unsubscribe method is not
49 // called. This may lead to an AlreadySubscribed error if the
50 // Activation is re-attempted.
51 }
52 else
53 {
54 log<level::ERR>("Error subscribing to systemd",
55 entry("ERROR=%s", e.what()));
56 }
57 }
Michael Tritzbed88af2017-07-19 16:00:06 -050058
59 return;
60}
61
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050062void Activation::unsubscribeFromSystemdSignals()
63{
Adriana Kobylak2285fe02018-02-27 15:36:59 -060064 auto method = this->bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
65 SYSTEMD_INTERFACE, "Unsubscribe");
Jayashankar Padatha0135602019-04-22 16:22:58 +053066 try
67 {
68 this->bus.call_noreply(method);
69 }
70 catch (const SdBusError& e)
71 {
72 log<level::ERR>("Error in unsubscribing from systemd signals",
73 entry("ERROR=%s", e.what()));
74 }
Michael Tritzf2b5e0d2017-07-25 14:39:34 -050075
76 return;
77}
78
Adriana Kobylak2285fe02018-02-27 15:36:59 -060079auto Activation::activation(Activations value) -> Activations
Saqib Khanb0774702017-05-23 16:02:41 -050080{
Saqib Khan4c1aec02017-07-06 11:46:13 -050081
Adriana Kobylak8bd84c82018-01-24 14:19:24 -060082 if ((value != softwareServer::Activation::Activations::Active) &&
83 (value != softwareServer::Activation::Activations::Activating))
Saqib Khan4c1aec02017-07-06 11:46:13 -050084 {
85 redundancyPriority.reset(nullptr);
86 }
87
Saqib Khanb0774702017-05-23 16:02:41 -050088 if (value == softwareServer::Activation::Activations::Activating)
89 {
Lei YUa7853ee2018-05-23 11:13:12 +080090#ifdef UBIFS_LAYOUT
Michael Tritzbed88af2017-07-19 16:00:06 -050091 if (rwVolumeCreated == false && roVolumeCreated == false)
Saqib Khanb0774702017-05-23 16:02:41 -050092 {
Adriana Kobylakaea48f22018-07-10 10:20:56 -050093 // Enable systemd signals
94 Activation::subscribeToSystemdSignals();
95
Adriana Kobylaka6963592018-09-07 14:13:29 -050096 parent.freeSpace(*this);
Adriana Kobylak204e1e72018-01-24 16:00:05 -060097
Michael Tritz0edd4ad2017-07-26 14:27:42 -050098 if (!activationProgress)
99 {
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600100 activationProgress =
101 std::make_unique<ActivationProgress>(bus, path);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500102 }
103
Michael Tritzbed88af2017-07-19 16:00:06 -0500104 if (!activationBlocksTransition)
105 {
106 activationBlocksTransition =
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600107 std::make_unique<ActivationBlocksTransition>(bus, path);
Michael Tritzbed88af2017-07-19 16:00:06 -0500108 }
Saqib Khan4c1aec02017-07-06 11:46:13 -0500109
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -0600110#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -0600111 fs::path uploadDir(IMG_UPLOAD_DIR);
Lei YU90532252018-05-24 11:15:24 +0800112 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -0600113 {
Lei YU90532252018-05-24 11:15:24 +0800114 onVerifyFailed();
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -0500115 // Stop the activation process, if fieldMode is enabled.
116 if (parent.control::FieldMode::fieldModeEnabled())
117 {
118 // Cleanup
119 activationBlocksTransition.reset(nullptr);
120 activationProgress.reset(nullptr);
Jayanth Othayoth9a9d7c22018-03-28 10:05:26 -0500121 return softwareServer::Activation::activation(
122 softwareServer::Activation::Activations::Failed);
123 }
Jayanth Othayoth0e0c1272018-02-21 05:46:36 -0600124 }
125#endif
126
Adriana Kobylak9f89e2e2018-05-30 13:16:20 -0500127 flashWrite();
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500128
129 activationProgress->progress(10);
Michael Tritzbed88af2017-07-19 16:00:06 -0500130 }
131 else if (rwVolumeCreated == true && roVolumeCreated == true)
Saqib Khan4c1aec02017-07-06 11:46:13 -0500132 {
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500133 if (ubootEnvVarsUpdated == false)
Michael Tritzbed88af2017-07-19 16:00:06 -0500134 {
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500135 activationProgress->progress(90);
136
137 if (!redundancyPriority)
138 {
139 redundancyPriority = std::make_unique<RedundancyPriority>(
140 bus, path, *this, 0);
141 }
Michael Tritzbed88af2017-07-19 16:00:06 -0500142 }
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500143 else
144 {
145 activationProgress->progress(100);
Saqib Khan4c1aec02017-07-06 11:46:13 -0500146
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500147 activationBlocksTransition.reset(nullptr);
148 activationProgress.reset(nullptr);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500149
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500150 rwVolumeCreated = false;
151 roVolumeCreated = false;
152 ubootEnvVarsUpdated = false;
153 Activation::unsubscribeFromSystemdSignals();
Michael Tritzf2b5e0d2017-07-25 14:39:34 -0500154
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500155 // Remove version object from image manager
156 Activation::deleteImageManagerObject();
Michael Tritzf2b5e0d2017-07-25 14:39:34 -0500157
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500158 // Create active association
159 parent.createActiveAssociation(path);
Saqib Khanee13e832017-10-23 12:53:11 -0500160
Jayashankar Padatha0135602019-04-22 16:22:58 +0530161 if (Activation::checkApplyTimeImmediate() == true)
162 {
163 log<level::INFO>("Image Active. ApplyTime is immediate, "
164 "rebooting BMC.");
165 Activation::rebootBmc();
166 }
167
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500168 return softwareServer::Activation::activation(
169 softwareServer::Activation::Activations::Active);
170 }
Michael Tritzbed88af2017-07-19 16:00:06 -0500171 }
Lei YUa7853ee2018-05-23 11:13:12 +0800172#else // !UBIFS_LAYOUT
173
Lei YU90532252018-05-24 11:15:24 +0800174#ifdef WANT_SIGNATURE_VERIFY
175 fs::path uploadDir(IMG_UPLOAD_DIR);
176 if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
177 {
178 onVerifyFailed();
179 // Stop the activation process, if fieldMode is enabled.
180 if (parent.control::FieldMode::fieldModeEnabled())
181 {
182 return softwareServer::Activation::activation(
183 softwareServer::Activation::Activations::Failed);
184 }
185 }
186#endif
Adriana Kobylaka6963592018-09-07 14:13:29 -0500187 parent.freeSpace(*this);
Lei YUa7853ee2018-05-23 11:13:12 +0800188
189 flashWrite();
190
191 if (!redundancyPriority)
192 {
193 redundancyPriority =
194 std::make_unique<RedundancyPriority>(bus, path, *this, 0);
195 }
196
197 // Remove version object from image manager
198 Activation::deleteImageManagerObject();
199
200 // Create active association
201 parent.createActiveAssociation(path);
202
203 log<level::INFO>("BMC image ready, need reboot to get activated.");
204 return softwareServer::Activation::activation(
205 softwareServer::Activation::Activations::Active);
206#endif
Saqib Khanb0774702017-05-23 16:02:41 -0500207 }
208 else
209 {
210 activationBlocksTransition.reset(nullptr);
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500211 activationProgress.reset(nullptr);
Saqib Khanb0774702017-05-23 16:02:41 -0500212 }
213 return softwareServer::Activation::activation(value);
214}
215
Saqib Khanee13e832017-10-23 12:53:11 -0500216void Activation::deleteImageManagerObject()
217{
Saqib Khanee13e832017-10-23 12:53:11 -0500218 // Call the Delete object for <versionID> inside image_manager
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600219 auto method = this->bus.new_method_call(VERSION_BUSNAME, path.c_str(),
220 "xyz.openbmc_project.Object.Delete",
221 "Delete");
Adriana Kobylak3b6a4cd2018-12-10 13:45:09 -0600222 try
223 {
224 bus.call_noreply(method);
225 }
226 catch (const SdBusError& e)
Saqib Khanee13e832017-10-23 12:53:11 -0500227 {
228 log<level::ERR>("Error in Deleting image from image manager",
Adriana Kobylak596466b2018-02-13 14:48:53 -0600229 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khanee13e832017-10-23 12:53:11 -0500230 return;
231 }
232}
233
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600234auto Activation::requestedActivation(RequestedActivations value)
235 -> RequestedActivations
Saqib Khanb0774702017-05-23 16:02:41 -0500236{
Michael Tritzbed88af2017-07-19 16:00:06 -0500237 rwVolumeCreated = false;
238 roVolumeCreated = false;
Adriana Kobylak166bdf32018-04-09 14:24:06 -0500239 ubootEnvVarsUpdated = false;
Michael Tritzbed88af2017-07-19 16:00:06 -0500240
Saqib Khanb0774702017-05-23 16:02:41 -0500241 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
242 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600243 softwareServer::Activation::RequestedActivations::Active))
Saqib Khanb0774702017-05-23 16:02:41 -0500244 {
245 if ((softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600246 softwareServer::Activation::Activations::Ready) ||
Saqib Khanb0774702017-05-23 16:02:41 -0500247 (softwareServer::Activation::activation() ==
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600248 softwareServer::Activation::Activations::Failed))
Saqib Khanb0774702017-05-23 16:02:41 -0500249 {
250 Activation::activation(
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600251 softwareServer::Activation::Activations::Activating);
Saqib Khanb0774702017-05-23 16:02:41 -0500252 }
253 }
254 return softwareServer::Activation::requestedActivation(value);
255}
256
Saqib Khan4c1aec02017-07-06 11:46:13 -0500257uint8_t RedundancyPriority::priority(uint8_t value)
258{
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500259 // Set the priority value so that the freePriority() function can order
260 // the versions by priority.
261 auto newPriority = softwareServer::RedundancyPriority::priority(value);
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500262 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500263 parent.parent.freePriority(value, parent.versionId);
264 return newPriority;
Saqib Khan4c1aec02017-07-06 11:46:13 -0500265}
266
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500267uint8_t RedundancyPriority::sdbusPriority(uint8_t value)
Saqib Khanf0382c32017-10-24 13:36:22 -0500268{
Adriana Kobylakbbcb7be2018-07-17 15:47:34 -0500269 parent.parent.savePriority(parent.versionId, value);
Adriana Kobylakb77551c2017-10-27 12:46:23 -0500270 return softwareServer::RedundancyPriority::priority(value);
Saqib Khanf0382c32017-10-24 13:36:22 -0500271}
272
Michael Tritzbed88af2017-07-19 16:00:06 -0500273void Activation::unitStateChange(sdbusplus::message::message& msg)
274{
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500275 if (softwareServer::Activation::activation() !=
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600276 softwareServer::Activation::Activations::Activating)
Michael Tritz0edd4ad2017-07-26 14:27:42 -0500277 {
278 return;
279 }
280
Adriana Kobylak3ce563a2018-06-06 16:41:15 -0500281 onStateChanges(msg);
Michael Tritzbed88af2017-07-19 16:00:06 -0500282
283 return;
284}
285
Lei YU90532252018-05-24 11:15:24 +0800286#ifdef WANT_SIGNATURE_VERIFY
287bool Activation::verifySignature(const fs::path& imageDir,
288 const fs::path& confDir)
289{
290 using Signature = phosphor::software::image::Signature;
291
292 Signature signature(imageDir, confDir);
293
294 return signature.verify();
295}
296
297void Activation::onVerifyFailed()
298{
299 log<level::ERR>("Error occurred during image validation");
300 report<InternalFailure>();
301}
302#endif
303
Saqib Khanf37cefc2017-09-12 08:44:41 -0500304void ActivationBlocksTransition::enableRebootGuard()
305{
306 log<level::INFO>("BMC image activating - BMC reboots are disabled.");
307
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600308 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
309 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500310 method.append("reboot-guard-enable.service", "replace");
311 bus.call_noreply(method);
312}
313
314void ActivationBlocksTransition::disableRebootGuard()
315{
316 log<level::INFO>("BMC activation has ended - BMC reboots are re-enabled.");
317
Adriana Kobylak2285fe02018-02-27 15:36:59 -0600318 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
319 SYSTEMD_INTERFACE, "StartUnit");
Saqib Khanf37cefc2017-09-12 08:44:41 -0500320 method.append("reboot-guard-disable.service", "replace");
321 bus.call_noreply(method);
322}
Michael Tritzbed88af2017-07-19 16:00:06 -0500323
Jayashankar Padatha0135602019-04-22 16:22:58 +0530324bool Activation::checkApplyTimeImmediate()
325{
326 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
327 if (service.empty())
328 {
329 log<level::INFO>("Error getting the service name for BMC image "
330 "ApplyTime. The BMC needs to be manually rebooted to "
331 "complete the image activation if needed "
332 "immediately.");
333 }
334 else
335 {
336
337 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
338 dbusPropIntf, "Get");
339 method.append(applyTimeIntf, applyTimeProp);
340
341 try
342 {
343 auto reply = bus.call(method);
344
345 sdbusplus::message::variant<std::string> result;
346 reply.read(result);
347 auto applyTime =
348 sdbusplus::message::variant_ns::get<std::string>(result);
349 if (applyTime == applyTimeImmediate)
350 {
351 return true;
352 }
353 }
354 catch (const SdBusError& e)
355 {
356 log<level::ERR>("Error in getting ApplyTime",
357 entry("ERROR=%s", e.what()));
358 }
359 }
360 return false;
361}
362
363void Activation::rebootBmc()
364{
365 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
366 SYSTEMD_INTERFACE, "StartUnit");
367 method.append("force-reboot.service", "replace");
368 try
369 {
370 auto reply = bus.call(method);
371 }
372 catch (const SdBusError& e)
373 {
374 log<level::ALERT>("Error in trying to reboot the BMC. "
375 "The BMC needs to be manually rebooted to complete "
376 "the image activation.");
377 report<InternalFailure>();
378 }
379}
380
Saqib Khanb0774702017-05-23 16:02:41 -0500381} // namespace updater
382} // namespace software
383} // namespace phosphor