use std::env; use std::fs; use std::io::prelude::*; use std::io::BufReader; use std::iter::FromIterator; use std::path::Path; use std::string::String; extern crate bindgen; fn gen_syscall() -> Result> { let mut buf = String::new(); for entry in Path::new("syscall-tables").read_dir()? { let p = entry?.path(); let filename = if let Some(f) = p.file_name() { f } else { continue; }; let arch = if let Some(a) = filename .to_string_lossy() .into_owned() .strip_suffix("_table.h") { a.to_string() } else { continue; }; buf.push_str("{ let mut t = HashMap::new(); for (num, name) in &["); // Entries look like // _S(0, "io_setup") // Just get rid of the _S. let defs = BufReader::new(fs::File::open(p)?) .lines() .filter(|line| line.as_ref().unwrap().starts_with("_S(")) .map(|line| line.unwrap()) .map(|line| line.strip_prefix("_S").unwrap().to_string()); for def in defs { buf.push_str(def.as_str()); buf.push(','); } buf.push_str("] { t.insert(*num, *name); } "); buf.push_str(format!(" hm.insert(\"{arch}\", t); }}\n").as_str()); } Ok(buf) } fn main() -> Result<(), Box> { let out_dir = env::var_os("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("const.rs"); let msg_file = "audit-specs/messages/message-dictionary.csv"; let fields_file = "audit-specs/fields/field-dictionary.csv"; let mut constants: Vec<(String, String)> = BufReader::new(fs::File::open(msg_file)?) .lines() .skip(1) // skip over header .map(|line| { line.unwrap() .split(',') .map(|x| x.to_string()) .collect::>() }) .map(|fields| { ( fields[0].strip_prefix("AUDIT_").unwrap().to_string(), fields[1].clone(), ) }) .collect(); // Artificial record constants.push(("CONTAINER_INFO".into(), "0xffffff01".into())); let fields: Vec<(String, String)> = BufReader::new(fs::File::open(fields_file)?) .lines() .skip(3) // skip over heder and regex describing a* mess .map(|line| { line.unwrap() .split(',') .map(|x| x.to_string()) .collect::>() }) .map(|fields| (fields[0].clone(), fields[1].clone())) .collect(); let mut template = Vec::new(); fs::File::open("src/const.rs.in")?.read_to_end(&mut template)?; let template = String::from_utf8(template)?; let buf = template .replace( "/* @EVENT_CONST@ */", &String::from_iter( constants .iter() .map(|(name, value)| format!(r#"("{name}", {value}), "#)), ), ) .replace( "/* @FIELD_TYPES@ */", &String::from_iter( fields .iter() .filter(|(_, typ)| typ == "encoded" || typ.starts_with("numeric")) .map(|(name, typ)| match typ.as_str() { "numeric hexadecimal" => format!(r#"("{name}", FieldType::NumericHex),"#), "numeric decimal" => format!(r#"("{name}", FieldType::NumericDec),"#), "numeric octal" => format!(r#"("{name}", FieldType::NumericOct),"#), "numeric" => format!(r#"("{name}", FieldType::Numeric),"#), "encoded" => format!(r#"("{name}", FieldType::Encoded),"#), _ => format!(r#"("{name}", FieldType::Invalid),"#), }), ), ) .replace( "/* @CONSTANTS@ */", &String::from_iter(constants.iter().map(|(name, value)| { format!( "#[allow(dead_code)] pub const {name}: MessageType = MessageType({value});\n", ) })), ) .replace("/* @SYSCALL_BUILD@ */", &gen_syscall()?) .into_bytes(); fs::write(dest_path, buf)?; #[cfg(target_os = "linux")] bindgen::Builder::default() .header("src/sockaddr.h") .rust_target(bindgen::RustTarget::Stable_1_47) .allowlist_type("^sockaddr_.*") .allowlist_var("^AF_.*") .layout_tests(false) .generate() .expect("unable to generate bindings") .write_to_file(std::path::PathBuf::from(env::var("OUT_DIR").unwrap()).join("sockaddr.rs")) .expect("Couldn't write bindings!"); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=const.rs.in"); #[cfg(target_os = "linux")] println!("cargo:rerun-if-changed=src/sockaddr.h"); println!("cargo:rerun-if-changed={msg_file}"); println!("cargo:rerun-if-changed={fields_file}"); Ok(()) }