From d8c3b1156113e2f578a253f2849fcbaf6eb618d6 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Mon, 14 Jan 2013 13:24:23 -0600
Subject: [PATCH 08/10] Move tsort, platform, and baseudev into storage.

Merge baseudev into storage.udev.
---
 anaconda                                  |   2 +-
 pyanaconda/__init__.py                    |  13 +-
 pyanaconda/baseudev.py                    |  95 -------
 pyanaconda/bootloader.py                  |  61 +++--
 pyanaconda/installclass.py                |   3 +-
 pyanaconda/kickstart.py                   |   1 -
 pyanaconda/packaging/__init__.py          |  11 +-
 pyanaconda/platform.py                    | 411 ------------------------------
 pyanaconda/pyudev.py                      | 232 -----------------
 pyanaconda/rescue.py                      |   4 +-
 pyanaconda/storage/__init__.py            |  27 +-
 pyanaconda/storage/dasd.py                |   2 +-
 pyanaconda/storage/devicetree.py          |   8 +-
 pyanaconda/storage/fcoe.py                |   2 +-
 pyanaconda/storage/formats/__init__.py    |   2 +-
 pyanaconda/storage/formats/biosboot.py    |   4 +-
 pyanaconda/storage/formats/fs.py          |   8 +-
 pyanaconda/storage/formats/prepboot.py    |   4 +-
 pyanaconda/storage/partitioning.py        |   3 -
 pyanaconda/storage/platform.py            | 409 +++++++++++++++++++++++++++++
 pyanaconda/storage/pyudev.py              | 232 +++++++++++++++++
 pyanaconda/storage/tsort.py               | 105 ++++++++
 pyanaconda/storage/udev.py                |  69 ++++-
 pyanaconda/tsort.py                       | 105 --------
 pyanaconda/ui/gui/spokes/storage.py       |   3 +-
 pyanaconda/ui/gui/tools/run-spoke.py      |   4 +-
 pyanaconda/ui/tui/tools/run-text-spoke.py |   4 +-
 tests/kickstart_test/commands_test.py     |   4 +-
 tests/pyanaconda_test/Makefile.am         |   1 -
 tests/pyanaconda_test/baseudev_test.py    | 139 ----------
 tests/storage_test/storagetestcase.py     |   2 +-
 tests/storage_test/tsort_test.py          |  62 +++++
 tests/storage_test/udev_test.py           | 139 ++++++++++
 tests/tsort_test.py                       |  62 -----
 34 files changed, 1083 insertions(+), 1150 deletions(-)
 delete mode 100644 pyanaconda/baseudev.py
 delete mode 100644 pyanaconda/platform.py
 delete mode 100644 pyanaconda/pyudev.py
 create mode 100644 pyanaconda/storage/platform.py
 create mode 100644 pyanaconda/storage/pyudev.py
 create mode 100644 pyanaconda/storage/tsort.py
 delete mode 100644 pyanaconda/tsort.py
 delete mode 100644 tests/pyanaconda_test/baseudev_test.py
 create mode 100644 tests/storage_test/tsort_test.py
 create mode 100644 tests/storage_test/udev_test.py
 delete mode 100644 tests/tsort_test.py

diff --git a/anaconda b/anaconda
index 8de01c5..1891053 100755
--- a/anaconda
+++ b/anaconda
@@ -981,7 +981,7 @@ if __name__ == "__main__":
 
     if anaconda.rescue:
         from pyanaconda.rescue import doRescue
-        doRescue(anaconda.rescue_mount, ksdata, anaconda.platform)
+        doRescue(anaconda.rescue_mount, ksdata)
 
     threadMgr.add(AnacondaThread(name="AnaStorageThread", target=storageInitialize, args=(anaconda.storage, ksdata, anaconda.protected)))
     threadMgr.add(AnacondaThread(name="AnaNetworkThread", target=networkInitialize, args=(ksdata,)))
diff --git a/pyanaconda/__init__.py b/pyanaconda/__init__.py
index 0b8119b..4767080 100644
--- a/pyanaconda/__init__.py
+++ b/pyanaconda/__init__.py
@@ -63,7 +63,6 @@ class Anaconda(object):
         self._network = None
         self.opts = None
         self._payload = None
-        self._platform = None
         self.proxy = None
         self.proxyUsername = None
         self.proxyPassword = None
@@ -87,7 +86,7 @@ class Anaconda(object):
     @property
     def bootloader(self):
         if not self._bootloader:
-            self._bootloader = get_bootloader(self.platform)
+            self._bootloader = get_bootloader()
 
         return self._bootloader
 
@@ -141,14 +140,6 @@ class Anaconda(object):
         return self._payload
 
     @property
-    def platform(self):
-        if not self._platform:
-            from pyanaconda import platform
-            self._platform = platform.getPlatform()
-
-        return self._platform
-
-    @property
     def protected(self):
         import stat
 
@@ -165,7 +156,7 @@ class Anaconda(object):
     def storage(self):
         if not self._storage:
             import storage
-            self._storage = storage.Storage(data=self.ksdata, platform=self.platform)
+            self._storage = storage.Storage(data=self.ksdata)
 
         return self._storage
 
diff --git a/pyanaconda/baseudev.py b/pyanaconda/baseudev.py
deleted file mode 100644
index cd8d016..0000000
--- a/pyanaconda/baseudev.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# udev.py
-# Python module for querying the udev database for device information.
-#
-# Copyright (C) 2009  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-# Public License for more details.  You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): Dave Lehman <dlehman@redhat.com>
-#                    Chris Lumens <clumens@redhat.com>
-#
-
-import iutil
-import os
-
-import pyudev
-global_udev = pyudev.Udev()
-
-import logging
-log = logging.getLogger("storage")
-
-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)
-
-    return dev
-
-def udev_get_devices(deviceClass="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
-
-def udev_settle():
-    # wait maximal 300 seconds for udev to be done running blkid, lvm,
-    # mdadm etc. This large timeout is needed when running on machines with
-    # lots of disks, or with slow disks
-    argv = ["settle", "--timeout=300"]
-
-    iutil.execWithRedirect("udevadm", argv)
-
-def udev_trigger(subsystem=None, action="add", name=None):
-    argv = ["trigger", "--action=%s" % action]
-    if subsystem:
-        argv.append("--subsystem-match=%s" % subsystem)
-    if name:
-        argv.append("--sysname-match=%s" % name)
-
-    iutil.execWithRedirect("udevadm", argv)
-    udev_settle()
diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
index bb92444..be7a019 100644
--- a/pyanaconda/bootloader.py
+++ b/pyanaconda/bootloader.py
@@ -36,7 +36,7 @@ from pyanaconda.constants import *
 from pyanaconda.storage.errors import StorageError
 from pyanaconda.storage.fcoe import fcoe
 import pyanaconda.network
-from pyanaconda import platform as _platform
+from pyanaconda.storage import platform
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
@@ -247,10 +247,7 @@ class BootLoader(object):
 
     _trusted_boot = False
 
-    def __init__(self, platform=None):
-        # pyanaconda.platform.Platform instance
-        self.platform = platform
-
+    def __init__(self):
         self.boot_args = Arguments()
         self.dracut_args = Arguments()
 
@@ -368,11 +365,11 @@ class BootLoader(object):
     #
     @property
     def disklabel_types(self):
-        return self.platform._disklabel_types
+        return platform.platform._disklabel_types
 
     @property
     def device_descriptions(self):
-        return self.platform.bootStage1ConstraintDict["descriptions"]
+        return platform.platform.bootStage1ConstraintDict["descriptions"]
 
     #
     # constraint checking for target devices
@@ -553,7 +550,7 @@ class BootLoader(object):
         self.errors = []
         self.warnings = []
         valid = True
-        constraint = self.platform.bootStage1ConstraintDict
+        constraint = platform.platform.bootStage1ConstraintDict
 
         if device is None:
             return False
@@ -696,7 +693,7 @@ class BootLoader(object):
                                      desc=self.stage2_description):
             valid = False
 
-        non_linux_format_types = self.platform._non_linux_format_types
+        non_linux_format_types = platform.platform._non_linux_format_types
         if non_linux and \
            not self._is_valid_format(device,
                                      format_types=non_linux_format_types):
@@ -979,8 +976,8 @@ class GRUB(BootLoader):
 
     packages = ["grub"]
 
-    def __init__(self, platform=None):
-        super(GRUB, self).__init__(platform=platform)
+    def __init__(self):
+        super(GRUB, self).__init__()
         self.encrypted_password = ""
 
     #
@@ -1355,8 +1352,8 @@ class GRUB2(GRUB):
     stage2_raid_levels = [mdraid.RAID0, mdraid.RAID1, mdraid.RAID4,
                           mdraid.RAID5, mdraid.RAID6, mdraid.RAID10]
 
-    def __init__(self, platform=None):
-        super(GRUB2, self).__init__(platform=platform)
+    def __init__(self):
+        super(GRUB2, self).__init__()
         self.boot_args.add("$([ -x /usr/sbin/rhcrashkernel-param ] && "\
                            "/usr/sbin/rhcrashkernel-param || :)")
 
@@ -1597,8 +1594,8 @@ class EFIGRUB(GRUB2):
     def _config_dir(self):
         return "efi/EFI/%s" % (self.efi_dir,)
 
-    def __init__(self, platform=None):
-        super(EFIGRUB, self).__init__(platform=platform)
+    def __init__(self):
+        super(EFIGRUB, self).__init__()
         self.efi_dir = 'BOOT'
 
     def efibootmgr(self, *args, **kwargs):
@@ -1986,8 +1983,8 @@ class ZIPL(BootLoader):
     image_label_attr = "short_label"
     preserve_args = ["cio_ignore"]
 
-    def __init__(self, platform=None):
-        super(ZIPL, self).__init__(platform=platform)
+    def __init__(self):
+        super(ZIPL, self).__init__()
         self.stage1_name = None
 
     #
@@ -2176,22 +2173,22 @@ class UBOOT(BootLoader):
 
 
 # every platform that wants a bootloader needs to be in this dict
