You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
multibootusb/scripts/gen.py

421 lines
15 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*
# Name: gen.py
# Purpose: This 'general' module contain many functions required to be called at many places
# 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
import logging
import sys
import os
import platform
import shutil
import string
import zipfile
import re
import ctypes
from . import config
from .osdriver import get_physical_disk_number, wmi_get_drive_info, \
log, resource_path, multibootusb_host_dir
def scripts_dir_path():
return os.path.dirname(os.path.realpath(__file__))
def print_version():
"""
Simple log the version number of the multibootusb application
:return:
"""
log('multibootusb version: ' + mbusb_version())
def quote(text):
"""
Function to quote the input word or sentence.
:param text: Any word or sentence.
:return: Quoted text or sentence. If already quoted the same text is returned.
"""
if not is_quoted(text):
return '"' + text + '"'
else:
return text
def is_quoted(text):
"""
Function to check if word is quoted.
:param text: Any word or sentence with or without quote.
:return: True if text is quoted else False.
"""
return bool(text.startswith("\"") and text.endswith("\""))
def has_digit(word):
"""
Useful function to detect if input word contain digit.
:param word: Any alphanumeric word.
:return: True if the word has a digit else False.
"""
return any(char.isdigit() for char in word)
def sys_64bits():
"""
Detect if the host system is 64 bit.
:return: True if system is 64 bit.
"""
return sys.maxsize > 2**32
def iso_cfg_ext_dir():
"""
Function to return the path to ISO configuration file extraction directory.
:return: Path to directory where ISO config files will be extracted.
"""
return os.path.join(multibootusb_host_dir(), 'iso_cfg_ext_dir')
def clean_iso_cfg_ext_dir(iso_cfg_ext_dir):
"""
Clean old ISO config files extracted by previous use of multibootusb.
:param iso_cfg_ext_dir: Path to config extract directory.
:return:
"""
if os.path.exists(iso_cfg_ext_dir):
for f in os.listdir(iso_cfg_ext_dir):
fullpath = os.path.join(iso_cfg_ext_dir, f)
if os.path.isdir(fullpath):
shutil.rmtree(fullpath)
else:
os.remove(fullpath)
else:
log('iso_cfg_ext_dir directory does not exist.')
def copy_mbusb_dir_usb(usb_disk):
"""
Copy the multibootusb directory to USB mount path.
:param usb_mount_path: Path to USB mount.
:return:
"""
# from .iso import iso_size
from .usb import details, PartitionNotMounted
try:
usb_details = details(usb_disk)
except PartitionNotMounted as e:
log(str(e))
return False
usb_mount_path = usb_details['mount_point']
result = ''
if not os.path.exists(os.path.join(usb_mount_path, "multibootusb")):
try:
log('Copying multibootusb directory to ' + usb_mount_path)
shutil.copytree(resource_path(os.path.join("data", "multibootusb")), os.path.join(usb_mount_path, "multibootusb"))
result = True
except:
log('multibootusb directory could not be copied to ' + usb_mount_path)
result = False
else:
log('multibootusb directory already exists. Not copying.')
if not os.path.exists(os.path.join(usb_mount_path, 'EFI', 'BOOT', 'multibootusb_grub2.txt')):
if not os.path.exists(os.path.join(usb_mount_path, 'EFI', 'BOOT')):
log('EFI/BOOT directory does not exist. Creating new.')
os.makedirs(os.path.join(usb_mount_path, 'EFI', 'BOOT'), exist_ok=True)
if os.path.exists(os.path.join(usb_mount_path, 'EFI')):
shutil.rmtree(os.path.join(usb_mount_path, 'EFI'))
try:
log('Copying EFI directory to ' + usb_mount_path)
shutil.copytree(resource_path(os.path.join("data", "EFI")), os.path.join(usb_mount_path, "EFI"))
result = True
except Exception as e:
log(e)
result = False
else:
log('EFI directory already exist. Not copying.')
'''
# For backward compatibility
if not os.path.exists(os.path.join(usb_mount_path, 'EFI', 'BOOT', 'bootx64-gpt.efi')):
shutil.copy(resource_path(os.path.join('data', 'EFI', 'BOOT', 'bootx64-gpt.efi')),
os.path.join(usb_mount_path, 'EFI', 'BOOT', 'bootx64-gpt.efi'))
if not os.path.exists(os.path.join(usb_mount_path, 'EFI', 'BOOT', 'bootx64-msdos.efi')):
shutil.copy(resource_path(os.path.join('data', 'EFI', 'BOOT', 'bootx64-msdos.efi')),
os.path.join(usb_mount_path, 'EFI', 'BOOT', 'bootx64-msdos.efi'))
if not os.path.exists(os.path.join(usb_mount_path, 'multibootusb', 'grub', 'core-gpt.img')):
shutil.copy(resource_path(os.path.join('data', 'multibootusb', 'grub', 'core-gpt.img')),
os.path.join(usb_mount_path, 'multibootusb', 'grub', 'core-gpt.img'))
if not os.path.exists(os.path.join(usb_mount_path, 'multibootusb', 'grub', 'core-msdos.img')):
shutil.copy(resource_path(os.path.join('data', 'multibootusb', 'grub', 'core-msdos.img')),
os.path.join(usb_mount_path, 'multibootusb', 'grub', 'core-msdos.img'))
if not os.path.exists(os.path.join(usb_mount_path, 'multibootusb', 'grub', 'x86_64-efi')):
log("New EFI modules does not exist. Copying now.")
shutil.copytree(resource_path(os.path.join('data', 'multibootusb', 'grub', 'x86_64-efi')),
os.path.join(usb_mount_path, 'multibootusb', 'grub', 'x86_64-efi'))
log("Replacing gpt efi binary with latest one.")
os.remove(os.path.join(usb_mount_path, 'EFI', 'BOOT', 'bootx64-gpt.efi'))
shutil.copy(resource_path(os.path.join('data', 'EFI', 'BOOT', 'bootx64-gpt.efi')),
os.path.join(usb_mount_path, 'EFI', 'BOOT', 'bootx64-gpt.efi'))
'''
# Warn users about older version
if not os.path.exists(os.path.join(usb_mount_path, 'multibootusb', 'grub', 'x86_64-efi')):
log("You have created live usb using old version of multibootusb.")
log("Please remove EFI and multibootusb directory and reinstall distros again.")
# Ensue that we have iso directory. Implemented from version 9.0.1
if not os.path.exists(os.path.join(usb_mount_path, 'multibootusb', 'iso')):
os.makedirs(os.path.join(usb_mount_path, 'multibootusb', 'iso'))
# Update the menu files from resource path to USB directory.
try:
with zipfile.ZipFile(resource_path(os.path.join('data', 'multibootusb', 'grub', 'menus.zip')), "r") as z:
z.extractall(os.path.join(usb_mount_path, 'multibootusb', 'grub', 'menus'))
except:
log('Unable to extract menu files to USB disk.')
return result
def read_input_yes():
"""
List option and read user input
:return: True if user selected yes or else false
"""
yes_list = ['Y', 'y', 'Yes', 'yes', 'YES']
no_list = ['N', 'n', 'No', 'no', 'NO']
response = input("Please enter the option listed above : ")
if response in yes_list:
return True
elif response in no_list:
return False
def strings(filename, _min=4):
with open(filename, errors="ignore") as f:
result = ""
for c in f.read():
if c in string.printable:
result += c
continue
if len(result) >= _min:
yield result
result = ""
if len(result) >= _min: # catch result at EOF
yield result
def size_not_enough(iso_link, usb_disk):
from .iso import iso_size
from .usb import details, PartitionNotMounted
isoSize = iso_size(iso_link)
try:
usb_details = details(usb_disk)
except PartitionNotMounted as e:
log(str(e))
return False
usb_size = usb_details['size_free']
return bool(isoSize > usb_size)
def mbusb_version():
version = open(resource_path(os.path.join("data", "version.txt")), 'r').read().strip()
return version
def check_text_in_file(file_path, text):
"""
Helper function to check if a text exist in a file.
:param file_path: Path to file
:param text: Text to be searched
:return: True if found else False
"""
if not os.path.exists(file_path):
return False
else:
with open(file_path) as data_file:
return any(text in line for line in data_file)
def prepare_mbusb_host_dir():
"""
Prepare multibootusb host directory and extract data files for use.
:return:
"""
home = multibootusb_host_dir()
if not os.path.exists(home):
os.makedirs(home)
else:
log("Cleaning old multibootusb directory...")
clean_iso_cfg_ext_dir(os.path.join(home, "iso_cfg_ext_dir"))
#shutil.rmtree(home)
#os.makedirs(home)
if not os.path.exists(os.path.join(home, "preference")):
os.makedirs(os.path.join(home, "preference"))
if not os.path.exists(os.path.join(home, "iso_cfg_ext_dir")):
os.makedirs(os.path.join(home, "iso_cfg_ext_dir"))
if os.path.exists(os.path.join(home, "syslinux", "bin", "syslinux4")):
log("Syslinux exist in multibootusb directory...")
else:
log("Extracting syslinux to multibootusb directory...")
if platform.system() == "Linux":
if sys_64bits() is True:
log('Host OS is 64 bit...')
log("Extracting syslinux 64 bit...")
# log(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_linux_64.zip")))
with zipfile.ZipFile(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_linux_64.zip")), "r") as z:
z.extractall(home)
else:
log("Extracting syslinux 32 bit...")
with zipfile.ZipFile(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_linux.zip")), "r") as z:
z.extractall(home)
else:
with zipfile.ZipFile(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_windows.zip")), "r") as z:
z.extractall(home)
log("Extracting syslinux modules to multibootusb directory...")
with zipfile.ZipFile(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_modules.zip")), "r") as z:
z.extractall(os.path.join(home, "syslinux"))
if os.listdir(os.path.join(home, "iso_cfg_ext_dir")):
log(os.listdir(os.path.join(home, "iso_cfg_ext_dir")))
log("iso extract directory is not empty.")
log("Removing junk files...")
for files in os.listdir(os.path.join(home, "iso_cfg_ext_dir")):
if os.path.isdir(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files))):
log(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
os.chmod(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)), 0o777)
shutil.rmtree(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
else:
try:
log(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
os.chmod(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)), 0o777)
os.unlink(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
os.remove(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
except OSError:
log("Can't remove the file. Skipping it.")
def grub_efi_exist(grub_efi_path):
"""
Detect efi present in USB disk is copied by multibootusb.
:param isolinux_path: Path to "grub efi image"
:return: True if yes else False
"""
from . import iso
if grub_efi_path is not None:
sl = list(iso.strings(grub_efi_path))
for strin in sl:
if re.search(r'multibootusb', strin, re.I):
return True
return False
def process_exist(process_name):
"""
Detect if process exist/ running and kill it.
:param process_name: process name to check
:return: True if processis killed else False
"""
if platform.system() == 'Windows':
import signal
import wmi
c = wmi.WMI()
for process in c.Win32_Process():
if process_name in process.Name:
log(process_name + ' exist...')
log(str(process.ProcessId) + ' ' + str(process.Name))
log("Having Windows explorer won't allow dd.exe to write ISO image properly."
"\nKilling the process..")
try:
os.kill(process.ProcessId, signal.SIGTERM)
return True
except:
log('Unable to kill process ' + str(process.ProcessId))
return False
def write_to_file(filepath, text):
"""
Simple function to write a text file
:param filepath: Path to file
:param text: Text to be written on to file
:return:
"""
with open(filepath, 'w') as f:
f.write(text.strip())
class MemoryCheck():
"""
Cross platform way to checks memory of a given system. Works on Linux and Windows.
psutil is a good option to get memory info. But version 5.0 and only will work.
Source: https://doeidoei.wordpress.com/2009/03/22/python-tip-3-checking-available-ram-with-python/
Call this class like this:
mem_info = memoryCheck()
print(mem_info.value)
"""
def __init__(self):
if platform.system() == 'Linux':
self.value = self.linuxRam()
elif platform.system() == 'Windows':
self.value = self.windowsRam()
else:
log("MemoryCheck Class will only work on Linux and Windows.")
def windowsRam(self):
"""
Uses Windows API to check RAM
"""
kernel32 = ctypes.windll.kernel32
c_ulong = ctypes.c_ulong
class MEMORYSTATUS(ctypes.Structure):
_fields_ = [
("dwLength", c_ulong),
("dwMemoryLoad", c_ulong),
("dwTotalPhys", c_ulong),
("dwAvailPhys", c_ulong),
("dwTotalPageFile", c_ulong),
("dwAvailPageFile", c_ulong),
("dwTotalVirtual", c_ulong),
("dwAvailVirtual", c_ulong)
]
memoryStatus = MEMORYSTATUS()
memoryStatus.dwLength = ctypes.sizeof(MEMORYSTATUS)
kernel32.GlobalMemoryStatus(ctypes.byref(memoryStatus))
return int(memoryStatus.dwTotalPhys / 1024 ** 2)
def linuxRam(self):
"""
Returns the RAM of a Linux system
"""
totalMemory = os.popen("free -m").readlines()[1].split()[1]
return int(totalMemory)
if __name__ == '__main__':
log(quote("""Test-string"""))
log(has_digit("test-string-with-01-digit"))
log(sys_64bits())
log(multibootusb_host_dir())
log(iso_cfg_ext_dir())
strings_test = strings('../../text-stings.bin')
log(strings_test)