blob: 504a9aec196fc9d9591a27335e84f7e3fd346fba [file] [log] [blame]
Alexander Hansencc372352025-01-14 14:15:39 +01001#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
13PHOSPHOR_LOG2_USING;
14
15using namespace phosphor::software;
16using namespace phosphor::software::device;
17using namespace phosphor::software::config;
18using namespace phosphor::software::update;
19
20const static std::string baseObjPathSoftware = "/xyz/openbmc_project/software/";
21
22SoftwareActivationProgress::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
32void SoftwareActivationProgress::setProgress(int progressArg)
33{
34 progress(progressArg);
35}
36
37Software::Software(sdbusplus::async::context& ctx, Device& parent) :
38 Software(ctx, parent, getRandomSoftwareId(parent))
39{}
40
41Software::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
Alexander Hansenf2c95a02024-11-26 11:16:44 +010058long int Software::getRandomId()
Alexander Hansencc372352025-01-14 14:15:39 +010059{
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
67std::string Software::getRandomSoftwareId(Device& parent)
68{
69 return std::format("{}_{}", parent.config.configName, getRandomId());
70}
71
72// NOLINTBEGIN(readability-static-accessed-through-instance)
73sdbusplus::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
Alexander Hansende5e76f2025-02-20 16:30:11 +0100126void Software::setVersion(const std::string& versionStr,
127 SoftwareVersion::VersionPurpose versionPurpose)
Alexander Hansencc372352025-01-14 14:15:39 +0100128{
129 debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr);
130
Alexander Hansende5e76f2025-02-20 16:30:11 +0100131 const bool emitSignal = !version;
132
Alexander Hansenccec7c62025-02-21 17:17:45 +0100133 if (!version)
Alexander Hansencc372352025-01-14 14:15:39 +0100134 {
Alexander Hansenccec7c62025-02-21 17:17:45 +0100135 version =
136 std::make_unique<SoftwareVersion>(ctx, objectPath.str.c_str());
Alexander Hansencc372352025-01-14 14:15:39 +0100137 }
138
Alexander Hansencc372352025-01-14 14:15:39 +0100139 version->version(versionStr);
Alexander Hansende5e76f2025-02-20 16:30:11 +0100140 version->purpose(versionPurpose);
141
142 if (emitSignal)
143 {
144 version->emit_added();
145 }
146}
147
148SoftwareVersion::VersionPurpose Software::getPurpose()
149{
150 return version->purpose();
Alexander Hansencc372352025-01-14 14:15:39 +0100151}
152
153void 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
166void Software::setActivation(SoftwareActivation::Activations act)
167{
168 activation(act);
169}
170
171void 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}