1 #include "software_update.hpp"
2
3 #include "device.hpp"
4 #include "software.hpp"
5
6 #include <phosphor-logging/elog-errors.hpp>
7 #include <phosphor-logging/elog.hpp>
8 #include <phosphor-logging/lg2.hpp>
9 #include <sdbusplus/async/context.hpp>
10 #include <xyz/openbmc_project/Software/Update/aserver.hpp>
11
12 PHOSPHOR_LOG2_USING;
13
14 using Unavailable = sdbusplus::xyz::openbmc_project::Common::Error::Unavailable;
15
16 using namespace phosphor::logging;
17 using namespace phosphor::software::update;
18 using namespace phosphor::software::device;
19 using namespace phosphor::software;
20
21 namespace SoftwareLogging = phosphor::logging::xyz::openbmc_project::software;
22 namespace SoftwareErrors =
23 sdbusplus::error::xyz::openbmc_project::software::image;
24
SoftwareUpdate(sdbusplus::async::context & ctx,const char * path,Software & software,const std::set<RequestedApplyTimes> & allowedApplyTimes)25 SoftwareUpdate::SoftwareUpdate(
26 sdbusplus::async::context& ctx, const char* path, Software& software,
27 const std::set<RequestedApplyTimes>& allowedApplyTimes) :
28 sdbusplus::aserver::xyz::openbmc_project::software::Update<SoftwareUpdate>(
29 ctx, path),
30 software(software), allowedApplyTimes(allowedApplyTimes)
31 {}
32
method_call(start_update_t,auto image,auto applyTime)33 auto SoftwareUpdate::method_call(start_update_t /*unused*/, auto image,
34 auto applyTime)
35 -> sdbusplus::async::task<start_update_t::return_type>
36 {
37 debug("Requesting Image update with {FD}", "FD", image.fd);
38
39 Device& device = software.parentDevice;
40
41 if (device.updateInProgress)
42 {
43 error("An update is already in progress, cannot update.");
44 report<Unavailable>();
45 co_return sdbusplus::message::object_path();
46 }
47
48 device.updateInProgress = true;
49
50 // check if the apply time is allowed by our device
51 if (!allowedApplyTimes.contains(applyTime))
52 {
53 error(
54 "the selected apply time {APPLYTIME} is not allowed by the device",
55 "APPLYTIME", applyTime);
56 device.updateInProgress = false;
57 report<Unavailable>();
58 co_return sdbusplus::message::object_path();
59 }
60
61 debug("started asynchronous update with fd {FD}", "FD", image.fd);
62
63 int imageDup = dup(image.fd);
64
65 if (imageDup < 0)
66 {
67 error("ERROR calling dup on fd: {ERR}", "ERR", strerror(errno));
68 device.updateInProgress = false;
69 co_return software.objectPath;
70 }
71
72 debug("starting async update with FD: {FD}\n", "FD", imageDup);
73
74 std::unique_ptr<Software> softwareInstance =
75 std::make_unique<Software>(ctx, device);
76
77 softwareInstance->setActivation(ActivationInterface::Activations::NotReady);
78
79 std::string newObjPath = softwareInstance->objectPath;
80
81 // NOLINTBEGIN(readability-static-accessed-through-instance)
82 ctx.spawn(
83 [](Device& device, int imageDup, RequestedApplyTimes applyTime,
84 std::unique_ptr<Software> swupdate) -> sdbusplus::async::task<> {
85 co_await device.startUpdateAsync(imageDup, applyTime,
86 std::move(swupdate));
87 device.updateInProgress = false;
88 close(imageDup);
89 co_return;
90 }(device, imageDup, applyTime, std::move(softwareInstance)));
91 // NOLINTEND
92
93 // We need the object path for the new software here.
94 // It must be the same as constructed during the update process.
95 // This is so that bmcweb and redfish clients can keep track of the update
96 // process.
97 co_return newObjPath;
98 }
99
get_property(allowed_apply_times_t) const100 auto SoftwareUpdate::get_property(allowed_apply_times_t /*unused*/) const
101 {
102 return allowedApplyTimes;
103 }
104