%PDF- %PDF-
Direktori : /lib/calibre/calibre/devices/ |
Current File : //lib/calibre/calibre/devices/scanner.py |
__license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' ''' Device scanner that fetches list of devices on system ina platform dependent manner. ''' import sys, os, time from collections import namedtuple from threading import Lock from calibre import prints, as_unicode from calibre.constants import (iswindows, ismacos, islinux, isfreebsd, isnetbsd) osx_scanner = linux_scanner = freebsd_scanner = netbsd_scanner = None if iswindows: drive_ok_lock = Lock() def drive_is_ok(letter, max_tries=10, debug=False): from calibre_extensions import winutil with drive_ok_lock: for i in range(max_tries): try: winutil.get_disk_free_space(letter+':\\') return True except Exception as e: if i >= max_tries - 1 and debug: prints('Unable to get free space for drive:', letter) prints(as_unicode(e)) time.sleep(0.2) return False _USBDevice = namedtuple('USBDevice', 'vendor_id product_id bcd manufacturer product serial') class USBDevice(_USBDevice): def __new__(cls, *args, **kwargs): self = super().__new__(cls, *args) self.busnum = self.devnum = -1 return self def __repr__(self): return ('USBDevice(busnum=%s, devnum=%s, ' 'vendor_id=0x%04x, product_id=0x%04x, bcd=0x%04x, ' 'manufacturer=%s, product=%s, serial=%s)')%( self.busnum, self.devnum, self.vendor_id, self.product_id, self.bcd, self.manufacturer, self.product, self.serial) __str__ = __repr__ __unicode__ = __repr__ class LibUSBScanner: def __call__(self): if not hasattr(self, 'libusb'): from calibre_extensions import libusb self.libusb = libusb ans = set() seen = set() for fingerprint, ids in self.libusb.get_devices(): seen.add(fingerprint) man = ids.get('manufacturer', None) prod = ids.get('product', None) serial = ids.get('serial', None) dev = fingerprint[2:] + (man, prod, serial) dev = USBDevice(*dev) dev.busnum, dev.devnum = fingerprint[:2] ans.add(dev) extra = set(self.libusb.cache) - seen for x in extra: self.libusb.cache.pop(x, None) return ans def check_for_mem_leak(self): import gc from calibre.utils.mem import memory memory() for num in (1, 10, 100): start = memory() for i in range(num): self() for i in range(3): gc.collect() print('Mem consumption increased by:', memory() - start, 'MB', end=' ') print('after', num, 'repeats') class LinuxScanner: SYSFS_PATH = os.environ.get('SYSFS_PATH', '/sys') def __init__(self): self.base = os.path.join(self.SYSFS_PATH, 'subsystem', 'usb', 'devices') if not os.path.exists(self.base): self.base = os.path.join(self.SYSFS_PATH, 'bus', 'usb', 'devices') self.ok = os.path.exists(self.base) def __call__(self): ans = set() if not self.ok: raise RuntimeError('DeviceScanner requires the /sys filesystem to work.') def read(f): with lopen(f, 'rb') as s: return s.read().strip() for x in os.listdir(self.base): base = os.path.join(self.base, x) ven = os.path.join(base, 'idVendor') prod = os.path.join(base, 'idProduct') bcd = os.path.join(base, 'bcdDevice') man = os.path.join(base, 'manufacturer') serial = os.path.join(base, 'serial') prod_string = os.path.join(base, 'product') dev = [] try: # Ignore USB HUBs if read(os.path.join(base, 'bDeviceClass')) == b'09': continue except Exception: continue try: dev.append(int(b'0x'+read(ven), 16)) except Exception: continue try: dev.append(int(b'0x'+read(prod), 16)) except Exception: continue try: dev.append(int(b'0x'+read(bcd), 16)) except Exception: continue try: dev.append(read(man).decode('utf-8')) except Exception: dev.append('') try: dev.append(read(prod_string).decode('utf-8')) except Exception: dev.append('') try: dev.append(read(serial).decode('utf-8')) except Exception: dev.append('') dev = USBDevice(*dev) try: dev.busnum = int(read(os.path.join(base, 'busnum'))) except Exception: pass try: dev.devnum = int(read(os.path.join(base, 'devnum'))) except Exception: pass ans.add(dev) return ans if islinux: linux_scanner = LinuxScanner() libusb_scanner = LibUSBScanner() if isfreebsd: freebsd_scanner = libusb_scanner ''' NetBSD support currently not written yet ''' if isnetbsd: netbsd_scanner = None class DeviceScanner: def __init__(self, *args): if iswindows: from calibre.devices.winusb import scan_usb_devices as win_scanner self.scanner = (win_scanner if iswindows else osx_scanner if ismacos else freebsd_scanner if isfreebsd else netbsd_scanner if isnetbsd else linux_scanner if islinux else libusb_scanner) if self.scanner is None: self.scanner = libusb_scanner self.devices = [] def scan(self): '''Fetch list of connected USB devices from operating system''' self.devices = self.scanner() def is_device_connected(self, device, debug=False, only_presence=False): ''' If only_presence is True don't perform any expensive checks ''' return device.is_usb_connected(self.devices, debug=debug, only_presence=only_presence) def test_for_mem_leak(): from calibre.utils.mem import memory, gc_histogram, diff_hists import gc gc.disable() scanner = DeviceScanner() scanner.scan() memory() # load the psutil library for i in range(3): gc.collect() for reps in (1, 10, 100, 1000): for i in range(3): gc.collect() h1 = gc_histogram() startmem = memory() for i in range(reps): scanner.scan() for i in range(3): gc.collect() usedmem = memory(startmem) prints('Memory used in %d repetitions of scan(): %.5f KB'%(reps, 1024*usedmem)) prints('Differences in python object counts:') diff_hists(h1, gc_histogram()) prints() def main(args=sys.argv): test_for_mem_leak() return 0 if __name__ == '__main__': sys.exit(main())