通过来自 Python 的 dbus 函数调用传递文件描述符(也称为调用 flatpak 的 HostCommand)
Pass file descriptor via a dbus function call from Python (aka call flatpak's HostCommand)
我想调用 Flatpak 的 new Development DBus service to spawn a process on the host,而不是在沙盒中。
为了调用 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 代理对象上的函数之前,我需要包装我的类型吗?
为了测试我是否可以调用具有该签名的服务,我从 this question 中窃取了大部分内容并提出了以下内容:
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 "/" + [=10=]
array [
array of bytes "ls" + [=10=]
]
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
所以区别在于空字节。将其添加到我的代码时,它可以工作。原来这个问题有bug report
我想调用 Flatpak 的 new Development DBus service to spawn a process on the host,而不是在沙盒中。
为了调用 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 代理对象上的函数之前,我需要包装我的类型吗?
为了测试我是否可以调用具有该签名的服务,我从 this question 中窃取了大部分内容并提出了以下内容:
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 "/" + [=10=]
array [
array of bytes "ls" + [=10=]
]
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
所以区别在于空字节。将其添加到我的代码时,它可以工作。原来这个问题有bug report