feat(build-time-versioning): worker --version and startup log

Worker uses plain getopt_long(), not argp, so it has no free --version
handling like controller/scheduler. Adds a long-only OPT_VERSION=257
option and a handling case that computes xce_compose_version() into a
static buffer and returns before any startup work (check_user()/
xcecd_init/xcecd_start). Both startup INFO log branches (--peers and
no-peers) extended to log the identical buffer.

Live-verified: --version and both startup-log branches are
byte-identical (captured via a real daemon run under sudo).

Also updates bug-1519 (pre-existing, unrelated ASAN "Joining already
joined thread" abort during worker shutdown): independently reproduced
under real root during this task's review, refining its prior "never
reproduced under real root" note -- not a userns/unshare artifact, still
unfixed, does not affect this task's code path.

Task 3.3/13 of build-time-versioning. This closes out the "Core: C
daemon version display" phase (tasks 3.1-3.3).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-08-20 11:47:12 +00:00
parent 88649a0462
commit bc5c669b94
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
3 changed files with 41 additions and 15 deletions

View file

@ -304,7 +304,8 @@ static int check_user(void)
}
/* Long-option identifiers (beyond ASCII range to avoid collisions) */
#define OPT_PEERS 256
#define OPT_PEERS 256
#define OPT_VERSION 257
int main(int argc, char* argv[])
{
@ -313,6 +314,15 @@ int main(int argc, char* argv[])
int verbose = 0;
__attribute__((unused)) char worker_log[1024] = { 0 };
const char* peers_str = NULL;
/* build-time-versioning task 3.3: worker uses plain getopt_long(), not
* argp, so there is no free argp_program_version auto-handling here
* (unlike controller/main.c, scheduler/src/main.c). version_buf is
* computed once, before argument parsing even starts, via the same
* xce_compose_version() runtime helper those two use -- both the
* --version case below and the startup INFO log lines further down
* read this SAME buffer, never recomputing it independently, so the
* two can never disagree (Requirement 2.2). */
static char version_buf[128];
xce_cluster_config_t cluster_cfg = {0};
int use_ha = 0; /* 1 when --peers given */
@ -356,11 +366,19 @@ int main(int argc, char* argv[])
char* logdir = NULL;
static struct option long_opts[] = {
{ "peers", required_argument, NULL, OPT_PEERS },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
{ "peers", required_argument, NULL, OPT_PEERS },
{ "version", no_argument, NULL, OPT_VERSION },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
/* Computed before argument parsing begins (mirrors controller/main.c's
* and scheduler/src/main.c's "compute before argp_parse()" ordering) so
* the OPT_VERSION case immediately below can print it, and so it is
* ready by the time the startup INFO log lines run later in main(). */
xce_compose_version(version_buf, sizeof(version_buf), "xce v0.0.1-",
STR(VERSION_COMMIT_ID), STR(VERSION_BUILD_TIME));
while ((opt = getopt_long(argc, argv, "n:l:vh", long_opts, NULL))
!= -1) {
switch (opt) {
@ -381,6 +399,12 @@ int main(int argc, char* argv[])
case OPT_PEERS:
peers_str = optarg;
break;
case OPT_VERSION:
/* Prints and exits before any other startup work (peer
* parsing, check_user(), daemon init, etc.) -- same contract
* as controller/scheduler's --version. */
printf("%s\n", version_buf);
return 0;
case 'h':
default:
printf("Usage: %s [-n name] [-l log_dir] [-v] "
@ -433,14 +457,16 @@ int main(int argc, char* argv[])
cluster_cfg.candidates_count, N_MAX_MASTERS);
}
XCECD_LOG(XCE_LOG_INFO,
"HA cluster config: %d candidate(s), identity=%s",
cluster_cfg.candidates_count, cluster_cfg.identity);
"HA cluster config: %d candidate(s), identity=%s, "
"version %s",
cluster_cfg.candidates_count, cluster_cfg.identity,
version_buf);
use_ha = 1;
} else {
XCECD_LOG(XCE_LOG_INFO,
"No --peers flag; using single-controller path "
"(host=%s port=%d)",
config.remote_host, config.remote_port);
"(host=%s port=%d), version %s",
config.remote_host, config.remote_port, version_buf);
}
/* P2.2 fix (component-failover-adoption, task 2.2, Req 1.4): assign
* cluster_cfg onto config BEFORE xcecd_init()/xcecd_start() run, so it