blob: a76b4ffb444442ebe92a89a475a0374bfdc6e46f (
plain) (
blame)
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
|
#! @runtimeShell@
# shellcheck shell=bash
set -e
shopt -s nullglob
export PATH=@path@:$PATH
# Ensure a consistent umask.
umask 0022
# Parse the command line for the -I flag
extraBuildFlags=()
flakeFlags=()
mountPoint=/mnt
channelPath=
system=
verbosity=()
attr=
buildFile=
buildingAttribute=1
while [ "$#" -gt 0 ]; do
i="$1"; shift 1
case "$i" in
--max-jobs|-j|--cores|-I|--substituters)
j="$1"; shift 1
extraBuildFlags+=("$i" "$j")
;;
--option)
j="$1"; shift 1
k="$1"; shift 1
extraBuildFlags+=("$i" "$j" "$k")
;;
--root)
mountPoint="$1"; shift 1
;;
--system|--closure)
system="$1"; shift 1
;;
--flake)
flake="$1"
flakeFlags=(--experimental-features 'nix-command flakes')
shift 1
;;
--file|-f)
if [ -z "$1" ]; then
log "$0: '$i' requires an argument"
exit 1
fi
buildFile="$1"
buildingAttribute=
shift 1
;;
--attr|-A)
if [ -z "$1" ]; then
log "$0: '$i' requires an argument"
exit 1
fi
attr="$1"
buildingAttribute=
shift 1
;;
--recreate-lock-file|--no-update-lock-file|--no-write-lock-file|--no-registries|--commit-lock-file)
lockFlags+=("$i")
;;
--update-input)
j="$1"; shift 1
lockFlags+=("$i" "$j")
;;
--override-input)
j="$1"; shift 1
k="$1"; shift 1
lockFlags+=("$i" "$j" "$k")
;;
--channel)
channelPath="$1"; shift 1
;;
--no-channel-copy)
noChannelCopy=1
;;
--no-root-password|--no-root-passwd)
noRootPasswd=1
;;
--no-bootloader)
noBootLoader=1
;;
--show-trace|--impure|--keep-going)
extraBuildFlags+=("$i")
;;
--help)
exec man nixos-install
exit 1
;;
--debug)
set -x
;;
-v*|--verbose)
verbosity+=("$i")
;;
*)
echo "$0: unknown option \`$i'"
exit 1
;;
esac
done
if ! test -e "$mountPoint"; then
echo "mount point $mountPoint doesn't exist"
exit 1
fi
# Verify permissions are okay-enough
checkPath="$(realpath "$mountPoint")"
while [[ "$checkPath" != "/" ]]; do
mode="$(stat -c '%a' "$checkPath")"
if [[ "${mode: -1}" -lt "5" ]]; then
echo "path $checkPath should have permissions 755, but had permissions $mode. Consider running 'chmod o+rx $checkPath'."
exit 1
fi
checkPath="$(dirname "$checkPath")"
done
# Verify that user is not trying to use attribute building and flake
# at the same time
if [[ -z $buildingAttribute && -n $flake ]]; then
echo "$0: '--flake' cannot be used with '--file' or '--attr'"
exit 1
fi
# Get the path of the NixOS configuration file.
if [[ -z $flake && -n $buildingAttribute ]]; then
if [[ -z $NIXOS_CONFIG ]]; then
NIXOS_CONFIG=$mountPoint/etc/nixos/configuration.nix
fi
if [[ ${NIXOS_CONFIG:0:1} != / ]]; then
echo "$0: \$NIXOS_CONFIG is not an absolute path"
exit 1
fi
elif [[ -z $buildingAttribute ]]; then
if [[ -z $buildFile ]]; then
buildFile="$mountPoint/etc/nixos/default.nix"
elif [[ -d $buildFile ]]; then
buildFile="$buildFile/default.nix"
fi
elif [[ -n $flake ]]; then
if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
flake="${BASH_REMATCH[1]}"
flakeAttr="${BASH_REMATCH[2]}"
fi
if [[ -z "$flakeAttr" ]]; then
echo "Please specify the name of the NixOS configuration to be installed, as a URI fragment in the flake-uri."
echo "For example, to use the output nixosConfigurations.foo from the flake.nix, append \"#foo\" to the flake-uri."
exit 1
fi
flakeAttr="nixosConfigurations.\"$flakeAttr\""
fi
# Resolve the flake.
if [[ -n $flake ]]; then
flake=$(nix "${flakeFlags[@]}" flake metadata --json "${extraBuildFlags[@]}" "${lockFlags[@]}" -- "$flake" | jq -r .url)
fi
if [[ ! -e $NIXOS_CONFIG && -z $system && -z $flake && -n $buildingAttribute ]]; then
echo "configuration file $NIXOS_CONFIG doesn't exist"
exit 1
fi
if [[ ! -z $buildingAttribute && -e $buildFile && -z $system ]]; then
echo "configuration file $buildFile doesn't exist"
exit 1
fi
# A place to drop temporary stuff.
tmpdir="$(mktemp -d -p "$mountPoint")"
trap 'rm -rf $tmpdir' EXIT
# store temporary files on target filesystem by default
export TMPDIR=${TMPDIR:-$tmpdir}
sub="auto?trusted=1"
# Copy the NixOS/Nixpkgs sources to the target as the initial contents
# of the NixOS channel.
if [[ -z $noChannelCopy ]]; then
if [[ -z $channelPath ]]; then
channelPath="$(nix-env -p /nix/var/nix/profiles/per-user/root/channels -q nixos --no-name --out-path 2>/dev/null || echo -n "")"
fi
if [[ -n $channelPath ]]; then
echo "copying channel..."
mkdir -p "$mountPoint"/nix/var/nix/profiles/per-user/root
nix-env --store "$mountPoint" "${extraBuildFlags[@]}" --extra-substituters "$sub" \
-p "$mountPoint"/nix/var/nix/profiles/per-user/root/channels --set "$channelPath" --quiet \
"${verbosity[@]}"
install -m 0700 -d "$mountPoint"/root/.nix-defexpr
ln -sfn /nix/var/nix/profiles/per-user/root/channels "$mountPoint"/root/.nix-defexpr/channels
fi
fi
# Build the system configuration in the target filesystem.
if [[ -z $system ]]; then
outLink="$tmpdir/system"
if [[ -z $flake && -n $buildingAttribute ]]; then
echo "building the configuration in $NIXOS_CONFIG..."
nix-build --out-link "$outLink" --store "$mountPoint" "${extraBuildFlags[@]}" \
--extra-substituters "$sub" \
'<nixpkgs/nixos>' -A system -I "nixos-config=$NIXOS_CONFIG" "${verbosity[@]}"
elif [[ -z $buildingAttribute ]]; then
if [[ -n $attr ]]; then
echo "building the configuration in $buildFile and attribute $attr..."
else
echo "building the configuration in $buildFile..."
fi
nix-build --out-link "$outLink" --store "$mountPoint" "${extraBuildFlags[@]}" \
--extra-substituters "$sub" \
"$buildFile" -A "${attr:+$attr.}config.system.build.toplevel" "${verbosity[@]}"
else
echo "building the flake in $flake..."
nix "${flakeFlags[@]}" build "$flake#$flakeAttr.config.system.build.toplevel" \
--store "$mountPoint" --extra-substituters "$sub" "${verbosity[@]}" \
"${extraBuildFlags[@]}" "${lockFlags[@]}" --out-link "$outLink"
fi
system=$(readlink -f "$outLink")
fi
# Set the system profile to point to the configuration. TODO: combine
# this with the previous step once we have a nix-env replacement with
# a progress bar.
nix-env --store "$mountPoint" "${extraBuildFlags[@]}" \
--extra-substituters "$sub" \
-p "$mountPoint"/nix/var/nix/profiles/system --set "$system" "${verbosity[@]}"
# Mark the target as a NixOS installation, otherwise switch-to-configuration will chicken out.
mkdir -m 0755 -p "$mountPoint/etc"
touch "$mountPoint/etc/NIXOS"
# Switch to the new system configuration. This will install Grub with
# a menu default pointing at the kernel/initrd/etc of the new
# configuration.
if [[ -z $noBootLoader ]]; then
echo "installing the boot loader..."
# Grub needs an mtab.
ln -sfn /proc/mounts "$mountPoint"/etc/mtab
export mountPoint
NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root "$mountPoint" -c "$(cat <<'EOF'
# Create a bind mount for each of the mount points inside the target file
# system. This preserves the validity of their absolute paths after changing
# the root with `nixos-enter`.
# Without this the bootloader installation may fail due to options that
# contain paths referenced during evaluation, like initrd.secrets.
# when not root, re-execute the script in an unshared namespace
mount --rbind --mkdir / "$mountPoint"
mount --make-rslave "$mountPoint"
/run/current-system/bin/switch-to-configuration boot
umount -R "$mountPoint" && (rmdir "$mountPoint" 2>/dev/null || true)
EOF
)"
fi
# Ask the user to set a root password, but only if the passwd command
# exists (i.e. when mutable user accounts are enabled).
if [[ -z $noRootPasswd ]] && [ -t 0 ]; then
if nixos-enter --root "$mountPoint" -c 'test -e /nix/var/nix/profiles/system/sw/bin/passwd'; then
set +e
nixos-enter --root "$mountPoint" -c 'echo "setting root password..." && /nix/var/nix/profiles/system/sw/bin/passwd'
exit_code=$?
set -e
if [[ $exit_code != 0 ]]; then
echo "Setting a root password failed with the above printed error."
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."
exit $exit_code
fi
fi
fi
echo "installation finished!"
|