[master 7/17] Add filesystem tasks to tasks directory.
mulkieran
installerbot-noreply at redhat.com
Thu Apr 23 16:39:44 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 | 195 ++++++++++++++++++++++++++++++
blivet/tasks/fsreadlabel.py | 133 +++++++++++++++++++++
blivet/tasks/fsresize.py | 148 +++++++++++++++++++++++
blivet/tasks/fssize.py | 166 ++++++++++++++++++++++++++
blivet/tasks/fssync.py | 89 ++++++++++++++
blivet/tasks/fswritelabel.py | 116 ++++++++++++++++++
tests/pylint/pylint-false-positives | 3 +
12 files changed, 1629 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..a70e45e
--- /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.application("dosfsck")
+ 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.application_by_package("e2fsck", availability.E2FSPROGS_PACKAGE)
+ 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.application("fsck.hfsplus")
+ 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..18eeb79
--- /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.application_by_package("dumpe2fs", availability.E2FSPROGS_PACKAGE)
+ options = ["-h"]
+
+class JFSInfo(FSInfo):
+ ext = availability.JFSTUNE_APP
+ options = ["-l"]
+
+class NTFSInfo(FSInfo):
+ ext = availability.application("ntfsinfo")
+ options = ["-m"]
+
+class ReiserFSInfo(FSInfo):
+ ext = availability.application("debugreiserfs")
+ options = []
+
+class XFSInfo(FSInfo):
+ ext = availability.application("xfs_db")
+ 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..33cd50f
--- /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):
+
+ can_label = 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 can_label(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.application("mkfs.btrfs")
+ label_option = None
+
+ @property
+ def args(self):
+ return []
+
+class Ext2FSMkfs(FSMkfs):
+ ext = availability.application_by_package("mke2fs", availability.E2FSPROGS_PACKAGE)
+ 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.application("mkdosfs")
+ label_option = "-n"
+
+ @property
+ def args(self):
+ return []
+
+class GFS2Mkfs(FSMkfs):
+ ext = availability.application("mkfs.gfs2")
+ label_option = None
+
+ @property
+ def args(self):
+ return ["-j", "1", "-p", "lock_nolock", "-O"]
+
+class HFSMkfs(FSMkfs):
+ ext = availability.application("hformat")
+ label_option = "-l"
+
+ @property
+ def args(self):
+ return []
+
+class HFSPlusMkfs(FSMkfs):
+ ext = availability.application("mkfs.hfsplus")
+ label_option = "-v"
+
+ @property
+ def args(self):
+ return []
+
+class JFSMkfs(FSMkfs):
+ ext = availability.application("mkfs.jfs")
+ label_option = "-L"
+
+ @property
+ def args(self):
+ return ["-q"]
+
+class NTFSMkfs(FSMkfs):
+ ext = availability.application("mkntfs")
+ label_option = "-L"
+
+ @property
+ def args(self):
+ return []
+
+class ReiserFSMkfs(FSMkfs):
+ ext = availability.application("mkreiserfs")
+ label_option = "-l"
+
+ @property
+ def args(self):
+ return ["-f", "-f"]
+
+class XFSMkfs(FSMkfs):
+ ext = availability.application("mkfs.xfs")
+ 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 can_label(self):
+ return False
diff --git a/blivet/tasks/fsmount.py b/blivet/tasks/fsmount.py
new file mode 100644
index 0000000..39a11b7
--- /dev/null
+++ b/blivet/tasks/fsmount.py
@@ -0,0 +1,195 @@
+# 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 _availabilityErrors(self):
+ errors = super(FSMount, self)._availabilityErrors
+
+ canmount = (self.mountType in fslib.kernel_filesystems) or \
+ (os.access("/sbin/mount.%s" % (self.mountType,), os.X_OK))
+
+ # Still consider the filesystem type mountable if there exists
+ # an appropriate filesystem driver in the kernel modules directory.
+ if not canmount:
+ 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):
+ canmount = True
+ break
+
+ if not 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 None
+ :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..8b61b02
--- /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._app())
+ 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..46023d1
--- /dev/null
+++ b/blivet/tasks/fsresize.py
@@ -0,0 +1,148 @@
+# 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 unit specifier is interpreted not as bytes, but block size
+ 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 supress 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..e4a7507
--- /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 or None
+ :rtype: :class:`~.size.Size` or NoneType
+ :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.application("df")
+
+ 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..5cf82b6
--- /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):
+ """ Info application for XFS. """
+
+ ext = availability.application("xfs_freeze")
+
+ 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..bcdff7c
--- /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.application("reiserfstune")
+
+ @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
diff --git a/tests/pylint/pylint-false-positives b/tests/pylint/pylint-false-positives
index d33c566..c02fff7 100644
--- a/tests/pylint/pylint-false-positives
+++ b/tests/pylint/pylint-false-positives
@@ -20,6 +20,9 @@
^blivet/blivet.py:[[:digit:]]+: \[E1101\(no\-member\), Blivet.savePassphrase\] Instance of 'DeviceTree' has no '_DeviceTree__luksDevs' member$
^blivet/blivet.py:[[:digit:]]+: \[E1101\(no\-member\), Blivet.savePassphrase\] Instance of 'DeviceTree' has no '_DeviceTree__passphrases' member$
^blivet/formats/__init__.py:[[:digit:]]+: \[W0201\(attribute\-defined\-outside\-init\), DeviceFormat._setDevice\] Attribute '_device' defined outside __init__$
+^blivet/tasks/.*py:[[:digit:]]+: \[W0223\(abstract\-method\), .*\] Method 'available' is abstract in class 'Task' but is not overridden$
+^blivet/tasks/.*py:[[:digit:]]+: \[W0223\(abstract\-method\), .*\] Method 'doTask' is abstract in class 'Task' but is not overridden$
+^blivet/tasks/.*py:[[:digit:]]+: \[W0223\(abstract\-method\), .*\] Method 'doTask' is abstract in class 'UnimplementedTask' but is not overridden$
^dm.c: [[:digit:]]+: not running as root returning empty list$
^tests/devicelibs_test/mdraid_test.py:[[:digit:]]+: \[E1003\(bad\-super\-call\), ([[:alnum:]\.]+).__init__\] Bad first argument YES given to super\(\)$
^tests/devicelibs_test/raid_test.py:[[:digit:]]+: \[E1120\(no\-value\-for\-parameter\), [[:alnum:]\.]+\] No value [[:alnum:] ]+ 'member_count' in [[:alnum:] ]+ call$
--
To view this commit on github, visit https://github.com/rhinstaller/blivet/commit/e91dd14b929aa01b780f584530306b897b67946c
More information about the anaconda-patches
mailing list