use std::env;
use std::path::Path;
pub fn setup_env(
onelf_dir: &str,
argv0: &str,
exec_path: &str,
entrypoint_name: &str,
mode: &str,
lib_subpath: &str,
target_path: &str,
) {
let launch_dir = env::current_dir()
.ok()
.and_then(|p| p.to_str().map(String::from))
.unwrap_or_default();
unsafe {
env::set_var("ONELF_DIR", onelf_dir);
env::set_var("ONELF_ARGV0", argv0);
env::set_var("ONELF_EXEC", exec_path);
env::set_var("ONELF_ENTRYPOINT", entrypoint_name);
env::set_var("ONELF_LAUNCH_DIR", &launch_dir);
env::set_var("ONELF_MODE", mode);
}
if onelf_dir.is_empty() {
return;
}
let pkg = Path::new(onelf_dir);
let target_is_elf = is_elf_file(target_path);
if target_is_elf && !lib_subpath.is_empty() {
let lib_paths: Vec<String> = lib_subpath
.split(':')
.map(|p| pkg.join(p).to_string_lossy().to_string())
.collect();
let lib_str = lib_paths.join(":");
if !lib_str.is_empty() {
let existing = env::var("LD_LIBRARY_PATH").unwrap_or_default();
let mut parts: Vec<String> = Vec::new();
parts.push(lib_str.clone());
if !existing.is_empty() {
parts.push(existing);
}
let host_paths = host_driver_paths();
if !host_paths.is_empty() {
parts.push(host_paths.join(":"));
}
unsafe {
env::set_var("LD_LIBRARY_PATH", parts.join(":"));
}
let dri_paths: Vec<String> = lib_paths
.iter()
.map(|p| Path::new(p).join("dri").to_string_lossy().to_string())
.filter(|p| Path::new(p).is_dir())
.collect();
if !dri_paths.is_empty() {
let joined = dri_paths.join(":");
if env::var("LIBGL_DRIVERS_PATH").is_err() {
unsafe {
env::set_var("LIBGL_DRIVERS_PATH", &joined);
}
}
if env::var("LIBVA_DRIVERS_PATH").is_err() {
unsafe {
env::set_var("LIBVA_DRIVERS_PATH", &joined);
}
}
}
if env::var("GBM_BACKENDS_PATH").is_err() {
let gbm_paths: Vec<String> = lib_paths
.iter()
.map(|p| Path::new(p).join("gbm").to_string_lossy().to_string())
.filter(|p| Path::new(p).is_dir())
.collect();
if !gbm_paths.is_empty() {
unsafe {
env::set_var("GBM_BACKENDS_PATH", gbm_paths.join(":"));
}
}
}
}
}
setup_xdg_data_dirs(pkg);
if env::var("__EGL_VENDOR_LIBRARY_DIRS").is_err() {
let egl_dir = pkg.join("share/glvnd/egl_vendor.d");
if egl_dir.is_dir() {
unsafe {
env::set_var(
"__EGL_VENDOR_LIBRARY_DIRS",
egl_dir.to_string_lossy().as_ref(),
);
}
}
}
if env::var("DRIRC_CONFIGDIR").is_err() {
let drirc_dir = pkg.join("share/drirc.d");
if drirc_dir.is_dir() {
unsafe {
env::set_var("DRIRC_CONFIGDIR", drirc_dir.to_string_lossy().as_ref());
}
}
}
if env::var("LIBDRM_IDS_PATH").is_err() {
let libdrm_dir = pkg.join("share/libdrm");
if libdrm_dir.is_dir() {
unsafe {
env::set_var("LIBDRM_IDS_PATH", libdrm_dir.to_string_lossy().as_ref());
}
}
}
if env::var("XKB_CONFIG_ROOT").is_err() {
let xkb_dir = pkg.join("share/X11/xkb");
if xkb_dir.is_dir() {
unsafe {
env::set_var("XKB_CONFIG_ROOT", xkb_dir.to_string_lossy().as_ref());
}
}
}
if env::var("LIBDECOR_PLUGIN_DIR").is_err() {
let libdecor_dir = pkg.join("share/libdecor/plugins-1");
if libdecor_dir.is_dir() {
unsafe {
env::set_var(
"LIBDECOR_PLUGIN_DIR",
libdecor_dir.to_string_lossy().as_ref(),
);
}
}
}
if env::var("VK_DRIVER_FILES").is_err() {
let vk_dir = pkg.join("share/vulkan/icd.d");
if vk_dir.is_dir() {
if let Ok(entries) = std::fs::read_dir(&vk_dir) {
let icd_files: Vec<String> = entries
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().map_or(false, |ext| ext == "json"))
.map(|e| e.path().to_string_lossy().into_owned())
.collect();
if !icd_files.is_empty() {
unsafe {
env::set_var("VK_DRIVER_FILES", icd_files.join(":"));
}
}
}
}
}
}
fn is_elf_file(path: &str) -> bool {
use std::io::Read;
let Ok(mut f) = std::fs::File::open(path) else {
return false;
};
let mut buf = [0u8; 4];
matches!(f.read(&mut buf), Ok(4)) && buf == *b"\x7fELF"
}
fn host_driver_paths() -> Vec<String> {
const CANDIDATES: &[&str] = &[
"/run/opengl-driver/lib",
"/run/opengl-driver-32/lib",
"/usr/lib/x86_64-linux-gnu",
"/usr/lib64",
"/usr/lib",
"/lib/x86_64-linux-gnu",
"/lib64",
];
CANDIDATES
.iter()
.filter(|p| Path::new(p).is_dir())
.map(|s| (*s).to_string())
.collect()
}
fn setup_xdg_data_dirs(pkg: &Path) {
let share = pkg.join("share");
if !share.is_dir() {
return;
}
let pkg_share = share.to_string_lossy();
let existing = env::var("XDG_DATA_DIRS").unwrap_or_default();
let new_val = if existing.is_empty() {
format!("{pkg_share}:/usr/local/share:/usr/share")
} else {
format!("{pkg_share}:{existing}")
};
unsafe {
env::set_var("XDG_DATA_DIRS", new_val);
}
}