#pragma once /* * snapverify.h — read-only checkpoint-file structural inspector/validator * (bug-1389 triage: OPCode_snapshotTransfer chunk-content corruption; * extended by config-upgrade-snapshot task 8.4, Requirement 4.2, for the * SNAPSHOT_FORMAT_VERSION=2 host + config-bytes sections and to decode -- * not merely report the presence of -- the header's cfgref tag/hash). * * Parses the on-disk checkpoint layout persist.c's load_snapshot() / * load_snapshot_entities() use (design.md "Checkpoint File Layout") WITHOUT * restoring any job/queue/host into a live cluster_t — a pure structural * walk, so it needs no jobmgr/qmgr/workermgr context and is safe to run * standalone against a snap-*.capnp (locally generated) or snap-*.bin * (received via ha_handle_snapshot_chunk, ha.c) file on disk. This tool * validates STRUCTURE only, never content: job/queue/host frame payloads * and the config-bytes section are walked past via their length prefix, * never capnp-decoded or interpreted. * * Strictly read-only: opens O_RDONLY, mutates nothing. */ #include #include #include typedef struct { uint64_t checkpoint_lsn; int has_cfgref; /* config-ref tail present in the header * (header[16] != 0) -- semantic presence, * distinct from cfgref_tag/cfgref_sha below * being decoded */ uint64_t cfgref_tag; /* header cfgref tag, decoded whenever the * header extends to SNAP_HEADER_MAX bytes, * REGARDLESS of has_cfgref -- meaningful * only when has_cfgref is also 1 */ uint8_t cfgref_sha[32]; /* header cfgref sha256, same decode- * unconditionally-but-gate-meaning-on- * has_cfgref discipline as cfgref_tag */ int has_entity_section; /* fmt + job_count present past the header; * 0 = legacy position-only checkpoint */ uint32_t format_version; uint32_t job_count; /* as declared in the file (0 if legacy) */ uint32_t jobs_ok; /* job frames structurally walked before any failure */ uint32_t queue_count; /* as declared in the file (0 if legacy, or if the * job-frame walk failed before reaching it) */ uint32_t queues_ok; /* queue frames structurally walked before any failure */ uint32_t host_count; /* as declared in the file (0 if legacy, or if an * earlier section's walk failed before reaching * it) */ uint32_t hosts_ok; /* host frames structurally walked before any failure */ int has_config_bytes_section; /* 1 iff the trailing config-bytes * section's 4-byte length field * itself was present and readable * (i.e. the file extends past the * host section at all) -- TRUE even * when that length decodes to 0, and * FALSE (not a failure) when the * file simply ends right after the * host section */ uint32_t config_bytes_len; /* decoded length of the config-bytes * section; valid only when * has_config_bytes_section is 1 */ off_t file_size; off_t consumed; /* bytes structurally accounted for */ int ok; /* 1 = well-formed, consumed == file_size */ off_t fail_offset; /* -1 if ok; else the byte offset of the field that * failed the structural check */ char fail_reason[160]; } snapverify_report_t; /* Parse+validate `path` (a snap-*.capnp or snap-*.bin checkpoint file). * Prints a human-readable report to `out` (may be NULL to suppress) and * fills `*rep` (may be NULL). Returns 0 if the file is structurally * well-formed to EOF, or the same rc class persist_load_snapshot() would * return for the equivalent defect (-EINVAL bad magic / unrecognized * format_version, -EIO short read or a length field that doesn't fit the * remaining bytes, -errno on open/fstat failure) — so a "persist_load_snapshot * failed rc=..." log line correlates directly against this tool's verdict. */ int snapverify_path(const char* path, FILE* out, snapverify_report_t* rep);