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 SoftwareActivationProgress::SoftwareActivationProgress( 23 sdbusplus::async::context& ctx, const char* objPath) : 24 ActivationProgress(ctx, objPath) 25 { 26 // This prevents "Conditional jump or move depends on uninitialised 27 // value(s)" 28 // when properties are updated for the first time 29 progress_ = 0; 30 } 31 32 void SoftwareActivationProgress::setProgress(int progressArg) 33 { 34 progress(progressArg); 35 } 36 37 Software::Software(sdbusplus::async::context& ctx, Device& parent) : 38 Software(ctx, parent, getRandomSoftwareId(parent)) 39 {} 40 41 Software::Software(sdbusplus::async::context& ctx, Device& parent, 42 const std::string& swid) : 43 SoftwareActivation(ctx, (baseObjPathSoftware + swid).c_str()), 44 objectPath(baseObjPathSoftware + swid), parentDevice(parent), swid(swid), 45 ctx(ctx) 46 { 47 // initialize the members of our base class to prevent 48 // "Conditional jump or move depends on uninitialised value(s)" 49 activation_ = Activations::NotReady; 50 requested_activation_ = RequestedActivations::None; 51 52 std::string objPath = baseObjPathSoftware + swid; 53 54 debug("{SWID}: created dbus interfaces on path {OBJPATH}", "SWID", swid, 55 "OBJPATH", objPath); 56 }; 57 58 long int Software::getRandomId() 59 { 60 struct timespec ts; 61 clock_gettime(CLOCK_REALTIME, &ts); 62 unsigned int seed = ts.tv_nsec ^ getpid(); 63 srandom(seed); 64 return random() % 10000; 65 } 66 67 std::string Software::getRandomSoftwareId(Device& parent) 68 { 69 return std::format("{}_{}", parent.config.configName, getRandomId()); 70 } 71 72 // NOLINTBEGIN(readability-static-accessed-through-instance) 73 sdbusplus::async::task<> Software::createInventoryAssociations(bool isRunning) 74 // NOLINTEND(readability-static-accessed-through-instance) 75 { 76 debug("{SWID}: setting association definitions", "SWID", swid); 77 78 std::string endpoint = ""; 79 80 try 81 { 82 endpoint = co_await parentDevice.config.getInventoryItemObjectPath(ctx); 83 } 84 catch (std::exception& e) 85 { 86 error(e.what()); 87 } 88 89 if (!associationDefinitions) 90 { 91 std::string path = objectPath; 92 associationDefinitions = 93 std::make_unique<SoftwareAssociationDefinitions>(ctx, path.c_str()); 94 } 95 96 std::vector<std::tuple<std::string, std::string, std::string>> assocs; 97 98 if (endpoint.empty()) 99 { 100 associationDefinitions->associations(assocs); 101 co_return; 102 } 103 104 if (isRunning) 105 { 106 debug("{SWID}: creating 'running' association to {OBJPATH}", "SWID", 107 swid, "OBJPATH", endpoint); 108 std::tuple<std::string, std::string, std::string> assocRunning = { 109 "running", "ran_on", endpoint}; 110 assocs.push_back(assocRunning); 111 } 112 else 113 { 114 debug("{SWID}: creating 'activating' association to {OBJPATH}", "SWID", 115 swid, "OBJPATH", endpoint); 116 std::tuple<std::string, std::string, std::string> assocActivating = { 117 "activating", "activated_on", endpoint}; 118 assocs.push_back(assocActivating); 119 } 120 121 associationDefinitions->associations(assocs); 122 123 co_return; 124 } 125 126 void Software::setVersion(const std::string& versionStr, 127 SoftwareVersion::VersionPurpose versionPurpose) 128 { 129 debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr); 130 131 const bool emitSignal = !version; 132 133 if (!version) 134 { 135 version = 136 std::make_unique<SoftwareVersion>(ctx, objectPath.str.c_str()); 137 } 138 139 version->version(versionStr); 140 version->purpose(versionPurpose); 141 142 if (emitSignal) 143 { 144 version->emit_added(); 145 } 146 } 147 148 SoftwareVersion::VersionPurpose Software::getPurpose() 149 { 150 return version->purpose(); 151 } 152 153 void Software::setActivationBlocksTransition(bool enabled) 154 { 155 if (!enabled) 156 { 157 activationBlocksTransition = nullptr; 158 return; 159 } 160 161 std::string path = objectPath; 162 activationBlocksTransition = 163 std::make_unique<SoftwareActivationBlocksTransition>(ctx, path.c_str()); 164 } 165 166 void Software::setActivation(SoftwareActivation::Activations act) 167 { 168 activation(act); 169 } 170 171 void Software::enableUpdate( 172 const std::set<RequestedApplyTimes>& allowedApplyTimes) 173 { 174 if (updateIntf != nullptr) 175 { 176 error("[Software] update of {OBJPATH} has already been enabled", 177 "OBJPATH", objectPath); 178 return; 179 } 180 181 debug( 182 "[Software] enabling update of {OBJPATH} (adding the update interface)", 183 "OBJPATH", objectPath); 184 185 updateIntf = std::make_unique<SoftwareUpdate>(ctx, objectPath.str.c_str(), 186 *this, allowedApplyTimes); 187 } 188