From 26e6708c966497ddf794e420de6593303114bc01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tenn=C3=A9?= Date: Tue, 20 Jun 2023 12:14:13 +0200 Subject: [PATCH] Fix tmpfiles.d symlinking This makes nix-ld and opengl-driver work --- src/config.rs | 4 ++-- src/setup.rs | 33 +++++++++++++++++++++++++++------ src/util/resolve_symlink.rs | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/config.rs b/src/config.rs index ae78334..28d0a54 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,7 +19,7 @@ fn data_dir() -> Option { fn current_system_dir() -> Option { let datadir = data_dir()?.join("root"); if datadir.symlink_metadata().is_ok() { - Some(datadir.join("sw/bin")) + Some(datadir) } else { None } @@ -79,7 +79,7 @@ impl Config { match current_system.clone() { Some(x) => { let mut os: OsString = x.into_os_string(); - os.push(":/usr/bin:/bin"); + os.push("/sw/bin:/usr/bin:/bin"); os } None => OsString::from("/usr/local/bin:/usr/bin:/bin"), diff --git a/src/setup.rs b/src/setup.rs index a4f56c6..9a09aca 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -26,10 +26,23 @@ pub fn setup(config: &Config) { if let Some(nix_profile_dir) = &config.nix_profile { bind_nix_profile(&config.chroot_dir, &config.nix_home, config.nixbox_root()); - bind_tmpfiles(nix_profile_dir); + bind_tmpfiles( + &config.chroot_dir, + &config.nix_home, + &nix_profile_dir.join("lib/tmpfiles.d"), + ); if let Some(current_system) = &config.current_system { - bind_tmpfiles(current_system); + bind_tmpfiles( + &config.chroot_dir, + &config.nix_home, + ¤t_system.join("lib/tmpfiles.d"), + ); + bind_tmpfiles( + &config.chroot_dir, + &config.nix_home, + ¤t_system.join("etc/tmpfiles.d"), + ); } } else { bind_host(&config.chroot_dir); @@ -188,11 +201,16 @@ fn bind_common(nix_dir: &Path, chroot_dir: &Path) { } } -fn bind_tmpfiles(path: &Path) { - let Ok(dir) = fs::read_dir(path.join("lib/tmpfiles.d")) else { return; }; +fn bind_tmpfiles(chroot_dir: &Path, nix_dir: &Path, path: &Path) { + println!("try read {:?}", path); + let Ok(path) = resolve_symlink(&(&Path::new("/nix"), &nix_dir), path) else { return; }; + println!("+++ read {:?}", path); + let Ok(dir) = fs::read_dir(path) else { return; }; + println!("read {:?}", dir); for entry in dir { let path = entry.unwrap().path(); + let Ok(path) = resolve_symlink(&(&Path::new("/nix"), &nix_dir), path) else { continue; }; if !path.is_file() { continue; } @@ -203,8 +221,11 @@ fn bind_tmpfiles(path: &Path) { let line = line.unwrap(); let vec = line.split_ascii_whitespace().collect::>(); if let ["L+", target, "-", "-", "-", "-", source] = vec.as_slice() { - fs::create_dir_all(Path::new(target).parent().unwrap_or(Path::new("/"))).unwrap(); - create_symlink(Path::new(source), Path::new(target)); + let Some(target) = target.strip_prefix('/') else { continue; }; + let target = chroot_dir.join(target); + println!("{:?} -> {:?}", source, target); + fs::create_dir_all(target.parent().unwrap_or(Path::new("/"))).unwrap(); + create_symlink(Path::new(source), &target); } } } diff --git a/src/util/resolve_symlink.rs b/src/util/resolve_symlink.rs index b32fd12..c1e2826 100644 --- a/src/util/resolve_symlink.rs +++ b/src/util/resolve_symlink.rs @@ -16,7 +16,7 @@ pub fn resolve_symlink( current_dir()?.join(path) }; - loop { + '_loop: loop { if path.symlink_metadata().is_err() { for parent in path.ancestors().skip(1) { if !parent.is_symlink() { @@ -25,7 +25,7 @@ pub fn resolve_symlink( let resolved = resolve_symlink(mapping, parent)?; path = resolved.join(path.strip_prefix(parent).unwrap()); - break; + continue '_loop; } } @@ -108,6 +108,36 @@ mod tests { assert_eq!(expect, actual); } + #[test] + fn it_resolves_nested() { + let path: PathBuf = testdir!(); + let expect = path.join("file"); + + File::create(&expect).unwrap(); + + // 'dir1/dir2' -> 'dir2' + fs::create_dir(path.join("dir1")).unwrap(); + symlink("/fake-directory/dir2", path.join("dir1/dir2")).unwrap(); + + // 'dir2/dir3' -> 'dir3' + fs::create_dir(path.join("dir2")).unwrap(); + symlink("/fake-directory/dir3", path.join("dir2/dir3")).unwrap(); + + // 'dir3/file' -> 'file' + fs::create_dir(path.join("dir3")).unwrap(); + symlink("/fake-directory/file", path.join("dir3/file")).unwrap(); + + // Cannot resolve symlink + assert!(path.join("dir1/dir2/dir3/file").canonicalize().is_err()); + + let actual = resolve_symlink( + &("/fake-directory", &path), + &path.join("dir1/dir2/dir3/file"), + ) + .unwrap(); + assert_eq!(expect, actual); + } + #[test] fn it_errors_when_file_not_found() { let path: PathBuf = testdir!();