From c52942f22f1b371c4a8d4a06bf075e0ba7b95ec7 Mon Sep 17 00:00:00 2001 From: cbdev Date: Sun, 2 Jul 2023 19:33:33 +0200 Subject: Basic command handling --- command.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- command.h | 4 ++ nfcommander.c | 20 ++++++- 3 files changed, 204 insertions(+), 5 deletions(-) diff --git a/command.c b/command.c index c7a7be8..17aa5ff 100644 --- a/command.c +++ b/command.c @@ -1,14 +1,195 @@ #include +#include +#include +#include +#include +#include "nfcommander.h" #include "command.h" +#include "config.h" + +#define COMMAND_ALIVE 1 +#define COMMAND_STOPPED 2 + +#define INPUT_BUFFER_MAX 4096 + +typedef struct { + uint8_t flags; + pid_t child; + int iopipe[2]; + nfc_tag_info_t* tag; +} command_t; + +static size_t ncommands = 0; +static command_t* commands = NULL; int command_handle(int fd){ + size_t n = 0; + ssize_t bytes; + uint8_t input_buffer[INPUT_BUFFER_MAX]; + + //find matching command + for(n = 0; n < ncommands; n++){ + if(commands[n].flags & COMMAND_ALIVE + && fd == commands[n].iopipe[0]){ + bytes = read(fd, input_buffer, sizeof(input_buffer)); + if(bytes < 0){ + perror("command/recv"); + } + else if(bytes == 0){ + printf("Command %lu pipe closed\n", n); + core_manage_fd(commands[n].iopipe[0], 0, system_command); + close(commands[n].iopipe[0]); + commands[n].iopipe[0] = -1; + } + else{ + printf("%d bytes from command %lu\n", bytes, n); + } + return 0; + } + } + + printf("Unhandled command fd\n"); + return 1; +} + +void command_reap(){ //TODO - printf("Handling data on command fd\n"); + printf("Reaping children\n"); +} + +static int command_spawn(command_t* cmd, char* command_name, char* command_static, size_t arg_length){ + char* workdir = config_get("command", "chdir"); + char* handler = config_get("command", "handler"); + + printf("Starting command %s, static %s\n", command_name, command_static); + if(pipe(cmd->iopipe)){ + perror("cmd/pipe"); + return 1; + } + + cmd->child = fork(); + switch(cmd->child){ + case -1: + perror("cmd/fork"); + return 1; + case 0: + //child + if(workdir && chdir(workdir)){ + perror("child/chdir"); + _exit(1); + } + + //connect stdout + while((dup2(cmd->iopipe[1], STDOUT_FILENO) == -1) && (errno == EINTR)) { + } + close(cmd->iopipe[1]); + close(cmd->iopipe[0]); + execl(command_name, command_static, NULL); + perror("cmd/exec"); + _exit(1); + default: + //parent + cmd->flags |= COMMAND_ALIVE; + close(cmd->iopipe[1]); + core_manage_fd(cmd->iopipe[0], 1, system_command); + } + + return 0; +} + +int command_start(nfc_tag_info_t* info){ + size_t n = 0, p = ncommands, arg_length = 0; + uint8_t* command_name = NULL, *command_static = NULL; + + for(n = 0; n < ncommands; n++){ + //if command already in list, do nothing + if(commands[n].tag == info){ + //this should not normally happen + return 0; + } + + //mark available slot + if(!commands[n].tag && !commands[n].flags){ + p = n; + } + } + + //cant run without an actual command + if(!info->static_data || !info->static_length){ + printf("Tag contains no command data\n"); + return 0; + } + + //parse out command data + command_name = calloc(info->static_length + 1, sizeof(uint8_t)); + if(!command_name){ + printf("Failed to allocate memory\n"); + return 1; + } + memcpy(command_name, info->static_data, info->static_length); + for(n = 0; n < info->static_length; n++){ + if(!isalnum(command_name[n])){ + command_name[n] = 0; + if(info->static_length - n > 1){ + command_static = command_name + n + 1; + arg_length = info->static_length - n - 1; + } + break; + } + } + //FIXME might want to parse out any non-graphs + + if(p == ncommands){ + commands = realloc(commands, (p + 1) * sizeof(command_t)); + if(!commands){ + ncommands = 0; + printf("Failed to allocate memory\n"); + goto bail; + } + memset(commands + p, 0, sizeof(command_t)); + ncommands++; + } + + commands[p].tag = info; + if(command_spawn(commands + p, (char*) command_name, (char*) command_static, arg_length)){ + //TODO clean up and free command instance + } + +bail: + free(command_name); + return 0; +} + +int command_stop(nfc_tag_info_t* info){ + size_t n = 0; + + for(n = 0; n < ncommands; n++){ + if(commands[n].tag == info){ + commands[n].tag = NULL; + if(commands[n].flags & COMMAND_ALIVE){ + //TODO stop running command + commands[n].flags |= COMMAND_STOPPED; + } + } + } + return 0; } void command_free(){ - //TODO + size_t n = 0; + printf("Shutting down any remaining commands\n"); + for(n = 0; n < ncommands; n++){ + if(commands[n].flags & COMMAND_ALIVE){ + //TODO stop command, terminate command + } + + //TODO free allocated data + } + + ncommands = 0; + free(commands); + commands = NULL; } diff --git a/command.h b/command.h index 7bae5ae..6c56651 100644 --- a/command.h +++ b/command.h @@ -1,2 +1,6 @@ int command_handle(int fd); +int command_start(nfc_tag_info_t* info); +int command_stop(nfc_tag_info_t* info); +void command_reap(); void command_free(); + diff --git a/nfcommander.c b/nfcommander.c index 50cbda7..66838aa 100644 --- a/nfcommander.c +++ b/nfcommander.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "nfcommander.h" #include "config.h" @@ -18,10 +19,16 @@ typedef union { } epoll_private_t; static volatile sig_atomic_t shutdown_requested = 0; +static volatile sig_atomic_t pid_signaled = 0; static int epoll_fd = -1; static void signal_handler(int signum){ - shutdown_requested = 1; + if(signum == SIGCHLD){ + pid_signaled = 1; + } + else { + shutdown_requested = 1; + } } static int usage(char* fn){ @@ -47,7 +54,7 @@ int core_manage_fd(int fd, int manage, notification_target_t system){ } if(epoll_ctl(epoll_fd, manage ? EPOLL_CTL_ADD : EPOLL_CTL_DEL, fd, &event)){ - fprintf(stderr, "Failed to modify epoll instance\n"); + perror("core/epoll_mod"); shutdown_requested = 1; return 1; } @@ -67,7 +74,7 @@ int main(int argc, char** argv){ struct epoll_event events[10]; epoll_fd = epoll_create1(EPOLL_CLOEXEC); if(epoll_fd < 0){ - printf("Failed to create epoll instance\n"); + perror("core/epoll"); return EXIT_FAILURE; } @@ -93,12 +100,14 @@ int main(int argc, char** argv){ //handle signals signal(SIGINT, signal_handler); + signal(SIGCHLD, signal_handler); signal(SIGPIPE, SIG_IGN); //handle events while(!shutdown_requested){ event_count = epoll_wait(epoll_fd, events, sizeof(events) / sizeof(struct epoll_event), 1000); if(event_count < 0){ + perror("core/poll"); break; } @@ -120,6 +129,11 @@ int main(int argc, char** argv){ break; } } + + if(pid_signaled){ + pid_signaled = 0; + command_reap(); + } } //clean up -- cgit v1.2.3