Skip to content

Commit c6b1fc4

Browse files
committed
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.
1 parent 840e6de commit c6b1fc4

File tree

3 files changed

+44
-4
lines changed

3 files changed

+44
-4
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ lalrpop-util = "0.19"
1919
regex = "1"
2020
sexp = "1.1"
2121
thiserror = "1.0"
22+
walkdir = "2"

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ on the secilc package.
2727

2828
## casc
2929
The Cascade compiler is named casc, and will be located at target/debug/casc after a
30-
successful build. It takes one argument, the name of a policy file to be built:
30+
successful build. Input files are supplied as arguments. Directory arguments
31+
are searched recursively for policy files. If no valid policy files are found,
32+
casc will exit with an error.
3133

3234
```
3335
$ casc my_policy.cas

src/bin/casc.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,40 @@ use selinux_cascade::error::ErrorItem;
66
use clap::Parser;
77
use std::fs::File;
88
use std::io::{Error, ErrorKind, Write};
9+
use walkdir::WalkDir;
910

1011
#[derive(Parser, Debug)]
11-
#[clap(author, version, name = "casc")]
12+
#[clap(author, version, name = "casc", about)]
1213
struct Args {
14+
/// List of input files to process. Directories are searched recursively.
1315
#[clap(required(true))]
1416
input_file: Vec<String>,
1517
}
1618

1719
fn main() -> std::io::Result<()> {
1820
let args = Args::parse();
19-
let policies: Vec<&str> = args.input_file.iter().map(|s| s as &str).collect();
21+
let policies: Vec<String> = match get_policy_files(args.input_file) {
22+
Ok(mut s) => {
23+
// Always treat files in the same order for determinism in compilation
24+
// sort_unstable() does not preserve equality, which is fine because two
25+
// different files cannot have the same relative path
26+
s.sort_unstable();
27+
s
28+
}
29+
Err(e) => {
30+
eprintln!("{}", e);
31+
return Err(e);
32+
}
33+
};
34+
if policies.is_empty() {
35+
// Files supplied on command line, but no .cas files found
36+
return Err(Error::new(
37+
ErrorKind::InvalidData,
38+
"No policy source files found",
39+
));
40+
}
2041
let mut out_file = File::create("out.cil")?;
21-
let res = compile_system_policy(policies);
42+
let res = compile_system_policy(policies.iter().map(|s| s as &str).collect());
2243
match res {
2344
Err(error_list) => {
2445
for e in error_list {
@@ -35,3 +56,19 @@ fn main() -> std::io::Result<()> {
3556
Ok(s) => out_file.write_all(s.as_bytes()),
3657
}
3758
}
59+
60+
// Create a list of policy files
61+
fn get_policy_files(filenames: Vec<String>) -> Result<Vec<String>, Error> {
62+
let mut policy_files = Vec::new();
63+
for file in filenames {
64+
for entry in WalkDir::new(file) {
65+
let entry = entry?;
66+
if entry.file_type().is_file() && entry.path().extension().unwrap_or_default() == "cas"
67+
{
68+
let filename = entry.path().display().to_string();
69+
policy_files.push(filename);
70+
}
71+
}
72+
}
73+
Ok(policy_files)
74+
}

0 commit comments

Comments
 (0)