Very weird bug: mv to /nix/store fails in simple derivation (single-user with proot)

I am on a debian jessy without root-access. So I am using nix in a single-user install with proot.

I had problems with derivations using writeText from nixpkgs. The error is very weird, so I tried to finde a minimal failing example:

$ cat fail.nix
with import <nixpkgs> {};
runCommand "test-file-name"
  {
    text="test text";
    passAsFile = [ "text" ];
  }
  ''
    if [[ -f "$textPath" ]]; then
        echo "$textPath exists with content:"
        cat "$textPath"
        echo ""
    fi
    if [[ -d "$(dirname "$out")" ]]; then
        echo "dir $(dirname "$out") exists"
    fi
    mv "$textPath" "$out"
  ''

this fails like this:

$ nix-build fail.nix
these derivations will be built:
  /nix/store/vas4dyknw73mx3hyj2l5k0znw1bq4z64-test-file-name.drv
building '/nix/store/vas4dyknw73mx3hyj2l5k0znw1bq4z64-test-file-name.drv'...
/tmp/user/18050/nix-build-test-file-name.drv-0/.attr-0 exists with content:
test text
dir /nix/store exists
mv: cannot move '/tmp/user/18050/nix-build-test-file-name.drv-0/.attr-0' to '/nix/store/xfm2pqsn21awy0rjk2xb1ddqw4nm31hz-test-file-name': No such file or directory
builder for '/nix/store/vas4dyknw73mx3hyj2l5k0znw1bq4z64-test-file-name.drv' failed with exit code 1
error: build of '/nix/store/vas4dyknw73mx3hyj2l5k0znw1bq4z64-test-file-name.drv' failed

So mv seems to be complaining that the target of the move does not exist. This strikes me as odd, since that is quite usual when using mv. To confirm this suspicion I can add a touch:

<same as before>
    touch "$out"
    mv "$textPath" "$out"
  ''

now it works:

$ nix-build fail.nix
/nix/store/95w5g1d9nbvclbpyhq74mfpl6i4b70ci-test-file-name

I can only speculate that this might be a problem with proot and the fact, that /tmp and /nix reside on different filesystems …
I would be glad for any insights on what I can do besides using a fork of nixpkgs with a completely unreasonable touch added to writeText.

IIRC, PRoot does not support the renameat2 syscall. I have had better luck with termux’s fork ( https://github.com/termux/proot ). It looks more actively maintained and supports more syscalls.

1 Like

Thanks for the hint @symphorien!

It’s a bit weird because I had this working before with proot, but your explanation makes sense.

Is there somewhere a static binary of termux’s fork that I can use or at least instruction on how to compile one?

Just a heads up:

I found a working proot binary in the gitlab CI of the again maintained proot-project. Thanks to a hint on github. The current master seems to have fixed the seccomp and the rename2 syscall issues (at least for me).

This doesn’t change the fact, that I couldn’t get proot to build with nix. But that’s not so much of a problem for me right now. Thank you again @symphorien.

Yeah the proot in nix should have a fix for the renameat2 issue.

Not sure if that’ll help you, but, in case it might, I have a working derivation for cross-compiling termux-proot here, which includes building talloc.

To compile a static termux proot with current nixpkgs master:

with import <nixpkgs> {};
(pkgsStatic.proot
.override { enablePython = false; })
.overrideAttrs(old: {
      src = fetchFromGitHub {
            owner = "termux";
            repo = "PRoot";
            rev = "0717de26d1394fec3acf90efdc1d172e01bc932b";
            sha256 = "1g0r3a67x94sgffz3gksyqk8r06zynfcgfdi33w6kzxnb03gbm4m";
      };
      name = "proot-termux-2019-05-05";
})

Run nix-build foo.nix and the static binary will be in result/bin/proot. Enjoy :slight_smile:

1 Like

with https://github.com/NixOS/nixpkgs/pull/62618 you should just need pkgsStatic.proot !

1 Like