fix(util): keep GLib child setup fork-safe

Move WAYBAR_OUTPUT_NAME injection into the parent-provided spawn environment and strip logging and setenv() out of the GLib child-setup hook.

That keeps the helper's post-fork path limited to the process setup it actually needs, which is a safer fit for sanitizer-heavy platforms such as FreeBSD.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
This commit is contained in:
Austin Horstman
2026-07-04 08:41:35 -05:00
committed by Austin Horstman
parent f987c24144
commit 1b6173ddda
+30 -20
View File
@@ -23,33 +23,42 @@
namespace { namespace {
void prepareChild(const std::string& output_name) { auto buildChildEnvironment(const std::string& output_name) -> std::vector<std::string> {
auto names = Glib::listenv();
std::vector<std::string> envp;
envp.reserve(names.size() + 1);
for (const auto& name : names) {
bool found = false;
auto value = Glib::getenv(name, found);
if (!found || name == "WAYBAR_OUTPUT_NAME") {
continue;
}
envp.push_back(name + "=" + value);
}
if (!output_name.empty()) {
envp.push_back("WAYBAR_OUTPUT_NAME=" + output_name);
}
return envp;
}
void prepareChild() {
sigset_t mask; sigset_t mask;
sigfillset(&mask); sigfillset(&mask);
const auto err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr); (void)pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
if (err != 0) {
spdlog::error("pthread_sigmask in LineStream failed: {}", std::strerror(err));
}
int deathsig = SIGTERM; int deathsig = SIGTERM;
#ifdef __linux__ #ifdef __linux__
if (prctl(PR_SET_PDEATHSIG, deathsig) != 0) { (void)prctl(PR_SET_PDEATHSIG, deathsig);
spdlog::error("prctl(PR_SET_PDEATHSIG) in LineStream failed: {}", std::strerror(errno));
}
#endif #endif
#ifdef __FreeBSD__ #ifdef __FreeBSD__
if (procctl(P_PID, 0, PROC_PDEATHSIG_CTL, reinterpret_cast<void*>(&deathsig)) == -1) { (void)procctl(P_PID, 0, PROC_PDEATHSIG_CTL, reinterpret_cast<void*>(&deathsig));
spdlog::error("procctl(PROC_PDEATHSIG_CTL) in LineStream failed: {}", std::strerror(errno));
}
#endif #endif
if (setpgid(0, 0) != 0) { (void)setpgid(0, 0);
spdlog::error("setpgid in LineStream failed: {}", std::strerror(errno));
}
if (!output_name.empty()) {
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
}
} }
void emitBufferedLines(std::string& buffer, void emitBufferedLines(std::string& buffer,
@@ -91,9 +100,10 @@ void waybar::util::command::LineStream::start(const std::string& cmd) {
stop(); stop();
std::vector<std::string> argv{"/bin/sh", "-c", cmd}; std::vector<std::string> argv{"/bin/sh", "-c", cmd};
Glib::spawn_async_with_pipes("", argv, Glib::SPAWN_DO_NOT_REAP_CHILD | Glib::SPAWN_CLOEXEC_PIPES, auto envp = buildChildEnvironment(output_name_);
sigc::bind(sigc::ptr_fun(&prepareChild), output_name_), &pid_, Glib::spawn_async_with_pipes("", argv, envp,
nullptr, &stdout_fd_, nullptr); Glib::SPAWN_DO_NOT_REAP_CHILD | Glib::SPAWN_CLOEXEC_PIPES,
sigc::ptr_fun(&prepareChild), &pid_, nullptr, &stdout_fd_, nullptr);
const auto flags = fcntl(stdout_fd_, F_GETFL, 0); const auto flags = fcntl(stdout_fd_, F_GETFL, 0);
if (flags == -1 || fcntl(stdout_fd_, F_SETFL, flags | O_NONBLOCK) == -1) { if (flags == -1 || fcntl(stdout_fd_, F_SETFL, flags | O_NONBLOCK) == -1) {