From 6bc6eccc34e1406fdb9d9d0f0fe091c2dcb06cb5 Mon Sep 17 00:00:00 2001 From: Roman Kubiak Date: Wed, 3 Mar 2021 11:49:41 +0100 Subject: [PATCH] [EGD-5565] Fix update process on new lf filesystem These changes are needed for update to work with new LFS fileystem, also minor bugfixes are included. --- .../service-desktop/WorkerDesktop.cpp | 2 +- .../endpoints/update/UpdateEndpoint.cpp | 10 +- .../endpoints/update/UpdateMuditaOS.cpp | 107 +++++++++++------- .../endpoints/update/UpdateMuditaOS.hpp | 3 +- .../service-desktop/parser/ParserUtils.hpp | 1 + module-vfs/src/purefs/filesystem_paths.cpp | 2 +- test/pytest/service-desktop/test_update.py | 1 + 7 files changed, 79 insertions(+), 47 deletions(-) diff --git a/module-services/service-desktop/WorkerDesktop.cpp b/module-services/service-desktop/WorkerDesktop.cpp index d474f33205e8c430b4cd97b8ab5d1423a9182f2e..3348201f1d96de0e1e09cff62deaa8b423128eb7 100644 --- a/module-services/service-desktop/WorkerDesktop.cpp +++ b/module-services/service-desktop/WorkerDesktop.cpp @@ -184,7 +184,7 @@ void WorkerDesktop::stopTransfer(const TransferFailAction action) responseContext.setResponseBody(responseJson); // close the file descriptor - fclose(fileDes); + std::fclose(fileDes); // stop the timeout timer stopTransferTimer(); diff --git a/module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp b/module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp index bcb95a28152e2eb8a4b3b25224cd9ff2470876ea..33d02ee577c43cbeba9179eae933b90aa62d35dc 100644 --- a/module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp +++ b/module-services/service-desktop/endpoints/update/UpdateEndpoint.cpp @@ -74,6 +74,7 @@ auto UpdateEndpoint::run(Context &context) -> sys::ReturnCodes auto UpdateEndpoint::getUpdates(Context &context) -> sys::ReturnCodes { const auto updatesOSPath = purefs::dir::getUpdatesOSPath(); + std::error_code errorCode; struct DirectoryEntry { std::string fileName; @@ -85,8 +86,13 @@ auto UpdateEndpoint::getUpdates(Context &context) -> sys::ReturnCodes }; auto dirEntryVector = std::vector(); - for (const auto &p : fs::directory_iterator(updatesOSPath)) { - if (!p.is_directory() && p.path().c_str() == updateos::extension::update) { + for (const auto &p : fs::directory_iterator(updatesOSPath, errorCode)) { + if (errorCode) { + LOG_WARN("can't get directory contents for %s, \"%s\"", updatesOSPath.c_str(), errorCode.message().c_str()); + return sys::ReturnCodes::Failure; + } + + if (!p.is_directory() && p.path().extension() == updateos::extension::update) { dirEntryVector.push_back(DirectoryEntry{p.path().string(), static_cast(p.file_size())}); } } diff --git a/module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp b/module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp index d43e2be04e5a90f7b7ddff7e58e3dba4f53b8f4a..1ec6e153f4300effa5ea025c597973c6101b207c 100644 --- a/module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp +++ b/module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp @@ -95,7 +95,7 @@ updateos::UpdateError UpdateMuditaOS::runUpdate() informDebug("Preparing temp dir"); updateRunStatus.startTime = utils::time::getCurrentTimestamp().getTime(); - updateRunStatus.fromVersion = bootConfig.to_json(); + updateRunStatus.fromVersion = bootConfig.to_json()[boot::json::git_info]; versionInformation = UpdateMuditaOS::getVersionInfoFromFile(updateFile); auto currentOSVersion = bootConfig.os_version(); @@ -326,7 +326,7 @@ updateos::UpdateError UpdateMuditaOS::verifyVersion() } else { /* version comparison goes here */ - updateRunStatus.toVersion = targetVersionInfo; + updateRunStatus.toVersion = targetVersionInfo[boot::json::git_info]; const bool ret = bootConfig.version_compare(targetVersionInfo[boot::json::version_string].string_value(), bootConfig.os_version()); LOG_DEBUG("verifyVersion comparison result == %s", ret ? "true" : "false"); @@ -405,11 +405,11 @@ updateos::UpdateError UpdateMuditaOS::prepareRoot() try { std::filesystem::remove_all(previousOSPath.c_str()); } - catch (const std::filesystem::filesystem_error &e) { + catch (const std::filesystem::filesystem_error &fsError) { return informError(updateos::UpdateError::CantDeletePreviousOS, - "prepareRoot ff_deltree on %s caused an error %s", + "prepareRoot remove_all on %s caused an error %s", previousOSPath.c_str(), - e.what()); + fsError.what()); } if (std::filesystem::is_directory(purefs::dir::getPreviousOSPath().c_str())) { @@ -427,25 +427,27 @@ updateos::UpdateError UpdateMuditaOS::prepareRoot() try { std::filesystem::rename(currentOSPath.c_str(), previousOSPath.c_str()); } - catch (const std::filesystem::filesystem_error &e) { + catch (const std::filesystem::filesystem_error &fsError) { return informError(updateos::UpdateError::CantRenameCurrentToPrevious, "prepareRoot can't rename %s -> %s error %s", purefs::dir::getCurrentOSPath().c_str(), purefs::dir::getPreviousOSPath().c_str(), - e.what()); + fsError.what()); } // rename the temp directory to current (extracted update) - informDebug("prepareRoot rename: %s->%s", updateTempDirectory.c_str(), currentOSPath.c_str()); + informDebug("prepareRoot copy: %s->%s", updateTempDirectory.c_str(), currentOSPath.c_str()); try { + // std::filesystem::copy(updateTempDirectory.c_str(), currentOSPath.c_str(), + // std::filesystem::copy_options::recursive); std::filesystem::rename(updateTempDirectory.c_str(), currentOSPath.c_str()); } - catch (const std::filesystem::filesystem_error &e) { - return informError(updateos::UpdateError::CantRenameTempToCurrent, - "prepareRoot can't rename %s -> %s error %s", + catch (const std::filesystem::filesystem_error &fsError) { + return informError(updateos::UpdateError::CantCopyTempToCurrent, + "prepareRoot can't copy %s -> %s error %s", updateTempDirectory.c_str(), purefs::dir::getCurrentOSPath().c_str(), - e.what()); + fsError.what()); } // move the contents of /sys/current/user if it exists to /user @@ -473,13 +475,16 @@ updateos::UpdateError UpdateMuditaOS::updateBootJSON() std::fclose(fpCRC); } else { - return updateos::UpdateError::CantUpdateCRC32JSON; + return informError(updateos::UpdateError::CantUpdateCRC32JSON, + "Can't open %s for writing", + (bootJSONAbsoulte += boot::consts::ext_crc32).c_str()); } std::fclose(fp); } else { - return updateos::UpdateError::CantUpdateCRC32JSON; + return informError( + updateos::UpdateError::CantUpdateCRC32JSON, "Can't open %s for reading", bootJSONAbsoulte.c_str()); } informDebug("updateBootJSON no error"); @@ -548,14 +553,25 @@ bool UpdateMuditaOS::unpackFileToTemp(mtar_header_t &h, unsigned long *crc32) updateos::UpdateError UpdateMuditaOS::cleanupAfterUpdate() { - if (std::filesystem::is_directory(updateTempDirectory.c_str()) && - std::filesystem::remove_all(updateTempDirectory.c_str())) { - return informError( - updateos::UpdateError::CantRemoveUniqueTmpDir, "remove_all failed on %s", updateTempDirectory.c_str()); + try { + if (std::filesystem::is_directory(updateTempDirectory.c_str()) && + std::filesystem::remove_all(updateTempDirectory.c_str())) { + return informError( + updateos::UpdateError::CantRemoveUniqueTmpDir, "remove_all failed on %s", updateTempDirectory.c_str()); + } } - mtar_close(&updateTar); - if (std::remove(updateFile.c_str())) { - return informError(updateos::UpdateError::CantRemoveUpdateFile, "Failed to delete %s", updateFile.c_str()); + catch (const std::filesystem::filesystem_error &e) { + LOG_ERROR("remove_all on %s, error %s", updateTempDirectory.c_str(), e.what()); + } + + try { + mtar_close(&updateTar); + if (std::remove(updateFile.c_str())) { + return informError(updateos::UpdateError::CantRemoveUpdateFile, "Failed to delete %s", updateFile.c_str()); + } + } + catch (const std::filesystem::filesystem_error &fsError) { + LOG_ERROR("remove_all on %s, error %s", updateFile.c_str(), fsError.what()); } status = updateos::UpdateState::ReadyForReset; @@ -704,51 +720,44 @@ const json11::Json UpdateMuditaOS::getVersionInfoFromFile(const fs::path &update { if (std::filesystem::exists(updateFile.c_str())) { mtar_t tar; - mtar_header_t h; + mtar_header_t tarHeader; if (mtar_open(&tar, updateFile.c_str(), "r") == MTAR_EOPENFAIL) { - LOG_INFO("UpdateMuditaOS::getVersionInfoFromFile %s can't open", updateFile.c_str()); + LOG_WARN("%s can't open", updateFile.c_str()); return json11::Json(); } - std::unique_ptr versionFilename(new char[boot::consts::crc_buf]); + std::unique_ptr versionFilename = std::make_unique(boot::consts::crc_buf); sprintf(versionFilename.get(), "./%s", updateos::file::version); - if (mtar_find(&tar, versionFilename.get(), &h) == MTAR_ENOTFOUND) { - LOG_INFO("UpdateMuditaOS::getVersionInfoFromFile can't find %s in %s", - updateos::file::version, - updateFile.c_str()); + if (mtar_find(&tar, versionFilename.get(), &tarHeader) == MTAR_ENOTFOUND) { + LOG_WARN("can't find %s in %s", updateos::file::version, updateFile.c_str()); mtar_close(&tar); return json11::Json(); } /* this file should never be larger then boot::consts::tar_buf */ - std::unique_ptr readBuf(new char[boot::consts::tar_buf]); - if (mtar_read_data(&tar, readBuf.get(), h.size) != MTAR_ESUCCESS) { - LOG_INFO("UpdateMuditaOS::getVersionInfoFromFile can't read %s in %s", - updateos::file::version, - updateFile.c_str()); + std::unique_ptr readBuf = std::make_unique(boot::consts::tar_buf); + if (mtar_read_data(&tar, readBuf.get(), tarHeader.size) != MTAR_ESUCCESS) { + LOG_WARN("can't read %s in %s", updateos::file::version, updateFile.c_str()); - // mtar_close(&tar); return json11::Json(); } mtar_close(&tar); std::string parserError; - std::string dataPackage = std::string(static_cast(readBuf.get()), h.size); + std::string dataPackage = std::string(static_cast(readBuf.get()), tarHeader.size); json11::Json versionInfo = json11::Json::parse(dataPackage, parserError); if (parserError != "") { - LOG_INFO("UpdateMuditaOS::getVersionInfoFromFile can't parse %s as JSON error: \"%s\"", - updateos::file::version, - parserError.c_str()); + LOG_WARN("can't parse %s as JSON error: \"%s\"", updateos::file::version, parserError.c_str()); return json11::Json(); } return versionInfo; } else { - LOG_INFO("UpdateMuditaOS::getVersionInfoFromFile %s does not exist", updateFile.c_str()); + LOG_WARN("%s does not exist", updateFile.c_str()); } return json11::Json(); @@ -762,10 +771,24 @@ bool UpdateMuditaOS::isUpgradeToCurrent(const std::string &versionToCompare) const fs::path UpdateMuditaOS::checkForUpdate() { const auto updatesOSPath = purefs::dir::getUpdatesOSPath(); - for (auto &file : std::filesystem::directory_iterator(updatesOSPath.c_str())) { + std::error_code errorCode; + if (!std::filesystem::is_directory(updatesOSPath, errorCode)) { + LOG_INFO("%s does not exist, try to create", updatesOSPath.c_str()); + std::filesystem::create_directory(updatesOSPath, errorCode); + if (errorCode) { + LOG_WARN("%s can't be created \"%s\"", updatesOSPath.c_str(), errorCode.message().c_str()); + return fs::path(); + } + } + + for (auto &file : std::filesystem::directory_iterator(updatesOSPath.c_str(), errorCode)) { json11::Json versionInfo = UpdateMuditaOS::getVersionInfoFromFile(updatesOSPath / file.path()); if (versionInfo.is_null()) continue; + if (errorCode) { + LOG_WARN("directory_iterator for %s failed \"%s\"", updatesOSPath.c_str(), errorCode.message().c_str()); + return fs::path(); + } if (versionInfo[boot::json::os_version][boot::json::version_string].is_string()) { if (UpdateMuditaOS::isUpgradeToCurrent( @@ -855,12 +878,12 @@ void UpdateMuditaOS::informUpdate(const updateos::UpdateState statusCode, const void UpdateMuditaOS::setInitialHistory(const std::string &initialHistory) { - LOG_DEBUG("setInitialHistory %s", initialHistory.c_str()); + LOG_DEBUG("%s", initialHistory.c_str()); std::string parseErrors; updateHistory = json11::Json::parse(initialHistory, parseErrors); if (!parseErrors.empty() && !initialHistory.empty()) { - LOG_ERROR("Can't parse current update history, resetting"); + LOG_WARN("Can't parse current update history, resetting"); updateHistory = json11::Json(); } } diff --git a/module-services/service-desktop/endpoints/update/UpdateMuditaOS.hpp b/module-services/service-desktop/endpoints/update/UpdateMuditaOS.hpp index 962a7a2dfd0b4cfdc2f7bedb4f0a89be15f5dab1..b44936aa815cd95906f480f862b698313e0d4e8e 100644 --- a/module-services/service-desktop/endpoints/update/UpdateMuditaOS.hpp +++ b/module-services/service-desktop/endpoints/update/UpdateMuditaOS.hpp @@ -71,7 +71,8 @@ namespace updateos CantOpenBootloaderFile, CantAllocateBuffer, CantLoadBootloaderFile, - UpdateAborted + UpdateAborted, + CantCopyTempToCurrent }; enum class UpdateState diff --git a/module-services/service-desktop/parser/ParserUtils.hpp b/module-services/service-desktop/parser/ParserUtils.hpp index 672ab9c1fe7f260a6c674c5ea10eb8071de70c44..a7177ec5cdecd5c2f21a139bacedae29e55f3e1d 100644 --- a/module-services/service-desktop/parser/ParserUtils.hpp +++ b/module-services/service-desktop/parser/ParserUtils.hpp @@ -106,6 +106,7 @@ namespace parserFSM inline constexpr auto errorCode = "errorCode"; inline constexpr auto statusCode = "statusCode"; inline constexpr auto updateHistory = "updateHistory"; + inline constexpr auto versionString = "string"; inline constexpr auto fileExists = "fileExists"; inline constexpr auto version = "version"; inline constexpr auto task = "task"; diff --git a/module-vfs/src/purefs/filesystem_paths.cpp b/module-vfs/src/purefs/filesystem_paths.cpp index 2012cfd80c45e0049c9ec331f67459231ca1300d..4b04e3d57db8efe5e64f86310347c1dcb2541e67 100644 --- a/module-vfs/src/purefs/filesystem_paths.cpp +++ b/module-vfs/src/purefs/filesystem_paths.cpp @@ -46,7 +46,7 @@ namespace purefs std::filesystem::path getUpdatesOSPath() noexcept { - return std::filesystem::path{eMMC_disk} / PATH_UPDATES; + return std::filesystem::path{eMMC_disk} / PATH_USER / PATH_UPDATES; } std::filesystem::path getTemporaryPath() noexcept diff --git a/test/pytest/service-desktop/test_update.py b/test/pytest/service-desktop/test_update.py index d86c60e3a8cc5d560b41c871ffaf933008568514..dd8d74fea192bc3672fc5732dc7eb22cc03e9f61 100644 --- a/test/pytest/service-desktop/test_update.py +++ b/test/pytest/service-desktop/test_update.py @@ -5,6 +5,7 @@ from harness.interface.defs import status @pytest.mark.service_desktop_test +@pytest.mark.rt1051 @pytest.mark.usefixtures("usb_unlocked") @pytest.mark.rt1051 def test_update(harness):