[master 7/22] Add filesystem tasks to tasks directory.

mulkieran installerbot-noreply at redhat.com
Tue May 5 16:35:31 UTC 2015


From: mulhern <amulhern at redhat.com>

Related: #12

Signed-off-by: mulhern <amulhern at redhat.com>
---
 blivet/tasks/fsck.py         | 157 +++++++++++++++++++++++++++++
 blivet/tasks/fsinfo.py       | 106 ++++++++++++++++++++
 blivet/tasks/fslabeling.py   |  98 ++++++++++++++++++
 blivet/tasks/fsminsize.py    | 187 +++++++++++++++++++++++++++++++++++
 blivet/tasks/fsmkfs.py       | 231 +++++++++++++++++++++++++++++++++++++++++++
 blivet/tasks/fsmount.py      | 198 +++++++++++++++++++++++++++++++++++++
 blivet/tasks/fsreadlabel.py  | 133 +++++++++++++++++++++++++
 blivet/tasks/fsresize.py     | 151 ++++++++++++++++++++++++++++
 blivet/tasks/fssize.py       | 166 +++++++++++++++++++++++++++++++
 blivet/tasks/fssync.py       |  89 +++++++++++++++++
 blivet/tasks/fswritelabel.py | 116 ++++++++++++++++++++++
 11 files changed, 1632 insertions(+)
 create mode 100644 blivet/tasks/fsck.py
 create mode 100644 blivet/tasks/fsinfo.py
 create mode 100644 blivet/tasks/fslabeling.py
 create mode 100644 blivet/tasks/fsminsize.py
 create mode 100644 blivet/tasks/fsmkfs.py
 create mode 100644 blivet/tasks/fsmount.py
 create mode 100644 blivet/tasks/fsreadlabel.py
 create mode 100644 blivet/tasks/fsresize.py
 create mode 100644 blivet/tasks/fssize.py
 create mode 100644 blivet/tasks/fssync.py
 create mode 100644 blivet/tasks/fswritelabel.py

