aboutsummaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorturret <turret@duck.com>2024-03-30 16:04:45 -0500
committerturret <turret@duck.com>2024-03-30 16:04:45 -0500
commit80a67b7d20393a29aa5d2cb92197f3381be7fd96 (patch)
treef0c313da5ef509e79e5067972edd91976513ce0e /init
parentf01745a2ee84f11b8cc54e37c5f7f596184ab785 (diff)
downloaddiscord-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 'init')
-rw-r--r--init/init.c210
-rw-r--r--init/log.c209
-rw-r--r--init/subsys.c180
3 files changed, 0 insertions, 599 deletions
diff --git a/init/init.c b/init/init.c
deleted file mode 100644
index 126442e..0000000
--- a/init/init.c
+++ /dev/null
@@ -1,210 +0,0 @@
-#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 <config.h>
-#include <init.h>
-#include <log.h>
-#include <util.h>
-
-extern int subsystem_handle_term(int pid);
-extern int subsystem_count;
-int mainpid = 0;
-long stack_size = 8192 * 512;
-char *token;
-
-/* 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);
-
- /* fetch token */
- char *token_base = getenv("TOKEN");
- if(!token_base)
- panic("init: cannot find TOKEN in env");
-
- token = calloc(strlen(token_base) + strlen("Authorization: Bot ") + 1,
- sizeof(char));
- strcpy(token, "Authorization: Bot ");
- strcat(token, token_base);
-
- /* init curl */
- if(curl_global_init(CURL_GLOBAL_DEFAULT))
- panic("init: curl init failed");
-
- /* init random seed */
- srand(time(NULL));
-
- /* Rest of the program.. */
- 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");
-}
diff --git a/init/log.c b/init/log.c
deleted file mode 100644
index f39467c..0000000
--- a/init/log.c
+++ /dev/null
@@ -1,209 +0,0 @@
-#include <execinfo.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/file.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <log.h>
-#include <util.h>
-
-extern int subsystem_change_mode(int pid, char mode);
-extern char *subsystem_get_name(int pid);
-extern int mainpid;
-
-static const char *colors[] = {
- [EMERG_LOGLEVEL] = ANSI_BLINK ANSI_REVERSE ANSI_BOLD ANSI_RED,
- [ALERT_LOGLEVEL] = ANSI_REVERSE ANSI_BOLD ANSI_RED,
- [CRIT_LOGLEVEL] = ANSI_BOLD ANSI_RED,
- [ERR_LOGLEVEL] = ANSI_RED,
- [WARNING_LOGLEVEL] = ANSI_BOLD,
- [NOTICE_LOGLEVEL] = ANSI_BRIGHT_WHITE,
- [INFO_LOGLEVEL] = ANSI_RESET,
- [DEBUG_LOGLEVEL] = ANSI_ITALIC ANSI_BRIGHT_BLUE,
-};
-
-static const char *mode_to_string[] = {
- [PANICMODE_DEBUGONLY] = "subsystem OOPS",
- [PANICMODE_RESPAWN] = "subsystem failure",
- [PANICMODE_DIE] = "catastrophic failure",
-};
-
-static int console_lock = 0;
-
-#define MAX_TRY_COUNT 1 << 17
-static void obtain_console_lock(void)
-{
- int try_count = 0;
- register int rax asm("rax");
-retry:
- while(console_lock && try_count <= MAX_TRY_COUNT)
- try_count += 1;
-
- asm("mov %0, 1 \n"
- "xchg %0, %1" : "=r" (rax), "=m" (console_lock));
-
- if(rax > 0 && try_count <= MAX_TRY_COUNT)
- goto retry;
-
- if(try_count > MAX_TRY_COUNT) {
- print(LOG_SOH "\3" "4" "log: broken console lock");
- }
-
- return;
-}
-
-static int vaprint(const char *fmt, va_list ap)
-{
- int loglevel = DEFAULT_LOGLEVEL;
- int dolocks = 1;
- int parsecolon = 1;
- if(fmt[0] == LOG_SOH_ASCII) {
- loglevel = (fmt[2] - 0x30) % 10;
- char flags = fmt[1];
- if(flags & 1 << 1)
- dolocks = 0;
- if(flags & 1 << 2)
- parsecolon = 0;
- fmt += 3;
- }
-
- /* not going to be printed? dont bother! */
- if(loglevel > CONSOLE_LOGLEVEL)
- return 0;
-
- /* we essentially print the user's raw input to its own buffer,
- later we will parse it and print out ANSI colors and what not */
- char buf[512];
-
- vsnprintf(buf, 512, fmt, ap);
- buf[512 - 1] = '\0';
-
- size_t colon = 0;
- if(parsecolon) {
- for(; colon < strlen(buf); ++colon) {
- if(buf[colon] == ':')
- break;
- }
- }
-
- char tsbuf[64] = "\0";
- struct timeval time;
- gettimeofday(&time, NULL);
- snprintf(tsbuf, sizeof(tsbuf), "[%5ld.%06ld] ",
- (long)time.tv_sec % 100000, (long)time.tv_usec);
-
- /* spin lock, at the cost of architecture portability
- concurrency is something that we need to adjust for, and the
- console will be scrambled and unreadable if we allow writing all
- at the same time. I considered simply writing all at once, but
- ended up just not caring enough to the point where spinlocks
- prevail. */
- if(dolocks)
- obtain_console_lock();
-
-
- /* we want to support stuff without colons, but frankly I havent
- tested this at time of writing. will find out later */
- writeputs(ANSI_RESET ANSI_GREEN);
- writeputs(tsbuf);
- writeputs(ANSI_RESET);
- if(parsecolon && buf[colon] == ':') {
- writeputs(colors[loglevel]);
- writeputs(ANSI_YELLOW);
- write(STDOUT_FILENO, buf, colon);
- writeputs(ANSI_RESET);
- }
- writeputs(colors[loglevel]);
- if(colon && *(buf + colon)) {
- writeputs(buf + colon);
- } else {
- writeputs(buf);
- }
- writeputs(ANSI_RESET);
- write(STDOUT_FILENO, "\n", 1);
- if(dolocks)
- console_lock = 0;
- return 0;
-}
-
-void _panic(const char *fileorigin,
- const int lineorigin,
- const char *fmt, ...)
-{
- char mode = PANICMODE_DIE;
- int pid = getpid();
- if(fmt[0] == LOG_SOH_ASCII) {
- mode = fmt[1];
- /* cannot respawn main thread */
- if(pid == mainpid && mode == PANICMODE_RESPAWN)
- mode = PANICMODE_DIE;
- fmt += 2;
- }
-
-#define NOLOCK(loglevel) LOG_SOH "\3" loglevel
- va_list ap;
- va_start(ap, fmt);
- char *_fmt = malloc(strlen(fmt) + 4 * sizeof(char));
- sprintf(_fmt, NOLOCK("1") "%s", fmt);
-
- void **backtrace_addresses = malloc(sizeof(void*) * 32);
- int backtrace_count = backtrace(backtrace_addresses, 32);
- char **backtrace_symbolnames =
- backtrace_symbols(backtrace_addresses, backtrace_count);
-
- obtain_console_lock();
-
- print(NOLOCK("5") "------------[ cut here ]------------");
- print(LOG_SOH "\7""0" "%s at %s:%d", mode_to_string[(int)mode],
- fileorigin, lineorigin);
- vaprint(_fmt, ap);
- print(LOG_SOH "\7""7" "Call Trace:");
- for(int i = 0; i < backtrace_count; ++i) {
- print(NOLOCK("7") " [0x%016x] %s", backtrace_addresses[i],
- backtrace_symbolnames[i]);
- }
- if(mainpid == pid){
- print(NOLOCK("7") " <start of main thread>");
- } else {
- print(NOLOCK("7") " <start of %s[%d]>",
- subsystem_get_name(pid), pid);
- }
-
- /* if we are going to die, we dont really need to clean up */
- if(mode == PANICMODE_DIE) {
- kill(0, SIGTERM);
- raise(SIGTERM);
- exit(0);
- }
-
- print(NOLOCK("5") "------------[ cut here ]------------");
-
- console_lock = 0;
- free(_fmt);
- free(backtrace_symbolnames);
- free(backtrace_addresses);
- va_end(ap);
-
- if(mode == PANICMODE_DEBUGONLY)
- return;
-
- if(pid != mainpid && mode == PANICMODE_RESPAWN) {
- /* we want to let the main process handle the rest */
- subsystem_change_mode(pid, mode);
- syscall(SYS_exit_group, 0);
- }
-}
-
-int print(const char *fmt, ...)
-{
- int ret = 0;
- va_list ap;
- va_start(ap, fmt);
- ret = vaprint(fmt, ap);
- va_end(ap);
- return ret;
-}
diff --git a/init/subsys.c b/init/subsys.c
deleted file mode 100644
index 704678f..0000000
--- a/init/subsys.c
+++ /dev/null
@@ -1,180 +0,0 @@
-#include <errno.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <config.h>
-#include <log.h>
-#include <util.h>
-
-#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, NAME_SHORTHAND ": %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;
-}