Search code examples
pythonsystemddbus

EOFError when trying to call Inhibit method on org.freedesktop.login1.Manager via dbus-fast


I'm developing a Python application which will be distributed to users on Linux in various forms (Flatpak, PyInstaller executable, maybe others). In this application, I want to call the Inhibit method on the org.freedesktop.login1.Manager dbus interface. Due to the relatively complex/diverse distribution requirements, I went with dbus-fast which is a pure Python implementation of dbus. Additionally, dbus-python's authors start the documentation of the library with various warnings, which was another point in dbus-fast's favour.

Anyway, dbus-fast seems to be working fine overall, and I am able to call e.g. the ListUsers method without problems like so:

import asyncio
from dbus_fast import BusType
from dbus_fast.aio import MessageBus

async def list_users() -> None:
    system_bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
    introspection = await system_bus.introspect(
        "org.freedesktop.login1",
        "/org/freedesktop/login1",
    )
    login_object = system_bus.get_proxy_object(
        "org.freedesktop.login1",
        "/org/freedesktop/login1",
        introspection,
    )
    login_manager_interface = login_object.get_interface(
        "org.freedesktop.login1.Manager",
    )

    user_list = await login_manager_interface.call_list_users()
    print(user_list)

asyncio.run(list_users())

Which I then can run and get a list like so:

$ python -m dbus_list_users
[[1000, 'newbyte', '/org/freedesktop/login1/user/_1000']]

However, if I try to call the Inhibit method, I get EOFError, which I don't understand the meaning of in this context. Here is the code:

import asyncio
from dbus_fast import BusType
from dbus_fast.aio import MessageBus

async def do_inhibit() -> None:
    system_bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
    introspection = await system_bus.introspect(
        "org.freedesktop.login1",
        "/org/freedesktop/login1",
    )
    login_object = system_bus.get_proxy_object(
        "org.freedesktop.login1",
        "/org/freedesktop/login1",
        introspection,
    )
    login_manager_interface = login_object.get_interface(
        "org.freedesktop.login1.Manager",
    )

    inhibit_fd = await login_manager_interface.call_inhibit(
        "sleep",
        "Stack Overflow example man",
        "To demonstrate that it does not work",
        "delay",
    )
    print(inhibit_fd)

asyncio.run(do_inhibit())

Running it gives me this long traceback:

$ python -m dbus_inhibit
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/mnt/storage/Programming/sparvio_toolbox/dbus_inhibit.py", line 28, in <module>
    asyncio.run(do_inhibit())
  File "/usr/lib64/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.12/asyncio/base_events.py", line 687, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/mnt/storage/Programming/sparvio_toolbox/dbus_inhibit.py", line 20, in do_inhibit
    inhibit_fd = await login_manager_interface.call_inhibit(
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/storage/Programming/sparvio_toolbox/_host-env/lib64/python3.12/site-packages/dbus_fast/aio/proxy_object.py", line 92, in method_fn
    msg = await self.bus.call(
          ^^^^^^^^^^^^^^^^^^^^
  File "/mnt/storage/Programming/sparvio_toolbox/_host-env/lib64/python3.12/site-packages/dbus_fast/aio/message_bus.py", line 385, in call
    await future
  File "src/dbus_fast/aio/message_reader.py", line 19, in dbus_fast.aio.message_reader._message_reader
  File "src/dbus_fast/_private/unmarshaller.py", line 775, in dbus_fast._private.unmarshaller.Unmarshaller._unmarshall
  File "src/dbus_fast/_private/unmarshaller.py", line 636, in dbus_fast._private.unmarshaller.Unmarshaller._read_header
  File "src/dbus_fast/_private/unmarshaller.py", line 376, in dbus_fast._private.unmarshaller.Unmarshaller._read_to_pos
  File "src/dbus_fast/_private/unmarshaller.py", line 339, in dbus_fast._private.unmarshaller.Unmarshaller._read_sock_without_fds
EOFError

I don't understand what to make of this. I've tried looking through the official documentation for inhibitor locks from systemd, but I haven't been able to figure anything out. How can I call the Inhibit method of org.freedesktop.login1.Manager and take an inhibitor lock in Python with dbus_python?


Solution

  • For some reason, dbus-fast does not enable support for file descriptor transfer by default. You must specify negotiate_unix_fd=True as a parameter to MessageBus() to enable this.