whew. finally done block.py.
the msdos table primary/extended/logical thing was a pain but the logic wasn't too bad.
This commit is contained in:
		
							parent
							
								
									305a0db34f
								
							
						
					
					
						commit
						9dada73cf0
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -18,3 +18,4 @@ | |||||||
| .*.swp | .*.swp | ||||||
| .editix | .editix | ||||||
| __pycache__/ | __pycache__/ | ||||||
|  | test.py | ||||||
|  | |||||||
| @ -1,4 +1,8 @@ | |||||||
|  | import os | ||||||
|  | import re | ||||||
|  | ## | ||||||
| import parted | import parted | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| PARTED_FSTYPES = list(dict(vars(parted.filesystem))['fileSystemType'].keys()) | PARTED_FSTYPES = list(dict(vars(parted.filesystem))['fileSystemType'].keys()) | ||||||
|  | 
 | ||||||
|  | |||||||
							
								
								
									
										0
									
								
								aif/disk/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								aif/disk/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -18,10 +18,11 @@ import blkinfo | |||||||
| import parted  # https://www.gnu.org/software/parted/api/index.html | import parted  # https://www.gnu.org/software/parted/api/index.html | ||||||
| import psutil | import psutil | ||||||
| ## | ## | ||||||
| from .aif_util import xmlBool | from aif.aif_util import xmlBool | ||||||
| from .constants import PARTED_FSTYPES |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | PARTED_FSTYPES = list(dict(vars(parted.filesystem))['fileSystemType'].keys()) | ||||||
|  | 
 | ||||||
