aboutsummaryrefslogtreecommitdiff
path: root/infra/libkookie/nixpkgs/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix
blob: c7cfd27d3faa05a963a67b513528190e7aea9938 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
{ callPackage, runCommandLocal, writeShellScriptBin, stdenv, coreutils, bubblewrap }:

let buildFHSEnv = callPackage ./env.nix { }; in

args @ {
  name,
  runScript ? "bash",
  extraInstallCommands ? "",
  meta ? {},
  passthru ? {},
  ...
}:

with builtins;
let
  env = buildFHSEnv (removeAttrs args [
    "runScript" "extraInstallCommands" "meta" "passthru"
  ]);

  chrootenv = callPackage ./chrootenv {};

  etcBindFlags = let
    files = [
      # NixOS Compatibility
      "static"
      # Users, Groups, NSS
      "passwd"
      "group"
      "shadow"
      "hosts"
      "resolv.conf"
      "nsswitch.conf"
      # Sudo & Su
      "login.defs"
      "sudoers"
      "sudoers.d"
      # Time
      "localtime"
      "zoneinfo"
      # Other Core Stuff
      "machine-id"
      "os-release"
      # PAM
      "pam.d"
      # Fonts
      "fonts"
      # ALSA
      "asound.conf"
      # SSL
      "ssl/certs"
      "pki"
    ];
  in concatStringsSep " \\\n  "
  (map (file: "--ro-bind-try /etc/${file} /etc/${file}") files);

  init = run: writeShellScriptBin "${name}-init" ''
    source /etc/profile
    exec ${run} "$@"
  '';

  bwrapCmd = { initArgs ? "" }: ''
    blacklist="/nix /dev /proc /etc"
    ro_mounts=""
    for i in ${env}/*; do
      path="/''${i##*/}"
      if [[ $path == '/etc' ]]; then
        continue
      fi
      ro_mounts="$ro_mounts --ro-bind $i $path"
      blacklist="$blacklist $path"
    done

    if [[ -d ${env}/etc ]]; then
      for i in ${env}/etc/*; do
        path="/''${i##*/}"
        ro_mounts="$ro_mounts --ro-bind $i /etc$path"
      done
    fi

    auto_mounts=""
    # loop through all directories in the root
    for dir in /*; do
      # if it is a directory and it is not in the blacklist
      if [[ -d "$dir" ]] && grep -v "$dir" <<< "$blacklist" >/dev/null; then
        # add it to the mount list
        auto_mounts="$auto_mounts --bind $dir $dir"
      fi
    done

    exec ${bubblewrap}/bin/bwrap \
      --dev-bind /dev /dev \
      --proc /proc \
      --chdir "$(pwd)" \
      --unshare-all \
      --share-net \
      --die-with-parent \
      --ro-bind /nix /nix \
      ${etcBindFlags} \
      $ro_mounts \
      $auto_mounts \
      ${init runScript}/bin/${name}-init ${initArgs}
  '';

  bin = writeShellScriptBin name (bwrapCmd { initArgs = ''"$@"''; });

in runCommandLocal name {
  inherit meta;

  passthru = passthru // {
    env = runCommandLocal "${name}-shell-env" {
      shellHook = bwrapCmd {};
    } ''
      echo >&2 ""
      echo >&2 "*** User chroot 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
      echo >&2 ""
      exit 1
    '';
  };
} ''
  mkdir -p $out/bin
  ln -s ${bin}/bin/${name} $out/bin/${name}
  ${extraInstallCommands}
''