#include "Sys.hpp" #include "Die.hpp" #include "StringUtils.hpp" #include #include #include #include #include #include #include #include using namespace Hyprutils::OS; using namespace Hyprutils::String; inline constexpr std::array SUPERUSER_BINARIES = { "sudo", "doas", "run0", }; static std::string validSubinsAsStr() { std::ostringstream oss; auto it = SUPERUSER_BINARIES.begin(); if (it != SUPERUSER_BINARIES.end()) { oss << *it++; for (; it != SUPERUSER_BINARIES.end(); ++it) oss << ", " << *it; } return oss.str(); } static bool executableExistsInPath(const std::string& exe) { const char* PATHENV = std::getenv("PATH"); if (!PATHENV) return false; CVarList paths(PATHENV, 0, ':', true); std::error_code ec; for (const auto& PATH : paths) { std::filesystem::path candidate = std::filesystem::path(PATH) / exe; if (!std::filesystem::exists(candidate, ec) || ec) continue; if (!std::filesystem::is_regular_file(candidate, ec) || ec) continue; auto perms = std::filesystem::status(candidate, ec).permissions(); if (ec) continue; if ((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none) return true; } return false; } static std::string subin() { static std::string bin; static bool once = true; if (!once) return bin; for (const auto& BIN : SUPERUSER_BINARIES) { if (!executableExistsInPath(std::string{BIN})) continue; 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() { const auto UID = getuid(); const auto PWUID = getpwuid(UID); return PWUID ? PWUID->pw_uid : UID; } int NSys::getEUID() { const auto UID = geteuid(); const auto PWUID = getpwuid(UID); return PWUID ? PWUID->pw_uid : UID; } bool NSys::isSuperuser() { return getuid() != geteuid() || geteuid() == 0; } 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 CProcess proc(subin(), {"echo", "hyprland"}); proc.runSync(); } 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", "0", "-g", "0", 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(); }