From 1b6173ddda9b2571ec0a754534fb8564d79aa1d1 Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Mon, 9 Mar 2026 08:00:27 -0500 Subject: [PATCH] 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 --- src/util/command_line_stream.cpp | 50 +++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/util/command_line_stream.cpp b/src/util/command_line_stream.cpp index aeeedfaf..7abb79b8 100644 --- a/src/util/command_line_stream.cpp +++ b/src/util/command_line_stream.cpp @@ -23,33 +23,42 @@ namespace { -void prepareChild(const std::string& output_name) { +auto buildChildEnvironment(const std::string& output_name) -> std::vector { + auto names = Glib::listenv(); + std::vector 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; sigfillset(&mask); - const auto err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr); - if (err != 0) { - spdlog::error("pthread_sigmask in LineStream failed: {}", std::strerror(err)); - } + (void)pthread_sigmask(SIG_UNBLOCK, &mask, nullptr); int deathsig = SIGTERM; #ifdef __linux__ - if (prctl(PR_SET_PDEATHSIG, deathsig) != 0) { - spdlog::error("prctl(PR_SET_PDEATHSIG) in LineStream failed: {}", std::strerror(errno)); - } + (void)prctl(PR_SET_PDEATHSIG, deathsig); #endif #ifdef __FreeBSD__ - if (procctl(P_PID, 0, PROC_PDEATHSIG_CTL, reinterpret_cast(&deathsig)) == -1) { - spdlog::error("procctl(PROC_PDEATHSIG_CTL) in LineStream failed: {}", std::strerror(errno)); - } + (void)procctl(P_PID, 0, PROC_PDEATHSIG_CTL, reinterpret_cast(&deathsig)); #endif - if (setpgid(0, 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)setpgid(0, 0); } void emitBufferedLines(std::string& buffer, @@ -91,9 +100,10 @@ void waybar::util::command::LineStream::start(const std::string& cmd) { stop(); std::vector argv{"/bin/sh", "-c", cmd}; - Glib::spawn_async_with_pipes("", argv, Glib::SPAWN_DO_NOT_REAP_CHILD | Glib::SPAWN_CLOEXEC_PIPES, - sigc::bind(sigc::ptr_fun(&prepareChild), output_name_), &pid_, - nullptr, &stdout_fd_, nullptr); + auto envp = buildChildEnvironment(output_name_); + Glib::spawn_async_with_pipes("", argv, envp, + 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); if (flags == -1 || fcntl(stdout_fd_, F_SETFL, flags | O_NONBLOCK) == -1) {