-bootloader_by_platform = {_platform.X86: GRUB2,
-                          _platform.EFI: EFIGRUB,
-                          _platform.MacEFI: MacEFIGRUB,
-                          _platform.PPC: GRUB2,
-                          _platform.IPSeriesPPC: IPSeriesGRUB2,
-                          _platform.NewWorldPPC: MacYaboot,
-                          _platform.S390: ZIPL,
-                          _platform.Sparc: SILO,
-                          _platform.ARM: UBOOT,
-                          _platform.omapARM: UBOOT}
-
-def get_bootloader(platform):
-    platform_name = platform.__class__.__name__
-    cls = bootloader_by_platform.get(platform.__class__, BootLoader)
+bootloader_by_platform = {platform.X86: GRUB2,
+                          platform.EFI: EFIGRUB,
+                          platform.MacEFI: MacEFIGRUB,
+                          platform.PPC: GRUB2,
+                          platform.IPSeriesPPC: IPSeriesGRUB2,
+                          platform.NewWorldPPC: MacYaboot,
+                          platform.S390: ZIPL,
+                          platform.Sparc: SILO,
+                          platform.ARM: UBOOT,
+                          platform.omapARM: UBOOT}
+
+def get_bootloader():
+    platform_name = platform.platform.__class__.__name__
+    cls = bootloader_by_platform.get(platform.platform.__class__, BootLoader)
     log.info("bootloader %s on %s platform" % (cls.__name__, platform_name))
-    return cls(platform)
+    return cls()
 
 
 # anaconda-specific functions
diff --git a/pyanaconda/installclass.py b/pyanaconda/installclass.py
index 2e817f2..888d081 100644
--- a/pyanaconda/installclass.py
+++ b/pyanaconda/installclass.py
@@ -32,6 +32,7 @@ from constants import *
 from product import *
 from storage.partspec import *
 from storage.devicelibs import swap
+from storage.platform import platform
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
@@ -105,7 +106,7 @@ class BaseInstallClass(object):
                                  size=500, grow=True, requiredSpace=50*1024,
                                  btr=True, lv=True, encrypted=True)]
 
-        bootreqs = storage.platform.setDefaultPartitioning()
+        bootreqs = platform.setDefaultPartitioning()
         if bootreqs:
             autorequests.extend(bootreqs)
 
diff --git a/pyanaconda/kickstart.py b/pyanaconda/kickstart.py
index f177cf4..b2abfaa 100644
--- a/pyanaconda/kickstart.py
+++ b/pyanaconda/kickstart.py
@@ -43,7 +43,6 @@ import shlex
 import sys
 import urlgrabber
 import pykickstart.commands as commands
-from storage.devices import *
 from pyanaconda.storage import arch
 from pyanaconda import keyboard
 from pyanaconda import ntp
diff --git a/pyanaconda/packaging/__init__.py b/pyanaconda/packaging/__init__.py
index 0ec42e8..57e982a 100644
--- a/pyanaconda/packaging/__init__.py
+++ b/pyanaconda/packaging/__init__.py
@@ -55,6 +55,7 @@ from pyanaconda.errors import *
 from pyanaconda.storage.errors import StorageError
 from pyanaconda.storage import util
 from pyanaconda.storage import arch
+from pyanaconda.storage.platform import platform
 #from pyanaconda.progress import progress
 
 from pyanaconda.product import productName, productVersion
@@ -655,8 +656,8 @@ class PackagePayload(Payload):
 
         # most ARM systems use platform-specific kernels
         if arch.isARM():
-            if self.storage.platform.armMachine is not None:
-                kernels = ["kernel-%s" % self.storage.platform.armMachine]
+            if platform.armMachine is not None:
+                kernels = ["kernel-%s" % platform.armMachine]
 
         return kernels
 
@@ -721,7 +722,6 @@ if __name__ == "__main__":
     import os
     import sys
     import pyanaconda.storage as _storage
-    import pyanaconda.platform as _platform
     from pykickstart.version import makeVersion
     from pyanaconda.packaging.yumpayload import YumPayload
 
@@ -735,9 +735,8 @@ if __name__ == "__main__":
     #ksdata.method.url = "http://husky/install/f17/os/"
     #ksdata.method.url = "http://dl.fedoraproject.org/pub/fedora/linux/development/17/x86_64/os/"
 
-    # set up storage and platform
-    platform = _platform.getPlatform()
-    storage = _storage.Storage(data=ksdata, platform=platform)
+    # set up storage
+    storage = _storage.Storage(data=ksdata)
     storage.reset()
 
     # set up the payload
