diff options
author | turret <turret@duck.com> | 2024-03-30 16:04:45 -0500 |
---|---|---|
committer | turret <turret@duck.com> | 2024-03-30 16:04:45 -0500 |
commit | 80a67b7d20393a29aa5d2cb92197f3381be7fd96 (patch) | |
tree | f0c313da5ef509e79e5067972edd91976513ce0e /util/init.c | |
parent | f01745a2ee84f11b8cc54e37c5f7f596184ab785 (diff) | |
download | discord-bot-skeleton-80a67b7d20393a29aa5d2cb92197f3381be7fd96.tar.gz discord-bot-skeleton-80a67b7d20393a29aa5d2cb92197f3381be7fd96.tar.bz2 discord-bot-skeleton-80a67b7d20393a29aa5d2cb92197f3381be7fd96.zip |
*: 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
Diffstat (limited to 'util/init.c')
-rw-r--r-- | util/init.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/util/init.c b/util/init.c new file mode 100644 index 0000000..77cd4eb --- /dev/null +++ b/util/init.c @@ -0,0 +1,200 @@ +#include <fcntl.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <curl/curl.h> + +#include <dbs/init.h> +#include <dbs/log.h> +#include <dbs/util.h> + +extern int subsystem_handle_term(int pid); +extern int subsystem_count; +int mainpid = 0; +long stack_size = 8192 * 512; + +/* For some reason, I get SIGSEGV'd when running because a random-ass + byte was inserted where it isnt supposed to be. Added a safety byte + because I cannot be asked to try to figure out how to do this cleanly. */ +static unsigned long __1bsafebuf + __attribute__((used)) __attribute__((section(".1bsafebuf.init"))) = 0; + +/* We start initcall levels at [1] instead of [0], so we must adjust + in code for this minor design choice. Math is done on the level passed + through i.e. do_initcall_level so that you can call it with (1) and have + the expected initcall (l1_initcall) run. */ +extern initcall_entry_t __initcall1_start[]; +extern initcall_entry_t __initcall2_start[]; +extern initcall_entry_t __initcall3_start[]; +extern initcall_entry_t __initcall4_start[]; +extern initcall_entry_t __initcall5_start[]; +extern initcall_entry_t __initcall_end[]; + +static initcall_entry_t *initcall_levels[] = { + __initcall1_start, + __initcall2_start, + __initcall3_start, + __initcall4_start, + __initcall5_start, + __initcall_end, +}; + +static void do_initcall_level(int level) +{ + initcall_entry_t *fn; + + for (fn = initcall_levels[level - 1]; + fn < initcall_levels[level]; + fn++) + initcall_from_entry(fn)(); +} + +static void do_initcalls(void) +{ + unsigned long level; + for (level = 1; level < ARRAY_SIZE(initcall_levels); level++) { + do_initcall_level(level); + } +} + +static void doenv(char *path) +{ + int fd = open(path, O_RDONLY); + if(fd < 0) + return; + + struct stat statbuf; + if(fstat(fd, &statbuf) < 0) + return; + + char *file_mmap = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if(file_mmap == NULL) + return; + + char *file = malloc(statbuf.st_size + 1); + file[statbuf.st_size + 1] = 0; + memcpy(file, file_mmap, statbuf.st_size); + munmap(file_mmap, statbuf.st_size); + + int offset = 0; + while(1) { + char *line = &(file[offset]); + if(*line == '\0') + break; + + char *eol = strchrnul(line, '\n'); + *eol = '\0'; + if(*line == '#') + goto nextline; + + char *divider = strchr(line, '='); + if(divider == NULL) + goto nextline; + + *divider = '\0'; + setenv(line, divider + 1, 0); + +nextline: + offset += (eol - line) + 1; + continue; + } + + free(file); +} + +int main(void) +{ + /* Hello, World! */ + + /* set mainpid for the subsystem service so it is fully accessible + during l1 */ + mainpid = getpid(); + + /* set stack_size for subsystem service */ + struct rlimit *stack_rlimit = malloc(sizeof(struct rlimit)); + getrlimit(RLIMIT_STACK, stack_rlimit); + if(stack_rlimit->rlim_cur != RLIM_INFINITY) { + stack_size = MIN(stack_rlimit->rlim_cur, stack_size); + } + free(stack_rlimit); + + /* configure signal handlers early to prevent race condition where subsystems + can terminate main process on accident, and disable Terminated output during + early-mode panic */ + static sigset_t set; + sigaddset(&set, SIGCHLD); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigprocmask(SIG_BLOCK, &set, NULL); + + /* use .env files if present */ + doenv(".env"); + + /* find directory of self and use env from there if it exists */ + { + char *buf = calloc(PATH_MAX, sizeof(char)); + ssize_t self_size = readlink("/proc/self/exe", buf, PATH_MAX); + if(self_size + strlen(".env") + 1 > PATH_MAX) + goto skip_self; + + char *lastslash = strrchr(buf, '/'); + *lastslash = '\0'; + + char *cwd = get_current_dir_name(); + int cwd_is_exec_dir = strcmp(buf, cwd) == 0; + free(cwd); + if(cwd_is_exec_dir) + goto skip_self; + + strcat(buf, "/.env"); + doenv(buf); +skip_self: + free(buf); + } + + /* init curl */ + if(curl_global_init(CURL_GLOBAL_DEFAULT)) + panic("init: curl init failed"); + + /* init random seed */ + srand(time(NULL)); + + /* Perform initcalls */ + do_initcalls(); + + /* Reaper. Much like init. */ + + siginfo_t siginfo; + while(subsystem_count > 0) { + sigwaitinfo(&set, &siginfo); + int sig = siginfo.si_signo; + switch(sig) { + case SIGCHLD: ; + int process = 0; + while((process = waitpid(-1, NULL, WNOHANG)) > 0) + if(subsystem_handle_term(process) > 0) + print(LOG_WARNING "init: failed to reap process %d", + process); + if(siginfo.si_status != 0) { + panic("init: process %d exited with non-zero status (%d)", siginfo.si_pid, siginfo.si_status); + } + break; + case SIGINT: + panic("init: keyboard interrupt"); + break; + case SIGTERM: + exit(0); + break; + default: + break; + } + } + + panic("init: no more subsystems"); +} |