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 ) ) ;
2026-01-29 07:52:58 +01:00
char * final_output = NULL ;
if ( ! running ) {
if ( asprintf ( & final_output , " [Final Output Captured] \n %s " , content ? content : " " ) = = - 1 ) {
final_output = strdup ( content ? content : " " ) ;
}
} else {
final_output = strdup ( content ? content : " " ) ;
}
json_object_object_add ( root , " output " , json_object_new_string ( final_output ) ) ;
2026-01-29 07:42:06 +01:00
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 ) ;
2026-01-29 07:52:58 +01:00
free ( final_output ) ;
2026-01-29 07:42:06 +01:00
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 ;
}