2 # SPDX-License-Identifier: LGPL-2.1-or-later
6 # shellcheck source=test/units/test-control.sh
7 .
"$(dirname "$0")"/test-control.sh
8 # shellcheck source=test/units/util.sh
9 .
"$(dirname "$0")"/util.sh
14 pkill
-u "$(id -u logind-test-user)"
16 pkill
-KILL -u "$(id -u logind-test-user)"
17 userdel
-r logind-test-user
23 mkdir
-p /var
/spool
/cron
/var
/spool
/mail
24 useradd
-m -s /bin
/bash logind-test-user
25 trap cleanup_test_user EXIT
29 mkdir
-p /run
/systemd
/system
/systemd-logind.service.d
30 cat >/run
/systemd
/system
/systemd-logind.service.d
/debug.conf
<<EOF
32 Environment=SYSTEMD_LOG_LEVEL=debug
34 systemctl daemon-reload
35 systemctl stop systemd-logind.service
38 testcase_properties
() {
39 mkdir
-p /run
/systemd
/logind.conf.d
41 cat >/run
/systemd
/logind.conf.d
/kill-user-processes.conf
<<EOF
46 systemctl restart systemd-logind.service
47 assert_eq
"$(busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager KillUserProcesses)" "b false"
49 cat >/run
/systemd
/logind.conf.d
/kill-user-processes.conf
<<EOF
54 systemctl restart systemd-logind.service
55 assert_eq
"$(busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager KillUserProcesses)" "b true"
57 rm -rf /run
/systemd
/logind.conf.d
63 systemctl restart systemd-logind.service
65 # should start at boot, not with D-BUS activation
66 pid
=$
(systemctl show systemd-logind.service
-p ExecMainPID
--value)
68 # loginctl should succeed
71 # logind should still be running
72 assert_eq
"$(systemctl show systemd-logind.service -p ExecMainPID --value)" "$pid"
76 timeout
"${1?}" bash
-c "while [[ ! -e /run/suspend.flag ]]; do sleep 1; done"
85 rm -rf /run
/systemd
/system
/systemd-suspend.service.d
86 systemctl daemon-reload
88 rm -f /run
/udev
/rules.d
/70-logindtest-lid.rules
89 udevadm control
--reload
94 testcase_suspend_on_lid
() {
95 local pid input_name lid_dev
97 if systemd-detect-virt
--quiet --container; then
98 echo "Skipping suspend test in container"
101 if ! grep -s -q mem
/sys
/power
/state
; then
102 echo "suspend not supported on this testbed, skipping"
105 if ! command -v evemu-device
>/dev
/null
; then
106 echo "command evemu-device not found, skipping"
109 if ! command -v evemu-event
>/dev
/null
; then
110 echo "command evemu-event not found, skipping"
114 trap teardown_suspend RETURN
117 pid
=$
(systemctl show systemd-logind.service
-p ExecMainPID
--value)
119 # create fake suspend
120 mkdir
-p /run
/systemd
/system
/systemd-suspend.service.d
121 cat >/run
/systemd
/system
/systemd-suspend.service.d
/override.conf
<<EOF
124 ExecStart=touch /run/suspend.flag
126 systemctl daemon-reload
128 # create fake lid switch
129 mkdir
-p /run
/udev
/rules.d
130 cat >/run
/udev
/rules.d
/70-logindtest-lid.rules
<<EOF
131 SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="Fake Lid Switch", TAG+="power-switch"
133 udevadm control
--reload
135 cat >/run
/lidswitch.evemu
<<EOF
137 # Input device name: "Lid Switch"
138 # Input device ID: bus 0x19 vendor 0000 product 0x05 version 0000
140 # Event type 0 (EV_SYN)
141 # Event code 0 (SYN_REPORT)
142 # Event code 5 (FF_STATUS_MAX)
143 # Event type 5 (EV_SW)
144 # Event code 0 (SW_LID)
147 I: 0019 0000 0005 0000
148 P: 00 00 00 00 00 00 00 00
149 B: 00 21 00 00 00 00 00 00 00
150 B: 01 00 00 00 00 00 00 00 00
151 B: 01 00 00 00 00 00 00 00 00
152 B: 01 00 00 00 00 00 00 00 00
153 B: 01 00 00 00 00 00 00 00 00
154 B: 01 00 00 00 00 00 00 00 00
155 B: 01 00 00 00 00 00 00 00 00
156 B: 01 00 00 00 00 00 00 00 00
157 B: 01 00 00 00 00 00 00 00 00
158 B: 01 00 00 00 00 00 00 00 00
159 B: 01 00 00 00 00 00 00 00 00
160 B: 01 00 00 00 00 00 00 00 00
161 B: 01 00 00 00 00 00 00 00 00
162 B: 02 00 00 00 00 00 00 00 00
163 B: 03 00 00 00 00 00 00 00 00
164 B: 04 00 00 00 00 00 00 00 00
165 B: 05 01 00 00 00 00 00 00 00
166 B: 11 00 00 00 00 00 00 00 00
167 B: 12 00 00 00 00 00 00 00 00
168 B: 15 00 00 00 00 00 00 00 00
169 B: 15 00 00 00 00 00 00 00 00
172 evemu-device
/run
/lidswitch.evemu
&
174 timeout
20 bash
-c 'until grep "^Fake Lid Switch" /sys/class/input/*/device/name; do sleep .5; done'
175 input_name
=$
(grep -l '^Fake Lid Switch' /sys
/class
/input
/*/device
/name ||
:)
176 if [[ -z "$input_name" ]]; then
177 echo "cannot find fake lid switch." >&2
180 input_name
=${input_name%/device/name}
181 lid_dev
=/dev
/${input_name#/sys/class/}
182 udevadm info
--wait-for-initialization=10s
"$lid_dev"
186 evemu-event
"$lid_dev" --sync --type 5 --code 0 --value 1
187 # need to wait for 30s suspend inhibition after boot
190 evemu-event
"$lid_dev" --sync --type 5 --code 0 --value 0
192 # waiting for 30s inhibition time between suspends
195 # now closing lid should cause instant suspend
196 evemu-event
"$lid_dev" --sync --type 5 --code 0 --value 1
198 evemu-event
"$lid_dev" --sync --type 5 --code 0 --value 0
200 assert_eq
"$(systemctl show systemd-logind.service -p ExecMainPID --value)" "$pid"
203 testcase_shutdown
() {
207 pid
=$
(systemctl show systemd-logind.service
-p ExecMainPID
--value)
209 # scheduled shutdown with wall message
213 # logind should still be running
214 assert_eq
"$(systemctl show systemd-logind.service -p ExecMainPID --value)" "$pid"
216 # scheduled shutdown without wall message
217 shutdown
--no-wall 2>&1
219 shutdown
-c --no-wall || true
220 assert_eq
"$(systemctl show systemd-logind.service -p ExecMainPID --value)" "$pid"
228 uid
=$
(id
-u logind-test-user
)
230 loginctl disable-linger logind-test-user
232 systemctl stop getty@tty2.service
234 for s
in $
(loginctl
--no-legend list-sessions |
awk '$3 == "logind-test-user" { print $1 }'); do
235 echo "INFO: stopping session $s"
236 loginctl terminate-session
"$s"
239 loginctl terminate-user logind-test-user
241 if ! timeout
30 bash
-c "while loginctl --no-legend | grep -q logind-test-user; do sleep 1; done"; then
242 echo "WARNING: session for logind-test-user still active, ignoring."
247 pkill
-KILL -u "$uid"
249 if ! timeout
30 bash
-c "while systemctl is-active --quiet user@${uid}.service; do sleep 1; done"; then
250 echo "WARNING: user@${uid}.service is still active, ignoring."
253 if ! timeout
30 bash
-c "while systemctl is-active --quiet user-runtime-dir@${uid}.service; do sleep 1; done"; then
254 echo "WARNING: user-runtime-dir@${uid}.service is still active, ignoring."
257 if ! timeout
30 bash
-c "while systemctl is-active --quiet user-${uid}.slice; do sleep 1; done"; then
258 echo "WARNING: user-${uid}.slice is still active, ignoring."
261 rm -rf /run
/systemd
/system
/getty@tty2.service.d
262 systemctl daemon-reload
272 rm -f /run
/udev
/rules.d
/70-logindtest-scsi_debug-user.rules
273 udevadm control
--reload
282 local seat session leader_pid
284 if [[ $
(loginctl
--no-legend |
grep -c "logind-test-user") != 1 ]]; then
285 echo "no session or multiple sessions for logind-test-user." >&2
289 seat
=$
(loginctl
--no-legend |
grep 'logind-test-user *seat' |
awk '{ print $4 }')
290 if [[ -z "$seat" ]]; then
291 echo "no seat found for user logind-test-user" >&2
295 session
=$
(loginctl
--no-legend |
awk '$3 == "logind-test-user" { print $1 }')
296 if [[ -z "$session" ]]; then
297 echo "no session found for user logind-test-user" >&2
301 if ! loginctl session-status
"$session" |
grep -q "Unit: session-${session}\.scope"; then
302 echo "cannot find scope unit for session $session" >&2
306 leader_pid
=$
(loginctl session-status
"$session" |
awk '$1 == "Leader:" { print $2 }')
307 if [[ -z "$leader_pid" ]]; then
308 echo "cannot found leader process for session $session" >&2
312 # cgroup v1: "1:name=systemd:/user.slice/..."; unified hierarchy: "0::/user.slice"
313 if ! grep -q -E '(name=systemd|^0:):.*session.*scope' /proc
/"$leader_pid"/cgroup
; then
314 echo "FAIL: process $leader_pid is not in the session cgroup" >&2
315 cat /proc
/self
/cgroup
321 # login with the test user to start a session
322 mkdir
-p /run
/systemd
/system
/getty@tty2.service.d
323 cat >/run
/systemd
/system
/getty@tty2.service.d
/override.conf
<<EOF
327 ExecStart=-/sbin/agetty --autologin logind-test-user --noclear %I $TERM
330 systemctl daemon-reload
332 systemctl restart getty@tty2.service
336 (( i
> 1 )) && sleep 1
337 check_session
&& break
340 assert_eq
"$(loginctl --no-legend | awk '$3=="logind-test-user
" { print $5 }')" "tty2"
343 testcase_sanity_check
() {
344 # Exercise basic loginctl options
346 if [[ ! -c /dev
/tty2
]]; then
347 echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}."
351 trap cleanup_session RETURN
354 # Run most of the loginctl commands from a user session to make
355 # the seat/session autodetection work-ish
356 systemd-run
--user --pipe --wait -M "logind-test-user@.host" bash
-eux <<\EOF
357 loginctl list-sessions
358 loginctl session-status
359 loginctl show-session
360 loginctl show-session
-P DelayInhibited
362 # We're not in the same session scope, so in this case we need to specify
363 # the session ID explicitly
364 session
=$
(loginctl
--no-legend |
awk '$3 == "logind-test-user" { print $1; exit; }')
365 loginctl kill-session
--signal=SIGCONT
"$session"
367 #loginctl kill-session --signal=SIGCONT --kill-whom=leader "$session"
371 loginctl show-user
-a
372 loginctl show-user
-P IdleAction
373 loginctl kill-user
--signal=SIGCONT
""
378 loginctl show-seat
-P IdleActionUSec
381 # Requires root privileges
382 loginctl lock-sessions
383 loginctl unlock-sessions
384 loginctl flush-devices
390 if systemd-detect-virt
--quiet --container; then
391 echo "Skipping ACL tests in container"
395 if [[ ! -c /dev
/tty2
]]; then
396 echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}."
400 trap teardown_session RETURN
404 # scsi_debug should not be loaded yet
405 if [[ -d /sys
/bus
/pseudo
/drivers
/scsi_debug
]]; then
406 echo "scsi_debug module is already loaded." >&2
410 # we use scsi_debug to create new devices which we can put ACLs on
411 # tell udev about the tagging, so that logind can pick it up
412 mkdir
-p /run
/udev
/rules.d
413 cat >/run
/udev
/rules.d
/70-logindtest-scsi_debug-user.rules
<<EOF
414 SUBSYSTEM=="block", ATTRS{model}=="scsi_debug*", TAG+="uaccess"
416 udevadm control
--reload
418 # coldplug: logind started with existing device
419 systemctl stop systemd-logind.service
421 timeout
30 bash
-c 'until ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null; do sleep 1; done'
422 dev
=/dev
/$
(ls /sys
/bus
/pseudo
/drivers
/scsi_debug
/adapter
*/host*/target
*/*:*/block
2>/dev
/null
)
423 if [[ ! -b "$dev" ]]; then
424 echo "cannot find suitable scsi block device" >&2
430 # trigger logind and activate session
431 loginctl activate
"$(loginctl --no-legend | awk '$3 == "logind-test-user
" { print $1 }')"
435 assert_in
"user:logind-test-user:rw-" "$(getfacl -p "$dev")"
437 # hotplug: new device appears while logind is running
440 timeout
30 bash
-c 'until ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null; do sleep 1; done'
441 dev
=/dev
/$
(ls /sys
/bus
/pseudo
/drivers
/scsi_debug
/adapter
*/host*/target
*/*:*/block
2>/dev
/null
)
442 if [[ ! -b "$dev" ]]; then
443 echo "cannot find suitable scsi block device" >&2
450 assert_in
"user:logind-test-user:rw-" "$(getfacl -p "$dev")"
453 teardown_lock_idle_action
() (
456 rm -f /run
/systemd
/logind.conf.d
/idle-action-lock.conf
457 systemctl restart systemd-logind.service
464 testcase_lock_idle_action
() {
467 if [[ ! -c /dev
/tty2
]]; then
468 echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}."
472 if loginctl
--no-legend |
grep -q logind-test-user
; then
473 echo >&2 "Session of the 'logind-test-user' is already present."
477 trap teardown_lock_idle_action RETURN
481 ts
="$(date '+%H:%M:%S')"
483 mkdir
-p /run
/systemd
/logind.conf.d
484 cat >/run
/systemd
/logind.conf.d
/idle-action-lock.conf
<<EOF
489 systemctl restart systemd-logind.service
491 # Wait for 35s, in that interval all sessions should have become idle
492 # and "Lock" signal should have been sent out. Then we wrote to tty to make
493 # session active again and next we slept for another 35s so sessions have
494 # become idle again. 'Lock' signal is sent out for each session, we have at
495 # least one session, so minimum of 2 "Lock" signals must have been sent.
496 timeout
35 bash
-c "while [[ \"\$(journalctl -b -u systemd-logind.service --since=$ts | grep -c 'Sent message type=signal .* member=Lock')\" -lt 1 ]]; do sleep 1; done"
502 timeout
35 bash
-c "while [[ \"\$(journalctl -b -u systemd-logind.service --since=$ts | grep -c 'Sent message type=signal .* member=Lock')\" -lt 2 ]]; do sleep 1; done"
504 if [[ "$(journalctl -b -u systemd-logind.service --since="$ts" | grep -c 'System idle. Will be locked now.')" -lt 2 ]]; then
505 echo >&2 "System haven't entered idle state at least 2 times."
510 testcase_session_properties
() {
513 if [[ ! -c /dev
/tty2
]]; then
514 echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}."
518 trap cleanup_session RETURN
521 s
=$
(loginctl list-sessions
--no-legend |
awk '$3 == "logind-test-user" { print $1 }')
522 /usr
/lib
/systemd
/tests
/unit-tests
/manual
/test-session-properties
"/org/freedesktop/login1/session/_3${s?}" /dev
/tty2
525 testcase_list_users_sessions_seats
() {
528 if [[ ! -c /dev
/tty2
]]; then
529 echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}."
533 trap cleanup_session RETURN
536 # Activate the session
537 loginctl activate
"$(loginctl --no-legend | awk '$3 == "logind-test-user
" { print $1 }')"
539 session
=$
(loginctl list-sessions
--no-legend |
awk '$3 == "logind-test-user" { print $1 }')
540 : check that we got a valid session id
541 busctl get-property org.freedesktop.login1
"/org/freedesktop/login1/session/_3${session?}" org.freedesktop.login1.Session Id
542 assert_eq
"$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user
" { print $2 }')" "$(id -ru logind-test-user)"
543 seat
=$
(loginctl list-sessions
--no-legend |
awk '$3 == "logind-test-user" { print $4 }')
544 assert_eq
"$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user
" { print $5 }')" tty2
545 assert_eq
"$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user
" { print $6 }')" active
546 assert_eq
"$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user
" { print $7 }')" no
547 assert_eq
"$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user
" { print $8 }')" '-'
549 loginctl list-seats
--no-legend |
grep -Fwq "${seat?}"
551 assert_eq
"$(loginctl list-users --no-legend | awk '$2 == "logind-test-user
" { print $1 }')" "$(id -ru logind-test-user)"
552 assert_eq
"$(loginctl list-users --no-legend | awk '$2 == "logind-test-user
" { print $3 }')" no
553 assert_eq
"$(loginctl list-users --no-legend | awk '$2 == "logind-test-user
" { print $4 }')" active
555 loginctl enable-linger logind-test-user
556 assert_eq
"$(loginctl list-users --no-legend | awk '$2 == "logind-test-user
" { print $3 }')" yes
558 for s
in $
(loginctl list-sessions
--no-legend |
awk '$3 == "logind-test-user" { print $1 }'); do
559 loginctl terminate-session
"$s"
561 if ! timeout
30 bash
-c "while loginctl --no-legend | grep -q logind-test-user; do sleep 1; done"; then
562 echo "WARNING: session for logind-test-user still active, ignoring."
566 assert_eq
"$(loginctl list-users --no-legend | awk '$2 == "logind-test-user
" { print $4 }')" lingering
569 teardown_stop_idle_session
() (
572 rm -f /run
/systemd
/logind.conf.d
/stop-idle-session.conf
573 systemctl restart systemd-logind.service
578 testcase_stop_idle_session
() {
581 if [[ ! -c /dev
/tty2
]]; then
582 echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}."
587 trap teardown_stop_idle_session RETURN
589 id
="$(loginctl --no-legend | awk '$3 == "logind-test-user
" { print $1; }')"
590 ts
="$(date '+%H:%M:%S')"
592 mkdir
-p /run
/systemd
/logind.conf.d
593 cat >/run
/systemd
/logind.conf.d
/stop-idle-session.conf
<<EOF
595 StopIdleSessionSec=2s
597 systemctl restart systemd-logind.service
600 assert_eq
"$(journalctl -b -u systemd-logind.service --since="$ts" --grep "Session
\"$id\" of user
\"logind-test-user
\" is idle
, stopping.
" | wc -l)" 1
601 assert_eq
"$(loginctl --no-legend | grep -c "logind-test-user
")" 0
604 testcase_ambient_caps
() {
605 local PAMSERVICE TRANSIENTUNIT SCRIPT
607 # Verify that pam_systemd works and assigns ambient caps as it should
609 if ! grep -q 'CapAmb:' /proc
/self
/status
; then
610 echo "ambient caps not available, skipping test." >&2
616 # Get PID 1's bounding set
617 BND
="0x$(grep 'CapBnd:' /proc/1/status | cut -d: -f2 | tr -d '[:space:]')"
619 # CAP_CHOWN | CAP_KILL
620 MASK
=$
(((1 << 0) | (1 << 5)))
622 if [ $((BND & MASK)) -ne "$MASK" ] ; then
623 echo "CAP_CHOWN or CAP_KILL not available in bounding set, skipping test." >&2
627 PAMSERVICE="pamserv$RANDOM"
628 TRANSIENTUNIT="capwakealarm$RANDOM.service"
629 SCRIPT="/tmp/capwakealarm$RANDOM.sh"
631 cat > /etc/pam.d/"$PAMSERVICE" <<EOF
632 auth sufficient pam_unix.so
633 auth required pam_deny.so
634 account sufficient pam_unix.so
635 account required pam_permit.so
636 session optional pam_systemd.so default-capability-ambient-set=CAP_CHOWN,CAP_KILL debug
637 session required pam_unix.so
640 cat > "$SCRIPT" <<'EOF'
644 AMB="0x$
(grep 'CapAmb:' /proc
/self
/status | cut
-d: -f2 |
tr -d '[:space:]')"
645 MASK=$(((1 << 0) | (1 << 5)))
646 test "$AMB" -eq "$MASK"
651 systemd-run -u "$TRANSIENTUNIT" -p PAMName="$PAMSERVICE" -p Type=oneshot -p User=logind-test-user -p StandardError=tty "$SCRIPT"
653 rm -f "$SCRIPT" "$PAMSERVICE"