diff --git a/src/ublue_update/cli.py b/src/ublue_update/cli.py index e692146..4b4cf43 100644 --- a/src/ublue_update/cli.py +++ b/src/ublue_update/cli.py @@ -11,7 +11,7 @@ from ublue_update.update_inhibitors.hardware import check_hardware_inhibitors from ublue_update.update_inhibitors.custom import check_custom_inhibitors from ublue_update.config import cfg -from ublue_update.session import get_active_sessions +from ublue_update.session import get_active_users from ublue_update.filelock import acquire_lock, release_lock @@ -33,7 +33,7 @@ def notify(title: str, body: str, actions: list = [], urgency: str = "normal"): if process_uid == 0: users = [] try: - users = get_active_sessions() + users = get_active_users() except KeyError as e: log.error("failed to get active logind session info", e) for user in users: @@ -41,8 +41,9 @@ def notify(title: str, body: str, actions: list = [], urgency: str = "normal"): "/usr/bin/systemd-run", "--user", "--machine", - f"{user['user']}@", - "--wait", + f"{user[1]}@", # magic number, corresponds to user name in ListUsers (see session.py) + "--pipe", + "--quiet", ] user_args += args out = subprocess.run(user_args, capture_output=True) @@ -106,7 +107,7 @@ def run_updates(system, system_update_available): ) users = [] try: - users = get_active_sessions() + users = get_active_users() except KeyError as e: log.error("failed to get active logind session info", e) @@ -133,15 +134,18 @@ def run_updates(system, system_update_available): """Users""" for user in users: - log.info(f"""Running update for user: '{user['user']}'""") + log.info( + f"""Running update for user: '{user[1]}'""" + ) # magic number, corresponds to username (see session.py) out = subprocess.run( [ "/usr/bin/systemd-run", "--setenv=TOPGRADE_SKIP_BRKC_NOTIFY=true", "--user", "--machine", - f"{user['user']}@", - "--wait", + f"{user[1]}@", + "--pipe", + "--quiet", "/usr/bin/topgrade", "--config", "/usr/share/ublue-update/topgrade-user.toml", diff --git a/src/ublue_update/session.py b/src/ublue_update/session.py index 2371452..a54ce23 100644 --- a/src/ublue_update/session.py +++ b/src/ublue_update/session.py @@ -2,14 +2,22 @@ import json -def get_active_sessions(): +def get_active_users(): out = subprocess.run( - ["/usr/bin/loginctl", "list-sessions", "--output=json"], + [ + "/usr/bin/busctl", + "--system", + "-j", + "call", + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListUsers", + ], capture_output=True, ) - sessions = json.loads(out.stdout.decode("utf-8")) - active_sessions = [] - for session in sessions: - if session.get("state") == "active": - active_sessions.append(session) - return active_sessions + # https://www.freedesktop.org/software/systemd/man/latest/org.freedesktop.login1.html + # ListUsers() returns an array of all currently logged in users. The structures in the array consist of the following fields: user id, user name, user object path. + users = json.loads(out.stdout.decode("utf-8")) + # sample output: {'type': 'a(uso)', 'data': [[[1000, 'user', '/org/freedesktop/login1/user/_1000']]] + return users["data"][0] diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 913644d..a681c41 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -47,7 +47,6 @@ def test_notify_uid_user(mock_run, mock_log, mock_os, mock_cfg): capture_output=True, ) - @patch("ublue_update.cli.cfg") def test_ask_for_updates_no_dbus_notify(mock_cfg): mock_cfg.dbus_notify = False @@ -163,7 +162,7 @@ def test_run_updates_user_no_system( @patch("ublue_update.cli.os") -@patch("ublue_update.cli.get_active_sessions") +@patch("ublue_update.cli.get_active_users") @patch("ublue_update.cli.acquire_lock") @patch("ublue_update.cli.transaction_wait") @patch("ublue_update.cli.subprocess.run") @@ -212,7 +211,7 @@ def test_run_updates_system( @patch("ublue_update.cli.os") -@patch("ublue_update.cli.get_active_sessions") +@patch("ublue_update.cli.get_active_users") @patch("ublue_update.cli.acquire_lock") @patch("ublue_update.cli.transaction_wait") @patch("ublue_update.cli.subprocess.run") @@ -255,7 +254,7 @@ def test_run_updates_without_image_update( @patch("ublue_update.cli.os") -@patch("ublue_update.cli.get_active_sessions") +@patch("ublue_update.cli.get_active_users") @patch("ublue_update.cli.acquire_lock") @patch("ublue_update.cli.transaction_wait") @patch("ublue_update.cli.subprocess.run") diff --git a/tests/unit/test_session.py b/tests/unit/test_session.py index 551e42d..e097334 100644 --- a/tests/unit/test_session.py +++ b/tests/unit/test_session.py @@ -7,57 +7,33 @@ 0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../src")) ) -from ublue_update.session import get_active_sessions +from ublue_update.session import get_active_users -loginctl_json_output = b""" -[ - { - "session" : "3", - "uid" : 1001, - "user" : "test", - "seat" : null, - "leader" : 6205, - "class" : "manager", - "tty" : null, - "state": "active", - "idle" : false, - "since" : null - }, - { - "session" : "c1", - "uid" : 1001, - "user" : "test", - "seat" : null, - "leader" : 6230, - "class" : "manager", - "tty" : null, - "state": "inactive", - "idle" : false, - "since" : null - } -] -""" +busctl_json_output = b"""{"type":"a(uso)","data":[[[1000,"user","/org/freedesktop/login1/user/_1000"]]]}""" @patch("ublue_update.session.subprocess.run") -def test_get_active_sessions(mock_run): +def test_get_active_users(mock_run): mock_run.side_effect = [ - MagicMock(stdout=loginctl_json_output), + MagicMock(stdout=busctl_json_output), ] - assert get_active_sessions() == [ - { - "session": "3", - "uid": 1001, - "user": "test", - "seat": None, - "leader": 6205, - "class": "manager", - "tty": None, - "state": "active", - "idle": False, - "since": None, - } + assert get_active_users() == [ + [ + 1000, + "user", + "/org/freedesktop/login1/user/_1000", + ] ] mock_run.assert_any_call( - ["/usr/bin/loginctl", "list-sessions", "--output=json"], capture_output=True + [ + "/usr/bin/busctl", + "--system", + "-j", + "call", + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListUsers", + ], + capture_output=True, ) diff --git a/ublue-update.spec b/ublue-update.spec index 6a2e722..c9b97dc 100644 --- a/ublue-update.spec +++ b/ublue-update.spec @@ -29,7 +29,7 @@ BuildRequires: python-setuptools_scm BuildRequires: python-wheel Requires: skopeo Requires: libnotify -Requires: sudo +Requires: systemd %global sub_name %{lua:t=string.gsub(rpm.expand("%{NAME}"), "^ublue%-", ""); print(t)}