diff --git a/Cargo.lock b/Cargo.lock index 493796d..e7fc4f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -52,7 +58,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -62,7 +68,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -71,6 +77,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.4.1" @@ -104,6 +116,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.31" @@ -115,7 +133,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -174,7 +192,7 @@ checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -183,6 +201,15 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "deranged" version = "0.3.9" @@ -200,12 +227,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.5" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -223,6 +250,28 @@ dependencies = [ "winapi", ] +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "hashbrown" version = "0.14.2" @@ -282,7 +331,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -308,15 +357,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" @@ -334,14 +383,38 @@ dependencies = [ "colored", "exitcode", "filesize", + "flate2", "log", + "nix", "serde", "serde_yaml", "sys-info", + "tar", "time", "walkdir", ] +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -381,17 +454,26 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "rustix" -version = "0.38.20" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -469,6 +551,17 @@ dependencies = [ "libc", ] +[[package]] +name = "tar" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "time" version = "0.3.30" @@ -627,7 +720,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -636,7 +729,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", ] [[package]] @@ -645,13 +747,29 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -660,38 +778,97 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] diff --git a/Cargo.toml b/Cargo.toml index 4027db2..d9726ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,10 +18,13 @@ clap = { version = "4.3.24", features = [ colored = "2.0.4" exitcode = "1.1.2" filesize = "0.2.0" +flate2 = "1.0.30" log = "0.4.20" +nix = "0.29.0" serde = { version = "1.0.188", features = ["derive", "alloc"] } serde_yaml = "0.9.25" sys-info = "0.9.1" +tar = "0.4.41" time = "0.3.28" walkdir = "2.4.0" diff --git a/src/clidef.rs b/src/clidef.rs index caf09c1..28e15b2 100644 --- a/src/clidef.rs +++ b/src/clidef.rs @@ -74,6 +74,12 @@ pub fn cli(version: &'static str) -> Command { .required_unless_present_any(["help", "version"]) .help("Root filesystem, e.g. mountpoint of an image") ) + .arg( + Arg::new("copy") + .short('c') + .long("copy") + .help("Collect all library dependencies of a target executable,\nand copy everything to a specified directory.") + ) // Filters .next_help_heading("Filters") diff --git a/src/main.rs b/src/main.rs index b523a2a..0b61f48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -100,6 +100,7 @@ fn get_profile(mut cli: Command, params: &ArgMatches) -> Profile { /// Main fn main() -> Result<(), std::io::Error> { + let default_empty = String::from(""); let args: Vec = env::args().collect(); let mut cli = clidef::cli(VERSION); @@ -151,6 +152,7 @@ fn main() -> Result<(), std::io::Error> { .set_profile(get_profile(cli, ¶ms)) .set_dry_run(params.get_flag("dry-run")) .set_autodeps(params.get_one::("autodeps").unwrap().to_string()) + .copy_to(params.get_one::("copy").unwrap_or_else(|| &default_empty))? .start() { log::error!("{}", err); diff --git a/src/procdata.rs b/src/procdata.rs index ba71583..06bbc73 100644 --- a/src/procdata.rs +++ b/src/procdata.rs @@ -1,3 +1,8 @@ +use chrono::Local; +use flate2::{write::GzEncoder, Compression}; +use log::{info, warn}; +use tar::Builder; + use crate::{ filters::{dirs::PathsDataFilter, intf::DataFilter, resources::ResourcesDataFilter, texts::TextDataFilter}, profile::Profile, @@ -5,11 +10,12 @@ use crate::{ scanner::{binlib::ElfScanner, debpkg::DebPackageScanner, dlst::ContentFormatter, general::Scanner}, shcall::ShellScript, }; -use std::fs::{self, canonicalize, remove_file, DirEntry, File}; +use core::arch; use std::{ collections::HashSet, - io::Error, - os::unix, + fs::{self, canonicalize, remove_file, DirEntry, File}, + io::{Error, ErrorKind}, + os::{fd::AsRawFd, unix}, path::{Path, PathBuf}, }; @@ -29,6 +35,7 @@ pub struct TintProcessor { dry_run: bool, autodeps: Autodeps, lockfile: PathBuf, + copy_to: Option, // do not erase unneeded, but instead extract content into an archive } impl TintProcessor { @@ -39,6 +46,7 @@ impl TintProcessor { dry_run: true, autodeps: Autodeps::Free, lockfile: PathBuf::from("/.tinted.lock"), + copy_to: None, } } @@ -66,8 +74,28 @@ impl TintProcessor { self } + // Set a path of an archive where to copy all the content, + // instead of erasing everything else from the given rootfs + pub fn copy_to(&mut self, dst: &str) -> Result<&mut Self, Error> { + if dst.is_empty() { + // Quietly bail-out + return Ok(self); + } + + let mut p = PathBuf::from(dst); + if p.is_dir() { + return Err(Error::new(ErrorKind::InvalidData, format!("{:?} is a directory", p))); + } else if p.exists() { + return Err(Error::new(ErrorKind::AlreadyExists, format!("File {:?} already exists", p))); + } + + self.copy_to = Some(p); + + Ok(self) + } + // Chroot to the mount point - fn switch_root(&self) -> Result<(), Error> { + fn switch_root(&mut self) -> Result<(), Error> { unix::fs::chroot(self.root.to_str().unwrap())?; std::env::set_current_dir("/")?; @@ -126,6 +154,37 @@ impl TintProcessor { Ok(()) } + /// Archive paths that needs to be preserved + fn into_archive(&self, paths: &Vec) -> Result<(), Error> { + let tmpdir = PathBuf::from(format!( + "/tmp/{}-{}", + self.copy_to.as_ref().unwrap().file_name().unwrap().to_str().unwrap_or_default(), + Local::now().format("%Y%m%d%H%M%S").to_string() + )); + + for src in paths { + let dst = tmpdir.join(src.strip_prefix("/").unwrap()); + if !dst.parent().unwrap().exists() { + fs::create_dir_all(dst.parent().unwrap())?; + } + + fs::copy(&src, &dst)?; + info!("Archiving {:?}", src); + } + + // targz the content + let archname = format!("{}.tar.gz", tmpdir.as_os_str().to_str().unwrap()); + let mut builder = Builder::new(GzEncoder::new(File::create(&archname)?, Compression::best())); + builder.append_dir_all(self.copy_to.to_owned().unwrap().file_name().unwrap().to_str().unwrap(), &tmpdir)?; + builder.into_inner()?.finish()?; + + // Cleanup + fs::remove_dir_all(tmpdir)?; + info!("Package archive has been created at {:?}", self.root.join(archname.trim_start_matches("/"))); + + Ok(()) + } + fn ext_path(p: HashSet, mut np: HashSet) -> HashSet { for tgt in p.iter() { if tgt.is_symlink() { @@ -161,12 +220,12 @@ impl TintProcessor { } // Start tint processor - pub fn start(&self) -> Result<(), Error> { + pub fn start(&mut self) -> Result<(), Error> { self.switch_root()?; // Bail-out if the image is already processed if self.lockfile.exists() { - return Err(Error::new(std::io::ErrorKind::AlreadyExists, "This container seems already tinted.")); + return Err(Error::new(ErrorKind::AlreadyExists, "This container seems already tinted.")); } // Run pre-hook, if any @@ -255,11 +314,16 @@ impl TintProcessor { } ContentFormatter::new(&paths).set_removed(&p).set_bundled_packages(self.profile.get_bundled_packages()).format(); } else { - // Run post-hook (doesn't affect changes apply) - if self.profile.has_post_hook() { - Self::call_script(self.profile.get_post_hook())?; + if self.copy_to.is_some() { + self.into_archive(&paths)?; + } else { + // Erase mode + if self.profile.has_post_hook() { + // Run post-hook (doesn't affect changes apply) + Self::call_script(self.profile.get_post_hook())?; + } + self.apply_changes(p)?; } - self.apply_changes(p)?; } Ok(())