1 #include "software.hpp" 2 3 #include "device.hpp" 4 #include "software_update.hpp" 5 6 #include <phosphor-logging/lg2.hpp> 7 #include <sdbusplus/async/context.hpp> 8 #include <xyz/openbmc_project/Association/Definitions/server.hpp> 9 #include <xyz/openbmc_project/Software/Activation/aserver.hpp> 10 #include <xyz/openbmc_project/Software/Update/aserver.hpp> 11 #include <xyz/openbmc_project/State/Host/client.hpp> 12 13 PHOSPHOR_LOG2_USING; 14 15 using namespace phosphor::software; 16 using namespace phosphor::software::device; 17 using namespace phosphor::software::config; 18 using namespace phosphor::software::update; 19 20 const static std::string baseObjPathSoftware = "/xyz/openbmc_project/software/"; 21 22 Software::Software(sdbusplus::async::context& ctx, Device& parent) : 23 Software(ctx, parent, getRandomSoftwareId(parent)) 24 {} 25 26 Software::Software(sdbusplus::async::context& ctx, Device& parent, 27 const std::string& swid) : 28 SoftwareActivation(ctx, (baseObjPathSoftware + swid).c_str(), 29 Activation::properties_t{Activations::NotReady, 30 RequestedActivations::None}), 31 parentDevice(parent), swid(swid), objectPath(baseObjPathSoftware + swid), 32 ctx(ctx) 33 { 34 std::string objPath = baseObjPathSoftware + swid; 35 36 emit_added(); 37 38 debug("{SWID}: created dbus interfaces on path {OBJPATH}", "SWID", swid, 39 "OBJPATH", objPath); 40 }; 41 42 long int Software::getRandomId() 43 { 44 struct timespec ts; 45 clock_gettime(CLOCK_REALTIME, &ts); 46 unsigned int seed = ts.tv_nsec ^ getpid(); 47 srandom(seed); 48 return random() % 10000; 49 } 50 51 std::string Software::getRandomSoftwareId(Device& parent) 52 { 53 return std::format("{}_{}", parent.config.configName, getRandomId()); 54 } 55 56 sdbusplus::async::task<> Software::createInventoryAssociations(bool isRunning) 57 { 58 debug("{SWID}: setting association definitions", "SWID", swid); 59 60 std::string endpoint = ""; 61 62 try 63 { 64 endpoint = co_await parentDevice.config.getInventoryItemObjectPath(ctx); 65 } 66 catch (std::exception& e) 67 { 68 error("Failed to create association with {ERROR}", "ERROR", e.what()); 69 co_return; 70 } 71 72 if (endpoint.empty()) 73 { 74 co_return; 75 } 76 77 createInventoryAssociation(isRunning, endpoint); 78 } 79 80 void Software::createInventoryAssociation(bool isRunning, 81 std::string objectPath) 82 { 83 std::vector<std::tuple<std::string, std::string, std::string>> assocs; 84 85 if (isRunning) 86 { 87 debug("{SWID}: creating 'running' association to {OBJPATH}", "SWID", 88 swid, "OBJPATH", objectPath); 89 std::tuple<std::string, std::string, std::string> assocRunning = { 90 "running", "ran_on", objectPath}; 91 assocs.push_back(assocRunning); 92 } 93 else 94 { 95 debug("{SWID}: creating 'activating' association to {OBJPATH}", "SWID", 96 swid, "OBJPATH", objectPath); 97 std::tuple<std::string, std::string, std::string> assocActivating = { 98 "activating", "activated_on", objectPath}; 99 assocs.push_back(assocActivating); 100 } 101 102 if (associationDefinitions) 103 { 104 associationDefinitions->associations(assocs); 105 } 106 else 107 { 108 associationDefinitions = 109 std::make_unique<SoftwareAssociationDefinitions>( 110 ctx, Software::objectPath.str.c_str(), 111 SoftwareAssociationDefinitions::properties_t{assocs}); 112 associationDefinitions->emit_added(); 113 } 114 } 115 116 void Software::setVersion(const std::string& versionStr, 117 SoftwareVersion::VersionPurpose versionPurpose) 118 { 119 debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr); 120 121 if (!version) 122 { 123 version = std::make_unique<SoftwareVersion>( 124 ctx, objectPath.str.c_str(), 125 SoftwareVersion::properties_t{versionStr, versionPurpose}); 126 version->emit_added(); 127 return; 128 } 129 130 version->version(versionStr); 131 version->purpose(versionPurpose); 132 } 133 134 std::optional<SoftwareVersion::VersionPurpose> Software::getPurpose() 135 { 136 if (!version) 137 { 138 return std::nullopt; 139 } 140 return version->purpose(); 141 } 142 143 void Software::setActivationBlocksTransition(bool enabled) 144 { 145 if (!enabled) 146 { 147 activationBlocksTransition = nullptr; 148 return; 149 } 150 151 std::string path = objectPath; 152 activationBlocksTransition = 153 std::make_unique<SoftwareActivationBlocksTransition>(ctx, path.c_str()); 154 155 activationBlocksTransition->emit_added(); 156 } 157 158 void Software::setActivation(SoftwareActivation::Activations act) 159 { 160 activation(act); 161 } 162 163 void Software::enableUpdate( 164 const std::set<RequestedApplyTimes>& allowedApplyTimes) 165 { 166 if (updateIntf != nullptr) 167 { 168 error("[Software] update of {OBJPATH} has already been enabled", 169 "OBJPATH", objectPath); 170 return; 171 } 172 173 debug( 174 "[Software] enabling update of {OBJPATH} (adding the update interface)", 175 "OBJPATH", objectPath); 176 177 updateIntf = std::make_unique<SoftwareUpdate>(ctx, objectPath.str.c_str(), 178 *this, allowedApplyTimes); 179 } 180