1 #include "config.h" 2 3 #include "activation.hpp" 4 5 #include "utils.hpp" 6 7 #include <cassert> 8 #include <filesystem> 9 10 namespace phosphor 11 { 12 namespace software 13 { 14 namespace updater 15 { 16 17 constexpr auto SYSTEMD_BUSNAME = "org.freedesktop.systemd1"; 18 constexpr auto SYSTEMD_PATH = "/org/freedesktop/systemd1"; 19 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 20 21 namespace fs = std::filesystem; 22 namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server; 23 24 using SoftwareActivation = softwareServer::Activation; 25 26 namespace internal 27 { 28 /** Construct the systemd service name */ 29 std::string getUpdateService(const std::string& psuInventoryPath, 30 const std::string& versionId) 31 { 32 fs::path imagePath(IMG_DIR); 33 imagePath /= versionId; 34 35 // The systemd unit shall be escaped 36 std::string args = psuInventoryPath; 37 args += "\\x20"; 38 args += imagePath; 39 std::replace(args.begin(), args.end(), '/', '-'); 40 41 std::string service = PSU_UPDATE_SERVICE; 42 auto p = service.find('@'); 43 assert(p != std::string::npos); 44 service.insert(p + 1, args); 45 return service; 46 } 47 48 } // namespace internal 49 auto Activation::activation(Activations value) -> Activations 50 { 51 if (value == Status::Activating) 52 { 53 startActivation(); 54 } 55 else 56 { 57 // TODO 58 } 59 60 return SoftwareActivation::activation(value); 61 } 62 63 auto Activation::requestedActivation(RequestedActivations value) 64 -> RequestedActivations 65 { 66 if ((value == SoftwareActivation::RequestedActivations::Active) && 67 (SoftwareActivation::requestedActivation() != 68 SoftwareActivation::RequestedActivations::Active)) 69 { 70 if ((activation() == Status::Ready) || (activation() == Status::Failed)) 71 { 72 activation(Status::Activating); 73 } 74 } 75 return SoftwareActivation::requestedActivation(value); 76 } 77 78 void Activation::unitStateChange(sdbusplus::message::message& msg) 79 { 80 uint32_t newStateID{}; 81 sdbusplus::message::object_path newStateObjPath; 82 std::string newStateUnit{}; 83 std::string newStateResult{}; 84 85 // Read the msg and populate each variable 86 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult); 87 88 if (newStateUnit == psuUpdateUnit) 89 { 90 if (newStateResult == "done") 91 { 92 finishActivation(); 93 } 94 if (newStateResult == "failed" || newStateResult == "dependency") 95 { 96 activation(Status::Failed); 97 } 98 } 99 } 100 101 void Activation::startActivation() 102 { 103 // TODO: for now only update one psu, future commits shall handle update 104 // multiple psus 105 auto psuPaths = utils::getPSUInventoryPath(bus); 106 if (psuPaths.empty()) 107 { 108 return; 109 } 110 111 psuUpdateUnit = internal::getUpdateService(psuPaths[0], versionId); 112 113 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 114 SYSTEMD_INTERFACE, "StartUnit"); 115 method.append(psuUpdateUnit, "replace"); 116 bus.call_noreply(method); 117 } 118 119 void Activation::finishActivation() 120 { 121 // TODO: delete the interfaces created by phosphor-software-manager 122 // TODO: delete the old software object 123 // TODO: create related associations 124 activation(Status::Active); 125 } 126 127 } // namespace updater 128 } // namespace software 129 } // namespace phosphor 130