From 86b73a6ca13f8534ac3605dbe27eda9b9c2053fd Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Fri, 9 Aug 2013 13:31:19 -0500
Subject: [PATCH 2/2] 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   | 117 ++++++++++++++-----------
 blivet/pyudev.py       | 232 -------------------------------------------------
 blivet/udev.py         | 136 ++++++++---------------------
 blivet/util.py         |   2 +-
 python-blivet.spec     |   1 +
 7 files changed, 120 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 4c85ed9..4b398d2 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):
@@ -666,7 +671,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:
@@ -927,7 +932,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
@@ -1352,23 +1357,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
@@ -1810,19 +1798,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)
 
@@ -3164,20 +3139,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.
 
@@ -3270,7 +3231,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"):
@@ -3287,7 +3248,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":
@@ -3331,7 +3292,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. """
@@ -3377,14 +3338,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 0a8503f..c7e0e72 100644
--- a/blivet/devicetree.py
+++ b/blivet/devicetree.py
@@ -509,7 +509,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)
@@ -548,10 +548,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)
@@ -595,7 +595,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
@@ -605,7 +605,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:
@@ -667,7 +667,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
@@ -677,7 +677,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:
@@ -712,7 +712,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
@@ -726,7 +726,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:
@@ -740,6 +740,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
@@ -782,7 +785,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)
@@ -883,7 +886,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))
@@ -953,7 +956,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:
@@ -1297,11 +1300,15 @@ class DeviceTree(object):
                                      uuid=lv_uuid, size=lv_size, 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
@@ -1321,12 +1328,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
@@ -1340,12 +1350,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
@@ -1362,16 +1372,15 @@ 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_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)
         except KeyError as e:
             log.warning("invalid data for %s: %s" % (device.name, e))
             return
@@ -1392,12 +1401,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)
@@ -1405,19 +1417,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
 
@@ -1517,13 +1529,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.
@@ -1616,28 +1628,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":
@@ -1673,18 +1685,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)
 
@@ -1784,7 +1796,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):
@@ -1881,18 +1893,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 bdb7ffe..d29fc45 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/<name>/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"])
@@ -519,7 +454,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":
@@ -617,7 +552,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:
@@ -636,7 +571,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):
@@ -678,11 +614,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)
 
@@ -697,7 +633,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):
@@ -713,12 +649,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]
@@ -731,7 +667,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 baefa44..f50d5eb 100644
--- a/python-blivet.spec
+++ b/python-blivet.spec
@@ -27,6 +27,7 @@ BuildRequires: transifex-client
 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

