From 815241572c995fa60c6fb76419a7639937e7ec6d Mon Sep 17 00:00:00 2001 From: mbusb Date: Sun, 14 May 2017 22:32:56 +0530 Subject: [PATCH] Improvements and memdisk for ISO boot: 1. Catch 7zip error while listing ISO content 2. Way to detect .ISO and .IMG files for direct booting using memdisk 3. Added a class for finding available RAM size 4. Added feature for selecting ISO, IMG, Zip and all files options in file chooser dialog 5. Added generic menu entry for memdisk 6. Corrected path to menu.lst file for distrs based on grub4dos 7. Fix for crash when multicard reader is inserted on the system without a SD card 8. Correctly detect USB disk information using udisk2-dbus without crash --- scripts/_7zip.py | 6 +++- scripts/distro.py | 5 +++- scripts/gen.py | 53 +++++++++++++++++++++++++++++++++++ scripts/grub.py | 4 +++ scripts/install.py | 3 +- scripts/mbusb_gui.py | 4 ++- scripts/menus.py | 57 +++++++++++++++++++++++++++++++++++++- scripts/update_cfg_file.py | 7 ++++- scripts/usb.py | 33 ++++++++++++++++------ 9 files changed, 157 insertions(+), 15 deletions(-) diff --git a/scripts/_7zip.py b/scripts/_7zip.py index 14707b8..668ab4e 100644 --- a/scripts/_7zip.py +++ b/scripts/_7zip.py @@ -74,7 +74,11 @@ def list_iso(iso_link, suppress_out=True): else: file_list = [] _cmd = _7zip + ' l ' + gen.quote(iso_link) + suppress_out - _cmd_out = subprocess.check_output(_cmd, stderr=subprocess.PIPE, shell=True).decode('utf-8', 'ignore').splitlines() + try: + _cmd_out = subprocess.check_output(_cmd, stderr=subprocess.PIPE, shell=True).decode('utf-8', 'ignore').splitlines() + except Exception as e: + gen.log(e) + _cmd_out = '' for line in _cmd_out: if '...' in line: line = line.split() diff --git a/scripts/distro.py b/scripts/distro.py index 7cac7d2..6d22e2b 100644 --- a/scripts/distro.py +++ b/scripts/distro.py @@ -110,7 +110,6 @@ def distro(iso_cfg_ext_dir, iso_link): elif re.search(r'zenwalk|slack|salix', string, re.I) and re.search(r'live', string, re.I): return "salix-live" elif re.search(r'zenwalk|slack|salix', string, re.I): - print(os.path.join(path, name)) return "zenwalk" elif re.search(r'ubuntu server', string, re.I): return "ubuntu-server" @@ -157,6 +156,10 @@ def distro(iso_cfg_ext_dir, iso_link): # # syslinux, update_cfg and install_distro modules. # if self.isolinux_bin_exist(): # return "generic" + elif str(iso_link).lower().endswith('.iso'): + return 'memdisk_iso' + elif str(iso_link).lower().endswith('.img'): + return 'memdisk_img' else: return None diff --git a/scripts/gen.py b/scripts/gen.py index 8bbf24d..d024aac 100644 --- a/scripts/gen.py +++ b/scripts/gen.py @@ -15,6 +15,7 @@ import string import zipfile import tempfile import re +import ctypes def scripts_dir_path(): @@ -399,6 +400,58 @@ def write_to_file(filepath, text): 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")) diff --git a/scripts/grub.py b/scripts/grub.py index 58e7e09..eb909e6 100644 --- a/scripts/grub.py +++ b/scripts/grub.py @@ -90,6 +90,10 @@ def mbusb_update_grub_cfg(): elif config.distro == 'ReactOS': f.write(' menuentry ' + iso.iso_basename(config.image_path) + ' {multiboot /loader/setupldr.sys}' + "\n") + elif config.distro == 'memdisk_img': + f.write(menus.memdisk_img_cfg(syslinux=False, grub=True)) + elif config.distro == 'memdisk_iso': + f.write(menus.memdisk_iso_cfg(syslinux=False, grub=True)) elif config.distro == 'memtest': f.write(' menuentry ' + iso.iso_basename(config.image_path) + ' {linux16 ' + '/multibootusb/' + iso.iso_basename(config.image_path) + '/BISOLINUX/MEMTEST}' + "\n") diff --git a/scripts/install.py b/scripts/install.py index 9cc94f1..a141464 100644 --- a/scripts/install.py +++ b/scripts/install.py @@ -98,7 +98,8 @@ def install_distro(): iso_extract_full(config.image_path, usb_mount) elif config.distro == 'ReactOS': iso_extract_full(config.image_path, usb_mount) - elif config.distro == 'grub4dos_iso' or config.distro == 'raw_iso': + elif config.distro == 'grub4dos_iso' or config.distro == 'raw_iso' or config.distro == 'memdisk_iso' or \ + config.distro == 'memdisk_img': copy_iso(config.image_path, install_dir) elif config.distro == 'Avira-RS': iso_extract_full(config.image_path, install_dir) diff --git a/scripts/mbusb_gui.py b/scripts/mbusb_gui.py index 35035bc..f47bc59 100644 --- a/scripts/mbusb_gui.py +++ b/scripts/mbusb_gui.py @@ -209,7 +209,9 @@ Are you SURE you want to enable it?", if os.path.exists(preference_file_path): dir_path = open(preference_file_path, 'r').read() - config.image_path = QtWidgets.QFileDialog.getOpenFileName(self, 'Select an iso...', dir_path, 'ISO Files (*.iso);; Zip Files(*.zip);; Img Files(*.img)')[0] + config.image_path = QtWidgets.QFileDialog.getOpenFileName(self, 'Select an iso...', dir_path, + 'ISO Files (*.iso);; Zip Files(*.zip);; ' + 'Img Files(*.img);; All Files(*.*)')[0] if config.image_path: default_dir_path = os.path.dirname(config.image_path) diff --git a/scripts/menus.py b/scripts/menus.py index dfdceac..1dd6f25 100644 --- a/scripts/menus.py +++ b/scripts/menus.py @@ -8,6 +8,7 @@ from . import iso from . import config +from .gen import MemoryCheck def pc_tool_config(syslinux=True, grub=False): @@ -28,7 +29,7 @@ initrd /system/stage2\n}""" def grub2only(): return """MENU LABEL """ + iso.iso_basename(config.image_path) + """ -Linux /multibootusb/grub/lnxboot.img +LINUX /multibootusb/grub/lnxboot.img INITRD /multibootusb/grub/core.img TEXT HELP Switch to GRUB2 to select boot options. @@ -46,3 +47,57 @@ def rising(syslinux=True, grub=False): return """menuentry """ + iso.iso_basename(config.image_path) + """ { linux /multibootusb/linux/boot/isolinux/vmlinuz lang=us ramdisk_size=100000 init=/etc/init apm=power-off pnpbios=off vga=0x314 nomce quiet BOOT_IMAGE=rising initrd /multibootusb/linux/boot/isolinux/ravroot.gz\n}""" + + +def memdisk_iso_cfg(syslinux=True, grub=False): + """ + Menu entry for ISO using memdisk. Need to have more RAM to make it work with mendisk properly. + By default, memory size is set to system RAM size or 3GB. The 'vmalloc=3072M' can also be used as 'mem=3G'. + :param syslinux: Default is True + :param grub: Default is False + :return: Menu entry for syslinux and grub2 + """ + M = MemoryCheck() + avl_mem = M.value + if not avl_mem: + avl_mem = int(3072) + if syslinux is True: + menu_entry = 'LINUX memdisk\n' \ + 'INITRD /multibootusb/' + iso.iso_basename(config.image_path) + '/' + iso.iso_name(config.image_path) + '\n' \ + 'APPEND iso vmalloc=' + str(avl_mem) + 'M\n' + elif grub is True: + menu_entry = ' search --set -f /multibootusb/' + iso.iso_basename(config.image_path) + '/' + iso.iso_name(config.image_path) + '\n' \ + ' menuentry ' + iso.iso_basename(config.image_path) + ' {\n' \ + ' linux16 /multibootusb/memdisk iso vmalloc=' + str(avl_mem) + 'M\n' \ + ' initrd16 /multibootusb/' + iso.iso_basename(config.image_path) + '/' + iso.iso_name(config.image_path) + '\n' \ + '}\n' + + return menu_entry + + +def memdisk_img_cfg(syslinux=True, grub=False): + """ + Menu entry for IMG files using memdisk. Need to have more RAM to make it work with mendisk properly. + By default, memory size is set to system RAM size or 3GB. + :param syslinux: Default is True + :param grub: Default is False + :return: Menu entry for syslinux and grub2 + """ + M = MemoryCheck() + avl_mem = M.value + if not avl_mem: + avl_mem = int(3072) + if syslinux is True: + menu_entry = 'LINUX memdisk\n' \ + 'INITRD /multibootusb/' + iso.iso_basename(config.image_path) + '/' + iso.iso_name(config.image_path) + '\n' \ + 'APPEND raw vmalloc=' + str(avl_mem) + 'M\n' + elif grub is True: + menu_entry = ' search --set -f /multibootusb/' + iso.iso_basename(config.image_path) + '/' + iso.iso_name(config.image_path) + '\n' \ + ' menuentry ' + iso.iso_basename(config.image_path) + ' {\n' \ + ' linux16 /multibootusb/memdisk raw vmalloc=' + str(avl_mem) + 'M\n' \ + ' initrd16 /multibootusb/' + iso.iso_basename(config.image_path) + '/' + iso.iso_name(config.image_path) + '\n' \ + '}\n' + + return menu_entry + + diff --git a/scripts/update_cfg_file.py b/scripts/update_cfg_file.py index c9c5bff..3f6fd66 100644 --- a/scripts/update_cfg_file.py +++ b/scripts/update_cfg_file.py @@ -366,6 +366,11 @@ def update_mbusb_cfg_file(iso_link, usb_uuid, usb_mount, distro): config_file.write(menus.pc_tool_config(syslinux=True, grub=False)) elif distro == 'grub2only': config_file.write(menus.grub2only()) + elif distro == 'memdisk_iso': + print(menus.memdisk_iso_cfg(syslinux=True, grub=False)) + config_file.write(menus.memdisk_iso_cfg(syslinux=True, grub=False)) + elif distro == 'memdisk_img': + config_file.write(menus.memdisk_img_cfg(syslinux=True, grub=False)) else: if isolinux_bin_exist(config.image_path) is True: if distro == "generic": @@ -441,5 +446,5 @@ def update_grub4dos_iso_menu(): f.write("LABEL " + iso_basename(config.image_path) + "\n") f.write("MENU LABEL " + iso_basename(config.image_path) + "\n") f.write("KERNEL grub.exe" + "\n") - f.write('APPEND --config-file=/multibootusb/' + iso_basename(config.image_path) + '/' + iso_name(config.image_path) + "\n") + f.write('APPEND --config-file=/multibootusb/' + iso_basename(config.image_path) + '/menu.lst' + "\n") f.write("#end " + iso_basename(config.image_path) + "\n") diff --git a/scripts/usb.py b/scripts/usb.py index 36969e9..9a4e013 100644 --- a/scripts/usb.py +++ b/scripts/usb.py @@ -102,15 +102,16 @@ def list_devices(fixed=False): context = pyudev.Context() for device in context.list_devices(subsystem='block', ID_BUS="usb"): - devices.append(str(device['DEVNAME'])) - gen.log("\t" + device['DEVNAME']) + if device.get('ID_PART_TABLE_TYPE') is not None: + devices.append(str(device.get('DEVNAME'))) + gen.log("\t" + device.get('DEVNAME')) if fixed is True: + devices = [] for device in context.list_devices(subsystem='block'): if device.get('DEVTYPE') in ['disk', 'partition'] and device.get('ID_PART_TABLE_TYPE'): - if device['DEVNAME'] not in devices: - devices.append(str(device['DEVNAME'])) - gen.log("\t" + device['DEVNAME']) + devices.append(str(device.get('DEVNAME'))) + gen.log("\t" + device.get('DEVNAME')) except Exception as e: gen.log(e) @@ -273,12 +274,26 @@ def details_udisks2(usb_disk_part): """ import dbus bus = dbus.SystemBus() + + mount_point = '' + uuid = '' + file_system = '' + vendor = '' + model = '' + label = '' + devtype = "disk" + bd = bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2/block_devices%s'%usb_disk_part[4:]) device = bd.Get('org.freedesktop.UDisks2.Block', 'Device', dbus_interface='org.freedesktop.DBus.Properties') device = bytearray(device).replace(b'\x00', b'').decode('utf-8') - uuid = bd.Get('org.freedesktop.UDisks2.Block', 'IdUUID', dbus_interface='org.freedesktop.DBus.Properties') - file_system = bd.Get('org.freedesktop.UDisks2.Block', 'IdType', dbus_interface='org.freedesktop.DBus.Properties') - mount_point = bd.Get('org.freedesktop.UDisks2.Filesystem', 'MountPoints', dbus_interface='org.freedesktop.DBus.Properties') + if device[-1].isdigit() is True: + uuid = bd.Get('org.freedesktop.UDisks2.Block', 'IdUUID', dbus_interface='org.freedesktop.DBus.Properties') + file_system = bd.Get('org.freedesktop.UDisks2.Block', 'IdType', dbus_interface='org.freedesktop.DBus.Properties') + mount_point = bd.Get('org.freedesktop.UDisks2.Filesystem', 'MountPoints', dbus_interface='org.freedesktop.DBus.Properties') + devtype = 'partition' + else: + devtype = 'disk' + file_system = 'No_File_System' if mount_point: # mount_point = str(bytearray(mount_point[0]).decode('utf-8').replace(b'\x00', b'')) mount_point = bytearray(mount_point[0]).replace(b'\x00', b'').decode('utf-8') @@ -312,7 +327,7 @@ def details_udisks2(usb_disk_part): return {'uuid': uuid, 'file_system': file_system, 'label': label, 'mount_point': mount_point, 'size_total': size_total, 'size_used': size_used, 'size_free': size_free, - 'vendor': vendor, 'model': model} + 'vendor': vendor, 'model': model, 'devtype': devtype} def bytes2human(n):