From 27ee0ab57e09c5defdfb2b8fc8591a4c0c86ca53 Mon Sep 17 00:00:00 2001 From: Jake Hillion Date: Mon, 28 Mar 2022 01:47:51 +0100 Subject: [PATCH] added clone namespace benchmarks --- Cargo.lock | 414 +++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 7 + benches/clone3.rs | 40 +++++ src/lib.rs | 116 +++++++++++++ src/main.rs | 117 +------------ 5 files changed, 576 insertions(+), 118 deletions(-) create mode 100644 benches/clone3.rs create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 886d2aa..e88edfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,6 +34,33 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "cast" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version", +] + [[package]] name = "cc" version = "1.0.72" @@ -46,6 +73,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags", + "textwrap 0.11.0", + "unicode-width", +] + [[package]] name = "clap" version = "3.0.14" @@ -58,15 +96,16 @@ dependencies = [ "os_str_bytes", "strsim", "termcolor", - "textwrap", + "textwrap 0.14.2", ] [[package]] name = "clone-shim" version = "0.1.0" dependencies = [ - "clap", + "clap 3.0.14", "close_fds", + "criterion", "env_logger", "exitcode", "ipnetwork", @@ -88,6 +127,115 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +dependencies = [ + "atty", + "cast", + "clap 2.34.0", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa 0.4.8", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + [[package]] name = "env_logger" version = "0.9.0" @@ -107,6 +255,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193" +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "hashbrown" version = "0.11.2" @@ -147,12 +301,42 @@ dependencies = [ "serde", ] +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "itoa" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.117" @@ -196,6 +380,31 @@ dependencies = [ "memoffset", ] +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + [[package]] name = "os_str_bytes" version = "6.0.0" @@ -205,6 +414,34 @@ dependencies = [ "memchr", ] +[[package]] +name = "plotters" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" + +[[package]] +name = "plotters-svg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +dependencies = [ + "plotters-backend", +] + [[package]] name = "proc-macro2" version = "1.0.36" @@ -223,6 +460,31 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + [[package]] name = "regex" version = "1.5.4" @@ -234,18 +496,54 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + [[package]] name = "regex-syntax" version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" + [[package]] name = "serde" version = "1.0.136" @@ -255,6 +553,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.136" @@ -272,7 +580,7 @@ version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ - "itoa", + "itoa 1.0.1", "ryu", "serde", ] @@ -303,6 +611,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "textwrap" version = "0.14.2" @@ -329,12 +646,103 @@ dependencies = [ "syn", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 773b5e6..8d211a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,10 @@ libc = "0.2.117" nix = "0.23.1" close_fds = "0.3.2" + +[dev-dependencies] +criterion = "0.3" + +[[bench]] +name = "clone3" +harness = false diff --git a/benches/clone3.rs b/benches/clone3.rs new file mode 100644 index 0000000..3c2d9a1 --- /dev/null +++ b/benches/clone3.rs @@ -0,0 +1,40 @@ +use clone_shim::clone::{clone3, CloneArgs, CloneFlags}; + +use criterion::{criterion_group, criterion_main, Criterion}; + +fn run_clone3(flags: CloneFlags) { + if clone3(CloneArgs::new(flags)).unwrap() == nix::unistd::Pid::from_raw(0) { + std::process::exit(0) + } +} + +pub fn benchmark_clone3(c: &mut Criterion) { + c.bench_function("clone3", |b| b.iter(|| run_clone3(CloneFlags::empty()))); + c.bench_function("clone3+CLONE_NEWCGROUP", |b| { + b.iter(|| run_clone3(CloneFlags::CLONE_NEWCGROUP)) + }); + c.bench_function("clone3+CLONE_NEWIPC", |b| { + b.iter(|| run_clone3(CloneFlags::CLONE_NEWIPC)) + }); + c.bench_function("clone3+CLONE_NEWNET", |b| { + b.iter(|| run_clone3(CloneFlags::CLONE_NEWNET)) + }); + c.bench_function("clone3+CLONE_NEWNS", |b| { + b.iter(|| run_clone3(CloneFlags::CLONE_NEWNS)) + }); + c.bench_function("clone3+CLONE_NEWPID", |b| { + b.iter(|| run_clone3(CloneFlags::CLONE_NEWPID)) + }); + c.bench_function("clone3+CLONE_NEWUSER", |b| { + b.iter(|| run_clone3(CloneFlags::CLONE_NEWUSER)) + }); + c.bench_function("clone3+CLONE_NEWUTS", |b| { + b.iter(|| run_clone3(CloneFlags::CLONE_NEWUTS)) + }); + c.bench_function("clone3+CLONE_NEWCGROUP+CLONE_NEWIPC+CLONE_NEWNET+CLONE_NEWNS+CLONE_NEWPID+CLONE_NEWUSER+CLONE_NEWUTS", |b| { + b.iter(|| run_clone3(CloneFlags::CLONE_NEWCGROUP|CloneFlags::CLONE_NEWIPC|CloneFlags::CLONE_NEWNET|CloneFlags::CLONE_NEWNS|CloneFlags::CLONE_NEWPID|CloneFlags::CLONE_NEWUSER|CloneFlags::CLONE_NEWUTS)) + }); +} + +criterion_group!(benches, benchmark_clone3); +criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9e19aa9 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,116 @@ +use log::{debug, info}; + +pub mod clone; +mod error; +mod spawner; +mod specification; + +use error::Error; +use spawner::Spawner; +use specification::Specification; + +use std::collections::HashMap; +use std::fs::File; +use std::os::unix::io::FromRawFd; + +use clap::{App, AppSettings}; +use nix::fcntl::OFlag; +use nix::unistd::{self}; + +pub fn run() -> Result<(), Error> { + // process arguments + let matches = App::new("clone-shim") + .version(env!("GIT_HASH")) + .author("Jake Hillion ") + .about("Launch a multi entrypoint app, cloning as requested by an external specification or the ELF.") + .arg(clap::Arg::new("spec").long("specification").short('s').help("Provide the specification as an external JSON file.").takes_value(true)) + .setting(AppSettings::TrailingVarArg) + .arg(clap::Arg::new("verbose").long("verbose").short('v').help("Use verbose logging.").takes_value(false)) + .arg(clap::Arg::new("binary").index(1).help("Binary and arguments to launch with the shim").required(true).multiple_values(true)) + .get_matches(); + + let (binary, trailing) = { + let mut argv = matches.values_of("binary").unwrap(); + + let binary = argv.next().unwrap(); + let trailing: Vec<&str> = argv.collect(); + + (binary, trailing) + }; + + // setup logging + let env = env_logger::Env::new().filter_or( + "LOG", + if matches.is_present("verbose") { + "debug" + } else { + "warn" + }, + ); + env_logger::init_from_env(env); + + // parse the specification + let spec: Specification = if let Some(m) = matches.value_of("spec") { + if m.ends_with(".json") { + let f = std::fs::File::open(m)?; + Ok(serde_json::from_reader(f)?) + } else { + Err(Error::BadSpecType) + } + } else { + unimplemented!("reading spec from the elf is unimplemented") + }?; + + debug!("specification read: {:?}", &spec); + spec.validate()?; + + // create all the pipes + let (pipes, _) = spec.pipes(); + let pipes = create_pipes(pipes)?; + + // spawn all processes + let spawner = Spawner { + spec: &spec, + pipes: &pipes, + binary, + trailing: &trailing, + }; + + spawner.spawn()?; + + // TODO: Fix this dirty hack to prevent files dropping (and closing) + // switch to Option and use a mut ref to take, then call + // IntoRawFd if used + std::thread::sleep(std::time::Duration::from_secs(10)); + + Ok(()) +} + +pub struct PipePair { + read: File, + write: File, +} + +fn create_pipes(names: Vec<&str>) -> Result, Error> { + let mut pipes = HashMap::new(); + + for pipe in names { + info!("creating pipe pair `{}`", pipe); + + let (read, write) = unistd::pipe2(OFlag::O_DIRECT).map_err(|e| Error::Nix { + msg: "pipe2", + src: e, + })?; + + // safe to create files given the successful return of pipe(2) + pipes.insert( + pipe.to_string(), + PipePair { + read: unsafe { File::from_raw_fd(read) }, + write: unsafe { File::from_raw_fd(write) }, + }, + ); + } + + Ok(pipes) +} diff --git a/src/main.rs b/src/main.rs index d7c51bc..f6516ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,6 @@ -use log::{debug, error, info}; +use log::{error, info}; -mod clone; -mod error; -mod spawner; -mod specification; - -use error::Error; -use spawner::Spawner; -use specification::Specification; - -use std::collections::HashMap; -use std::fs::File; -use std::os::unix::io::FromRawFd; - -use clap::{App, AppSettings}; -use nix::fcntl::OFlag; -use nix::unistd::{self}; +use clone_shim::run; fn main() { std::process::exit(match run() { @@ -29,101 +14,3 @@ fn main() { } }) } - -fn run() -> Result<(), Error> { - // process arguments - let matches = App::new("clone-shim") - .version(env!("GIT_HASH")) - .author("Jake Hillion ") - .about("Launch a multi entrypoint app, cloning as requested by an external specification or the ELF.") - .arg(clap::Arg::new("spec").long("specification").short('s').help("Provide the specification as an external JSON file.").takes_value(true)) - .setting(AppSettings::TrailingVarArg) - .arg(clap::Arg::new("verbose").long("verbose").short('v').help("Use verbose logging.").takes_value(false)) - .arg(clap::Arg::new("binary").index(1).help("Binary and arguments to launch with the shim").required(true).multiple_values(true)) - .get_matches(); - - let (binary, trailing) = { - let mut argv = matches.values_of("binary").unwrap(); - - let binary = argv.next().unwrap(); - let trailing: Vec<&str> = argv.collect(); - - (binary, trailing) - }; - - // setup logging - let env = env_logger::Env::new().filter_or( - "LOG", - if matches.is_present("verbose") { - "debug" - } else { - "warn" - }, - ); - env_logger::init_from_env(env); - - // parse the specification - let spec: Specification = if let Some(m) = matches.value_of("spec") { - if m.ends_with(".json") { - let f = std::fs::File::open(m)?; - Ok(serde_json::from_reader(f)?) - } else { - Err(Error::BadSpecType) - } - } else { - unimplemented!("reading spec from the elf is unimplemented") - }?; - - debug!("specification read: {:?}", &spec); - spec.validate()?; - - // create all the pipes - let (pipes, _) = spec.pipes(); - let pipes = create_pipes(pipes)?; - - // spawn all processes - let spawner = Spawner { - spec: &spec, - pipes: &pipes, - binary, - trailing: &trailing, - }; - - spawner.spawn()?; - - // TODO: Fix this dirty hack to prevent files dropping (and closing) - // switch to Option and use a mut ref to take, then call - // IntoRawFd if used - std::thread::sleep(std::time::Duration::from_secs(10)); - - Ok(()) -} - -pub struct PipePair { - read: File, - write: File, -} - -fn create_pipes(names: Vec<&str>) -> Result, Error> { - let mut pipes = HashMap::new(); - - for pipe in names { - info!("creating pipe pair `{}`", pipe); - - let (read, write) = unistd::pipe2(OFlag::O_DIRECT).map_err(|e| Error::Nix { - msg: "pipe2", - src: e, - })?; - - // safe to create files given the successful return of pipe(2) - pipes.insert( - pipe.to_string(), - PipePair { - read: unsafe { File::from_raw_fd(read) }, - write: unsafe { File::from_raw_fd(write) }, - }, - ); - } - - Ok(pipes) -}