1 #include "config.h" 2 3 #include "activation.hpp" 4 5 #include "item_updater.hpp" 6 7 #include <phosphor-logging/elog-errors.hpp> 8 #include <phosphor-logging/elog.hpp> 9 #include <phosphor-logging/log.hpp> 10 #include <sdbusplus/exception.hpp> 11 #include <sdbusplus/server.hpp> 12 #include <xyz/openbmc_project/Common/error.hpp> 13 14 #include <filesystem> 15 16 #ifdef WANT_SIGNATURE_VERIFY 17 #include "image_verify.hpp" 18 #endif 19 20 namespace openpower 21 { 22 namespace software 23 { 24 namespace updater 25 { 26 27 namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server; 28 29 using namespace phosphor::logging; 30 using InternalFailure = 31 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 32 33 #ifdef WANT_SIGNATURE_VERIFY 34 // Field mode path and interface. 35 constexpr auto FIELDMODE_PATH("/xyz/openbmc_project/software"); 36 constexpr auto FIELDMODE_INTERFACE("xyz.openbmc_project.Control.FieldMode"); 37 #endif 38 39 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 40 constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1"; 41 42 void Activation::subscribeToSystemdSignals() 43 { 44 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, 45 SYSTEMD_INTERFACE, "Subscribe"); 46 try 47 { 48 this->bus.call_noreply(method); 49 } 50 catch (const sdbusplus::exception::exception& e) 51 { 52 if (e.name() != nullptr && 53 strcmp("org.freedesktop.systemd1.AlreadySubscribed", e.name()) == 0) 54 { 55 // If an Activation attempt fails, the Unsubscribe method is not 56 // called. This may lead to an AlreadySubscribed error if the 57 // Activation is re-attempted. 58 } 59 else 60 { 61 log<level::ERR>("Error subscribing to systemd", 62 entry("ERROR=%s", e.what())); 63 } 64 } 65 return; 66 } 67 68 void Activation::unsubscribeFromSystemdSignals() 69 { 70 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, 71 SYSTEMD_INTERFACE, "Unsubscribe"); 72 this->bus.call_noreply(method); 73 74 return; 75 } 76 77 auto Activation::requestedActivation(RequestedActivations value) 78 -> RequestedActivations 79 { 80 if ((value == softwareServer::Activation::RequestedActivations::Active) && 81 (softwareServer::Activation::requestedActivation() != 82 softwareServer::Activation::RequestedActivations::Active)) 83 { 84 if ((softwareServer::Activation::activation() == 85 softwareServer::Activation::Activations::Ready) || 86 (softwareServer::Activation::activation() == 87 softwareServer::Activation::Activations::Failed)) 88 { 89 activation(softwareServer::Activation::Activations::Activating); 90 } 91 } 92 return softwareServer::Activation::requestedActivation(value); 93 } 94 95 void Activation::deleteImageManagerObject() 96 { 97 // Get the Delete object for <versionID> inside image_manager 98 constexpr auto versionServiceStr = "xyz.openbmc_project.Software.Version"; 99 constexpr auto deleteInterface = "xyz.openbmc_project.Object.Delete"; 100 std::string versionService; 101 auto method = this->bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 102 MAPPER_INTERFACE, "GetObject"); 103 104 method.append(path); 105 method.append(std::vector<std::string>({deleteInterface})); 106 107 std::map<std::string, std::vector<std::string>> mapperResponse; 108 109 try 110 { 111 auto mapperResponseMsg = bus.call(method); 112 mapperResponseMsg.read(mapperResponse); 113 if (mapperResponse.begin() == mapperResponse.end()) 114 { 115 log<level::ERR>("ERROR in reading the mapper response", 116 entry("VERSIONPATH=%s", path.c_str())); 117 return; 118 } 119 } 120 catch (const sdbusplus::exception::exception& e) 121 { 122 log<level::ERR>("Error in Get Delete Object", 123 entry("VERSIONPATH=%s", path.c_str())); 124 return; 125 } 126 127 // We need to find the phosphor-software-manager's version service 128 // to invoke the delete interface 129 for (auto resp : mapperResponse) 130 { 131 if (resp.first.find(versionServiceStr) != std::string::npos) 132 { 133 versionService = resp.first; 134 } 135 } 136 137 if (versionService.empty()) 138 { 139 log<level::ERR>("Error finding version service"); 140 return; 141 } 142 143 // Call the Delete object for <versionID> inside image_manager 144 method = this->bus.new_method_call(versionService.c_str(), path.c_str(), 145 deleteInterface, "Delete"); 146 try 147 { 148 bus.call(method); 149 } 150 catch (const sdbusplus::exception::exception& e) 151 { 152 if (e.name() != nullptr && strcmp("System.Error.ELOOP", e.name()) == 0) 153 { 154 // TODO: Error being tracked with openbmc/openbmc#3311 155 } 156 else 157 { 158 log<level::ERR>("Error performing call to Delete object path", 159 entry("ERROR=%s", e.what()), 160 entry("PATH=%s", path.c_str())); 161 } 162 return; 163 } 164 } 165 166 bool Activation::checkApplyTimeImmediate() 167 { 168 auto service = utils::getService(bus, applyTimeObjPath, applyTimeIntf); 169 if (service.empty()) 170 { 171 log<level::INFO>("Error getting the service name for Host image " 172 "ApplyTime. The Host needs to be manually rebooted to " 173 "complete the image activation if needed " 174 "immediately."); 175 } 176 else 177 { 178 179 auto method = bus.new_method_call(service.c_str(), applyTimeObjPath, 180 dbusPropIntf, "Get"); 181 method.append(applyTimeIntf, applyTimeProp); 182 183 try 184 { 185 auto reply = bus.call(method); 186 187 std::variant<std::string> result; 188 reply.read(result); 189 auto applyTime = std::get<std::string>(result); 190 if (applyTime == applyTimeImmediate) 191 { 192 return true; 193 } 194 } 195 catch (const sdbusplus::exception::exception& e) 196 { 197 log<level::ERR>("Error in getting ApplyTime", 198 entry("ERROR=%s", e.what())); 199 } 200 } 201 return false; 202 } 203 204 void Activation::rebootHost() 205 { 206 auto service = utils::getService(bus, hostStateObjPath, hostStateIntf); 207 if (service.empty()) 208 { 209 log<level::ALERT>("Error in getting the service name to reboot the " 210 "Host. The Host needs to be manually rebooted to " 211 "complete the image activation."); 212 } 213 214 auto method = bus.new_method_call(service.c_str(), hostStateObjPath, 215 dbusPropIntf, "Set"); 216 std::variant<std::string> hostReboot = hostStateRebootVal; 217 method.append(hostStateIntf, hostStateRebootProp, hostReboot); 218 219 try 220 { 221 auto reply = bus.call(method); 222 } 223 catch (const sdbusplus::exception::exception& e) 224 { 225 log<level::ALERT>("Error in trying to reboot the Host. " 226 "The Host needs to be manually rebooted to complete " 227 "the image activation.", 228 entry("ERROR=%s", e.what())); 229 report<InternalFailure>(); 230 } 231 } 232 233 uint8_t RedundancyPriority::priority(uint8_t value) 234 { 235 parent.parent.freePriority(value, parent.versionId); 236 return softwareServer::RedundancyPriority::priority(value); 237 } 238 239 #ifdef WANT_SIGNATURE_VERIFY 240 bool Activation::validateSignature(const std::string& pnorFileName) 241 { 242 using Signature = openpower::software::image::Signature; 243 std::filesystem::path imageDir(IMG_DIR); 244 245 Signature signature(imageDir / versionId, pnorFileName, 246 PNOR_SIGNED_IMAGE_CONF_PATH); 247 248 // Validate the signed image. 249 if (signature.verify()) 250 { 251 return true; 252 } 253 // Log error and continue activation process, if field mode disabled. 254 log<level::ERR>("Error occurred during image validation"); 255 report<InternalFailure>(); 256 257 try 258 { 259 if (!fieldModeEnabled()) 260 { 261 return true; 262 } 263 } 264 catch (const InternalFailure& e) 265 { 266 report<InternalFailure>(); 267 } 268 return false; 269 } 270 271 bool Activation::fieldModeEnabled() 272 { 273 auto fieldModeSvc = 274 utils::getService(bus, FIELDMODE_PATH, FIELDMODE_INTERFACE); 275 276 auto method = bus.new_method_call(fieldModeSvc.c_str(), FIELDMODE_PATH, 277 "org.freedesktop.DBus.Properties", "Get"); 278 279 method.append(FIELDMODE_INTERFACE, "FieldModeEnabled"); 280 281 std::variant<bool> fieldMode; 282 283 try 284 { 285 auto reply = bus.call(method); 286 reply.read(fieldMode); 287 return std::get<bool>(fieldMode); 288 } 289 catch (const sdbusplus::exception::exception& e) 290 { 291 log<level::ERR>("Error in fieldModeEnabled getValue"); 292 elog<InternalFailure>(); 293 } 294 } 295 296 #endif 297 298 } // namespace updater 299 } // namespace software 300 } // namespace openpower 301