diff --git a/src/bin/uhyve.rs b/src/bin/uhyve.rs index 5de640c8..c19b478d 100644 --- a/src/bin/uhyve.rs +++ b/src/bin/uhyve.rs @@ -56,6 +56,16 @@ struct Args { #[clap(long)] file_mapping: Vec, + /// The path that should be used for temporary directories storing unmapped files. + /// + /// This is useful for manually created tmpfs filesystems and for selecting + /// directories not managed by a temporary file cleaner, which can remove open files + /// manually. In most cases, mapping the guest path /root/ instead should be sufficient. + /// + /// Defaults to /tmp. + #[clap(long)] + tempdir: Option, + #[clap(flatten, next_help_heading = "Memory OPTIONS")] memory_args: MemoryArgs, @@ -257,6 +267,7 @@ impl From for Params { #[cfg(target_os = "linux")] gdb_port, file_mapping, + tempdir, kernel: _, kernel_args, output, @@ -277,6 +288,7 @@ impl From for Params { #[cfg(target_os = "macos")] gdb_port: None, kernel_args, + tempdir, // TODO output: if let Some(outp) = output { Output::from_str(&outp).unwrap() diff --git a/src/isolation/filemap.rs b/src/isolation/filemap.rs index b9ba3ebe..67d32e83 100644 --- a/src/isolation/filemap.rs +++ b/src/isolation/filemap.rs @@ -24,7 +24,8 @@ impl UhyveFileMap { /// Creates a UhyveFileMap. /// /// * `mappings` - A list of host->guest path mappings with the format "./host_path.txt:guest.txt" - pub fn new(mappings: &[String]) -> UhyveFileMap { + /// * `tempdir` - Path to create temporary directory on + pub fn new(mappings: &[String], tempdir: &Option) -> UhyveFileMap { UhyveFileMap { files: mappings .iter() @@ -32,7 +33,7 @@ impl UhyveFileMap { .map(Self::split_guest_and_host_path) .map(Result::unwrap) .collect(), - tempdir: create_temp_dir(), + tempdir: create_temp_dir(tempdir), } } @@ -193,7 +194,7 @@ mod tests { path_prefix.clone() + "/this_symlink_leads_to_a_file" + ":guest_file_symlink", ]; - let mut map = UhyveFileMap::new(&map_parameters); + let mut map = UhyveFileMap::new(&map_parameters, &None); assert_eq!( map.get_host_path("readme_file.md").unwrap(), @@ -245,7 +246,7 @@ mod tests { host_path_map.to_str().unwrap(), guest_path_map.to_str().unwrap() )]; - let mut map = UhyveFileMap::new(&uhyvefilemap_params); + let mut map = UhyveFileMap::new(&uhyvefilemap_params, &None); let mut found_host_path = map.get_host_path(target_guest_path.clone().to_str().unwrap()); @@ -276,7 +277,7 @@ mod tests { guest_path_map.to_str().unwrap() )]; - map = UhyveFileMap::new(&uhyvefilemap_params); + map = UhyveFileMap::new(&uhyvefilemap_params, &None); target_guest_path = PathBuf::from("/root/this_symlink_leads_to_a_file"); target_host_path = fixture_path.clone(); @@ -289,7 +290,7 @@ mod tests { // Tests directory traversal with no maps let empty_array: [String; 0] = []; - map = UhyveFileMap::new(&empty_array); + map = UhyveFileMap::new(&empty_array, &None); found_host_path = map.get_host_path(target_guest_path.to_str().unwrap()); assert!(found_host_path.is_none()); } diff --git a/src/isolation/tempdir.rs b/src/isolation/tempdir.rs index 496f4abf..8b8e7f9d 100644 --- a/src/isolation/tempdir.rs +++ b/src/isolation/tempdir.rs @@ -1,15 +1,30 @@ use std::{fs::Permissions, os::unix::fs::PermissionsExt}; use tempfile::{Builder, TempDir}; +use uuid::Uuid; /// Creates a temporary directory. -pub fn create_temp_dir() -> TempDir { - let dir = Builder::new() - .permissions(Permissions::from_mode(0o700)) - .prefix("uhyve-") - .tempdir() - .ok() - .unwrap_or_else(|| panic!("The temporary directory could not be created.")); +/// +/// * `dir_path` - The location in which the temporary directory should be created. +pub fn create_temp_dir(dir_path: &Option) -> TempDir { + let dir: TempDir; + if let Some(dir_path) = dir_path { + dir = Builder::new() + .permissions(Permissions::from_mode(0o700)) + .prefix("uhyve-") + .suffix(&Uuid::new_v4().to_string()) + .tempdir_in(dir_path) + .ok() + .unwrap_or_else(|| panic!("The temporary directory could not be created.")); + } else { + dir = Builder::new() + .permissions(Permissions::from_mode(0o700)) + .prefix("uhyve-") + .suffix(&Uuid::new_v4().to_string()) + .tempdir() + .ok() + .unwrap_or_else(|| panic!("The temporary directory could not be created.")); + } let dir_permissions = dir.path().metadata().unwrap().permissions(); assert!(!dir_permissions.readonly()); diff --git a/src/params.rs b/src/params.rs index 547bb918..15d2fa39 100644 --- a/src/params.rs +++ b/src/params.rs @@ -38,6 +38,9 @@ pub struct Params { /// Mapped paths between the guest and host OS pub file_mapping: Vec, + /// Path to create temporary directory on + pub tempdir: Option, + /// Kernel output handling pub output: Output, @@ -59,6 +62,7 @@ impl Default for Params { cpu_count: Default::default(), gdb_port: Default::default(), file_mapping: Default::default(), + tempdir: Default::default(), kernel_args: Default::default(), output: Default::default(), stats: false, diff --git a/src/vm.rs b/src/vm.rs index c22097b6..a10fbb9c 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -185,7 +185,7 @@ impl UhyveVm { "gdbstub is only supported with one CPU" ); - let file_mapping = Mutex::new(UhyveFileMap::new(¶ms.file_mapping)); + let file_mapping = Mutex::new(UhyveFileMap::new(¶ms.file_mapping, ¶ms.tempdir)); let output = match params.output { params::Output::None => Output::None,