diff --git a/warp-packer/Cargo.toml b/warp-packer/Cargo.toml index c592916..4609231 100644 --- a/warp-packer/Cargo.toml +++ b/warp-packer/Cargo.toml @@ -8,6 +8,7 @@ clap = "2.32.0" dirs = "1.0.4" reqwest = "0.9.2" tempdir = "0.3.7" +rand = "0.6" flate2 = "1.0" tar = "0.4" lazy_static = "1.1.0" \ No newline at end of file diff --git a/warp-packer/src/main.rs b/warp-packer/src/main.rs index 8bc9796..5dece14 100644 --- a/warp-packer/src/main.rs +++ b/warp-packer/src/main.rs @@ -3,6 +3,7 @@ extern crate dirs; extern crate flate2; #[macro_use] extern crate lazy_static; +extern crate rand; extern crate reqwest; extern crate tar; extern crate tempdir; @@ -10,6 +11,8 @@ extern crate tempdir; use clap::{App, AppSettings, Arg}; use flate2::Compression; use flate2::write::GzEncoder; +use rand::{thread_rng, Rng}; +use rand::distributions::Alphanumeric; use std::collections::HashMap; use std::error::Error; use std::fs; @@ -26,7 +29,8 @@ const APP_NAME: &str = env!("CARGO_PKG_NAME"); const AUTHOR: &str = env!("CARGO_PKG_AUTHORS"); const VERSION: &str = env!("CARGO_PKG_VERSION"); -const RUNNER_MAGIC: &[u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0"; +const RUNNER_EXEC_MAGIC: &[u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0"; +const RUNNER_UID_MAGIC: &[u8] = b"DR1PWsJsM6KxNbng9Y38\0"; const RUNNER_LINUX_X64: &[u8] = include_bytes!("../../target/x86_64-unknown-linux-gnu/release/warp-runner"); const RUNNER_MACOS_X64: &[u8] = include_bytes!("../../target/x86_64-apple-darwin/release/warp-runner"); @@ -51,34 +55,38 @@ macro_rules! bail { }) } -fn patch_runner(arch: &str, exec_name: &str) -> io::Result> { +fn patch_runner(arch: &str, exec_name: &str, uid: &str) -> io::Result> { // Read runner executable in memory let runner_contents = RUNNER_BY_ARCH.get(arch).unwrap(); let mut buf = runner_contents.to_vec(); - // Set the correct target executable name into the local magic buffer - let magic_len = RUNNER_MAGIC.len(); + write_magic(&mut buf, RUNNER_UID_MAGIC, uid); + write_magic(&mut buf, RUNNER_EXEC_MAGIC, exec_name); + Ok(buf) +} + +fn write_magic(buf: &mut Vec, magic: &[u8], new_value: &str) { + // Set the correct target executable name into the local magic buffer + let magic_len = magic.len(); let mut new_magic = vec![0; magic_len]; - new_magic[..exec_name.len()].clone_from_slice(exec_name.as_bytes()); + new_magic[..new_value.len()].clone_from_slice(new_value.as_bytes()); // Find the magic buffer offset inside the runner executable let mut offs_opt = None; for (i, chunk) in buf.windows(magic_len).enumerate() { - if chunk == RUNNER_MAGIC { + if chunk == magic { offs_opt = Some(i); break; } } if offs_opt.is_none() { - return Err(io::Error::new(io::ErrorKind::Other, "no magic found inside runner")); + bail!("no magic found inside runner"); } // Replace the magic with the new one that points to the target executable let offs = offs_opt.unwrap(); buf[offs..offs + magic_len].clone_from_slice(&new_magic); - - Ok(buf) } fn create_tgz(dirs: &Vec<&Path>, out: &Path) -> io::Result<()> { @@ -145,6 +153,13 @@ fn check_executable_exists(exec_path: &Path){ } } +fn generate_uid() -> String { + return thread_rng() + .sample_iter(&Alphanumeric) + .take(RUNNER_UID_MAGIC.len() - 1) + .collect(); +} + fn main() -> Result<(), Box> { let args = App::new(APP_NAME) .settings(&[AppSettings::ArgRequiredElseHelp, AppSettings::ColoredHelp]) @@ -200,6 +215,14 @@ fn main() -> Result<(), Box> { .display_order(6) .takes_value(true) .required(true)) + .arg(Arg::with_name("unique_id") + .short("q") + .long("unique_id") + .value_name("unique_id") + .help("Generate unique id for each package build") + .display_order(7) + .takes_value(false) + .required(false)) .get_matches(); let arch = args.value_of("arch").unwrap(); @@ -223,7 +246,7 @@ fn main() -> Result<(), Box> { .collect(); let exec_name = args.value_of("exec").unwrap(); - if exec_name.len() >= RUNNER_MAGIC.len() { + if exec_name.len() >= RUNNER_EXEC_MAGIC.len() { bail!("Executable name is too long, please consider using a shorter name"); } @@ -233,7 +256,13 @@ fn main() -> Result<(), Box> { check_executable_exists(&exec_path); } - let runner_buf = patch_runner(&arch, &exec_name)?; + let mut uid:String = "".to_string(); + let do_generate_uid = args.is_present("unique_id"); + if do_generate_uid { + uid = generate_uid(); + } + + let runner_buf = patch_runner(&arch, &exec_name, &uid)?; create_tgz(&input_dirs, &main_tgz_path)?; diff --git a/warp-runner/src/main.rs b/warp-runner/src/main.rs index f711f4c..7b7da84 100644 --- a/warp-runner/src/main.rs +++ b/warp-runner/src/main.rs @@ -16,17 +16,26 @@ mod extractor; mod executor; static TARGET_FILE_NAME_BUF: &'static [u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0"; +static TARGET_UID_BUF: &'static [u8] = b"DR1PWsJsM6KxNbng9Y38\0"; + +fn build_uid() -> &'static str { + return read_magic("TARGET_UID_BUF", &TARGET_UID_BUF) +} fn target_file_name() -> &'static str { - let nul_pos = TARGET_FILE_NAME_BUF.iter() - .position(|elem| *elem == b'\0') - .expect("TARGET_FILE_NAME_BUF has no NUL terminator"); + return read_magic("TARGET_FILE_NAME_BUF", &TARGET_FILE_NAME_BUF) +} - let slice = &TARGET_FILE_NAME_BUF[..(nul_pos + 1)]; +fn read_magic(magic_name: &str, magic: &'static [u8]) -> &'static str { + let nul_pos = magic.iter() + .position(|elem| *elem == b'\0') + .expect(&format!("{} has no NUL terminator", magic_name)); + + let slice = &magic[..(nul_pos + 1)]; CStr::from_bytes_with_nul(slice) - .expect("Can't convert TARGET_FILE_NAME_BUF slice to CStr") + .expect(&format!("Can't convert {} slice to CStr", magic_name)) .to_str() - .expect("Can't convert TARGET_FILE_NAME_BUF CStr to str") + .expect(&format!("Can't convert {} CStr to str", magic_name)) } fn cache_path(target: &str) -> PathBuf { @@ -48,12 +57,17 @@ fn main() -> Result<(), Box> { simple_logger::init_with_level(Level::Trace)?; } + + + let build_uid = build_uid(); let self_path = env::current_exe()?; let self_file_name = self_path.file_name().unwrap(); - let cache_path = cache_path(&self_file_name.to_string_lossy()); + let cache_folder_name = format!("{}.{}", self_file_name.to_string_lossy(), build_uid); + let cache_path = cache_path(&cache_folder_name); trace!("self_path={:?}", self_path); trace!("self_file_name={:?}", self_file_name); + trace!("build_uid={:?}", build_uid); trace!("cache_path={:?}", cache_path); let target_file_name = target_file_name();