#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;
// Loop
sd_event* loop;
+ // Timeout
+ uint64_t timeout;
+
// pidfd
int pidfd;
sd_event_source* stdout;
sd_event_source* stderr;
sd_event_source* exit;
+ sd_event_source* timeout;
} events;
};
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) {
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)
// 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;
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;
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;
}
}
- 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;
}