From fc10d8a0818bb87001a64a72552ed28fe60931ee Mon Sep 17 00:00:00 2001 From: auric Date: Sat, 21 Feb 2026 14:59:07 -0600 Subject: Add A2S probing, sd-bus state, tail/broadcast, and bot audit log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit State detection: - Add STATE_STOPPING to ProcessState enum - Replace system("systemctl is-active") with libsystemd sd-bus API for accurate starting/stopping/crashed state reporting; works for any unit type (RCON or STDIN) that declares a service: field - Implement real A2S_INFO UDP queries (src/console/a2s.c) for units with health.type = a2s (Valve games: TF2, GMod); differentiates running / hibernating (0 players) / changing_map (A2S down, RCON up) / unreachable; includes player count and map name in responses - Refactor probe_rcon_state() into probe_unit_state() returning a ProbeResult struct with state, players, max_players, map fields - status and list responses now include players/max_players/map fields New daemon commands: - tail : return ring buffer snapshot as a single response - broadcast : send broadcast_cmd-formatted message to all running units; works for both RCON and STDIN console types New YAML field: - broadcast_cmd: command template (e.g. "say {msg}") — opt-in per unit; units without it are skipped by broadcast CLI (umbrella-cli): - Add tail subcommand (non-interactive output snapshot) - Add broadcast subcommand - status shows Players and Map when available - list adds PLAYERS and MAP columns Bot (umbrella-bot): - Replace !attach / !detach with !tail (shows last 30 lines, no streaming) - Add !broadcast command - Write per-!cmd audit entries to /var/log/umbrella/bot-audit.log - !units and !status responses include player counts when available Co-Authored-By: Claude Sonnet 4.6 --- src/unit.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/unit.c') diff --git a/src/unit.c b/src/unit.c index 3dd9d26..5baea20 100644 --- a/src/unit.c +++ b/src/unit.c @@ -41,6 +41,7 @@ const char *unit_state_str(ProcessState state) { case STATE_STARTING: return "starting"; case STATE_RUNNING: return "running"; case STATE_CRASHED: return "crashed"; + case STATE_STOPPING: return "stopping"; default: return "unknown"; } } @@ -160,6 +161,8 @@ int unit_load_file(const char *path, Unit *out) { strncpy(out->display, val, MAX_DISPLAY - 1); else if (strcmp(last_key, "service") == 0) strncpy(out->service, val, MAX_NAME - 1); + else if (strcmp(last_key, "broadcast_cmd") == 0) + strncpy(out->broadcast_cmd, val, sizeof(out->broadcast_cmd) - 1); break; case SECTION_CONSOLE: -- cgit v1.2.3