diff options
author | Jose M. Guisado <jguisado@soleta.eu> | 2023-04-25 14:03:29 +0200 |
---|---|---|
committer | Jose M. Guisado <jguisado@soleta.eu> | 2023-05-02 17:31:08 +0200 |
commit | dd999bfe34e7f812d4ce61828f262ee06b5d4fa4 (patch) | |
tree | 587d17a5f5226f53892e0413bdd36c0e5c2f1c1d /src/utils/fs.py | |
parent | 22dce48d3ec27d0db8f6a069744d44454382bcc4 (diff) |
utils: rewrite ogReduceFs
Drop subprocess call to bash function ogReduceFs. Use a native python
solution with subprocess calls to the required underlying tools.
Use get_filesystem_type to get the filesystem from a partition and call
the corresponding supported filesystem shrink function.
Filesystem specific functions are declared "_reduce_{filesystem}" and
should not be imported elsewhere.
In case of NTFS filesystems, the output of 'ntfsresize' is processed
directly. This is dirty, but we can expect no changes to the output
strings if we read the following comment in the nftsresize.c source
code:
https://github.com/tuxera/ntfs-3g/blob/edge/ntfsprogs/ntfsresize.c#L12
ntfsresize requires to do previous dry-run executions to confirm
that the resizing is possible.
If a dry-run fails but a 10% increase in size is still smaller than
original filesystem then retry the operation until dry-run reports
sucess or the size increase is bigger than original.
If resizing to a smaller ntfs filesystem is not possible then ogReduceFs
will do nothing.
Diffstat (limited to 'src/utils/fs.py')
-rw-r--r-- | src/utils/fs.py | 61 |
1 files changed, 52 insertions, 9 deletions
diff --git a/src/utils/fs.py b/src/utils/fs.py index a7058a7..bffdb8c 100644 --- a/src/utils/fs.py +++ b/src/utils/fs.py @@ -82,15 +82,21 @@ def get_usedperc(mountpoint): def ogReduceFs(disk, part): """ - Bash function 'ogReduceFs' wrapper - """ - proc = subprocess.run(f'ogReduceFs {disk} {part}', - shell=True, stdout=PIPE, - encoding='utf-8') - if proc.returncode != 0: - logging.warn(f'ogReduceFS exited with non zero code: {proc.returncode}') - subprocess.run(f'ogUnmount {disk} {part}', - shell=True) + Shrink filesystem of a partition. Supports ext4 and ntfs partitions. + Unsupported filesystem or invalid paths don't raise an exception, + instead this method logs a warning message and does nothing. + """ + partdev = get_partition_device(disk, part) + fstype = get_filesystem_type(partdev) + + umount(partdev) + if fstype == 'ext4': + _reduce_resize2fs(partdev) + elif fstype == 'ntfs': + _reduce_ntfsresize(partdev) + else: + logging.warn(f'Unable to shrink filesystem at {partdev}. ' + f'Unsupported filesystem "{fstype}".') def ogExtendFs(disk, part): @@ -177,3 +183,40 @@ def get_filesystem_type(partdev): if proc.returncode != 0: raise RuntimeError(f'Error getting filesystem from {partdev}') return proc.stdout.strip() + + +def _reduce_resize2fs(partdev): + cmd = shlex.split(f'resize2fs -fpM {partdev}') + with open('/tmp/command.log', 'ab', 0) as logfile: + subprocess.run(cmd, stdout=logfile, stderr=STDOUT) + + +def _reduce_ntfsresize(partdev): + cmd_info = shlex.split(f'ntfsresize -Pfi {partdev}') + proc_info = subprocess.run(cmd_info, stdout=subprocess.PIPE, encoding='utf-8') + out_info = proc_info.stdout.strip() + + # Process ntfsresize output directly. + # The first split operation leaves the wanted data at the second element of + # the split ([1]). Finally do a second split with ' ' to get the data but + # nothing else following it. + # + # In addition, increase by 10%+1K the reported shrink location on which the + # filesystem can be resized according to ntfsresize. + size = int(out_info.split('device size: ')[1].split(' ')[0]) + new_size = int(int(out_info.split('resize at ')[1].split(' ')[0])*1.1+1024) + + # Dry-run loop to test if resizing is actually possible. This is required by ntfsresize. + returncode = 1 + while new_size < size and returncode != 0: + cmd_resize_dryrun = shlex.split(f'ntfsresize -Pfns {new_size:.0f} {partdev}') + proc_resize_dryrun = subprocess.run(cmd_resize_dryrun, stdout=subprocess.PIPE, encoding='utf-8') + returncode = proc_resize_dryrun.returncode + out_resize_dryrun = proc_resize_dryrun.stdout.strip() + extra_size = int(out_resize_dryrun.split('Needed relocations : ')[1].split(' ')[0])*1.1+1024 + new_size += int(extra_size) + + if new_size < size: + cmd_resize = shlex.split(f'ntfsresize -fs {new_size:.0f} {partdev}') + with open('/tmp/command.log', 'ab', 0) as logfile: + subprocess.run(cmd_resize, input='y', stderr=STDOUT, encoding='utf-8') |