From c6b1fc4397bf29df10928b88c1ad2d03685ff978 Mon Sep 17 00:00:00 2001 From: Daniel Burgener Date: Tue, 3 May 2022 18:56:44 -0400 Subject: [PATCH] Enable recursive directory traversal in casc This enables recursively discovering all policy files in the specified path(s), which is expected to be the most common use case. Additional ergonomics, like defaulting to CWD if no path is specified is future work. --- Cargo.toml | 1 + README.md | 4 +++- src/bin/casc.rs | 43 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 65c96332..3dd65457 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,4 @@ lalrpop-util = "0.19" regex = "1" sexp = "1.1" thiserror = "1.0" +walkdir = "2" diff --git a/README.md b/README.md index ac04c7e2..0fe61530 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,9 @@ on the secilc package. ## casc The Cascade compiler is named casc, and will be located at target/debug/casc after a -successful build. It takes one argument, the name of a policy file to be built: +successful build. Input files are supplied as arguments. Directory arguments +are searched recursively for policy files. If no valid policy files are found, +casc will exit with an error. ``` $ casc my_policy.cas diff --git a/src/bin/casc.rs b/src/bin/casc.rs index 58053c45..aecc7d89 100644 --- a/src/bin/casc.rs +++ b/src/bin/casc.rs @@ -6,19 +6,40 @@ use selinux_cascade::error::ErrorItem; use clap::Parser; use std::fs::File; use std::io::{Error, ErrorKind, Write}; +use walkdir::WalkDir; #[derive(Parser, Debug)] -#[clap(author, version, name = "casc")] +#[clap(author, version, name = "casc", about)] struct Args { + /// List of input files to process. Directories are searched recursively. #[clap(required(true))] input_file: Vec, } fn main() -> std::io::Result<()> { let args = Args::parse(); - let policies: Vec<&str> = args.input_file.iter().map(|s| s as &str).collect(); + let policies: Vec = match get_policy_files(args.input_file) { + Ok(mut s) => { + // Always treat files in the same order for determinism in compilation + // sort_unstable() does not preserve equality, which is fine because two + // different files cannot have the same relative path + s.sort_unstable(); + s + } + Err(e) => { + eprintln!("{}", e); + return Err(e); + } + }; + if policies.is_empty() { + // Files supplied on command line, but no .cas files found + return Err(Error::new( + ErrorKind::InvalidData, + "No policy source files found", + )); + } let mut out_file = File::create("out.cil")?; - let res = compile_system_policy(policies); + let res = compile_system_policy(policies.iter().map(|s| s as &str).collect()); match res { Err(error_list) => { for e in error_list { @@ -35,3 +56,19 @@ fn main() -> std::io::Result<()> { Ok(s) => out_file.write_all(s.as_bytes()), } } + +// Create a list of policy files +fn get_policy_files(filenames: Vec) -> Result, Error> { + let mut policy_files = Vec::new(); + for file in filenames { + for entry in WalkDir::new(file) { + let entry = entry?; + if entry.file_type().is_file() && entry.path().extension().unwrap_or_default() == "cas" + { + let filename = entry.path().display().to_string(); + policy_files.push(filename); + } + } + } + Ok(policy_files) +}