1#! @runtimeShell@
2
3set -e
4shopt -s nullglob
5
6export PATH=@path@:$PATH
7
8# Ensure a consistent umask.
9umask 0022
10
11# Parse the command line for the -I flag
12extraBuildFlags=()
13flakeFlags=()
14
15mountPoint=/mnt
16channelPath=
17system=
18verbosity=()
19
20while [ "$#" -gt 0 ]; do
21 i="$1"; shift 1
22 case "$i" in
23 --max-jobs|-j|--cores|-I|--substituters)
24 j="$1"; shift 1
25 extraBuildFlags+=("$i" "$j")
26 ;;
27 --option)
28 j="$1"; shift 1
29 k="$1"; shift 1
30 extraBuildFlags+=("$i" "$j" "$k")
31 ;;
32 --root)
33 mountPoint="$1"; shift 1
34 ;;
35 --system|--closure)
36 system="$1"; shift 1
37 ;;
38 --flake)
39 flake="$1"
40 flakeFlags=(--experimental-features 'nix-command flakes')
41 shift 1
42 ;;
43 --recreate-lock-file|--no-update-lock-file|--no-write-lock-file|--no-registries|--commit-lock-file)
44 lockFlags+=("$i")
45 ;;
46 --update-input)
47 j="$1"; shift 1
48 lockFlags+=("$i" "$j")
49 ;;
50 --override-input)
51 j="$1"; shift 1
52 k="$1"; shift 1
53 lockFlags+=("$i" "$j" "$k")
54 ;;
55 --channel)
56 channelPath="$1"; shift 1
57 ;;
58 --no-channel-copy)
59 noChannelCopy=1
60 ;;
61 --no-root-password|--no-root-passwd)
62 noRootPasswd=1
63 ;;
64 --no-bootloader)
65 noBootLoader=1
66 ;;
67 --show-trace|--impure|--keep-going)
68 extraBuildFlags+=("$i")
69 ;;
70 --help)
71 exec man nixos-install
72 exit 1
73 ;;
74 --debug)
75 set -x
76 ;;
77 -v*|--verbose)
78 verbosity+=("$i")
79 ;;
80 *)
81 echo "$0: unknown option \`$i'"
82 exit 1
83 ;;
84 esac
85done
86
87if ! test -e "$mountPoint"; then
88 echo "mount point $mountPoint doesn't exist"
89 exit 1
90fi
91
92# Verify permissions are okay-enough
93checkPath="$(realpath "$mountPoint")"
94while [[ "$checkPath" != "/" ]]; do
95 mode="$(stat -c '%a' "$checkPath")"
96 if [[ "${mode: -1}" -lt "5" ]]; then
97 echo "path $checkPath should have permissions 755, but had permissions $mode. Consider running 'chmod o+rx $checkPath'."
98 exit 1
99 fi
100 checkPath="$(dirname "$checkPath")"
101done
102
103# Get the path of the NixOS configuration file.
104if [[ -z $NIXOS_CONFIG ]]; then
105 NIXOS_CONFIG=$mountPoint/etc/nixos/configuration.nix
106fi
107
108if [[ ${NIXOS_CONFIG:0:1} != / ]]; then
109 echo "$0: \$NIXOS_CONFIG is not an absolute path"
110 exit 1
111fi
112
113if [[ -n $flake ]]; then
114 if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
115 flake="${BASH_REMATCH[1]}"
116 flakeAttr="${BASH_REMATCH[2]}"
117 fi
118 if [[ -z "$flakeAttr" ]]; then
119 echo "Please specify the name of the NixOS configuration to be installed, as a URI fragment in the flake-uri."
120 echo "For example, to use the output nixosConfigurations.foo from the flake.nix, append \"#foo\" to the flake-uri."
121 exit 1
122 fi
123 flakeAttr="nixosConfigurations.\"$flakeAttr\""
124fi
125
126# Resolve the flake.
127if [[ -n $flake ]]; then
128 flake=$(nix "${flakeFlags[@]}" flake metadata --json "${extraBuildFlags[@]}" "${lockFlags[@]}" -- "$flake" | jq -r .url)
129fi
130
131if [[ ! -e $NIXOS_CONFIG && -z $system && -z $flake ]]; then
132 echo "configuration file $NIXOS_CONFIG doesn't exist"
133 exit 1
134fi
135
136# A place to drop temporary stuff.
137tmpdir="$(mktemp -d -p "$mountPoint")"
138trap 'rm -rf $tmpdir' EXIT
139
140# store temporary files on target filesystem by default
141export TMPDIR=${TMPDIR:-$tmpdir}
142
143sub="auto?trusted=1"
144
145# Build the system configuration in the target filesystem.
146if [[ -z $system ]]; then
147 outLink="$tmpdir/system"
148 if [[ -z $flake ]]; then
149 echo "building the configuration in $NIXOS_CONFIG..."
150 nix-build --out-link "$outLink" --store "$mountPoint" "${extraBuildFlags[@]}" \
151 --extra-substituters "$sub" \
152 '<nixpkgs/nixos>' -A system -I "nixos-config=$NIXOS_CONFIG" "${verbosity[@]}"
153 else
154 echo "building the flake in $flake..."
155 nix "${flakeFlags[@]}" build "$flake#$flakeAttr.config.system.build.toplevel" \
156 --store "$mountPoint" --extra-substituters "$sub" "${verbosity[@]}" \
157 "${extraBuildFlags[@]}" "${lockFlags[@]}" --out-link "$outLink"
158 fi
159 system=$(readlink -f "$outLink")
160fi
161
162# Set the system profile to point to the configuration. TODO: combine
163# this with the previous step once we have a nix-env replacement with
164# a progress bar.
165nix-env --store "$mountPoint" "${extraBuildFlags[@]}" \
166 --extra-substituters "$sub" \
167 -p "$mountPoint"/nix/var/nix/profiles/system --set "$system" "${verbosity[@]}"
168
169# Copy the NixOS/Nixpkgs sources to the target as the initial contents
170# of the NixOS channel.
171if [[ -z $noChannelCopy ]]; then
172 if [[ -z $channelPath ]]; then
173 channelPath="$(nix-env -p /nix/var/nix/profiles/per-user/root/channels -q nixos --no-name --out-path 2>/dev/null || echo -n "")"
174 fi
175 if [[ -n $channelPath ]]; then
176 echo "copying channel..."
177 mkdir -p "$mountPoint"/nix/var/nix/profiles/per-user/root
178 nix-env --store "$mountPoint" "${extraBuildFlags[@]}" --extra-substituters "$sub" \
179 -p "$mountPoint"/nix/var/nix/profiles/per-user/root/channels --set "$channelPath" --quiet \
180 "${verbosity[@]}"
181 install -m 0700 -d "$mountPoint"/root/.nix-defexpr
182 ln -sfn /nix/var/nix/profiles/per-user/root/channels "$mountPoint"/root/.nix-defexpr/channels
183 fi
184fi
185
186# Mark the target as a NixOS installation, otherwise switch-to-configuration will chicken out.
187mkdir -m 0755 -p "$mountPoint/etc"
188touch "$mountPoint/etc/NIXOS"
189
190# Switch to the new system configuration. This will install Grub with
191# a menu default pointing at the kernel/initrd/etc of the new
192# configuration.
193if [[ -z $noBootLoader ]]; then
194 echo "installing the boot loader..."
195 # Grub needs an mtab.
196 ln -sfn /proc/mounts "$mountPoint"/etc/mtab
197 NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root "$mountPoint" -- /run/current-system/bin/switch-to-configuration boot
198fi
199
200# Ask the user to set a root password, but only if the passwd command
201# exists (i.e. when mutable user accounts are enabled).
202if [[ -z $noRootPasswd ]] && [ -t 0 ]; then
203 if nixos-enter --root "$mountPoint" -c 'test -e /nix/var/nix/profiles/system/sw/bin/passwd'; then
204 set +e
205 nixos-enter --root "$mountPoint" -c 'echo "setting root password..." && /nix/var/nix/profiles/system/sw/bin/passwd'
206 exit_code=$?
207 set -e
208
209 if [[ $exit_code != 0 ]]; then
210 echo "Setting a root password failed with the above printed error."
211 echo "You can set the root password manually by executing \`nixos-enter --root ${mountPoint@Q}\` and then running \`passwd\` in the shell of the new system."
212 exit $exit_code
213 fi
214 fi
215fi
216
217echo "installation finished!"