memfaultd 1.25.0

Memfault daemon for embedded Linux systems. Observability, logging, crash reporting, and updating all in one service. Learn more at https://docs.memfault.com/
Documentation
//
// Copyright (c) Memfault, Inc.
// See License.txt for details
use std::collections::HashMap;
use std::env;
use std::fs::write;
use std::path::{Path, PathBuf};

/// Generates $OUT_DIR/build_info.rs, based on the values in the VERSION file (generated by sdk_release.py).
fn generate_build_info_rs() {
    let mut version_file_path =
        PathBuf::from(&env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not set"));
    version_file_path.push("../VERSION");
    println!("cargo:rerun-if-changed={}", version_file_path.display());

    let version_file_content =
        std::fs::read_to_string(version_file_path).unwrap_or_else(|_| String::new());

    let key_values_from_version_file: HashMap<&str, &str> = version_file_content
        .lines()
        .filter_map(|l| l.split_once(':'))
        .map(|(k, v)| (k.trim(), v.trim()))
        .collect();

    struct VersionVarInfo {
        key: &'static str,
        var: &'static str,
        default: &'static str,
    }

    let keys_and_vars_defaults = [
        VersionVarInfo {
            key: "VERSION",
            var: "VERSION",
            default: "dev",
        },
        VersionVarInfo {
            key: "GIT COMMIT",
            var: "GIT_COMMIT",
            default: "unknown",
        },
        VersionVarInfo {
            key: "BUILD ID",
            var: "BUILD_ID",
            default: "unknown",
        },
    ];

    let build_info_rs_src = keys_and_vars_defaults
        .iter()
        .fold(String::new(), |mut acc, info| {
            let value = key_values_from_version_file
                .get(info.key)
                .unwrap_or(&info.default);
            acc.push_str(&format!("pub const {}: &str = \"{}\";\n", info.var, value));
            acc
        });

    let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR is not set");
    let dest_path = Path::new(&out_dir).join("build_info.rs");
    write(dest_path, build_info_rs_src).expect("Failed to write build_info.rs");
}

#[cfg(all(feature = "ebpf", not(target_os = "macos")))]
mod ebpf {
    use std::{env, fs::write};
    use std::{path::Path, process::Command};

    struct EbpfProgram {
        src_dir: &'static str,
        out_key: &'static str,
        out_name: &'static str,
    }

    impl EbpfProgram {
        const fn new(src_dir: &'static str, out_key: &'static str, out_name: &'static str) -> Self {
            EbpfProgram {
                src_dir,
                out_key,
                out_name,
            }
        }
    }

    const PROGRAMS: [EbpfProgram; 1] = [EbpfProgram::new("ebpf/disk_io.c", "DISK_IO", "disk_io.o")];
    pub fn build_ebpf() {
        let cargo_dir = env::var_os("CARGO_MANIFEST_DIR")
            .expect("CARGO_MANIFEST_DIR is not set")
            .into_string()
            .expect("Failed to convert to string");
        let out_dir = env::var_os("OUT_DIR")
            .expect("OUT_DIR is not set")
            .into_string()
            .expect("Failed to convert to string");

        let mut ebpf_programs_rs_src = String::new();
        ebpf_programs_rs_src.push_str("use aya::include_bytes_aligned;\n");
        for program in &PROGRAMS {
            println!("cargo:rerun-if-changed={}", program.src_dir);
            let program_dir = format!("{}/{}", out_dir, program.out_name);
            // PENG-779: Proper clang toolchain discovery for yocto
            let clang_exit_status = Command::new("clang")
                .args([
                    "-target",
                    "bpf",
                    "-O2",
                    "-c",
                    "-g",
                    &format!("{}/{}", &cargo_dir, program.src_dir),
                    "-o",
                    &program_dir,
                ])
                .status()
                .expect("Failed to execute clang");

            if !clang_exit_status.success() {
                panic!(
                    "Failed to build ebpf program {}: {}",
                    program.src_dir, clang_exit_status
                );
            }

            let output_def = format!(
                "pub const {}: &[u8] = include_bytes_aligned!(\"{}\");\n",
                program.out_key, program_dir
            );
            ebpf_programs_rs_src.push_str(&output_def);
        }
        let out_dir = env::var_os("OUT_DIR")
            .expect("OUT_DIR is not set")
            .into_string()
            .expect("Failed to convert to string");
        let dest_path = Path::new(&out_dir).join("ebpf_programs.rs");
        println!("Output ebpf: {:?}", dest_path);
        write(dest_path, ebpf_programs_rs_src).expect("Failed to write ebpf_program.rs");
    }
}

#[cfg(all(feature = "ebpf", target_os = "macos"))]
mod ebpf {
    pub fn build_ebpf() {}
}

fn main() {
    generate_build_info_rs();
    #[cfg(feature = "ebpf")]
    ebpf::build_ebpf();
    println!("cargo:rerun-if-changed=build.rs");
}