diff --git a/pyanaconda/platform.py b/pyanaconda/platform.py
deleted file mode 100644
index 39b49ec..0000000
--- a/pyanaconda/platform.py
+++ /dev/null
@@ -1,411 +0,0 @@
-#
-# platform.py:  Architecture-specific information
-#
-# Copyright (C) 2009-2011
-# Red Hat, Inc.  All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Authors: Chris Lumens <clumens@redhat.com>
-#
-import os
-import logging
-log = logging.getLogger("anaconda")
-
-import parted
-
-from pyanaconda.storage import arch
-
-from flags import flags
-
-import gettext
-_ = lambda x: gettext.ldgettext("anaconda", x)
-N_ = lambda x: x
-
-class Platform(object):
-    """Platform
-
-       A class containing platform-specific information and methods for use
-       during installation.  The intent is to eventually encapsulate all the
-       architecture quirks in one place to avoid lots of platform checks
-       throughout anaconda."""
-    _minimumSector = 0
-    _packages = []
-
-    # requirements for bootloader stage1 devices
-    _boot_stage1_device_types = []
-    _boot_stage1_format_types = []
-    _boot_stage1_mountpoints = []
-    _boot_stage1_max_end_mb = None
-    _boot_stage1_raid_levels = []
-    _boot_stage1_raid_metadata = []
-    _boot_stage1_raid_member_types = []
-    _boot_stage1_description = N_("bootloader device")
-    _boot_raid_description = N_("RAID Device")
-    _boot_partition_description = N_("First sector of boot partition")
-    _boot_descriptions = {}
-
-    _disklabel_types = []
-    _non_linux_format_types = []
-
-    def __init__(self):
-        """Creates a new Platform object.  This is basically an abstract class.
-           You should instead use one of the platform-specific classes as
-           returned by getPlatform below.  Not all subclasses need to provide
-           all the methods in this class."""
-
-        if flags.gpt and "gpt" in self._disklabel_types:
-            # move GPT to the top of the list
-            self._disklabel_types.remove("gpt")
-            self._disklabel_types.insert(0, "gpt")
-
-    @property
-    def diskLabelTypes(self):
-        """A list of valid disklabel types for this architecture."""
-        return self._disklabel_types
-
-    @property
-    def defaultDiskLabelType(self):
-        """The default disklabel type for this architecture."""
-        return self.diskLabelTypes[0]
-
-    @property
-    def bootStage1ConstraintDict(self):
-        d = {"device_types": self._boot_stage1_device_types,
-             "format_types": self._boot_stage1_format_types,
-             "mountpoints": self._boot_stage1_mountpoints,
-             "max_end_mb": self._boot_stage1_max_end_mb,
-             "raid_levels": self._boot_stage1_raid_levels,
-             "raid_metadata": self._boot_stage1_raid_metadata,
-             "raid_member_types": self._boot_stage1_raid_member_types,
-             "descriptions": self._boot_descriptions}
-        return d
-
-    def requiredDiskLabelType(self, device_type):
-        return None
-
-    def bestDiskLabelType(self, device):
-        """The best disklabel type for the specified device."""
-        if flags.testing:
-            return self.defaultDiskLabelType
-
-        # if there's a required type for this device type, use that
-        labelType = self.requiredDiskLabelType(device.partedDevice.type)
-        log.debug("required disklabel type for %s (%s) is %s"
-                  % (device.name, device.partedDevice.type, labelType))
-        if not labelType:
-            # otherwise, use the first supported type for this platform
-            # that is large enough to address the whole device
-            labelType = self.defaultDiskLabelType
-            log.debug("default disklabel type for %s is %s" % (device.name,
-                                                               labelType))
-            for lt in self.diskLabelTypes:
-                l = parted.freshDisk(device=device.partedDevice, ty=lt)
-                if l.maxPartitionStartSector > device.partedDevice.length:
-                    labelType = lt
-                    log.debug("selecting %s disklabel for %s based on size"
-                              % (labelType, device.name))
-                    break
-
-        return labelType
-
-    @property
-    def minimumSector(self, disk):
-        """Return the minimum starting sector for the provided disk."""
-        return self._minimumSector
-
-    @property
-    def packages (self):
-        _packages = self._packages
-        if flags.cmdline.get('fips', None) == '1':
-            _packages.append('dracut-fips')
-        return _packages
-
-    def setDefaultPartitioning(self):
-        """Return the default platform-specific partitioning information."""
-        from storage.partspec import PartSpec
-        return [PartSpec(mountpoint="/boot",
-                         size=500, weight=self.weight(mountpoint="/boot"))]
-
-    def weight(self, fstype=None, mountpoint=None):
-        """ Given an fstype (as a string) or a mountpoint, return an integer
-            for the base sorting weight.  This is used to modify the sort
-            algorithm for partition requests, mainly to make sure bootable
-            partitions and /boot are placed where they need to be."""
-        if mountpoint == "/boot":
-            return 2000
-        else:
-            return 0
-
-class X86(Platform):
-    _boot_stage1_device_types = ["disk"]
-    _boot_mbr_description = N_("Master Boot Record")
-    _boot_descriptions = {"disk": _boot_mbr_description,
-                          "partition": Platform._boot_partition_description,
-                          "mdarray": Platform._boot_raid_description}
-
-
-    _disklabel_types = ["msdos", "gpt"]
-    # XXX hpfs, if reported by blkid/udev, will end up with a type of None
-    _non_linux_format_types = ["vfat", "ntfs", "hpfs"]
-
-    def __init__(self):
-        super(X86, self).__init__()
-
-    def setDefaultPartitioning(self):
-        """Return the default platform-specific partitioning information."""
-        from storage.partspec import PartSpec
-        ret = Platform.setDefaultPartitioning(self)
-        ret.append(PartSpec(fstype="biosboot", size=1,
-                            weight=self.weight(fstype="biosboot")))
-        return ret
-
-    def weight(self, fstype=None, mountpoint=None):
-        score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
-        if score:
-            return score
-        elif fstype == "biosboot":
-            return 5000
-        else:
-            return 0
-
-class EFI(Platform):
-
-    _boot_stage1_format_types = ["efi"]
-    _boot_stage1_device_types = ["partition"]
-    _boot_stage1_mountpoints = ["/boot/efi"]
-    _boot_efi_description = N_("EFI System Partition")
-    _boot_descriptions = {"partition": _boot_efi_description,
-                          "mdarray": Platform._boot_raid_description}
-
-    _disklabel_types = ["gpt"]
-    # XXX hpfs, if reported by blkid/udev, will end up with a type of None
-    _non_linux_format_types = ["vfat", "ntfs", "hpfs"]
-
-    def setDefaultPartitioning(self):
-        from storage.partspec import PartSpec
-        ret = Platform.setDefaultPartitioning(self)
-        ret.append(PartSpec(mountpoint="/boot/efi", fstype="efi", size=20,
-                            maxSize=200,
-                            grow=True, weight=self.weight(fstype="efi")))
-        return ret
-
-    def weight(self, fstype=None, mountpoint=None):
-        score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
-        if score:
-            return score
-        elif fstype == "efi" or mountpoint == "/boot/efi":
-            return 5000
-        else:
-            return 0
-
-class MacEFI(EFI):
-    _boot_stage1_format_types = ["hfs+"]
-    _boot_efi_description = N_("Apple EFI Boot Partition")
-    _non_linux_format_types = ["hfs+"]
-    _packages = ["mactel-boot"]
-
-    def setDefaultPartitioning(self):
-        from storage.partspec import PartSpec
-        ret = Platform.setDefaultPartitioning(self)
-        ret.append(PartSpec(mountpoint="/boot/efi", fstype="hfs+", size=20,
-                            maxSize=200,
-                            grow=True, weight=self.weight(mountpoint="/boot/efi")))
-        return ret
-
-class PPC(Platform):
-    _ppcMachine = arch.getPPCMachine()
-    _boot_stage1_device_types = ["partition"]
-
-    @property
-    def ppcMachine(self):
-        return self._ppcMachine
-
-class IPSeriesPPC(PPC):
-    _boot_stage1_format_types = ["prepboot"]
-    _boot_stage1_max_end_mb = 10
-    _boot_prep_description = N_("PReP Boot Partition")
-    _boot_descriptions = {"partition": _boot_prep_description}
-    _disklabel_types = ["msdos"]
-
-    def setDefaultPartitioning(self):
-        from storage.partspec import PartSpec
-        ret = PPC.setDefaultPartitioning(self)
-        ret.append(PartSpec(fstype="prepboot", size=4,
-                            weight=self.weight(fstype="prepboot")))
-        return ret
-
-    def weight(self, fstype=None, mountpoint=None):
-        score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
-        if score:
-            return score
-        elif fstype == "prepboot":
-            return 5000
-        else:
-            return 0
-
-class NewWorldPPC(PPC):
-    _boot_stage1_format_types = ["appleboot"]
-    _boot_apple_description = N_("Apple Bootstrap Partition")
-    _boot_descriptions = {"partition": _boot_apple_description}
-    _disklabel_types = ["mac"]
-    _non_linux_format_types = ["hfs", "hfs+"]
-
-    def setDefaultPartitioning(self):
-        from storage.partspec import PartSpec
-        ret = Platform.setDefaultPartitioning(self)
-        ret.append(PartSpec(fstype="appleboot", size=1, maxSize=1,
-                            weight=self.weight(fstype="appleboot")))
-        return ret
-
-    def weight(self, fstype=None, mountpoint=None):
-        score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
-        if score:
-            return score
-        elif fstype == "appleboot":
-            return 5000
-        else:
-            return 0
-
-class PS3(PPC):
-    pass
-
-class S390(Platform):
-    _packages = ["s390utils"]
-    _disklabel_types = ["msdos", "dasd"]
-    _boot_stage1_device_types = ["disk", "partition"]
-    _boot_dasd_description = N_("DASD")
-    _boot_zfcp_description = N_("zFCP")
-    _boot_descriptions = {"dasd": _boot_dasd_description,
-                          "zfcp": _boot_zfcp_description,
-                          "partition": Platform._boot_partition_description}
-
-    def __init__(self):
-        Platform.__init__(self)
-
-    def setDefaultPartitioning(self):
-        """Return the default platform-specific partitioning information."""
-        from storage.partspec import PartSpec
-        return [PartSpec(mountpoint="/boot", size=500,
-                         weight=self.weight(mountpoint="/boot"), lv=True,
-                         singlePV=True)]
-
-    def requiredDiskLabelType(self, device_type):
-        """The required disklabel type for the specified device type."""
-        if device_type == parted.DEVICE_DASD:
-            return "dasd"
-
-        return super(S390, self).requiredDiskLabelType(device_type)
-
-class Sparc(Platform):
-    _boot_stage1_format_types = []
-    _boot_stage1_mountpoints = []
-    _boot_stage1_max_end_mb = None
-    _disklabel_types = ["sun"]
-
-    @property
-    def minimumSector(self, disk):
-        (cylinders, heads, sectors) = disk.device.biosGeometry
-        start = long(sectors * heads)
-        start /= long(1024 / disk.device.sectorSize)
-        return start+1
-
-class ARM(Platform):
-    _armMachine = None
-    _boot_stage1_device_types = ["disk"]
-    _boot_mbr_description = N_("Master Boot Record")
-    _boot_descriptions = {"disk": _boot_mbr_description,
-                          "partition": Platform._boot_partition_description}
-
-    _disklabel_types = ["msdos"]
-
-    @property
-    def armMachine(self):
-        if not self._armMachine:
-            self._armMachine = arch.getARMMachine()
-        return self._armMachine
-
-    def weight(self, fstype=None, mountpoint=None):
-        """Return the ARM platform-specific weight for the / partition.
-           On ARM images '/' must be the last partition, so we try to
-           weight it accordingly."""
-        if mountpoint == "/":
-            return -100
-        else:
-            return Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
-
-class omapARM(ARM):
-    _boot_stage1_format_types = ["vfat"]
-    _boot_stage1_device_types = ["partition"]
-    _boot_stage1_mountpoints = ["/boot/uboot"]
-    _boot_uboot_description = N_("U-Boot Partition")
-    _boot_descriptions = {"partition": _boot_uboot_description}
-
-    def setDefaultPartitioning(self):
-        """Return the ARM-OMAP platform-specific partitioning information."""
-        from storage.partspec import PartSpec
-        ret = [PartSpec(mountpoint="/boot/uboot", fstype="vfat",
-                        size=20, maxSize=200, grow=True,
-                        weight=self.weight(fstype="vfat", mountpoint="/boot/uboot"))]
-        ret.append(PartSpec(mountpoint="/", fstype="ext4",
-                            size=2000, maxSize=3000,
-                            weight=self.weight(mountpoint="/")))
-        return ret
-
-    def weight(self, fstype=None, mountpoint=None):
-        """Return the ARM-OMAP platform-specific weights for the uboot
-           and / partitions.  On OMAP, uboot must be the first partition,
-           and '/' must be the last partition, so we try to weight them
-           accordingly."""
-        if fstype == "vfat" and mountpoint == "/boot/uboot":
-            return 6000
-        elif mountpoint == "/":
-            return -100
-        else:
-            return Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
-
-def getPlatform():
-    """Check the architecture of the system and return an instance of a
-       Platform subclass to match.  If the architecture could not be determined,
-       raise an exception."""
-    if arch.isPPC():
-        ppcMachine = arch.getPPCMachine()
-
-        if (ppcMachine == "PMac" and arch.getPPCMacGen() == "NewWorld"):
-            return NewWorldPPC()
-        elif ppcMachine in ["iSeries", "pSeries"]:
-            return IPSeriesPPC()
-        elif ppcMachine == "PS3":
-            return PS3()
-        else:
-            raise SystemError, "Unsupported PPC machine type: %s" % ppcMachine
-    elif arch.isS390():
-        return S390()
-    elif arch.isSparc():
-        return Sparc()
-    elif arch.isEfi():
-        if arch.isMactel():
-            return MacEFI()
-        else:
-            return EFI()
-    elif arch.isX86():
-        return X86()
-    elif arch.isARM():
-        armMachine = arch.getARMMachine()
-        if armMachine == "omap":
-            return omapARM()
-        else:
-            return ARM()
-    else:
-        raise SystemError, "Could not determine system architecture."
diff --git a/pyanaconda/pyudev.py b/pyanaconda/pyudev.py
deleted file mode 100644
index 705b93d..0000000
--- a/pyanaconda/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/pyanaconda/rescue.py b/pyanaconda/rescue.py
index ed06592..2fc5722 100644
--- a/pyanaconda/rescue.py
+++ b/pyanaconda/rescue.py
@@ -191,7 +191,7 @@ def runShell(screen = None, msg=""):
     if screen:
         screen.finish()
 
