Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@elazarl
Created April 30, 2019 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elazarl/0083bce717491568403b34a14caa696d to your computer and use it in GitHub Desktop.
Save elazarl/0083bce717491568403b34a14caa696d to your computer and use it in GitHub Desktop.
Create an image with filesystem, copies a local directory content to it
#!/usr/bin/python3
"""Create image from a directory
This script creates image whose contents are a given directoy on the filesystem.
Example usage:
$ mkdir mydir
$ echo A > mydir/a
$ ./dir2img.py -d mydir -i myimage.img
$ virt-ls -a myimage.img /
a
$ virt-cat -a myimage.img /a
A
Requirements:
command line utilities:
- losetup
- rsync
- mount
- umount
root permissions for creating the loopback device and mounting the image
"""
import argparse
import os
import subprocess
import tempfile
def main():
parser = argparse.ArgumentParser("create a filesystem from directory to image file")
parser.add_argument('-d' ,'--dir', required=True, help='directory to pack in image')
parser.add_argument('-i', '--image', required=True, help='image file name')
parser.add_argument('-s' ,'--size', default='*2', help='size of the image, prefix with * or + to set it to directory size + or * a ratio')
args = parser.parse_args()
size = get_size(args.dir)
if args.size.startswith('*'):
size *= float(args.size[1:])
elif args.size.startswith('+'):
size += int(args.size[1:])
elif size > int(args.size):
size = args.size
else:
raise ErrorException('Cannot create image smaller than directory size')
# round to nearest sector size
size = ((size-1)/512 + 1)*512
# ensure tiny ext4 can fit image
size = max(size, 100*1024)
print('creating file of size %d bytes' % size)
with open(args.image, 'w') as fp:
fp.truncate(size)
subprocess.check_call(['mkfs.ext4', args.image])
lodevice = subprocess.check_output(['losetup', '-f']).strip()
subprocess.check_call(['losetup', lodevice, args.image])
tempdir = None
try:
tempdir = tempfile.mkdtemp(prefix='losetup_mounted_dir')
subprocess.check_call(['mount', lodevice, tempdir])
try:
subprocess.check_call(['rsync', '-aP', args.dir+'/', tempdir])
finally:
subprocess.check_call(['umount', tempdir])
finally:
if tempdir:
os.removedirs(tempdir)
subprocess.check_call(['losetup', '-d', lodevice])
class ErrorException(Exception):
pass
def get_size(start_path):
total_size = 0
for dirpath, dirnames, filenames in os.walk(start_path):
for f in filenames:
fp = os.path.join(dirpath, f)
total_size += os.path.getsize(fp)
return total_size
if __name__ == '__main__':
try:
main()
except ErrorException as e:
print(e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment