From 5243f0a834fb0839aa9537f7558d2c78bb1d10ae Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 22 Sep 2026 05:16:36 -0400 Subject: [PATCH] fix: shutdown ordering, silent probe failures, and unused import in the mini clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - hbc_mini.c: move the probe-thread pthread_join to after the shutdown HTB send, so the clean-shutdown notification is no longer delayed behind (and possibly lost to a SIGKILL racing) a probe thread blocked in popen()/ping. - hbc_mini.c: log a LOGW when pthread_create() fails to start the probe thread, and when probe_v4/probe_v6 are not IP literals (probe_init), so both previously silent no-op failure modes are now diagnosable. Diagnostic only — no behavior change to the PROBE_UNKNOWN fallback path. - hbc_mini.py: remove the unused 'import struct' (F401). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01Uc9V1v7iXruubpoLiSE24M --- scripts/c/hbc_mini.c | 21 +++++++++++++++++++-- scripts/hbc_mini.py | 1 - 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/scripts/c/hbc_mini.c b/scripts/c/hbc_mini.c index e1aa3d3..6316912 100644 --- a/scripts/c/hbc_mini.c +++ b/scripts/c/hbc_mini.c @@ -1310,6 +1310,16 @@ static void probe_init(probe_t *p, const config_t *cfg) { pthread_mutex_init(&p->mu, NULL); g_have_timeout = system("command -v timeout >/dev/null 2>&1") == 0; g_probe_enabled = cfg->probe_enabled; + + /* Diagnostic only: sys_local_address already turns a non-literal target into PROBE_UNKNOWN + * (via inet_pton failing there), so this does not change behavior — it just stops that from + * being silent. */ + struct in_addr a4; + struct in6_addr a6; + if (inet_pton(AF_INET, p->target[0], &a4) != 1) + LOGW("probe_v4 is not an IPv4 literal: %s", p->target[0]); + if (inet_pton(AF_INET6, p->target[1], &a6) != 1) + LOGW("probe_v6 is not an IPv6 literal: %s", p->target[1]); } static void *probe_thread(void *arg) { @@ -1760,7 +1770,11 @@ int main(int argc, char **argv) { pthread_create(&tid, NULL, monitor_thread, &tctx); pthread_t ptid; bool probe_running = false; - if (g_probe_enabled && pthread_create(&ptid, NULL, probe_thread, &g_probe) == 0) probe_running = true; + if (g_probe_enabled) { + int prc = pthread_create(&ptid, NULL, probe_thread, &g_probe); + if (prc == 0) probe_running = true; + else LOGW("pthread_create(probe): %s", strerror(prc)); + } /* Main heartbeat + receive loop */ time_t last_hb = 0; @@ -1799,7 +1813,6 @@ int main(int argc, char **argv) { pthread_cancel(tid); pthread_join(tid, NULL); - if (probe_running) pthread_join(ptid, NULL); if (send_shutdown) { kvdict_t sh; kv_clear(&sh); @@ -1808,6 +1821,10 @@ int main(int argc, char **argv) { conn_send(primary, "HTB", &sh); usleep(300000); } + /* Joined after the shutdown HTB goes out: the probe thread is never cancelled (it can be + * inside popen), so joining it can block for a few seconds — long enough to lose the + * clean-shutdown notification to an impatient supervisor's SIGKILL. */ + if (probe_running) pthread_join(ptid, NULL); for (int i = 0; i < g_nconns; i++) conn_close(&g_conns[i]); if (g_use_syslog) closelog(); if (g_restart) { LOGI("restarting..."); execv(argv[0], argv); } diff --git a/scripts/hbc_mini.py b/scripts/hbc_mini.py index 20880d0..da99488 100755 --- a/scripts/hbc_mini.py +++ b/scripts/hbc_mini.py @@ -36,7 +36,6 @@ import re import shutil import signal import socket -import struct import subprocess import sys import time