diff --git a/engine/commands/cortex_upd_cmd.h b/engine/commands/cortex_upd_cmd.h index 4a94ba01a..4d2899a36 100644 --- a/engine/commands/cortex_upd_cmd.h +++ b/engine/commands/cortex_upd_cmd.h @@ -1,5 +1,9 @@ #pragma once #include +#if !defined(_WIN32) +#include +#include +#endif #include "httplib.h" #include "nlohmann/json.hpp" @@ -16,6 +20,14 @@ const std::string kCortexBinary = "cortex"; constexpr const auto kBetaComp = "-rc"; constexpr const auto kReleaseFormat = ".tar.gz"; +inline std::string GetRole() { +#if defined(_WIN32) + return ""; +#else + return "sudo "; +#endif +} + inline std::string GetCortexBinary() { #if defined(_WIN32) constexpr const bool has_exe = true; @@ -88,7 +100,8 @@ inline void CheckNewUpdate() { if (current_version != latest_version) { CLI_LOG("\nA new release of cortex is available: " << current_version << " -> " << latest_version); - CLI_LOG("To upgrade, run: " << GetCortexBinary() << " update"); + CLI_LOG("To upgrade, run: " << GetRole() << GetCortexBinary() + << " update"); if (CORTEX_VARIANT == file_manager_utils::kProdVariant) { CLI_LOG(json_res["html_url"].get()); } @@ -113,25 +126,60 @@ inline bool ReplaceBinaryInflight(const std::filesystem::path& src, } std::filesystem::path temp = dst.parent_path() / "cortex_temp"; + auto restore_binary = [&temp, &dst]() { + if (std::filesystem::exists(temp)) { + std::rename(temp.string().c_str(), dst.string().c_str()); + CLI_LOG("Restored binary file"); + } + }; try { if (std::filesystem::exists(temp)) { std::filesystem::remove(temp); } +#if !defined(_WIN32) + // Get permissions of the executable file + struct stat dst_file_stat; + if (stat(dst.string().c_str(), &dst_file_stat) != 0) { + CTL_ERR("Error getting permissions of executable file: " << dst.string()); + return false; + } + + // Get owner and group of the executable file + uid_t dst_file_owner = dst_file_stat.st_uid; + gid_t dst_file_group = dst_file_stat.st_gid; +#endif std::rename(dst.string().c_str(), temp.string().c_str()); std::filesystem::copy_file( src, dst, std::filesystem::copy_options::overwrite_existing); - std::filesystem::permissions(dst, std::filesystem::perms::owner_all | - std::filesystem::perms::group_all | - std::filesystem::perms::others_read | - std::filesystem::perms::others_exec); + +#if !defined(_WIN32) + // Set permissions of the executable file + if (chmod(dst.string().c_str(), dst_file_stat.st_mode) != 0) { + CTL_ERR("Error setting permissions of executable file: " << dst.string()); + restore_binary(); + return false; + } + + // Set owner and group of the executable file + if (chown(dst.string().c_str(), dst_file_owner, dst_file_group) != 0) { + CTL_ERR( + "Error setting owner and group of executable file: " << dst.string()); + restore_binary(); + return false; + } + + // Remove cortex_temp + if (unlink(temp.string().c_str()) != 0) { + CTL_ERR("Error deleting self: " << strerror(errno)); + restore_binary(); + return false; + } +#endif } catch (const std::exception& e) { CTL_ERR("Something went wrong: " << e.what()); - if (std::filesystem::exists(temp)) { - std::rename(temp.string().c_str(), dst.string().c_str()); - CLI_LOG("Restored binary file"); - } + restore_binary(); return false; } diff --git a/engine/test/components/test_cortex_upd_cmd.cc b/engine/test/components/test_cortex_upd_cmd.cc index 93f555535..ff70c814d 100644 --- a/engine/test/components/test_cortex_upd_cmd.cc +++ b/engine/test/components/test_cortex_upd_cmd.cc @@ -42,8 +42,24 @@ TEST_F(CortexUpdCmdTest, return_true_if_self_replace) { TEST_F(CortexUpdCmdTest, replace_binary_successfully) { std::filesystem::path new_binary(kNewReleaseFile); std::filesystem::path cur_binary(kCurReleaseFile); +#if !defined(_WIN32) + struct stat cur_file_stat; + EXPECT_TRUE(stat(cur_binary.string().c_str(), &cur_file_stat) == 0); +#endif + EXPECT_TRUE(commands::ReplaceBinaryInflight(new_binary, cur_binary)); + +#if !defined(_WIN32) + EXPECT_FALSE(std::filesystem::exists(kCortexTemp)); + + struct stat new_file_stat; + EXPECT_TRUE(stat(cur_binary.string().c_str(), &new_file_stat) == 0); + EXPECT_EQ(cur_file_stat.st_uid, new_file_stat.st_uid); + EXPECT_EQ(cur_file_stat.st_gid, new_file_stat.st_gid); + EXPECT_EQ(cur_file_stat.st_mode, new_file_stat.st_mode); +#else EXPECT_TRUE(std::filesystem::exists(kCortexTemp)); +#endif } TEST_F(CortexUpdCmdTest, should_restore_old_binary_if_has_error) {