blob: 03e9199a89a4e9d812fe98e25f68d90dd5f35c16 [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
58static long int 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
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
126void Software::setVersion(const std::string& versionStr)
127{
128 debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr);
129
130 if (version)
131 {
132 error("{SWID}: version was already set", "SWID", swid);
133 return;
134 }
135
136 version = std::make_unique<SoftwareVersion>(ctx, objectPath.str.c_str());
137 version->version(versionStr);
138}
139
140void Software::setActivationBlocksTransition(bool enabled)
141{
142 if (!enabled)
143 {
144 activationBlocksTransition = nullptr;
145 return;
146 }
147
148 std::string path = objectPath;
149 activationBlocksTransition =
150 std::make_unique<SoftwareActivationBlocksTransition>(ctx, path.c_str());
151}
152
153void Software::setActivation(SoftwareActivation::Activations act)
154{
155 activation(act);
156}
157
158void Software::enableUpdate(
159 const std::set<RequestedApplyTimes>& allowedApplyTimes)
160{
161 if (updateIntf != nullptr)
162 {
163 error("[Software] update of {OBJPATH} has already been enabled",
164 "OBJPATH", objectPath);
165 return;
166 }
167
168 debug(
169 "[Software] enabling update of {OBJPATH} (adding the update interface)",
170 "OBJPATH", objectPath);
171
172 updateIntf = std::make_unique<SoftwareUpdate>(ctx, objectPath.str.c_str(),
173 *this, allowedApplyTimes);
174}