blob: 26a4602c23fba97ef2a771fb11b1438988696f3e [file] [log] [blame]
#include "software_update.hpp"
#include "device.hpp"
#include "software.hpp"
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/async/context.hpp>
#include <xyz/openbmc_project/Software/Update/aserver.hpp>
PHOSPHOR_LOG2_USING;
using Unavailable = sdbusplus::xyz::openbmc_project::Common::Error::Unavailable;
using namespace phosphor::logging;
using namespace phosphor::software::update;
using namespace phosphor::software::device;
using namespace phosphor::software;
namespace SoftwareLogging = phosphor::logging::xyz::openbmc_project::software;
namespace SoftwareErrors =
sdbusplus::error::xyz::openbmc_project::software::image;
SoftwareUpdate::SoftwareUpdate(
sdbusplus::async::context& ctx, const char* path, Software& software,
const std::set<RequestedApplyTimes>& allowedApplyTimes) :
sdbusplus::aserver::xyz::openbmc_project::software::Update<SoftwareUpdate>(
ctx, path),
software(software), allowedApplyTimes(allowedApplyTimes)
{}
auto SoftwareUpdate::method_call(start_update_t /*unused*/, auto image,
auto applyTime)
-> sdbusplus::async::task<start_update_t::return_type>
{
debug("Requesting Image update with {FD}", "FD", image.fd);
Device& device = software.parentDevice;
if (device.updateInProgress)
{
error("An update is already in progress, cannot update.");
report<Unavailable>();
co_return sdbusplus::message::object_path();
}
device.updateInProgress = true;
// check if the apply time is allowed by our device
if (!allowedApplyTimes.contains(applyTime))
{
error(
"the selected apply time {APPLYTIME} is not allowed by the device",
"APPLYTIME", applyTime);
device.updateInProgress = false;
report<Unavailable>();
co_return sdbusplus::message::object_path();
}
debug("started asynchronous update with fd {FD}", "FD", image.fd);
int imageDup = dup(image.fd);
if (imageDup < 0)
{
error("ERROR calling dup on fd: {ERR}", "ERR", strerror(errno));
device.updateInProgress = false;
co_return software.objectPath;
}
debug("starting async update with FD: {FD}\n", "FD", imageDup);
std::unique_ptr<Software> softwareInstance =
std::make_unique<Software>(ctx, device);
softwareInstance->setActivation(ActivationInterface::Activations::NotReady);
std::string newObjPath = softwareInstance->objectPath;
// NOLINTBEGIN(readability-static-accessed-through-instance)
ctx.spawn(
[](Device& device, int imageDup, RequestedApplyTimes applyTime,
std::unique_ptr<Software> swupdate) -> sdbusplus::async::task<> {
co_await device.startUpdateAsync(imageDup, applyTime,
std::move(swupdate));
device.updateInProgress = false;
close(imageDup);
co_return;
}(device, imageDup, applyTime, std::move(softwareInstance)));
// NOLINTEND
// We need the object path for the new software here.
// It must be the same as constructed during the update process.
// This is so that bmcweb and redfish clients can keep track of the update
// process.
co_return newObjPath;
}
auto SoftwareUpdate::get_property(allowed_apply_times_t /*unused*/) const
{
return allowedApplyTimes;
}