Port freebsd device open/eject code to use jeepney

Note that I have no way to test this code
This commit is contained in:
Kovid Goyal 2021-06-27 16:01:10 +05:30
parent 5319cacd41
commit 54e510a415
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 164 additions and 132 deletions

View File

@ -12,18 +12,22 @@ intended to be subclassed with the relevant parts implemented for a particular
device. This class handles device detection.
'''
import os, subprocess, time, re, sys, glob
from itertools import repeat
import glob
import os
import re
import subprocess
import sys
import time
from collections import namedtuple
from itertools import repeat
from calibre import prints
from calibre.constants import DEBUG
from calibre.devices.interface import DevicePlugin
from calibre.constants import DEBUG, isfreebsd, islinux, ismacos, iswindows
from calibre.devices.errors import DeviceError
from calibre.devices.interface import DevicePlugin
from calibre.devices.usbms.deviceconfig import DeviceConfig
from calibre.constants import iswindows, islinux, ismacos, isfreebsd
from calibre.utils.filenames import ascii_filename as sanitize
from polyglot.builtins import iteritems, string_or_bytes, map
from polyglot.builtins import iteritems, map, string_or_bytes
if ismacos:
osx_sanitize_name_pat = re.compile(r'[.-]')
@ -649,7 +653,6 @@ class Device(DeviceConfig, DevicePlugin):
# 4. when finished, we have a list of mount points and associated dbus nodes
#
def open_freebsd(self):
import dbus
# There should be some way to access the -v arg...
verbose = False
@ -660,107 +663,17 @@ class Device(DeviceConfig, DevicePlugin):
if not d.serial:
raise DeviceError("Device has no S/N. Can't continue")
return False
vols=[]
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object('org.freedesktop.Hal',
'/org/freedesktop/Hal/Manager'), 'org.freedesktop.Hal.Manager')
paths = manager.FindDeviceStringMatch('usb.serial',d.serial)
for path in paths:
objif = dbus.Interface(bus.get_object('org.freedesktop.Hal', path), 'org.freedesktop.Hal.Device')
# Extra paranoia...
try:
if d.idVendor == objif.GetProperty('usb.vendor_id') and \
d.idProduct == objif.GetProperty('usb.product_id') and \
d.manufacturer == objif.GetProperty('usb.vendor') and \
d.product == objif.GetProperty('usb.product') and \
d.serial == objif.GetProperty('usb.serial'):
midpath = manager.FindDeviceStringMatch('info.parent', path)
dpaths = manager.FindDeviceStringMatch(
'storage.originating_device', path) + manager.FindDeviceStringMatch('storage.originating_device', midpath[0])
for dpath in dpaths:
# devif = dbus.Interface(bus.get_object('org.freedesktop.Hal', dpath), 'org.freedesktop.Hal.Device')
try:
vpaths = manager.FindDeviceStringMatch('block.storage_device', dpath)
for vpath in vpaths:
try:
vdevif = dbus.Interface(bus.get_object('org.freedesktop.Hal', vpath), 'org.freedesktop.Hal.Device')
if not vdevif.GetProperty('block.is_volume'):
continue
if vdevif.GetProperty('volume.fsusage') != 'filesystem':
continue
volif = dbus.Interface(bus.get_object('org.freedesktop.Hal', vpath), 'org.freedesktop.Hal.Device.Volume')
pdevif = dbus.Interface(bus.get_object('org.freedesktop.Hal', vdevif.GetProperty('info.parent')),
'org.freedesktop.Hal.Device')
vol = {'node': pdevif.GetProperty('block.device'),
'dev': vdevif,
'vol': volif,
'label': vdevif.GetProperty('volume.label')}
vols.append(vol)
except dbus.exceptions.DBusException as e:
print(e)
continue
except dbus.exceptions.DBusException as e:
print(e)
continue
except dbus.exceptions.DBusException:
continue
vols.sort(key=lambda x: x['node'])
from .hal import get_hal
hal = get_hal()
vols = hal.get_volumes(d)
if verbose:
print("FBSD: ", vols)
mtd=0
for vol in vols:
mp = ''
if vol['dev'].GetProperty('volume.is_mounted'):
mp = vol['dev'].GetProperty('volume.mount_point')
else:
try:
vol['vol'].Mount('Calibre-'+vol['label'],
vol['dev'].GetProperty('volume.fstype'), [])
loops = 0
while not vol['dev'].GetProperty('volume.is_mounted'):
time.sleep(1)
loops += 1
if loops > 100:
print("ERROR: Timeout waiting for mount to complete")
continue
mp = vol['dev'].GetProperty('volume.mount_point')
except dbus.exceptions.DBusException as e:
print("Failed to mount ", e)
continue
# Mount Point becomes Mount Path
mp += '/'
if verbose:
print("FBSD: mounted", vol['label'], "on", mp)
if mtd == 0:
self._main_prefix = mp
self._main_vol = vol['vol']
if verbose:
print("FBSD: main = ", self._main_prefix)
if mtd == 1:
self._card_a_prefix = mp
self._card_a_vol = vol['vol']
if verbose:
print("FBSD: card a = ", self._card_a_prefix)
if mtd == 2:
self._card_b_prefix = mp
self._card_b_vol = vol['vol']
if verbose:
print("FBSD: card b = ", self._card_b_prefix)
# Note that mtd is used as a bool... not incrementing is fine.
break
mtd += 1
if mtd > 0:
return True
raise DeviceError(_('Unable to mount the device'))
ok, mv = hal.mount_volumes(vols)
if not ok:
raise DeviceError(_('Unable to mount the device'))
for k, v in mv.items():
setattr(self, k, v)
#
# ------------------------------------------------------
@ -770,37 +683,18 @@ class Device(DeviceConfig, DevicePlugin):
# mounted filesystems, using the stored volume object
#
def eject_freebsd(self):
import dbus
# There should be some way to access the -v arg...
verbose = False
from .hal import get_hal
hal = get_hal()
if self._main_prefix:
if verbose:
print("FBSD: umount main:", self._main_prefix)
try:
self._main_vol.Unmount([])
except dbus.exceptions.DBusException as e:
print('Unable to eject ', e)
hal.unmount(self._main_vol)
if self._card_a_prefix:
if verbose:
print("FBSD: umount card a:", self._card_a_prefix)
try:
self._card_a_vol.Unmount([])
except dbus.exceptions.DBusException as e:
print('Unable to eject ', e)
hal.unmount(self._card_a_vol)
if self._card_b_prefix:
if verbose:
print("FBSD: umount card b:", self._card_b_prefix)
try:
self._card_b_vol.Unmount([])
except dbus.exceptions.DBusException as e:
print('Unable to eject ', e)
hal.unmount(self._card_b_vol)
self._main_prefix = None
self._card_a_prefix = None
self._card_b_prefix = None
self._main_prefix = self._main_vol = None
self._card_a_prefix = self._card_a_vol = None
self._card_b_prefix = self._card_b_vol = None
# ------------------------------------------------------
def open(self, connected_device, library_uuid):

View File

@ -0,0 +1,138 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# 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