use std::path::Path;
use crate::fuse::mount;
use crate::loader::PackageData;
fn tmpfs_size_for(pkg: &PackageData) -> u64 {
let content_size: u64 = pkg
.manifest
.entries
.iter()
.flat_map(|e| e.blocks.iter())
.map(|b| u64::from(b.original_size))
.sum();
let with_overhead = content_size + content_size / 4;
with_overhead.max(8 * 1024 * 1024)
}
pub fn execute_tmpfs(
pkg: &mut PackageData,
ep_idx: usize,
argv0: &str,
exec_path: &str,
args: &[String],
interp_data: Option<&[u8]>,
env_data: Option<&[u8]>,
) -> bool {
use std::os::unix::process::CommandExt;
mount::sweep_stale_mountpoints();
let mountpoint =
match crate::paths::create_mountpoint(pkg.manifest.name(), &pkg.manifest.header.package_id)
{
Some(m) => m,
None => return false,
};
if let Err(e) = mount::enter_namespace() {
eprintln!("onelf-rt: tmpfs: enter_namespace failed: {e}");
let _ = std::fs::remove_dir(&mountpoint);
return false;
}
let size = tmpfs_size_for(pkg);
if let Err(e) = mount::mount_tmpfs(&mountpoint, size) {
eprintln!("onelf-rt: tmpfs: mount failed: {e}");
let _ = std::fs::remove_dir(&mountpoint);
return false;
}
if let Err(e) = crate::cache::extract_direct(pkg, &mountpoint) {
eprintln!("onelf-rt: tmpfs: extract failed: {e}");
return false;
}
let ep_target_entry = pkg.manifest.entrypoints[ep_idx].target_entry as usize;
let ep_working_dir = pkg.manifest.entrypoints[ep_idx].working_dir;
let ep_name = pkg
.manifest
.get_string(pkg.manifest.entrypoints[ep_idx].name)
.to_string();
let target_path_str = pkg.manifest.entry_path(ep_target_entry);
let target_path = mountpoint.join(&target_path_str);
let mountpoint_str = mountpoint.to_str().unwrap_or("").to_string();
let lib_paths_str = pkg.manifest.lib_dirs().join(":");
let exe_path = Path::new(exec_path);
let exe_dir = exe_path.parent().unwrap_or(Path::new("/"));
let exe_name = exe_path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("onelf");
crate::portable::setup_portable(exe_dir, exe_name);
let target_path_s = target_path.to_str().unwrap_or("");
let lib_path = crate::env::setup_env(
&mountpoint_str,
argv0,
exec_path,
&ep_name,
"tmpfs",
&lib_paths_str,
target_path_s,
);
if let Some(data) = env_data {
crate::env::apply_custom_env(data, &mountpoint_str);
}
match ep_working_dir {
onelf_format::WorkingDir::PackageRoot => {
let _ = std::env::set_current_dir(&mountpoint);
}
onelf_format::WorkingDir::EntrypointParent => {
if let Some(parent) = target_path.parent() {
let _ = std::env::set_current_dir(parent);
}
}
onelf_format::WorkingDir::Inherit => {}
}
let lib_dirs = pkg.manifest.lib_dirs();
let bundled_interp_rel = interp_data.and_then(crate::interp::parse_bundled_interp_rel);
if let Some(interp) =
crate::interp::should_use_userland_exec(&target_path, &mountpoint, bundled_interp_rel)
{
crate::interp::exec_userland(&target_path, &interp, &lib_path, argv0, args);
}
let mut cmd = crate::interp::build_exec_command(
&target_path,
&mountpoint,
&lib_dirs,
&lib_path,
true, argv0,
args,
);
let err = cmd.exec();
eprintln!("onelf-rt: tmpfs: exec failed: {err}");
false
}