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
SoftwareActivationProgress(sdbusplus::async::context & ctx,const char * objPath)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
setProgress(int progressArg)32 void SoftwareActivationProgress::setProgress(int progressArg)
33 {
34 progress(progressArg);
35 }
36
Software(sdbusplus::async::context & ctx,Device & parent)37 Software::Software(sdbusplus::async::context& ctx, Device& parent) :
38 Software(ctx, parent, getRandomSoftwareId(parent))
39 {}
40
Software(sdbusplus::async::context & ctx,Device & parent,const std::string & swid)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
getRandomId()58 static 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
getRandomSoftwareId(Device & parent)67 std::string Software::getRandomSoftwareId(Device& parent)
68 {
69 return std::format("{}_{}", parent.config.configName, getRandomId());
70 }
71
72 // NOLINTBEGIN(readability-static-accessed-through-instance)
createInventoryAssociations(bool isRunning)73 sdbusplus::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
setVersion(const std::string & versionStr)126 void Software::setVersion(const std::string& versionStr)
127 {
128 debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr);
129
130 if (!version)
131 {
132 version =
133 std::make_unique<SoftwareVersion>(ctx, objectPath.str.c_str());
134 }
135
136 version->version(versionStr);
137 }
138
setActivationBlocksTransition(bool enabled)139 void 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
setActivation(SoftwareActivation::Activations act)152 void Software::setActivation(SoftwareActivation::Activations act)
153 {
154 activation(act);
155 }
156
enableUpdate(const std::set<RequestedApplyTimes> & allowedApplyTimes)157 void 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 }
174