From f8bbe5124c0012865ea36f52d304313084a31fe9 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 6 May 2025 22:43:08 +0200 Subject: [PATCH] hyprpm: clean up root access and properly check input (#10304) * manifest: reject bad names from parsing * sys: restructure root functions --- hyprpm/src/core/DataState.cpp | 77 ++++++++++++++----- hyprpm/src/core/Manifest.cpp | 44 +++++++---- hyprpm/src/core/Manifest.hpp | 6 +- hyprpm/src/core/PluginManager.cpp | 37 ++++----- hyprpm/src/helpers/Sys.cpp | 124 ++++++++++++++++++++---------- hyprpm/src/helpers/Sys.hpp | 23 ++++-- hyprpm/src/main.cpp | 24 +++--- 7 files changed, 224 insertions(+), 111 deletions(-) diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp index 3e7ae399d..623395b18 100644 --- a/hyprpm/src/core/DataState.cpp +++ b/hyprpm/src/core/DataState.cpp @@ -3,11 +3,37 @@ #include #include #include +#include #include "PluginManager.hpp" #include "../helpers/Die.hpp" #include "../helpers/Sys.hpp" #include "../helpers/StringUtils.hpp" +static std::string getTempRoot() { + static auto ENV = getenv("XDG_RUNTIME_DIR"); + if (!ENV) { + std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n"; + exit(1); + } + + const auto STR = ENV + std::string{"/hyprpm/"}; + + return STR; +} + +// write the state to a file +static bool writeState(const std::string& str, const std::string& to) { + // create temp file in a safe temp root + std::ofstream of(getTempRoot() + ".temp-state", std::ios::trunc); + if (!of.good()) + return false; + + of << str; + of.close(); + + return NSys::root::install(getTempRoot() + ".temp-state", to, "644"); +} + std::filesystem::path DataState::getDataStatePath() { return std::filesystem::path("/var/cache/hyprpm/" + g_pPluginManager->m_szUsername); } @@ -37,11 +63,16 @@ void DataState::ensureStateStoreExists() { std::error_code ec; if (!std::filesystem::exists(getHeadersPath(), ec) || ec) { std::println("{}", infoString("The hyprpm state store doesn't exist. Creating now...")); - if (!std::filesystem::exists("/var/cache/hyprpm/", ec) || ec) - NSys::runAsSuperuser("mkdir -p -m 755 '/var/cache/hyprpm/'"); - if (!std::filesystem::exists(getDataStatePath(), ec) || ec) - NSys::runAsSuperuser("mkdir -p -m 755 '" + getDataStatePath().string() + "'"); - NSys::runAsSuperuser("mkdir -p -m 755 '" + getHeadersPath() + "'"); + if (!std::filesystem::exists("/var/cache/hyprpm/", ec) || ec) { + if (!NSys::root::createDirectory("/var/cache/hyprpm", "755")) + Debug::die("ensureStateStoreExists: Failed to run a superuser cmd"); + } + if (!std::filesystem::exists(getDataStatePath(), ec) || ec) { + if (!NSys::root::createDirectory(getDataStatePath().string(), "755")) + Debug::die("ensureStateStoreExists: Failed to run a superuser cmd"); + } + if (!NSys::root::createDirectory(getHeadersPath(), "755")) + Debug::die("ensureStateStoreExists: Failed to run a superuser cmd"); } } @@ -51,8 +82,10 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) { const auto PATH = getDataStatePath() / repo.name; std::error_code ec; - if (!std::filesystem::exists(PATH, ec) || ec) - NSys::runAsSuperuser("mkdir -p -m 755 '" + PATH.string() + "'"); + if (!std::filesystem::exists(PATH, ec) || ec) { + if (!NSys::root::createDirectory(PATH.string(), "755")) + Debug::die("addNewPluginRepo: failed to create cache dir"); + } // clang-format off auto DATA = toml::table{ {"repository", toml::table{ @@ -66,8 +99,10 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) { const auto filename = p.name + ".so"; // copy .so to the good place and chmod 755 - if (std::filesystem::exists(p.filename)) - NSys::runAsSuperuser("cp '" + p.filename + "' '" + (PATH / filename).string() + "' && chmod 755 '" + (PATH / filename).string() + "'"); + if (std::filesystem::exists(p.filename)) { + if (!NSys::root::install(p.filename, (PATH / filename).string(), "0755")) + Debug::die("addNewPluginRepo: failed to install so file"); + } DATA.emplace(p.name, toml::table{ {"filename", filename}, @@ -80,8 +115,8 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) { std::stringstream ss; ss << DATA; - NSys::runAsSuperuser("cat << EOF > " + (PATH / "state.toml").string() + "\n" + ss.str() + "\nEOF"); - NSys::runAsSuperuser("chmod 644 '" + (PATH / "state.toml").string() + "'"); + if (!writeState(ss.str(), (PATH / "state.toml").string())) + Debug::die("{}", failureString("Failed to write plugin state")); } bool DataState::pluginRepoExists(const std::string& urlOrName) { @@ -123,7 +158,8 @@ void DataState::removePluginRepo(const std::string& urlOrName) { return; // WTF? // scary! - NSys::runAsSuperuser("rm -r '" + PATH + "'"); + if (!NSys::root::removeRecursive(PATH)) + Debug::die("removePluginRepo: failed to remove dir"); return; } } @@ -135,8 +171,10 @@ void DataState::updateGlobalState(const SGlobalState& state) { const auto PATH = getDataStatePath(); std::error_code ec; - if (!std::filesystem::exists(PATH, ec) || ec) - NSys::runAsSuperuser("mkdir -p -m 755 '" + PATH.string() + "'"); + if (!std::filesystem::exists(PATH, ec) || ec) { + if (!NSys::root::createDirectory(PATH.string(), "755")) + Debug::die("updateGlobalState: failed to create dir"); + } // clang-format off auto DATA = toml::table{ {"state", toml::table{ @@ -149,8 +187,8 @@ void DataState::updateGlobalState(const SGlobalState& state) { std::stringstream ss; ss << DATA; - NSys::runAsSuperuser("cat << EOF > " + (PATH / "state.toml").string() + "\n" + ss.str() + "\nEOF"); - NSys::runAsSuperuser("chmod 644 '" + (PATH / "state.toml").string() + "'"); + if (!writeState(ss.str(), (PATH / "state.toml").string())) + Debug::die("{}", failureString("Failed to write plugin state")); } SGlobalState DataState::getGlobalState() { @@ -229,8 +267,8 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) { std::stringstream ss; ss << modifiedState; - NSys::runAsSuperuser("cat << EOF > " + stateFile.string() + "\n" + ss.str() + "\nEOF"); - NSys::runAsSuperuser("chmod 644 '" + stateFile.string() + "'"); + if (!writeState(ss.str(), stateFile.string())) + Debug::die("{}", failureString("Failed to write plugin state")); return true; } @@ -250,5 +288,6 @@ void DataState::purgeAllCache() { if (PATH.contains('\'')) return; // scary! - NSys::runAsSuperuser("rm -r '" + PATH + "'"); + if (!NSys::root::removeRecursive(PATH)) + Debug::die("Failed to run a superuser cmd"); } diff --git a/hyprpm/src/core/Manifest.cpp b/hyprpm/src/core/Manifest.cpp index 754d9d693..90f6fbff1 100644 --- a/hyprpm/src/core/Manifest.cpp +++ b/hyprpm/src/core/Manifest.cpp @@ -1,6 +1,12 @@ #include "Manifest.hpp" #include -#include +#include + +// Alphanumerics and -_ allowed for plugin names. No magic names. +// [A-Za-z0-9\-_]* +static bool validManifestName(const std::string_view& n) { + return std::ranges::all_of(n, [](const char& c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '-' || c == '_' || c == '=' || (c >= '0' && c <= '9'); }); +} CManifest::CManifest(const eManifestType type, const std::string& path) { auto manifest = toml::parse_file(path); @@ -11,11 +17,17 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { continue; CManifest::SManifestPlugin plugin; + + if (!validManifestName(key.str())) { + m_good = false; + return; + } + plugin.name = key; - m_vPlugins.push_back(plugin); + m_plugins.push_back(plugin); } - for (auto& plugin : m_vPlugins) { + for (auto& plugin : m_plugins) { plugin.description = manifest[plugin.name]["description"].value_or("?"); plugin.version = manifest[plugin.name]["version"].value_or("?"); plugin.output = manifest[plugin.name]["build"]["output"].value_or("?"); @@ -37,21 +49,21 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { } if (plugin.output.empty() || plugin.buildSteps.empty()) { - m_bGood = false; + m_good = false; return; } } } else if (type == MANIFEST_HYPRPM) { - m_sRepository.name = manifest["repository"]["name"].value_or(""); - auto authors = manifest["repository"]["authors"].as_array(); + m_repository.name = manifest["repository"]["name"].value_or(""); + auto authors = manifest["repository"]["authors"].as_array(); if (authors) { for (auto&& a : *authors) { - m_sRepository.authors.push_back(a.as_string()->value_or("?")); + m_repository.authors.push_back(a.as_string()->value_or("?")); } } else { auto author = manifest["repository"]["author"].value_or(""); if (!std::string{author}.empty()) - m_sRepository.authors.push_back(author); + m_repository.authors.push_back(author); } auto pins = manifest["repository"]["commit_pins"].as_array(); @@ -59,7 +71,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { for (auto&& pin : *pins) { auto pinArr = pin.as_array(); if (pinArr && pinArr->get(1)) - m_sRepository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get())); + m_repository.commitPins.push_back(std::make_pair<>(pinArr->get(0)->as_string()->get(), pinArr->get(1)->as_string()->get())); } } @@ -68,11 +80,17 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { continue; CManifest::SManifestPlugin plugin; + + if (!validManifestName(key.str())) { + m_good = false; + return; + } + plugin.name = key; - m_vPlugins.push_back(plugin); + m_plugins.push_back(plugin); } - for (auto& plugin : m_vPlugins) { + for (auto& plugin : m_plugins) { plugin.description = manifest[plugin.name]["description"].value_or("?"); plugin.output = manifest[plugin.name]["output"].value_or("?"); plugin.since = manifest[plugin.name]["since_hyprland"].value_or(0); @@ -94,12 +112,12 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { } if (plugin.output.empty() || plugin.buildSteps.empty()) { - m_bGood = false; + m_good = false; return; } } } else { // ??? - m_bGood = false; + m_good = false; } } \ No newline at end of file diff --git a/hyprpm/src/core/Manifest.hpp b/hyprpm/src/core/Manifest.hpp index 19f967eb1..41a49350a 100644 --- a/hyprpm/src/core/Manifest.hpp +++ b/hyprpm/src/core/Manifest.hpp @@ -27,8 +27,8 @@ class CManifest { std::string name; std::vector authors; std::vector> commitPins; - } m_sRepository; + } m_repository; - std::vector m_vPlugins; - bool m_bGood = true; + std::vector m_plugins; + bool m_good = true; }; \ No newline at end of file diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 33e565d35..8686910ff 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -236,14 +236,14 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& return false; } - if (!pManifest->m_bGood) { + if (!pManifest->m_good) { std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); return false; } progress.m_iSteps = 2; - progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:")); - for (auto const& pl : pManifest->m_vPlugins) { + progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_plugins.size()) + " plugins:")); + for (auto const& pl : pManifest->m_plugins) { std::string message = "→ " + pl.name + " by "; for (auto const& a : pl.authors) { message += a + ", "; @@ -256,12 +256,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(message); } - if (!pManifest->m_sRepository.commitPins.empty()) { + if (!pManifest->m_repository.commitPins.empty()) { // check commit pins - progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); + progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_repository.commitPins.size())); - for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { + for (auto const& [hl, plugin] : pManifest->m_repository.commitPins) { if (hl != HLVER.hash) continue; @@ -293,7 +293,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.m_szCurrentMessage = "Building plugin(s)"; progress.print(); - for (auto& p : pManifest->m_vPlugins) { + for (auto& p : pManifest->m_plugins) { std::string out; if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) { @@ -336,11 +336,11 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::string repohash = execAndGet("cd " + m_szWorkingPluginDirectory + " && git rev-parse HEAD"); if (repohash.length() > 0) repohash.pop_back(); - repo.name = pManifest->m_sRepository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_sRepository.name; + repo.name = pManifest->m_repository.name.empty() ? url.substr(url.find_last_of('/') + 1) : pManifest->m_repository.name; repo.url = url; repo.rev = rev; repo.hash = repohash; - for (auto const& p : pManifest->m_vPlugins) { + for (auto const& p : pManifest->m_plugins) { repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed}); } DataState::addNewPluginRepo(repo); @@ -566,13 +566,14 @@ bool CPluginManager::updateHeaders(bool force) { ret = execAndGet(cmd); - cmd = std::format("cd {} && make installheaders && chmod -R 644 {} && find {} -type d -exec chmod o+x {{}} \\;", WORKINGDIR, DataState::getHeadersPath(), + cmd = std::format("make -C '{}' installheaders && chmod -R 644 '{}' && find '{}' -type d -exec chmod o+x {{}} \\;", WORKINGDIR, DataState::getHeadersPath(), DataState::getHeadersPath()); if (m_bVerbose) progress.printMessageAbove(verboseString("install will run as sudo: {}", cmd)); - ret = NSys::runAsSuperuser(cmd); + // WORKINGDIR and headersPath should not contain anything unsafe. Usernames can't contain cmd exec parts. + ret = NSys::root::runAsSuperuserUnsafe(cmd); if (m_bVerbose) std::println("{}", verboseString("installer returned: {}", ret)); @@ -701,17 +702,17 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { continue; } - if (!pManifest->m_bGood) { - std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); + if (!pManifest->m_good) { + std::println(stderr, "\n{}", failureString("The provided plugin repository has a bad manifest")); continue; } - if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) { + if (repo.rev.empty() && !pManifest->m_repository.commitPins.empty()) { // check commit pins unless a revision is specified - progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); + progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_repository.commitPins.size())); - for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { + for (auto const& [hl, plugin] : pManifest->m_repository.commitPins) { if (hl != HLVER.hash) continue; @@ -721,7 +722,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { } } - for (auto& p : pManifest->m_vPlugins) { + for (auto& p : pManifest->m_plugins) { std::string out; if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) { @@ -763,7 +764,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { if (repohash.length() > 0) repohash.pop_back(); newrepo.hash = repohash; - for (auto const& p : pManifest->m_vPlugins) { + for (auto const& p : pManifest->m_plugins) { const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; }); newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false}); } diff --git a/hyprpm/src/helpers/Sys.cpp b/hyprpm/src/helpers/Sys.cpp index 868ad9a95..a5876b9d0 100644 --- a/hyprpm/src/helpers/Sys.cpp +++ b/hyprpm/src/helpers/Sys.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -20,7 +20,7 @@ inline constexpr std::array SUPERUSER_BINARIES = { "run0", }; -static std::string fetchSuperuserBins() { +static std::string validSubinsAsStr() { std::ostringstream oss; auto it = SUPERUSER_BINARIES.begin(); if (it != SUPERUSER_BINARIES.end()) { @@ -56,17 +56,30 @@ static bool executableExistsInPath(const std::string& exe) { return false; } -static std::optional> execAndGet(std::string_view cmd, bool noRedirect = false) { - std::string command = std::string{cmd}; - if (!noRedirect) - command += " 2>&1"; +static std::string subin() { + static std::string bin; + static bool once = true; + if (!once) + return bin; - CProcess proc("/bin/sh", {"-c", command}); - if (!proc.runSync()) - // optional handles nullopt gracefully - return std::nullopt; + for (const auto& BIN : SUPERUSER_BINARIES) { + if (!executableExistsInPath(std::string{BIN})) + continue; - return {{proc.stdOut(), proc.exitCode()}}; + bin = BIN; + break; + } + + once = false; + + if (bin.empty()) + Debug::die("{}", failureString("No valid superuser binary present. Supported: {}", validSubinsAsStr())); + + return bin; +} + +static bool verifyStringValid(const std::string& s) { + return std::ranges::none_of(s, [](const char& c) { return c == '`' || c == '$' || c == '(' || c == ')' || c == '\'' || c == '"'; }); } int NSys::getUID() { @@ -85,39 +98,70 @@ bool NSys::isSuperuser() { return getuid() != geteuid() || geteuid() == 0; } -std::string NSys::runAsSuperuser(const std::string& cmd) { - for (const auto& BIN : SUPERUSER_BINARIES) { - if (!executableExistsInPath(std::string{BIN})) - continue; - - const auto result = execAndGet(std::string{BIN} + " /bin/sh -c \"" + cmd + "\"", true); - if (!result.has_value() || result->second != 0) - Debug::die("Failed to run a command as sudo. This could be due to an invalid password, or a hyprpm bug."); - - return result->first; - } - - Debug::die("{} {}", "Failed to find a superuser binary. Supported: ", fetchSuperuserBins()); - return ""; -} - -void NSys::cacheSudo() { +void NSys::root::cacheSudo() { // "caches" the sudo so that the prompt later doesn't pop up in a weird spot // sudo will not ask us again for a moment - runAsSuperuser("echo e > /dev/null"); + CProcess proc(subin(), {"echo", "hyprland"}); + proc.runSync(); } -void NSys::dropSudo() { - for (const auto& BIN : SUPERUSER_BINARIES) { - if (!executableExistsInPath(std::string{BIN})) - continue; - - if (BIN == "sudo") - execAndGet("sudo -k"); - else { - // note the superuser binary that is being dropped - std::println("{}", infoString("Don't know how to drop timestamp for '{}', ignoring.", BIN)); - } +void NSys::root::dropSudo() { + if (subin() != "sudo") { + std::println("{}", infoString("Don't know how to drop timestamp for '{}', ignoring.", subin())); return; } + + CProcess proc(subin(), {"-k"}); + proc.runSync(); +} + +bool NSys::root::createDirectory(const std::string& path, const std::string& mode) { + if (!verifyStringValid(path)) + return false; + + if (!std::ranges::all_of(mode, [](const char& c) { return c >= '0' && c <= '9'; })) + return false; + + CProcess proc(subin(), {"mkdir", "-p", "-m", mode, path}); + + return proc.runSync() && proc.exitCode() == 0; +} + +bool NSys::root::removeRecursive(const std::string& path) { + if (!verifyStringValid(path)) + return false; + + std::error_code ec; + const std::string PATH_ABSOLUTE = std::filesystem::canonical(path, ec); + + if (ec) + return false; + + if (!PATH_ABSOLUTE.starts_with("/var/cache/hyprpm")) + return false; + + CProcess proc(subin(), {"rm", "-fr", PATH_ABSOLUTE}); + + return proc.runSync() && proc.exitCode() == 0; +} + +bool NSys::root::install(const std::string& what, const std::string& where, const std::string& mode) { + if (!verifyStringValid(what) || !verifyStringValid(where)) + return false; + + if (!std::ranges::all_of(mode, [](const char& c) { return c >= '0' && c <= '9'; })) + return false; + + CProcess proc(subin(), {"install", "-m" + mode, "-o", "root", "-g", "root", what, where}); + + return proc.runSync() && proc.exitCode() == 0; +} + +std::string NSys::root::runAsSuperuserUnsafe(const std::string& cmd) { + CProcess proc(subin(), {"/bin/sh", "-c", cmd}); + + if (!proc.runSync()) + return ""; + + return proc.stdOut(); } diff --git a/hyprpm/src/helpers/Sys.hpp b/hyprpm/src/helpers/Sys.hpp index 2d643d401..b44eb7580 100644 --- a/hyprpm/src/helpers/Sys.hpp +++ b/hyprpm/src/helpers/Sys.hpp @@ -3,10 +3,21 @@ #include namespace NSys { - bool isSuperuser(); - int getUID(); - int getEUID(); - std::string runAsSuperuser(const std::string& cmd); - void cacheSudo(); - void dropSudo(); + bool isSuperuser(); + int getUID(); + int getEUID(); + + // NOLINTNEXTLINE + namespace root { + void cacheSudo(); + void dropSudo(); + + // + [[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool createDirectory(const std::string& path, const std::string& mode); + [[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool removeRecursive(const std::string& path); + [[nodiscard("Discarding could lead to vulnerabilities and bugs")]] bool install(const std::string& what, const std::string& where, const std::string& mode); + + // Do not use this unless absolutely necessary! + std::string runAsSuperuserUnsafe(const std::string& cmd); + }; }; \ No newline at end of file diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp index a70a0c0b2..ca9c0fdb6 100644 --- a/hyprpm/src/main.cpp +++ b/hyprpm/src/main.cpp @@ -101,8 +101,8 @@ int main(int argc, char** argv, char** envp) { if (command.size() >= 3) rev = command[2]; - NSys::cacheSudo(); - CScopeGuard x([] { NSys::dropSudo(); }); + NSys::root::cacheSudo(); + CScopeGuard x([] { NSys::root::dropSudo(); }); return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1; } else if (command[0] == "remove") { @@ -111,13 +111,13 @@ int main(int argc, char** argv, char** envp) { return 1; } - NSys::cacheSudo(); - CScopeGuard x([] { NSys::dropSudo(); }); + NSys::root::cacheSudo(); + CScopeGuard x([] { NSys::root::dropSudo(); }); return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1; } else if (command[0] == "update") { - NSys::cacheSudo(); - CScopeGuard x([] { NSys::dropSudo(); }); + NSys::root::cacheSudo(); + CScopeGuard x([] { NSys::root::dropSudo(); }); bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK; bool headers = g_pPluginManager->updateHeaders(force); @@ -152,8 +152,8 @@ int main(int argc, char** argv, char** envp) { return 1; } - NSys::cacheSudo(); - CScopeGuard x([] { NSys::dropSudo(); }); + NSys::root::cacheSudo(); + CScopeGuard x([] { NSys::root::dropSudo(); }); auto ret = g_pPluginManager->ensurePluginsLoadState(); @@ -173,8 +173,8 @@ int main(int argc, char** argv, char** envp) { return 1; } - NSys::cacheSudo(); - CScopeGuard x([] { NSys::dropSudo(); }); + NSys::root::cacheSudo(); + CScopeGuard x([] { NSys::root::dropSudo(); }); auto ret = g_pPluginManager->ensurePluginsLoadState(); @@ -200,8 +200,8 @@ int main(int argc, char** argv, char** envp) { g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); } } else if (command[0] == "purge-cache") { - NSys::cacheSudo(); - CScopeGuard x([] { NSys::dropSudo(); }); + NSys::root::cacheSudo(); + CScopeGuard x([] { NSys::root::dropSudo(); }); DataState::purgeAllCache(); } else if (command[0] == "list") { g_pPluginManager->listAllPlugins();