-def doRescue(rescue_mount, ksdata, platform):
+def doRescue(rescue_mount, ksdata):
     import storage
 
     for file in [ "services", "protocols", "group", "joe", "man.config",
@@ -242,7 +242,7 @@ def doRescue(rescue_mount, ksdata, platform):
 
             break
 
-    sto = storage.Storage(ksdata, platform)
+    sto = storage.Storage(ksdata)
     storage.storageInitialize(sto, ksdata, [])
     roots = storage.findExistingInstallations(sto.devicetree)
 
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py
index f6cd380..bc973e3 100644
--- a/pyanaconda/storage/__init__.py
+++ b/pyanaconda/storage/__init__.py
@@ -41,7 +41,6 @@ import nss.nss
 import parted
 
 from pykickstart.constants import *
-from pyanaconda import tsort
 
 from storage_log import log_method_call
 from errors import *
@@ -69,6 +68,7 @@ import dasd
 import util
 import arch
 from flags import flags
+from platform import platform as _platform
 
 import shelve
 import contextlib
@@ -278,17 +278,14 @@ class StorageDiscoveryConfig(object):
         self.zeroMbr = ksdata.zerombr.zerombr
 
 class Storage(object):
-    def __init__(self, data=None, platform=None):
+    def __init__(self, data=None):
         """ Create a Storage instance.
 
             Keyword Arguments:
 
                 data        -   a pykickstart Handler instance
-                platform    -   a Platform instance
-
         """
         self.data = data
-        self.platform = platform
         self._bootloader = None
 
         self.config = StorageDiscoveryConfig()
@@ -784,9 +781,6 @@ class Storage(object):
                 - Needs some error handling
 
         """
-        if not hasattr(self.platform, "diskLabelTypes"):
-            raise StorageError("can't clear partitions without platform data")
-
         # Sort partitions by descending partition number to minimize confusing
         # things like multiple "destroy sda5" actions due to parted renumbering
         # partitions. This can still happen through the UI but it makes sense to
@@ -842,10 +836,7 @@ class Storage(object):
         destroy_action = ActionDestroyFormat(disk)
         self.devicetree.registerAction(destroy_action)
 
-        if self.platform:
-            labelType = self.platform.bestDiskLabelType(disk)
-        else:
-            labelType = None
+        labelType = _platform.bestDiskLabelType(disk)
 
         # create a new disklabel on the disk
         newLabel = getFormat("disklabel", device=disk.path,
@@ -1049,7 +1040,7 @@ class Storage(object):
             if fmt:
                 mountpoint = getattr(fmt, "mountpoint", None)
 
-                kwargs["weight"] = self.platform.weight(mountpoint=mountpoint,
+                kwargs["weight"] = _platform.weight(mountpoint=mountpoint,
                                                         fstype=fmt.type)
 
 
@@ -1569,7 +1560,7 @@ class Storage(object):
             #
             # check that GPT boot disk on BIOS system has a BIOS boot partition
             #
-            if self.platform.weight(fstype="biosboot") and \
+            if _platform.weight(fstype="biosboot") and \
                stage1 and stage1.isDisk and \
                getattr(stage1.format, "labelType", None) == "gpt":
                 missing = True
@@ -1645,8 +1636,7 @@ class Storage(object):
     @property
     def packages(self):
         pkgs = set()
-        if self.platform:
-            pkgs.update(self.platform.packages)
+        pkgs.update(_platform.packages)
 
         if self.bootloader:
             pkgs.update(self.bootloader.packages)
@@ -1691,9 +1681,8 @@ class Storage(object):
 
     @property
     def bootloader(self):
-        if self._bootloader is None and self.platform is not None and \
-           flags.installer_mode:
-            self._bootloader = get_bootloader(self.platform)
+        if self._bootloader is None and flags.installer_mode:
+            self._bootloader = get_bootloader()
 
         return self._bootloader
 
diff --git a/pyanaconda/storage/dasd.py b/pyanaconda/storage/dasd.py
index abf97b9..bd3d4de 100644
--- a/pyanaconda/storage/dasd.py
+++ b/pyanaconda/storage/dasd.py
@@ -26,7 +26,7 @@ from pyanaconda.storage.devices import deviceNameToDiskByPath
 from pyanaconda.storage import util
 from pyanaconda.storage import arch
 from . import ROOT_PATH
-from pyanaconda.baseudev import udev_trigger
+from .udev import udev_trigger
 
 import logging
 log = logging.getLogger("storage")
diff --git a/pyanaconda/storage/devicetree.py b/pyanaconda/storage/devicetree.py
index dff17ae..106b397 100644
--- a/pyanaconda/storage/devicetree.py
+++ b/pyanaconda/storage/devicetree.py
@@ -41,8 +41,8 @@ import devicelibs.loop
 import devicelibs.edd
 from udev import *
 import util
-from pyanaconda import platform
-from pyanaconda import tsort
+from platform import platform
+import tsort
 from flags import flags
 from storage_log import log_method_call, log_method_return
 import parted
@@ -177,8 +177,6 @@ class DeviceTree(object):
         self.dasd = dasd
         self.mpathFriendlyNames = getattr(conf, "mpathFriendlyNames", True)
 
-        self.platform = platform.getPlatform()
-
         self.diskImages = {}
         images = getattr(conf, "diskImages", {})
         if images:
@@ -1144,7 +1142,7 @@ class DeviceTree(object):
 
         # we're going to pass the "best" disklabel type into the DiskLabel
         # constructor, but it only has meaning for non-existent disklabels.
-        labelType = self.platform.bestDiskLabelType(device)
+        labelType = platform.bestDiskLabelType(device)
 
         try:
             format = getFormat("disklabel",
diff --git a/pyanaconda/storage/fcoe.py b/pyanaconda/storage/fcoe.py
index 22c6258..8e8e301 100644
--- a/pyanaconda/storage/fcoe.py
+++ b/pyanaconda/storage/fcoe.py
@@ -19,7 +19,7 @@
 
 import os
 from . import util
-from pyanaconda.baseudev import udev_settle
+from .udev import udev_settle
 #from pyanaconda import isys
 from . import ROOT_PATH
 import logging
diff --git a/pyanaconda/storage/formats/__init__.py b/pyanaconda/storage/formats/__init__.py
index 8a51cfe..62122fb 100644
--- a/pyanaconda/storage/formats/__init__.py
+++ b/pyanaconda/storage/formats/__init__.py
@@ -22,7 +22,7 @@
 
 import os
 
-from pyanaconda.baseudev import udev_get_device
+from ..udev import udev_get_device
 from ..util import notify_kernel
 from ..util import get_sysfs_path_by_name
 from ..util import run_program
diff --git a/pyanaconda/storage/formats/biosboot.py b/pyanaconda/storage/formats/biosboot.py
index 861b591..c3aef8d 100644
--- a/pyanaconda/storage/formats/biosboot.py
+++ b/pyanaconda/storage/formats/biosboot.py
@@ -23,6 +23,7 @@
 from parted import PARTITION_BIOS_GRUB
 
 from ..errors import *
+from .. import platform
 from . import DeviceFormat, register_device_format
 
 class BIOSBoot(DeviceFormat):
@@ -53,8 +54,7 @@ class BIOSBoot(DeviceFormat):
 
     @property
     def supported(self):
-        from pyanaconda import platform
-        return isinstance(platform.getPlatform(), platform.X86)
+        return isinstance(platform.platform, platform.X86)
 
 register_device_format(BIOSBoot)
 
diff --git a/pyanaconda/storage/formats/fs.py b/pyanaconda/storage/formats/fs.py
index 1d355c3..b472e87 100644
--- a/pyanaconda/storage/formats/fs.py
+++ b/pyanaconda/storage/formats/fs.py
@@ -35,6 +35,7 @@ import selinux
 from ..errors import *
 from . import DeviceFormat, register_device_format
 from .. import util
+from .. import platform
 from ..flags import flags
 from parted import fileSystemType
 from ..storage_log import log_method_call
@@ -975,9 +976,7 @@ class EFIFS(FATFS):
 
     @property
     def supported(self):
-        from pyanaconda import platform
-        p = platform.getPlatform()
-        return (isinstance(p, platform.EFI) and
+        return (isinstance(platform.platform, platform.EFI) and
                 self.utilsAvailable)
 
 register_device_format(EFIFS)
@@ -1210,8 +1209,7 @@ class AppleBootstrapFS(HFS):
 
     @property
     def supported(self):
-        from pyanaconda import platform
-        return (isinstance(platform.getPlatform(), platform.NewWorldPPC)
+        return (isinstance(platform.platform, platform.NewWorldPPC)
                 and self.utilsAvailable)
 
 register_device_format(AppleBootstrapFS)
diff --git a/pyanaconda/storage/formats/prepboot.py b/pyanaconda/storage/formats/prepboot.py
index 884aa8f..dd2cf8c 100644
--- a/pyanaconda/storage/formats/prepboot.py
+++ b/pyanaconda/storage/formats/prepboot.py
@@ -21,6 +21,7 @@
 #
 
 from ..errors import *
+from .. import platform
 from . import DeviceFormat, register_device_format
 from parted import PARTITION_PREP
 import os
@@ -80,8 +81,7 @@ class PPCPRePBoot(DeviceFormat):
 
     @property
     def supported(self):
-        from pyanaconda import platform
-        return isinstance(platform.getPlatform(), platform.IPSeriesPPC)
+        return isinstance(platform.platform, platform.IPSeriesPPC)
 
 register_device_format(PPCPRePBoot)
 
diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py
index 64aa250..243c62b 100644
--- a/pyanaconda/storage/partitioning.py
+++ b/pyanaconda/storage/partitioning.py
@@ -721,9 +721,6 @@ def doPartitioning(storage):
             None
 
     """
-    if not hasattr(storage.platform, "diskLabelTypes"):
-        raise StorageError(_("can't allocate partitions without platform data"))
-
     disks = storage.partitioned
     if storage.config.exclusiveDisks:
         disks = [d for d in disks if d.name in storage.config.exclusiveDisks]
diff --git a/pyanaconda/storage/platform.py b/pyanaconda/storage/platform.py
new file mode 100644
index 0000000..5221a30
--- /dev/null
+++ b/pyanaconda/storage/platform.py
@@ -0,0 +1,409 @@
+#
+# platform.py:  Architecture-specific information
+#
+# Copyright (C) 2009-2011
+# Red Hat, Inc.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Authors: Chris Lumens <clumens@redhat.com>
+#
+import os
+import logging
+log = logging.getLogger("storage")
+
+import parted
+
+from . import arch
+from .flags import flags
+from .partspec import PartSpec
+
+import gettext
+_ = lambda x: gettext.ldgettext("anaconda", x)
+N_ = lambda x: x
+
+class Platform(object):
+    """Platform
+
+       A class containing platform-specific information and methods for use
+       during installation.  The intent is to eventually encapsulate all the
+       architecture quirks in one place to avoid lots of platform checks
+       throughout anaconda."""
+    _minimumSector = 0
+    _packages = []
+
+    # requirements for bootloader stage1 devices
+    _boot_stage1_device_types = []
+    _boot_stage1_format_types = []
+    _boot_stage1_mountpoints = []
+    _boot_stage1_max_end_mb = None
+    _boot_stage1_raid_levels = []
+    _boot_stage1_raid_metadata = []
+    _boot_stage1_raid_member_types = []
+    _boot_stage1_description = N_("bootloader device")
+    _boot_raid_description = N_("RAID Device")
+    _boot_partition_description = N_("First sector of boot partition")
+    _boot_descriptions = {}
+
+    _disklabel_types = []
+    _non_linux_format_types = []
+
+    def __init__(self):
+        """Creates a new Platform object.  This is basically an abstract class.
+           You should instead use one of the platform-specific classes as
+           returned by getPlatform below.  Not all subclasses need to provide
+           all the methods in this class."""
+
+        if flags.gpt and "gpt" in self._disklabel_types:
+            # move GPT to the top of the list
+            self._disklabel_types.remove("gpt")
+            self._disklabel_types.insert(0, "gpt")
+
+    def __call__(self):
+        return self
+
+    @property
+    def diskLabelTypes(self):
+        """A list of valid disklabel types for this architecture."""
+        return self._disklabel_types
+
+    @property
+    def defaultDiskLabelType(self):
+        """The default disklabel type for this architecture."""
+        return self.diskLabelTypes[0]
+
+    @property
+    def bootStage1ConstraintDict(self):
+        d = {"device_types": self._boot_stage1_device_types,
+             "format_types": self._boot_stage1_format_types,
+             "mountpoints": self._boot_stage1_mountpoints,
+             "max_end_mb": self._boot_stage1_max_end_mb,
+             "raid_levels": self._boot_stage1_raid_levels,
+             "raid_metadata": self._boot_stage1_raid_metadata,
+             "raid_member_types": self._boot_stage1_raid_member_types,
+             "descriptions": self._boot_descriptions}
+        return d
+
+    def requiredDiskLabelType(self, device_type):
+        return None
+
+    def bestDiskLabelType(self, device):
+        """The best disklabel type for the specified device."""
+        if flags.testing:
+            return self.defaultDiskLabelType
+
+        # if there's a required type for this device type, use that
+        labelType = self.requiredDiskLabelType(device.partedDevice.type)
+        log.debug("required disklabel type for %s (%s) is %s"
+                  % (device.name, device.partedDevice.type, labelType))
+        if not labelType:
+            # otherwise, use the first supported type for this platform
+            # that is large enough to address the whole device
+            labelType = self.defaultDiskLabelType
+            log.debug("default disklabel type for %s is %s" % (device.name,
+                                                               labelType))
+            for lt in self.diskLabelTypes:
+                l = parted.freshDisk(device=device.partedDevice, ty=lt)
+                if l.maxPartitionStartSector > device.partedDevice.length:
+                    labelType = lt
+                    log.debug("selecting %s disklabel for %s based on size"
+                              % (labelType, device.name))
+                    break
+
+        return labelType
+
+    @property
+    def minimumSector(self, disk):
+        """Return the minimum starting sector for the provided disk."""
+        return self._minimumSector
+
+    @property
+    def packages (self):
+        _packages = self._packages
+        if flags.boot_cmdline.get('fips', None) == '1':
+            _packages.append('dracut-fips')
+        return _packages
+
+    def setDefaultPartitioning(self):
+        """Return the default platform-specific partitioning information."""
+        return [PartSpec(mountpoint="/boot",
+                         size=500, weight=self.weight(mountpoint="/boot"))]
+
+    def weight(self, fstype=None, mountpoint=None):
+        """ Given an fstype (as a string) or a mountpoint, return an integer
+            for the base sorting weight.  This is used to modify the sort
+            algorithm for partition requests, mainly to make sure bootable
+            partitions and /boot are placed where they need to be."""
+        if mountpoint == "/boot":
+            return 2000
+        else:
+            return 0
+
+class X86(Platform):
+    _boot_stage1_device_types = ["disk"]
+    _boot_mbr_description = N_("Master Boot Record")
+    _boot_descriptions = {"disk": _boot_mbr_description,
+                          "partition": Platform._boot_partition_description,
+                          "mdarray": Platform._boot_raid_description}
+
+
+    _disklabel_types = ["msdos", "gpt"]
+    # XXX hpfs, if reported by blkid/udev, will end up with a type of None
+    _non_linux_format_types = ["vfat", "ntfs", "hpfs"]
+
+    def __init__(self):
+        super(X86, self).__init__()
+
+    def setDefaultPartitioning(self):
+        """Return the default platform-specific partitioning information."""
+        ret = Platform.setDefaultPartitioning(self)
+        ret.append(PartSpec(fstype="biosboot", size=1,
+                            weight=self.weight(fstype="biosboot")))
+        return ret
+
+    def weight(self, fstype=None, mountpoint=None):
+        score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+        if score:
+            return score
+        elif fstype == "biosboot":
+            return 5000
+        else:
+            return 0
+
+class EFI(Platform):
+
+    _boot_stage1_format_types = ["efi"]
+    _boot_stage1_device_types = ["partition"]
+    _boot_stage1_mountpoints = ["/boot/efi"]
+    _boot_efi_description = N_("EFI System Partition")
+    _boot_descriptions = {"partition": _boot_efi_description,
+                          "mdarray": Platform._boot_raid_description}
+
+    _disklabel_types = ["gpt"]
+    # XXX hpfs, if reported by blkid/udev, will end up with a type of None
+    _non_linux_format_types = ["vfat", "ntfs", "hpfs"]
+
+    def setDefaultPartitioning(self):
+        ret = Platform.setDefaultPartitioning(self)
+        ret.append(PartSpec(mountpoint="/boot/efi", fstype="efi", size=20,
+                            maxSize=200,
+                            grow=True, weight=self.weight(fstype="efi")))
+        return ret
+
+    def weight(self, fstype=None, mountpoint=None):
+        score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+        if score:
+            return score
+        elif fstype == "efi" or mountpoint == "/boot/efi":
+            return 5000
+        else:
+            return 0
+
+class MacEFI(EFI):
+    _boot_stage1_format_types = ["hfs+"]
+    _boot_efi_description = N_("Apple EFI Boot Partition")
+    _non_linux_format_types = ["hfs+"]
+    _packages = ["mactel-boot"]
+
+    def setDefaultPartitioning(self):
+        ret = Platform.setDefaultPartitioning(self)
+        ret.append(PartSpec(mountpoint="/boot/efi", fstype="hfs+", size=20,
+                            maxSize=200,
+                            grow=True, weight=self.weight(mountpoint="/boot/efi")))
+        return ret
+
+class PPC(Platform):
+    _ppcMachine = arch.getPPCMachine()
+    _boot_stage1_device_types = ["partition"]
+
+    @property
+    def ppcMachine(self):
+        return self._ppcMachine
+
+class IPSeriesPPC(PPC):
+    _boot_stage1_format_types = ["prepboot"]
+    _boot_stage1_max_end_mb = 10
+    _boot_prep_description = N_("PReP Boot Partition")
+    _boot_descriptions = {"partition": _boot_prep_description}
+    _disklabel_types = ["msdos"]
+
+    def setDefaultPartitioning(self):
+        ret = PPC.setDefaultPartitioning(self)
+        ret.append(PartSpec(fstype="prepboot", size=4,
+                            weight=self.weight(fstype="prepboot")))
+        return ret
+
+    def weight(self, fstype=None, mountpoint=None):
+        score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+        if score:
+            return score
+        elif fstype == "prepboot":
+            return 5000
+        else:
+            return 0
+
+class NewWorldPPC(PPC):
+    _boot_stage1_format_types = ["appleboot"]
+    _boot_apple_description = N_("Apple Bootstrap Partition")
+    _boot_descriptions = {"partition": _boot_apple_description}
+    _disklabel_types = ["mac"]
+    _non_linux_format_types = ["hfs", "hfs+"]
+
+    def setDefaultPartitioning(self):
+        ret = Platform.setDefaultPartitioning(self)
+        ret.append(PartSpec(fstype="appleboot", size=1, maxSize=1,
+                            weight=self.weight(fstype="appleboot")))
+        return ret
+
+    def weight(self, fstype=None, mountpoint=None):
+        score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+        if score:
+            return score
+        elif fstype == "appleboot":
+            return 5000
+        else:
+            return 0
+
+class PS3(PPC):
+    pass
+
+class S390(Platform):
+    _packages = ["s390utils"]
+    _disklabel_types = ["msdos", "dasd"]
+    _boot_stage1_device_types = ["disk", "partition"]
+    _boot_dasd_description = N_("DASD")
+    _boot_zfcp_description = N_("zFCP")
+    _boot_descriptions = {"dasd": _boot_dasd_description,
+                          "zfcp": _boot_zfcp_description,
+                          "partition": Platform._boot_partition_description}
+
+    def __init__(self):
+        Platform.__init__(self)
+
+    def setDefaultPartitioning(self):
+        """Return the default platform-specific partitioning information."""
+        return [PartSpec(mountpoint="/boot", size=500,
+                         weight=self.weight(mountpoint="/boot"), lv=True,
+                         singlePV=True)]
+
+    def requiredDiskLabelType(self, device_type):
+        """The required disklabel type for the specified device type."""
+        if device_type == parted.DEVICE_DASD:
+            return "dasd"
+
+        return super(S390, self).requiredDiskLabelType(device_type)
+
+class Sparc(Platform):
+    _boot_stage1_format_types = []
+    _boot_stage1_mountpoints = []
+    _boot_stage1_max_end_mb = None
+    _disklabel_types = ["sun"]
+
+    @property
+    def minimumSector(self, disk):
+        (cylinders, heads, sectors) = disk.device.biosGeometry
+        start = long(sectors * heads)
+        start /= long(1024 / disk.device.sectorSize)
+        return start+1
+
+class ARM(Platform):
+    _armMachine = None
+    _boot_stage1_device_types = ["disk"]
+    _boot_mbr_description = N_("Master Boot Record")
+    _boot_descriptions = {"disk": _boot_mbr_description,
+                          "partition": Platform._boot_partition_description}
+
+    _disklabel_types = ["msdos"]
+
+    @property
+    def armMachine(self):
+        if not self._armMachine:
+            self._armMachine = arch.getARMMachine()
+        return self._armMachine
+
+    def weight(self, fstype=None, mountpoint=None):
+        """Return the ARM platform-specific weight for the / partition.
+           On ARM images '/' must be the last partition, so we try to
+           weight it accordingly."""
+        if mountpoint == "/":
+            return -100
+        else:
+            return Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+
+class omapARM(ARM):
+    _boot_stage1_format_types = ["vfat"]
+    _boot_stage1_device_types = ["partition"]
+    _boot_stage1_mountpoints = ["/boot/uboot"]
+    _boot_uboot_description = N_("U-Boot Partition")
+    _boot_descriptions = {"partition": _boot_uboot_description}
+
+    def setDefaultPartitioning(self):
+        """Return the ARM-OMAP platform-specific partitioning information."""
+        ret = [PartSpec(mountpoint="/boot/uboot", fstype="vfat",
+                        size=20, maxSize=200, grow=True,
+                        weight=self.weight(fstype="vfat", mountpoint="/boot/uboot"))]
+        ret.append(PartSpec(mountpoint="/", fstype="ext4",
+                            size=2000, maxSize=3000,
+                            weight=self.weight(mountpoint="/")))
+        return ret
+
+    def weight(self, fstype=None, mountpoint=None):
+        """Return the ARM-OMAP platform-specific weights for the uboot
+           and / partitions.  On OMAP, uboot must be the first partition,
+           and '/' must be the last partition, so we try to weight them
+           accordingly."""
+        if fstype == "vfat" and mountpoint == "/boot/uboot":
+            return 6000
+        elif mountpoint == "/":
+            return -100
+        else:
+            return Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+
+def getPlatform():
+    """Check the architecture of the system and return an instance of a
+       Platform subclass to match.  If the architecture could not be determined,
+       raise an exception."""
+    if arch.isPPC():
+        ppcMachine = arch.getPPCMachine()
+
+        if (ppcMachine == "PMac" and arch.getPPCMacGen() == "NewWorld"):
+            return NewWorldPPC()
+        elif ppcMachine in ["iSeries", "pSeries"]:
+            return IPSeriesPPC()
+        elif ppcMachine == "PS3":
+            return PS3()
+        else:
+            raise SystemError, "Unsupported PPC machine type: %s" % ppcMachine
+    elif arch.isS390():
+        return S390()
+    elif arch.isSparc():
+        return Sparc()
+    elif arch.isEfi():
+        if arch.isMactel():
+            return MacEFI()
+        else:
+            return EFI()
+    elif arch.isX86():
+        return X86()
+    elif arch.isARM():
+        armMachine = arch.getARMMachine()
+        if armMachine == "omap":
+            return omapARM()
+        else:
+            return ARM()
+    else:
+        raise SystemError, "Could not determine system architecture."
+
+global platform
+platform = getPlatform()
diff --git a/pyanaconda/storage/pyudev.py b/pyanaconda/storage/pyudev.py
new file mode 100644
index 0000000..705b93d
--- /dev/null
+++ b/pyanaconda/storage/pyudev.py
@@ -0,0 +1,232 @@
+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/pyanaconda/storage/tsort.py b/pyanaconda/storage/tsort.py
new file mode 100644
index 0000000..52a871f
--- /dev/null
+++ b/pyanaconda/storage/tsort.py
@@ -0,0 +1,105 @@
+#!/usr/bin/python
+# tsort.py
+# Topological sorting.
+#
+# Copyright (C) 2010  Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# the GNU General Public License v.2, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY expressed or implied, including the implied warranties of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.  You should have received a copy of the
+# GNU General Public License along with this program; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
+# source code or documentation are not subject to the GNU General Public
+# License and may only be used or replicated with the express permission of
+# Red Hat, Inc.
+#
+# Red Hat Author(s): Dave Lehman <dlehman@redhat.com>
+#
+
+class CyclicGraphError(Exception):
+    pass
+
+def tsort(graph):
+    order = []  # sorted list of items
+
+    if not graph or not graph['items']:
+        return order
+
+    # determine which nodes have no incoming edges
+    roots = [n for n in graph['items'] if graph['incoming'][n] == 0]
+    if not roots:
+        raise CyclicGraphError("no root nodes")
+
+    visited = []    # list of nodes visited, for cycle detection
+    while roots:
+        # remove a root, add it to the order
+        root = roots.pop()
+        if root in visited:
+            raise CyclicGraphError("graph contains cycles")
+
+        visited.append(root)
+        i = graph['items'].index(root)
+        order.append(root)
+        # remove each edge from the root to another node
+        for (parent, child) in [e for e in graph['edges'] if e[0] == root]:
+            graph['incoming'][child] -= 1
+            graph['edges'].remove((parent, child))
+            # if destination node is now a root, add it to roots
+            if graph['incoming'][child] == 0:
+                roots.append(child)
+
+    if len(graph['items']) != len(visited):
+        raise CyclicGraphError("graph contains cycles")
+
+
+    return order
+
+def create_graph(items, edges):
+    """ Create a graph based on a list of items and a list of edges.
+
+        Arguments:
+
+            items   -   an iterable containing (hashable) items to sort
+            edges   -   an iterable containing (parent, child) edge pair tuples
+
+        Return Value:
+
+            The return value is a dictionary representing the directed graph.
+            It has three keys:
+
+                items is the same as the input argument of the same name
+                edges is the same as the input argument of the same name
+                incoming is a dict of incoming edge count hashed by item
+
+    """
+    graph = {'items': [],       # the items to sort
+             'edges': [],       # partial order info: (parent, child) pairs
+             'incoming': {}}    # incoming edge count for each item
+
+    graph['items'] = items
+    graph['edges'] = edges
+    for item in items:
+        graph['incoming'][item] = 0
+
+    for (parent, child) in edges:
+        graph['incoming'][child] += 1
+
+    return graph 
+
+
+if __name__ == "__main__":
+
+    items = [5, 2, 3, 4, 1]
+    edges = [(1, 2), (2, 4), (4, 5), (3, 2)]
+
+    print items
+    print edges
+
+    graph = create_graph(items, edges)
+    print tsort(graph)
+
diff --git a/pyanaconda/storage/udev.py b/pyanaconda/storage/udev.py
index cb9601b..f8ba09c 100644
--- a/pyanaconda/storage/udev.py
+++ b/pyanaconda/storage/udev.py
@@ -1,7 +1,7 @@
 # udev.py
 # Python module for querying the udev database for device information.
 #
-# Copyright (C) 2009  Red Hat, Inc.
+# Copyright (C) 2009, 2013  Red Hat, Inc.
 #
 # This copyrighted material is made available to anyone wishing to use,
 # modify, copy, or redistribute it subject to the terms and conditions of
@@ -18,6 +18,7 @@
 # Red Hat, Inc.
 #
 # Red Hat Author(s): Dave Lehman <dlehman@redhat.com>
+#                    Chris Lumens <clumens@redhat.com>
 #
 
 import os
@@ -25,11 +26,75 @@ import re
 
 import util
 from errors import *
-from pyanaconda.baseudev import *
+
+import pyudev
+global_udev = pyudev.Udev()
 
 import logging
 log = logging.getLogger("storage")
 
+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)
+
+    return dev
+
+def udev_get_devices(deviceClass="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
+
+def udev_settle():
+    # wait maximal 300 seconds for udev to be done running blkid, lvm,
+    # mdadm etc. This large timeout is needed when running on machines with
+    # lots of disks, or with slow disks
+    util.run_program(["udevadm", "settle", "--timeout=300"])
+
+def udev_trigger(subsystem=None, action="add", name=None):
+    argv = ["trigger", "--action=%s" % action]
+    if subsystem:
+        argv.append("--subsystem-match=%s" % subsystem)
+    if name:
+        argv.append("--sysname-match=%s" % name)
+
+    util.run_program(["udevadm"] + argv)
+    udev_settle()
+
 def udev_resolve_devspec(devspec):
     if not devspec:
         return None
diff --git a/pyanaconda/tsort.py b/pyanaconda/tsort.py
deleted file mode 100644
index 52a871f..0000000
--- a/pyanaconda/tsort.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/python
-# tsort.py
-# Topological sorting.
-#
-# Copyright (C) 2010  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-# Public License for more details.  You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): Dave Lehman <dlehman@redhat.com>
-#
-
-class CyclicGraphError(Exception):
-    pass
-
-def tsort(graph):
-    order = []  # sorted list of items
-
-    if not graph or not graph['items']:
-        return order
-
-    # determine which nodes have no incoming edges
-    roots = [n for n in graph['items'] if graph['incoming'][n] == 0]
-    if not roots:
-        raise CyclicGraphError("no root nodes")
-
-    visited = []    # list of nodes visited, for cycle detection
-    while roots:
-        # remove a root, add it to the order
-        root = roots.pop()
-        if root in visited:
-            raise CyclicGraphError("graph contains cycles")
-
-        visited.append(root)
-        i = graph['items'].index(root)
-        order.append(root)
-        # remove each edge from the root to another node
-        for (parent, child) in [e for e in graph['edges'] if e[0] == root]:
-            graph['incoming'][child] -= 1
-            graph['edges'].remove((parent, child))
-            # if destination node is now a root, add it to roots
-            if graph['incoming'][child] == 0:
-                roots.append(child)
-
-    if len(graph['items']) != len(visited):
-        raise CyclicGraphError("graph contains cycles")
-
-
-    return order
-
-def create_graph(items, edges):
-    """ Create a graph based on a list of items and a list of edges.
-
-        Arguments:
-
-            items   -   an iterable containing (hashable) items to sort
-            edges   -   an iterable containing (parent, child) edge pair tuples
-
-        Return Value:
-
-            The return value is a dictionary representing the directed graph.
-            It has three keys:
-
-                items is the same as the input argument of the same name
-                edges is the same as the input argument of the same name
-                incoming is a dict of incoming edge count hashed by item
-
-    """
-    graph = {'items': [],       # the items to sort
-             'edges': [],       # partial order info: (parent, child) pairs
-             'incoming': {}}    # incoming edge count for each item
-
-    graph['items'] = items
-    graph['edges'] = edges
-    for item in items:
-        graph['incoming'][item] = 0
-
-    for (parent, child) in edges:
-        graph['incoming'][child] += 1
-
-    return graph 
-
-
-if __name__ == "__main__":
-
-    items = [5, 2, 3, 4, 1]
-    edges = [(1, 2), (2, 4), (4, 5), (3, 2)]
-
-    print items
-    print edges
-
-    graph = create_graph(items, edges)
-    print tsort(graph)
-
diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py
index 0324ef3..1c6a589 100644
--- a/pyanaconda/ui/gui/spokes/storage.py
+++ b/pyanaconda/ui/gui/spokes/storage.py
@@ -52,6 +52,7 @@ from pyanaconda.ui.gui.utils import enlightbox, gtk_call_once, gtk_thread_wait
 from pyanaconda.kickstart import doKickstartStorage
 from pyanaconda.storage.size import Size
 from pyanaconda.storage.errors import StorageError
+from pyanaconda.storage.platform import platform
 from pyanaconda.threads import threadMgr, AnacondaThread
 from pyanaconda.product import productName
 from pyanaconda.flags import flags
@@ -663,7 +664,7 @@ class StorageSpoke(NormalSpoke, StorageChecker):
         # any of the free space to be useful.
         disk_labels = set([disk.format.labelType for disk in disks \
                                                  if hasattr(disk.format, "labelType")])
-        platform_labels = set(self.storage.platform.diskLabelTypes)
+        platform_labels = set(platform.diskLabelTypes)
         if disk_labels and platform_labels.isdisjoint(disk_labels):
             disk_free = 0
             fs_free = 0
diff --git a/pyanaconda/ui/gui/tools/run-spoke.py b/pyanaconda/ui/gui/tools/run-spoke.py
index 2a16ab8..92173e7 100755
--- a/pyanaconda/ui/gui/tools/run-spoke.py
+++ b/pyanaconda/ui/gui/tools/run-spoke.py
@@ -30,7 +30,6 @@ from pyanaconda.installclass import DefaultInstall
 from pyanaconda.storage import Storage
 from pyanaconda.threads import initThreading
 from pyanaconda.packaging.yumpayload import YumPayload
-from pyanaconda.platform import getPlatform
 from pykickstart.version import makeVersion
 
 # Don't worry with fcoe, iscsi, dasd, any of that crud.
@@ -89,9 +88,8 @@ if not spokeClass:
 
 print "Running %s %s from %s" % (spokeText, spokeClass, spokeModule)
 
-platform = getPlatform()
 ksdata = makeVersion()
-storage = Storage(data=ksdata, platform=platform)
+storage = Storage(data=ksdata)
 storage.reset()
 instclass = DefaultInstall()
 
diff --git a/pyanaconda/ui/tui/tools/run-text-spoke.py b/pyanaconda/ui/tui/tools/run-text-spoke.py
index b542fcb..bc132f8 100755
--- a/pyanaconda/ui/tui/tools/run-text-spoke.py
+++ b/pyanaconda/ui/tui/tools/run-text-spoke.py
@@ -16,7 +16,6 @@ from pyanaconda.installclass import DefaultInstall
 from pyanaconda.storage import Storage
 from pyanaconda.threads import initThreading
 from pyanaconda.packaging.yumpayload import YumPayload
-from pyanaconda.platform import getPlatform
 from pykickstart.version import makeVersion
 from pyanaconda.ui.tui.simpleline import App
 from pyanaconda.ui.tui import YesNoDialog
@@ -79,9 +78,8 @@ if not spokeClass:
 
 print "Running %s %s from %s" % (spokeText, spokeClass, spokeModule)
 
-platform = getPlatform()
 ksdata = makeVersion()
-storage = Storage(data=ksdata, platform=platform)
+storage = Storage(data=ksdata)
 storage.reset()
 instclass = DefaultInstall()
 app = App("TEST HARNESS", yes_or_no_question = YesNoDialog)
diff --git a/tests/kickstart_test/commands_test.py b/tests/kickstart_test/commands_test.py
index 6fce53c..feb7132 100644
--- a/tests/kickstart_test/commands_test.py
+++ b/tests/kickstart_test/commands_test.py
@@ -40,14 +40,14 @@ class CommandVersionTestCase(TestCase):
             'pyanaconda.storage.devicelibs.lvm',
             'pyanaconda.storage.iscsi',
             'pyanaconda.storage.fcoe',
+            'pyanaconda.storage.udev',
             'pyanaconda.storage.zfcp',
             'iutil',
             'constants',
             'flags',
             'anaconda_log',
             'parted',
-            'block',
-            'baseudev'])
+            'block'])
 
         import pyanaconda.anaconda_log
         pyanaconda.anaconda_log.init()
