From e93414a9b2574c2b15f3188820d482a7888e2081 Mon Sep 17 00:00:00 2001 From: David Lehman Date: Fri, 9 Aug 2013 13:31:19 -0500 Subject: [PATCH 2/9] Replace blivet.pyudev with python-pyudev. This is going to provide a way to monitor udev add/remove/change events in addition to being a nice interface and that much less code to maintain. Some of the highlights: - sysfs paths now include '/sys' prefix - udev info objects are not dicts, but do have a __getitem__ method and have all of the same keys as the previous dicts except for sysfs_path, symlinks, and name, all of which were our additions and all of which are still available via dev.sys_path, dev["DEVLINKS"] and dev.sys_name, respectively - since the objects are no longer dicts we cannot inject data into them --- blivet/deviceaction.py | 4 +- blivet/devices.py | 73 ++++------------ blivet/devicetree.py | 118 ++++++++++++++----------- blivet/pyudev.py | 232 ------------------------------------------------- blivet/udev.py | 136 ++++++++--------------------- blivet/util.py | 2 +- python-blivet.spec | 1 + 7 files changed, 121 insertions(+), 445 deletions(-) delete mode 100644 blivet/pyudev.py diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py index 202a66c..d548054 100644 --- a/blivet/deviceaction.py +++ b/blivet/deviceaction.py @@ -470,9 +470,7 @@ class ActionCreateFormat(DeviceAction): self.device.format.create(device=self.device.path, options=self.device.formatArgs) # Get the UUID now that the format is created - udev_settle() - self.device.updateSysfsPath() - info = udev_get_block_device(self.device.sysfsPath) + info = udev_get_device(self.device.sysfsPath) self.device.format.uuid = udev_device_get_uuid(info) self.device.deviceLinks = udev_device_get_symlinks(info) diff --git a/blivet/devices.py b/blivet/devices.py index 24e9821..b1557b4 100644 --- a/blivet/devices.py +++ b/blivet/devices.py @@ -98,6 +98,7 @@ import math import copy import pprint import tempfile +import pyudev # device backend modules from devicelibs import mdraid @@ -640,10 +641,14 @@ class StorageDevice(Device): def updateSysfsPath(self): """ Update this device's sysfs path. """ log_method_call(self, self.name, status=self.status) - sysfsName = self.name.replace("/", "!") - path = os.path.join("/sys", self.sysfsBlockDir, sysfsName) - self.sysfsPath = os.path.realpath(path)[4:] - log.debug("%s sysfsPath set to %s" % (self.name, self.sysfsPath)) + try: + udev_device = pyudev.Device.from_device_file(global_udev, self.path) + except pyudev.DeviceNotFoundError as e: + log.error("failed to update sysfs path for %s: %s" % (self.name, e)) + self.sysfs_path = '' + else: + self.sysfsPath = udev_device.sys_path + log.debug("%s sysfsPath set to %s" % (self.name, self.sysfsPath)) @property def formatArgs(self): @@ -667,7 +672,7 @@ class StorageDevice(Device): log.debug("not sending change uevent for inactive device") return - path = os.path.normpath("/sys/%s" % self.sysfsPath) + path = os.path.normpath(self.sysfsPath) try: util.notify_kernel(path, action="change") except (ValueError, IOError) as e: @@ -928,7 +933,7 @@ class StorageDevice(Device): @property def removable(self): - devpath = os.path.normpath("/sys/%s" % self.sysfsPath) + devpath = os.path.normpath(self.sysfsPath) remfile = os.path.normpath("%s/removable" % devpath) return (self.sysfsPath and os.path.exists(devpath) and os.access(remfile, os.R_OK) and @@ -1369,23 +1374,6 @@ class PartitionDevice(StorageDevice): weight = property(lambda d: d._getWeight(), lambda d,w: d._setWeight(w)) - def updateSysfsPath(self): - """ Update this device's sysfs path. """ - log_method_call(self, self.name, status=self.status) - if not self.parents: - self.sysfsPath = '' - - elif isinstance(self.parents[0], DMDevice): - dm_node = dm.dm_node_from_name(self.name) - path = os.path.join("/sys", self.sysfsBlockDir, dm_node) - self.sysfsPath = os.path.realpath(path)[4:] - elif isinstance(self.parents[0], MDRaidArrayDevice): - md_node = mdraid.md_node_from_name(self.name) - path = os.path.join("/sys", self.sysfsBlockDir, md_node) - self.sysfsPath = os.path.realpath(path)[4:] - else: - StorageDevice.updateSysfsPath(self) - def updateName(self): if self.partedPartition is None: self._name = self.req_name @@ -1840,19 +1828,6 @@ class DMDevice(StorageDevice): return _status - def updateSysfsPath(self): - """ Update this device's sysfs path. """ - log_method_call(self, self.name, status=self.status) - if not self.exists: - raise DeviceError("device has not been created", self.name) - - if self.status: - dm_node = self.getDMNode() - path = os.path.join("/sys", self.sysfsBlockDir, dm_node) - self.sysfsPath = os.path.realpath(path)[4:] - else: - self.sysfsPath = '' - #def getTargetType(self): # return dm.getDmTarget(name=self.name) @@ -3201,20 +3176,6 @@ class MDRaidArrayDevice(StorageDevice): spares = property(_getSpares, _setSpares) - def updateSysfsPath(self): - """ Update this device's sysfs path. """ - log_method_call(self, self.name, status=self.status) - if not self.exists: - raise DeviceError("device has not been created", self.name) - - # We don't use self.status here because self.status requires a valid - # sysfs path to function correctly. - if os.path.exists(self.path): - md_node = mdraid.md_node_from_name(self.name) - self.sysfsPath = "/devices/virtual/block/%s" % md_node - else: - self.sysfsPath = '' - def _addDevice(self, device): """ Add a new member device to the array. @@ -3307,7 +3268,7 @@ class MDRaidArrayDevice(StorageDevice): if not self.exists: return status - state_file = "/sys/%s/md/array_state" % self.sysfsPath + state_file = "%s/md/array_state" % self.sysfsPath try: state = open(state_file).read().strip() if state in ("clean", "active", "active-idle", "readonly", "read-auto"): @@ -3324,7 +3285,7 @@ class MDRaidArrayDevice(StorageDevice): def degraded(self): """ Return True if the array is running in degraded mode. """ rc = False - degraded_file = "/sys/%s/md/degraded" % self.sysfsPath + degraded_file = "%s/md/degraded" % self.sysfsPath if os.access(degraded_file, os.R_OK): val = open(degraded_file).read().strip() if val == "1": @@ -3368,7 +3329,7 @@ class MDRaidArrayDevice(StorageDevice): # mdadm reuses minors indiscriminantly when there is no mdadm.conf, so # we need to clear the sysfs path now so our status method continues to # give valid results - self.updateSysfsPath() + self.sysfsPath = '' def teardown(self, recursive=None): """ Close, or tear down, a device. """ @@ -3414,14 +3375,12 @@ class MDRaidArrayDevice(StorageDevice): def _postCreate(self): # this is critical since our status method requires a valid sysfs path - md_node = mdraid.md_node_from_name(self.name) - self.sysfsPath = "/devices/virtual/block/%s" % md_node - self.exists = True # I think we can remove this. + self.updateSysfsPath() StorageDevice._postCreate(self) # update our uuid attribute with the new array's UUID - info = udev_get_block_device(self.sysfsPath) + info = mdraid.mdexamine(self.parents[0].path) self.uuid = udev_device_get_md_uuid(info) for member in self.devices: member.mdUuid = self.uuid diff --git a/blivet/devicetree.py b/blivet/devicetree.py index 39e756c..b91d20c 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -503,7 +503,7 @@ class DeviceTree(object): if self.udevDeviceIsDisk(info): # Ignore any readonly disks - if util.get_sysfs_attr(info["sysfs_path"], 'ro') == '1': + if util.get_sysfs_attr(udev_device_get_sysfs_path(info), 'ro') == '1': log.debug("Ignoring read only device %s" % name) # FIXME: We have to handle this better, ie: not ignore these. self.addIgnoredDisk(name) @@ -542,10 +542,10 @@ class DeviceTree(object): if not device: # initiate detection of all PVs and hope that it leads to us having # the VG and LVs in the tree - for pv_name in os.listdir("/sys" + sysfs_path + "/slaves"): - link = os.readlink("/sys" + sysfs_path + "/slaves/" + pv_name) + for pv_name in os.listdir(sysfs_path + "/slaves"): + link = os.readlink(sysfs_path + "/slaves/" + pv_name) pv_sysfs_path = os.path.normpath(sysfs_path + '/slaves/' + link) - pv_info = udev_get_block_device(pv_sysfs_path) + pv_info = udev_get_device(pv_sysfs_path) self.addUdevDevice(pv_info) vg_name = udev_device_get_lv_vg_name(info) @@ -589,7 +589,7 @@ class DeviceTree(object): if device is None: # we couldn't find it, so create it # first, get a list of the slave devs and look them up - dir = os.path.normpath("/sys/%s/slaves" % sysfs_path) + dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name first @@ -599,7 +599,7 @@ class DeviceTree(object): dev_name = slave_name.replace("!", "/") # handles cciss slave_dev = self.getDeviceByName(dev_name) path = os.path.normpath("%s/%s" % (dir, slave_name)) - new_info = udev_get_block_device(os.path.realpath(path)[4:]) + new_info = udev_get_device(os.path.realpath(path)) if not slave_dev: # we haven't scanned the slave yet, so do it now if new_info: @@ -661,7 +661,7 @@ class DeviceTree(object): # TODO: look for this device by dm-uuid? # first, get a list of the slave devs and look them up - dir = os.path.normpath("/sys/%s/slaves" % sysfs_path) + dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name first @@ -671,7 +671,7 @@ class DeviceTree(object): dev_name = slave_name.replace("!", "/") # handles cciss slave_dev = self.getDeviceByName(dev_name) path = os.path.normpath("%s/%s" % (dir, slave_name)) - new_info = udev_get_block_device(os.path.realpath(path)[4:]) + new_info = udev_get_device(os.path.realpath(path)) if not slave_dev: # we haven't scanned the slave yet, so do it now if new_info: @@ -706,7 +706,7 @@ class DeviceTree(object): device = None slaves = [] - dir = os.path.normpath("/sys/%s/slaves" % sysfs_path) + dir = os.path.normpath("%s/slaves" % sysfs_path) slave_names = os.listdir(dir) for slave_name in slave_names: # if it's a dm-X name, resolve it to a map name @@ -720,7 +720,7 @@ class DeviceTree(object): else: # we haven't scanned the slave yet, so do it now path = os.path.normpath("%s/%s" % (dir, slave_name)) - new_info = udev_get_block_device(os.path.realpath(path)[4:]) + new_info = udev_get_device(os.path.realpath(path)) if new_info: self.addUdevDevice(new_info) if self.getDeviceByName(dev_name) is None: @@ -734,6 +734,9 @@ class DeviceTree(object): if device is None: device = self.getDeviceByUuid(info.get("MD_UUID")) + if device.name != name: + log.debug("changing %s to in-use name %s" % (device.name, name)) + device._name = name # if we get here, we found all of the slave devices and # something must be wrong -- if all of the slaves are in @@ -776,7 +779,7 @@ class DeviceTree(object): if disk is None: # create a device instance for the disk - new_info = udev_get_block_device(os.path.dirname(sysfs_path)) + new_info = udev_get_device(os.path.dirname(sysfs_path)) if new_info: self.addUdevDevice(new_info) disk = self.getDeviceByName(disk_name) @@ -877,7 +880,7 @@ class DeviceTree(object): if not container: parentSysName = devicelibs.mdraid.md_node_from_name(parentName) container_sysfs = "/class/block/" + parentSysName - container_info = udev_get_block_device(container_sysfs) + container_info = udev_get_device(container_sysfs) if not container_info: log.error("failed to find md container %s at %s" % (parentName, container_sysfs)) @@ -949,7 +952,7 @@ class DeviceTree(object): name = udev_device_get_name(info) log_method_call(self, name=name) sysfs_path = udev_device_get_sysfs_path(info) - sys_file = "/sys/%s/loop/backing_file" % sysfs_path + sys_file = "%s/loop/backing_file" % sysfs_path backing_file = open(sys_file).read().strip() file_device = self.getDeviceByName(backing_file) if not file_device: @@ -1304,11 +1307,15 @@ class DeviceTree(object): exists=True) self._addDevice(lv_device) if flags.installer_mode: - lv_device.setup() + try: + lv_device.setup() + except StorageError as e: + # FIXME: mark it as broken to prevent attempted reuse + log.error("failed to activate lv %s: %s" % (lv_name, e)) if lv_device.status: lv_device.updateSysfsPath() - lv_info = udev_get_block_device(lv_device.sysfsPath) + lv_info = udev_get_device(lv_device.sysfsPath) if not lv_info: log.error("failed to get udev data for lv %s" % lv_device.name) continue @@ -1330,12 +1337,15 @@ class DeviceTree(object): return ret - def handleUdevLVMPVFormat(self, info, device): + def handleUdevLVMPVFormat(self, info, device, pvInfo=None): log_method_call(self, name=device.name, type=device.format.type) + if pvInfo is None: + return + # lookup/create the VG and LVs try: - vg_name = udev_device_get_vg_name(info) - vg_uuid = udev_device_get_vg_uuid(info) + vg_name = udev_device_get_vg_name(pvInfo) + vg_uuid = udev_device_get_vg_uuid(pvInfo) except KeyError: # no vg name means no vg -- we're done with this pv return @@ -1349,12 +1359,12 @@ class DeviceTree(object): vg_device._addDevice(device) else: try: - vg_size = udev_device_get_vg_size(info) - vg_free = udev_device_get_vg_free(info) - pe_size = udev_device_get_vg_extent_size(info) - pe_count = udev_device_get_vg_extent_count(info) - pe_free = udev_device_get_vg_free_extents(info) - pv_count = udev_device_get_vg_pv_count(info) + vg_size = udev_device_get_vg_size(pvInfo) + vg_free = udev_device_get_vg_free(pvInfo) + pe_size = udev_device_get_vg_extent_size(pvInfo) + pe_count = udev_device_get_vg_extent_count(pvInfo) + pe_free = udev_device_get_vg_free_extents(pvInfo) + pv_count = udev_device_get_vg_pv_count(pvInfo) except (KeyError, ValueError) as e: log.warning("invalid data for %s: %s" % (device.name, e)) return @@ -1371,17 +1381,17 @@ class DeviceTree(object): exists=True) self._addDevice(vg_device) - info.update(lvm.lvs(vg_name)) + lv_info = lvm.lvs(vg_name) # Now we add any lv info found in this pv to the vg_device, we # do this for all pvs as pvs only contain lv info for lvs which they # contain themselves try: - lv_names = udev_device_get_lv_names(info) - lv_uuids = udev_device_get_lv_uuids(info) - lv_sizes = udev_device_get_lv_sizes(info) - lv_attr = udev_device_get_lv_attr(info) - lv_types = udev_device_get_lv_types(info) + lv_names = udev_device_get_lv_names(lv_info) + lv_uuids = udev_device_get_lv_uuids(lv_info) + lv_sizes = udev_device_get_lv_sizes(lv_info) + lv_attr = udev_device_get_lv_attr(lv_info) + lv_types = udev_device_get_lv_types(lv_info) except KeyError as e: log.warning("invalid data for %s: %s" % (device.name, e)) return @@ -1403,12 +1413,15 @@ class DeviceTree(object): self.handleVgLvs(vg_device) - def handleUdevMDMemberFormat(self, info, device): + def handleUdevMDMemberFormat(self, info, device, mdInfo=None): log_method_call(self, name=device.name, type=device.format.type) # either look up or create the array device name = udev_device_get_name(info) sysfs_path = udev_device_get_sysfs_path(info) + if mdInfo is None: + mdInfo = {} + md_array = self.getDeviceByUuid(device.format.mdUuid, incomplete=True) if device.format.mdUuid and md_array: md_array._addDevice(device) @@ -1416,19 +1429,19 @@ class DeviceTree(object): # create the array with just this one member try: # level is reported as, eg: "raid1" - md_level = udev_device_get_md_level(info) - md_devices = int(udev_device_get_md_devices(info)) - md_uuid = udev_device_get_md_uuid(info) + md_level = udev_device_get_md_level(mdInfo) + md_devices = int(udev_device_get_md_devices(mdInfo)) + md_uuid = udev_device_get_md_uuid(mdInfo) except (KeyError, ValueError) as e: log.warning("invalid data for %s: %s" % (name, e)) return - md_metadata = info.get("MD_METADATA") + md_metadata = mdInfo.get("MD_METADATA") md_name = None # check the list of devices udev knows about to see if the array # this device belongs to is already active - for dev in udev_get_block_devices(): + for dev in udev_get_devices(): if not udev_device_is_md(dev): continue @@ -1528,13 +1541,13 @@ class DeviceTree(object): self._addDevice(dm_array) # Wait for udev to scan the just created nodes, to avoid a race - # with the udev_get_block_device() call below. + # with the udev_get_device() call below. udev_settle() # Get the DMRaidArrayDevice a DiskLabel format *now*, in case # its partitions get scanned before it does. dm_array.updateSysfsPath() - dm_array_info = udev_get_block_device(dm_array.sysfsPath) + dm_array_info = udev_get_device(dm_array.sysfsPath) self.handleUdevDiskLabelFormat(dm_array_info, dm_array) # Use the rs's object on the device. @@ -1627,28 +1640,28 @@ class DeviceTree(object): # luks/dmcrypt kwargs["name"] = "luks-%s" % uuid elif format_type in formats.mdraid.MDRaidMember._udevTypes: - info.update(devicelibs.mdraid.mdexamine(device.path)) + md_info = devicelibs.mdraid.mdexamine(device.path) # mdraid try: - kwargs["mdUuid"] = udev_device_get_md_uuid(info) + kwargs["mdUuid"] = udev_device_get_md_uuid(md_info) except KeyError: log.warning("mdraid member %s has no md uuid" % name) kwargs["biosraid"] = udev_device_is_biosraid_member(info) elif format_type == "LVM2_member": # lvm - info.update(devicelibs.lvm.pvinfo(device.path)) + pv_info = devicelibs.lvm.pvinfo(device.path) try: - kwargs["vgName"] = udev_device_get_vg_name(info) + kwargs["vgName"] = udev_device_get_vg_name(pv_info) except KeyError as e: log.warning("PV %s has no vg_name" % name) try: - kwargs["vgUuid"] = udev_device_get_vg_uuid(info) + kwargs["vgUuid"] = udev_device_get_vg_uuid(pv_info) except KeyError: log.warning("PV %s has no vg_uuid" % name) try: - kwargs["peStart"] = udev_device_get_pv_pe_start(info) + kwargs["peStart"] = udev_device_get_pv_pe_start(pv_info) except KeyError: log.warning("PV %s has no pe_start" % name) elif format_type == "vfat": @@ -1684,18 +1697,18 @@ class DeviceTree(object): if device.format.type == "luks": self.handleUdevLUKSFormat(info, device) elif device.format.type == "mdmember": - self.handleUdevMDMemberFormat(info, device) + self.handleUdevMDMemberFormat(info, device, mdInfo=md_info) elif device.format.type == "dmraidmember": self.handleUdevDMRaidMemberFormat(info, device) elif device.format.type == "lvmpv": - self.handleUdevLVMPVFormat(info, device) + self.handleUdevLVMPVFormat(info, device, pvInfo=pv_info) elif device.format.type == "btrfs": self.handleBTRFSFormat(info, device) def updateDeviceFormat(self, device): log.info("updating format of device: %s" % device) try: - util.notify_kernel("/sys%s" % device.sysfsPath) + util.notify_kernel(device.sysfsPath) except (ValueError, IOError) as e: log.warning("failed to notify kernel of change: %s" % e) @@ -1801,7 +1814,7 @@ class DeviceTree(object): self._addDevice(filedev) self._addDevice(loopdev) self._addDevice(dmdev) - info = udev_get_block_device(dmdev.sysfsPath) + info = udev_get_device(dmdev.sysfsPath) self.addUdevDevice(info) def backupConfigs(self, restore=False): @@ -1898,18 +1911,19 @@ class DeviceTree(object): # blocks or since previous iterations. while True: devices = [] - new_devices = udev_get_block_devices() + new_devices = udev_get_devices() for new_device in new_devices: - if not old_devices.has_key(new_device['name']): - old_devices[new_device['name']] = new_device + new_name = udev_device_get_name(new_device) + if not old_devices.has_key(new_name): + old_devices[new_name] = new_device devices.append(new_device) if len(devices) == 0: # nothing is changing -- we are finished building devices break - log.info("devices to scan: %s" % [d['name'] for d in devices]) + log.info("devices to scan: %s" % [udev_device_get_name(d) for d in devices]) for dev in devices: self.addUdevDevice(dev) diff --git a/blivet/pyudev.py b/blivet/pyudev.py deleted file mode 100644 index 705b93d..0000000 --- a/blivet/pyudev.py +++ /dev/null @@ -1,232 +0,0 @@ -from __future__ import print_function - -import sys -import os -import fnmatch -from ctypes import * - - -# XXX this one may need some tweaking... -def find_library(name, somajor=0): - env = os.environ.get("LD_LIBRARY_PATH") - common = ["/lib64", "/lib"] - - if env: - libdirs = env.split(":") + common - else: - libdirs = common - - libdirs = filter(os.path.isdir, libdirs) - - for dir in libdirs: - files = fnmatch.filter(os.listdir(dir), "lib%s.so.%d" % (name, somajor)) - files = [os.path.join(dir, file) for file in files] - - if files: - break - - if files: - return files[0] - else: - return None - -# find the udev library -name = "udev" -somajor = 1 -libudev = find_library(name=name, somajor=somajor) - -if not libudev or not os.path.exists(libudev): - raise ImportError, "No library named %s.%d" % (name, somajor) - -# load the udev library -libudev = CDLL(libudev) - - -# create aliases for needed functions and set the return types where needed -libudev_udev_new = libudev.udev_new -libudev_udev_new.argtypes = [] -libudev_udev_new.restype = c_void_p -libudev_udev_unref = libudev.udev_unref -libudev_udev_unref.argtypes = [ c_void_p ] - -libudev_udev_device_new_from_syspath = libudev.udev_device_new_from_syspath -libudev_udev_device_new_from_syspath.restype = c_void_p -libudev_udev_device_new_from_syspath.argtypes = [ c_void_p, c_char_p ] -libudev_udev_device_unref = libudev.udev_device_unref -libudev_udev_device_unref.argtypes = [ c_void_p ] - -libudev_udev_device_get_syspath = libudev.udev_device_get_syspath -libudev_udev_device_get_syspath.restype = c_char_p -libudev_udev_device_get_syspath.argtypes = [ c_void_p ] -libudev_udev_device_get_sysname = libudev.udev_device_get_sysname -libudev_udev_device_get_sysname.restype = c_char_p -libudev_udev_device_get_sysname.argtypes = [ c_void_p ] -libudev_udev_device_get_devpath = libudev.udev_device_get_devpath -libudev_udev_device_get_devpath.restype = c_char_p -libudev_udev_device_get_devpath.argtypes = [ c_void_p ] -libudev_udev_device_get_devtype = libudev.udev_device_get_devtype -libudev_udev_device_get_devtype.restype = c_char_p -libudev_udev_device_get_devtype.argtypes = [ c_void_p ] -libudev_udev_device_get_devnode = libudev.udev_device_get_devnode -libudev_udev_device_get_devnode.restype = c_char_p -libudev_udev_device_get_devnode.argtypes = [ c_void_p ] -libudev_udev_device_get_subsystem = libudev.udev_device_get_subsystem -libudev_udev_device_get_subsystem.restype = c_char_p -libudev_udev_device_get_subsystem.argtypes = [ c_void_p ] -libudev_udev_device_get_sysnum = libudev.udev_device_get_sysnum -libudev_udev_device_get_sysnum.restype = c_char_p -libudev_udev_device_get_sysnum.argtypes = [ c_void_p ] - -libudev_udev_device_get_properties_list_entry = libudev.udev_device_get_properties_list_entry -libudev_udev_device_get_properties_list_entry.restype = c_void_p -libudev_udev_device_get_properties_list_entry.argtypes = [ c_void_p ] -libudev_udev_list_entry_get_next = libudev.udev_list_entry_get_next -libudev_udev_list_entry_get_next.restype = c_void_p -libudev_udev_list_entry_get_next.argtypes = [ c_void_p ] - -libudev_udev_list_entry_get_name = libudev.udev_list_entry_get_name -libudev_udev_list_entry_get_name.restype = c_char_p -libudev_udev_list_entry_get_name.argtypes = [ c_void_p ] -libudev_udev_list_entry_get_value = libudev.udev_list_entry_get_value -libudev_udev_list_entry_get_value.restype = c_char_p -libudev_udev_list_entry_get_value.argtypes = [ c_void_p ] - -libudev_udev_enumerate_new = libudev.udev_enumerate_new -libudev_udev_enumerate_new.restype = c_void_p -libudev_udev_enumerate_new.argtypes = [ c_void_p ] -libudev_udev_enumerate_unref = libudev.udev_enumerate_unref -libudev_udev_enumerate_unref.argtypes = [ c_void_p ] - -libudev_udev_enumerate_add_match_subsystem = libudev.udev_enumerate_add_match_subsystem -libudev_udev_enumerate_add_match_subsystem.restype = c_int -libudev_udev_enumerate_add_match_subsystem.argtypes = [ c_void_p, c_char_p ] -libudev_udev_enumerate_scan_devices = libudev.udev_enumerate_scan_devices -libudev_udev_enumerate_scan_devices.restype = c_int -libudev_udev_enumerate_scan_devices.argtypes = [ c_void_p ] -libudev_udev_enumerate_get_list_entry = libudev.udev_enumerate_get_list_entry -libudev_udev_enumerate_get_list_entry.restype = c_void_p -libudev_udev_enumerate_get_list_entry.argtypes = [ c_void_p ] - -libudev_udev_device_get_devlinks_list_entry = libudev.udev_device_get_devlinks_list_entry -libudev_udev_device_get_devlinks_list_entry.restype = c_void_p -libudev_udev_device_get_devlinks_list_entry.argtypes = [ c_void_p ] - - -class UdevDevice(dict): - - def __init__(self, udev, sysfs_path): - dict.__init__(self) - - # create new udev device from syspath - udev_device = libudev_udev_device_new_from_syspath(udev, sysfs_path) - if not udev_device: - # device does not exist - return - - # set syspath and sysname properties - self.syspath = libudev_udev_device_get_syspath(udev_device) - self.sysname = libudev_udev_device_get_sysname(udev_device) - - # get the devlinks list - devlinks = [] - devlinks_entry = libudev_udev_device_get_devlinks_list_entry(udev_device) - - while devlinks_entry: - path = libudev_udev_list_entry_get_name(devlinks_entry) - devlinks.append(path) - - devlinks_entry = libudev_udev_list_entry_get_next(devlinks_entry) - - # add devlinks list to the dictionary - self["symlinks"] = devlinks - - # get the first property entry - property_entry = libudev_udev_device_get_properties_list_entry(udev_device) - - while property_entry: - name = libudev_udev_list_entry_get_name(property_entry) - value = libudev_udev_list_entry_get_value(property_entry) - - # lvm outputs values for multiple lvs in one line - # we want to split them and make a list - # if the first lv's value is empty we end up with a value starting - # with name=, prepend a space that our split does the right thing - if value.startswith("%s=" % name): - value = " " + value - - if value.count(" %s=" % name): - value = value.split(" %s=" % name) - - self[name] = value - - # get next property entry - property_entry = libudev_udev_list_entry_get_next(property_entry) - - # set additional properties - self.devpath = libudev_udev_device_get_devpath(udev_device) - self.subsystem = libudev_udev_device_get_subsystem(udev_device) - self.devtype = libudev_udev_device_get_devtype(udev_device) - self.sysnum = libudev_udev_device_get_sysnum(udev_device) - self.devnode = libudev_udev_device_get_devnode(udev_device) - - # cleanup - libudev_udev_device_unref(udev_device) - - -class Udev(object): - - def __init__(self): - self.udev = libudev_udev_new() - - def create_device(self, sysfs_path): - return UdevDevice(self.udev, sysfs_path) - - def enumerate_devices(self, subsystem=None): - enumerate = libudev_udev_enumerate_new(self.udev) - - # add the match subsystem - if subsystem is not None: - rc = libudev_udev_enumerate_add_match_subsystem(enumerate, subsystem) - if not rc == 0: - print("error: unable to add the match subsystem", file=sys.stderr) - libudev_udev_enumerate_unref(enumerate) - return [] - - # scan the devices - rc = libudev_udev_enumerate_scan_devices(enumerate) - if not rc == 0: - print("error: unable to enumerate the devices", file=sys.stderr) - libudev_udev_enumerate_unref(enumerate) - return [] - - # create the list of sysfs paths - sysfs_paths = [] - - # get the first list entry - list_entry = libudev_udev_enumerate_get_list_entry(enumerate) - - while list_entry: - sysfs_path = libudev_udev_list_entry_get_name(list_entry) - sysfs_paths.append(sysfs_path) - - # get next list entry - list_entry = libudev_udev_list_entry_get_next(list_entry) - - # cleanup - libudev_udev_enumerate_unref(enumerate) - - return sysfs_paths - - def scan_devices(self, sysfs_paths=None): - if sysfs_paths is None: - sysfs_paths = self.enumerate_devices() - - for sysfs_path in sysfs_paths: - device = self.create_device(sysfs_path) - - if device: - yield device - - def unref(self): - libudev_udev_unref(self.udev) - self.udev = None diff --git a/blivet/udev.py b/blivet/udev.py index ebcf92e..c0e77df 100644 --- a/blivet/udev.py +++ b/blivet/udev.py @@ -28,56 +28,24 @@ import util from errors import * import pyudev -global_udev = pyudev.Udev() +global_udev = pyudev.Context() import logging log = logging.getLogger("blivet") -def udev_enumerate_devices(deviceClass="block"): - devices = global_udev.enumerate_devices(subsystem=deviceClass) - return [path[4:] for path in devices] - def udev_get_device(sysfs_path): - if not os.path.exists("/sys%s" % sysfs_path): - log.debug("%s does not exist" % sysfs_path) - return None - - # XXX we remove the /sys part when enumerating devices, - # so we have to prepend it when creating the device - dev = global_udev.create_device("/sys" + sysfs_path) - - if dev: - dev["name"] = dev.sysname - dev["sysfs_path"] = sysfs_path - - # now add in the contents of the uevent file since they're handy - dev = udev_parse_uevent_file(dev) + try: + dev = pyudev.Device.from_sys_path(global_udev, sysfs_path) + except pyudev.DeviceNotFoundError as e: + log.error(e) + dev = None return dev -def udev_get_devices(deviceClass="block"): +def udev_get_devices(subsystem="block"): udev_settle() - entries = [] - for path in udev_enumerate_devices(deviceClass): - entry = udev_get_device(path) - if entry: - entries.append(entry) - return entries - -def udev_parse_uevent_file(dev): - path = os.path.normpath("/sys/%s/uevent" % dev['sysfs_path']) - if not os.access(path, os.R_OK): - return dev - - with open(path) as f: - for line in f.readlines(): - (key, equals, value) = line.strip().partition("=") - if not equals: - continue - - dev[key] = value - - return dev + return [d for d in global_udev.list_devices(subsystem=subsystem) + if not __is_blacklisted_blockdev(d.sys_name)] def udev_settle(): # wait maximal 300 seconds for udev to be done running blkid, lvm, @@ -101,7 +69,7 @@ def udev_resolve_devspec(devspec): import devices as _devices ret = None - for dev in udev_get_block_devices(): + for dev in udev_get_devices(): if devspec.startswith("LABEL="): if udev_device_get_label(dev) == devspec[6:]: ret = dev @@ -134,37 +102,18 @@ def udev_resolve_glob(glob): if not glob: return ret - for dev in udev_get_block_devices(): + for dev in udev_get_devices(): name = udev_device_get_name(dev) if fnmatch.fnmatch(name, glob): ret.append(name) else: - for link in dev["symlinks"]: + for link in dev["DEVLINKS"]: if fnmatch.fnmatch(link, glob): ret.append(name) return ret -def udev_get_block_devices(): - udev_settle() - entries = [] - for path in udev_enumerate_block_devices(): - entry = udev_get_block_device(path) - if entry: - if entry["name"].startswith("md"): - # mdraid is really braindead, when a device is stopped - # it is no longer usefull in anyway (and we should not - # probe it) yet it still sticks around, see bug rh523387 - state = None - state_file = "/sys/%s/md/array_state" % entry["sysfs_path"] - if os.access(state_file, os.R_OK): - state = open(state_file).read().strip() - if state == "clear": - continue - entries.append(entry) - return entries - def __is_blacklisted_blockdev(dev_name): """Is this a blockdev we never want for an install?""" if dev_name.startswith("ram") or dev_name.startswith("fd"): @@ -179,20 +128,6 @@ def __is_blacklisted_blockdev(dev_name): return False -def udev_enumerate_block_devices(): - import os.path - - return filter(lambda d: not __is_blacklisted_blockdev(os.path.basename(d)), - udev_enumerate_devices(deviceClass="block")) - -def udev_get_block_device(sysfs_path): - dev = udev_get_device(sysfs_path) - if not dev or not dev.has_key("name"): - return None - else: - return dev - - # These are functions for retrieving specific pieces of information from # udev database entries. def udev_device_get_name(udev_info): @@ -200,7 +135,7 @@ def udev_device_get_name(udev_info): if "DM_NAME" in udev_info: name = udev_info["DM_NAME"] else: - name = udev_info["name"] + name = udev_info.sys_name return name @@ -223,7 +158,7 @@ def udev_device_get_label(udev_info): def udev_device_is_dm(info): """ Return True if the device is a device-mapper device. """ - return info.has_key("DM_NAME") + return "DM_NAME" in info def udev_device_is_md(info): """ Return True if the device is a mdraid array device. """ @@ -233,7 +168,7 @@ def udev_device_is_md(info): # The udev information keeps shifting around. Only md arrays have a # /sys/class/block//md/ subdirectory. - md_dir = "/sys" + udev_device_get_sysfs_path(info) + "/md" + md_dir = udev_device_get_sysfs_path(info) + "/md" return os.path.exists(md_dir) def udev_device_is_cciss(info): @@ -253,7 +188,7 @@ def udev_device_is_zfcp(info): if info.get("DEVTYPE") != "disk": return False - subsystem = "/sys" + info.get("sysfs_path") + subsystem = udev_device_get_sysfs_path(info) while True: topdir = os.path.realpath(os.path.dirname(subsystem)) @@ -281,7 +216,7 @@ def udev_device_get_zfcp_attribute(info, attr=None): log.debug("udev_device_get_zfcp_attribute() called with attr=None") return None - attribute = "/sys%s/device/%s" % (info.get("sysfs_path"), attr,) + attribute = "%s/device/%s" % (udev_device_get_sysfs_path(info), attr,) attribute = os.path.realpath(attribute) if not os.path.isfile(attribute): @@ -292,14 +227,14 @@ def udev_device_get_zfcp_attribute(info, attr=None): def udev_device_get_dasd_bus_id(info): """ Return the CCW bus ID of the dasd device. """ - return info.get("sysfs_path").split("/")[-3] + return udev_device_get_sysfs_path(info).split("/")[-3] def udev_device_get_dasd_flag(info, flag=None): """ Return the specified flag for the dasd device. """ if flag is None: return None - path = "/sys" + info.get("sysfs_path") + "/device/" + flag + path = udev_device_get_sysfs_path(info) + "/device/" + flag if not os.path.isfile(path): return None @@ -315,17 +250,17 @@ def udev_device_is_disk(info): """ Return True is the device is a disk. """ if udev_device_is_cdrom(info): return False - has_range = os.path.exists("/sys/%s/range" % info['sysfs_path']) + has_range = os.path.exists("%s/range" % udev_device_get_sysfs_path(info)) return info.get("DEVTYPE") == "disk" or has_range def udev_device_is_partition(info): - has_start = os.path.exists("/sys/%s/start" % info['sysfs_path']) + has_start = os.path.exists("%s/start" % udev_device_get_sysfs_path(info)) return info.get("DEVTYPE") == "partition" or has_start def udev_device_is_loop(info): """ Return True if the device is a configured loop device. """ return (udev_device_get_name(info).startswith("loop") and - os.path.isdir("/sys/%s/loop" % info['sysfs_path'])) + os.path.isdir("%s/loop" % udev_device_get_sysfs_path(info))) def udev_device_get_serial(udev_info): """ Get the serial number/UUID from the device as reported by udev. """ @@ -353,7 +288,7 @@ def udev_device_get_path(info): return info["ID_PATH"] def udev_device_get_symlinks(info): - return info.get("symlinks", []) + return info.get("DEVLINKS", []) def udev_device_get_by_path(info): for link in udev_device_get_symlinks(info): @@ -363,7 +298,7 @@ def udev_device_get_by_path(info): return udev_device_get_name(info) def udev_device_get_sysfs_path(info): - return info['sysfs_path'] + return info.sys_path def udev_device_get_major(info): return int(info["MAJOR"]) @@ -527,7 +462,7 @@ def udev_device_is_biosraid_member(info): # dmraid will be everything that is raid and not linux_raid_member from formats.dmraid import DMRaidMember from formats.mdraid import MDRaidMember - if info.has_key("ID_FS_TYPE") and \ + if "ID_FS_TYPE" in info and \ (info["ID_FS_TYPE"] in DMRaidMember._udevTypes or \ info["ID_FS_TYPE"] in MDRaidMember._udevTypes) and \ info["ID_FS_TYPE"] != "linux_raid_member": @@ -625,7 +560,7 @@ def udev_device_get_iscsi_session(info): # The position of sessionX part depends on device # (e.g. offload vs. sw; also varies for different offload devs) session = None - match = re.match('/.*/(session\d+)', info["sysfs_path"]) + match = re.match('/.*/(session\d+)', udev_device_get_sysfs_path(info)) if match: session = match.groups()[0] else: @@ -644,7 +579,8 @@ def udev_device_get_iscsi_nic(info): def udev_device_get_iscsi_initiator(info): initiator = None if udev_device_is_partoff_iscsi(info): - host = re.match('.*/(host\d+)', info["sysfs_path"]).groups()[0] + host = re.match('.*/(host\d+)', + udev_device_get_sysfs_path(info)).groups()[0] if host: initiator_file = "/sys/class/iscsi_host/%s/initiatorname" % host if os.access(initiator_file, os.R_OK): @@ -686,11 +622,11 @@ def udev_device_get_iscsi_initiator(info): def _detect_broadcom_fcoe(info): re_pci_host=re.compile('/(.*)/(host\d+)') - match = re_pci_host.match(info["sysfs_path"]) + match = re_pci_host.match(udev_device_get_sysfs_path(info)) if match: sysfs_pci, host = match.groups() - if os.access('/sys/%s/%s/fc_host' %(sysfs_pci, host), os.X_OK) and \ - os.access('/sys/%s/net' %(sysfs_pci), os.X_OK): + if os.access('%s/%s/fc_host' %(sysfs_pci, host), os.X_OK) and \ + os.access('%s/net' %(sysfs_pci), os.X_OK): return (sysfs_pci, host) return (None, None) @@ -705,7 +641,7 @@ def udev_device_is_fcoe(info): path_components[2] == "fc": return True - if path.startswith("fc-") and "fcoe" in info["sysfs_path"]: + if path.startswith("fc-") and "fcoe" in udev_device_get_sysfs_path(info): return True if _detect_broadcom_fcoe(info) != (None, None): @@ -721,12 +657,12 @@ def udev_device_get_fcoe_nic(info): path_components[2] == "fc": return path_components[1] - if path.startswith("fc-") and "fcoe" in info["sysfs_path"]: - return info["sysfs_path"].split("/")[4].split(".")[0] + if path.startswith("fc-") and "fcoe" in udev_device_get_sysfs_path(info): + return udev_device_get_sysfs_path(info).split("/")[4].split(".")[0] (sysfs_pci, host) = _detect_broadcom_fcoe(info) if (sysfs_pci, host) != (None, None): - net_path = '/sys/%s/net' % sysfs_pci + net_path = '%s/net' % sysfs_pci listdir = os.listdir(net_path) if len(listdir) > 0 : return listdir[0] @@ -739,7 +675,7 @@ def udev_device_get_fcoe_identifier(info): path_components[2] == "fc": return path_components[3] - if path.startswith("fc-") and "fcoe" in info["sysfs_path"]: + if path.startswith("fc-") and "fcoe" in udev_device_get_sysfs_path(info): return path_components[1] if udev_device_is_fcoe(info) and len(path_components) >= 4 and \ diff --git a/blivet/util.py b/blivet/util.py index 9d038cd..5c79492 100644 --- a/blivet/util.py +++ b/blivet/util.py @@ -164,7 +164,7 @@ def get_sysfs_attr(path, attr): log.debug("get_sysfs_attr() called with attr=None") return None - attribute = "/sys%s/%s" % (path, attr) + attribute = "%s/%s" % (path, attr) attribute = os.path.realpath(attribute) if not os.path.isfile(attribute) and not os.path.islink(attribute): diff --git a/python-blivet.spec b/python-blivet.spec index 04a928f..3129146 100644 --- a/python-blivet.spec +++ b/python-blivet.spec @@ -26,6 +26,7 @@ BuildRequires: python-setuptools-devel Requires: python Requires: pykickstart >= %{pykickstartver} Requires: util-linux >= %{utillinuxver} +Requires: python-pyudev Requires: parted >= %{partedver} Requires: pyparted >= %{pypartedver} Requires: device-mapper >= %{dmver} -- 1.8.1.4