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:
committed by
Austin Horstman
parent
f987c24144
commit
1b6173ddda
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user