sdrangel: fix build on x86_64-darwin
[NixPkgs.git] / pkgs / build-support / build-fhsenv-bubblewrap / default.nix
blob12f3e7d585521723c19422d170a901d25e4715e0
1 { lib
2 , stdenv
3 , callPackage
4 , runCommandLocal
5 , writeShellScript
6 , glibc
7 , pkgsi686Linux
8 , coreutils
9 , bubblewrap
12 { runScript ? "bash"
13 , extraInstallCommands ? ""
14 , meta ? {}
15 , passthru ? {}
16 , extraPreBwrapCmds ? ""
17 , extraBwrapArgs ? []
18 , unshareUser ? false
19 , unshareIpc ? false
20 , unsharePid ? false
21 , unshareNet ? false
22 , unshareUts ? false
23 , unshareCgroup ? false
24 , privateTmp ? false
25 , dieWithParent ? true
26 , ...
27 } @ args:
29 assert (!args ? pname || !args ? version) -> (args ? name); # You must provide name if pname or version (preferred) is missing.
31 let
32   inherit (lib)
33     concatLines
34     concatStringsSep
35     escapeShellArgs
36     filter
37     optionalString
38     splitString
39     ;
41   inherit (lib.attrsets) removeAttrs;
43   name = args.name or "${args.pname}-${args.version}";
44   executableName = args.pname or args.name;
45   # we don't know which have been supplied, and want to avoid defaulting missing attrs to null. Passed into runCommandLocal
46   nameAttrs = lib.filterAttrs (key: value: builtins.elem key [ "name" "pname" "version" ]) args;
48   buildFHSEnv = callPackage ./buildFHSEnv.nix { };
50   fhsenv = buildFHSEnv (removeAttrs args [
51     "runScript" "extraInstallCommands" "meta" "passthru" "extraPreBwrapCmds" "extraBwrapArgs" "dieWithParent"
52     "unshareUser" "unshareCgroup" "unshareUts" "unshareNet" "unsharePid" "unshareIpc" "privateTmp"
53   ]);
55   etcBindEntries = let
56     files = [
57       # NixOS Compatibility
58       "static"
59       "nix" # mainly for nixUnstable users, but also for access to nix/netrc
60       # Shells
61       "shells"
62       "bashrc"
63       "zshenv"
64       "zshrc"
65       "zinputrc"
66       "zprofile"
67       # Users, Groups, NSS
68       "passwd"
69       "group"
70       "shadow"
71       "hosts"
72       "resolv.conf"
73       "nsswitch.conf"
74       # User profiles
75       "profiles"
76       # Sudo & Su
77       "login.defs"
78       "sudoers"
79       "sudoers.d"
80       # Time
81       "localtime"
82       "zoneinfo"
83       # Other Core Stuff
84       "machine-id"
85       "os-release"
86       # PAM
87       "pam.d"
88       # Fonts
89       "fonts"
90       # ALSA
91       "alsa"
92       "asound.conf"
93       # SSL
94       "ssl/certs"
95       "ca-certificates"
96       "pki"
97     ];
98   in map (path: "/etc/${path}") files;
100   # Create this on the fly instead of linking from /nix
101   # The container might have to modify it and re-run ldconfig if there are
102   # issues running some binary with LD_LIBRARY_PATH
103   createLdConfCache = ''
104     cat > /etc/ld.so.conf <<EOF
105     /lib
106     /lib/x86_64-linux-gnu
107     /lib64
108     /usr/lib
109     /usr/lib/x86_64-linux-gnu
110     /usr/lib64
111     /lib/i386-linux-gnu
112     /lib32
113     /usr/lib/i386-linux-gnu
114     /usr/lib32
115     /run/opengl-driver/lib
116     /run/opengl-driver-32/lib
117     EOF
118     ldconfig &> /dev/null
119   '';
120   init = run: writeShellScript "${name}-init" ''
121     source /etc/profile
122     ${createLdConfCache}
123     exec ${run} "$@"
124   '';
126   indentLines = str: concatLines (map (s: "  " + s) (filter (s: s != "") (splitString "\n" str)));
127   bwrapCmd = { initArgs ? "" }: ''
128     ${extraPreBwrapCmds}
129     ignored=(/nix /dev /proc /etc ${optionalString privateTmp "/tmp"})
130     ro_mounts=()
131     symlinks=()
132     etc_ignored=()
134     # loop through all entries of root in the fhs environment, except its /etc.
135     for i in ${fhsenv}/*; do
136       path="/''${i##*/}"
137       if [[ $path == '/etc' ]]; then
138         :
139       elif [[ -L $i ]]; then
140         symlinks+=(--symlink "$(${coreutils}/bin/readlink "$i")" "$path")
141         ignored+=("$path")
142       else
143         ro_mounts+=(--ro-bind "$i" "$path")
144         ignored+=("$path")
145       fi
146     done
148     # loop through the entries of /etc in the fhs environment.
149     if [[ -d ${fhsenv}/etc ]]; then
150       for i in ${fhsenv}/etc/*; do
151         path="/''${i##*/}"
152         # NOTE: we're binding /etc/fonts and /etc/ssl/certs from the host so we
153         # don't want to override it with a path from the FHS environment.
154         if [[ $path == '/fonts' || $path == '/ssl' ]]; then
155           continue
156         fi
157         if [[ -L $i ]]; then
158           symlinks+=(--symlink "$i" "/etc$path")
159         else
160           ro_mounts+=(--ro-bind "$i" "/etc$path")
161         fi
162         etc_ignored+=("/etc$path")
163       done
164     fi
166     # propagate /etc from the actual host if nested
167     if [[ -e /.host-etc ]]; then
168       ro_mounts+=(--ro-bind /.host-etc /.host-etc)
169     else
170       ro_mounts+=(--ro-bind /etc /.host-etc)
171     fi
173     # link selected etc entries from the actual root
174     for i in ${escapeShellArgs etcBindEntries}; do
175       if [[ "''${etc_ignored[@]}" =~ "$i" ]]; then
176         continue
177       fi
178       if [[ -e $i ]]; then
179         symlinks+=(--symlink "/.host-etc/''${i#/etc/}" "$i")
180       fi
181     done
183     declare -a auto_mounts
184     # loop through all directories in the root
185     for dir in /*; do
186       # if it is a directory and it is not ignored
187       if [[ -d "$dir" ]] && [[ ! "''${ignored[@]}" =~ "$dir" ]]; then
188         # add it to the mount list
189         auto_mounts+=(--bind "$dir" "$dir")
190       fi
191     done
193     declare -a x11_args
194     # Always mount a tmpfs on /tmp/.X11-unix
195     # Rationale: https://github.com/flatpak/flatpak/blob/be2de97e862e5ca223da40a895e54e7bf24dbfb9/common/flatpak-run.c#L277
196     x11_args+=(--tmpfs /tmp/.X11-unix)
198     # Try to guess X socket path. This doesn't cover _everything_, but it covers some things.
199     if [[ "$DISPLAY" == :* ]]; then
200       display_nr=''${DISPLAY#?}
201       local_socket=/tmp/.X11-unix/X$display_nr
202       x11_args+=(--ro-bind-try "$local_socket" "$local_socket")
203     fi
205     ${optionalString privateTmp ''
206     # sddm places XAUTHORITY in /tmp
207     if [[ "$XAUTHORITY" == /tmp/* ]]; then
208       x11_args+=(--ro-bind-try "$XAUTHORITY" "$XAUTHORITY")
209     fi
211     # dbus-run-session puts the socket in /tmp
212     IFS=";" read -ra addrs <<<"$DBUS_SESSION_BUS_ADDRESS"
213     for addr in "''${addrs[@]}"; do
214       [[ "$addr" == unix:* ]] || continue
215       IFS="," read -ra parts <<<"''${addr#unix:}"
216       for part in "''${parts[@]}"; do
217         printf -v part '%s' "''${part//\\/\\\\}"
218         printf -v part '%b' "''${part//%/\\x}"
219         [[ "$part" == path=/tmp/* ]] || continue
220         x11_args+=(--ro-bind-try "''${part#path=}" "''${part#path=}")
221       done
222     done
223     ''}
225     cmd=(
226       ${bubblewrap}/bin/bwrap
227       --dev-bind /dev /dev
228       --proc /proc
229       --chdir "$(pwd)"
230       ${optionalString unshareUser "--unshare-user"}
231       ${optionalString unshareIpc "--unshare-ipc"}
232       ${optionalString unsharePid "--unshare-pid"}
233       ${optionalString unshareNet "--unshare-net"}
234       ${optionalString unshareUts "--unshare-uts"}
235       ${optionalString unshareCgroup "--unshare-cgroup"}
236       ${optionalString dieWithParent "--die-with-parent"}
237       --ro-bind /nix /nix
238       ${optionalString privateTmp "--tmpfs /tmp"}
239       # Our glibc will look for the cache in its own path in `/nix/store`.
240       # As such, we need a cache to exist there, because pressure-vessel
241       # depends on the existence of an ld cache. However, adding one
242       # globally proved to be a bad idea (see #100655), the solution we
243       # settled on being mounting one via bwrap.
244       # Also, the cache needs to go to both 32 and 64 bit glibcs, for games
245       # of both architectures to work.
246       --tmpfs ${glibc}/etc \
247       --tmpfs /etc \
248       --symlink /etc/ld.so.conf ${glibc}/etc/ld.so.conf \
249       --symlink /etc/ld.so.cache ${glibc}/etc/ld.so.cache \
250       --ro-bind ${glibc}/etc/rpc ${glibc}/etc/rpc \
251       --remount-ro ${glibc}/etc \
252   '' + optionalString fhsenv.isMultiBuild (indentLines ''
253       --tmpfs ${pkgsi686Linux.glibc}/etc \
254       --symlink /etc/ld.so.conf ${pkgsi686Linux.glibc}/etc/ld.so.conf \
255       --symlink /etc/ld.so.cache ${pkgsi686Linux.glibc}/etc/ld.so.cache \
256       --ro-bind ${pkgsi686Linux.glibc}/etc/rpc ${pkgsi686Linux.glibc}/etc/rpc \
257       --remount-ro ${pkgsi686Linux.glibc}/etc \
258   '') + ''
259       "''${ro_mounts[@]}"
260       "''${symlinks[@]}"
261       "''${auto_mounts[@]}"
262       "''${x11_args[@]}"
263       ${concatStringsSep "\n  " extraBwrapArgs}
264       ${init runScript} ${initArgs}
265     )
266     exec "''${cmd[@]}"
267   '';
269   bin = writeShellScript "${name}-bwrap" (bwrapCmd { initArgs = ''"$@"''; });
270 in runCommandLocal name (nameAttrs // {
271   inherit meta;
273   passthru = passthru // {
274     env = runCommandLocal "${name}-shell-env" {
275       shellHook = bwrapCmd {};
276     } ''
277       echo >&2 ""
278       echo >&2 "*** User chroot 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
279       echo >&2 ""
280       exit 1
281     '';
282     inherit args fhsenv;
283   };
284 }) ''
285   mkdir -p $out/bin
286   ln -s ${bin} $out/bin/${executableName}
288   ${extraInstallCommands}