diff --git a/README.md b/README.md index abd36d7..a43b614 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ Preset files are simple TOML files which contain: * A list of packages to install: `packages = ["mypackage"]` * A post-installation script: `script = """ ... """` * Environment variables required by the preset (e.g. used in the script): `enironment_variables = ["USERNAME"]` +* A list of shared directories `shared_directories = ["subdirectory"]` - where subdirectory would be available at `/shared_dirs/subdirectory/` for use in the script of the preset. See the presets directory for examples. @@ -106,6 +107,8 @@ Presets are used via the `--presets` argument (multiple preset files or director sudo ALMA_USER=archie alma create /dev/disk/by-id/usb-Generic_USB_Flash_Disk-0:0 --presets ./presets/user.toml ./presets/custom_preset.toml ``` +Preset scripts are executed in the same order they are provided. + If a directory is provided, then all files and subdirectories in the directory are recursively crawled in alphanumeric order (all files must be ALMA .toml files). This allows you to use the following structure to compose many scripts in a specific order: ``` @@ -132,7 +135,7 @@ usermod -G wheel -a ${ALMA_USER} environment_variables = ["ALMA_USER"] ``` -Preset scripts are executed in the same order they are provided. +Note that shared directories in the preset scripts are mounted as bind mounts, so they are *not* mounted read-only. Any changes the custom script makes to the shared directory will be carried out in the preset shared directory of the host system, so be sure to copy (not move) files from the shared directories. ## Similar projects diff --git a/presets/copy_file.toml b/presets/copy_file.toml new file mode 100644 index 0000000..43bc5ff --- /dev/null +++ b/presets/copy_file.toml @@ -0,0 +1,5 @@ +script = """ +ls /shared_dirs/copy_file_example/ +cp /shared_dirs/copy_file_example/testfile.txt /root/ +""" +shared_directories = ["copy_file_example"] diff --git a/presets/copy_file_example/testfile.txt b/presets/copy_file_example/testfile.txt new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/presets/copy_file_example/testfile.txt @@ -0,0 +1 @@ +test diff --git a/src/main.rs b/src/main.rs index a9ad9fe..abebcae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ use std::process::{exit, Command as ProcessCommand}; use std::thread; use std::time::Duration; use storage::EncryptedDevice; -use storage::{BlockDevice, Filesystem, FilesystemType, LoopDevice}; +use storage::{BlockDevice, Filesystem, FilesystemType, LoopDevice, MountStack}; use structopt::StructOpt; use tempfile::tempdir; use tool::Tool; @@ -264,10 +264,33 @@ fn create(command: args::CreateCommand) -> Result<(), Error> { } for script in presets.scripts { + let mut bind_mount_stack = MountStack::new(); + if let Some(shared_dirs) = &script.shared_dirs { + for dir in shared_dirs { + // Create shared directories mount points inside chroot + std::fs::create_dir_all( + mount_point + .path() + .join(PathBuf::from("shared_dirs/")) + .join(dir.file_name().unwrap()), + ) + .context(ErrorKind::PresetScript)?; + + // Bind mount shared directories + let target = mount_point + .path() + .join(PathBuf::from("shared_dirs/")) + .join(dir.file_name().unwrap()); + bind_mount_stack + .bind_mount(dir.clone(), target, None) + .context(ErrorKind::Mounting)?; + } + } + let mut script_file = tempfile::NamedTempFile::new_in(mount_point.path()).context(ErrorKind::PresetScript)?; script_file - .write_all(script.as_bytes()) + .write_all(script.script_text.as_bytes()) .and_then(|_| script_file.as_file_mut().metadata()) .and_then(|metadata| { let mut permissions = metadata.permissions(); diff --git a/src/presets.rs b/src/presets.rs index 6a7c022..54db31d 100644 --- a/src/presets.rs +++ b/src/presets.rs @@ -12,6 +12,7 @@ struct Preset { packages: Option>, script: Option, environment_variables: Option>, + shared_directories: Option>, } fn visit_dirs(dir: &Path, filevec: &mut Vec) -> Result<(), io::Error> { @@ -22,7 +23,9 @@ fn visit_dirs(dir: &Path, filevec: &mut Vec) -> Result<(), io::Error> { if path.is_dir() { visit_dirs(&path, filevec)?; } else { - filevec.push(entry.path()); + if entry.path().extension() == Some(&std::ffi::OsString::from("toml")) { + filevec.push(entry.path()); + } } } } @@ -40,9 +43,10 @@ impl Preset { fn process( &self, packages: &mut HashSet, - scripts: &mut Vec, + scripts: &mut Vec