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 sdbusplus::async::task<> Software::createInventoryAssociations(bool isRunning) 73 { 74 debug("{SWID}: setting association definitions", "SWID", swid); 75 76 std::string endpoint = ""; 77 78 try 79 { 80 endpoint = co_await parentDevice.config.getInventoryItemObjectPath(ctx); 81 } 82 catch (std::exception& e) 83 { 84 error(e.what()); 85 } 86 87 if (!associationDefinitions) 88 { 89 std::string path = objectPath; 90 associationDefinitions = 91 std::make_unique<SoftwareAssociationDefinitions>(ctx, path.c_str()); 92 } 93 94 std::vector<std::tuple<std::string, std::string, std::string>> assocs; 95 96 if (endpoint.empty()) 97 { 98 associationDefinitions->associations(assocs); 99 co_return; 100 } 101 102 if (isRunning) 103 { 104 debug("{SWID}: creating 'running' association to {OBJPATH}", "SWID", 105 swid, "OBJPATH", endpoint); 106 std::tuple<std::string, std::string, std::string> assocRunning = { 107 "running", "ran_on", endpoint}; 108 assocs.push_back(assocRunning); 109 } 110 else 111 { 112 debug("{SWID}: creating 'activating' association to {OBJPATH}", "SWID", 113 swid, "OBJPATH", endpoint); 114 std::tuple<std::string, std::string, std::string> assocActivating = { 115 "activating", "activated_on", endpoint}; 116 assocs.push_back(assocActivating); 117 } 118 119 associationDefinitions->associations(assocs); 120 121 co_return; 122 } 123 124 void Software::setVersion(const std::string& versionStr, 125 SoftwareVersion::VersionPurpose versionPurpose) 126 { 127 debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr); 128 129 const bool emitSignal = !version; 130 131 if (!version) 132 { 133 version = 134 std::make_unique<SoftwareVersion>(ctx, objectPath.str.c_str()); 135 } 136 137 version->version(versionStr); 138 version->purpose(versionPurpose); 139 140 if (emitSignal) 141 { 142 version->emit_added(); 143 } 144 } 145 146 SoftwareVersion::VersionPurpose Software::getPurpose() 147 { 148 return version->purpose(); 149 } 150 151 void Software::setActivationBlocksTransition(bool enabled) 152 { 153 if (!enabled) 154 { 155 activationBlocksTransition = nullptr; 156 return; 157 } 158 159 std::string path = objectPath; 160 activationBlocksTransition = 161 std::make_unique<SoftwareActivationBlocksTransition>(ctx, path.c_str()); 162 } 163 164 void Software::setActivation(SoftwareActivation::Activations act) 165 { 166 activation(act); 167 } 168 169 void Software::enableUpdate( 170 const std::set<RequestedApplyTimes>& allowedApplyTimes) 171 { 172 if (updateIntf != nullptr) 173 { 174 error("[Software] update of {OBJPATH} has already been enabled", 175 "OBJPATH", objectPath); 176 return; 177 } 178 179 debug( 180 "[Software] enabling update of {OBJPATH} (adding the update interface)", 181 "OBJPATH", objectPath); 182 183 updateIntf = std::make_unique<SoftwareUpdate>(ctx, objectPath.str.c_str(), 184 *this, allowedApplyTimes); 185 } 186