Esempio n. 1
0
    def open_linux(self):
        def mount(node, type):
            mp = self.node_mountpoint(node)
            if mp is not None:
                return mp, 0

            def do_mount(node):
                try:
                    from calibre.devices.udisks import mount
                    mount(node)
                    return 0
                except:
                    print('Udisks mount call failed:')
                    import traceback
                    traceback.print_exc()
                    return 1

            ret = do_mount(node)
            if ret != 0:
                return None, ret
            return self.node_mountpoint(node) + '/', 0

        main, carda, cardb = self.find_device_nodes()
        if main is None:
            raise DeviceError(
                _('Unable to detect the %s disk drive. Either '
                  'the device has already been ejected, or your '
                  'kernel is exporting a deprecated version of SYSFS.') %
                self.__class__.__name__)
        if is_debugging():
            print('\nFound device nodes:', main, carda, cardb)

        self._linux_mount_map = {}
        mp, ret = mount(main, 'main')
        if mp is None:
            raise DeviceError(
                _('Unable to mount main memory (Error code: %d)') % ret)
        if not mp.endswith('/'):
            mp += '/'
        self._linux_mount_map[main] = mp
        self._main_prefix = mp
        self._linux_main_device_node = main
        cards = [(carda, '_card_a_prefix', 'carda'),
                 (cardb, '_card_b_prefix', 'cardb')]
        for card, prefix, typ in cards:
            if card is None:
                continue
            mp, ret = mount(card, typ)
            if mp is None:
                print('Unable to mount card (Error code: %d)' % ret,
                      file=sys.stderr)
            else:
                if not mp.endswith('/'):
                    mp += '/'
                setattr(self, prefix, mp)
                self._linux_mount_map[card] = mp

        self.filter_read_only_mount_points()
Esempio n. 2
0
    def open_windows(self):
        from calibre.devices.scanner import drive_is_ok
        from calibre.devices.winusb import get_drive_letters_for_device
        usbdev = self.device_being_opened
        debug = is_debugging() or getattr(self, 'do_device_debug', False)
        try:
            dlmap = get_drive_letters_for_device(usbdev, debug=debug)
        except Exception:
            dlmap = {}

        if not dlmap.get('drive_letters'):
            time.sleep(7)
            dlmap = get_drive_letters_for_device(usbdev, debug=debug)

        if debug:
            from pprint import pformat
            prints(f'Drive letters for {usbdev}')
            prints(pformat(dlmap))

        filtered = set()
        for dl in dlmap['drive_letters']:
            pnp_id = dlmap['pnp_id_map'][dl].upper()
            if dl in dlmap['readonly_drives']:
                filtered.add(dl)
                if debug:
                    prints('Ignoring the drive %s as it is readonly' % dl)
            elif self.windows_filter_pnp_id(pnp_id):
                filtered.add(dl)
                if debug:
                    prints(
                        f'Ignoring the drive {dl} because of a PNP filter on {pnp_id}'
                    )
            elif not drive_is_ok(dl, debug=debug):
                filtered.add(dl)
                if debug:
                    prints(
                        'Ignoring the drive %s because failed to get free space for it'
                        % dl)
        dlmap['drive_letters'] = [
            dl for dl in dlmap['drive_letters'] if dl not in filtered
        ]

        if not dlmap['drive_letters']:
            raise DeviceError(
                _('Unable to detect any disk drives for the device: %s. Try rebooting'
                  ) % self.get_gui_name())

        drives = {}

        for drive_letter, which in zip(dlmap['drive_letters'],
                                       'main carda cardb'.split()):
            drives[which] = drive_letter + ':\\'

        drives = self.windows_sort_drives(drives)
        self._main_prefix = drives.get('main')
        self._card_a_prefix = drives.get('carda', None)
        self._card_b_prefix = drives.get('cardb', None)
Esempio n. 3
0
    def open_osx(self):
        from calibre_extensions.usbobserver import get_mounted_filesystems
        bsd_drives = self.osx_bsd_names()
        drives = self.osx_sort_names(bsd_drives.copy())
        mount_map = get_mounted_filesystems()
        # macOS 13 Ventura uses a weird scheme for mounted FAT devices of the
        # form fat://basename_of_bsd_name/basename_of_mountpoint
        # see https://www.mobileread.com/forums/showthread.php?t=347294
        for dev_node in tuple(mount_map):
            if ':' in dev_node and '//' in dev_node:
                val = mount_map[dev_node]
                dev_node = dev_node.split('/')[-2]
                dev_node = f'/dev/{dev_node}'
                if dev_node not in mount_map:
                    mount_map[dev_node] = val
        drives = {k: mount_map.get(v) for k, v in iteritems(drives)}
        if is_debugging():
            print()
            from pprint import pprint
            pprint({
                'bsd_drives': bsd_drives,
                'mount_map': mount_map,
                'drives': drives
            })
        if drives.get('carda') is None and drives.get('cardb') is not None:
            drives['carda'] = drives.pop('cardb')
        if drives.get('main') is None and drives.get('carda') is not None:
            drives['main'] = drives.pop('carda')
        if drives.get('carda') is None and drives.get('cardb') is not None:
            drives['carda'] = drives.pop('cardb')
        if drives.get('main') is None:
            raise DeviceError(
                _('Unable to detect the %s mount point. Try rebooting.') %
                self.__class__.__name__)
        pat = self.OSX_MAIN_MEM_VOL_PAT
        if pat is not None and len(drives) > 1 and 'main' in drives:
            if pat.search(drives['main']) is None:
                main = drives['main']
                for x in ('carda', 'cardb'):
                    if x in drives and pat.search(drives[x]):
                        drives['main'] = drives.pop(x)
                        drives[x] = main
                        break

        self._main_prefix = drives['main'] + os.sep

        def get_card_prefix(c):
            ans = drives.get(c, None)
            if ans is not None:
                ans += os.sep
            return ans

        self._card_a_prefix = get_card_prefix('carda')
        self._card_b_prefix = get_card_prefix('cardb')
Esempio n. 4
0
 def is_readonly(mp):
     if mp is None:
         return True
     path = os.path.join(mp, 'calibre_readonly_test')
     ro = True
     try:
         with lopen(path, 'wb'):
             ro = False
     except:
         pass
     else:
         try:
             os.remove(path)
         except:
             pass
     if is_debugging() and ro:
         print('\nThe mountpoint', mp, 'is readonly, ignoring it')
     return ro
Esempio n. 5
0
    def find_device_nodes(self, detected_device=None):
        def walk(base):
            base = os.path.abspath(os.path.realpath(base))
            for x in os.listdir(base):
                p = os.path.join(base, x)
                if os.path.islink(p) or not os.access(p, os.R_OK):
                    continue
                isfile = os.path.isfile(p)
                yield p, isfile
                if not isfile:
                    yield from walk(p)

        def raw2num(raw):
            raw = raw.lower()
            if not raw.startswith('0x'):
                raw = '0x' + raw
            return int(raw, 16)

        # Find device node based on vendor, product and bcd
        d, j = os.path.dirname, os.path.join
        usb_dir = None

        if detected_device is None:
            detected_device = self.detected_device

        def test(val, attr):
            q = getattr(detected_device, attr)
            return q == val

        def getnum(usb_dir):
            def rc(q):
                with open(j(usb_dir, q), 'rb') as f:
                    return raw2num(f.read().decode('utf-8'))

            return rc

        for x, isfile in walk('/sys/devices'):
            if isfile and x.endswith('idVendor'):
                usb_dir = d(x)
                for y in ('idProduct', 'idVendor', 'bcdDevice'):
                    if not os.access(j(usb_dir, y), os.R_OK):
                        usb_dir = None
                        break
                if usb_dir is None:
                    continue
                ven, prod, bcd = map(getnum(usb_dir),
                                     ('idVendor', 'idProduct', 'bcdDevice'))
                if not (test(ven, 'idVendor') and test(prod, 'idProduct')
                        and test(bcd, 'bcdDevice')):
                    usb_dir = None
                    continue
                else:
                    break

        if usb_dir is None:
            raise DeviceError(
                _('Unable to detect the %s disk drive.') %
                self.__class__.__name__)

        devnodes, ok = [], {}
        for x, isfile in walk(usb_dir):
            if not isfile and '/block/' in x:
                parts = x.split('/')
                idx = parts.index('block')
                if idx == len(parts) - 2:
                    sz = j(x, 'size')
                    node = parts[idx + 1]
                    try:
                        with open(sz, 'rb') as szf:
                            exists = int(szf.read().decode('utf-8')) > 0
                        if exists:
                            node = self.find_largest_partition(x)
                            ok[node] = True
                        else:
                            ok[node] = False
                    except:
                        ok[node] = False
                    if is_debugging() and not ok[node]:
                        print(
                            f'\nIgnoring the node: {node} as could not read size from: {sz}'
                        )

                    devnodes.append(node)

        devnodes += list(repeat(None, 3))
        ans = ['/dev/' + x if ok.get(x, False) else None for x in devnodes]
        ans.sort(key=lambda x: x[5:] if x else 'zzzzz')
        return self.linux_swap_drives(ans[:3])
Esempio n. 6
0
def debug_print(*args, **kw):
    base_time = getattr(debug_print, 'base_time', None)
    if base_time is None:
        debug_print.base_time = base_time = time.monotonic()
    if is_debugging():
        prints('DEBUG: %6.1f'%(time.monotonic()-base_time), *args, **kw)
