From: Michael Tremer Date: Mon, 6 Oct 2025 16:59:01 +0000 (+0000) Subject: command: Kill commands after 30 seconds X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f9f1751fc96ba16a1c48108d7da83332fbf8ff7d;p=telemetry.git command: Kill commands after 30 seconds Signed-off-by: Michael Tremer --- diff --git a/src/daemon/command.c b/src/daemon/command.c index 4481f9e..5fdd2fe 100644 --- a/src/daemon/command.c +++ b/src/daemon/command.c @@ -31,8 +31,12 @@ #include "command.h" #include "ctx.h" +#include "time.h" #include "util.h" +// By default, commands are being killed after 30 seconds +#define DEFAULT_TIMEOUT SEC_TO_USEC(30) + struct collecty_command { collecty_ctx* ctx; int nrefs; @@ -43,6 +47,9 @@ struct collecty_command { // Loop sd_event* loop; + // Timeout + uint64_t timeout; + // pidfd int pidfd; @@ -71,6 +78,7 @@ struct collecty_command { sd_event_source* stdout; sd_event_source* stderr; sd_event_source* exit; + sd_event_source* timeout; } events; }; @@ -78,6 +86,10 @@ static inline int clone3(struct clone_args* args, size_t size) { return syscall(__NR_clone3, args, size); } +static inline int pidfd_send_signal(int pidfd, int sig, siginfo_t* info, unsigned int flags) { + return syscall(SYS_pidfd_send_signal, pidfd, sig, info, flags); +} + static void collecty_command_close_pipe(int fds[2]) { for (unsigned int i = 0; i < 2; i++) { if (fds[i] >= 0) { @@ -105,6 +117,8 @@ static void collecty_command_free(collecty_command* self) { free(self->stderr.buffer); // Free events + if (self->events.timeout) + sd_event_source_unref(self->events.timeout); if (self->events.exit) sd_event_source_unref(self->events.exit); if (self->events.stdout) @@ -143,6 +157,9 @@ int collecty_command_create(collecty_command** command, // Fetch a reference to the event loop self->loop = collecty_daemon_loop(daemon); + // Set default timeout + self->timeout = DEFAULT_TIMEOUT; + // Initialize pidfd self->pidfd = -EBADF; @@ -202,6 +219,10 @@ collecty_command* collecty_command_unref(collecty_command* self) { return NULL; } +void collecty_command_set_timeout(collecty_command* self, uint64_t timeout) { + self->timeout = timeout; +} + void collecty_command_on_success(collecty_command* self, collecty_command_success_callback callback, void* data) { self->callbacks.on_success = callback; @@ -358,6 +379,27 @@ ERROR: return r; } +static int collecty_command_timeout(sd_event_source* source, uint64_t usec, void* data) { + collecty_command* self = data; + int r; + + // Log action + DEBUG(self->ctx, "Command has timed out\n"); + + // Skip this if we don't have a pidfd + if (self->pidfd < 0) + return 0; + + // Send SIGKILL to the command + r = pidfd_send_signal(self->pidfd, SIGKILL, NULL, 0); + if (r < 0) { + ERROR(self->ctx, "Failed to kill command: %m\n"); + return -errno; + } + + return 0; +} + static int collecty_command_parent(collecty_command* self) { int fd = -EBADF; int r; @@ -394,7 +436,15 @@ static int collecty_command_parent(collecty_command* self) { } } - DEBUG(self->ctx, "Parent has finished\n"); + // Set the timeout + if (self->timeout) { + r = sd_event_add_time_relative(self->loop, &self->events.timeout, + CLOCK_MONOTONIC, self->timeout, 0, collecty_command_timeout, self); + if (r < 0) { + ERROR(self->ctx, "Failed to setup timer: %s\n", strerror(-r)); + return r; + } + } return r; } diff --git a/src/daemon/command.h b/src/daemon/command.h index 1864e31..46bfa1e 100644 --- a/src/daemon/command.h +++ b/src/daemon/command.h @@ -32,6 +32,9 @@ int collecty_command_create(collecty_command** command, collecty_command* collecty_command_ref(collecty_command* self); collecty_command* collecty_command_unref(collecty_command* self); +// Timeout +void collecty_command_set_timeout(collecty_command* self, uint64_t timeout); + typedef int (*collecty_command_success_callback)(collecty_ctx* ctx, int rc, const char* output, const size_t length, void* data);