def device_matches(spec, devicetree=None, disks_only=False): """Return names of block devices matching the provided specification. :param str spec: a device identifier (name, UUID=<uuid>, &c) :keyword devicetree: device tree to look up devices in (optional) :type devicetree: :class:`blivet.DeviceTree` :param bool disks_only: if only disk devices matching the spec should be returned :returns: names of matching devices :rtype: list of str The spec can contain multiple "sub specs" delimited by a |, for example: "sd*|hd*|vd*" In such case we resolve the specs from left to right and return all unique matches, for example: ["sda", "sda1", "sda2", "sdb", "sdb1", "vdb"] If disks_only is specified we only return disk devices matching the spec. For the example above the output with disks_only=True would be: ["sda", "sdb", "vdb"] Also note that parse methods will not have access to a devicetree, while execute methods will. The devicetree is superior in that it can resolve md array names and in that it reflects scheduled device removals, but for normal local disks udev.resolve_devspec should suffice. """ matches = [] # the device specifications might contain multiple "sub specs" separated by a | # - the specs are processed from left to right for single_spec in spec.split("|"): full_spec = single_spec if not full_spec.startswith("/dev/"): full_spec = os.path.normpath("/dev/" + full_spec) # the regular case single_spec_matches = udev.resolve_glob(full_spec) for match in single_spec_matches: if match not in matches: # skip non-disk devices in disk-only mode if disks_only and not device_name_is_disk(match): continue matches.append(match) dev_name = None # Use spec here instead of full_spec to preserve the spec and let the # called code decide whether to treat the spec as a path instead of a name. if devicetree is None: # we run the spec through resolve_devspec() here as unlike resolve_glob() # it can also resolve labels and UUIDs dev_name = udev.resolve_devspec(single_spec) if disks_only and dev_name: if not device_name_is_disk(dev_name): dev_name = None # not a disk else: # devicetree can also handle labels and UUIDs device = devicetree.resolve_device(single_spec) if device: dev_name = device.name if disks_only and not device_name_is_disk(dev_name, devicetree=devicetree): dev_name = None # not a disk # The dev_name variable can be None if the spec is not not found or is not valid, # but we don't want that ending up in the list. if dev_name and dev_name not in matches: matches.append(dev_name) log.debug("%s matches %s for devicetree=%s and disks_only=%s", spec, matches, devicetree, disks_only) return matches