簡體   English   中英

通過Python的dbus函數調用傳遞文件描述符(又稱調用flatpak的HostCommand)

[英]Pass file descriptor via a dbus function call from Python (aka call flatpak's HostCommand)

我想調用Flatpak的新開發DBus服務來在主機上而不是在沙箱中生成進程

要調用DBus服務,我想出了以下代碼:

#!/usr/bin/env python
import logging
import os
import sys

import dbus

def call_on_host(cmd):
    "Calls Flatpak via DBus to spawn a process"
    name = "org.freedesktop.Flatpak"
    path = "/org/freedesktop/Flatpak/Development"
    bus = dbus.SessionBus()
    proxy = bus.get_object(name, path)

    iface = "org.freedesktop.Flatpak.Development"
    fp_helper = dbus.Interface(proxy, iface)

    wd = '/tmp/'
    read_fd, write_fd = os.pipe()
    fds = {0:dbus.types.UnixFd(read_fd)}
    envs = {'FOO':'bar'}
    flags = 1

    # cwd, cmd, fds, env, flags = ('/', ['ls'], {0:dbus.types.UnixFd(open('/etc/passwd'))}, {'foo':'bar'}, 1)
    logging.info("Executing %r %r %r %r %r", wd, cmd, fds, envs, flags)
    ret = fp_helper.HostCommand(wd, cmd, fds, envs, flags)
    return ret


logging.basicConfig(level=logging.DEBUG)

print (call_on_host(sys.argv[1:]))

然而,這並不是那么好用。 Flatpak DBus幫助程序不接收任何值,即它們都是NULL。

$ python execute_on_host.py  'ls' /
INFO:root:Executing '/tmp/' ['ls'] {0: <dbus.UnixFd object at 0x7f4b5ae6c120>} {'FOO': 'bar'} 1
Traceback (most recent call last):
  File "execute_on_host.py", line 42, in <module>
    print (call_on_host(sys.argv[1:]))
  File "execute_on_host.py", line 35, in call_on_host
    ret = fp_helper.HostCommand(wd, cmd, fds, envs, flags)
  File "/usr/lib/python2.7/dist-packages/dbus/proxies.py", line 70, in __call__
    return self._proxy_method(*args, **keywords)
  File "/usr/lib/python2.7/dist-packages/dbus/proxies.py", line 145, in __call__
    **keywords)
  File "/usr/lib/python2.7/dist-packages/dbus/connection.py", line 651, in call_blocking
    message, timeout)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.InvalidArgs: No command 19430 given!!1 - *arg_argv[0] == 0

我現在有點困惑。 在調用GVariants代理對象上的函數之前,是否需要包裝我的類型?

為了測試我是否可以使用該簽名調用服務,我從這個問題中竊取了大部分文本並提出了以下內容:

import unittest

import os
import sys
import subprocess
import time

import dbus
import dbus.service
import dbus.glib
import gobject

class MyDBUSService(dbus.service.Object):

    def __init__(self):
        bus_name = dbus.service.BusName('test.helloservice', bus = dbus.SessionBus())
        dbus.service.Object.__init__(self, bus_name, '/test/helloservice')

    def listen(self):
        loop = gobject.MainLoop()
        loop.run()

    @dbus.service.method('test.helloservice', in_signature="ayaaya{uh}a{ss}u")
    def hello(self, cwd, cmd, fds, env, flags):
        print ([type(foo) for foo in (cwd, cmd, fds, env, flags)]  )
        print ("cwd: %s" % cwd)
        print ("cmd: %s" % cmd)
        print ("fsd: %s" % fds)
        r = os.fdopen(fds[0].take()).read()
        return r


class BaseTestCase(unittest.TestCase):

    def setUp(self):
        env = os.environ.copy()
        self.p = subprocess.Popen(['python', __file__, 'server'], env=env)
        # Wait for the service to become available
        time.sleep(1)
        assert self.p.stdout == None
        assert self.p.stderr == None

        open("/tmp/dbus-test", "w").write("Hello, World!")

    def testHelloService(self):
        bus = dbus.SessionBus()
        helloservice = bus.get_object('test.helloservice', '/test/helloservice')
        hello = helloservice.get_dbus_method('hello', 'test.helloservice')
        cwd, cmd, fds, env, flags = ('/', ['ls'], {0:dbus.types.UnixFd(open('/tmp/dbus-test'))}, {'foo':'bar'}, 1)
        r = hello(cwd, cmd, fds, env, flags)
        assert r == "Hello, World!"

    def tearDown(self):
        # terminate() not supported in Python 2.5
        #self.p.terminate()
        os.kill(self.p.pid, 15)


if __name__ == '__main__':

    arg = ""
    if len(sys.argv) > 1:
        arg = sys.argv[1]

    if arg == "server":
        myservice = MyDBUSService()
        myservice.listen()

    else:
        unittest.main()

這很好用。

所以我想知道:如何從Python調用Flatpak開發服務?

為了調查我的代碼是否導致通過總線發送相同的消息,我啟動了dbus-monitor來檢查如果一個已知良好的客戶端發送該消息會發生什么。 我得到以下內容:

method call time=14743.5 sender=:1.6736 -> destination=org.freedesktop.Flatpak serial=8 path=/org/freedesktop/Flatpak/Development; interface=org.freedesktop.Flatpak.Development; member=HostCommand
   array of bytes "/" + \0
   array [
      array of bytes "ls" + \0
   ]
   array [
      dict entry(
         uint32 0
         file descriptor
               inode: 40
               type: char
      )
      dict entry(
         uint32 1
         file descriptor
               inode: 58091333
               type: fifo
      )
      dict entry(
         uint32 2
         file descriptor
               inode: 40
               type: char
      )
   ]
   array [
      dict entry(
         string "CLUTTER_IM_MODULE"
         string "xim"
      )
   ]
   uint32 1

然而,我自己的客戶產生了:

array of bytes "/"
array [
  array of bytes "ls"
]
array [
  dict entry(
     uint32 0
     file descriptor
           inode: 1866322
           type: file
  )
]
array [
  dict entry(
     string "FOO"
     string "bar"
  )
]
uint32 1

所以區別在於空字節。 將它添加到我的代碼時,它可以工作。 事實證明,有關於此問題的錯誤報告

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM