1*cab87e9cSJagpal Singh Gill #include "update_manager.hpp" 2*cab87e9cSJagpal Singh Gill 3*cab87e9cSJagpal Singh Gill #include "item_updater.hpp" 4*cab87e9cSJagpal Singh Gill #include "software_utils.hpp" 5*cab87e9cSJagpal Singh Gill #include "version.hpp" 6*cab87e9cSJagpal Singh Gill 7*cab87e9cSJagpal Singh Gill #include <phosphor-logging/elog-errors.hpp> 8*cab87e9cSJagpal Singh Gill #include <phosphor-logging/elog.hpp> 9*cab87e9cSJagpal Singh Gill #include <phosphor-logging/lg2.hpp> 10*cab87e9cSJagpal Singh Gill #include <sdbusplus/async.hpp> 11*cab87e9cSJagpal Singh Gill #include <xyz/openbmc_project/Common/error.hpp> 12*cab87e9cSJagpal Singh Gill #include <xyz/openbmc_project/Software/Image/error.hpp> 13*cab87e9cSJagpal Singh Gill 14*cab87e9cSJagpal Singh Gill #include <filesystem> 15*cab87e9cSJagpal Singh Gill 16*cab87e9cSJagpal Singh Gill PHOSPHOR_LOG2_USING; 17*cab87e9cSJagpal Singh Gill 18*cab87e9cSJagpal Singh Gill namespace phosphor::software::update 19*cab87e9cSJagpal Singh Gill { 20*cab87e9cSJagpal Singh Gill 21*cab87e9cSJagpal Singh Gill namespace fs = std::filesystem; 22*cab87e9cSJagpal Singh Gill namespace softwareUtils = phosphor::software::utils; 23*cab87e9cSJagpal Singh Gill namespace SoftwareLogging = phosphor::logging::xyz::openbmc_project::software; 24*cab87e9cSJagpal Singh Gill namespace SoftwareErrors = 25*cab87e9cSJagpal Singh Gill sdbusplus::error::xyz::openbmc_project::software::image; 26*cab87e9cSJagpal Singh Gill using namespace phosphor::logging; 27*cab87e9cSJagpal Singh Gill using Version = phosphor::software::manager::Version; 28*cab87e9cSJagpal Singh Gill using ActivationIntf = phosphor::software::updater::Activation; 29*cab87e9cSJagpal Singh Gill using ManifestFail = SoftwareLogging::image::ManifestFileFailure; 30*cab87e9cSJagpal Singh Gill using UnTarFail = SoftwareLogging::image::UnTarFailure; 31*cab87e9cSJagpal Singh Gill using InternalFail = SoftwareLogging::image::InternalFailure; 32*cab87e9cSJagpal Singh Gill using ImageFail = SoftwareLogging::image::ImageFailure; 33*cab87e9cSJagpal Singh Gill 34*cab87e9cSJagpal Singh Gill void Manager::processImageFailed(sdbusplus::message::unix_fd image, 35*cab87e9cSJagpal Singh Gill std::string& id) 36*cab87e9cSJagpal Singh Gill { 37*cab87e9cSJagpal Singh Gill close(image); 38*cab87e9cSJagpal Singh Gill updateInProgress = false; 39*cab87e9cSJagpal Singh Gill itemUpdater.updateActivationStatus(id, 40*cab87e9cSJagpal Singh Gill ActivationIntf::Activations::Invalid); 41*cab87e9cSJagpal Singh Gill } 42*cab87e9cSJagpal Singh Gill 43*cab87e9cSJagpal Singh Gill bool verifyImagePurpose(Version::VersionPurpose purpose, 44*cab87e9cSJagpal Singh Gill ItemUpdaterIntf::UpdaterType type) 45*cab87e9cSJagpal Singh Gill { 46*cab87e9cSJagpal Singh Gill if (purpose == Version::VersionPurpose::Host) 47*cab87e9cSJagpal Singh Gill { 48*cab87e9cSJagpal Singh Gill return (type == ItemUpdaterIntf::UpdaterType::BIOS || 49*cab87e9cSJagpal Singh Gill type == ItemUpdaterIntf::UpdaterType::ALL); 50*cab87e9cSJagpal Singh Gill } 51*cab87e9cSJagpal Singh Gill return true; 52*cab87e9cSJagpal Singh Gill } 53*cab87e9cSJagpal Singh Gill 54*cab87e9cSJagpal Singh Gill // NOLINTNEXTLINE(readability-static-accessed-through-instance) 55*cab87e9cSJagpal Singh Gill auto Manager::processImage(sdbusplus::message::unix_fd image, 56*cab87e9cSJagpal Singh Gill ApplyTimeIntf::RequestedApplyTimes applyTime, 57*cab87e9cSJagpal Singh Gill std::string id, std::string objPath) 58*cab87e9cSJagpal Singh Gill -> sdbusplus::async::task<> 59*cab87e9cSJagpal Singh Gill { 60*cab87e9cSJagpal Singh Gill debug("Processing image {FD}", "FD", image.fd); 61*cab87e9cSJagpal Singh Gill fs::path tmpDirPath(std::string{IMG_UPLOAD_DIR}); 62*cab87e9cSJagpal Singh Gill tmpDirPath /= "imageXXXXXX"; 63*cab87e9cSJagpal Singh Gill auto tmpDir = tmpDirPath.string(); 64*cab87e9cSJagpal Singh Gill // Create a tmp dir to copy tarball. 65*cab87e9cSJagpal Singh Gill if (!mkdtemp(tmpDir.data())) 66*cab87e9cSJagpal Singh Gill { 67*cab87e9cSJagpal Singh Gill error("Error ({ERRNO}) occurred during mkdtemp", "ERRNO", errno); 68*cab87e9cSJagpal Singh Gill processImageFailed(image, id); 69*cab87e9cSJagpal Singh Gill report<SoftwareErrors::InternalFailure>(InternalFail::FAIL("mkdtemp")); 70*cab87e9cSJagpal Singh Gill co_return; 71*cab87e9cSJagpal Singh Gill } 72*cab87e9cSJagpal Singh Gill 73*cab87e9cSJagpal Singh Gill std::error_code ec; 74*cab87e9cSJagpal Singh Gill tmpDirPath = tmpDir; 75*cab87e9cSJagpal Singh Gill softwareUtils::RemovablePath tmpDirToRemove(tmpDirPath); 76*cab87e9cSJagpal Singh Gill 77*cab87e9cSJagpal Singh Gill // Untar tarball into the tmp dir 78*cab87e9cSJagpal Singh Gill if (!softwareUtils::unTar(image, tmpDirPath.string())) 79*cab87e9cSJagpal Singh Gill { 80*cab87e9cSJagpal Singh Gill error("Error occurred during untar"); 81*cab87e9cSJagpal Singh Gill processImageFailed(image, id); 82*cab87e9cSJagpal Singh Gill report<SoftwareErrors::UnTarFailure>( 83*cab87e9cSJagpal Singh Gill UnTarFail::PATH(tmpDirPath.c_str())); 84*cab87e9cSJagpal Singh Gill co_return; 85*cab87e9cSJagpal Singh Gill } 86*cab87e9cSJagpal Singh Gill 87*cab87e9cSJagpal Singh Gill fs::path manifestPath = tmpDirPath; 88*cab87e9cSJagpal Singh Gill manifestPath /= MANIFEST_FILE_NAME; 89*cab87e9cSJagpal Singh Gill 90*cab87e9cSJagpal Singh Gill // Get version 91*cab87e9cSJagpal Singh Gill auto version = Version::getValue(manifestPath.string(), "version"); 92*cab87e9cSJagpal Singh Gill if (version.empty()) 93*cab87e9cSJagpal Singh Gill { 94*cab87e9cSJagpal Singh Gill error("Unable to read version from manifest file"); 95*cab87e9cSJagpal Singh Gill processImageFailed(image, id); 96*cab87e9cSJagpal Singh Gill report<SoftwareErrors::ManifestFileFailure>( 97*cab87e9cSJagpal Singh Gill ManifestFail::PATH(manifestPath.string().c_str())); 98*cab87e9cSJagpal Singh Gill co_return; 99*cab87e9cSJagpal Singh Gill } 100*cab87e9cSJagpal Singh Gill 101*cab87e9cSJagpal Singh Gill // Get running machine name 102*cab87e9cSJagpal Singh Gill std::string currMachine = Version::getBMCMachine(OS_RELEASE_FILE); 103*cab87e9cSJagpal Singh Gill if (currMachine.empty()) 104*cab87e9cSJagpal Singh Gill { 105*cab87e9cSJagpal Singh Gill auto path = OS_RELEASE_FILE; 106*cab87e9cSJagpal Singh Gill error("Failed to read machine name from osRelease: {PATH}", "PATH", 107*cab87e9cSJagpal Singh Gill path); 108*cab87e9cSJagpal Singh Gill processImageFailed(image, id); 109*cab87e9cSJagpal Singh Gill report<SoftwareErrors::ImageFailure>( 110*cab87e9cSJagpal Singh Gill ImageFail::FAIL("Failed to read machine name"), 111*cab87e9cSJagpal Singh Gill ImageFail::PATH(path)); 112*cab87e9cSJagpal Singh Gill co_return; 113*cab87e9cSJagpal Singh Gill } 114*cab87e9cSJagpal Singh Gill 115*cab87e9cSJagpal Singh Gill // Get machine name for image to be upgraded 116*cab87e9cSJagpal Singh Gill std::string machineStr = 117*cab87e9cSJagpal Singh Gill Version::getValue(manifestPath.string(), "MachineName"); 118*cab87e9cSJagpal Singh Gill if (!machineStr.empty()) 119*cab87e9cSJagpal Singh Gill { 120*cab87e9cSJagpal Singh Gill if (machineStr != currMachine) 121*cab87e9cSJagpal Singh Gill { 122*cab87e9cSJagpal Singh Gill error( 123*cab87e9cSJagpal Singh Gill "BMC upgrade: Machine name doesn't match: {CURRENT_MACHINE} vs {NEW_MACHINE}", 124*cab87e9cSJagpal Singh Gill "CURRENT_MACHINE", currMachine, "NEW_MACHINE", machineStr); 125*cab87e9cSJagpal Singh Gill processImageFailed(image, id); 126*cab87e9cSJagpal Singh Gill report<SoftwareErrors::ImageFailure>( 127*cab87e9cSJagpal Singh Gill ImageFail::FAIL("Machine name does not match"), 128*cab87e9cSJagpal Singh Gill ImageFail::PATH(manifestPath.string().c_str())); 129*cab87e9cSJagpal Singh Gill co_return; 130*cab87e9cSJagpal Singh Gill } 131*cab87e9cSJagpal Singh Gill } 132*cab87e9cSJagpal Singh Gill else 133*cab87e9cSJagpal Singh Gill { 134*cab87e9cSJagpal Singh Gill warning("No machine name in Manifest file"); 135*cab87e9cSJagpal Singh Gill report<SoftwareErrors::ImageFailure>( 136*cab87e9cSJagpal Singh Gill ImageFail::FAIL("MANIFEST is missing machine name"), 137*cab87e9cSJagpal Singh Gill ImageFail::PATH(manifestPath.string().c_str())); 138*cab87e9cSJagpal Singh Gill } 139*cab87e9cSJagpal Singh Gill 140*cab87e9cSJagpal Singh Gill // Get purpose 141*cab87e9cSJagpal Singh Gill auto purposeString = Version::getValue(manifestPath.string(), "purpose"); 142*cab87e9cSJagpal Singh Gill if (purposeString.empty()) 143*cab87e9cSJagpal Singh Gill { 144*cab87e9cSJagpal Singh Gill error("Unable to read purpose from manifest file"); 145*cab87e9cSJagpal Singh Gill processImageFailed(image, id); 146*cab87e9cSJagpal Singh Gill report<SoftwareErrors::ManifestFileFailure>( 147*cab87e9cSJagpal Singh Gill ManifestFail::PATH(manifestPath.string().c_str())); 148*cab87e9cSJagpal Singh Gill co_return; 149*cab87e9cSJagpal Singh Gill } 150*cab87e9cSJagpal Singh Gill auto convertedPurpose = 151*cab87e9cSJagpal Singh Gill sdbusplus::message::convert_from_string<Version::VersionPurpose>( 152*cab87e9cSJagpal Singh Gill purposeString); 153*cab87e9cSJagpal Singh Gill if (!convertedPurpose) 154*cab87e9cSJagpal Singh Gill { 155*cab87e9cSJagpal Singh Gill warning( 156*cab87e9cSJagpal Singh Gill "Failed to convert manifest purpose ({PURPOSE}) to enum; setting to Unknown.", 157*cab87e9cSJagpal Singh Gill "PURPOSE", purposeString); 158*cab87e9cSJagpal Singh Gill } 159*cab87e9cSJagpal Singh Gill auto purpose = convertedPurpose.value_or(Version::VersionPurpose::Unknown); 160*cab87e9cSJagpal Singh Gill 161*cab87e9cSJagpal Singh Gill if (!verifyImagePurpose(purpose, itemUpdater.type)) 162*cab87e9cSJagpal Singh Gill { 163*cab87e9cSJagpal Singh Gill error("Purpose ({PURPOSE}) is not supported", "PURPOSE", purpose); 164*cab87e9cSJagpal Singh Gill processImageFailed(image, id); 165*cab87e9cSJagpal Singh Gill report<SoftwareErrors::ImageFailure>( 166*cab87e9cSJagpal Singh Gill ImageFail::FAIL("Purpose is not supported"), 167*cab87e9cSJagpal Singh Gill ImageFail::PATH(manifestPath.string().c_str())); 168*cab87e9cSJagpal Singh Gill co_return; 169*cab87e9cSJagpal Singh Gill } 170*cab87e9cSJagpal Singh Gill 171*cab87e9cSJagpal Singh Gill // Get ExtendedVersion 172*cab87e9cSJagpal Singh Gill std::string extendedVersion = 173*cab87e9cSJagpal Singh Gill Version::getValue(manifestPath.string(), "ExtendedVersion"); 174*cab87e9cSJagpal Singh Gill 175*cab87e9cSJagpal Singh Gill // Get CompatibleNames 176*cab87e9cSJagpal Singh Gill std::vector<std::string> compatibleNames = 177*cab87e9cSJagpal Singh Gill Version::getRepeatedValues(manifestPath.string(), "CompatibleName"); 178*cab87e9cSJagpal Singh Gill 179*cab87e9cSJagpal Singh Gill // Rename IMG_UPLOAD_DIR/imageXXXXXX to IMG_UPLOAD_DIR/id as Manifest 180*cab87e9cSJagpal Singh Gill // parsing succedded. 181*cab87e9cSJagpal Singh Gill fs::path imageDirPath = std::string{IMG_UPLOAD_DIR}; 182*cab87e9cSJagpal Singh Gill imageDirPath /= id; 183*cab87e9cSJagpal Singh Gill fs::rename(tmpDirPath, imageDirPath, ec); 184*cab87e9cSJagpal Singh Gill tmpDirToRemove.path.clear(); 185*cab87e9cSJagpal Singh Gill 186*cab87e9cSJagpal Singh Gill auto filePath = imageDirPath.string(); 187*cab87e9cSJagpal Singh Gill // Create Version object 188*cab87e9cSJagpal Singh Gill auto state = itemUpdater.verifyAndCreateObjects( 189*cab87e9cSJagpal Singh Gill id, objPath, version, purpose, extendedVersion, filePath, 190*cab87e9cSJagpal Singh Gill compatibleNames); 191*cab87e9cSJagpal Singh Gill if (state != ActivationIntf::Activations::Ready) 192*cab87e9cSJagpal Singh Gill { 193*cab87e9cSJagpal Singh Gill error("Software image is invalid"); 194*cab87e9cSJagpal Singh Gill processImageFailed(image, id); 195*cab87e9cSJagpal Singh Gill report<SoftwareErrors::ImageFailure>( 196*cab87e9cSJagpal Singh Gill ImageFail::FAIL("Image is invalid"), 197*cab87e9cSJagpal Singh Gill ImageFail::PATH(filePath.c_str())); 198*cab87e9cSJagpal Singh Gill co_return; 199*cab87e9cSJagpal Singh Gill } 200*cab87e9cSJagpal Singh Gill if (applyTime == ApplyTimeIntf::RequestedApplyTimes::Immediate || 201*cab87e9cSJagpal Singh Gill applyTime == ApplyTimeIntf::RequestedApplyTimes::OnReset) 202*cab87e9cSJagpal Singh Gill { 203*cab87e9cSJagpal Singh Gill itemUpdater.requestActivation(id); 204*cab87e9cSJagpal Singh Gill } 205*cab87e9cSJagpal Singh Gill 206*cab87e9cSJagpal Singh Gill updateInProgress = false; 207*cab87e9cSJagpal Singh Gill close(image); 208*cab87e9cSJagpal Singh Gill co_return; 209*cab87e9cSJagpal Singh Gill } 210*cab87e9cSJagpal Singh Gill 211*cab87e9cSJagpal Singh Gill sdbusplus::message::object_path 212*cab87e9cSJagpal Singh Gill Manager::startUpdate(sdbusplus::message::unix_fd image, 213*cab87e9cSJagpal Singh Gill ApplyTimeIntf::RequestedApplyTimes applyTime) 214*cab87e9cSJagpal Singh Gill { 215*cab87e9cSJagpal Singh Gill info("Starting update for image {FD}", "FD", static_cast<int>(image)); 216*cab87e9cSJagpal Singh Gill using sdbusplus::xyz::openbmc_project::Common::Error::Unavailable; 217*cab87e9cSJagpal Singh Gill if (updateInProgress) 218*cab87e9cSJagpal Singh Gill { 219*cab87e9cSJagpal Singh Gill error("Failed to start as update is already in progress"); 220*cab87e9cSJagpal Singh Gill report<Unavailable>(); 221*cab87e9cSJagpal Singh Gill return sdbusplus::message::object_path(); 222*cab87e9cSJagpal Singh Gill } 223*cab87e9cSJagpal Singh Gill updateInProgress = true; 224*cab87e9cSJagpal Singh Gill 225*cab87e9cSJagpal Singh Gill auto id = Version::getId(std::to_string(randomGen())); 226*cab87e9cSJagpal Singh Gill auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id; 227*cab87e9cSJagpal Singh Gill 228*cab87e9cSJagpal Singh Gill // Create Activation Object 229*cab87e9cSJagpal Singh Gill itemUpdater.createActivationWithApplyTime(id, objPath, applyTime); 230*cab87e9cSJagpal Singh Gill 231*cab87e9cSJagpal Singh Gill int newFd = dup(image); 232*cab87e9cSJagpal Singh Gill ctx.spawn(processImage(newFd, applyTime, id, objPath)); 233*cab87e9cSJagpal Singh Gill 234*cab87e9cSJagpal Singh Gill return sdbusplus::message::object_path(objPath); 235*cab87e9cSJagpal Singh Gill } 236*cab87e9cSJagpal Singh Gill 237*cab87e9cSJagpal Singh Gill } // namespace phosphor::software::update 238