| # parted lib can do SI or IEC (see table to right at https://en.wikipedia.org/wiki/Binary_prefix) | # parted lib can do SI or IEC (see table to right at https://en.wikipedia.org/wiki/Binary_prefix) | ||||||
| # We bit-shift to do conversions: | # We bit-shift to do conversions: | ||||||
| # https://stackoverflow.com/a/12912296/733214 | # https://stackoverflow.com/a/12912296/733214 | ||||||
| @ -61,11 +62,24 @@ def convertSizeUnit(pos): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Partition(object): | class Partition(object): | ||||||
|     def __init__(self, part_xml, diskobj, start_sector, partnum, tbltype): |     def __init__(self, part_xml, diskobj, start_sector, partnum, tbltype, part_type = None): | ||||||
|         if tbltype not in ('gpt', 'msdos'): |         if tbltype not in ('gpt', 'msdos'): | ||||||
|             raise ValueError('{0} must be one of gpt or msdos'.format(tbltype)) |             raise ValueError('{0} must be one of gpt or msdos'.format(tbltype)) | ||||||
|  |         if tbltype == 'msdos' and part_type not in ('primary', 'extended', 'logical'): | ||||||
|  |             raise ValueError(('You must specify if this is a ' | ||||||
|  |                               'primary, extended, or logical partition for msdos partition tables')) | ||||||
|         self.xml = part_xml |         self.xml = part_xml | ||||||
|         self.partnum = partnum |         self.partnum = partnum | ||||||
|  |         if tbltype == 'msdos': | ||||||
|  |             if partnum > 4: | ||||||
|  |                 self.part_type = parted.PARTITION_LOGICAL | ||||||
|  |             else: | ||||||
|  |                 if part_type == 'extended': | ||||||
|  |                     self.part_type = parted.PARTITION_EXTENDED | ||||||
|  |                 elif part_type == 'logical': | ||||||
|  |                     self.part_type = parted.PARTITION_LOGICAL | ||||||
|  |         else: | ||||||
|  |             self.part_type = parted.PARTITION_NORMAL | ||||||
|         self.fstype = self.xml.attrib['fsType'].lower() |         self.fstype = self.xml.attrib['fsType'].lower() | ||||||
|         if self.fstype not in PARTED_FSTYPES: |         if self.fstype not in PARTED_FSTYPES: | ||||||
|             raise ValueError(('{0} is not a valid partition filesystem type; ' |             raise ValueError(('{0} is not a valid partition filesystem type; ' | ||||||
| @ -73,7 +87,8 @@ class Partition(object): | |||||||
|                                                             ', '.join(sorted(PARTED_FSTYPES)))) |                                                             ', '.join(sorted(PARTED_FSTYPES)))) | ||||||
|         self.disk = diskobj |         self.disk = diskobj | ||||||
|         self.device = self.disk.device |         self.device = self.disk.device | ||||||
|         self.dev = '{0}{1}'.format(self.device.path, partnum) |         self.devpath = '{0}{1}'.format(self.device.path, partnum) | ||||||
|  |         self.is_hiformatted = False | ||||||
|         sizes = {} |         sizes = {} | ||||||
|         for s in ('start', 'stop'): |         for s in ('start', 'stop'): | ||||||
|             x = dict(zip(('from_bgn', 'size', 'type'), |             x = dict(zip(('from_bgn', 'size', 'type'), | ||||||
| @ -95,7 +110,7 @@ class Partition(object): | |||||||
|             if sizes['stop'][1]: |             if sizes['stop'][1]: | ||||||
|                 self.end = sizes['stop'][0] + 0 |                 self.end = sizes['stop'][0] + 0 | ||||||
|             else: |             else: | ||||||
|                 # This *technically* should be - 34, but the alignment optimizer fixes it for us. |                 # This *technically* should be - 34, at least for gpt, but the alignment optimizer fixes it for us. | ||||||
|                 self.end = (self.device.getLength() - 1) - sizes['stop'][0] |                 self.end = (self.device.getLength() - 1) - sizes['stop'][0] | ||||||
|         else: |         else: | ||||||
|             self.end = self.begin + sizes['stop'][0] |             self.end = self.begin + sizes['stop'][0] | ||||||
| @ -107,7 +122,7 @@ class Partition(object): | |||||||
|         self.filesystem = parted.FileSystem(type = self.fstype, |         self.filesystem = parted.FileSystem(type = self.fstype, | ||||||
|                                             geometry = self.geometry) |                                             geometry = self.geometry) | ||||||
|         self.partition = parted.Partition(disk = diskobj, |         self.partition = parted.Partition(disk = diskobj, | ||||||
|                                           type = parted.PARTITION_NORMAL, |                                           type = self.part_type, | ||||||
|                                           geometry = self.geometry, |                                           geometry = self.geometry, | ||||||
|                                           fs = self.filesystem) |                                           fs = self.filesystem) | ||||||
|         if tbltype == 'gpt' and self.xml.attrib.get('name'): |         if tbltype == 'gpt' and self.xml.attrib.get('name'): | ||||||
| @ -123,32 +138,22 @@ class Disk(object): | |||||||
|     def __init__(self, disk_xml): |     def __init__(self, disk_xml): | ||||||
|         self.xml = disk_xml |         self.xml = disk_xml | ||||||
|         self.devpath = self.xml.attrib['device'] |         self.devpath = self.xml.attrib['device'] | ||||||
|         self.partitions = [] |  | ||||||
|         self._initDisk() |         self._initDisk() | ||||||
| 
 | 
 | ||||||
|     def _initDisk(self): |     def _initDisk(self): | ||||||
|  |         self.tabletype = self.xml.attrib.get('diskFormat', 'gpt').lower() | ||||||
|  |         if self.tabletype in ('bios', 'mbr', 'dos'): | ||||||
|  |             self.tabletype = 'msdos' | ||||||
|  |         validlabels = parted.getLabels() | ||||||
|  |         if self.tabletype not in validlabels: | ||||||
|  |             raise ValueError(('Disk format {0} is not valid for this architecture;' | ||||||
|  |                               'must be one of: {1}'.format(self.tabletype, ', '.join(list(validlabels))))) | ||||||
|         self.device = parted.getDevice(self.devpath) |         self.device = parted.getDevice(self.devpath) | ||||||
|         try: |         self.disk = parted.freshDisk(self.device, self.tabletype) | ||||||
|             self.disk = parted.newDisk(self.device) |  | ||||||
|             self.is_new = False |  | ||||||
|             if xmlBool(self.xml.attrib.get('forceReformat')): |  | ||||||
|                 self.is_lowformatted = False |  | ||||||
|                 self.is_hiformatted = False |  | ||||||
|             else: |  | ||||||
|                 self.is_lowformatted = True |  | ||||||
|                 self.is_hiformatted = False |  | ||||||
|                 for d in blkinfo.BlkDiskInfo().get_disks(filters = {'group': 'disk', |  | ||||||
|                                                                     'name': os.path.basename(self.devpath), |  | ||||||
|                                                                     'kname': os.path.basename(self.devpath)}): |  | ||||||
|                     if d.get('fstype', '').strip() != '': |  | ||||||
|                         self.is_hiformatted = True |  | ||||||
|                         break |  | ||||||
|         except parted._ped.DiskException: |  | ||||||
|             self.disk = None |  | ||||||
|             self.is_new = True |  | ||||||
|         self.is_lowformatted = False |         self.is_lowformatted = False | ||||||
|         self.is_hiformatted = False |         self.is_hiformatted = False | ||||||
|         self.is_partitioned = False |         self.is_partitioned = False | ||||||
|  |         self.partitions = [] | ||||||
|         return() |         return() | ||||||
| 
 | 
 | ||||||
|     def diskFormat(self): |     def diskFormat(self): | ||||||
| @ -158,37 +163,34 @@ class Disk(object): | |||||||
|         for p in psutil.disk_partitions(all = True): |         for p in psutil.disk_partitions(all = True): | ||||||
|             if self.devpath in p: |             if self.devpath in p: | ||||||
|                 raise RuntimeError('{0} is mounted; we are cowardly refusing to low-format it'.format(self.devpath)) |                 raise RuntimeError('{0} is mounted; we are cowardly refusing to low-format it'.format(self.devpath)) | ||||||
|         if not self.is_new: |  | ||||||
|         self.disk.deleteAllPartitions() |         self.disk.deleteAllPartitions() | ||||||
|         self.tabletype = self.xml.attrib.get('diskFormat', 'gpt').lower() |         self.disk.commit() | ||||||
|         if self.tabletype in ('bios', 'mbr', 'dos'): |  | ||||||
|             self.tabletype = 'msdos' |  | ||||||
|         validlabels = parted.getLabels() |  | ||||||
|         if self.tabletype not in validlabels: |  | ||||||
|             raise ValueError(('Disk format {0} is not valid for this architecture;' |  | ||||||
|                               'must be one of: {1}'.format(self.tabletype, ', '.join(list(validlabels))))) |  | ||||||
|         self.disk = parted.freshDisk(self.device, self.tabletype) |  | ||||||
|         self.is_lowformatted = True |         self.is_lowformatted = True | ||||||
|         return() |         self.is_partitioned = False | ||||||
| 
 |  | ||||||
|     def fsFormat(self): |  | ||||||
|         if self.is_hiformatted: |  | ||||||
|             return() |  | ||||||
|         # This is a safeguard. We do *not* want to high-format a disk that is mounted. |  | ||||||
|         for p in psutil.disk_partitions(all = True): |  | ||||||
|             if self.devpath in p: |  | ||||||
|                 raise RuntimeError('{0} is mounted; we are cowardly refusing to high-format it'.format(self.devpath)) |  | ||||||
|         # TODO! |  | ||||||
|         pass |  | ||||||
|         return() |         return() | ||||||
| 
 | 
 | ||||||
|     def getPartitions(self): |     def getPartitions(self): | ||||||
|         # For GPT, this *technically* should be 34 -- or, more precisely, 2048 (see FAQ in manual), but the alignment |         # For GPT, this *technically* should be 34 -- or, more precisely, 2048 (see FAQ in manual), but the alignment | ||||||
|         # optimizer fixes it for us automatically. |         # optimizer fixes it for us automatically. | ||||||
|  |         # But for DOS tables, it's required. | ||||||
|  |         if self.tabletype == 'msdos': | ||||||
|  |             start_sector = 2048 | ||||||
|  |         else: | ||||||
|             start_sector = 0 |             start_sector = 0 | ||||||
|         self.partitions = [] |         self.partitions = [] | ||||||
|         for idx, part in enumerate(self.xml.findall('part')): |         xml_partitions = self.xml.findall('part') | ||||||
|             p = Partition(part, self.disk, start_sector, idx + 1, self.tabletype) |         for idx, part in enumerate(xml_partitions): | ||||||
|  |             partnum = idx + 1 | ||||||
|  |             if self.tabletype == 'gpt': | ||||||
|  |                 p = Partition(part, self.disk, start_sector, partnum, self.tabletype) | ||||||
|  |             else: | ||||||
|  |                 parttype = 'primary' | ||||||
|  |                 if len(xml_partitions) > 4: | ||||||
|  |                     if partnum == 4: | ||||||
|  |                         parttype = 'extended' | ||||||
|  |                     elif partnum > 4: | ||||||
|  |                         parttype = 'logical' | ||||||
|  |                 p = Partition(part, self.disk, start_sector, partnum, self.tabletype, part_type = parttype) | ||||||
|             start_sector = p.end + 1 |             start_sector = p.end + 1 | ||||||
|             self.partitions.append(p) |             self.partitions.append(p) | ||||||
|         return() |         return() | ||||||
| @ -209,5 +211,7 @@ class Disk(object): | |||||||
|         for p in self.partitions: |         for p in self.partitions: | ||||||
|             self.disk.addPartition(partition = p, constraint = self.device.optimalAlignedConstraint) |             self.disk.addPartition(partition = p, constraint = self.device.optimalAlignedConstraint) | ||||||
|             self.disk.commit() |             self.disk.commit() | ||||||
|  |             p.devpath = p.partition.path | ||||||
|  |             p.is_hiformatted = True | ||||||
|         self.is_partitioned = True |         self.is_partitioned = True | ||||||
|         return() |         return() | ||||||
							
								
								
									
										75
									
								
								aif/disk/filesystem.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								aif/disk/filesystem.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | |||||||
|  | import os | ||||||
|  | import re | ||||||
|  | import subprocess | ||||||
|  | ## | ||||||
|  | import psutil | ||||||
|  | ## | ||||||
|  | from aif.disk.block import Partition | ||||||
|  | from aif.disk.luks import LUKS | ||||||
|  | from aif.disk.lvm import Group as LVMGroup | ||||||
|  | from aif.disk.mdadm import Array as MDArray | ||||||
|  | 
 | ||||||
|  | # I wish there was a better way of doing this. | ||||||
|  | # https://unix.stackexchange.com/a/98680 | ||||||
|  | FS_FSTYPES = [] | ||||||
|  | with open('/proc/filesystems', 'r') as fh: | ||||||
|  |     for line in fh.readlines(): | ||||||
|  |         l = [i.strip() for i in line.split()] | ||||||
|  |         if not l: | ||||||
|  |             continue | ||||||
|  |         if len(l) == 1: | ||||||
|  |             FS_FSTYPES.append(l[0]) | ||||||
|  |         else: | ||||||
|  |             FS_FSTYPES.append(l[1]) | ||||||
|  | _mod_dir = os.path.join('/lib/modules', | ||||||
|  |                         os.uname().release, | ||||||
|  |                         'kernel/fs') | ||||||
|  | _strip_mod_suffix = re.compile(r'(?P<fsname>)\.ko(\.(x|g)?z))?$', re.IGNORECASE) | ||||||
|  | for i in os.listdir(_mod_dir): | ||||||
|  |     path = os.path.join(_mod_dir, i) | ||||||
|  |     fs_name = None | ||||||
|  |     if os.path.isdir(path): | ||||||
|  |         fs_name = i | ||||||
|  |     elif os.path.isfile(path): | ||||||
|  |         mod_name = _strip_mod_suffix.search(i) | ||||||
|  |         fs_name = mod_name.group('fsname') | ||||||
|  |     if fs_name: | ||||||
|  |         # The kernel *probably* has autoloading enabled, but in case it doesn't... | ||||||
|  |         # TODO: logging! | ||||||
|  |         subprocess.run(['modprobe', fs_name]) | ||||||
|  |         FS_FSTYPES.append(fs_name) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class FS(object): | ||||||
|  |     def __init__(self, fs_xml, sourceobj): | ||||||
|  |         self.xml = fs_xml | ||||||
|  |         if not isinstance(sourceobj, (Partition, LUKS, LVMGroup, MDArray)): | ||||||
|  |             raise ValueError(('sourceobj must be of type ' | ||||||
|  |                               'aif.disk.block.Partition, ' | ||||||
|  |                               'aif.disk.luks.LUKS, ' | ||||||
|  |                               'aif.disk.lvm.Group, or' | ||||||
|  |                               'aif.disk.mdadm.Array')) | ||||||
|  |         self.source = sourceobj | ||||||
|  |         self.devpath = sourceobj.devpath | ||||||
|  |         self.formatted = False | ||||||
|  |         self.fstype = self.xml.attrib.get('type') | ||||||
|  | 
 | ||||||
|  |     def format(self): | ||||||
|  |         if self.formatted: | ||||||
|  |             return () | ||||||
|  |         # This is a safeguard. We do *not* want to high-format a disk that is mounted. | ||||||
|  |         for p in psutil.disk_partitions(all = True): | ||||||
|  |             if self.devpath in p: | ||||||
|  |                 raise RuntimeError(('{0} is mounted;' | ||||||
|  |                                     'we are cowardly refusing to apply a filesystem to it').format(self.devpath)) | ||||||
|  |         # TODO! Logging | ||||||
|  |         cmd = ['mkfs', | ||||||
|  |                '-t', self.fstype] | ||||||
|  |         for o in self.xml.findall('opt'): | ||||||
|  |             cmd.append(o.attrib['name']) | ||||||
|  |             if o.text: | ||||||
|  |                 cmd.append(o.text) | ||||||
|  |         cmd.append(self.devpath) | ||||||
|  |         subprocess.run(cmd) | ||||||
|  |         self.is_hiformatted = True | ||||||
|  |         return() | ||||||
							
								
								
									
										4
									
								
								aif/disk/luks.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								aif/disk/luks.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | class LUKS(object): | ||||||
|  |     def __init__(self): | ||||||
|  |         self.devpath = None | ||||||
|  |         pass | ||||||
							
								
								
									
										13
									
								
								aif/disk/lvm.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								aif/disk/lvm.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | class PV(object): | ||||||
|  |     def __init__(self, partobj): | ||||||
|  |         self.devpath = None | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  | class LV(object): | ||||||
|  |     def __init__(self, lv_xml, pv_objs): | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  | class Group(object): | ||||||
|  |     def __init__(self, vg_xml, lv_objs): | ||||||
|  |         self.devpath = None | ||||||
|  |         pass | ||||||
							
								
								
									
										11
									
								
								aif/disk/mdadm.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								aif/disk/mdadm.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | class Member(object): | ||||||
|  |     def __init__(self, member_xml, partobj): | ||||||
|  |         self.xml = member_xml | ||||||
|  |         self.device = partobj | ||||||
|  |         self.devpath = self.device.devpath | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  | class Array(object): | ||||||
|  |     def __init__(self, array_xml): | ||||||
|  |         self.devpath = None | ||||||
|  |         pass | ||||||
| @ -3,7 +3,7 @@ | |||||||
|      xmlns="http://aif-ng.io/" |      xmlns="http://aif-ng.io/" | ||||||
|      xsi:schemaLocation="http://aif-ng.io/aif.xsd"> |      xsi:schemaLocation="http://aif-ng.io/aif.xsd"> | ||||||
|     <storage> |     <storage> | ||||||
|         <disk device="/dev/sda" diskFormat="gpt" forceReformat="true"> |         <disk device="/dev/sda" diskFormat="gpt"> | ||||||
|             <!-- Partitions are numbered *in the order they are specified*. --> |             <!-- Partitions are numbered *in the order they are specified*. --> | ||||||
|             <part id="boot" name="BOOT" label="/boot" start="0%" stop="10%" fsType="ef00"/><!-- e.g. this would be /dev/sda1 --> |             <part id="boot" name="BOOT" label="/boot" start="0%" stop="10%" fsType="ef00"/><!-- e.g. this would be /dev/sda1 --> | ||||||
|             <part id="secrets1" name="crypted" label="shh" start="10%" stop="20%" fsType="8300"/> |             <part id="secrets1" name="crypted" label="shh" start="10%" stop="20%" fsType="8300"/> | ||||||
| @ -12,11 +12,6 @@ | |||||||
|             <part id="raid1_d2" start="55%" stop="80%" fsType="fd00"/> |             <part id="raid1_d2" start="55%" stop="80%" fsType="fd00"/> | ||||||
|             <part id="swap" start="80%" stop="100%" fsType="8200" /> |             <part id="swap" start="80%" stop="100%" fsType="8200" /> | ||||||
|         </disk> |         </disk> | ||||||
|         <fileSystems> |  | ||||||
|             <fs source="boot" type="vfat"> |  | ||||||
|                 <opts>-F 32 -n {label}</opts> |  | ||||||
|             </fs> |  | ||||||
|         </fileSystems> |  | ||||||
|         <!-- "Special" devices are processed *in the order they are specified*. This is important if you wish to |         <!-- "Special" devices are processed *in the order they are specified*. This is important if you wish to | ||||||
|              e.g. layer LUKS on top of LVM - you would specify <lvm> before <luks> and reference the |              e.g. layer LUKS on top of LVM - you would specify <lvm> before <luks> and reference the | ||||||
|              <luksDev id="SOMETHING" ... > as <lvmLogical source="SOMETHING" ... />. --> |              <luksDev id="SOMETHING" ... > as <lvmLogical source="SOMETHING" ... />. --> | ||||||
| @ -34,8 +29,27 @@ | |||||||
|                 <member source="raid1_d2"/> |                 <member source="raid1_d2"/> | ||||||
|             </array> |             </array> | ||||||
|         </mdadm> |         </mdadm> | ||||||
|  |         <fileSystems> | ||||||
|  |             <fs source="boot" type="vfat"> | ||||||
|  |                 <!-- Supports mkfs arguments. Leave off the filesystem type and device name, obviously; | ||||||
|  |                      those are handled by the above attributes. --> | ||||||
|  |                 <opt name="-F">32</opt> | ||||||
|  |                 <opt name="-n">ESP</opt> | ||||||
|  |             </fs> | ||||||
|  |             <fs source="luks_secrets" type="ext4"> | ||||||
|  |                 <opt name="-L">seekrit</opt> | ||||||
|  |             </fs> | ||||||
|  |         </fileSystems> | ||||||
|         <!-- And you use the id to reference mountpoints as well. --> |         <!-- And you use the id to reference mountpoints as well. --> | ||||||
|         <mount source="luks_secrets" target="/mnt/aif" order="1" /> |         <mount source="luks_secrets" target="/mnt/aif" order="1"> | ||||||
|  |             <opt name="rw"/> | ||||||
|  |             <opt name="relatime"/> | ||||||
|  |             <opt name="compress">lzo</opt> | ||||||
|  |             <opt name="ssd"/> | ||||||
|  |             <opt name="space_cache"/> | ||||||
|  |             <opt name="subvolid">5</opt> | ||||||
|  |             <opt name="subvol">/</opt> | ||||||
|  |         </mount> | ||||||
|         <mount source="boot" target="/mnt/aif/boot" order="2" /> |         <mount source="boot" target="/mnt/aif/boot" order="2" /> | ||||||
|         <mount source="swap" target="swap" order="3" /> |         <mount source="swap" target="swap" order="3" /> | ||||||
|         <mount source="vg1" target="/mnt/aif/mnt/pool" order="4" /> |         <mount source="vg1" target="/mnt/aif/mnt/pool" order="4" /> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 brent s
						brent s