From 05fe72e73324975b8e668dd96073b11f2ee159fb Mon Sep 17 00:00:00 2001 From: Jake Hillion Date: Wed, 4 May 2022 10:48:44 +0100 Subject: [PATCH] moved argument processing to main.rs --- src/lib.rs | 50 +++++++++------------------------- src/main.rs | 65 ++++++++++++++++++++++++++++++++++++++------- src/spawner/args.rs | 9 +++++-- src/spawner/mod.rs | 6 ++--- 4 files changed, 78 insertions(+), 52 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f7c6477..a4c6065 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,47 +13,23 @@ use specification::Specification; use std::collections::HashMap; use std::fs::File; use std::os::unix::io::FromRawFd; +use std::path::Path; -use clap::{App, AppSettings}; use nix::fcntl::OFlag; use nix::sys::socket; use nix::unistd; -pub fn run() -> Result<()> { - // 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("debug").long("debug").short('d').help("Stop each spawned application process so that it can be attached to.").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(); +pub struct RunArgs<'a> { + pub spec: Option<&'a Path>, + pub debug: bool, - 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); + pub binary: &'a Path, + pub binary_args: Vec<&'a str>, +} +pub fn run(args: &RunArgs) -> Result<()> { // parse the specification - let spec: Specification = if let Some(m) = matches.value_of("spec") { + let spec: Specification = if let Some(m) = args.spec { if m.ends_with(".json") { let f = std::fs::File::open(m)?; Ok(serde_json::from_reader(f)?) @@ -75,13 +51,11 @@ pub fn run() -> Result<()> { let sockets = create_sockets(sockets)?; // spawn all processes - let debug = matches.is_present("debug"); - Spawner { spec: &spec, - binary, - trailing: &trailing, - debug, + binary: args.binary, + binary_args: &args.binary_args, + debug: args.debug, pipes, sockets, diff --git a/src/main.rs b/src/main.rs index f6516ed..06f8f7f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,63 @@ use log::{error, info}; -use clone_shim::run; +use clone_shim::{run, RunArgs}; + +use std::path::Path; + +use clap::{App, AppSettings}; fn main() { - std::process::exit(match run() { - Ok(_) => { - info!("launched successfully"); - exitcode::OK - } - Err(e) => { - error!("error: {}", e); - -1 + // 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("debug").long("debug").short('d').help("Stop each spawned application process so that it can be attached to.").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(); + + // 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); + + // launch process + // execute shimmed process + std::process::exit({ + let (binary, binary_args) = { + let mut argv = matches.values_of("binary").unwrap(); + + let binary = Path::new(argv.next().expect("one value is required")); + let binary_args: Vec<&str> = argv.collect(); + + (binary, binary_args) + }; + + let args = RunArgs { + spec: matches.value_of("spec").map(Path::new), + debug: matches.is_present("debug"), + binary, + binary_args, + }; + + match run(&args) { + Ok(_) => { + info!("launched successfully"); + exitcode::OK + } + Err(e) => { + error!("error: {}", e); + -1 + } } }) } diff --git a/src/spawner/args.rs b/src/spawner/args.rs index b3f4527..e3aba55 100644 --- a/src/spawner/args.rs +++ b/src/spawner/args.rs @@ -6,6 +6,7 @@ use crate::{Error, Result}; use std::ffi::CString; use std::fs::File; use std::net::TcpListener; +use std::os::unix::ffi::OsStrExt; use std::os::unix::io::IntoRawFd; pub struct PreparedArgs(Vec); @@ -162,7 +163,11 @@ impl PreparedArg { trigger: &mut TriggerData, ) -> Result> { match self { - PreparedArg::BinaryName => Ok(vec![CString::new(spawner.binary).unwrap()]), + PreparedArg::BinaryName => { + Ok(vec![ + CString::new(spawner.binary.as_os_str().as_bytes()).unwrap() + ]) + } PreparedArg::Entrypoint => Ok(vec![CString::new(entrypoint).unwrap()]), PreparedArg::Pipe(p) => Ok(vec![CString::new(p.into_raw_fd().to_string()).unwrap()]), @@ -179,7 +184,7 @@ impl PreparedArg { } PreparedArg::Trailing => Ok(spawner - .trailing + .binary_args .iter() .map(|s| CString::new(*s).unwrap()) .collect()), diff --git a/src/spawner/mod.rs b/src/spawner/mod.rs index 3f1bbbb..c310ee8 100644 --- a/src/spawner/mod.rs +++ b/src/spawner/mod.rs @@ -14,7 +14,7 @@ use std::ffi::CString; use std::fs::File; use std::io::Read; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use nix::sys::signal::{kill, Signal}; use nix::sys::socket::{recvmsg, ControlMessageOwned, MsgFlags}; @@ -24,8 +24,8 @@ const BUFFER_SIZE: usize = 1024; pub struct Spawner<'a> { pub spec: &'a Specification, - pub binary: &'a str, - pub trailing: &'a Vec<&'a str>, + pub binary: &'a Path, + pub binary_args: &'a Vec<&'a str>, pub debug: bool, pub pipes: HashMap,