zlayer-overlayd 0.14.0

Standalone ZLayer overlay daemon: owns the WireGuard/Wintun adapter, HCN/bridge mechanics, IP allocation, DNS and NAT; driven by the main daemon over IPC
Documentation
//! Stamp a deterministic SOURCE build-id into the overlayd binary.
//!
//! The install/sync change-gate needs an identity for overlayd that is stable
//! across rebuilds of byte-identical source — the binary's own content hash is
//! NOT (embedded paths/metadata differ every build), so a content-hash gate
//! re-registers the root overlayd service (and re-prompts for a password) on
//! every `install-dev --replace`. Here we fold a SHA-256 over the overlayd
//! source inputs (this crate's `src/` + `Cargo.toml`, plus the shared
//! `zlayer-overlay` lib it wraps) and expose it as `ZLAYER_OVERLAYD_BUILD_ID`;
//! `--build-id` prints it at runtime, and the gate compares those.

use std::path::{Path, PathBuf};

use sha2::{Digest, Sha256};

/// Recursively collect every regular file under `dir` into `out`.
fn collect_files(dir: &Path, out: &mut Vec<PathBuf>) {
    let Ok(entries) = std::fs::read_dir(dir) else {
        return;
    };
    for entry in entries.flatten() {
        let path = entry.path();
        if path.is_dir() {
            collect_files(&path, out);
        } else if path.is_file() {
            out.push(path);
        }
    }
}

fn main() {
    let manifest_dir = PathBuf::from(
        std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by cargo"),
    );
    // `crates/` — the common ancestor of both crates. Hashing paths relative to
    // it keeps the id machine-independent (no absolute home prefix leaks in).
    let crates_dir = manifest_dir
        .parent()
        .expect("overlayd crate has a parent dir")
        .to_path_buf();

    let daemon_src = manifest_dir.join("src");
    let daemon_toml = manifest_dir.join("Cargo.toml");
    let shared_dir = crates_dir.join("zlayer-overlay");
    let shared_src = shared_dir.join("src");
    let shared_toml = shared_dir.join("Cargo.toml");

    // Watch the dirs (catches added/removed files) and each toml explicitly.
    for dir in [&daemon_src, &shared_src] {
        println!("cargo:rerun-if-changed={}", dir.display());
    }
    for toml in [&daemon_toml, &shared_toml] {
        println!("cargo:rerun-if-changed={}", toml.display());
    }

    // Gather every input file, then watch each one (catches in-place edits, which
    // a bare dir rerun-if-changed does not reliably detect).
    let mut files = Vec::new();
    collect_files(&daemon_src, &mut files);
    collect_files(&shared_src, &mut files);
    files.push(daemon_toml);
    files.push(shared_toml);
    for file in &files {
        println!("cargo:rerun-if-changed={}", file.display());
    }

    // Sort so the fold order is independent of readdir order, then fold
    // sha256(relative_path || file_bytes) for each input into one digest.
    files.sort();
    let mut hasher = Sha256::new();
    for file in &files {
        let rel = file.strip_prefix(&crates_dir).unwrap_or(file);
        hasher.update(rel.to_string_lossy().as_bytes());
        let bytes = std::fs::read(file).unwrap_or_default();
        hasher.update(&bytes);
    }
    let mut build_id = String::with_capacity(64);
    for byte in hasher.finalize() {
        use std::fmt::Write as _;
        let _ = write!(build_id, "{byte:02x}");
    }

    println!("cargo:rustc-env=ZLAYER_OVERLAYD_BUILD_ID={build_id}");
}