blob: d024d07fa615a7c76a4e6736aac303a75dec9cdd [file] [log] [blame]
Adriana Kobylak692b5552017-04-17 14:02:58 -05001#include "config.h"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05002
3#include "activation.hpp"
4
Saqib Khan81bac882017-06-08 12:17:01 -05005#include "item_updater.hpp"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05006
7#include <experimental/filesystem>
Jayashankar Padath4d3d9122019-07-24 16:46:22 +05308#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/elog.hpp>
Saqib Khan7f80e0b2017-10-22 11:29:07 -050010#include <phosphor-logging/log.hpp>
Gunnar Mills74b657e2018-07-13 09:27:31 -050011#include <sdbusplus/exception.hpp>
Jayashankar Padath4d3d9122019-07-24 16:46:22 +053012#include <sdbusplus/server.hpp>
13#include <xyz/openbmc_project/Common/error.hpp>
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050014
Jayanth Othayoth4016e522018-03-20 09:39:06 -050015#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth4016e522018-03-20 09:39:06 -050016#include "image_verify.hpp"
Jayanth Othayoth4016e522018-03-20 09:39:06 -050017#endif
18
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050019namespace openpower
20{
21namespace software
22{
23namespace updater
24{
25
Adriana Kobylak55f9e832017-05-14 16:13:00 -050026namespace fs = std::experimental::filesystem;
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -050027namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
28
Saqib Khan7f80e0b2017-10-22 11:29:07 -050029using namespace phosphor::logging;
Gunnar Mills74b657e2018-07-13 09:27:31 -050030using sdbusplus::exception::SdBusError;
Jayanth Othayoth4016e522018-03-20 09:39:06 -050031using InternalFailure =
32 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Jayanth Othayoth11271fb2018-03-29 10:25:50 -050033
Jayashankar Padath4d3d9122019-07-24 16:46:22 +053034#ifdef WANT_SIGNATURE_VERIFY
Jayanth Othayoth11271fb2018-03-29 10:25:50 -050035// Field mode path and interface.
36constexpr auto FIELDMODE_PATH("/xyz/openbmc_project/software");
37constexpr auto FIELDMODE_INTERFACE("xyz.openbmc_project.Control.FieldMode");
Jayanth Othayoth4016e522018-03-20 09:39:06 -050038#endif
39
Adriana Kobylak70dcb632018-02-27 15:46:52 -060040constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
41constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Michael Tritz9d25b602017-06-14 14:41:43 -050042
43void Activation::subscribeToSystemdSignals()
44{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060045 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
46 SYSTEMD_INTERFACE, "Subscribe");
Gunnar Mills74b657e2018-07-13 09:27:31 -050047 try
48 {
49 this->bus.call_noreply(method);
50 }
51 catch (const SdBusError& e)
52 {
53 if (e.name() != nullptr &&
54 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0)
55 {
56 // If an Activation attempt fails, the Unsubscribe method is not
57 // called. This may lead to an AlreadySubscribed error if the
58 // Activation is re-attempted.
59 }
60 else
61 {
62 log<level::ERR>("Error subscribing to systemd",
63 entry("ERROR=%s", e.what()));
64 }
65 }
Michael Tritz9d25b602017-06-14 14:41:43 -050066 return;
67}
68
Michael Tritz1cb127f2017-07-26 15:40:38 -050069void Activation::unsubscribeFromSystemdSignals()
70{
Adriana Kobylak70dcb632018-02-27 15:46:52 -060071 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
72 SYSTEMD_INTERFACE, "Unsubscribe");
Michael Tritz1cb127f2017-07-26 15:40:38 -050073 this->bus.call_noreply(method);
74
75 return;
76}
77
Adriana Kobylak70dcb632018-02-27 15:46:52 -060078auto Activation::requestedActivation(RequestedActivations value)
79 -> RequestedActivations
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050080{
81 if ((value == softwareServer::Activation::RequestedActivations::Active) &&
82 (softwareServer::Activation::requestedActivation() !=
Adriana Kobylak70dcb632018-02-27 15:46:52 -060083 softwareServer::Activation::RequestedActivations::Active))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050084 {
85 if ((softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -060086 softwareServer::Activation::Activations::Ready) ||
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050087 (softwareServer::Activation::activation() ==
Adriana Kobylak70dcb632018-02-27 15:46:52 -060088 softwareServer::Activation::Activations::Failed))
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050089 {
Lei YUa2e67162019-02-22 17:35:24 +080090 activation(softwareServer::Activation::Activations::Activating);
Adriana Kobylak2fdb9312017-05-14 19:08:26 -050091 }
92 }
Adriana Kobylak99c8c0e2017-04-17 13:39:11 -050093 return softwareServer::Activation::requestedActivation(value);
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050094}
95
Saqib Khan7f80e0b2017-10-22 11:29:07 -050096void Activation::deleteImageManagerObject()
97{
98 // Get the Delete object for <versionID> inside image_manager
Lei YUc9caf862019-01-24 15:40:25 +080099 constexpr auto versionServiceStr = "xyz.openbmc_project.Software.Version";
100 constexpr auto deleteInterface = "xyz.openbmc_project.Object.Delete";
101 std::string versionService;
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600102 auto method = this->bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
103 MAPPER_INTERFACE, "GetObject");
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500104
105 method.append(path);
Lei YUc9caf862019-01-24 15:40:25 +0800106 method.append(std::vector<std::string>({deleteInterface}));
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500107
108 std::map<std::string, std::vector<std::string>> mapperResponse;
109
110 try
111 {
112 auto mapperResponseMsg = bus.call(method);
113 mapperResponseMsg.read(mapperResponse);
114 if (mapperResponse.begin() == mapperResponse.end())
115 {
116 log<level::ERR>("ERROR in reading the mapper response",
117 entry("VERSIONPATH=%s", path.c_str()));
118 return;
119 }
120 }
121 catch (const SdBusError& e)
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500122 {
123 log<level::ERR>("Error in Get Delete Object",
Joseph Reynoldsafd0a452018-05-30 11:16:03 -0500124 entry("VERSIONPATH=%s", path.c_str()));
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500125 return;
126 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500127
Lei YUc9caf862019-01-24 15:40:25 +0800128 // We need to find the phosphor-software-manager's version service
129 // to invoke the delete interface
130 for (auto resp : mapperResponse)
131 {
132 if (resp.first.find(versionServiceStr) != std::string::npos)
133 {
134 versionService = resp.first;
135 }
136 }
137
138 if (versionService.empty())
139 {
140 log<level::ERR>("Error finding version service");
141 return;
142 }
143
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500144 // Call the Delete object for <versionID> inside image_manager
Lei YUc9caf862019-01-24 15:40:25 +0800145 method = this->bus.new_method_call(versionService.c_str(), path.c_str(),
146 deleteInterface, "Delete");
Adriana Kobylakab435df2018-07-16 11:37:19 -0500147 try
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500148 {
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500149 bus.call(method);
Adriana Kobylakab435df2018-07-16 11:37:19 -0500150 }
151 catch (const SdBusError& e)
152 {
153 if (e.name() != nullptr && strcmp("System.Error.ELOOP", e.name()) == 0)
154 {
155 // TODO: Error being tracked with openbmc/openbmc#3311
156 }
157 else
158 {
159 log<level::ERR>("Error performing call to Delete object path",
160 entry("ERROR=%s", e.what()),
161 entry("PATH=%s", path.c_str()));
162 }
Saqib Khan7f80e0b2017-10-22 11:29:07 -0500163 return;
164 }
165}
166
Jayashankar Padath4d3d9122019-07-24 16:46:22 +0530167bool Activation::checkApplyTimeImmediate()
168{
169 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf);
170 if (service.empty())
171 {
172 log<level::INFO>("Error getting the service name for Host image "
173 "ApplyTime. The Host needs to be manually rebooted to "
174 "complete the image activation if needed "
175 "immediately.");
176 }
177 else
178 {
179
180 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath,
181 dbusPropIntf, "Get");
182 method.append(applyTimeIntf, applyTimeProp);
183
184 try
185 {
186 auto reply = bus.call(method);
187
Patrick Williams212102e2020-05-13 17:50:50 -0500188 std::variant<std::string> result;
Jayashankar Padath4d3d9122019-07-24 16:46:22 +0530189 reply.read(result);
Patrick Williams550f31b2020-05-13 11:15:24 -0500190 auto applyTime = std::get<std::string>(result);
Jayashankar Padath4d3d9122019-07-24 16:46:22 +0530191 if (applyTime == applyTimeImmediate)
192 {
193 return true;
194 }
195 }
196 catch (const SdBusError& e)
197 {
198 log<level::ERR>("Error in getting ApplyTime",
199 entry("ERROR=%s", e.what()));
200 }
201 }
202 return false;
203}
204
205void Activation::rebootHost()
206{
207 auto service = utils::getService(bus, hostStateObjPath, hostStateIntf);
208 if (service.empty())
209 {
210 log<level::ALERT>("Error in getting the service name to reboot the "
211 "Host. The Host needs to be manually rebooted to "
212 "complete the image activation.");
213 }
214
215 auto method = bus.new_method_call(service.c_str(), hostStateObjPath,
216 dbusPropIntf, "Set");
Patrick Williams212102e2020-05-13 17:50:50 -0500217 std::variant<std::string> hostReboot = hostStateRebootVal;
Jayashankar Padath4d3d9122019-07-24 16:46:22 +0530218 method.append(hostStateIntf, hostStateRebootProp, hostReboot);
219
220 try
221 {
222 auto reply = bus.call(method);
223 }
224 catch (const SdBusError& e)
225 {
226 log<level::ALERT>("Error in trying to reboot the Host. "
227 "The Host needs to be manually rebooted to complete "
228 "the image activation.",
229 entry("ERROR=%s", e.what()));
230 report<InternalFailure>();
231 }
232}
233
Saqib Khan2021b4c2017-06-07 14:37:36 -0500234uint8_t RedundancyPriority::priority(uint8_t value)
235{
Saqib Khanb8e7f312017-08-12 10:24:10 -0500236 parent.parent.freePriority(value, parent.versionId);
Saqib Khan2021b4c2017-06-07 14:37:36 -0500237 return softwareServer::RedundancyPriority::priority(value);
238}
239
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500240#ifdef WANT_SIGNATURE_VERIFY
Lei YU2b2d2292019-03-18 15:22:56 +0800241bool Activation::validateSignature(const std::string& pnorFileName)
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500242{
243 using Signature = openpower::software::image::Signature;
244 fs::path imageDir(IMG_DIR);
245
Lei YU2b2d2292019-03-18 15:22:56 +0800246 Signature signature(imageDir / versionId, pnorFileName,
247 PNOR_SIGNED_IMAGE_CONF_PATH);
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500248
249 // Validate the signed image.
250 if (signature.verify())
251 {
252 return true;
253 }
254 // Log error and continue activation process, if field mode disabled.
255 log<level::ERR>("Error occurred during image validation");
256 report<InternalFailure>();
257
258 try
259 {
260 if (!fieldModeEnabled())
261 {
262 return true;
263 }
264 }
265 catch (const InternalFailure& e)
266 {
267 report<InternalFailure>();
268 }
269 return false;
270}
271
272bool Activation::fieldModeEnabled()
273{
Lei YUe4994462019-03-14 14:41:53 +0800274 auto fieldModeSvc =
275 utils::getService(bus, FIELDMODE_PATH, FIELDMODE_INTERFACE);
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500276
277 auto method = bus.new_method_call(fieldModeSvc.c_str(), FIELDMODE_PATH,
278 "org.freedesktop.DBus.Properties", "Get");
279
280 method.append(FIELDMODE_INTERFACE, "FieldModeEnabled");
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500281
Patrick Williams212102e2020-05-13 17:50:50 -0500282 std::variant<bool> fieldMode;
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500283
284 try
285 {
286 auto reply = bus.call(method);
287 reply.read(fieldMode);
Patrick Williams550f31b2020-05-13 11:15:24 -0500288 return std::get<bool>(fieldMode);
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500289 }
290 catch (const SdBusError& e)
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500291 {
292 log<level::ERR>("Error in fieldModeEnabled getValue");
293 elog<InternalFailure>();
294 }
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500295}
296
Jayanth Othayoth11271fb2018-03-29 10:25:50 -0500297#endif
298
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500299} // namespace updater
300} // namespace software
301} // namespace openpower