#include "software.hpp" #include "device.hpp" #include "software_update.hpp" #include #include #include #include #include #include PHOSPHOR_LOG2_USING; using namespace phosphor::software; using namespace phosphor::software::device; using namespace phosphor::software::config; using namespace phosphor::software::update; const static std::string baseObjPathSoftware = "/xyz/openbmc_project/software/"; Software::Software(sdbusplus::async::context& ctx, Device& parent) : Software(ctx, parent, getRandomSoftwareId(parent)) {} Software::Software(sdbusplus::async::context& ctx, Device& parent, const std::string& swid) : SoftwareActivation(ctx, (baseObjPathSoftware + swid).c_str(), Activation::properties_t{Activations::NotReady, RequestedActivations::None}), parentDevice(parent), swid(swid), objectPath(baseObjPathSoftware + swid), ctx(ctx) { std::string objPath = baseObjPathSoftware + swid; emit_added(); debug("{SWID}: created dbus interfaces on path {OBJPATH}", "SWID", swid, "OBJPATH", objPath); }; long int Software::getRandomId() { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); unsigned int seed = ts.tv_nsec ^ getpid(); srandom(seed); return random() % 10000; } std::string Software::getRandomSoftwareId(Device& parent) { return std::format("{}_{}", parent.config.configName, getRandomId()); } sdbusplus::async::task<> Software::createInventoryAssociations(bool isRunning) { debug("{SWID}: setting association definitions", "SWID", swid); std::string endpoint = ""; try { endpoint = co_await parentDevice.config.getInventoryItemObjectPath(ctx); } catch (std::exception& e) { error("Failed to create association with {ERROR}", "ERROR", e.what()); co_return; } if (endpoint.empty()) { co_return; } createInventoryAssociation(isRunning, endpoint); } void Software::createInventoryAssociation(bool isRunning, std::string objectPath) { std::vector> assocs; if (isRunning) { debug("{SWID}: creating 'running' association to {OBJPATH}", "SWID", swid, "OBJPATH", objectPath); std::tuple assocRunning = { "running", "ran_on", objectPath}; assocs.push_back(assocRunning); } else { debug("{SWID}: creating 'activating' association to {OBJPATH}", "SWID", swid, "OBJPATH", objectPath); std::tuple assocActivating = { "activating", "activated_on", objectPath}; assocs.push_back(assocActivating); } if (associationDefinitions) { associationDefinitions->associations(assocs); } else { associationDefinitions = std::make_unique( ctx, Software::objectPath.str.c_str(), SoftwareAssociationDefinitions::properties_t{assocs}); associationDefinitions->emit_added(); } } void Software::setVersion(const std::string& versionStr, SoftwareVersion::VersionPurpose versionPurpose) { debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr); if (!version) { version = std::make_unique( ctx, objectPath.str.c_str(), SoftwareVersion::properties_t{versionStr, versionPurpose}); version->emit_added(); return; } version->version(versionStr); version->purpose(versionPurpose); } std::optional Software::getPurpose() { if (!version) { return std::nullopt; } return version->purpose(); } void Software::setActivationBlocksTransition(bool enabled) { if (!enabled) { activationBlocksTransition = nullptr; return; } std::string path = objectPath; activationBlocksTransition = std::make_unique(ctx, path.c_str()); activationBlocksTransition->emit_added(); } void Software::setActivation(SoftwareActivation::Activations act) { activation(act); } void Software::enableUpdate( const std::set& allowedApplyTimes) { if (updateIntf != nullptr) { error("[Software] update of {OBJPATH} has already been enabled", "OBJPATH", objectPath); return; } debug( "[Software] enabling update of {OBJPATH} (adding the update interface)", "OBJPATH", objectPath); updateIntf = std::make_unique(ctx, objectPath.str.c_str(), *this, allowedApplyTimes); }