1#! @shell@
2
3# This script's goal is to perform all "static" setup of a filesystem structure from pre-built store paths. Everything
4# in here should run in a non-root context and inside a Nix builder. It's designed primarily to be called from image-
5# building scripts and from nixos-install, but because it makes very few assumptions about the context in which it runs,
6# it could be useful in other contexts as well.
7#
8# Current behavior:
9# - set up basic filesystem structure
10# - make Nix store etc.
11# - copy Nix, system, channel, and misceallaneous closures to target Nix store
12# - register validity of all paths in the target store
13# - set up channel and system profiles
14
15# Ensure a consistent umask.
16umask 0022
17
18set -e
19
20mountPoint="$1"
21channel="$2"
22system="$3"
23shift 3
24closures="$@"
25
26PATH="@coreutils@/bin:@nix@/bin:@perl@/bin:@utillinux@/bin:@rsync@/bin"
27
28if ! test -e "$mountPoint"; then
29 echo "mount point $mountPoint doesn't exist"
30 exit 1
31fi
32
33# Create a few of the standard directories in the target root directory.
34mkdir -m 0755 -p $mountPoint/dev $mountPoint/proc $mountPoint/sys $mountPoint/etc $mountPoint/run $mountPoint/home
35mkdir -m 01777 -p $mountPoint/tmp
36mkdir -m 0755 -p $mountPoint/tmp/root
37mkdir -m 0755 -p $mountPoint/var
38mkdir -m 0700 -p $mountPoint/root
39
40ln -sf /run $mountPoint/var/run
41
42# Create the necessary Nix directories on the target device
43mkdir -m 0755 -p \
44 $mountPoint/nix/var/nix/gcroots \
45 $mountPoint/nix/var/nix/temproots \
46 $mountPoint/nix/var/nix/userpool \
47 $mountPoint/nix/var/nix/profiles \
48 $mountPoint/nix/var/nix/db \
49 $mountPoint/nix/var/log/nix/drvs
50
51mkdir -m 1775 -p $mountPoint/nix/store
52
53# All Nix operations below should operate on our target store, not /nix/store.
54# N.B: this relies on Nix 1.12 or higher
55export NIX_REMOTE=local?root=$mountPoint
56
57# Copy our closures to the Nix store on the target mount point, unless they're already there.
58for i in $closures; do
59 # We support closures both in the format produced by `nix-store --export` and by `exportReferencesGraph`,
60 # mostly because there doesn't seem to be a single format that can be produced outside of a nix build and
61 # inside one. See https://github.com/NixOS/nix/issues/1242 for more discussion.
62 if [[ "$i" =~ \.closure$ ]]; then
63 echo "importing serialized closure $i to $mountPoint..."
64 nix-store --import < $i
65 else
66 # There has to be a better way to do this, right?
67 echo "copying closure $i to $mountPoint..."
68 for j in $(perl @pathsFromGraph@ $i); do
69 echo " $j... "
70 rsync -a $j $mountPoint/nix/store/
71 done
72
73 nix-store --option build-users-group root --register-validity < $i
74 fi
75done
76
77# Create the required /bin/sh symlink; otherwise lots of things
78# (notably the system() function) won't work.
79if [ ! -x $mountPoint/@shell@ ]; then
80 echo "Error: @shell@ wasn't included in the closure" >&2
81 exit 1
82fi
83mkdir -m 0755 -p $mountPoint/bin
84ln -sf @shell@ $mountPoint/bin/sh
85
86echo "setting the system closure to '$system'..."
87nix-env "${extraBuildFlags[@]}" -p $mountPoint/nix/var/nix/profiles/system --set "$system"
88
89ln -sfn /nix/var/nix/profiles/system $mountPoint/run/current-system
90
91# Copy the NixOS/Nixpkgs sources to the target as the initial contents of the NixOS channel.
92mkdir -m 0755 -p $mountPoint/nix/var/nix/profiles
93mkdir -m 1777 -p $mountPoint/nix/var/nix/profiles/per-user
94mkdir -m 0755 -p $mountPoint/nix/var/nix/profiles/per-user/root
95
96if [ -z "$noChannelCopy" ] && [ -n "$channel" ]; then
97 echo "copying channel..."
98 nix-env --option build-use-substitutes false "${extraBuildFlags[@]}" -p $mountPoint/nix/var/nix/profiles/per-user/root/channels --set "$channel" --quiet
99fi
100mkdir -m 0700 -p $mountPoint/root/.nix-defexpr
101ln -sfn /nix/var/nix/profiles/per-user/root/channels $mountPoint/root/.nix-defexpr/channels
102
103# Mark the target as a NixOS installation, otherwise switch-to-configuration will chicken out.
104touch $mountPoint/etc/NIXOS
105