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