#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Name: persistence.py # Purpose: Module to deal with persistence of a selected distro. # Authors: Sundar # Licence: This file is a part of multibootusb package. You can redistribute it or modify # under the terms of GNU General Public License, v.2 or above from functools import partial import os import platform import stat import subprocess import tarfile from . import iso from . import gen from . import config def max_disk_persistence(usb_disk): """ Detect max persistence value for filesystem on usb_disk :param usb_disk: Disk filesystem to check :return: Max persistence supported (bytes) """ assert usb_disk is not None fat_max_size = (4096 * 1024 * 1024) usb_details = config.usb_details config.usb_uuid = usb_details['uuid'] config.usb_label = usb_details['label'] size_free = usb_details['size_free'] if usb_details['file_system'] in ['vfat', 'FAT32']: _max_size = min(fat_max_size, size_free) else: _max_size = size_free return _max_size def persistence_distro(distro, iso_link): """ Function to detect if distro can have persistence option. :param distro: Detected distro name. :return: Distro name as string or None otherwise. """ assert distro is not None assert iso_link is not None # iso_size = iso.iso_size(iso_link) if distro in ["ubuntu", "debian", "debian-install", "fedora", "centos"]: gen.log("Persistence option is available.") return distro else: return None def create_persistence_using_mkfs(persistence_fname, persistence_size): persistence_path = os.path.join(config.usb_mount, 'multibootusb', iso.iso_basename(config.image_path), persistence_fname) volume_name = os.path.basename(persistence_fname) if platform.system() == 'Windows': tools_dir = os.path.join('data', 'tools') mke2fs_relative_path = os.path.join(tools_dir, 'mkfs', 'mke2fs.exe') mkfs = gen.resource_path(mke2fs_relative_path) dd_relative_path = os.path.join(tools_dir, 'dd', 'dd.exe') dd = gen.resource_path(dd_relative_path) persistence_mkfs_cmd = 'echo y|' + mkfs + ' -b 1024 ' + \ '-L ' + volume_name + ' ' + \ persistence_path else: mkfs = 'mkfs.ext3' dd = 'dd' persistence_mkfs_cmd = mkfs + ' -F ' + persistence_path mbytes = persistence_size / 1024 / 1024 persistence_dd_cmd = dd + ' if=/dev/zero ' + \ 'of=' + persistence_path + \ ' bs=1M count=' + str(int(mbytes)) gen.log('Executing ==>' + persistence_dd_cmd) config.status_text = 'Creating persistence file...' if subprocess.call(persistence_dd_cmd, shell=True) == 0: gen.log("\nSuccessfully created persistence file...\n") if config.distro != 'fedora': gen.log('Applying filesystem to persistence file...') config.status_text = 'Applying filesystem to persistence file. Please wait...' gen.log('Executing ==> ' + persistence_mkfs_cmd) config.status_text = 'Applying filesystem to persistence file...' if subprocess.call(persistence_mkfs_cmd, shell=True) == 0: gen.log("\nSuccessfully applied filesystem...\n") def create_persistence_using_resize2fs(persistence_fname, persistence_size): outdir = os.path.join(config.usb_mount, 'multibootusb', iso.iso_basename(config.image_path)) persistence_path = os.path.join(outdir, persistence_fname) tools_dir = os.path.join('data', 'tools') if platform.system()=='Windows': _7zip_exe = gen.resource_path( os.path.join(tools_dir, '7zip', '7z.exe')) e2fsck_exe = gen.resource_path(os.path.join(tools_dir, 'cygwin', 'e2fsck.exe')) resize2fs_exe = gen.resource_path(os.path.join(tools_dir, 'cygwin', 'resize2fs.exe')) else: _7zip_exe = '7z' e2fsck_exe = 'e2fsck' resize2fs_exe = 'resize2fs' config.status_text = 'Copying persistence file...' persistence_gz = gen.resource_path( os.path.join(tools_dir, 'persistence.gz')) _7zip_cmd_base = [_7zip_exe, 'x', '-o' + outdir] for more_opts in ( ['-y'], ['-aoa'] ): _7zip_cmd = _7zip_cmd_base + more_opts + [persistence_gz] if subprocess.call(_7zip_cmd)==0: if not os.path.exists(persistence_path): gen.log("%s has failed to create the persistence file." % _7zip_cmd) continue gen.log("Generated 'persistence' file in '%s'" % outdir) if persistence_fname != 'persistence': os.rename(os.path.join(outdir, 'persistence'), persistence_path) gen.log("Renamed to '%s'." % persistence_path) break gen.log("%s has failed with non-zero exit status." % _7zip_cmd) else: gen.log("Couldn't generate persistence file '%s' by any means." % persistence_path) return current_size = os.stat(persistence_path)[stat.ST_SIZE] if current_size < persistence_size: msg = 'Extending the persistence file by %.1f MB...' % \ ((persistence_size - current_size) / float(1024*1024)) config.status_text = msg gen.log(msg) with open(persistence_path, 'ab') as f: _1M_block = b'\0' * (1024*1024) bytes_left = persistence_size - current_size while 0