diff --git a/tests/pyanaconda_test/Makefile.am b/tests/pyanaconda_test/Makefile.am
index cd9b189..889d867 100644
--- a/tests/pyanaconda_test/Makefile.am
+++ b/tests/pyanaconda_test/Makefile.am
@@ -25,7 +25,6 @@ ANACDIR = $(top_builddir)/pyanaconda
 TESTS_ENVIRONMENT = PYTHONPATH=$(top_builddir)/tests:$(ANACDIR)/isys/.libs:$(ANACDIR):$(top_builddir)
 
 TESTS = backend_test.py \
-    baseudev_test.py \
     bootloader_test.py \
     cmdline_test.py \
     desktop_test.py \
diff --git a/tests/pyanaconda_test/baseudev_test.py b/tests/pyanaconda_test/baseudev_test.py
deleted file mode 100644
index 4dd422b..0000000
--- a/tests/pyanaconda_test/baseudev_test.py
+++ /dev/null
@@ -1,139 +0,0 @@
-#!/usr/bin/python
-
-import mock
-import os
-
-class BaseudevTest(mock.TestCase):
-
-    def setUp(self):
-        self.setupModules(["_isys", "block", "ConfigParser"])
-        self.fs = mock.DiskIO()
-
-        import pyanaconda.baseudev
-        pyanaconda.baseudev.os = mock.Mock()
-        pyanaconda.baseudev.log = mock.Mock()
-        pyanaconda.baseudev.open = self.fs.open
-
-    def tearDown(self):
-        self.tearDownModules()
-
-    def udev_enumerate_devices_test(self):
-        import pyanaconda.baseudev
-        ENUMERATE_LIST = [
-            '/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
-            '/sys/devices/virtual/block/loop0',
-            '/sys/devices/virtual/block/loop1',
-            '/sys/devices/virtual/block/ram0',
-            '/sys/devices/virtual/block/ram1',
-            '/sys/devices/virtual/block/dm-0',
-        ]
-
-        pyanaconda.baseudev.global_udev.enumerate_devices = mock.Mock(return_value=ENUMERATE_LIST)
-        ret = pyanaconda.baseudev.udev_enumerate_devices()
-        self.assertEqual(set(ret),
-            set(['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
-            '/devices/virtual/block/loop0', '/devices/virtual/block/loop1',
-            '/devices/virtual/block/ram0', '/devices/virtual/block/ram1',
-            '/devices/virtual/block/dm-0'])
-        )
-
-    def udev_get_device_1_test(self):
-        import pyanaconda.baseudev
-
-        class Device(object):
-            def __init__(self):
-                self.sysname = 'loop1'
-                self.dict = {'symlinks': ['/dev/block/7:1'],
-                    'SUBSYSTEM': 'block',
-                    'MAJOR': '7',
-                    'DEVPATH': '/devices/virtual/block/loop1',
-                    'UDISKS_PRESENTATION_NOPOLICY': '1',
-                    'UDEV_LOG': '3',
-                    'DEVNAME': '/dev/loop1',
-                    'DEVTYPE': 'disk',
-                    'DEVLINKS': '/dev/block/7:1',
-                    'MINOR': '1'
-                }
-
-            def __getitem__(self, key):
-                return self.dict[key]
-
-            def __setitem__(self, key, value):
-                self.dict[key] = value
-
-        pyanaconda.baseudev.os.path.exists.return_value = True
-        DEV_PATH = '/devices/virtual/block/loop1'
-        dev = Device()
-        pyanaconda.baseudev.global_udev = mock.Mock()
-        pyanaconda.baseudev.global_udev.create_device.return_value = dev
-        pyanaconda.baseudev.udev_parse_uevent_file = mock.Mock(return_value=dev)
-
-        ret = pyanaconda.baseudev.udev_get_device(DEV_PATH)
-        self.assertTrue(isinstance(ret, Device))
-        self.assertEqual(ret['name'], ret.sysname)
-        self.assertEqual(ret['sysfs_path'], DEV_PATH)
-        self.assertTrue(pyanaconda.baseudev.udev_parse_uevent_file.called)
-
-    def udev_get_device_2_test(self):
-        import pyanaconda.baseudev
-        pyanaconda.baseudev.os.path.exists.return_value = False
-        ret = pyanaconda.baseudev.udev_get_device('')
-        self.assertEqual(ret, None)
-
-    def udev_get_device_3_test(self):
-        import pyanaconda.baseudev
-        pyanaconda.baseudev.os.path.exists.return_value = True
-        pyanaconda.baseudev.global_udev = mock.Mock()
-        pyanaconda.baseudev.global_udev.create_device.return_value = None
-        ret = pyanaconda.baseudev.udev_get_device('')
-        self.assertEqual(ret, None)
-
-    def udev_get_devices_test(self):
-        import pyanaconda.baseudev
-        pyanaconda.baseudev.udev_settle = mock.Mock()
-        DEVS = \
-            ['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
-            '/devices/virtual/block/loop0', '/devices/virtual/block/loop1',
-            '/devices/virtual/block/ram0', '/devices/virtual/block/ram1',
-            '/devices/virtual/block/dm-0']
-        pyanaconda.baseudev.udev_enumerate_devices = mock.Mock(return_value=DEVS)
-        pyanaconda.baseudev.udev_get_device = lambda x: x
-        ret = pyanaconda.baseudev.udev_get_devices()
-        self.assertEqual(ret, DEVS)
-
-    def udev_parse_uevent_file_1_test(self):
-        import pyanaconda.baseudev
-        pyanaconda.baseudev.os.path.normpath = os.path.normpath
-        pyanaconda.baseudev.os.access.return_value = True
-
-        FILE_CONTENT = "MAJOR=7\nMINOR=1\nDEVNAME=loop1\nDEVTYPE=disk\n"
-        self.fs.open('/sys/devices/virtual/block/loop1/uevent', 'w').write(FILE_CONTENT)
-        dev = {'sysfs_path': '/devices/virtual/block/loop1'}
-        ret = pyanaconda.baseudev.udev_parse_uevent_file(dev)
-        self.assertEqual(ret,
-            {'sysfs_path': '/devices/virtual/block/loop1',
-            'DEVNAME': 'loop1',
-            'DEVTYPE': 'disk',
-            'MAJOR': '7',
-            'MINOR': '1'})
-
-    def udev_parse_uevent_file_2_test(self):
-        import pyanaconda.baseudev
-        pyanaconda.baseudev.os.path.normpath = os.path.normpath
-        pyanaconda.baseudev.os.access.return_value = False
-
-        dev = {'sysfs_path': '/devices/virtual/block/loop1'}
-        ret = pyanaconda.baseudev.udev_parse_uevent_file(dev)
-        self.assertEqual(ret, {'sysfs_path': '/devices/virtual/block/loop1'})
-
-    def udev_settle_test(self):
-        import pyanaconda.baseudev
-        pyanaconda.baseudev.iutil = mock.Mock()
-        pyanaconda.baseudev.udev_settle()
-        self.assertTrue(pyanaconda.baseudev.iutil.execWithRedirect.called)
-
-    def udev_trigger_test(self):
-        import pyanaconda.baseudev
-        pyanaconda.baseudev.iutil = mock.Mock()
-        pyanaconda.baseudev.udev_trigger()
-        self.assertTrue(pyanaconda.baseudev.iutil.execWithRedirect.called)
diff --git a/tests/storage_test/storagetestcase.py b/tests/storage_test/storagetestcase.py
index 4289137..8e5df1d 100644
--- a/tests/storage_test/storagetestcase.py
+++ b/tests/storage_test/storagetestcase.py
@@ -44,7 +44,7 @@ class StorageTestCase(TestCase):
         pyanaconda.iutil.execWithRedirect = Mock()
         pyanaconda.iutil.execWithCapture = Mock()
         pyanaconda.iutil.execWithPulseProgress = Mock()
