Set child stdout and stderr to /dev/null (#1000)

Some scripts or utilities check to see if stdout or stderr are connected
to a TTY or not to determine certain behaviors (for example, you might
want to prompt a user for input with fzf(1) if in a terminal but tofi(1)
or wofi(1) when spawned from your WM).  Since hyprland never closes
these output streams for spawned processes, they end up just spewing
their output onto the TTY while giving the user no real way to have a
script detect if it's being run from the shell or WM.

Instead of just closing stdout and stderr though, we close them and then
proceed to reopen them but connect them to /dev/null.  This allows
scripts and processes to not fail when attempting to write, but for that
writing to simply have no effect.
This commit is contained in:
Thomas Voss 2022-11-13 12:58:20 +01:00 committed by GitHub
parent 5a00f0c657
commit 1e5cab1ee7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,5 +1,7 @@
#include "KeybindManager.hpp"
#include <fcntl.h>
#include <paths.h>
#include <regex>
CKeybindManager::CKeybindManager() {
@ -526,6 +528,25 @@ void CKeybindManager::spawn(std::string args) {
// run in grandchild
close(socket[0]);
close(socket[1]);
close(STDOUT_FILENO);
close(STDERR_FILENO);
int devnull = open(_PATH_DEVNULL, O_WRONLY);
if (devnull == -1) {
Debug::log(LOG, "Unable to open /dev/null for writing");
return;
}
if (dup2(devnull, STDOUT_FILENO) == -1) {
Debug::log(LOG, "Unable to duplicate /dev/null to stdout");
return;
}
if (dup2(devnull, STDERR_FILENO) == -1) {
Debug::log(LOG, "Unable to duplicate /dev/null to stderr");
return;
}
close(devnull);
execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr);
// exit grandchild
_exit(0);