]>
Commit | Line | Data |
---|---|---|
ff12a795 | 1 | #!/usr/bin/env bash |
7b3cec95 | 2 | # SPDX-License-Identifier: LGPL-2.1-or-later |
209d355c | 3 | # shellcheck disable=SC2016 |
084575ff | 4 | set -eux |
79411bbc LP |
5 | set -o pipefail |
6 | ||
5f882cc3 YW |
7 | # shellcheck source=test/units/assert.sh |
8 | . "$(dirname "$0")"/assert.sh | |
9 | ||
10 | : >/failed | |
11 | ||
d16684fe FS |
12 | at_exit() { |
13 | if [[ -v UNIT_NAME && -e "/usr/lib/systemd/system/$UNIT_NAME" ]]; then | |
209d355c | 14 | rm -fvr "/usr/lib/systemd/system/$UNIT_NAME" "/etc/systemd/system/$UNIT_NAME.d" "+4" |
d16684fe | 15 | fi |
5f882cc3 YW |
16 | |
17 | rm -f /etc/init.d/issue-24990 | |
18 | return 0 | |
d16684fe FS |
19 | } |
20 | ||
9aaa333f MY |
21 | # shellcheck source=test/units/assert.sh |
22 | . "$(dirname "$0")"/assert.sh | |
23 | ||
d16684fe FS |
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 | |
209d355c | 29 | export UNIT_NAME="systemctl-test-$RANDOM.service" |
d16684fe FS |
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 | ||
209d355c | 53 | EDITOR='true' script -ec 'systemctl edit "$UNIT_NAME"' /dev/null |
54 | [ ! -e "/etc/systemd/system/$UNIT_NAME.d/override.conf" ] | |
55 | ||
7a17e41d | 56 | printf '%s\n' '[Service]' 'ExecStart=' 'ExecStart=sleep 10d' >"+4" |
209d355c | 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 | ||
7a17e41d | 60 | printf '%b' '[Service]\n' 'ExecStart=\n' 'ExecStart=sleep 10d' >"+4" |
209d355c | 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" | |
d16684fe FS |
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 | |
23f3a6f5 FS |
82 | # Compat: --type= allows load states for compatibility reasons |
83 | systemctl list-units --type=loaded | |
84 | systemctl list-units --type=loaded,socket | |
d16684fe FS |
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 "*" | |
37299769 MY |
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 | |
d16684fe | 105 | |
9aaa333f MY |
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 | ||
d16684fe FS |
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 | |
23f3a6f5 | 200 | (! systemd-run --wait --unit "failed.service" /bin/false) |
d16684fe FS |
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 | ||
23f3a6f5 FS |
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 | |
e0e7bc82 | 248 | systemctl status 1 |
23f3a6f5 FS |
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 | ||
d16684fe FS |
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" | |
23f3a6f5 FS |
289 | systemctl service-watchdogs |
290 | systemctl service-watchdogs "$(systemctl service-watchdogs)" | |
d16684fe FS |
291 | |
292 | # show/set-environment | |
79411bbc LP |
293 | # Make sure PATH is set |
294 | systemctl show-environment | grep -q '^PATH=' | |
79411bbc LP |
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 | |
79411bbc LP |
297 | # Check that both are set |
298 | systemctl show-environment | grep -q '^PATH=.*testaddition$' | |
299 | systemctl show-environment | grep -q '^FOO=BAR$' | |
79411bbc | 300 | systemctl daemon-reload |
79411bbc LP |
301 | # Check again after the reload |
302 | systemctl show-environment | grep -q '^PATH=.*testaddition$' | |
303 | systemctl show-environment | grep -q '^FOO=BAR$' | |
5ef599b3 JH |
304 | # Check that JSON output is supported |
305 | systemctl show-environment --output=json | grep -q '^{.*"FOO":"BAR".*}$' | |
79411bbc LP |
306 | # Drop both |
307 | systemctl unset-environment FOO PATH | |
79411bbc | 308 | # Check that one is gone and the other reverted to the built-in |
4e20fe27 ZJS |
309 | systemctl show-environment | grep '^FOO=$' && exit 1 |
310 | systemctl show-environment | grep '^PATH=.*testaddition$' && exit 1 | |
79411bbc | 311 | systemctl show-environment | grep -q '^PATH=' |
d16684fe FS |
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=") | |
79411bbc | 321 | |
5f882cc3 YW |
322 | # test for sysv-generator (issue #24990) |
323 | if [[ -x /usr/lib/systemd/system-generators/systemd-sysv-generator ]]; then | |
fc2a0bc0 FS |
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 | ||
5f882cc3 | 328 | # invalid dependency |
fc2a0bc0 | 329 | cat >"${SYSVINIT_PATH:?}/issue-24990" <<\EOF |
5f882cc3 YW |
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 | ||
fc2a0bc0 | 355 | chmod +x "$SYSVINIT_PATH/issue-24990" |
5f882cc3 YW |
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) | |
fc2a0bc0 | 362 | assert_in "SourcePath=$SYSVINIT_PATH/issue-24990" "$output" |
5f882cc3 YW |
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" | |
fc2a0bc0 FS |
368 | assert_in "ExecStart=$SYSVINIT_PATH/issue-24990 start" "$output" |
369 | assert_in "ExecStop=$SYSVINIT_PATH/issue-24990 stop" "$output" | |
5f882cc3 YW |
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 | |
fc2a0bc0 | 383 | cat >"$SYSVINIT_PATH/issue-24990" <<\EOF |
5f882cc3 YW |
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 | |
79411bbc | 408 | |
fc2a0bc0 | 409 | chmod +x "$SYSVINIT_PATH/issue-24990" |
5f882cc3 YW |
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) | |
fc2a0bc0 | 416 | assert_in "SourcePath=$SYSVINIT_PATH/issue-24990" "$output" |
5f882cc3 YW |
417 | assert_in "Description=LSB: Test" "$output" |
418 | assert_in "After=remote-fs.target" "$output" | |
fc2a0bc0 FS |
419 | assert_in "ExecStart=$SYSVINIT_PATH/issue-24990 start" "$output" |
420 | assert_in "ExecStop=$SYSVINIT_PATH/issue-24990 stop" "$output" | |
5f882cc3 YW |
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 | |
79411bbc | 429 | |
5f882cc3 YW |
430 | touch /testok |
431 | rm /failed |