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
|
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
at_exit() {
set +e
[[ -n "${LOOP:-}" ]] && losetup -d "$LOOP"
[[ -n "${WORK_DIR:-}" ]] && rm -fr "$WORK_DIR"
}
trap at_exit EXIT
WORK_DIR="$(mktemp -d)"
mkdir -p "$WORK_DIR/mnt"
systemd-mount --list
systemd-mount --list --full
systemd-mount --list --no-legend
systemd-mount --list --no-pager
systemd-mount --list --quiet
systemd-mount --list --json=pretty
# tmpfs
mkdir -p "$WORK_DIR/mnt/foo/bar"
systemd-mount --tmpfs "$WORK_DIR/mnt/foo"
test ! -d "$WORK_DIR/mnt/foo/bar"
touch "$WORK_DIR/mnt/foo/baz"
systemd-umount "$WORK_DIR/mnt/foo"
test -d "$WORK_DIR/mnt/foo/bar"
test ! -e "$WORK_DIR/mnt/foo/baz"
# overlay
systemd-mount --type=overlay --options="lowerdir=/etc,upperdir=$WORK_DIR/upper,workdir=$WORK_DIR/work" /etc "$WORK_DIR/overlay"
touch "$WORK_DIR/overlay/foo"
test -e "$WORK_DIR/upper/foo"
systemd-umount "$WORK_DIR/overlay"
# We're going to play around with block/loop devices, so bail out early
# if we're running in nspawn
if systemd-detect-virt --container >/dev/null; then
echo "Container detected, skipping the test"
exit 0
fi
# Set up a simple block device for further tests
dd if=/dev/zero of="$WORK_DIR/simple.img" bs=1M count=16
mkfs.ext4 -L sd-mount-test "$WORK_DIR/simple.img"
LOOP="$(losetup --show --find "$WORK_DIR/simple.img")"
udevadm wait --timeout 60 --settle "$LOOP"
# Also wait for the .device unit for the loop device is active. Otherwise, the .device unit activation
# that is triggered by the .mount unit introduced by systemd-mount below may time out.
timeout 60 bash -c "until systemctl is-active $LOOP; do sleep 1; done"
mount "$LOOP" "$WORK_DIR/mnt"
touch "$WORK_DIR/mnt/foo.bar"
umount "$LOOP"
(! mountpoint "$WORK_DIR/mnt")
# Wait for the mount unit to be unloaded. Otherwise, creation of the transient unit below may fail.
MOUNT_UNIT=$(systemd-escape --path --suffix=mount "$WORK_DIR/mnt")
timeout 60 bash -c "while [[ -n \$(systemctl list-units --all --no-legend $MOUNT_UNIT) ]]; do sleep 1; done"
# Mount with both source and destination set
systemd-mount "$LOOP" "$WORK_DIR/mnt"
systemctl status "$WORK_DIR/mnt"
systemd-mount --list --full
test -e "$WORK_DIR/mnt/foo.bar"
systemd-umount "$WORK_DIR/mnt"
# Same thing, but with explicitly specified filesystem and disabled filesystem check
systemd-mount --type=ext4 --fsck=no --collect "$LOOP" "$WORK_DIR/mnt"
systemctl status "$(systemd-escape --path "$WORK_DIR/mnt").mount"
test -e "$WORK_DIR/mnt/foo.bar"
systemd-mount --umount "$LOOP"
# Discover additional metadata (unit description should now contain filesystem label)
systemd-mount --no-ask-password --discover "$LOOP" "$WORK_DIR/mnt"
test -e "$WORK_DIR/mnt/foo.bar"
systemctl show -P Description "$WORK_DIR/mnt" | grep -q sd-mount-test
systemd-umount "$WORK_DIR/mnt"
# Set a unit description
systemd-mount --description="Very Important Unit" "$LOOP" "$WORK_DIR/mnt"
test -e "$WORK_DIR/mnt/foo.bar"
systemctl show -P Description "$WORK_DIR/mnt" | grep -q "Very Important Unit"
systemd-umount "$WORK_DIR/mnt"
# Set a property
systemd-mount --property="Description=Foo Bar" "$LOOP" "$WORK_DIR/mnt"
test -e "$WORK_DIR/mnt/foo.bar"
systemctl show -P Description "$WORK_DIR/mnt" | grep -q "Foo Bar"
systemd-umount "$WORK_DIR/mnt"
# Set mount options
systemd-mount --options=ro,x-foo-bar "$LOOP" "$WORK_DIR/mnt"
test -e "$WORK_DIR/mnt/foo.bar"
systemctl show -P Options "$WORK_DIR/mnt" | grep -Eq "(^ro|,ro)"
systemctl show -P Options "$WORK_DIR/mnt" | grep -q "x-foo-bar"
systemd-umount "$WORK_DIR/mnt"
# Mount with only source set
systemd-mount "$LOOP"
systemctl status /run/media/system/sd-mount-test
systemd-mount --list --full
test -e /run/media/system/sd-mount-test/foo.bar
systemd-umount LABEL=sd-mount-test
# Automount
systemd-mount --automount=yes "$LOOP" "$WORK_DIR/mnt"
systemd-mount --list --full
systemctl status "$(systemd-escape --path "$WORK_DIR/mnt").automount"
[[ "$(systemctl show -P ActiveState "$WORK_DIR/mnt")" == inactive ]]
test -e "$WORK_DIR/mnt/foo.bar"
systemctl status "$WORK_DIR/mnt"
systemd-umount "$WORK_DIR/mnt"
# Automount + automount-specific property
systemd-mount -A --automount-property="Description=Bar Baz" "$LOOP" "$WORK_DIR/mnt"
systemctl show -P Description "$(systemd-escape --path "$WORK_DIR/mnt").automount" | grep -q "Bar Baz"
test -e "$WORK_DIR/mnt/foo.bar"
# Call --umount via --machine=, first with a relative path (bad) and then with
# an absolute one (good)
(! systemd-umount --machine=.host "$(realpath --relative-to=. "$WORK_DIR/mnt")")
systemd-umount --machine=.host "$WORK_DIR/mnt"
# ext4 doesn't support uid=/gid=
(! systemd-mount -t ext4 --owner=testuser "$LOOP" "$WORK_DIR/mnt")
# Automount + --bind-device
systemd-mount --automount=yes --bind-device --timeout-idle-sec=1 "$LOOP" "$WORK_DIR/mnt"
systemctl status "$(systemd-escape --path "$WORK_DIR/mnt").automount"
# Trigger the automount
test -e "$WORK_DIR/mnt/foo.bar"
# Wait until it's idle again
sleep 1.5
# Safety net for slower/overloaded systems
timeout 10s bash -c "while systemctl is-active -q $WORK_DIR/mnt; do sleep .2; done"
systemctl status "$(systemd-escape --path "$WORK_DIR/mnt").automount"
# Disassemble the underlying block device
losetup -d "$LOOP"
unset LOOP
# The automount unit should disappear once the underlying blockdev is gone
timeout 10s bash -c "while systemctl status '$(systemd-escape --path "$WORK_DIR/mnt".automount)'; do sleep .2; done"
# Mount a disk image
systemd-mount --discover "$WORK_DIR/simple.img"
# We can access files in the image even if the loopback block device is not initialized by udevd.
test -e /run/media/system/simple.img/foo.bar
# systemd-mount --list and systemd-umount require the loopback block device is initialized by udevd.
udevadm settle --timeout 30
assert_in "/dev/loop.* ext4 +sd-mount-test" "$(systemd-mount --list --full)"
LOOP_AUTO=$(systemd-mount --list --full --no-legend | awk '$7 == "sd-mount-test" { print $1 }')
LOOP_AUTO_DEVPATH=$(udevadm info --query property --property DEVPATH --value "$LOOP_AUTO")
systemd-umount "$WORK_DIR/simple.img"
# Wait for 'change' uevent for the device with DISK_MEDIA_CHANGE=1.
# After the event, the backing_file attribute should be removed.
timeout 60 bash -c "while [[ -e /sys/$LOOP_AUTO_DEVPATH/loop/backing_file ]]; do sleep 1; done"
# --owner + vfat
#
# Create a vfat image, as ext4 doesn't support uid=/gid= fixating for all
# files/directories
dd if=/dev/zero of="$WORK_DIR/owner-vfat.img" bs=1M count=16
mkfs.vfat -n owner-vfat "$WORK_DIR/owner-vfat.img"
LOOP="$(losetup --show --find "$WORK_DIR/owner-vfat.img")"
# If the synthesized uevent triggered by inotify event has been processed earlier than the kernel finishes to
# attach the backing file, then SYSTEMD_READY=0 is set for the device. As a workaround, monitor sysattr
# and re-trigger uevent after that.
LOOP_DEVPATH=$(udevadm info --query property --property DEVPATH --value "$LOOP")
timeout 60 bash -c "until [[ -e /sys/$LOOP_DEVPATH/loop/backing_file ]]; do sleep 1; done"
udevadm trigger --settle "$LOOP"
# Also wait for the .device unit for the loop device is active. Otherwise, the .device unit activation
# that is triggered by the .mount unit introduced by systemd-mount below may time out.
if ! timeout 60 bash -c "until systemctl is-active $LOOP; do sleep 1; done"; then
# For debugging issue like
# https://github.com/systemd/systemd/issues/32680#issuecomment-2120959238
# https://github.com/systemd/systemd/issues/32680#issuecomment-2122074805
udevadm info "$LOOP"
udevadm info --attribute-walk "$LOOP"
cat /sys/"$(udevadm info --query property --property DEVPATH --value "$LOOP")"/loop/backing_file || :
false
fi
# Mount it and check the UID/GID
[[ "$(stat -c "%U:%G" "$WORK_DIR/mnt")" == "root:root" ]]
systemd-mount --owner=testuser "$LOOP" "$WORK_DIR/mnt"
systemctl status "$WORK_DIR/mnt"
[[ "$(stat -c "%U:%G" "$WORK_DIR/mnt")" == "testuser:testuser" ]]
touch "$WORK_DIR/mnt/hello"
[[ "$(stat -c "%U:%G" "$WORK_DIR/mnt/hello")" == "testuser:testuser" ]]
systemd-umount LABEL=owner-vfat
|