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<String, Box<dyn std::error::Error>> {
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 &[");
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<dyn std::error::Error>> {
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) .map(|line| {
line.unwrap()
.split(',')
.map(|x| x.to_string())
.collect::<Vec<_>>()
})
.map(|fields| {
(
fields[0].strip_prefix("AUDIT_").unwrap().to_string(),
fields[1].clone(),
)
})
.collect();
constants.push(("CONTAINER_INFO".into(), "0xffffff01".into()));
let fields: Vec<(String, String)> = BufReader::new(fs::File::open(fields_file)?)
.lines()
.skip(3) .map(|line| {
line.unwrap()
.split(',')
.map(|x| x.to_string())
.collect::<Vec<_>>()
})
.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(())
}