Build configcompare_paths(), an offline sibling to snapdiff/walcompare that recomputes each member's active-config sha256 fresh from its own on-disk workdir/name/conf bytes and reports identical vs. divergent (Req 4.2). Wire it as a cmd_configcompare CLI subcommand in test.c, matching its siblings, after review caught it shipped as an unreachable library function in round 1. Extend snapverify to match the current on-disk checkpoint format: bump SNAP_FORMAT_VERSION to 2, replace the stale raw queue-frame decode with the capnp length-prefixed walk, add host-frame and config-bytes-section structural walks, and decode (not just presence-check) the header's cfgref tag/sha. Without this fix snapverify rejected every checkpoint written by the current codebase.
78 lines
4.6 KiB
C
78 lines
4.6 KiB
C
#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 <stdint.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
|
|
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);
|