Restore device support on FreeBSD. Fixes #924503 (Patches for Devices on FreeBSD)

This commit is contained in:
Kovid Goyal 2012-02-01 11:54:58 +05:30
parent 205d323bf7
commit cecff25eb3
2 changed files with 194 additions and 110 deletions

View File

@ -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):

View File

@ -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) try:
devmatch=subprocess.Popen(["grep", dvc], stdin=p.stdout, stdout=subprocess.PIPE).communicate()[0] if d.idVendor == objif.GetProperty('usb.vendor_id') and \
p.stdout.close() d.idProduct == objif.GetProperty('usb.product_id') and \
if devmatch: d.manufacturer == objif.GetProperty('usb.vendor') and \
#print "Checking ", devmatch d.product == objif.GetProperty('usb.product') and \
# ... see if we can get a S/N from the actual device node d.serial == objif.GetProperty('usb.serial'):
sn=subprocess.Popen(["camcontrol", "inquiry", dvc, "-S"], stdout=subprocess.PIPE).communicate()[0] dpaths = manager.FindDeviceStringMatch('storage.originating_device', path)
sn=sn[0:-1] # drop the trailing newline for dpath in dpaths:
#print "S/N = ", sn devif = dbus.Interface(bus.get_object('org.freedesktop.Hal', dpath), 'org.freedesktop.Hal.Device')
if sn and d.match_serial(sn): try:
# we have a matching s/n, record this device node vpaths = manager.FindDeviceStringMatch('block.storage_device', dpath)
#print "match found: ", dvc for vpath in vpaths:
devs[di]=dvc try:
di += 1 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
# sort the list of devices def ocmp(x,y):
for i in range(1,ndevs+1): if x['node'] < y['node']:
for j in reversed(range(1,i)): return -1
if devs[j-1] > devs[j]: if x['node'] > y['node']:
x=devs[j-1] return 1
devs[j-1]=devs[j] return 0
devs[j]=x
#print devs vols.sort(cmp=ocmp)
if verbose:
print "FBSD: ", vols
# now we need to see if any of these have slices/partitions
mtd=0 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 vol in vols:
for dev in devs[i].split(): mp = ''
mp='/media/'+label+'-'+dev if vol['dev'].GetProperty('volume.is_mounted'):
mmp = mp mp = vol['dev'].GetProperty('volume.mount_point')
if mmp.endswith('/'): else:
mmp = mmp[:-1] if verbose:
#print "trying ", dev, "on", mp print "FBSD: trying ", vol['label'], "on", 'Calibre-'+labels[i]
try: try:
p = subprocess.Popen(cmd + ["/dev/"+dev, mmp]) vol['vol'].Mount('Calibre-'+vol['label'],
except OSError: vol['dev'].GetProperty('volume.fstype'), [])
raise DeviceError(_('Could not find mount helper: %s.')%cmd[0]) loops = 0
while p.poll() is None: while not vol['dev'].GetProperty('volume.is_mounted'):
time.sleep(0.1) 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
if p.returncode == 0: # Mount Point becomes Mount Path
#print " mounted", dev mp += '/'
if i == 0:
self._main_prefix = mp
self._main_dev = "/dev/"+dev
#print "main = ", self._main_dev, self._main_prefix
if i == 1:
self._card_a_prefix = mp
self._card_a_dev = "/dev/"+dev
#print "card a = ", self._card_a_dev, self._card_a_prefix
if i == 2:
self._card_b_prefix = mp
self._card_b_dev = "/dev/"+dev
#print "card b = ", self._card_b_dev, self._card_b_prefix
mtd += 1 if verbose:
break 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: 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: