xref: /openbmc/phosphor-bmc-code-mgmt/common/src/software.cpp (revision ccec7c673fc17f1d94f9514464ab75c4fe93a782)
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