From 80a67b7d20393a29aa5d2cb92197f3381be7fd96 Mon Sep 17 00:00:00 2001 From: turret Date: Sat, 30 Mar 2024 16:04:45 -0500 Subject: *: directory changes since this project is a skeleton and not meant to clutter up the code that will actually consume the bot, i've opted to consolidate the majority of files under a single directory and minimise extra files *: move code to util/ *: move include files to include/dbs/ net: consolidate net functions into single file config: remove config --- util/subsys.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 util/subsys.c (limited to 'util/subsys.c') diff --git a/util/subsys.c b/util/subsys.c new file mode 100644 index 0000000..a2dc057 --- /dev/null +++ b/util/subsys.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_SUBSYSTEMS 32 +#define MAX_RESPAWN 3 + +struct subsystem_info { + char *fn_name; + int (*fn)(void); + int pid; + void *stack; + char mode; + int respawn_count; +}; + +extern long stack_size; +extern int mainpid; +static struct subsystem_info *subsystems[MAX_SUBSYSTEMS + 1]; +int subsystem_count = 0; + +static int __subsystem_entry(struct subsystem_info *info) +{ + /* entry point from clone(). we setup the process name so we know + what we are looking at from a glance in a ps view or htop or + whatever. */ + char *name = malloc(16 * sizeof(char)); + snprintf(name, 16, "DBS: %s", info->fn_name); + name[15] = '\0'; + prctl(PR_SET_NAME, name); + free(name); + + /* clear signal handlers so SIGTERM is no longer caught */ + static sigset_t set; + sigprocmask(SIG_SETMASK, &set, NULL); + + int ret = info->fn(); + + return ret; +} + +char *subsystem_get_name(int pid) +{ + for(int i = 0; i < MAX_SUBSYSTEMS; ++i) { + struct subsystem_info *subsystem = subsystems[i]; + if(!subsystem || subsystem->pid != pid) + continue; + + return subsystem->fn_name; + } + return 0; +} + +int subsystem_change_mode(int pid, char mode) +{ + for(int i = 0; i < MAX_SUBSYSTEMS; ++i) { + struct subsystem_info *subsystem = subsystems[i]; + if(!subsystem || subsystem->pid != pid) + continue; + + subsystem->mode = mode; + return 0; + } + + return 1; +} + +int subsystem_handle_term(int pid) +{ + for(int i = 0; i < MAX_SUBSYSTEMS; ++i) { + struct subsystem_info *subsystem = subsystems[i]; + if(!subsystem || subsystem->pid != pid) + continue; + + if(subsystem->mode == PANICMODE_RESPAWN + && subsystem->respawn_count < MAX_RESPAWN) { + ++(subsystem->respawn_count); + + int pid = clone((int (*)(void *))__subsystem_entry, + (void *)((long)(subsystem->stack) + stack_size), + CLONE_FILES | CLONE_VM | SIGCHLD, subsystem); + subsystem->pid = pid; + if(pid < 0) { + print(LOG_CRIT "subsys: cannot re-start subsystem %s: " + "clone failed (errno %d)", subsystem->fn_name, errno); + if(munmap(subsystem->stack, stack_size) < 0) + print(LOG_CRIT "subsys: failed to deallocate " + "stack for subsystem %s (%d) (errno %d)", + subsystem->fn_name, pid, errno); + free(subsystem); + return 0; + } + + subsystem->mode = 'o'; + return 0; + } else if(subsystem->mode == PANICMODE_RESPAWN) { + panic("subsys: exceeded maximum respawn count for subsystem " + "%s (%d)", subsystem->fn_name, subsystem->pid); + } + + if(munmap(subsystem->stack, stack_size) < 0) + print(LOG_CRIT "subsys: failed to deallocate stack " + "for subsystem %s (%d) (errno %d)", + subsystem->fn_name, pid, errno); + subsystems[i] = 0; + --subsystem_count; + free(subsystem); + + return 0; + } + + return 1; +} + +int __impl_start_subsystem(char *fn_name, int (*fn)(void)) +{ + if(getpid() != mainpid) { + print(LOG_CRIT "subsys: cannot perform subsystem inception " + "(attempted from %d)", getpid()); + return 1; + } + if(subsystem_count >= MAX_SUBSYSTEMS) { + print(LOG_CRIT "subsys: cannot start subsystem %s: " + "reached maximum number of subsystems", fn_name); + return 1; + } + + /* because CLONE_VM is being set, our stack is not duplicated and + therefore we need to map a stack */ + void *stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_GROWSDOWN | MAP_STACK | MAP_PRIVATE, -1, 0); + if((long)stack <= 0) { + print(LOG_CRIT "subsys: cannot start subsystem %s: " + "failed to allocate stack (errno %d)", fn_name, errno); + return 1; + } + + /* the libc gods have graced us with the ability to pass one (1) arg + to the function. struct required. the absence of a free is not a + memory leak because we free it above. */ + struct subsystem_info *info = malloc(sizeof(struct subsystem_info)); + info->fn_name = fn_name; + info->fn = fn; + info->stack = stack; + info->mode = 'o'; + info->respawn_count = 0; + + int pid = clone((int (*)(void *))__subsystem_entry, + (void *)((long)stack + stack_size), + CLONE_FILES | CLONE_VM | SIGCHLD, info); + info->pid = pid; + if(pid < 0) { + print(LOG_CRIT "subsys: cannot start subsystem %s: " + "clone failed (errno %d)", fn_name, errno); + munmap(stack, stack_size); + free(info); + return 1; + } + + for(int i = 0; i < MAX_SUBSYSTEMS; ++i) { + if(!subsystems[i]) { + subsystems[i] = info; + ++subsystem_count; + break; + } + } + + return 0; +} -- cgit v1.2.3