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 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 emit_added(); 33 } 34 35 SoftwareUpdate::~SoftwareUpdate() 36 { 37 emit_removed(); 38 } 39 40 auto SoftwareUpdate::method_call(start_update_t /*unused*/, auto image, 41 auto applyTime) 42 -> sdbusplus::async::task<start_update_t::return_type> 43 { 44 debug("Requesting Image update with {FD}", "FD", image.fd); 45 46 Device& device = software.parentDevice; 47 48 if (device.updateInProgress) 49 { 50 error("An update is already in progress, cannot update."); 51 report<Unavailable>(); 52 co_return sdbusplus::message::object_path(); 53 } 54 55 device.updateInProgress = true; 56 57 // check if the apply time is allowed by our device 58 if (!allowedApplyTimes.contains(applyTime)) 59 { 60 error( 61 "the selected apply time {APPLYTIME} is not allowed by the device", 62 "APPLYTIME", applyTime); 63 device.updateInProgress = false; 64 report<Unavailable>(); 65 co_return sdbusplus::message::object_path(); 66 } 67 68 debug("started asynchronous update with fd {FD}", "FD", image.fd); 69 70 int imageDup = dup(image.fd); 71 72 if (imageDup < 0) 73 { 74 error("ERROR calling dup on fd: {ERR}", "ERR", strerror(errno)); 75 device.updateInProgress = false; 76 co_return software.objectPath; 77 } 78 79 debug("starting async update with FD: {FD}\n", "FD", imageDup); 80 81 std::unique_ptr<Software> softwareInstance = 82 std::make_unique<Software>(ctx, device); 83 84 softwareInstance->setActivation(ActivationInterface::Activations::NotReady); 85 86 std::string newObjPath = softwareInstance->objectPath; 87 88 ctx.spawn( 89 [](Device& device, int imageDup, RequestedApplyTimes applyTime, 90 std::unique_ptr<Software> swupdate) -> sdbusplus::async::task<> { 91 co_await device.startUpdateAsync(imageDup, applyTime, 92 std::move(swupdate)); 93 device.updateInProgress = false; 94 close(imageDup); 95 co_return; 96 }(device, imageDup, applyTime, std::move(softwareInstance))); 97 98 // We need the object path for the new software here. 99 // It must be the same as constructed during the update process. 100 // This is so that bmcweb and redfish clients can keep track of the update 101 // process. 102 co_return newObjPath; 103 } 104 105 auto SoftwareUpdate::get_property(allowed_apply_times_t /*unused*/) const 106 { 107 return allowedApplyTimes; 108 } 109