#ifndef UMBRELLA_H #define UMBRELLA_H #include #include /* ── Version ─────────────────────────────────────────────────────────────── */ #define UMBRELLA_VERSION "0.1.0" /* ── Paths ───────────────────────────────────────────────────────────────── */ #define UMBRELLA_CONF_DIR "/etc/umbrella" #define UMBRELLA_UNITS_DIR "/etc/umbrella/units" #define UMBRELLA_CONF_FILE "/etc/umbrella/umbrella.conf" #define UMBRELLA_SOCK_PATH "/run/umbrella/umbrella.sock" #define UMBRELLA_PID_FILE "/run/umbrella/umbrella.pid" #define UMBRELLA_LOG_FILE "/var/log/umbrella/umbrella.log" /* ── Limits ──────────────────────────────────────────────────────────────── */ #define MAX_UNITS 64 #define MAX_CLIENTS 32 #define MAX_NAME 64 #define MAX_PATH 256 #define MAX_DISPLAY 128 #define MAX_ACTIONS 16 #define RING_BUF_LINES 500 /* output lines buffered per unit */ #define RING_BUF_LINE_MAX 1024 /* max bytes per buffered line */ #define PROTO_MAX_MSG 65536 /* max wire message size */ /* ── Console types ───────────────────────────────────────────────────────── */ typedef enum { CONSOLE_RCON = 0, CONSOLE_STDIN = 1, } ConsoleType; /* ── Health check types ──────────────────────────────────────────────────── */ typedef enum { HEALTH_A2S = 0, HEALTH_TCP = 1, HEALTH_NONE = 2, } HealthType; /* ── Process state ───────────────────────────────────────────────────────── */ typedef enum { STATE_STOPPED = 0, STATE_STARTING = 1, STATE_RUNNING = 2, STATE_CRASHED = 3, STATE_STOPPING = 4, } ProcessState; /* ── Action: a named script ──────────────────────────────────────────────── */ typedef struct { char name[MAX_NAME]; char script[MAX_PATH]; } Action; /* ── Console config ──────────────────────────────────────────────────────── */ typedef struct { ConsoleType type; char host[64]; uint16_t port; char password[128]; /* RCON password; empty for stdin */ char password_env[64]; /* env var name to read password from */ } ConsoleConfig; /* ── Health config ───────────────────────────────────────────────────────── */ typedef struct { HealthType type; char host[64]; uint16_t port; int timeout_ms; } HealthConfig; /* ── Ring buffer: circular store of recent output lines ──────────────────── */ typedef struct { char lines[RING_BUF_LINES][RING_BUF_LINE_MAX]; int head; /* next write position */ int count; /* how many lines are valid */ } RingBuffer; /* ── Unit: a loaded descriptor ───────────────────────────────────────────── */ typedef struct { char name[MAX_NAME]; char display[MAX_DISPLAY]; char service[MAX_NAME]; /* systemd unit name, informational */ char broadcast_cmd[128]; /* command template for !broadcast, e.g. "say {msg}" */ ConsoleConfig console; HealthConfig health; char log_paths[4][MAX_PATH]; int log_count; Action actions[MAX_ACTIONS]; int action_count; char log_filter[MAX_PATH]; /* path to filter executable, or empty */ char log_dir[MAX_PATH]; /* directory to watch, or "" if not used */ char log_dir_pattern[MAX_PATH]; /* fnmatch pattern for log files; default "*" */ /* Runtime state (populated by process/rcon layer, not yaml) */ ProcessState state; pid_t pid; /* only for CONSOLE_STDIN */ int stdin_fd; /* only for CONSOLE_STDIN */ int stdout_fd; /* only for CONSOLE_STDIN */ RingBuffer *output; /* Log filter subprocess (populated at runtime if log_filter is set) */ pid_t filter_pid; int filter_in_fd; /* write end: daemon → filter stdin */ int filter_out_fd; /* read end: filter stdout → daemon */ } Unit; /* ── Client: a connected socket client ───────────────────────────────────── */ typedef struct { int fd; char attached[MAX_NAME]; /* unit name, or empty if not attached */ int uid; /* peer uid from SO_PEERCRED */ } Client; /* ── Global daemon state ─────────────────────────────────────────────────── */ typedef struct { Unit units[MAX_UNITS]; int unit_count; Client clients[MAX_CLIENTS]; int client_count; int epoll_fd; int listen_fd; int signal_fd; int running; } Daemon; extern Daemon g; #endif /* UMBRELLA_H */