diff --git a/src/core/Hypridle.cpp b/src/core/Hypridle.cpp index 4157674..dfbdc92 100644 --- a/src/core/Hypridle.cpp +++ b/src/core/Hypridle.cpp @@ -19,7 +19,19 @@ CHypridle::CHypridle() { } } +void setupSignals(void) { + struct sigaction sa; + + // don't transform child processes into zombies and don't handle SIGCHLD. + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); +} + void CHypridle::run() { + setupSignals(); + m_sWaylandState.registry = makeShared((wl_proxy*)wl_display_get_registry(m_sWaylandState.display)); m_sWaylandState.registry->setGlobal([this](CCWlRegistry* r, uint32_t name, const char* interface, uint32_t version) { const std::string IFACE = interface; @@ -235,53 +247,30 @@ void CHypridle::enterEventLoop() { static void spawn(const std::string& args) { Debug::log(LOG, "Executing {}", args); - int socket[2]; - if (pipe(socket) != 0) { - Debug::log(LOG, "Unable to create pipe for fork"); - } - - pid_t child, grandchild; - child = fork(); + pid_t child = fork(); if (child < 0) { - close(socket[0]); - close(socket[1]); - Debug::log(LOG, "Fail to create the first fork"); + Debug::log(ERR, "Failed to fork"); return; - } - if (child == 0) { - // run in child + } else if (child == 0) { + setsid(); - sigset_t set; - sigemptyset(&set); - sigprocmask(SIG_SETMASK, &set, nullptr); + struct sigaction sa; + // reset signals to the default + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); - grandchild = fork(); - if (grandchild == 0) { - // run in grandchild - close(socket[0]); - close(socket[1]); - execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); - // exit grandchild - _exit(0); - } - close(socket[0]); - write(socket[1], &grandchild, sizeof(grandchild)); - close(socket[1]); - // exit child - _exit(0); - } - // run in parent - close(socket[1]); - read(socket[0], &grandchild, sizeof(grandchild)); - close(socket[0]); - // clear child and leave grandchild to init - waitpid(child, nullptr, 0); - if (grandchild < 0) { - Debug::log(LOG, "Failed to create the second fork"); - return; + // TODO: ??? Why do we need that ??? + // We already make sure we have O_CLOEXEC and that should be enough. Still somehow, without this, releasing the inhibitor does not work. + // Somehow related to sdbus::UnixFd calling dup on the fd?? + g_pHypridle->closeInhibitFd(); + + execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); + _exit(1); } - Debug::log(LOG, "Process Created with pid {}", grandchild); + Debug::log(LOG, "Process Created with pid {}", child); } void CHypridle::onIdled(SIdleListener* pListener) { @@ -424,7 +413,7 @@ static void handleDbusLogin(sdbus::Message msg) { Debug::log(LOG, "Got Unlock from dbus"); if (!std::string{*UNLOCKCMD}.empty()) { - Debug::log(LOG, "Locking with {}", *UNLOCKCMD); + Debug::log(LOG, "Unlocking with {}", *UNLOCKCMD); spawn(*UNLOCKCMD); } } @@ -609,6 +598,11 @@ void CHypridle::handleInhibitOnDbusSleep(bool toSleep) { } void CHypridle::inhibitSleep() { + if (m_sDBUSState.sleepInhibitFd.isValid()) { + Debug::log(WARN, "Called inhibitSleep, but previous sleep inhibitor is still active!"); + m_sDBUSState.sleepInhibitFd.reset(); + } + auto method = m_sDBUSState.login->createMethodCall(sdbus::InterfaceName{"org.freedesktop.login1.Manager"}, sdbus::MethodName{"Inhibit"}); method << "sleep"; method << "hypridle"; @@ -628,11 +622,18 @@ void CHypridle::inhibitSleep() { return; } - reply >> m_sDBUSState.sleepInhibitFd; - Debug::log(TRACE, "Inhibited sleep with fd {}", m_sDBUSState.sleepInhibitFd.get()); - } catch (const std::exception& e) { Debug::log(ERR, "Failed to inhibit sleep ({})", e.what()); } + sdbus::UnixFd fd; + // This calls dup on the fd, no F_DUPFD_CLOEXEC :( + // There seems to be no way to get the file descriptor out of the reply other than that. + reply >> fd; - Debug::log(LOG, "Inhibited sleep!"); + m_sDBUSState.sleepInhibitFd = Hyprutils::OS::CFileDescriptor(fd.release()); + auto flags = m_sDBUSState.sleepInhibitFd.getFlags(); + if (!(flags & O_CLOEXEC) && !m_sDBUSState.sleepInhibitFd.setFlags(flags | O_CLOEXEC)) + Debug::log(ERR, "Sleep inhibitor has no O_CLOEXEC"); + + Debug::log(LOG, "Inhibited sleep with fd {}", m_sDBUSState.sleepInhibitFd.get()); + } catch (const std::exception& e) { Debug::log(ERR, "Failed to inhibit sleep ({})", e.what()); } } void CHypridle::uninhibitSleep() { @@ -642,5 +643,9 @@ void CHypridle::uninhibitSleep() { } Debug::log(LOG, "Releasing the sleep inhibitor!"); - close(m_sDBUSState.sleepInhibitFd.release()); + m_sDBUSState.sleepInhibitFd.reset(); +} + +void CHypridle::closeInhibitFd() { + m_sDBUSState.sleepInhibitFd.reset(); } diff --git a/src/core/Hypridle.hpp b/src/core/Hypridle.hpp index d7fc588..6f7fcb3 100644 --- a/src/core/Hypridle.hpp +++ b/src/core/Hypridle.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "wayland.hpp" @@ -48,6 +49,8 @@ class CHypridle { void inhibitSleep(); void uninhibitSleep(); + void closeInhibitFd(); + private: void setupDBUS(); void enterEventLoop(); @@ -83,7 +86,7 @@ class CHypridle { std::unique_ptr login; std::vector> screenSaverObjects; std::vector inhibitCookies; - sdbus::UnixFd sleepInhibitFd; + Hyprutils::OS::CFileDescriptor sleepInhibitFd; } m_sDBUSState; struct {