summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2023-07-02 19:33:33 +0200
committercbdev <cb@cbcdn.com>2023-07-02 19:33:33 +0200
commitc52942f22f1b371c4a8d4a06bf075e0ba7b95ec7 (patch)
tree53ad2d25375f949d60068c5f6e306cd74b9a6b29
parent2b3f7614188d766db3d31a54e7d4e2c57ebab93a (diff)
downloadnfcommander-c52942f22f1b371c4a8d4a06bf075e0ba7b95ec7.tar.gz
nfcommander-c52942f22f1b371c4a8d4a06bf075e0ba7b95ec7.tar.bz2
nfcommander-c52942f22f1b371c4a8d4a06bf075e0ba7b95ec7.zip
Basic command handling
-rw-r--r--command.c185
-rw-r--r--command.h4
-rw-r--r--nfcommander.c20
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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#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 <signal.h>
#include <sys/epoll.h>
#include <unistd.h>
+#include <errno.h>
#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