%PDF- %PDF-
| Direktori : /usr/lib/calibre/calibre/devices/usbms/ |
| Current File : //usr/lib/calibre/calibre/devices/usbms/hal.py |
#!/usr/bin/env python3
# License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
import time
from jeepney import (
DBusAddress, DBusErrorResponse, MessageType, Properties, new_method_call
)
from jeepney.io.blocking import open_dbus_connection
from calibre.constants import DEBUG
class HAL:
def __init__(self):
self.bus = open_dbus_connection('SYSTEM')
def send(self, msg):
reply = self.bus.send_and_get_reply(msg)
if reply.header.message_type is MessageType.error:
raise DBusErrorResponse(reply)
return reply.body[0]
def call(self, addr, method, sig='', *args):
if sig:
return self.send(new_method_call(addr, method, sig, args))
return self.send(new_method_call(addr, method))
def prop(self, addr, name):
return self.send(Properties(addr).get(name))
def addr(self, path, interface):
return DBusAddress(path, bus_name='org.freedesktop.Hal', interface=f'org.freedesktop.Hal.{interface}')
def get_volume(self, vpath):
vdevif = self.addr(vpath, 'Device')
if not self.prop(vdevif, 'block.is_volume') or self.prop(vdevif, 'volume.fsusage') != 'filesystem':
return
volif = self.addr(vpath, 'Volume')
pdevif = self.addr(self.prop(volif, 'info.parent'), 'Device')
return {'node': self.prop(pdevif, 'block.device'),
'dev': vdevif,
'vol': volif,
'label': self.prop(vdevif, 'volume.label')}
def get_volumes(self, d):
vols = []
manager = self.addr('/org/freedesktop/Hal/Manager', 'Manager')
paths = self.call(manager, 'FindDeviceStringMatch', 'ss', 'usb.serial', d.serial)
for path in paths:
objif = self.addr(path, 'Device')
# Extra paranoia...
try:
if d.idVendor == self.prop(objif, 'usb.vendor_id') and \
d.idProduct == self.prop(objif, 'usb.product_id') and \
d.manufacturer == self.prop(objif, 'usb.vendor') and \
d.product == self.prop(objif, 'usb.product') and \
d.serial == self.prop(objif, 'usb.serial'):
midpath = self.call(manager, 'FindDeviceStringMatch', 'ss', 'info.parent', path)
dpaths = self.call(manager, 'FindDeviceStringMatch', 'ss', 'storage.originating_device', path
) + self.call(manager, 'FindDeviceStringMatch', 'ss', 'storage.originating_device', midpath[0])
for dpath in dpaths:
try:
vpaths = self.call(manager, 'FindDeviceStringMatch', 'block.storage_device', dpath)
for vpath in vpaths:
try:
vol = self.get_volume(vpath)
if vol is not None:
vols.append(vol)
except DBusErrorResponse as e:
print(e)
continue
except DBusErrorResponse as e:
print(e)
continue
except DBusErrorResponse:
continue
vols.sort(key=lambda x: x['node'])
return vols
def get_mount_point(self, vol):
if not self.prop(vol['dev'], 'volume.is_mounted'):
fstype = self.prop(vol['dev'], 'volume.fstype')
self.call(vol['vol'], 'Mount', 'ssas', 'Calibre-'+vol['label'], fstype, [])
loops = 0
while not self.prop(vol['dev'], 'volume.is_mounted'):
time.sleep(1)
loops += 1
if loops > 100:
raise Exception("ERROR: Timeout waiting for mount to complete")
return self.prop(vol['dev'], 'volume.mount_point')
def mount_volumes(self, volumes):
mtd=0
ans = {
'_main_prefix': None, '_main_vol': None,
'_card_a_prefix': None, '_card_a_vol': None,
'_card_b_prefix': None, '_card_b_vol': None,
}
for vol in volumes:
try:
mp = self.get_mount_point(vol)
except Exception as e:
print("Failed to mount: {vol['label']}", e)
continue
# Mount Point becomes Mount Path
mp += '/'
if DEBUG:
print("FBSD: mounted", vol['label'], "on", mp)
if mtd == 0:
ans['_main_prefix'], ans['_main_vol'] = mp, vol['vol']
if DEBUG:
print("FBSD: main = ", mp)
elif mtd == 1:
ans['_card_a_prefix'], ans['_card_a_vol'] = mp, vol['vol']
if DEBUG:
print("FBSD: card a = ", mp)
elif mtd == 2:
ans['_card_b_prefix'], ans['_card_b_vol'] = mp, vol['vol']
if DEBUG:
print("FBSD: card b = ", mp)
break
mtd += 1
return mtd > 0, ans
def unmount(self, vol):
try:
self.call(vol, 'Unmount', 'as', [])
except DBusErrorResponse as e:
print('Unable to eject ', e)
def get_hal():
if not hasattr(get_hal, 'ans'):
get_hal.ans = HAL()
return get_hal.ans