···
if config.system.etc.overlay.enable then
254
-
# This script atomically remounts /etc when switching configuration. On a (re-)boot
255
-
# this should not run because /etc is mounted via a systemd mount unit
256
-
# instead. To a large extent this mimics what composefs does. Because
255
+
# This script atomically remounts /etc when switching configuration.
256
+
# On a (re-)boot this should not run because /etc is mounted via a
257
+
# systemd mount unit instead.
258
+
# The activation script can also be called in cases where we didn't have
259
+
# an initrd though, like for instance when using nixos-enter,
260
+
# so we cannot assume that /etc has already been mounted.
262
+
# To a large extent this mimics what composefs does. Because
# it's relatively simple, however, we avoid the composefs dependency.
# Since this script is not idempotent, it should not run when etc hasn't
if [[ ! $IN_NIXOS_SYSTEMD_STAGE1 ]] && [[ "${config.system.build.etc}/etc" != "$(readlink -f /run/current-system/etc)" ]]; then
echo "remounting /etc..."
263
-
tmpMetadataMount=$(mktemp --directory -t nixos-etc-metadata.XXXXXXXXXX)
269
+
${lib.optionalString config.system.etc.overlay.mutable ''
270
+
# These directories are usually created in initrd,
271
+
# but we need to create them here when we didn't we're called directly,
272
+
# for instance by nixos-enter
273
+
mkdir --parents /.rw-etc/upper /.rw-etc/work
274
+
chmod --recursive 0755 /.rw-etc
277
+
tmpMetadataMount=$(TMPDIR="" mktemp --tmpdir=/tmp --directory -t nixos-etc-metadata.XXXXXXXXXX)
mount --type erofs -o ro ${config.system.build.etcMetadataImage} $tmpMetadataMount
266
-
# Mount the new /etc overlay to a temporary private mount.
267
-
# This needs the indirection via a private bind mount because you
268
-
# cannot move shared mounts.
269
-
tmpEtcMount=$(mktemp --directory -t nixos-etc.XXXXXXXXXX)
270
-
mount --bind --make-private $tmpEtcMount $tmpEtcMount
271
-
mount --type overlay overlay \
272
-
--options lowerdir=$tmpMetadataMount::${config.system.build.etcBasedir},${etcOverlayOptions} \
280
+
# There was no previous /etc mounted. This happens when we're called
281
+
# directly without an initrd, like with nixos-enter.
282
+
if ! mountpoint -q /etc; then
283
+
mount --type overlay overlay \
284
+
--options lowerdir=$tmpMetadataMount::${config.system.build.etcBasedir},${etcOverlayOptions} \
287
+
# Mount the new /etc overlay to a temporary private mount.
288
+
# This needs the indirection via a private bind mount because you
289
+
# cannot move shared mounts.
290
+
tmpEtcMount=$(TMPDIR="" mktemp --tmpdir=/tmp --directory -t nixos-etc.XXXXXXXXXX)
291
+
mount --bind --make-private $tmpEtcMount $tmpEtcMount
292
+
mount --type overlay overlay \
293
+
--options lowerdir=$tmpMetadataMount::${config.system.build.etcBasedir},${etcOverlayOptions} \
275
-
# Before moving the new /etc overlay under the old /etc, we have to
276
-
# move mounts on top of /etc to the new /etc mountpoint.
277
-
findmnt /etc --submounts --list --noheading --kernel --output TARGET | while read -r mountPoint; do
278
-
if [[ "$mountPoint" = "/etc" ]]; then
296
+
# Before moving the new /etc overlay under the old /etc, we have to
297
+
# move mounts on top of /etc to the new /etc mountpoint.
298
+
findmnt /etc --submounts --list --noheading --kernel --output TARGET | while read -r mountPoint; do
299
+
if [[ "$mountPoint" = "/etc" ]]; then
282
-
tmpMountPoint="$tmpEtcMount/''${mountPoint:5}"
284
-
if config.system.etc.overlay.mutable then
286
-
if [[ -f "$mountPoint" ]]; then
287
-
touch "$tmpMountPoint"
288
-
elif [[ -d "$mountPoint" ]]; then
289
-
mkdir -p "$tmpMountPoint"
294
-
if [[ ! -e "$tmpMountPoint" ]]; then
295
-
echo "Skipping undeclared mountpoint in environment.etc: $mountPoint"
300
-
mount --bind "$mountPoint" "$tmpMountPoint"
303
+
tmpMountPoint="$tmpEtcMount/''${mountPoint:5}"
305
+
if config.system.etc.overlay.mutable then
307
+
if [[ -f "$mountPoint" ]]; then
308
+
touch "$tmpMountPoint"
309
+
elif [[ -d "$mountPoint" ]]; then
310
+
mkdir -p "$tmpMountPoint"
315
+
if [[ ! -e "$tmpMountPoint" ]]; then
316
+
echo "Skipping undeclared mountpoint in environment.etc: $mountPoint"
321
+
mount --bind "$mountPoint" "$tmpMountPoint"
303
-
# Move the new temporary /etc mount underneath the current /etc mount.
305
-
# This should eventually use util-linux to perform this move beneath,
306
-
# however, this functionality is not yet in util-linux. See this
307
-
# tracking issue: https://github.com/util-linux/util-linux/issues/2604
308
-
${pkgs.move-mount-beneath}/bin/move-mount --move --beneath $tmpEtcMount /etc
324
+
# Move the new temporary /etc mount underneath the current /etc mount.
326
+
# This should eventually use util-linux to perform this move beneath,
327
+
# however, this functionality is not yet in util-linux. See this
328
+
# tracking issue: https://github.com/util-linux/util-linux/issues/2604
329
+
${pkgs.move-mount-beneath}/bin/move-mount --move --beneath $tmpEtcMount /etc
310
-
# Unmount the top /etc mount to atomically reveal the new mount.
311
-
umount --lazy --recursive /etc
331
+
# Unmount the top /etc mount to atomically reveal the new mount.
332
+
umount --lazy --recursive /etc
313
-
# Unmount the temporary mount
314
-
umount --lazy "$tmpEtcMount"
315
-
rmdir "$tmpEtcMount"
334
+
# Unmount the temporary mount
335
+
umount --lazy "$tmpEtcMount"
336
+
rmdir "$tmpEtcMount"
# Unmount old metadata mounts
# For some reason, `findmnt /tmp --submounts` does not show the nested
···
findmnt --type erofs --list --kernel --output TARGET | while read -r mountPoint; do
if [[ "$mountPoint" =~ ^/tmp/nixos-etc-metadata\..{10}$ &&
"$mountPoint" != "$tmpMetadataMount" ]]; then
324
-
umount --lazy $mountPoint
346
+
umount --lazy "$mountPoint"