diff --git a/blivet/tasks/fsck.py b/blivet/tasks/fsck.py
new file mode 100644
index 0000000..80d8661
--- /dev/null
+++ b/blivet/tasks/fsck.py
@@ -0,0 +1,157 @@
+# fsck.py
+# Filesystem check functionality.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+
+from six import add_metaclass
+
+from ..errors import FSError
+from .. import util
+
+from . import availability
+from . import task
+
+_UNKNOWN_RC_MSG = "Unknown return code: %d"
+
+ at add_metaclass(abc.ABCMeta)
+class FSCK(task.BasicApplication):
+    """An abstract class that represents actions associated with
+       checking consistency of a filesystem.
+    """
+    description = "fsck"
+
+    options = abc.abstractproperty(
+       doc="Options for invoking the application.")
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    # IMPLEMENTATION methods
+
+    @abc.abstractmethod
+    def _errorMessage(self, rc):
+        """ Error message corresponding to rc.
+
+            :param int rc: the fsck program return code
+            :returns: an error message corresponding to the code, or None
+            :rtype: str or NoneType
+
+            A return value of None indicates no error.
+        """
+        raise NotImplementedError()
+
+    @property
+    def _fsckCommand(self):
+        """The command to check the filesystem.
+
+           :return: the command
+           :rtype: list of str
+        """
+        return [str(self.ext)] + self.options + [self.fs.device]
+
+    def doTask(self):
+        """ Check the filesystem.
+
+           :raises FSError: on failure
+        """
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        try:
+            rc = util.run_program(self._fsckCommand)
+        except OSError as e:
+            raise FSError("filesystem check failed: %s" % e)
+
+        error_msg = self._errorMessage(rc)
+        if error_msg is not None:
+            hdr = "%(type)s filesystem check failure on %(device)s: " % \
+                    {"type": self.fs.type, "device": self.fs.device}
+
+            raise FSError(hdr + error_msg)
+
+
+class DosFSCK(FSCK):
+    _fsckErrors = {1: "Recoverable errors have been detected or dosfsck has "
+                      "discovered an internal inconsistency.",
+                   2: "Usage error."}
+
+    ext = availability.DOSFSCK_APP
+    options = ["-n"]
+
+    def _errorMessage(self, rc):
+        if rc < 1:
+            return None
+        try:
+            return self._fsckErrors[rc]
+        except KeyError:
+            return _UNKNOWN_RC_MSG % rc
+
+
+class Ext2FSCK(FSCK):
+    _fsckErrors = {4: "File system errors left uncorrected.",
+                   8: "Operational error.",
+                   16: "Usage or syntax error.",
+                   32: "e2fsck cancelled by user request.",
+                   128: "Shared library error."}
+
+    ext = availability.E2FSCK_APP
+    options = ["-f", "-p", "-C", "0"]
+
+    def _errorMessage(self, rc):
+        msgs = (self._fsckErrors[c] for c in self._fsckErrors.keys() if rc & c)
+        return "\n".join(msgs) or None
+
+class HFSPlusFSCK(FSCK):
+    _fsckErrors = {3: "Quick check found a dirty filesystem; no repairs done.",
+                   4: "Root filesystem was dirty. System should be rebooted.",
+                   8: "Corrupt filesystem, repairs did not succeed.",
+                   47: "Major error found; no repairs attempted."}
+    ext = availability.FSCK_HFSPLUS_APP
+    options = []
+
+    def _errorMessage(self, rc):
+        if rc < 1:
+            return None
+        try:
+            return self._fsckErrors[rc]
+        except KeyError:
+            return _UNKNOWN_RC_MSG % rc
+
+class NTFSFSCK(FSCK):
+    ext = availability.NTFSRESIZE_APP
+    options = ["-c"]
+
+    def _errorMessage(self, rc):
+        return _UNKNOWN_RC_MSG % (rc,) if rc != 0 else None
+
+class UnimplementedFSCK(task.UnimplementedTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
diff --git a/blivet/tasks/fsinfo.py b/blivet/tasks/fsinfo.py
new file mode 100644
index 0000000..13ed555
--- /dev/null
+++ b/blivet/tasks/fsinfo.py
@@ -0,0 +1,106 @@
+# fsinfo.py
+# Filesystem information gathering classes.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+
+from six import add_metaclass
+
+from ..errors import FSError
+from .. import util
+
+from . import availability
+from . import task
+
+ at add_metaclass(abc.ABCMeta)
+class FSInfo(task.BasicApplication):
+    """ An abstract class that represents an information gathering app. """
+
+    description = "filesystem info"
+
+    options = abc.abstractproperty(
+       doc="Options for invoking the application.")
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    @property
+    def _infoCommand(self):
+        """ Returns the command for reading filesystem information.
+
+            :returns: a list of appropriate options
+            :rtype: list of str
+        """
+        return [str(self.ext)] + self.options + [self.fs.device]
+
+    def doTask(self):
+        """ Returns information from the command.
+
+            :returns: a string representing the output of the command
+            :rtype: str
+            :raises FSError: if info cannot be obtained
+        """
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        error_msg = None
+        try:
+            (rc, out) = util.run_program_and_capture_output(self._infoCommand)
+            if rc:
+                error_msg = "failed to gather fs info: %s" % rc
+        except OSError as e:
+            error_msg = "failed to gather fs info: %s" % e
+        if error_msg:
+            raise FSError(error_msg)
+        return out
+
+class Ext2FSInfo(FSInfo):
+    ext = availability.DUMPE2FS_APP
+    options = ["-h"]
+
+class JFSInfo(FSInfo):
+    ext = availability.JFSTUNE_APP
+    options = ["-l"]
+
+class NTFSInfo(FSInfo):
+    ext = availability.NTFSINFO_APP
+    options = ["-m"]
+
+class ReiserFSInfo(FSInfo):
+    ext = availability.DEBUGREISERFS_APP
+    options = []
+
+class XFSInfo(FSInfo):
+    ext = availability.XFSDB_APP
+    options = ["-c", "sb 0", "-c", "p dblocks", "-c", "p blocksize"]
+
+class UnimplementedFSInfo(task.UnimplementedTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
diff --git a/blivet/tasks/fslabeling.py b/blivet/tasks/fslabeling.py
new file mode 100644
index 0000000..b0a4c7e
--- /dev/null
+++ b/blivet/tasks/fslabeling.py
@@ -0,0 +1,98 @@
+# fslabeling.py
+# Filesystem labeling classes for anaconda's storage configuration module.
+#
+# Copyright (C) 2014  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+
+from six import add_metaclass
+
+ at add_metaclass(abc.ABCMeta)
+class FSLabeling(object):
+    """An abstract class that represents filesystem labeling actions.
+    """
+
+    default_label = abc.abstractproperty(
+       doc="Default label set on this filesystem at creation.")
+
+    @abc.abstractmethod
+    def labelFormatOK(self, label):
+        """Returns True if this label is correctly formatted for this
+           filesystem, otherwise False.
+
+           :param str label: the label for this filesystem
+           :rtype: bool
+        """
+        raise NotImplementedError
+
+class Ext2FSLabeling(FSLabeling):
+
+    default_label = ""
+
+    def labelFormatOK(self, label):
+        return len(label) < 17
+
+class FATFSLabeling(FSLabeling):
+
+    default_label = "NO NAME"
+
+    def labelFormatOK(self, label):
+        return len(label) < 12
+
+class JFSLabeling(FSLabeling):
+
+    default_label = ""
+
+    def labelFormatOK(self, label):
+        return len(label) < 17
+
+class ReiserFSLabeling(FSLabeling):
+
+    default_label = ""
+
+    def labelFormatOK(self, label):
+        return len(label) < 17
+
+class XFSLabeling(FSLabeling):
+
+    default_label = ""
+
+    def labelFormatOK(self, label):
+        return ' ' not in label and len(label) < 13
+
+class HFSLabeling(FSLabeling):
+
+    default_label = "Untitled"
+
+    def labelFormatOK(self, label):
+        return ':' not in label and len(label) < 28 and len(label) > 0
+
+class HFSPlusLabeling(FSLabeling):
+
+    default_label = "Untitled"
+
+    def labelFormatOK(self, label):
+        return ':' not in label and 0 < len(label) < 129
+
+class NTFSLabeling(FSLabeling):
+
+    default_label = ""
+
+    def labelFormatOK(self, label):
+        return len(label) < 129
diff --git a/blivet/tasks/fsminsize.py b/blivet/tasks/fsminsize.py
new file mode 100644
index 0000000..5044190
--- /dev/null
+++ b/blivet/tasks/fsminsize.py
@@ -0,0 +1,187 @@
+# fsminsize.py
+# Filesystem size gathering classes.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+
+from six import add_metaclass
+
+from ..errors import FSError
+from .. import util
+from ..size import Size
+
+from . import availability
+from . import task
+
+ at add_metaclass(abc.ABCMeta)
+class FSMinSize(task.BasicApplication):
+    """ An abstract class that represents min size information extraction. """
+
+    description = "minimum filesystem size"
+
+    options = abc.abstractproperty(doc="Options for use with app.")
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    def _resizeCommand(self):
+        return [str(self.ext)] + self.options + [self.fs.device]
+
+    def _getResizeInfo(self):
+        """ Get info from fsresize program.
+
+            :rtype: str
+            :returns: output returned by fsresize program
+        """
+        error_msg = None
+        try:
+            (rc, out) = util.run_program_and_capture_output(self._resizeCommand())
+        except OSError as e:
+            error_msg = "failed to gather info from resize program: %s" % e
+        if rc:
+            error_msg = "failed to gather info from resize program: %s" % e
+
+        if error_msg:
+            raise FSError(error_msg)
+        return out
+
+    @abc.abstractmethod
+    def doTask(self):
+        """ Returns the minimum size for this filesystem object.
+
+            :rtype: :class:`~.size.Size`
+            :returns: the minimum size
+            :raises FSError: if filesystem can not be obtained
+        """
+        raise NotImplementedError()
+
+class Ext2FSMinSize(FSMinSize):
+
+    ext = availability.RESIZE2FS_APP
+    options = ["-P"]
+
+    @property
+    def dependsOn(self):
+        return [self.fs._info]
+
+    def _extractBlockSize(self):
+        """ Extract block size from filesystem info.
+
+            :returns: block size of fileystem or None
+            :rtype: :class:`~.size.Size` or NoneType
+        """
+        if self.fs._current_info is None:
+            return None
+
+        blockSize = None
+        for line in (l.strip() for l in self.fs._current_info.splitlines() if l.startswith("Block size:")):
+            try:
+                blockSize = int(line.split(" ")[-1])
+                break
+            except ValueError:
+                continue
+
+        return Size(blockSize) if blockSize else None
+
+    def _extractNumBlocks(self, info):
+        """ Extract the number of blocks from the resizefs info.
+
+           :returns: the number of blocks or None
+           :rtype: int or NoneType
+        """
+        numBlocks = None
+        for line in info.splitlines():
+            (text, _sep, value) = line.partition(":")
+            if "minimum size of the filesystem" not in text:
+                continue
+
+            try:
+                numBlocks = int(value.strip())
+                break
+            except ValueError:
+                break
+
+        return numBlocks
+
+    def doTask(self):
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        blockSize = self._extractBlockSize()
+        if blockSize is None:
+            raise FSError("failed to get block size for %s filesystem on %s" % (self.fs.mountType, self.fs.device.name))
+
+        resize_info = self._getResizeInfo()
+        numBlocks = self._extractNumBlocks(resize_info)
+        if numBlocks is None:
+            raise FSError("failed to get minimum block number for %s filesystem on %s" % (self.fs.mountType, self.fs.device.name))
+
+        return blockSize * numBlocks
+
+class NTFSMinSize(FSMinSize):
+
+    ext = availability.NTFSRESIZE_APP
+    options = ["-m"]
+
+    def _extractMinSize(self, info):
+        """ Extract the minimum size from the resizefs info.
+
+            :param str info: info obtained from resizefs prog
+            :rtype: :class:`~.size.Size` or NoneType
+            :returns: the minimum size, or None
+        """
+        minSize = None
+        for line in info.splitlines():
+            (text, _sep, value) = line.partition(":")
+            if "Minsize" not in text:
+                continue
+
+            try:
+                minSize = Size("%d MB" % int(value.strip()))
+            except ValueError:
+                break
+
+        return minSize
+
+
+    def doTask(self):
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        resize_info = self._getResizeInfo()
+        minSize = self._extractMinSize(resize_info)
+        if minSize is None:
+            raise FSError("Unable to discover minimum size of filesystem on %s" % self.fs.device)
+        return minSize
+
+class UnimplementedFSMinSize(task.UnimplementedTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
diff --git a/blivet/tasks/fsmkfs.py b/blivet/tasks/fsmkfs.py
new file mode 100644
index 0000000..a2110a9
--- /dev/null
+++ b/blivet/tasks/fsmkfs.py
@@ -0,0 +1,231 @@
+# fsmkfs.py
+# Filesystem formatting classes.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+
+from six import add_metaclass
+
+from ..errors import FSError, FSWriteLabelError
+from .. import util
+
+from . import availability
+from . import task
+
+ at add_metaclass(abc.ABCMeta)
+class FSMkfsTask(task.Task):
+
+    canLabel = abc.abstractproperty(doc="whether this task labels")
+
+ at add_metaclass(abc.ABCMeta)
+class FSMkfs(task.BasicApplication, FSMkfsTask):
+    """An abstract class that represents filesystem creation actions. """
+    description = "mkfs"
+
+    label_option = abc.abstractproperty(
+       doc="Option for setting a filesystem label.")
+
+    args = abc.abstractproperty(doc="options for creating filesystem")
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    # IMPLEMENTATION methods
+
+    @property
+    def canLabel(self):
+        """ Whether this task can label the filesystem.
+
+            :returns: True if this task can label the filesystem
+            :rtype: bool
+        """
+        return self.label_option is not None
+
+    @property
+    def _labelOptions(self):
+        """ Any labeling options that a particular filesystem may use.
+
+            :returns: labeling options
+            :rtype: list of str
+        """
+        # Do not know how to set label while formatting.
+        if self.label_option is None:
+            return []
+
+        # No label to set
+        if self.fs.label is None:
+            return []
+
+        if self.fs.labelFormatOK(self.fs.label):
+            return [self.label_option, self.fs.label]
+        else:
+            raise FSWriteLabelError("Choosing not to apply label (%s) during creation of filesystem %s. Label format is unacceptable for this filesystem." % (self.fs.label, self.fs.type))
+
+    def _formatOptions(self, options=None, label=False):
+        """Get a list of format options to be used when creating the
+           filesystem.
+
+           :param options: any special options
+           :type options: list of str or None
+           :param bool label: if True, label if possible, default is False
+        """
+        options = options or []
+
+        if not isinstance(options, list):
+            raise FSError("options parameter must be a list.")
+
+        label_options = self._labelOptions if label else []
+        return options + self.args + label_options + [self.fs.device]
+
+    def _mkfsCommand(self, options, label):
+        """Return the command to make the filesystem.
+
+           :param options: any special options
+           :type options: list of str or None
+           :returns: the mkfs command
+           :rtype: list of str
+        """
+        return [str(self.ext)] + self._formatOptions(options, label)
+
+    def doTask(self, options=None, label=False):
+        """Create the format on the device and label if possible and desired.
+
+           :param options: any special options, may be None
+           :type options: list of str or NoneType
+           :param bool label: whether to label while creating, default is False
+        """
+        # pylint: disable=arguments-differ
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        options = options or []
+        try:
+            ret = util.run_program(self._mkfsCommand(options, label))
+        except OSError as e:
+            raise FSError(e)
+
+        if ret:
+            raise FSError("format failed: %s" % ret)
+
+class BTRFSMkfs(FSMkfs):
+    ext = availability.MKFS_BTRFS_APP
+    label_option = None
+
+    @property
+    def args(self):
+        return []
+
+class Ext2FSMkfs(FSMkfs):
+    ext = availability.MKE2FS_APP
+    label_option = "-L"
+
+    _opts = []
+
+    @property
+    def args(self):
+        return self._opts + (["-T", self.fs.fsprofile] if self.fs.fsprofile else [])
+
+class Ext3FSMkfs(Ext2FSMkfs):
+    _opts = ["-t", "ext3"]
+
+class Ext4FSMkfs(Ext3FSMkfs):
+    _opts = ["-t", "ext4"]
+
+class FATFSMkfs(FSMkfs):
+    ext = availability.MKDOSFS_APP
+    label_option = "-n"
+
+    @property
+    def args(self):
+        return []
+
+class GFS2Mkfs(FSMkfs):
+    ext = availability.MKFS_GFS2_APP
+    label_option = None
+
+    @property
+    def args(self):
+        return ["-j", "1", "-p", "lock_nolock", "-O"]
+
+class HFSMkfs(FSMkfs):
+    ext = availability.HFORMAT_APP
+    label_option = "-l"
+
+    @property
+    def args(self):
+        return []
+
+class HFSPlusMkfs(FSMkfs):
+    ext = availability.MKFS_HFSPLUS_APP
+    label_option = "-v"
+
+    @property
+    def args(self):
+        return []
+
+class JFSMkfs(FSMkfs):
+    ext = availability.MKFS_JFS_APP
+    label_option = "-L"
+
+    @property
+    def args(self):
+        return ["-q"]
+
+class NTFSMkfs(FSMkfs):
+    ext = availability.MKNTFS_APP
+    label_option = "-L"
+
+    @property
+    def args(self):
+        return []
+
+class ReiserFSMkfs(FSMkfs):
+    ext = availability.MKREISERFS_APP
+    label_option = "-l"
+
+    @property
+    def args(self):
+        return ["-f", "-f"]
+
+class XFSMkfs(FSMkfs):
+    ext = availability.MKFS_XFS_APP
+    label_option = "-L"
+
+    @property
+    def args(self):
+        return ["-f"]
+
+class UnimplementedFSMkfs(task.UnimplementedTask, FSMkfsTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    @property
+    def canLabel(self):
+        return False
diff --git a/blivet/tasks/fsmount.py b/blivet/tasks/fsmount.py
new file mode 100644
index 0000000..552faed
--- /dev/null
+++ b/blivet/tasks/fsmount.py
@@ -0,0 +1,198 @@
+# fsmount.py
+# Filesystem mounting classes.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import os
+
+from ..errors import FSError
+from ..flags import flags
+from .. import util
+from ..formats import fslib
+
+from . import availability
+from . import task
+
+class FSMount(task.BasicApplication):
+    """An abstract class that represents filesystem mounting actions. """
+    description = "mount a filesystem"
+
+    options = ["defaults"]
+    # type argument to pass to mount, if different from filesystem type
+    fstype = None
+
+    ext = availability.MOUNT_APP
+
+    def __init__(self, an_fs):
+        self.fs = an_fs
+
+    # TASK methods
+
+    @property
+    def _hasDriver(self):
+        """ Is there a filesystem driver in the kernel modules directory. """
+        modpath = os.path.realpath(os.path.join("/lib/modules", os.uname()[2]))
+        if os.path.isdir(modpath):
+            modname = "%s.ko" % self.mountType
+            for _root, _dirs, files in os.walk(modpath):
+                if any(x.startswith(modname) for x in files):
+                    return True
+        return False
+
+    @property
+    def _canMount(self):
+        return (self.mountType in fslib.kernel_filesystems) or \
+           (os.access("/sbin/mount.%s" % (self.mountType,), os.X_OK)) or \
+           self._hasDriver
+
+    @property
+    def _availabilityErrors(self):
+        errors = super(FSMount, self)._availabilityErrors
+
+        if not self._canMount:
+            errors.append("mounting filesystem %s is not supported" % self.mountType)
+        return errors
+
+    # IMPLEMENTATION methods
+
+    @property
+    def mountType(self):
+        """ Mount type string to pass to mount command.
+
+            :returns: mount type string
+            :rtype: str
+        """
+        return self.fstype or self.fs._type
+
+    def _modifyOptions(self, options):
+        """ Any mandatory options can be added in this method.
+
+            :param str options: an option string
+            :returns: a modified option string
+            :rtype: str
+        """
+        return options
+
+    def mountOptions(self, options):
+        """ The options used for mounting.
+
+           :param options: mount options
+           :type options: str or NoneType
+           :returns: the options used by the task
+           :rtype: str
+        """
+        if not options or not isinstance(options, str):
+            options = self.fs.mountopts or ",".join(self.options)
+
+        return self._modifyOptions(options)
+
+    def doTask(self, mountpoint, options=None):
+        """Create the format on the device and label if possible and desired.
+
+           :param str mountpoint: mountpoint that overrides self.mountpoint
+           :param options: mount options
+           :type options: str or None
+        """
+        # pylint: disable=arguments-differ
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        try:
+            rc = util.mount(self.fs.device, mountpoint,
+                            fstype=self.mountType,
+                            options=self.mountOptions(options))
+        except OSError as e:
+            raise FSError("mount failed: %s" % e)
+
+        if rc:
+            raise FSError("mount failed: %s" % rc)
+
+class AppleBootstrapFSMount(FSMount):
+    fstype = "hfs"
+
+class BindFSMount(FSMount):
+
+    @property
+    def _availabilityErrors(self):
+        errors = []
+        if not self.ext.available:
+            errors.append("application %s is not available" % self.ext)
+
+        return errors
+
+    def _modifyOptions(self, options):
+        return ",".join(["bind", options])
+
+class DevPtsFSMount(FSMount):
+    options = ["gid=5", "mode=620"]
+
+class FATFSMount(FSMount):
+    options = ["umask=0077", "shortname=winnt"]
+
+class EFIFSMount(FATFSMount):
+    fstype = "vfat"
+
+class HFSPlusMount(FSMount):
+    fstype = "hfsplus"
+
+class Iso9660FSMount(FSMount):
+    options = ["ro"]
+
+class NoDevFSMount(FSMount):
+
+    @property
+    def mountType(self):
+        return self.fs.device
+
+class NFSMount(FSMount):
+
+    def _availabilityErrors(self):
+        return ["nfs filesystem can't be mounted"]
+
+class NTFSMount(FSMount):
+    options = ["default", "ro"]
+
+class SELinuxFSMount(NoDevFSMount):
+
+    @property
+    def _availabilityErrors(self):
+        errors = super(SELinuxFSMount, self)._availabilityErrors
+        if not flags.selinux:
+            errors.append("selinux not enabled")
+        return errors
+
+class TmpFSMount(NoDevFSMount):
+
+    def _modifyOptions(self, options):
+        # This duplicates some code in fs.TmpFS._getOptions.
+        # There seems to be no way around that.
+        if self.fs._accept_default_size:
+            size_opt = None
+        else:
+            size_opt = self.fs._sizeOption(self.fs._size)
+        return ",".join(o for o in (options, size_opt) if o)
+
+    @property
+    def _availabilityErrors(self):
+        errors = []
+        if not self.ext.available:
+            errors.append("application %s is not available" % self.ext)
+
+        return errors
diff --git a/blivet/tasks/fsreadlabel.py b/blivet/tasks/fsreadlabel.py
new file mode 100644
index 0000000..59e3e12
--- /dev/null
+++ b/blivet/tasks/fsreadlabel.py
@@ -0,0 +1,133 @@
+# fsreadlabel.py
+# Filesystem label reading classes.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+import re
+
+from six import add_metaclass
+
+from ..errors import FSReadLabelError
+from .. import util
+
+from . import availability
+from . import task
+
+ at add_metaclass(abc.ABCMeta)
+class FSReadLabel(task.BasicApplication):
+    """ An abstract class that represents reading a filesystem's label. """
+    description = "read filesystem label"
+
+    label_regex = abc.abstractproperty(
+        doc="Matches the string output by the reading application.")
+
+    args = abc.abstractproperty(doc="arguments for reading a label.")
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+           :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    # IMPLEMENTATION methods
+
+    @property
+    def _readCommand(self):
+        """Get the command to read the filesystem label.
+
+           :return: the command
+           :rtype: list of str
+        """
+        return [str(self.ext)] + self.args
+
+    def _extractLabel(self, labelstr):
+        """Extract the label from an output string.
+
+           :param str labelstr: the string containing the label information
+
+           :return: the label
+           :rtype: str
+
+           Raises an FSReadLabelError if the label can not be extracted.
+        """
+        match = re.match(self.label_regex, labelstr)
+        if match is None:
+            raise FSReadLabelError("Unknown format for application %s" % self.ext)
+        return match.group('label')
+
+    def doTask(self):
+        """ Get the label.
+
+            :returns: the filesystem label
+            :rtype: str
+        """
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSReadLabelError("\n".join(error_msgs))
+
+        (rc, out) = util.run_program_and_capture_output(self._readCommand)
+        if rc != 0:
+            raise FSReadLabelError("read label failed")
+
+        label = out.strip()
+
+        return label if label == "" else self._extractLabel(label)
+
+class DosFSReadLabel(FSReadLabel):
+    ext = availability.DOSFSLABEL_APP
+    label_regex = r'(?P<label>.*)'
+
+    @property
+    def args(self):
+        return [self.fs.device]
+
+class Ext2FSReadLabel(FSReadLabel):
+    ext = availability.E2LABEL_APP
+    label_regex = r'(?P<label>.*)'
+
+    @property
+    def args(self):
+        return [self.fs.device]
+
+class NTFSReadLabel(FSReadLabel):
+    ext = availability.NTFSLABEL_APP
+    label_regex = r'(?P<label>.*)'
+
+    @property
+    def args(self):
+        return [self.fs.device]
+
+class XFSReadLabel(FSReadLabel):
+    ext = availability.XFSADMIN_APP
+    label_regex = r'label = "(?P<label>.*)"'
+
+    @property
+    def args(self):
+        return ["-l", self.fs.device]
+
+class UnimplementedFSReadLabel(task.UnimplementedTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
diff --git a/blivet/tasks/fsresize.py b/blivet/tasks/fsresize.py
new file mode 100644
index 0000000..ef12686
--- /dev/null
+++ b/blivet/tasks/fsresize.py
@@ -0,0 +1,151 @@
+# fsresize.py
+# Filesystem resizing classes.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+
+from six import add_metaclass
+
+from ..errors import FSError
+from ..size import B, KiB, MiB, GiB, KB, MB, GB
+from ..import util
+
+from . import availability
+from . import task
+
+ at add_metaclass(abc.ABCMeta)
+class FSResizeTask(task.Task):
+    """ The abstract properties that any resize task must have. """
+
+    unit = abc.abstractproperty(doc="Resize unit.")
+    size_fmt = abc.abstractproperty(doc="Size format string.")
+
+ at add_metaclass(abc.ABCMeta)
+class FSResize(task.BasicApplication, FSResizeTask):
+    """ An abstract class for resizing a filesystem. """
+
+    description = "resize filesystem"
+
+    args = abc.abstractproperty(doc="Resize arguments.")
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    # IMPLEMENTATION methods
+
+    @abc.abstractmethod
+    def sizeSpec(self):
+        """ Returns a string specification for the target size of the command.
+            :returns: size specification
+            :rtype: str
+        """
+        raise NotImplementedError()
+
+    def _resizeCommand(self):
+        return [str(self.ext)] + self.args
+
+    def doTask(self):
+        """ Resize the device.
+
+            :raises FSError: on failure
+        """
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        try:
+            ret = util.run_program(self._resizeCommand())
+        except OSError as e:
+            raise FSError(e)
+
+        if ret:
+            raise FSError("resize failed: %s" % ret)
+
+class Ext2FSResize(FSResize):
+    ext = availability.RESIZE2FS_APP
+    unit = MiB
+
+    # No bytes specification is described in the man pages. A number without
+    # any suffix is interpreted as indicating the number of filesystem blocks.
+    # A suffix of "s" specifies a 512 byte sector. It is omitted here because
+    # the lookup is only by standard binary units.
+    size_fmt = {KiB: "%dK", MiB: "%dM", GiB: "%dG"}[unit]
+
+    def sizeSpec(self):
+        return self.size_fmt % self.fs.targetSize.convertTo(self.unit)
+
+    @property
+    def args(self):
+        return ["-p", self.fs.device, self.sizeSpec()]
+
+class NTFSResize(FSResize):
+    ext = availability.NTFSRESIZE_APP
+    unit = B
+    size_fmt = {B: "%d", KB: "%dK", MB: "%dM", GB: "%dG"}[unit]
+
+    def sizeSpec(self):
+        return self.size_fmt % self.fs.targetSize.convertTo(self.unit)
+
+    @property
+    def args(self):
+        return [
+           "-ff", # need at least two 'f's to fully suppress interaction
+           "-s", self.sizeSpec(),
+           self.fs.device
+        ]
+
+class TmpFSResize(FSResize):
+
+    ext = availability.MOUNT_APP
+    unit = MiB
+    size_fmt = {KiB: "%dk", MiB: "%dm", GiB: "%dg"}[unit]
+
+    def sizeSpec(self):
+        return "size=%s" % (self.size_fmt % self.fs.targetSize.convertTo(self.unit))
+
+    @property
+    def args(self):
+        # This is too closely mixed in w/ TmpFS object, due to the
+        # fact that resizing is done by mounting and that the options are
+        # therefore mount options. The situation is hard to avoid, though.
+        opts = self.fs.mountopts or ",".join(self.fs._mount.options)
+        options = ("remount", opts, self.sizeSpec())
+        return ['-o', ",".join(options), self.fs._type, self.fs.systemMountpoint]
+
+class UnimplementedFSResize(task.UnimplementedTask, FSResizeTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    @property
+    def unit(self):
+        raise NotImplementedError()
+
+    @property
+    def size_fmt(self):
+        raise NotImplementedError()
diff --git a/blivet/tasks/fssize.py b/blivet/tasks/fssize.py
new file mode 100644
index 0000000..b28083e
--- /dev/null
+++ b/blivet/tasks/fssize.py
@@ -0,0 +1,166 @@
+# fssize.py
+# Filesystem size gathering classes.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+from collections import namedtuple
+
+from six import add_metaclass
+
+from ..errors import FSError
+from ..size import Size
+from .. import util
+
+from . import availability
+from . import task
+
+_tags = ("count", "size")
+_Tags = namedtuple("_Tags", _tags)
+
+ at add_metaclass(abc.ABCMeta)
+class FSSize(task.Task):
+    """ An abstract class that represents size information extraction. """
+    description = "current filesystem size"
+
+    tags = abc.abstractproperty(
+        doc="Strings used for extracting components of size.")
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    # TASK methods
+
+    @property
+    def _availabilityErrors(self):
+        return []
+
+    @property
+    def dependsOn(self):
+        return [self.fs._info]
+
+    # IMPLEMENTATION methods
+
+    def doTask(self):
+        """ Returns the size of the filesystem.
+
+            :returns: the size of the filesystem
+            :rtype: :class:`~.size.Size`
+            :raises FSError: on failure
+        """
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        if self.fs._current_info is None:
+            raise FSError("No info available for size computation.")
+
+        # Setup initial values
+        values = {}
+        for k in _tags:
+            values[k] = None
+
+        # Attempt to set values from info
+        for line in (l.strip() for l in self.fs._current_info.splitlines()):
+            key = next((k for k in _tags if line.startswith(getattr(self.tags, k))), None)
+            if not key:
+                continue
+
+            if values[key] is not None:
+                raise FSError("found two matches for key %s" % key)
+
+            # Look for last numeric value in matching line
+            fields = line.split()
+            fields.reverse()
+            for field in fields:
+                try:
+                    values[key] = int(field)
+                    break
+                except ValueError:
+                    continue
+
+        # Raise an error if a value is missing
+        missing = next((k for k in _tags if values[k] is None), None)
+        if missing is not None:
+            raise FSError("Failed to parse info for %s." % missing)
+
+        return values["count"] * Size(values["size"])
+
+class Ext2FSSize(FSSize):
+    tags = _Tags(size="Block size:", count="Block count:")
+
+class JFSSize(FSSize):
+    tags = _Tags(size="Physical block size:", count="Aggregate size:")
+
+class NTFSSize(FSSize):
+    tags = _Tags(size="Cluster Size:", count="Volume Size in Clusters:")
+
+class ReiserFSSize(FSSize):
+    tags = _Tags(size="Blocksize:", count="Count of blocks on the device:")
+
+class XFSSize(FSSize):
+    tags = _Tags(size="blocksize =", count="dblocks =")
+
+class TmpFSSize(task.BasicApplication):
+    description = "current filesystem size"
+
+    ext = availability.DF_APP
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+           :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    @property
+    def _sizeCommand(self):
+        return [str(self.ext), self.fs.systemMountpoint, "--output=size"]
+
+    def doTask(self):
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        try:
+            (ret, out) = util.run_program_and_capture_output(self._sizeCommand)
+            if ret:
+                raise FSError("Failed to execute command %s." % self._sizeCommand)
+        except OSError:
+            raise FSError("Failed to execute command %s." % self._sizeCommand)
+
+        lines = out.splitlines()
+        if len(lines) != 2 or lines[0].strip() != "1K-blocks":
+            raise FSError("Failed to parse output of command %s." % self._sizeCommand)
+
+        return Size("%s KiB" % lines[1])
+
+
+class UnimplementedFSSize(task.UnimplementedTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
diff --git a/blivet/tasks/fssync.py b/blivet/tasks/fssync.py
new file mode 100644
index 0000000..e83aa12
--- /dev/null
+++ b/blivet/tasks/fssync.py
@@ -0,0 +1,89 @@
+# fssync.py
+# Filesystem syncing classes.
+#
+# Copyright (C) 2014  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+
+from six import add_metaclass
+
+from ..errors import FSError
+from .. import util
+
+from . import availability
+from . import task
+
+ at add_metaclass(abc.ABCMeta)
+class FSSync(task.BasicApplication):
+    """ An abstract class that represents syncing a filesystem. """
+
+    description = "filesystem syncing"
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    @abc.abstractmethod
+    def doTask(self):
+        raise NotImplementedError()
+
+class XFSSync(FSSync):
+    """ Sync application for XFS. """
+
+    ext = availability.XFSFREEZE_APP
+
+    def _freezeCommand(self):
+        return [str(self.ext), "-f", self.fs.systemMountpoint]
+
+    def _unfreezeCommand(self):
+        return [str(self.ext), "-u", self.fs.systemMountpoint]
+
+    def doTask(self, root="/"):
+        # pylint: disable=arguments-differ
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSError("\n".join(error_msgs))
+
+        error_msg = None
+        try:
+            rc = util.run_program(self._freezeCommand(), root=root)
+        except OSError as e:
+            error_msg = "failed to sync filesytem: %s" % e
+        error_msg = error_msg or rc
+
+        try:
+            rc = util.run_program(self._unfreezeCommand(), root=root)
+        except OSError as e:
+            error_msg = error_msg or "failed to sync filesystem: %s" % e
+        error_msg = error_msg or rc
+
+        if error_msg:
+            raise FSError(error_msg)
+
+class UnimplementedFSSync(task.UnimplementedTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
diff --git a/blivet/tasks/fswritelabel.py b/blivet/tasks/fswritelabel.py
new file mode 100644
index 0000000..af64d92
--- /dev/null
+++ b/blivet/tasks/fswritelabel.py
@@ -0,0 +1,116 @@
+# fswritelabel.py
+# Filesystem label writing classes.
+#
+# Copyright (C) 2015  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): Anne Mulhern <amulhern at redhat.com>
+
+import abc
+
+from six import add_metaclass
+
+from .. import util
+from ..errors import FSWriteLabelError
+
+from . import availability
+from . import task
+
+ at add_metaclass(abc.ABCMeta)
+class FSWriteLabel(task.BasicApplication):
+    """ An abstract class that represents writing a label for a filesystem. """
+
+    description = "write filesystem label"
+
+    args = abc.abstractproperty(doc="arguments for writing a label")
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs
+
+    # IMPLEMENTATION methods
+
+    @property
+    def _setCommand(self):
+        """Get the command to label the filesystem.
+
+           :return: the command
+           :rtype: list of str
+        """
+        return [str(self.ext)] + self.args
+
+    def doTask(self):
+        error_msgs = self.availabilityErrors
+        if error_msgs:
+            raise FSWriteLabelError("\n".join(error_msgs))
+
+        rc = util.run_program(self._setCommand)
+        if rc:
+            raise FSWriteLabelError("label failed")
+
+class DosFSWriteLabel(FSWriteLabel):
+    ext = availability.DOSFSLABEL_APP
+
+    @property
+    def args(self):
+        return [self.fs.device, self.fs.label]
+
+class Ext2FSWriteLabel(FSWriteLabel):
+    ext = availability.E2LABEL_APP
+
+    @property
+    def args(self):
+        return [self.fs.device, self.fs.label]
+
+class JFSWriteLabel(FSWriteLabel):
+    ext = availability.JFSTUNE_APP
+
+    @property
+    def args(self):
+        return ["-L", self.fs.label, self.fs.device]
+
+class NTFSWriteLabel(FSWriteLabel):
+    ext = availability.NTFSLABEL_APP
+
+    @property
+    def args(self):
+        return [self.fs.device, self.fs.label]
+
+class ReiserFSWriteLabel(FSWriteLabel):
+    ext = availability.REISERFSTUNE_APP
+
+    @property
+    def args(self):
+        return ["-l", self.fs.label, self.fs.device]
+
+class XFSWriteLabel(FSWriteLabel):
+    ext = availability.XFSADMIN_APP
+
+    @property
+    def args(self):
+        return ["-L", self.fs.label if self.fs.label != "" else "--", self.fs.device]
+
+class UnimplementedFSWriteLabel(task.UnimplementedTask):
+
+    def __init__(self, an_fs):
+        """ Initializer.
+
+            :param FS an_fs: a filesystem object
+        """
+        self.fs = an_fs


-- 
To view this commit on github, visit https://github.com/rhinstaller/blivet/commit/3da1157ab4cf654c8b4bdb6d2de4793ff5778209


More information about the anaconda-patches mailing list