mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Restore device support on FreeBSD. Fixes #924503 (Patches for Devices on FreeBSD)
This commit is contained in:
parent
205d323bf7
commit
cecff25eb3
@ -8,7 +8,7 @@ manner.
|
|||||||
import sys, os, re
|
import sys, os, re
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
|
|
||||||
from calibre.constants import iswindows, isosx, plugins, islinux
|
from calibre.constants import iswindows, isosx, plugins, islinux, isfreebsd
|
||||||
|
|
||||||
osx_scanner = win_scanner = linux_scanner = None
|
osx_scanner = win_scanner = linux_scanner = None
|
||||||
|
|
||||||
@ -155,17 +155,80 @@ class LinuxScanner(object):
|
|||||||
ans.add(tuple(dev))
|
ans.add(tuple(dev))
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
class FreeBSDScanner(object):
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
ans = set([])
|
||||||
|
import dbus
|
||||||
|
devs = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
bus = dbus.SystemBus()
|
||||||
|
manager = dbus.Interface(bus.get_object('org.freedesktop.Hal',
|
||||||
|
'/org/freedesktop/Hal/Manager'), 'org.freedesktop.Hal.Manager')
|
||||||
|
paths = manager.FindDeviceStringMatch('freebsd.driver','da')
|
||||||
|
for path in paths:
|
||||||
|
obj = bus.get_object('org.freedesktop.Hal', path)
|
||||||
|
objif = dbus.Interface(obj, 'org.freedesktop.Hal.Device')
|
||||||
|
devif = objif
|
||||||
|
parentdriver = None
|
||||||
|
while parentdriver != 'umass':
|
||||||
|
try:
|
||||||
|
obj = bus.get_object('org.freedesktop.Hal',
|
||||||
|
objif.GetProperty('info.parent'))
|
||||||
|
objif = dbus.Interface(obj, 'org.freedesktop.Hal.Device')
|
||||||
|
try:
|
||||||
|
parentdriver = objif.GetProperty('freebsd.driver')
|
||||||
|
except dbus.exceptions.DBusException, e:
|
||||||
|
continue
|
||||||
|
except dbus.exceptions.DBusException, e:
|
||||||
|
break
|
||||||
|
if parentdriver != 'umass':
|
||||||
|
continue
|
||||||
|
dev = []
|
||||||
|
try:
|
||||||
|
dev.append(objif.GetProperty('usb.vendor_id'))
|
||||||
|
dev.append(objif.GetProperty('usb.product_id'))
|
||||||
|
dev.append(objif.GetProperty('usb.device_revision_bcd'))
|
||||||
|
except dbus.exceptions.DBusException, e:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
dev.append(objif.GetProperty('info.vendor'))
|
||||||
|
except:
|
||||||
|
dev.append('')
|
||||||
|
try:
|
||||||
|
dev.append(objif.GetProperty('info.product'))
|
||||||
|
except:
|
||||||
|
dev.append('')
|
||||||
|
try:
|
||||||
|
dev.append(objif.GetProperty('usb.serial'))
|
||||||
|
except:
|
||||||
|
dev.append('')
|
||||||
|
dev.append(path)
|
||||||
|
ans.add(tuple(dev))
|
||||||
|
except dbus.exceptions.DBusException, e:
|
||||||
|
print >>sys.stderr, "Execution failed:", e
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
linux_scanner = None
|
linux_scanner = None
|
||||||
|
|
||||||
if islinux:
|
if islinux:
|
||||||
linux_scanner = LinuxScanner()
|
linux_scanner = LinuxScanner()
|
||||||
|
|
||||||
|
freebsd_scanner = None
|
||||||
|
|
||||||
|
if isfreebsd:
|
||||||
|
freebsd_scanner = FreeBSDScanner()
|
||||||
|
|
||||||
|
|
||||||
class DeviceScanner(object):
|
class DeviceScanner(object):
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
if isosx and osx_scanner is None:
|
if isosx and osx_scanner is None:
|
||||||
raise RuntimeError('The Python extension usbobserver must be available on OS X.')
|
raise RuntimeError('The Python extension usbobserver must be available on OS X.')
|
||||||
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
|
self.scanner = win_scanner if iswindows else osx_scanner if isosx else freebsd_scanner if isfreebsd else linux_scanner
|
||||||
self.devices = []
|
self.devices = []
|
||||||
|
|
||||||
def scan(self):
|
def scan(self):
|
||||||
|
@ -677,19 +677,21 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
self._card_a_prefix = self._card_b_prefix
|
self._card_a_prefix = self._card_b_prefix
|
||||||
self._card_b_prefix = None
|
self._card_b_prefix = None
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
#
|
#
|
||||||
# open for FreeBSD
|
# open for FreeBSD
|
||||||
# find the device node or nodes that match the S/N we already have from the scanner
|
# find the device node or nodes that match the S/N we already have from the scanner
|
||||||
# and attempt to mount each one
|
# and attempt to mount each one
|
||||||
# 1. get list of disk devices from sysctl
|
# 1. get list of devices in /dev with matching s/n etc.
|
||||||
# 2. compare that list with the one from camcontrol
|
# 2. get list of volumes associated with each
|
||||||
# 3. and see if it has a matching s/n
|
# 3. attempt to mount each one using Hal
|
||||||
# 6. find any partitions/slices associated with each node
|
# 4. when finished, we have a list of mount points and associated dbus nodes
|
||||||
# 7. attempt to mount, using calibre-mount-helper, each one
|
|
||||||
# 8. when finished, we have a list of mount points and associated device nodes
|
|
||||||
#
|
#
|
||||||
def open_freebsd(self):
|
def open_freebsd(self):
|
||||||
|
import dbus
|
||||||
|
# There should be some way to access the -v arg...
|
||||||
|
verbose = False
|
||||||
|
|
||||||
# this gives us access to the S/N, etc. of the reader that the scanner has found
|
# this gives us access to the S/N, etc. of the reader that the scanner has found
|
||||||
# and the match routines for some of that data, like s/n, vendor ID, etc.
|
# and the match routines for some of that data, like s/n, vendor ID, etc.
|
||||||
@ -699,128 +701,148 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
raise DeviceError("Device has no S/N. Can't continue")
|
raise DeviceError("Device has no S/N. Can't continue")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
devs={}
|
vols=[]
|
||||||
di=0
|
|
||||||
ndevs=4 # number of possible devices per reader (main, carda, cardb, launcher)
|
|
||||||
|
|
||||||
#get list of disk devices
|
bus = dbus.SystemBus()
|
||||||
p=subprocess.Popen(["sysctl", "kern.disks"], stdout=subprocess.PIPE)
|
manager = dbus.Interface(bus.get_object('org.freedesktop.Hal',
|
||||||
kdsks=subprocess.Popen(["sed", "s/kern.disks: //"], stdin=p.stdout, stdout=subprocess.PIPE).communicate()[0]
|
'/org/freedesktop/Hal/Manager'), 'org.freedesktop.Hal.Manager')
|
||||||
p.stdout.close()
|
paths = manager.FindDeviceStringMatch('usb.serial',d.serial)
|
||||||
#print kdsks
|
for path in paths:
|
||||||
for dvc in kdsks.split():
|
objif = dbus.Interface(bus.get_object('org.freedesktop.Hal', path), 'org.freedesktop.Hal.Device')
|
||||||
# for each one that's also in the list of cam devices ...
|
# Extra paranoia...
|
||||||
p=subprocess.Popen(["camcontrol", "devlist"], stdout=subprocess.PIPE)
|
|
||||||
devmatch=subprocess.Popen(["grep", dvc], stdin=p.stdout, stdout=subprocess.PIPE).communicate()[0]
|
|
||||||
p.stdout.close()
|
|
||||||
if devmatch:
|
|
||||||
#print "Checking ", devmatch
|
|
||||||
# ... see if we can get a S/N from the actual device node
|
|
||||||
sn=subprocess.Popen(["camcontrol", "inquiry", dvc, "-S"], stdout=subprocess.PIPE).communicate()[0]
|
|
||||||
sn=sn[0:-1] # drop the trailing newline
|
|
||||||
#print "S/N = ", sn
|
|
||||||
if sn and d.match_serial(sn):
|
|
||||||
# we have a matching s/n, record this device node
|
|
||||||
#print "match found: ", dvc
|
|
||||||
devs[di]=dvc
|
|
||||||
di += 1
|
|
||||||
|
|
||||||
# sort the list of devices
|
|
||||||
for i in range(1,ndevs+1):
|
|
||||||
for j in reversed(range(1,i)):
|
|
||||||
if devs[j-1] > devs[j]:
|
|
||||||
x=devs[j-1]
|
|
||||||
devs[j-1]=devs[j]
|
|
||||||
devs[j]=x
|
|
||||||
#print devs
|
|
||||||
|
|
||||||
# now we need to see if any of these have slices/partitions
|
|
||||||
mtd=0
|
|
||||||
label="READER" # could use something more unique, like S/N or productID...
|
|
||||||
cmd = '/usr/local/bin/calibre-mount-helper'
|
|
||||||
cmd = [cmd, 'mount']
|
|
||||||
for i in range(0,ndevs):
|
|
||||||
cmd2="ls /dev/"+devs[i]+"*"
|
|
||||||
p=subprocess.Popen(cmd2, shell=True, stdout=subprocess.PIPE)
|
|
||||||
devs[i]=subprocess.Popen(["cut", "-d", "/", "-f" "3"], stdin=p.stdout, stdout=subprocess.PIPE).communicate()[0]
|
|
||||||
p.stdout.close()
|
|
||||||
|
|
||||||
# try all the nodes to see what we can mount
|
|
||||||
for dev in devs[i].split():
|
|
||||||
mp='/media/'+label+'-'+dev
|
|
||||||
mmp = mp
|
|
||||||
if mmp.endswith('/'):
|
|
||||||
mmp = mmp[:-1]
|
|
||||||
#print "trying ", dev, "on", mp
|
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(cmd + ["/dev/"+dev, mmp])
|
if d.idVendor == objif.GetProperty('usb.vendor_id') and \
|
||||||
except OSError:
|
d.idProduct == objif.GetProperty('usb.product_id') and \
|
||||||
raise DeviceError(_('Could not find mount helper: %s.')%cmd[0])
|
d.manufacturer == objif.GetProperty('usb.vendor') and \
|
||||||
while p.poll() is None:
|
d.product == objif.GetProperty('usb.product') and \
|
||||||
time.sleep(0.1)
|
d.serial == objif.GetProperty('usb.serial'):
|
||||||
|
dpaths = manager.FindDeviceStringMatch('storage.originating_device', path)
|
||||||
|
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, e:
|
||||||
|
print e
|
||||||
|
continue
|
||||||
|
except dbus.exceptions.DBusException, e:
|
||||||
|
print e
|
||||||
|
continue
|
||||||
|
except dbus.exceptions.DBusException, e:
|
||||||
|
continue
|
||||||
|
|
||||||
if p.returncode == 0:
|
def ocmp(x,y):
|
||||||
#print " mounted", dev
|
if x['node'] < y['node']:
|
||||||
if i == 0:
|
return -1
|
||||||
|
if x['node'] > y['node']:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
vols.sort(cmp=ocmp)
|
||||||
|
|
||||||
|
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:
|
||||||
|
if verbose:
|
||||||
|
print "FBSD: trying ", vol['label'], "on", 'Calibre-'+labels[i]
|
||||||
|
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, 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_prefix = mp
|
||||||
self._main_dev = "/dev/"+dev
|
self._main_vol = vol['vol']
|
||||||
#print "main = ", self._main_dev, self._main_prefix
|
if verbose:
|
||||||
if i == 1:
|
print "FBSD: main = ", self._main_prefix
|
||||||
|
if mtd == 1:
|
||||||
self._card_a_prefix = mp
|
self._card_a_prefix = mp
|
||||||
self._card_a_dev = "/dev/"+dev
|
self._card_a_vol = vol['vol']
|
||||||
#print "card a = ", self._card_a_dev, self._card_a_prefix
|
if verbose:
|
||||||
if i == 2:
|
print "FBSD: card a = ", self._card_a_prefix
|
||||||
|
if mtd == 2:
|
||||||
self._card_b_prefix = mp
|
self._card_b_prefix = mp
|
||||||
self._card_b_dev = "/dev/"+dev
|
self._card_b_vol = vol['vol']
|
||||||
#print "card b = ", self._card_b_dev, self._card_b_prefix
|
if verbose:
|
||||||
|
print "FBSD: card b = ", self._card_b_prefix
|
||||||
mtd += 1
|
# Note that mtd is used as a bool... not incrementing is fine.
|
||||||
break
|
break
|
||||||
|
mtd += 1
|
||||||
|
|
||||||
if mtd > 0:
|
if mtd > 0:
|
||||||
return True
|
return True
|
||||||
else :
|
raise DeviceError(_('Unable to mount the device'))
|
||||||
return False
|
|
||||||
#
|
#
|
||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
#
|
#
|
||||||
# this one is pretty simple:
|
# this one is pretty simple:
|
||||||
# just umount each of the previously
|
# just umount each of the previously
|
||||||
# mounted filesystems, using the mount helper
|
# mounted filesystems, using the stored volume object
|
||||||
#
|
#
|
||||||
def eject_freebsd(self):
|
def eject_freebsd(self):
|
||||||
cmd = '/usr/local/bin/calibre-mount-helper'
|
import dbus
|
||||||
cmd = [cmd, 'eject']
|
# There should be some way to access the -v arg...
|
||||||
|
verbose = False
|
||||||
|
|
||||||
if self._main_prefix:
|
if self._main_prefix:
|
||||||
#print "umount main:", cmd, self._main_dev, self._main_prefix
|
if verbose:
|
||||||
|
print "FBSD: umount main:", self._main_prefix
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(cmd + [self._main_dev, self._main_prefix])
|
self._main_vol.Unmount([])
|
||||||
except OSError:
|
except dbus.exceptions.DBusException, e:
|
||||||
raise DeviceError(
|
print 'Unable to eject ', e
|
||||||
_('Could not find mount helper: %s.')%cmd[0])
|
|
||||||
while p.poll() is None:
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
if self._card_a_prefix:
|
if self._card_a_prefix:
|
||||||
#print "umount card a:", cmd, self._card_a_dev, self._card_a_prefix
|
if verbose:
|
||||||
|
print "FBSD: umount card a:", self._card_a_prefix
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(cmd + [self._card_a_dev, self._card_a_prefix])
|
self._card_a_vol.Unmount([])
|
||||||
except OSError:
|
except dbus.exceptions.DBusException, e:
|
||||||
raise DeviceError(
|
print 'Unable to eject ', e
|
||||||
_('Could not find mount helper: %s.')%cmd[0])
|
|
||||||
while p.poll() is None:
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
if self._card_b_prefix:
|
if self._card_b_prefix:
|
||||||
#print "umount card b:", cmd, self._card_b_dev, self._card_b_prefix
|
if verbose:
|
||||||
|
print "FBSD: umount card b:", self._card_b_prefix
|
||||||
try:
|
try:
|
||||||
p = subprocess.Popen(cmd + [self._card_b_dev, self._card_b_prefix])
|
self._card_b_vol.Unmount([])
|
||||||
except OSError:
|
except dbus.exceptions.DBusException, e:
|
||||||
raise DeviceError(
|
print 'Unable to eject ', e
|
||||||
_('Could not find mount helper: %s.')%cmd[0])
|
|
||||||
while p.poll() is None:
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
self._main_prefix = None
|
self._main_prefix = None
|
||||||
self._card_a_prefix = None
|
self._card_a_prefix = None
|
||||||
@ -839,11 +861,10 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
time.sleep(7)
|
time.sleep(7)
|
||||||
self.open_linux()
|
self.open_linux()
|
||||||
if isfreebsd:
|
if isfreebsd:
|
||||||
self._main_dev = self._card_a_dev = self._card_b_dev = None
|
self._main_vol = self._card_a_vol = self._card_b_vol = None
|
||||||
try:
|
try:
|
||||||
self.open_freebsd()
|
self.open_freebsd()
|
||||||
except DeviceError:
|
except DeviceError:
|
||||||
subprocess.Popen(["camcontrol", "rescan", "all"])
|
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
self.open_freebsd()
|
self.open_freebsd()
|
||||||
if iswindows:
|
if iswindows:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user