272 lines
12 KiB
C
Raw Normal View History

2026-01-29 00:38:21 +01:00
// retoor <retoor@molodetz.nl>
#include "tool.h"
2026-01-29 06:01:05 +01:00
#include "r_config.h"
2026-01-29 00:38:21 +01:00
#include "bash_executor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2026-01-29 07:42:06 +01:00
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
2026-01-29 00:38:21 +01:00
static struct json_object *process_monitor_get_description(void);
static char *process_monitor_execute(tool_t *self, struct json_object *args);
static void process_monitor_print_action(const char *name, struct json_object *args);
2026-01-29 07:42:06 +01:00
static struct json_object *process_status_get_description(void);
static char *process_status_execute(tool_t *self, struct json_object *args);
static struct json_object *process_terminate_get_description(void);
static char *process_terminate_execute(tool_t *self, struct json_object *args);
2026-01-29 00:38:21 +01:00
static const tool_vtable_t process_monitor_vtable = {
.get_description = process_monitor_get_description,
.execute = process_monitor_execute,
.print_action = process_monitor_print_action
};
2026-01-29 07:42:06 +01:00
static const tool_vtable_t process_status_vtable = {
.get_description = process_status_get_description,
.execute = process_status_execute,
.print_action = NULL
};
static const tool_vtable_t process_terminate_vtable = {
.get_description = process_terminate_get_description,
.execute = process_terminate_execute,
.print_action = NULL
};
2026-01-29 00:38:21 +01:00
static tool_t process_monitor_tool = { .vtable = &process_monitor_vtable, .name = "process_monitor" };
2026-01-29 07:42:06 +01:00
static tool_t process_status_tool = { .vtable = &process_status_vtable, .name = "process_get_status" };
static tool_t process_terminate_tool = { .vtable = &process_terminate_vtable, .name = "process_terminate" };
2026-01-29 00:38:21 +01:00
tool_t *tool_process_monitor_create(void) { return &process_monitor_tool; }
2026-01-29 07:42:06 +01:00
tool_t *tool_process_get_status_create(void) { return &process_status_tool; }
tool_t *tool_process_terminate_create(void) { return &process_terminate_tool; }
2026-01-29 00:38:21 +01:00
static void process_monitor_print_action(const char *name, struct json_object *args) {
(void)name;
struct json_object *action;
if (json_object_object_get_ex(args, "action", &action)) {
fprintf(stderr, " -> Process monitor: %s\n", json_object_get_string(action));
}
}
static char *process_monitor_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *action_obj;
if (!json_object_object_get_ex(args, "action", &action_obj)) {
return strdup("Error: missing 'action' argument (list or kill)");
}
const char *action = json_object_get_string(action_obj);
if (strcmp(action, "list") == 0) {
2026-01-29 07:42:06 +01:00
struct json_object *filter_obj;
if (json_object_object_get_ex(args, "filter", &filter_obj)) {
char cmd[512];
snprintf(cmd, sizeof(cmd), "ps aux | grep -i '%s' | grep -v grep", json_object_get_string(filter_obj));
return r_bash_execute(cmd, false, 300);
}
return r_bash_execute("ps aux --sort=-%cpu | head -n 20", false, 300);
2026-01-29 00:38:21 +01:00
} else if (strcmp(action, "kill") == 0) {
struct json_object *pid_obj;
if (!json_object_object_get_ex(args, "pid", &pid_obj)) {
return strdup("Error: missing 'pid' for kill action");
}
char cmd[256];
2026-01-29 07:42:06 +01:00
snprintf(cmd, sizeof(cmd), "kill -9 %d 2>&1", json_object_get_int(pid_obj));
2026-01-29 06:01:05 +01:00
return r_bash_execute(cmd, false, 300);
2026-01-29 00:38:21 +01:00
}
return strdup("Error: unknown action");
}
2026-01-29 07:42:06 +01:00
static char *process_status_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *pid_obj;
if (!json_object_object_get_ex(args, "pid", &pid_obj)) return strdup("Error: missing 'pid'");
int pid = json_object_get_int(pid_obj);
int status;
bool running = true;
int exit_status = -1;
pid_t ret = waitpid(pid, &status, WNOHANG);
if (ret == pid) {
running = false;
exit_status = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
} else if (ret == -1) {
running = (kill(pid, 0) == 0);
}
char log_path[256];
snprintf(log_path, sizeof(log_path), "/tmp/r_process_%d.log", pid);
char *content = NULL;
FILE *f = fopen(log_path, "r");
if (f) {
fseek(f, 0, SEEK_END);
long size = ftell(f);
rewind(f);
if (size >= 0) {
content = malloc((size_t)size + 1);
if (content) {
size_t rs = fread(content, 1, (size_t)size, f);
content[rs] = '\0';
}
}
fclose(f);
}
struct json_object *root = json_object_new_object();
json_object_object_add(root, "pid", json_object_new_int(pid));
json_object_object_add(root, "is_running", json_object_new_boolean(running));
json_object_object_add(root, "output", json_object_new_string(content ? content : ""));
if (!running) {
json_object_object_add(root, "exit_status", json_object_new_int(exit_status));
}
if (content && *content) {
char *copy = strdup(content);
char *saveptr;
char *line = strtok_r(copy, "\n", &saveptr);
while (line) {
fprintf(stdout, "[%d]\t %s\n", pid, line);
line = strtok_r(NULL, "\n", &saveptr);
}
fflush(stdout);
free(copy);
}
char *out_str = strdup(json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY));
json_object_put(root);
free(content);
return out_str;
}
static char *process_terminate_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *pid_obj;
if (!json_object_object_get_ex(args, "pid", &pid_obj)) return strdup("Error: missing 'pid'");
int pid = json_object_get_int(pid_obj);
kill(pid, SIGTERM);
usleep(100000);
if (kill(pid, 0) == 0) kill(pid, SIGKILL);
char log_path[256];
snprintf(log_path, sizeof(log_path), "/tmp/r_process_%d.log", pid);
unlink(log_path);
return strdup("Process terminated and logs cleaned up.");
}
2026-01-29 00:38:21 +01:00
static struct json_object *process_monitor_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("process_monitor"));
2026-01-29 07:42:06 +01:00
json_object_object_add(function, "description", json_object_new_string("Monitor system processes. Use 'list' to see running processes (optionally with 'filter') and 'kill' to stop one."));
2026-01-29 00:38:21 +01:00
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *action = json_object_new_object();
json_object_object_add(action, "type", json_object_new_string("string"));
2026-01-29 07:42:06 +01:00
json_object_object_add(action, "description", json_object_new_string("Action: 'list' or 'kill'."));
2026-01-29 00:38:21 +01:00
json_object_object_add(properties, "action", action);
2026-01-29 07:42:06 +01:00
struct json_object *filter = json_object_new_object();
json_object_object_add(filter, "type", json_object_new_string("string"));
json_object_object_add(filter, "description", json_object_new_string("Optional grep filter for 'list' action."));
json_object_object_add(properties, "filter", filter);
2026-01-29 00:38:21 +01:00
struct json_object *pid = json_object_new_object();
json_object_object_add(pid, "type", json_object_new_string("integer"));
2026-01-29 07:42:06 +01:00
json_object_object_add(pid, "description", json_object_new_string("PID for 'kill' action. Use 0 if not killing."));
2026-01-29 00:38:21 +01:00
json_object_object_add(properties, "pid", pid);
2026-01-29 07:42:06 +01:00
struct json_object *as = json_object_new_object();
json_object_object_add(as, "type", json_object_new_string("boolean"));
json_object_object_add(as, "description", json_object_new_string("Not used for monitor but required for strict compliance."));
json_object_object_add(properties, "async", as);
2026-01-29 00:38:21 +01:00
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("action"));
2026-01-29 07:42:06 +01:00
json_object_array_add(required, json_object_new_string("filter"));
2026-01-29 06:01:05 +01:00
json_object_array_add(required, json_object_new_string("pid"));
2026-01-29 07:42:06 +01:00
json_object_array_add(required, json_object_new_string("async"));
2026-01-29 00:38:21 +01:00
json_object_object_add(parameters, "required", required);
2026-01-29 06:01:05 +01:00
json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0));
2026-01-29 00:38:21 +01:00
json_object_object_add(function, "parameters", parameters);
2026-01-29 06:01:05 +01:00
r_config_handle cfg = r_config_get_instance();
2026-01-29 07:42:06 +01:00
if (r_config_use_strict(cfg)) json_object_object_add(function, "strict", json_object_new_boolean(1));
2026-01-29 00:38:21 +01:00
json_object_object_add(root, "function", function);
return root;
}
2026-01-29 07:42:06 +01:00
static struct json_object *process_status_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *f = json_object_new_object();
json_object_object_add(f, "name", json_object_new_string("process_get_status"));
json_object_object_add(f, "description", json_object_new_string("Get status, exit code, and logs of ANY background process (Python or Shell) by PID."));
struct json_object *p = json_object_new_object();
json_object_object_add(p, "type", json_object_new_string("object"));
struct json_object *props = json_object_new_object();
struct json_object *pid = json_object_new_object();
json_object_object_add(pid, "type", json_object_new_string("integer"));
json_object_object_add(props, "pid", pid);
struct json_object *as = json_object_new_object();
json_object_object_add(as, "type", json_object_new_string("boolean"));
json_object_object_add(as, "description", json_object_new_string("Required for strict mode."));
json_object_object_add(props, "async", as);
json_object_object_add(p, "properties", props);
struct json_object *req = json_object_new_array();
json_object_array_add(req, json_object_new_string("pid"));
json_object_array_add(req, json_object_new_string("async"));
json_object_object_add(p, "required", req);
json_object_object_add(p, "additionalProperties", json_object_new_boolean(0));
json_object_object_add(f, "parameters", p);
r_config_handle cfg = r_config_get_instance();
if (r_config_use_strict(cfg)) json_object_object_add(f, "strict", json_object_new_boolean(1));
json_object_object_add(root, "function", f);
return root;
}
static struct json_object *process_terminate_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *f = json_object_new_object();
json_object_object_add(f, "name", json_object_new_string("process_terminate"));
json_object_object_add(f, "description", json_object_new_string("Terminate ANY background process (Python or Shell) and clean up."));
struct json_object *p = json_object_new_object();
json_object_object_add(p, "type", json_object_new_string("object"));
struct json_object *props = json_object_new_object();
struct json_object *pid = json_object_new_object();
json_object_object_add(pid, "type", json_object_new_string("integer"));
json_object_object_add(props, "pid", pid);
struct json_object *as = json_object_new_object();
json_object_object_add(as, "type", json_object_new_string("boolean"));
json_object_object_add(as, "description", json_object_new_string("Required for strict mode."));
json_object_object_add(props, "async", as);
json_object_object_add(p, "properties", props);
struct json_object *req = json_object_new_array();
json_object_array_add(req, json_object_new_string("pid"));
json_object_array_add(req, json_object_new_string("async"));
json_object_object_add(p, "required", req);
json_object_object_add(p, "additionalProperties", json_object_new_boolean(0));
json_object_object_add(f, "parameters", p);
r_config_handle cfg = r_config_get_instance();
if (r_config_use_strict(cfg)) json_object_object_add(f, "strict", json_object_new_boolean(1));
json_object_object_add(root, "function", f);
return root;
}