diff options
-rw-r--r-- | Cargo.lock | 42 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/main.rs | 52 |
3 files changed, 85 insertions, 10 deletions
@@ -5,6 +5,7 @@ dependencies = [ "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -16,6 +17,16 @@ dependencies = [ ] [[package]] +name = "bitflags" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "env_logger" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -57,6 +68,19 @@ dependencies = [ ] [[package]] +name = "nix" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "regex" version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -74,6 +98,19 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "rustc_version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "thread-id" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -96,6 +133,11 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["bnewbold <bnewbold@robocracy.org>"] [dependencies] +nix = "0.7" log = "0.3" env_logger = "0.3" getopts = "^0.2" diff --git a/src/main.rs b/src/main.rs index d87f037..d4221dc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,28 +19,45 @@ extern crate getopts; extern crate log; extern crate env_logger; +extern crate nix; use std::env; use std::u64; use std::str::FromStr; -use std::{time, thread}; use std::process::exit; use std::process::Command; +use std::process::Child; +use std::net::SocketAddr; +use std::net::TcpListener; +use std::net::ToSocketAddrs; use getopts::Options; -fn run(prog: Vec<String>, number: u64) { +use std::os::unix::io::IntoRawFd; +fn run(binds: Vec<TcpListener>, mut prog: Command, number: u64) { + prog.env("EINHORN_FD_COUNT", binds.len().to_string()); + // This iterator destroys the TcpListeners + for (i, b) in binds.into_iter().enumerate() { + let orig_fd = b.into_raw_fd(); + // Duplicate, which also clears the CLOEXEC flag + //let fd = nix::fcntl::fcntl(nix::fcntl::FcntlArg::F_DUPFD(orig_fd)).unwrap(); + let fd = nix::unistd::dup(orig_fd).unwrap(); + println!("fd={} FD_CLOEXEC={}", fd, nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_GETFD).unwrap()); + prog.env(format!("EINHORN_FD_{}", i), fd.to_string()); + // NB: is fd getting destroyed here? + } + + let mut children: Vec<Child> = vec![]; for _ in 0..number { println!("Running!"); - Command::new(&prog[0]) - .args(&prog[1..]) - .spawn() - .expect("command failed"); + children.push(prog.spawn().expect("error spawning")); } - println!("Sleeping for 1sec"); - thread::sleep(time::Duration::from_secs(1)); + println!("Waiting for all children to die"); + for mut c in children { + c.wait().unwrap(); + } } fn print_usage(opts: Options) { @@ -54,6 +71,7 @@ fn main() { let args: Vec<String> = env::args().collect(); let mut opts = Options::new(); + opts.parsing_style(getopts::ParsingStyle::StopAtFirstFree); opts.optflag("h", "help", "print this help menu"); opts.optflag("v", "verbose", "more debugging messages"); opts.optopt("n", "number", "how many program copies to spawn", "COUNT"); @@ -70,10 +88,16 @@ fn main() { } let number: u64 = match matches.opt_str("number") { - Some(n) => u64::from_str(&n).unwrap(), + Some(n) => u64::from_str(&n).expect("number arg should be an integer"), None => 1 }; + let sock_addrs: Vec<SocketAddr> = matches.opt_strs("bind").iter().map(|b| { + //let sa: SocketAddr = b.to_socket_addrs().unwrap().next().unwrap(); + //sa + b.to_socket_addrs().unwrap().next().unwrap() + }).collect(); + let program_and_args = if !matches.free.is_empty() { matches.free } else { @@ -88,5 +112,13 @@ fn main() { } builder.init().unwrap(); - run(program_and_args, number); + let binds: Vec<TcpListener> = sock_addrs.iter().map(|sa| { + TcpListener::bind(sa).unwrap() + }).collect(); + + let mut prog = Command::new(&program_and_args[0]); + prog.args(&program_and_args[1..]); + + run(binds, prog, number); + exit(0); } |