]>
git.ipfire.org Git - ipfire-3.x.git/blob - src/pomona/storage/formats/__init__.py
7 def register_device_format(fmt_class
):
8 if not issubclass(fmt_class
, DeviceFormat
):
9 raise ValueError("Argument must be a subclass of DeviceFormat")
10 device_formats
[fmt_class
._type
] = fmt_class
12 def getFormat(fmt_type
, *args
, **kwargs
):
13 """ Return a DeviceFormat instance based on fmt_type and args.
15 Given a device format type and a set of constructor arguments,
16 return a DeviceFormat instance.
18 Return None if no suitable format class is found.
22 fmt_type -- the name of the format type (eg: 'ext3', 'swap')
26 The keyword arguments may vary according to the format type,
27 but here is the common set:
29 device -- path to the device on which the format resides
30 uuid -- the UUID of the (preexisting) formatted device
31 exists -- whether or not the format exists on the device
35 #installer = kwargs["installer"]
37 fmt_class
= get_device_format_class(fmt_type
)
40 fmt
= fmt_class(*args
, **kwargs
)
42 className
= fmt
.__class
__.__name
__
43 except AttributeError:
45 #installer.log.debug("getFormat('%s') returning %s instance" % (fmt_type, className))
48 def get_device_format_class(fmt_type
):
49 """ Return an appropriate format class based on fmt_type. """
50 if not device_formats
:
51 collect_device_format_classes()
53 fmt
= device_formats
.get(fmt_type
)
55 for fmt_class
in device_formats
.values():
56 if fmt_type
and fmt_type
== fmt_class
._name
:
59 elif fmt_type
in fmt_class
._udevTypes
:
63 # default to no formatting, AKA "Unknown"
68 def collect_device_format_classes():
69 """ Pick up all device format classes from this directory.
71 Note: Modules must call register_device_format(FormatClass) in
72 order for the format class to be picked up.
74 dir = os
.path
.dirname(__file__
)
75 for module_file
in os
.listdir(dir):
76 # make sure we're not importing this module
77 if module_file
.endswith(".py") and module_file
!= __file__
:
78 mod_name
= module_file
[:-3]
80 globals()[mod_name
] = __import__(mod_name
, globals(), locals(), [], -1)
81 except ImportError, e
:
84 default_fstypes
= ("ext4", "ext3", "ext2")
85 default_boot_fstypes
= ("ext3", "ext2")
86 def get_default_filesystem_type(boot
=None):
88 fstypes
= default_boot_fstypes
90 fstypes
= default_fstypes
92 for fstype
in fstypes
:
94 supported
= get_device_format_class(fstype
).supported
95 except AttributeError:
101 raise DeviceFormatError("None of %s is supported by your kernel" % ",".join(fstypes
))
103 class DeviceFormat(object):
104 """ Generic device format. """
109 _formattable
= False # can be formatted
110 _supported
= False # is supported
111 _resizable
= False # can be resized
112 _bootable
= False # can be used as boot
113 _migratable
= False # can be migrated
114 _maxSize
= 0 # maximum size in MB
115 _minSize
= 0 # minimum size in MB
119 def __init__(self
, installer
, *args
, **kwargs
):
120 """ Create a DeviceFormat instance.
124 device -- path to the underlying device
125 uuid -- this format's UUID
126 exists -- indicates whether this is an existing format
129 self
.installer
= installer
131 self
.device
= kwargs
.get("device")
132 self
.uuid
= kwargs
.get("uuid")
133 self
.exists
= kwargs
.get("exists")
134 self
.options
= kwargs
.get("options")
135 self
._migrate
= False
137 def __deepcopy__(self
, memo
):
138 new
= self
.__class
__.__new
__(self
.__class
__)
140 shallow_copy_attrs
= ('installer', 'screen')
141 for (attr
, value
) in self
.__dict
__.items():
142 if attr
in shallow_copy_attrs
:
143 setattr(new
, attr
, copy
.copy(value
))
145 setattr(new
, attr
, copy
.deepcopy(value
, memo
))
149 def _setOptions(self
, options
):
150 self
._options
= options
152 def _getOptions(self
):
155 options
= property(_getOptions
, _setOptions
)
157 def _setDevice(self
, devspec
):
158 if devspec
and not devspec
.startswith("/"):
159 raise ValueError("device must be a fully qualified path")
160 self
._device
= devspec
162 def _getDevice(self
):
165 device
= property(lambda f
: f
._getDevice
(),
166 lambda f
,d
: f
._setDevice
(d
),
167 doc
="Full path the device this format occupies")
184 def notifyKernel(self
):
188 if self
.device
.startswith("/dev/mapper/"):
190 name
= dm_node_from_name(os
.path
.basename(self
.device
))
192 self
.installer
.log
.warning("Failed to get dm node for %s" % self
.device
)
195 name
= os
.path
.basename(self
.device
)
197 path
= get_sysfs_path_by_name(name
)
199 notify_kernel(path
, action
="change")
201 self
.installer
.log
.warning("Failed to notify kernel of change: %s" % e
)
203 def create(self
, *args
, **kwargs
):
204 # allow late specification of device path
205 device
= kwargs
.get("device")
209 if not os
.path
.exists(self
.device
):
210 raise FormatCreateError("invalid device specification")
212 def destroy(self
, *args
, **kwargs
):
213 # zero out the 1MB at the beginning and end of the device in the
214 # hope that it will wipe any metadata from filesystems that
215 # previously occupied this device
216 self
.installer
.log
.debug("Zeroing out beginning and end of %s..." % self
.device
)
218 fd
= os
.open(self
.device
, os
.O_RDWR
)
219 buf
= '\0' * 1024 * 1024
221 os
.lseek(fd
, -1024 * 1024, 2)
225 if getattr(e
, "errno", None) == 28: # No space left in device
228 self
.installer
.log
.error("Error zeroing out %s: %s" % (self
.device
, e
))
230 except Exception as e
:
231 self
.installer
.log
.error("Error zeroing out %s: %s" % (self
.device
, e
))
236 def setup(self
, *args
, **kwargs
):
238 raise FormatSetupError("format has not been created")
243 # allow late specification of device path
244 device
= kwargs
.get("device")
248 if not self
.device
or not os
.path
.exists(self
.device
):
249 raise FormatSetupError("invalid device specification")
251 def teardown(self
, *args
, **kwargs
):
256 return (self
.exists
and
257 self
.__class
__ is not DeviceFormat
and
258 isinstance(self
.device
, str) and
260 os
.path
.exists(self
.device
))
263 def formattable(self
):
264 """ Can we create formats of this type? """
265 return self
._formattable
269 """ Is this format a supported type? """
270 return self
._supported
274 """ Can formats of this type be resized? """
275 return self
._resizable
279 """ Is this format type suitable for a boot partition? """
280 return self
._bootable
283 def migratable(self
):
284 """ Can formats of this type be migrated? """
285 return self
._migratable
292 def linuxNative(self
):
293 """ Is this format type native to linux? """
294 return self
._linuxNative
298 """ Is this something we can mount? """
303 """ Whether or not this format will be dumped by dump(8). """
308 """ Whether or not this format is checked on boot. """
313 """ Maximum size (in MB) for this format type. """
318 """ Minimum size (in MB) for this format type. """
322 collect_device_format_classes()