Esempio n. 7
0
def debug(ioreg_to_tmp=False, buf=None, plugins=None, disabled_plugins=None):
    '''
    If plugins is None, then this method calls startup and shutdown on the
    device plugins. So if you are using it in a context where startup could
    already have been called (for example in the main GUI), pass in the list of
    device plugins as the plugins parameter.
    '''
    import textwrap
    from calibre.customize.ui import device_plugins, disabled_device_plugins
    from calibre.debug import print_basic_debug_info
    from calibre.devices.scanner import DeviceScanner
    from calibre.constants import iswindows, ismacos, debug, is_debugging
    from calibre import prints
    from polyglot.io import PolyglotStringIO
    oldo, olde = sys.stdout, sys.stderr

    if buf is None:
        buf = PolyglotStringIO()
    sys.stdout = sys.stderr = buf
    out = partial(prints, file=buf)

    devplugins = device_plugins() if plugins is None else plugins
    devplugins = list(sorted(devplugins, key=lambda x: x.__class__.__name__))
    if plugins is None:
        for d in devplugins:
            try:
                d.startup()
            except:
                out('Startup failed for device plugin: %s' % d)

    if disabled_plugins is None:
        disabled_plugins = list(disabled_device_plugins())

    orig_debug = is_debugging()
    debug(True)
    try:
        print_basic_debug_info(out=buf)
        s = DeviceScanner()
        s.scan()
        devices = (s.devices)
        if not iswindows:
            devices = [list(x) for x in devices]
            for d in devices:
                for i in range(3):
                    d[i] = hex(d[i])
        out('USB devices on system:')
        out(pprint.pformat(devices))

        ioreg = None
        if ismacos:
            from calibre.devices.usbms.device import Device
            mount = '\n'.join(
                repr(x) for x in Device.osx_run_mount().splitlines())
            drives = pprint.pformat(Device.osx_get_usb_drives())
            ioreg = 'Output from mount:\n' + mount + '\n\n'
            ioreg += 'Output from osx_get_usb_drives:\n' + drives + '\n\n'
            ioreg += Device.run_ioreg().decode('utf-8', 'replace')
        connected_devices = []
        if disabled_plugins:
            out(
                '\nDisabled plugins:',
                textwrap.fill(' '.join(
                    [x.__class__.__name__ for x in disabled_plugins])))
            out(' ')
        else:
            out('\nNo disabled plugins')
        found_dev = False
        for dev in devplugins:
            if not dev.MANAGES_DEVICE_PRESENCE:
                continue
            out('Looking for devices of type:', dev.__class__.__name__)
            if dev.debug_managed_device_detection(s.devices, buf):
                found_dev = True
                break
            out(' ')

        if not found_dev:
            out('Looking for devices...')
            for dev in devplugins:
                if dev.MANAGES_DEVICE_PRESENCE:
                    continue
                connected, det = s.is_device_connected(dev, debug=True)
                if connected:
                    out('\t\tDetected possible device', dev.__class__.__name__)
                    connected_devices.append((dev, det))

            out(' ')
            errors = {}
            success = False
            out('Devices possibly connected:', end=' ')
            for dev, det in connected_devices:
                out(dev.name, end=', ')
            if not connected_devices:
                out('None', end='')
            out(' ')
            for dev, det in connected_devices:
                out('Trying to open', dev.name, '...', end=' ')
                dev.do_device_debug = True
                try:
                    dev.reset(detected_device=det)
                    dev.open(det, None)
                    out('OK')
                except:
                    import traceback
                    errors[dev] = traceback.format_exc()
                    out('failed')
                    continue
                dev.do_device_debug = False
                success = True
                if hasattr(dev, '_main_prefix'):
                    out('Main memory:', repr(dev._main_prefix))
                out('Total space:', dev.total_space())
                break
            if not success and errors:
                out('Opening of the following devices failed')
                for dev, msg in errors.items():
                    out(dev)
                    out(msg)
                    out(' ')

            if ioreg is not None:
                ioreg = 'IOREG Output\n' + ioreg
                out(' ')
                if ioreg_to_tmp:
                    lopen('/tmp/ioreg.txt', 'w').write(ioreg)
                    out('Dont forget to send the contents of /tmp/ioreg.txt')
                    out('You can open it with the command: open /tmp/ioreg.txt'
                        )
                else:
                    out(ioreg)

        if hasattr(buf, 'getvalue'):
            return buf.getvalue()
    finally:
        debug(orig_debug)
        sys.stdout = oldo
        sys.stderr = olde
        if plugins is None:
            for d in devplugins:
                try:
                    d.shutdown()
                except:
                    pass