-        pyanaconda.baseudev = Mock()
+        pyanaconda.storage.udev = Mock()
 
         self.anaconda = Mock()
         self.setUpStorage()
diff --git a/tests/storage_test/tsort_test.py b/tests/storage_test/tsort_test.py
new file mode 100644
index 0000000..cb96997
--- /dev/null
+++ b/tests/storage_test/tsort_test.py
@@ -0,0 +1,62 @@
+
+import unittest
+import pyanaconda.storage.tsort
+
+class TopologicalSortTestCase(unittest.TestCase):
+    def runTest(self):
+        items = [1, 2, 3, 4, 5]
+        edges = [(5, 4), (4, 3), (3, 2), (2, 1)]
+        graph = pyanaconda.storage.tsort.create_graph(items, edges)
+        self._tsortTest(graph)
+
+        edges = [(5, 4), (2, 3), (1, 5)]
+        graph = pyanaconda.storage.tsort.create_graph(items, edges)
+        self._tsortTest(graph)
+
+        edges = [(5, 4), (4, 3), (3, 2), (2, 1), (3, 5)]
+        graph = pyanaconda.storage.tsort.create_graph(items, edges)
+        self.failUnlessRaises(pyanaconda.storage.tsort.CyclicGraphError,
+                              pyanaconda.storage.tsort.tsort,
+                              graph)
+
+        edges = [(5, 4), (4, 3), (3, 2), (2, 1), (2, 3)]
+        graph = pyanaconda.storage.tsort.create_graph(items, edges)
+        self.failUnlessRaises(pyanaconda.storage.tsort.CyclicGraphError,
+                              pyanaconda.storage.tsort.tsort,
+                              graph)
+
+        items = ['a', 'b', 'c', 'd']
+        edges = [('a', 'c'), ('c', 'b')]
+        graph = pyanaconda.storage.tsort.create_graph(items, edges)
+        self._tsortTest(graph)
+
+    def _tsortTest(self, graph):
+        def check_order(order, graph):
+            # since multiple solutions can potentially exist, just verify
+            # that the ordering constraints are satisfied
+            for parent, child in graph['edges']:
+                if order.index(parent) > order.index(child):
+                    return False
+            return True
+
+        try:
+            order = pyanaconda.storage.tsort.tsort(graph)
+        except Exception as e:
+            self.fail(e)
+
+        # verify output list is of the correct length
+        self.failIf(len(order) != len(graph['items']),
+                    "sorted list length is incorrect")
+
+        # verify that all ordering constraints are satisfied
+        self.failUnless(check_order(order, graph),
+                        "ordering constraints not satisfied")
+
+
+def suite():
+    return unittest.TestLoader().loadTestsFromTestCase(TopologicalSortTestCase)
+
+
+if __name__ == "__main__":
+    unittest.main()
+
diff --git a/tests/storage_test/udev_test.py b/tests/storage_test/udev_test.py
new file mode 100644
index 0000000..5d48279
--- /dev/null
+++ b/tests/storage_test/udev_test.py
@@ -0,0 +1,139 @@
+#!/usr/bin/python
+
+import mock
+import os
+
+class UdevTest(mock.TestCase):
+
+    def setUp(self):
+        self.setupModules(["_isys", "block", "ConfigParser"])
+        self.fs = mock.DiskIO()
+
+        import pyanaconda.storage.udev
+        pyanaconda.storage.udev.os = mock.Mock()
+        pyanaconda.storage.udev.log = mock.Mock()
+        pyanaconda.storage.udev.open = self.fs.open
+
+    def tearDown(self):
+        self.tearDownModules()
+
+    def udev_enumerate_devices_test(self):
+        import pyanaconda.storage.udev
+        ENUMERATE_LIST = [
+            '/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
+            '/sys/devices/virtual/block/loop0',
+            '/sys/devices/virtual/block/loop1',
+            '/sys/devices/virtual/block/ram0',
+            '/sys/devices/virtual/block/ram1',
+            '/sys/devices/virtual/block/dm-0',
+        ]
+
+        pyanaconda.storage.udev.global_udev.enumerate_devices = mock.Mock(return_value=ENUMERATE_LIST)
+        ret = pyanaconda.storage.udev.udev_enumerate_devices()
+        self.assertEqual(set(ret),
+            set(['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
+            '/devices/virtual/block/loop0', '/devices/virtual/block/loop1',
+            '/devices/virtual/block/ram0', '/devices/virtual/block/ram1',
+            '/devices/virtual/block/dm-0'])
+        )
+
+    def udev_get_device_1_test(self):
+        import pyanaconda.storage.udev
+
+        class Device(object):
+            def __init__(self):
+                self.sysname = 'loop1'
+                self.dict = {'symlinks': ['/dev/block/7:1'],
+                    'SUBSYSTEM': 'block',
+                    'MAJOR': '7',
+                    'DEVPATH': '/devices/virtual/block/loop1',
+                    'UDISKS_PRESENTATION_NOPOLICY': '1',
+                    'UDEV_LOG': '3',
+                    'DEVNAME': '/dev/loop1',
+                    'DEVTYPE': 'disk',
+                    'DEVLINKS': '/dev/block/7:1',
+                    'MINOR': '1'
+                }
+
+            def __getitem__(self, key):
+                return self.dict[key]
+
+            def __setitem__(self, key, value):
+                self.dict[key] = value
+
+        pyanaconda.storage.udev.os.path.exists.return_value = True
+        DEV_PATH = '/devices/virtual/block/loop1'
+        dev = Device()
+        pyanaconda.storage.udev.global_udev = mock.Mock()
+        pyanaconda.storage.udev.global_udev.create_device.return_value = dev
+        pyanaconda.storage.udev.udev_parse_uevent_file = mock.Mock(return_value=dev)
+
+        ret = pyanaconda.storage.udev.udev_get_device(DEV_PATH)
+        self.assertTrue(isinstance(ret, Device))
+        self.assertEqual(ret['name'], ret.sysname)
+        self.assertEqual(ret['sysfs_path'], DEV_PATH)
+        self.assertTrue(pyanaconda.storage.udev.udev_parse_uevent_file.called)
+
+    def udev_get_device_2_test(self):
+        import pyanaconda.storage.udev
+        pyanaconda.storage.udev.os.path.exists.return_value = False
+        ret = pyanaconda.storage.udev.udev_get_device('')
+        self.assertEqual(ret, None)
+
+    def udev_get_device_3_test(self):
+        import pyanaconda.storage.udev
+        pyanaconda.storage.udev.os.path.exists.return_value = True
+        pyanaconda.storage.udev.global_udev = mock.Mock()
+        pyanaconda.storage.udev.global_udev.create_device.return_value = None
+        ret = pyanaconda.storage.udev.udev_get_device('')
+        self.assertEqual(ret, None)
+
+    def udev_get_devices_test(self):
+        import pyanaconda.storage.udev
+        pyanaconda.storage.udev.udev_settle = mock.Mock()
+        DEVS = \
+            ['/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda',
+            '/devices/virtual/block/loop0', '/devices/virtual/block/loop1',
+            '/devices/virtual/block/ram0', '/devices/virtual/block/ram1',
+            '/devices/virtual/block/dm-0']
+        pyanaconda.storage.udev.udev_enumerate_devices = mock.Mock(return_value=DEVS)
+        pyanaconda.storage.udev.udev_get_device = lambda x: x
+        ret = pyanaconda.storage.udev.udev_get_devices()
+        self.assertEqual(ret, DEVS)
+
+    def udev_parse_uevent_file_1_test(self):
+        import pyanaconda.storage.udev
+        pyanaconda.storage.udev.os.path.normpath = os.path.normpath
+        pyanaconda.storage.udev.os.access.return_value = True
+
+        FILE_CONTENT = "MAJOR=7\nMINOR=1\nDEVNAME=loop1\nDEVTYPE=disk\n"
+        self.fs.open('/sys/devices/virtual/block/loop1/uevent', 'w').write(FILE_CONTENT)
+        dev = {'sysfs_path': '/devices/virtual/block/loop1'}
+        ret = pyanaconda.storage.udev.udev_parse_uevent_file(dev)
+        self.assertEqual(ret,
+            {'sysfs_path': '/devices/virtual/block/loop1',
+            'DEVNAME': 'loop1',
+            'DEVTYPE': 'disk',
+            'MAJOR': '7',
+            'MINOR': '1'})
+
+    def udev_parse_uevent_file_2_test(self):
+        import pyanaconda.storage.udev
+        pyanaconda.storage.udev.os.path.normpath = os.path.normpath
+        pyanaconda.storage.udev.os.access.return_value = False
+
+        dev = {'sysfs_path': '/devices/virtual/block/loop1'}
+        ret = pyanaconda.storage.udev.udev_parse_uevent_file(dev)
+        self.assertEqual(ret, {'sysfs_path': '/devices/virtual/block/loop1'})
+
+    def udev_settle_test(self):
+        import pyanaconda.storage.udev
+        pyanaconda.storage.udev.util = mock.Mock()
+        pyanaconda.storage.udev.udev_settle()
+        self.assertTrue(pyanaconda.storage.udev.util.run_program.called)
+
+    def udev_trigger_test(self):
+        import pyanaconda.storage.udev
+        pyanaconda.storage.udev.util = mock.Mock()
+        pyanaconda.storage.udev.udev_trigger()
+        self.assertTrue(pyanaconda.storage.udev.util.run_program.called)
diff --git a/tests/tsort_test.py b/tests/tsort_test.py
deleted file mode 100644
index d16ee76..0000000
--- a/tests/tsort_test.py
+++ /dev/null
@@ -1,62 +0,0 @@
-
-import unittest
-import pyanaconda.tsort
-
-class TopologicalSortTestCase(unittest.TestCase):
-    def runTest(self):
-        items = [1, 2, 3, 4, 5]
-        edges = [(5, 4), (4, 3), (3, 2), (2, 1)]
-        graph = pyanaconda.tsort.create_graph(items, edges)
-        self._tsortTest(graph)
-
-        edges = [(5, 4), (2, 3), (1, 5)]
-        graph = pyanaconda.tsort.create_graph(items, edges)
-        self._tsortTest(graph)
-
-        edges = [(5, 4), (4, 3), (3, 2), (2, 1), (3, 5)]
-        graph = pyanaconda.tsort.create_graph(items, edges)
-        self.failUnlessRaises(pyanaconda.tsort.CyclicGraphError,
-                              pyanaconda.tsort.tsort,
-                              graph)
-
-        edges = [(5, 4), (4, 3), (3, 2), (2, 1), (2, 3)]
-        graph = pyanaconda.tsort.create_graph(items, edges)
-        self.failUnlessRaises(pyanaconda.tsort.CyclicGraphError,
-                              pyanaconda.tsort.tsort,
-                              graph)
-
-        items = ['a', 'b', 'c', 'd']
-        edges = [('a', 'c'), ('c', 'b')]
-        graph = pyanaconda.tsort.create_graph(items, edges)
-        self._tsortTest(graph)
-
-    def _tsortTest(self, graph):
-        def check_order(order, graph):
-            # since multiple solutions can potentially exist, just verify
-            # that the ordering constraints are satisfied
-            for parent, child in graph['edges']:
-                if order.index(parent) > order.index(child):
-                    return False
-            return True
-
-        try:
-            order = pyanaconda.tsort.tsort(graph)
-        except Exception as e:
-            self.fail(e)
-
-        # verify output list is of the correct length
-        self.failIf(len(order) != len(graph['items']),
-                    "sorted list length is incorrect")
-
-        # verify that all ordering constraints are satisfied
-        self.failUnless(check_order(order, graph),
-                        "ordering constraints not satisfied")
-
-
-def suite():
-    return unittest.TestLoader().loadTestsFromTestCase(TopologicalSortTestCase)
-
-
-if __name__ == "__main__":
-    unittest.main()
-
-- 
1.7.11.7

