diff --git a/pkgs/build-support/build-fhs-userenv/chroot-user.rb b/pkgs/build-support/build-fhs-userenv/chroot-user.rb index b7d6276ceab0..05b4914b6f6b 100755 --- a/pkgs/build-support/build-fhs-userenv/chroot-user.rb +++ b/pkgs/build-support/build-fhs-userenv/chroot-user.rb @@ -1,18 +1,18 @@ #!/usr/bin/env ruby -# Bind mounts hierarchy: [from, to (relative)] +# Bind mounts hierarchy: from => to (relative) # If 'to' is nil, path will be the same -mounts = [ ['/nix/store', nil], - ['/dev', nil], - ['/proc', nil], - ['/sys', nil], - ['/etc', 'host-etc'], - ['/tmp', 'host-tmp'], - ['/home', nil], - ['/var', nil], - ['/run', nil], - ['/root', nil], - ] +mounts = { '/nix/store' => nil, + '/dev' => nil, + '/proc' => nil, + '/sys' => nil, + '/etc' => 'host-etc', + '/tmp' => 'host-tmp', + '/home' => nil, + '/var' => nil, + '/run' => nil, + '/root' => nil, + } # Propagate environment variables envvars = [ 'TERM', @@ -65,8 +65,22 @@ abort "Usage: chrootenv swdir program args..." unless ARGV.length >= 2 swdir = Pathname.new ARGV[0] execp = ARGV.drop 1 +# Populate extra mounts +if not ENV["CHROOTENV_EXTRA_BINDS"].nil? + for extra in ENV["CHROOTENV_EXTRA_BINDS"].split(':') + paths = extra.split('=') + if not paths.empty? + if paths.size <= 2 + mounts[paths[0]] = paths[1] + else + $stderr.puts "Ignoring invalid entry in CHROOTENV_EXTRA_BINDS: #{extra}" + end + end + end +end + # Set destination paths for mounts -mounts.map! { |x| [x[0], x[1].nil? ? x[0].sub(/^\/*/, '') : x[1]] } +mounts = mounts.map { |k, v| [k, v.nil? ? k.sub(/^\/*/, '') : v] }.to_h # Create temporary directory for root and chdir root = Dir.mktmpdir 'chrootenv' @@ -97,10 +111,10 @@ if $cpid == 0 write_file '/proc/self/gid_map', "#{gid} #{gid} 1" # Do rbind mounts. - mounts.each do |x| - to = "#{root}/#{x[1]}" + mounts.each do |from, rto| + to = "#{root}/#{rto}" FileUtils.mkdir_p to - $mount.call x[0], to, nil, MS_BIND | MS_REC, nil + $mount.call from, to, nil, MS_BIND | MS_REC, nil end # Chroot! @@ -108,7 +122,7 @@ if $cpid == 0 Dir.chdir '/' # Symlink swdir hierarchy - mount_dirs = Set.new mounts.map { |x| Pathname.new x[1] } + mount_dirs = Set.new mounts.map { |_, v| Pathname.new v } link_swdir = lambda do |swdir, prefix| swdir.find do |path| rel = prefix.join path.relative_path_from(swdir) diff --git a/pkgs/build-support/build-fhs-userenv/default.nix b/pkgs/build-support/build-fhs-userenv/default.nix index 9060c073eee3..d0470c72a780 100644 --- a/pkgs/build-support/build-fhs-userenv/default.nix +++ b/pkgs/build-support/build-fhs-userenv/default.nix @@ -1,4 +1,4 @@ -{ runCommand, writeText, writeScriptBin, stdenv, ruby } : { env, runScript ? "bash" } : +{ runCommand, lib, writeText, writeScriptBin, stdenv, ruby } : { env, runScript ? "bash", extraBindMounts ? [] } : let name = env.pname; @@ -27,6 +27,7 @@ in runCommand name { passthru.env = runCommand "${name}-shell-env" { shellHook = '' + export CHROOTENV_EXTRA_BINDS="${lib.makeSearchPath extraBindMounts}:$CHROOTENV_EXTRA_BINDS" exec ${chroot-user}/bin/chroot-user ${env} bash -l ${init "bash"} "$(pwd)" ''; } ''