]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/units/testsuite-26.sh
Merge pull request #30284 from YHNdnzj/fstab-wantedby-defaultdeps
[thirdparty/systemd.git] / test / units / testsuite-26.sh
CommitLineData
ff12a795 1#!/usr/bin/env bash
7b3cec95 2# SPDX-License-Identifier: LGPL-2.1-or-later
209d355c 3# shellcheck disable=SC2016
084575ff 4set -eux
79411bbc
LP
5set -o pipefail
6
cb153b4f
FS
7# shellcheck source=test/units/util.sh
8. "$(dirname "$0")"/util.sh
5f882cc3 9
d16684fe
FS
10at_exit() {
11 if [[ -v UNIT_NAME && -e "/usr/lib/systemd/system/$UNIT_NAME" ]]; then
209d355c 12 rm -fvr "/usr/lib/systemd/system/$UNIT_NAME" "/etc/systemd/system/$UNIT_NAME.d" "+4"
d16684fe 13 fi
5f882cc3 14
87993468
RM
15 maybe_umount_usr_overlay
16
5f882cc3
YW
17 rm -f /etc/init.d/issue-24990
18 return 0
d16684fe
FS
19}
20
87993468 21maybe_mount_usr_overlay
d16684fe
FS
22trap at_exit EXIT
23
24# Create a simple unit file for testing
25# Note: the service file is created under /usr on purpose to test
26# the 'revert' verb as well
209d355c 27export UNIT_NAME="systemctl-test-$RANDOM.service"
dd063027
ZJS
28export UNIT_NAME2="systemctl-test-$RANDOM.service"
29
d16684fe
FS
30cat >"/usr/lib/systemd/system/$UNIT_NAME" <<\EOF
31[Unit]
32Description=systemctl test
33
34[Service]
35ExecStart=sleep infinity
36ExecReload=true
37
38# For systemctl clean
39CacheDirectory=%n
40ConfigurationDirectory=%n
41LogsDirectory=%n
42RuntimeDirectory=%n
43StateDirectory=%n
44
45[Install]
46WantedBy=multi-user.target
47EOF
48
49# Configure the preset setting for the unit file
50mkdir /run/systemd/system-preset/
51echo "disable $UNIT_NAME" >/run/systemd/system-preset/99-systemd-test.preset
52
209d355c 53EDITOR='true' script -ec 'systemctl edit "$UNIT_NAME"' /dev/null
54[ ! -e "/etc/systemd/system/$UNIT_NAME.d/override.conf" ]
55
7a17e41d 56printf '%s\n' '[Service]' 'ExecStart=' 'ExecStart=sleep 10d' >"+4"
209d355c 57EDITOR='mv' script -ec 'systemctl edit "$UNIT_NAME"' /dev/null
58printf '%s\n' '[Service]' 'ExecStart=' 'ExecStart=sleep 10d' | cmp - "/etc/systemd/system/$UNIT_NAME.d/override.conf"
59
7a17e41d 60printf '%b' '[Service]\n' 'ExecStart=\n' 'ExecStart=sleep 10d' >"+4"
209d355c 61EDITOR='mv' script -ec 'systemctl edit "$UNIT_NAME"' /dev/null
62printf '%s\n' '[Service]' 'ExecStart=' 'ExecStart=sleep 10d' | cmp - "/etc/systemd/system/$UNIT_NAME.d/override.conf"
d16684fe 63
dd063027
ZJS
64systemctl edit "$UNIT_NAME" --stdin --drop-in=override2.conf <<EOF
65[Unit]
66Description=spectacular
67# this comment should remain
68
69EOF
70printf '%s\n' '[Unit]' 'Description=spectacular' '# this comment should remain' | \
71 cmp - "/etc/systemd/system/$UNIT_NAME.d/override2.conf"
72
73# Test simultaneous editing of two units and creation of drop-in for a nonexistent unit
74systemctl edit "$UNIT_NAME" "$UNIT_NAME2" --stdin --force --drop-in=override2.conf <<<'[X-Section]'
75printf '%s\n' '[X-Section]' | cmp - "/etc/systemd/system/$UNIT_NAME.d/override2.conf"
76printf '%s\n' '[X-Section]' | cmp - "/etc/systemd/system/$UNIT_NAME2.d/override2.conf"
77
adae3552
FS
78# Double free when editing a template unit (#26483)
79EDITOR='true' script -ec 'systemctl edit user@0' /dev/null
80
d16684fe
FS
81# Argument help
82systemctl --state help
83systemctl --signal help
84systemctl --type help
85
86# list-dependencies
87systemctl list-dependencies systemd-journald
88systemctl list-dependencies --after systemd-journald
89systemctl list-dependencies --before systemd-journald
90systemctl list-dependencies --after --reverse systemd-journald
91systemctl list-dependencies --before --reverse systemd-journald
92systemctl list-dependencies --plain systemd-journald
93
94# list-* verbs
95systemctl list-units
96systemctl list-units --recursive
97systemctl list-units --type=socket
98systemctl list-units --type=service,timer
23f3a6f5
FS
99# Compat: --type= allows load states for compatibility reasons
100systemctl list-units --type=loaded
101systemctl list-units --type=loaded,socket
d16684fe
FS
102systemctl list-units --legend=yes -a "systemd-*"
103systemctl list-units --state=active
104systemctl list-units --with-dependencies systemd-journald.service
105systemctl list-units --with-dependencies --after systemd-journald.service
106systemctl list-units --with-dependencies --before --reverse systemd-journald.service
107systemctl list-sockets
108systemctl list-sockets --legend=no -a "*journal*"
109systemctl list-sockets --show-types
110systemctl list-sockets --state=listening
111systemctl list-timers -a -l
d16684fe
FS
112systemctl list-jobs
113systemctl list-jobs --after
114systemctl list-jobs --before
115systemctl list-jobs --after --before
116systemctl list-jobs "*"
37299769
MY
117systemctl list-dependencies sysinit.target --type=socket,mount
118systemctl list-dependencies multi-user.target --state=active
119systemctl list-dependencies sysinit.target --state=mounted --all
a2ceb880
DT
120systemctl list-paths
121systemctl list-paths --legend=no -a "systemd*"
d16684fe 122
e7f5525f
DT
123test_list_unit_files() {
124 systemctl list-unit-files "$@"
125 systemctl list-unit-files "$@" "*journal*"
126}
127
128test_list_unit_files
129test_list_unit_files --root=/
130
9aaa333f
MY
131# is-* verbs
132# Should return 4 for a missing unit file
133assert_rc 4 systemctl --quiet is-active not-found.service
134assert_rc 4 systemctl --quiet is-failed not-found.service
135assert_rc 4 systemctl --quiet is-enabled not-found.service
136# is-active: return 3 when the unit exists but inactive
137assert_rc 3 systemctl --quiet is-active "$UNIT_NAME"
138# is-enabled: return 1 when the unit exists but disabled
139assert_rc 1 systemctl --quiet is-enabled "$UNIT_NAME"
140
d16684fe
FS
141# Basic service management
142systemctl start --show-transaction "$UNIT_NAME"
143systemctl status -n 5 "$UNIT_NAME"
144systemctl is-active "$UNIT_NAME"
145systemctl reload -T "$UNIT_NAME"
146systemctl restart -T "$UNIT_NAME"
147systemctl try-restart --show-transaction "$UNIT_NAME"
148systemctl try-reload-or-restart --show-transaction "$UNIT_NAME"
149systemctl kill "$UNIT_NAME"
150(! systemctl is-active "$UNIT_NAME")
151systemctl restart "$UNIT_NAME"
152systemctl is-active "$UNIT_NAME"
153systemctl restart "$UNIT_NAME"
154systemctl stop "$UNIT_NAME"
155(! systemctl is-active "$UNIT_NAME")
156
2ee34616
MY
157assert_eq "$(systemctl is-system-running)" "$(systemctl is-failed)"
158
d16684fe 159# enable/disable/preset
e7f5525f
DT
160test_enable_disable_preset() {
161 (! systemctl is-enabled "$@" "$UNIT_NAME")
162 systemctl enable "$@" "$UNIT_NAME"
163 systemctl is-enabled "$@" -l "$UNIT_NAME"
164 # We created a preset file for this unit above with a "disable" policy
165 systemctl preset "$@" "$UNIT_NAME"
166 (! systemctl is-enabled "$@" "$UNIT_NAME")
167 systemctl reenable "$@" "$UNIT_NAME"
168 systemctl is-enabled "$@" "$UNIT_NAME"
169 systemctl preset "$@" --preset-mode=enable-only "$UNIT_NAME"
170 systemctl is-enabled "$@" "$UNIT_NAME"
171 systemctl preset "$@" --preset-mode=disable-only "$UNIT_NAME"
172 (! systemctl is-enabled "$@" "$UNIT_NAME")
173 systemctl enable "$@" --runtime "$UNIT_NAME"
174 [[ -e "/run/systemd/system/multi-user.target.wants/$UNIT_NAME" ]]
175 systemctl is-enabled "$@" "$UNIT_NAME"
176 systemctl disable "$@" "$UNIT_NAME"
177 # The unit should be still enabled, as we didn't use the --runtime switch
178 systemctl is-enabled "$@" "$UNIT_NAME"
179 systemctl disable "$@" --runtime "$UNIT_NAME"
180 (! systemctl is-enabled "$@" "$UNIT_NAME")
181}
182
183test_enable_disable_preset
184test_enable_disable_preset --root=/
d16684fe
FS
185
186# mask/unmask/revert
e7f5525f
DT
187test_mask_unmask_revert() {
188 systemctl disable "$@" "$UNIT_NAME"
189 [[ "$(systemctl is-enabled "$@" "$UNIT_NAME")" == disabled ]]
190 systemctl mask "$@" "$UNIT_NAME"
191 [[ "$(systemctl is-enabled "$@" "$UNIT_NAME")" == masked ]]
192 systemctl unmask "$@" "$UNIT_NAME"
193 [[ "$(systemctl is-enabled "$@" "$UNIT_NAME")" == disabled ]]
194 systemctl mask "$@" "$UNIT_NAME"
195 [[ "$(systemctl is-enabled "$@" "$UNIT_NAME")" == masked ]]
196 systemctl revert "$@" "$UNIT_NAME"
197 [[ "$(systemctl is-enabled "$@" "$UNIT_NAME")" == disabled ]]
198 systemctl mask "$@" --runtime "$UNIT_NAME"
199 [[ "$(systemctl is-enabled "$@" "$UNIT_NAME")" == masked-runtime ]]
200 # This should be a no-op without the --runtime switch
201 systemctl unmask "$@" "$UNIT_NAME"
202 [[ "$(systemctl is-enabled "$@" "$UNIT_NAME")" == masked-runtime ]]
203 systemctl unmask "$@" --runtime "$UNIT_NAME"
204 [[ "$(systemctl is-enabled "$@" "$UNIT_NAME")" == disabled ]]
205}
206
207test_mask_unmask_revert
208test_mask_unmask_revert --root=/
d16684fe
FS
209
210# add-wants/add-requires
211(! systemctl show -P Wants "$UNIT_NAME" | grep "systemd-journald.service")
212systemctl add-wants "$UNIT_NAME" "systemd-journald.service"
213systemctl show -P Wants "$UNIT_NAME" | grep "systemd-journald.service"
214(! systemctl show -P Requires "$UNIT_NAME" | grep "systemd-journald.service")
215systemctl add-requires "$UNIT_NAME" "systemd-journald.service"
216systemctl show -P Requires "$UNIT_NAME" | grep "systemd-journald.service"
217
218# set-property
219systemctl set-property "$UNIT_NAME" IPAccounting=yes MemoryMax=1234567
220systemctl cat "$UNIT_NAME"
221# These properties should be saved to a persistent storage
222grep -r "IPAccounting=yes" "/etc/systemd/system.control/${UNIT_NAME}.d/"
223grep -r "MemoryMax=1234567" "/etc/systemd/system.control/${UNIT_NAME}.d"
224systemctl revert "$UNIT_NAME"
225(! grep -r "IPAccounting=" "/etc/systemd/system.control/${UNIT_NAME}.d/")
226(! grep -r "MemoryMax=" "/etc/systemd/system.control/${UNIT_NAME}.d/")
227# Same stuff, but with --runtime, which should use /run
228systemctl set-property --runtime "$UNIT_NAME" CPUAccounting=no CPUQuota=10%
229systemctl cat "$UNIT_NAME"
230grep -r "CPUAccounting=no" "/run/systemd/system.control/${UNIT_NAME}.d/"
231grep -r "CPUQuota=10%" "/run/systemd/system.control/${UNIT_NAME}.d/"
232systemctl revert "$UNIT_NAME"
233(! grep -r "CPUAccounting=" "/run/systemd/system.control/${UNIT_NAME}.d/")
234(! grep -r "CPUQuota=" "/run/systemd/system.control/${UNIT_NAME}.d/")
235
236# Failed-unit related tests
23f3a6f5 237(! systemd-run --wait --unit "failed.service" /bin/false)
d16684fe
FS
238systemctl is-failed failed.service
239systemctl --state=failed | grep failed.service
240systemctl --failed | grep failed.service
241systemctl reset-failed "fail*.service"
242(! systemctl is-failed failed.service)
243
244# clean
245systemctl restart "$UNIT_NAME"
246systemctl stop "$UNIT_NAME"
247# Check if the directories from *Directory= directives exist
248# (except RuntimeDirectory= in /run, which is removed when the unit is stopped)
249for path in /var/lib /var/cache /var/log /etc; do
250 [[ -e "$path/$UNIT_NAME" ]]
251done
252# Run the cleanup
253for what in "" configuration state cache logs runtime all; do
254 systemctl clean ${what:+--what="$what"} "$UNIT_NAME"
255done
256# All respective directories should be removed
257for path in /run /var/lib /var/cache /var/log /etc; do
258 [[ ! -e "$path/$UNIT_NAME" ]]
259done
260
261# --timestamp
262for value in pretty us µs utc us+utc µs+utc; do
263 systemctl show -P KernelTimestamp --timestamp="$value"
264done
265
23f3a6f5 266# set-default/get-default
e7f5525f
DT
267test_get_set_default() {
268 target="$(systemctl get-default "$@")"
269 systemctl set-default "$@" emergency.target
270 [[ "$(systemctl get-default "$@")" == emergency.target ]]
271 systemctl set-default "$@" "$target"
272 [[ "$(systemctl get-default "$@")" == "$target" ]]
273}
274
275test_get_set_default
276test_get_set_default --root=/
23f3a6f5
FS
277
278# show/status
279systemctl show --property ""
280# Pick a heavily sandboxed unit for the best effect on coverage
281systemctl show systemd-logind.service
282systemctl status
283# Ignore the exit code in this case, as it might try to load non-existing units
284systemctl status -a >/dev/null || :
285systemctl status -a --state active,running,plugged >/dev/null
286systemctl status "systemd-*.timer"
287systemctl status "systemd-journald*.socket"
288systemctl status "sys-devices-*-ttyS0.device"
289systemctl status -- -.mount
e0e7bc82 290systemctl status 1
23f3a6f5
FS
291
292# --marked
293systemctl restart "$UNIT_NAME"
294systemctl set-property "$UNIT_NAME" Markers=needs-restart
295systemctl show -P Markers "$UNIT_NAME" | grep needs-restart
296systemctl reload-or-restart --marked
297(! systemctl show -P Markers "$UNIT_NAME" | grep needs-restart)
298
299# --dry-run with destructive verbs
300# kexec is skipped intentionally, as it requires a bit more involved setup
301VERBS=(
302 default
303 emergency
304 exit
305 halt
306 hibernate
307 hybrid-sleep
308 poweroff
309 reboot
310 rescue
311 suspend
312 suspend-then-hibernate
313)
314
315for verb in "${VERBS[@]}"; do
316 systemctl --dry-run "$verb"
317
318 if [[ "$verb" =~ (halt|poweroff|reboot) ]]; then
319 systemctl --dry-run --message "Hello world" "$verb"
320 systemctl --dry-run --no-wall "$verb"
321 systemctl --dry-run -f "$verb"
322 systemctl --dry-run -ff "$verb"
323 fi
324done
325
d16684fe
FS
326# Aux verbs & assorted checks
327systemctl is-active "*-journald.service"
328systemctl cat "*journal*"
329systemctl cat "$UNIT_NAME"
330systemctl help "$UNIT_NAME"
23f3a6f5
FS
331systemctl service-watchdogs
332systemctl service-watchdogs "$(systemctl service-watchdogs)"
d16684fe
FS
333
334# show/set-environment
79411bbc
LP
335# Make sure PATH is set
336systemctl show-environment | grep -q '^PATH='
79411bbc
LP
337# Let's add an entry and override a built-in one
338systemctl set-environment PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/testaddition FOO=BAR
79411bbc
LP
339# Check that both are set
340systemctl show-environment | grep -q '^PATH=.*testaddition$'
341systemctl show-environment | grep -q '^FOO=BAR$'
79411bbc 342systemctl daemon-reload
79411bbc
LP
343# Check again after the reload
344systemctl show-environment | grep -q '^PATH=.*testaddition$'
345systemctl show-environment | grep -q '^FOO=BAR$'
5ef599b3
JH
346# Check that JSON output is supported
347systemctl show-environment --output=json | grep -q '^{.*"FOO":"BAR".*}$'
79411bbc
LP
348# Drop both
349systemctl unset-environment FOO PATH
79411bbc 350# Check that one is gone and the other reverted to the built-in
4e20fe27
ZJS
351systemctl show-environment | grep '^FOO=$' && exit 1
352systemctl show-environment | grep '^PATH=.*testaddition$' && exit 1
79411bbc 353systemctl show-environment | grep -q '^PATH='
d16684fe
FS
354# Check import-environment
355export IMPORT_THIS=hello
356export IMPORT_THIS_TOO=world
357systemctl import-environment IMPORT_THIS IMPORT_THIS_TOO
358systemctl show-environment | grep "^IMPORT_THIS=$IMPORT_THIS"
359systemctl show-environment | grep "^IMPORT_THIS_TOO=$IMPORT_THIS_TOO"
360systemctl unset-environment IMPORT_THIS IMPORT_THIS_TOO
361(! systemctl show-environment | grep "^IMPORT_THIS=")
362(! systemctl show-environment | grep "^IMPORT_THIS_TOO=")
79411bbc 363
5f882cc3
YW
364# test for sysv-generator (issue #24990)
365if [[ -x /usr/lib/systemd/system-generators/systemd-sysv-generator ]]; then
fc2a0bc0
FS
366 # This is configurable via -Dsysvinit-path=, but we can't get the value
367 # at runtime, so let's just support the two most common paths for now.
368 [[ -d /etc/rc.d/init.d ]] && SYSVINIT_PATH="/etc/rc.d/init.d" || SYSVINIT_PATH="/etc/init.d"
369
5f882cc3 370 # invalid dependency
fc2a0bc0 371 cat >"${SYSVINIT_PATH:?}/issue-24990" <<\EOF
5f882cc3
YW
372#!/bin/bash
373
374### BEGIN INIT INFO
375# Provides:test1 test2
376# Required-Start:test1 $remote_fs $network
377# Required-Stop:test1 $remote_fs $network
378# Description:Test
379# Short-Description: Test
380### END INIT INFO
381
382case "$1" in
383 start)
384 echo "Starting issue-24990.service"
385 sleep 1000 &
386 ;;
387 stop)
388 echo "Stopping issue-24990.service"
389 sleep 10 &
390 ;;
391 *)
392 echo "Usage: service test {start|stop|restart|status}"
393 ;;
394esac
395EOF
396
fc2a0bc0 397 chmod +x "$SYSVINIT_PATH/issue-24990"
5f882cc3
YW
398 systemctl daemon-reload
399 [[ -L /run/systemd/generator.late/test1.service ]]
400 [[ -L /run/systemd/generator.late/test2.service ]]
401 assert_eq "$(readlink -f /run/systemd/generator.late/test1.service)" "/run/systemd/generator.late/issue-24990.service"
402 assert_eq "$(readlink -f /run/systemd/generator.late/test2.service)" "/run/systemd/generator.late/issue-24990.service"
403 output=$(systemctl cat issue-24990)
fc2a0bc0 404 assert_in "SourcePath=$SYSVINIT_PATH/issue-24990" "$output"
5f882cc3
YW
405 assert_in "Description=LSB: Test" "$output"
406 assert_in "After=test1.service" "$output"
407 assert_in "After=remote-fs.target" "$output"
408 assert_in "After=network-online.target" "$output"
409 assert_in "Wants=network-online.target" "$output"
fc2a0bc0
FS
410 assert_in "ExecStart=$SYSVINIT_PATH/issue-24990 start" "$output"
411 assert_in "ExecStop=$SYSVINIT_PATH/issue-24990 stop" "$output"
5f882cc3
YW
412 systemctl status issue-24990 || :
413 systemctl show issue-24990
414 assert_not_in "issue-24990.service" "$(systemctl show --property=After --value)"
415 assert_not_in "issue-24990.service" "$(systemctl show --property=Before --value)"
416
417 if ! systemctl is-active network-online.target; then
418 systemctl start network-online.target
419 fi
420
421 systemctl restart issue-24990
422 systemctl stop issue-24990
423
424 # valid dependency
fc2a0bc0 425 cat >"$SYSVINIT_PATH/issue-24990" <<\EOF
5f882cc3
YW
426#!/bin/bash
427
428### BEGIN INIT INFO
429# Provides:test1 test2
430# Required-Start:$remote_fs
431# Required-Stop:$remote_fs
432# Description:Test
433# Short-Description: Test
434### END INIT INFO
435
436case "$1" in
437 start)
438 echo "Starting issue-24990.service"
439 sleep 1000 &
440 ;;
441 stop)
442 echo "Stopping issue-24990.service"
443 sleep 10 &
444 ;;
445 *)
446 echo "Usage: service test {start|stop|restart|status}"
447 ;;
448esac
449EOF
79411bbc 450
fc2a0bc0 451 chmod +x "$SYSVINIT_PATH/issue-24990"
5f882cc3
YW
452 systemctl daemon-reload
453 [[ -L /run/systemd/generator.late/test1.service ]]
454 [[ -L /run/systemd/generator.late/test2.service ]]
455 assert_eq "$(readlink -f /run/systemd/generator.late/test1.service)" "/run/systemd/generator.late/issue-24990.service"
456 assert_eq "$(readlink -f /run/systemd/generator.late/test2.service)" "/run/systemd/generator.late/issue-24990.service"
457 output=$(systemctl cat issue-24990)
fc2a0bc0 458 assert_in "SourcePath=$SYSVINIT_PATH/issue-24990" "$output"
5f882cc3
YW
459 assert_in "Description=LSB: Test" "$output"
460 assert_in "After=remote-fs.target" "$output"
fc2a0bc0
FS
461 assert_in "ExecStart=$SYSVINIT_PATH/issue-24990 start" "$output"
462 assert_in "ExecStop=$SYSVINIT_PATH/issue-24990 stop" "$output"
5f882cc3
YW
463 systemctl status issue-24990 || :
464 systemctl show issue-24990
465 assert_not_in "issue-24990.service" "$(systemctl show --property=After --value)"
466 assert_not_in "issue-24990.service" "$(systemctl show --property=Before --value)"
467
468 systemctl restart issue-24990
469 systemctl stop issue-24990
470fi
79411bbc 471
4190124b
FS
472# %J in WantedBy= causes ABRT (#26467)
473cat >/run/systemd/system/test-WantedBy.service <<EOF
474[Service]
475ExecStart=true
476
477[Install]
478WantedBy=user-%i@%J.service
479EOF
480systemctl daemon-reload
481systemctl enable --now test-WantedBy.service || :
482systemctl daemon-reload
483
5f882cc3 484touch /testok