summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
authorinfo@mode42.com <info@mode42.com>2026-08-08 03:54:55 +0000
committerinfo@mode42.com <info@mode42.com>2026-08-08 03:54:55 +0000
commit20cb29c2f8c5c87bc590896854a20b1473ceb358 (patch)
tree2857f41513a56ad41af97b57362639298aa7f033 /src/main.c
#2
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c371
1 files changed, 371 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..670de7a
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,371 @@
+/*
+ * HyBBX instance daemon — hybbxd (Main) / hybbxsd (Secondary) / hybbxpd (Proxy).
+ * Role is linked via instance_role_*.c. Plugins: CMake HYBBX_PLUGIN_*.
+ * Config: -c path/to/hybbx.ini
+ */
+#if defined(__linux__)
+#define _DEFAULT_SOURCE
+#endif
+
+#include "hybbx/hybbx.h"
+#include "hybbx/instance.h"
+#include "hybbx/service.h"
+#include "hybbx/registry.h"
+#include "hybbx/config.h"
+#include "hybbx/command.h"
+#include "hybbx/commands_registry.h"
+#include "hybbx/daemon_wrap.h"
+#include "hybbx/util.h"
+#include "hybbx/limits.h"
+#include "hybbx/instance.h"
+#include "hybbx/privilege.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#ifdef HYBBX_HAVE_PLUGIN_TELNET
+extern const hybbx_transport_plugin_t hybbx_plugin_telnet;
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_PACKET_RADIO
+extern const hybbx_transport_plugin_t hybbx_plugin_packet_radio;
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_ARDOP
+extern const hybbx_transport_plugin_t hybbx_plugin_ardop;
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_CRDOP
+extern const hybbx_transport_plugin_t hybbx_plugin_crdop;
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_SSH
+extern const hybbx_transport_plugin_t hybbx_plugin_ssh;
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_WEBSOCKET
+extern const hybbx_transport_plugin_t hybbx_plugin_websocket;
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_BAYCOM
+extern const hybbx_transport_plugin_t hybbx_plugin_baycom;
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_MAINS_PROXY
+extern const hybbx_transport_plugin_t hybbx_plugin_mains_proxy;
+#endif
+
+static void register_builtin_plugins(void)
+{
+ /* Register every compiled plugin; instance/INI gating is at apply time. */
+#ifdef HYBBX_HAVE_PLUGIN_TELNET
+ hybbx_registry_register(&hybbx_plugin_telnet);
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_PACKET_RADIO
+ hybbx_registry_register(&hybbx_plugin_packet_radio);
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_ARDOP
+ hybbx_registry_register(&hybbx_plugin_ardop);
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_CRDOP
+ hybbx_registry_register(&hybbx_plugin_crdop);
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_SSH
+ hybbx_registry_register(&hybbx_plugin_ssh);
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_WEBSOCKET
+ hybbx_registry_register(&hybbx_plugin_websocket);
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_BAYCOM
+ hybbx_registry_register(&hybbx_plugin_baycom);
+#endif
+#ifdef HYBBX_HAVE_PLUGIN_MAINS_PROXY
+ hybbx_registry_register(&hybbx_plugin_mains_proxy);
+#endif
+}
+
+static void print_usage(const char *prog)
+{
+ fprintf(stderr,
+ "HyBBX %s — %s instance (%s)\n"
+ "\n"
+ "Usage: %s [options]\n"
+ "\n"
+ "Options:\n"
+ " -c, --config <file> Load INI configuration file\n"
+ " -f, --foreground Run in foreground (default)\n"
+ " --screen [name] Run detached in GNU screen (default: %s)\n"
+ " --tmux [name] Run detached in tmux (default: %s)\n"
+ " --attach Attach to screen/tmux session (with --screen/--tmux)\n"
+ " -h, --help Show this help\n"
+ " -V, --version Show version\n"
+ "\n"
+ "Instances: hybbxd=Main hybbxsd=Secondary hybbxpd=Proxy\n"
+ "\n",
+ HYBBX_VERSION_STRING,
+ hybbx_instance_role_name(),
+ hybbx_instance_binary_name(),
+ prog,
+ hybbx_instance_binary_name(),
+ hybbx_instance_binary_name());
+}
+
+static void print_version(void)
+{
+ printf("HyBBX %s — %s (%s)%s\n",
+ HYBBX_VERSION_STRING,
+ hybbx_instance_role_name(),
+ hybbx_instance_binary_name(),
+ hybbx_instance_offers_user_bbx() ? "" : " [no user BBX]");
+}
+
+static void list_plugins_cb(const hybbx_transport_plugin_t *plugin, void *userdata)
+{
+ (void)userdata;
+ printf(" - %s (kind=%d, version=%u)\n",
+ plugin->name, (int)plugin->kind, plugin->version);
+}
+
+static int path_is_readable(const char *path)
+{
+ return path != NULL && path[0] != '\0' && access(path, R_OK) == 0;
+}
+
+/**
+ * When -c is omitted: HYBBX_CONFIG, then <binary>/hybbx.ini (install layout).
+ */
+static const char *discover_config_path(char *buf, size_t buflen,
+ const char *argv0)
+{
+ const char *env;
+
+ if (buf == NULL || buflen == 0) {
+ return NULL;
+ }
+
+ env = getenv("HYBBX_CONFIG");
+ if (path_is_readable(env)) {
+ snprintf(buf, buflen, "%s", env);
+ return buf;
+ }
+
+ if (argv0 == NULL || argv0[0] == '\0') {
+ return NULL;
+ }
+
+#if defined(__linux__)
+ {
+ char exe[HYBBX_PATH_MAX];
+ char etc[HYBBX_PATH_MAX];
+ ssize_t n = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
+
+ if (n > 0) {
+ char *slash;
+ size_t dir_len;
+
+ exe[n] = '\0';
+ slash = strrchr(exe, '/');
+ if (slash != NULL) {
+ dir_len = (size_t)(slash - exe);
+ if (dir_len + 1 < sizeof(etc)) {
+ memcpy(etc, exe, dir_len);
+ etc[dir_len] = '\0';
+ if (hybbx_path_join(buf, buflen, etc, HYBBX_FILE_CONFIG) ==
+ HYBBX_OK &&
+ path_is_readable(buf)) {
+ return buf;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ snprintf(buf, buflen, "%s", argv0);
+ {
+ char path_copy[HYBBX_PATH_MAX];
+ char candidate[HYBBX_PATH_MAX];
+ char *dir;
+
+ snprintf(path_copy, sizeof(path_copy), "%s", argv0);
+ dir = dirname(path_copy);
+ if (hybbx_path_join(candidate, sizeof(candidate), dir,
+ HYBBX_FILE_CONFIG) == HYBBX_OK &&
+ path_is_readable(candidate)) {
+ snprintf(buf, buflen, "%s", candidate);
+ return buf;
+ }
+ }
+
+ return NULL;
+}
+
+static void setup_install_root(const char *config_path)
+{
+ const char *env;
+
+ env = getenv(HYBBX_ENV_ROOT);
+ if (env != NULL && env[0] != '\0') {
+ hybbx_install_root_set(env);
+ return;
+ }
+
+ if (config_path != NULL && config_path[0] != '\0') {
+ char dir[HYBBX_PATH_MAX];
+
+ if (hybbx_path_dirname(config_path, dir, sizeof(dir)) == HYBBX_OK) {
+ hybbx_install_root_set(dir);
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ hybbx_service_t *service;
+ hybbx_config_t config;
+ const char *config_path = NULL;
+ char discovered_config[HYBBX_PATH_MAX];
+ hybbx_daemon_launch_opts_t launch;
+ int have_config = 0;
+ int i;
+ hybbx_result_t rc;
+
+ hybbx_daemon_launch_opts_defaults(&launch);
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
+ print_usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+ if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
+ print_version();
+ return EXIT_SUCCESS;
+ }
+ if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--foreground") == 0) {
+ launch.foreground = 1;
+ continue;
+ }
+ if (strcmp(argv[i], "--attach") == 0) {
+ launch.attach = 1;
+ continue;
+ }
+ if (strcmp(argv[i], "--screen") == 0) {
+ launch.use_screen = 1;
+ if (i + 1 < argc && argv[i + 1][0] != '-' &&
+ strcmp(argv[i + 1], "-c") != 0 &&
+ strcmp(argv[i + 1], "--config") != 0) {
+ hybbx_strlcpy(launch.session, argv[++i], sizeof(launch.session));
+ }
+ continue;
+ }
+ if (strcmp(argv[i], "--tmux") == 0) {
+ launch.use_tmux = 1;
+ if (i + 1 < argc && argv[i + 1][0] != '-' &&
+ strcmp(argv[i + 1], "-c") != 0 &&
+ strcmp(argv[i + 1], "--config") != 0) {
+ hybbx_strlcpy(launch.session, argv[++i], sizeof(launch.session));
+ }
+ continue;
+ }
+ if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--config") == 0) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "Missing argument for %s\n", argv[i]);
+ return EXIT_FAILURE;
+ }
+ config_path = argv[++i];
+ continue;
+ }
+
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ print_usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ rc = hybbx_daemon_apply_launch_opts(&launch, argv[0], argc, argv);
+ if (rc != HYBBX_OK) {
+ return EXIT_FAILURE;
+ }
+
+ if (config_path == NULL) {
+ config_path = discover_config_path(discovered_config,
+ sizeof(discovered_config), argv[0]);
+ }
+
+ register_builtin_plugins();
+
+ printf("HyBBX %s starting (%s / %s)\n",
+ HYBBX_VERSION_STRING,
+ hybbx_instance_binary_name(),
+ hybbx_instance_role_name());
+
+ service = hybbx_service_create(NULL);
+ if (service == NULL) {
+ fprintf(stderr, "Failed to create service (out of memory?)\n");
+ return EXIT_FAILURE;
+ }
+
+ if (config_path != NULL) {
+ rc = hybbx_config_load(&config, config_path);
+
+ if (rc != HYBBX_OK) {
+ fprintf(stderr, "Failed to load config '%s'\n", config_path);
+ hybbx_service_destroy(service);
+ return EXIT_FAILURE;
+ }
+
+ have_config = 1;
+ printf("Loaded configuration: %s\n", config_path);
+
+ rc = hybbx_privilege_apply_from_config(&config);
+ if (rc != HYBBX_OK) {
+ fprintf(stderr,
+ "Privilege setup failed — %s\n",
+ hybbx_result_name(rc));
+ hybbx_config_free(&config);
+ hybbx_service_destroy(service);
+ return EXIT_FAILURE;
+ }
+
+ setup_install_root(config_path);
+
+ rc = hybbx_commands_registry_init();
+ if (rc != HYBBX_OK) {
+ fprintf(stderr, "Failed to load command registry\n");
+ hybbx_config_free(&config);
+ hybbx_service_destroy(service);
+ return EXIT_FAILURE;
+ }
+
+ rc = hybbx_service_apply_config(service, &config, config_path);
+ if (rc != HYBBX_OK) {
+ fprintf(stderr,
+ "Failed to apply configuration (storage path writable? "
+ "telnet/circuit bind ok?) — %s\n",
+ hybbx_result_name(rc));
+ hybbx_commands_registry_shutdown();
+ hybbx_config_free(&config);
+ hybbx_service_destroy(service);
+ return EXIT_FAILURE;
+ }
+
+ printf("Available transport plugins:\n");
+ hybbx_registry_foreach(list_plugins_cb, NULL);
+ } else {
+ fprintf(stderr,
+ "No configuration loaded. Use -c <hybbx.ini>, set HYBBX_CONFIG, "
+ "or run hybbx-start.\n");
+ fprintf(stderr, "No transports will listen without a config file.\n");
+ }
+
+ hybbx_service_set_launch_binary(service, argv[0]);
+
+ hybbx_service_run(service);
+
+ if (hybbx_service_shutdown_mode(service) == HYBBX_SHUTDOWN_RESTART) {
+ hybbx_service_restart_exec(service);
+ }
+
+ if (have_config) {
+ hybbx_config_free(&config);
+ }
+ hybbx_commands_registry_shutdown();
+ hybbx_service_destroy(service);
+
+ return EXIT_SUCCESS;
+}
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com