#!/usr/bin/env bash # SPDX-License-Identifier: LGPL-2.1-or-later set -eux set -o pipefail # shellcheck source=test/units/assert.sh . "$(dirname "$0")"/assert.sh cleanup_test_user() ( set +ex pkill -u "$(id -u logind-test-user)" sleep 1 pkill -KILL -u "$(id -u logind-test-user)" userdel -r logind-test-user return 0 ) setup_test_user() { mkdir -p /var/spool/cron /var/spool/mail useradd -m -s /bin/bash logind-test-user trap cleanup_test_user EXIT } test_enable_debug() { mkdir -p /run/systemd/system/systemd-logind.service.d cat >/run/systemd/system/systemd-logind.service.d/debug.conf </run/systemd/logind.conf.d/kill-user-processes.conf </run/systemd/logind.conf.d/kill-user-processes.conf </dev/null; then echo "command evemu-device not found, skipping" return fi if ! command -v evemu-event &>/dev/null; then echo "command evemu-event not found, skipping" return fi trap teardown_suspend RETURN # save pid pid=$(systemctl show systemd-logind.service -p ExecMainPID --value) # create fake suspend mkdir -p /run/systemd/system/systemd-suspend.service.d cat >/run/systemd/system/systemd-suspend.service.d/override.conf </run/udev/rules.d/70-logindtest-lid.rules </run/lidswitch.evemu <&2 exit 1 fi input_name=${input_name%/device/name} lid_dev=/dev/${input_name#/sys/class/} udevadm info --wait-for-initialization=10s "$lid_dev" udevadm settle # close lid evemu-event "$lid_dev" --sync --type 5 --code 0 --value 1 # need to wait for 30s suspend inhibition after boot wait_suspend 31 # open lid again evemu-event "$lid_dev" --sync --type 5 --code 0 --value 0 # waiting for 30s inhibition time between suspends sleep 30 # now closing lid should cause instant suspend evemu-event "$lid_dev" --sync --type 5 --code 0 --value 1 wait_suspend 2 evemu-event "$lid_dev" --sync --type 5 --code 0 --value 0 assert_eq "$(systemctl show systemd-logind.service -p ExecMainPID --value)" "$pid" } test_shutdown() { local pid # save pid pid=$(systemctl show systemd-logind.service -p ExecMainPID --value) # scheduled shutdown with wall message shutdown 2>&1 sleep 5 shutdown -c || : # logind should still be running assert_eq "$(systemctl show systemd-logind.service -p ExecMainPID --value)" "$pid" # scheduled shutdown without wall message shutdown --no-wall 2>&1 sleep 5 shutdown -c --no-wall || true assert_eq "$(systemctl show systemd-logind.service -p ExecMainPID --value)" "$pid" } cleanup_session() ( set +ex local uid uid=$(id -u logind-test-user) loginctl disable-linger logind-test-user systemctl stop getty@tty2.service pkill -u "$uid" sleep 1 pkill -KILL -u "$uid" if ! timeout 30 bash -c "while systemctl is-active --quiet user@${uid}.service; do sleep 1; done"; then echo "WARNING: user@${uid}.service is still active, ignoring." fi if ! timeout 30 bash -c "while systemctl is-active --quiet user-runtime-dir@${uid}.service; do sleep 1; done"; then echo "WARNING: user-runtime-dir@${uid}.service is still active, ignoring." fi if ! timeout 30 bash -c "while systemctl is-active --quiet user-${uid}.slice; do sleep 1; done"; then echo "WARNING: user-${uid}.slice is still active, ignoring." fi rm -rf /run/systemd/system/getty@tty2.service.d systemctl daemon-reload return 0 ) teardown_session() ( set +ex cleanup_session rm -f /run/udev/rules.d/70-logindtest-scsi_debug-user.rules udevadm control --reload rmmod scsi_debug return 0 ) check_session() ( set +ex local seat session leader_pid if [[ $(loginctl --no-legend | grep -c "logind-test-user") != 1 ]]; then echo "no session or multiple sessions for logind-test-user." >&2 return 1 fi seat=$(loginctl --no-legend | grep 'logind-test-user *seat' | awk '{ print $4 }') if [[ -z "$seat" ]]; then echo "no seat found for user logind-test-user" >&2 return 1 fi session=$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1 }') if [[ -z "$session" ]]; then echo "no session found for user logind-test-user" >&2 return 1 fi if ! loginctl session-status "$session" | grep -q "Unit: session-${session}\.scope"; then echo "cannot find scope unit for session $session" >&2 return 1 fi leader_pid=$(loginctl session-status "$session" | awk '$1 == "Leader:" { print $2 }') if [[ -z "$leader_pid" ]]; then echo "cannot found leader process for session $session" >&2 return 1 fi # cgroup v1: "1:name=systemd:/user.slice/..."; unified hierarchy: "0::/user.slice" if ! grep -q -E '(name=systemd|^0:):.*session.*scope' /proc/"$leader_pid"/cgroup; then echo "FAIL: process $leader_pid is not in the session cgroup" >&2 cat /proc/self/cgroup return 1 fi ) create_session() { # login with the test user to start a session mkdir -p /run/systemd/system/getty@tty2.service.d cat >/run/systemd/system/getty@tty2.service.d/override.conf <&2 exit 1 fi # we use scsi_debug to create new devices which we can put ACLs on # tell udev about the tagging, so that logind can pick it up mkdir -p /run/udev/rules.d cat >/run/udev/rules.d/70-logindtest-scsi_debug-user.rules </dev/null; do sleep 1; done' dev=/dev/$(ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null) if [[ ! -b "$dev" ]]; then echo "cannot find suitable scsi block device" >&2 exit 1 fi udevadm settle udevadm info "$dev" # trigger logind and activate session loginctl activate "$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1 }')" # check ACL sleep 1 assert_in "user:logind-test-user:rw-" "$(getfacl -p "$dev")" # hotplug: new device appears while logind is running rmmod scsi_debug modprobe scsi_debug timeout 30 bash -c 'while ! ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null; do sleep 1; done' dev=/dev/$(ls /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block 2>/dev/null) if [[ ! -b "$dev" ]]; then echo "cannot find suitable scsi block device" >&2 exit 1 fi udevadm settle # check ACL sleep 1 assert_in "user:logind-test-user:rw-" "$(getfacl -p "$dev")" } teardown_lock_idle_action() ( set +eux cleanup_session rm -f /run/systemd/logind.conf.d/idle-action-lock.conf systemctl restart systemd-logind.service return 0 ) test_lock_idle_action() { local ts if [[ ! -c /dev/tty2 ]]; then echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}." return fi if loginctl --no-legend | grep -q logind-test-user; then echo >&2 "Session of the \'logind-test-user\' is already present." exit 1 fi trap teardown_lock_idle_action RETURN create_session ts="$(date '+%H:%M:%S')" mkdir -p /run/systemd/logind.conf.d cat >/run/systemd/logind.conf.d/idle-action-lock.conf <&2 "System haven't entered idle state at least 2 times." exit 1 fi } test_session_properties() { local s if [[ ! -c /dev/tty2 ]]; then echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}." return fi trap cleanup_session RETURN create_session s=$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $1 }') /usr/lib/systemd/tests/manual/test-session-properties "/org/freedesktop/login1/session/_3${s?}" } test_list_users() { if [[ ! -c /dev/tty2 ]]; then echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}." return fi trap cleanup_session RETURN create_session assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $1 }')" "$(id -ru logind-test-user)" assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $3 }')" no loginctl enable-linger logind-test-user assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $3 }')" yes } : >/failed setup_test_user test_enable_debug test_properties test_started test_suspend_on_lid test_shutdown test_session test_lock_idle_action test_session_properties test_list_users touch /testok rm /failed