blob: faa377a2a3eb0bd7b15f7d7a7e97e1a4ef45bf13 [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
Alexander Hansenccec7c62025-02-21 17:17:45 +0100130 if (!version)
Alexander Hansencc372352025-01-14 14:15:39 +0100131 {
Alexander Hansenccec7c62025-02-21 17:17:45 +0100132 version =
133 std::make_unique<SoftwareVersion>(ctx, objectPath.str.c_str());
Alexander Hansencc372352025-01-14 14:15:39 +0100134 }
135
Alexander Hansencc372352025-01-14 14:15:39 +0100136 version->version(versionStr);
137}
138
139void Software::setActivationBlocksTransition(bool enabled)
140{
141 if (!enabled)
142 {
143 activationBlocksTransition = nullptr;
144 return;
145 }
146
147 std::string path = objectPath;
148 activationBlocksTransition =
149 std::make_unique<SoftwareActivationBlocksTransition>(ctx, path.c_str());
150}
151
152void Software::setActivation(SoftwareActivation::Activations act)
153{
154 activation(act);
155}
156
157void Software::enableUpdate(
158 const std::set<RequestedApplyTimes>& allowedApplyTimes)
159{
160 if (updateIntf != nullptr)
161 {
162 error("[Software] update of {OBJPATH} has already been enabled",
163 "OBJPATH", objectPath);
164 return;
165 }
166
167 debug(
168 "[Software] enabling update of {OBJPATH} (adding the update interface)",
169 "OBJPATH", objectPath);
170
171 updateIntf = std::make_unique<SoftwareUpdate>(ctx, objectPath.str.c_str(),
172 *this, allowedApplyTimes);
173}