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
Software(sdbusplus::async::context & ctx,Device & parent)22 Software::Software(sdbusplus::async::context& ctx, Device& parent) :
23 Software(ctx, parent, getRandomSoftwareId(parent))
24 {}
25
Software(sdbusplus::async::context & ctx,Device & parent,const std::string & swid)26 Software::Software(sdbusplus::async::context& ctx, Device& parent,
27 const std::string& swid) :
28 SoftwareActivation(ctx, (baseObjPathSoftware + swid).c_str(),
29 Activation::properties_t{Activations::NotReady,
30 RequestedActivations::None}),
31 parentDevice(parent), swid(swid), objectPath(baseObjPathSoftware + swid),
32 ctx(ctx)
33 {
34 std::string objPath = baseObjPathSoftware + swid;
35
36 emit_added();
37
38 debug("{SWID}: created dbus interfaces on path {OBJPATH}", "SWID", swid,
39 "OBJPATH", objPath);
40 };
41
getRandomId()42 long int Software::getRandomId()
43 {
44 struct timespec ts;
45 clock_gettime(CLOCK_REALTIME, &ts);
46 unsigned int seed = ts.tv_nsec ^ getpid();
47 srandom(seed);
48 return random() % 10000;
49 }
50
getRandomSoftwareId(Device & parent)51 std::string Software::getRandomSoftwareId(Device& parent)
52 {
53 return std::format("{}_{}", parent.config.configName, getRandomId());
54 }
55
createInventoryAssociations(bool isRunning)56 sdbusplus::async::task<> Software::createInventoryAssociations(bool isRunning)
57 {
58 debug("{SWID}: setting association definitions", "SWID", swid);
59
60 std::string endpoint = "";
61
62 try
63 {
64 endpoint = co_await parentDevice.config.getInventoryItemObjectPath(ctx);
65 }
66 catch (std::exception& e)
67 {
68 error("Failed to create association with {ERROR}", "ERROR", e.what());
69 co_return;
70 }
71
72 if (endpoint.empty())
73 {
74 co_return;
75 }
76
77 createInventoryAssociation(isRunning, endpoint);
78 }
79
createInventoryAssociation(bool isRunning,std::string objectPath)80 void Software::createInventoryAssociation(bool isRunning,
81 std::string objectPath)
82 {
83 std::vector<std::tuple<std::string, std::string, std::string>> assocs;
84
85 if (isRunning)
86 {
87 debug("{SWID}: creating 'running' association to {OBJPATH}", "SWID",
88 swid, "OBJPATH", objectPath);
89 std::tuple<std::string, std::string, std::string> assocRunning = {
90 "running", "ran_on", objectPath};
91 assocs.push_back(assocRunning);
92 }
93 else
94 {
95 debug("{SWID}: creating 'activating' association to {OBJPATH}", "SWID",
96 swid, "OBJPATH", objectPath);
97 std::tuple<std::string, std::string, std::string> assocActivating = {
98 "activating", "activated_on", objectPath};
99 assocs.push_back(assocActivating);
100 }
101
102 if (associationDefinitions)
103 {
104 associationDefinitions->associations(assocs);
105 }
106 else
107 {
108 associationDefinitions =
109 std::make_unique<SoftwareAssociationDefinitions>(
110 ctx, Software::objectPath.str.c_str(),
111 SoftwareAssociationDefinitions::properties_t{assocs});
112 associationDefinitions->emit_added();
113 }
114 }
115
setVersion(const std::string & versionStr,SoftwareVersion::VersionPurpose versionPurpose)116 void Software::setVersion(const std::string& versionStr,
117 SoftwareVersion::VersionPurpose versionPurpose)
118 {
119 debug("{SWID}: set version {VERSION}", "SWID", swid, "VERSION", versionStr);
120
121 if (!version)
122 {
123 version = std::make_unique<SoftwareVersion>(
124 ctx, objectPath.str.c_str(),
125 SoftwareVersion::properties_t{versionStr, versionPurpose});
126 version->emit_added();
127 return;
128 }
129
130 version->version(versionStr);
131 version->purpose(versionPurpose);
132 }
133
getPurpose()134 std::optional<SoftwareVersion::VersionPurpose> Software::getPurpose()
135 {
136 if (!version)
137 {
138 return std::nullopt;
139 }
140 return version->purpose();
141 }
142
setActivationBlocksTransition(bool enabled)143 void Software::setActivationBlocksTransition(bool enabled)
144 {
145 if (!enabled)
146 {
147 activationBlocksTransition = nullptr;
148 return;
149 }
150
151 std::string path = objectPath;
152 activationBlocksTransition =
153 std::make_unique<SoftwareActivationBlocksTransition>(ctx, path.c_str());
154
155 activationBlocksTransition->emit_added();
156 }
157
setActivation(SoftwareActivation::Activations act)158 void Software::setActivation(SoftwareActivation::Activations act)
159 {
160 activation(act);
161 }
162
enableUpdate(const std::set<RequestedApplyTimes> & allowedApplyTimes)163 void Software::enableUpdate(
164 const std::set<RequestedApplyTimes>& allowedApplyTimes)
165 {
166 if (updateIntf != nullptr)
167 {
168 error("[Software] update of {OBJPATH} has already been enabled",
169 "OBJPATH", objectPath);
170 return;
171 }
172
173 debug(
174 "[Software] enabling update of {OBJPATH} (adding the update interface)",
175 "OBJPATH", objectPath);
176
177 updateIntf = std::make_unique<SoftwareUpdate>(ctx, objectPath.str.c_str(),
178 *this, allowedApplyTimes);
179 }
180