diff --git a/.gitignore b/.gitignore index 06bfaab..c32cff0 100644 --- a/.gitignore +++ b/.gitignore @@ -106,6 +106,4 @@ multibootusb*.exe mbusb_te*py text.txt text.py - -# Temp files -*~ \ No newline at end of file +*~ diff --git a/CHANGELOG b/CHANGELOG index c17a42c..c7a4bef 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,28 @@ +Version - 8.8.0 +--------------- +* Fix for crash when listing fixed partition +* Simplified 7zip listing to include directories as well +* Correctly remove files installed outside multibootusb directory when uninstalling +* Added option to select zip files when choosing ISO files +* Added option to choose between two methods when syslinux shipped by ISO is version 3 or below +* Fix for trinity boot issue +* Updated README file +* Modified setup file for including grub2 modules in correct place +* Add python path so as to avoid import error under debian +* Fixed shipping of grub2 modules under correct directory (on Linux) +* Display version info only before launching the application +* Updated user guide +* Added FAQ section on the official site +* Reduced 7zip call when extracting files +* Improved usage info string of command line option (Thanks to Keshav Kini) +* Various code cleanup and removed redundancy codes +* Added RISING Antivirus CD +* Added INSERT ISO +* Added Liberte +* Added Alpine +* Added Trinity Rescue Disk +* Added AntiVirus Live CD (Calm AV) + Version - 8.7.1 --------------- * Warning text under 'Write image to disk' tab diff --git a/data/version.txt b/data/version.txt index d139a75..3b68253 100644 --- a/data/version.txt +++ b/data/version.txt @@ -1 +1 @@ -8.7.1 +8.8.0 diff --git a/multibootusb b/multibootusb index 9117231..2d4a633 100644 --- a/multibootusb +++ b/multibootusb @@ -6,14 +6,21 @@ # Licence: This file is a part of multibootusb package. You can redistribute it or modify # under the terms of GNU General Public License, version 2 or above. +<<<<<<< HEAD import os +======= +>>>>>>> devel import getopt import sys import platform -# The following line is required for distros based on rpm so as to avoid import errors when running from installed system +# The following line is required for distros based on rpm so as to avoid import errors when running from +# installed system sys.path.append('/usr/local/lib/python3.4/dist-packages') -# print(sys.path) + +# Ensure that above issue doesn't occur on debian based distro as well +if '/usr/lib/python3/dist-packages/scripts/' not in sys.path: + sys.path.append('/usr/lib/python3/dist-packages/scripts/') # Had trouble in importing scripts directory. Had to add few lines below to ensure it works on source as well as # post install @@ -56,7 +63,7 @@ Options: -h or --help : Print this help message and exit -c or --command : Invoke command line usage. This option is required; if omitted, the GUI will be launched. - -i or --iso : Path to ISO file()s. If many ISOs are supplied, + -i or --iso : Path to ISO file(s). If many ISOs are supplied, they should be separated by ',' with no spaces in between. -t or --target : Path to target USB device partition (e.g. "/dev/sdb1"). @@ -104,7 +111,6 @@ def start_gui(): if __name__ == '__main__': - running_from() if platform.system() == 'Windows': if not admin.isUserAdmin(): admin.runAsAdmin() @@ -164,7 +170,9 @@ if gui is False: log('\nOptions \'-i\' and \'-t\' must be supplied together. See the usage below.') usage() else: + running_from() cli_install_distro() elif gui is True: + running_from() start_gui() diff --git a/org.debian.pkexec.run-multibootusb.policy b/org.debian.pkexec.run-multibootusb.policy index d8e8566..e111748 100644 --- a/org.debian.pkexec.run-multibootusb.policy +++ b/org.debian.pkexec.run-multibootusb.policy @@ -12,7 +12,7 @@ auth_admin auth_admin - /usr/local/bin/multibootusb + /usr/bin/multibootusb true diff --git a/scripts/_7zip.py b/scripts/_7zip.py index f1e70a8..14707b8 100644 --- a/scripts/_7zip.py +++ b/scripts/_7zip.py @@ -29,12 +29,12 @@ def extract_iso(src, dst, pattern=None, suppress_out=True): # 7z x -y -oC:\path_to_directory X:\path_to_iso_file.iso # 7z e archive.zip -oC:\path_to_directory *.cfg *.bin -r if platform.system() == 'Windows': - cli_option = ' -bb1' # Linux does not accept this option (may be due to version diff). + cli_option = ' -ssc- -bb1' # Linux does not accept this option (may be due to version diff). if suppress_out != '': # suppress_out = ' 2> nul' suppress_out = '' else: - cli_option = '' + cli_option = ' -ssc- ' if suppress_out != '': suppress_out = ' 2> /dev/null' @@ -47,7 +47,7 @@ def extract_iso(src, dst, pattern=None, suppress_out=True): if pattern is None: _cmd = _7zip + cli_option + ' x -y -o' + gen.quote(dst) + ' ' + gen.quote(src) + suppress_out else: - _cmd = _7zip + ' x -y ' + gen.quote(src) + ' -o' + dst + ' ' + gen.quote(pattern) + ' -r' + suppress_out + _cmd = _7zip + cli_option + ' x -y ' + gen.quote(src) + ' -o' + dst + ' ' + gen.quote(pattern) + ' -r' + suppress_out gen.log('Executing ==> ' + _cmd) config.status_text = 'Status: Extracting ' + os.path.basename(src).strip() @@ -60,7 +60,7 @@ def list_iso(iso_link, suppress_out=True): List the content of ISO files. It does'nt work with non 'utf' characters (simply ignores them). :param iso_link:Path to ISO link :param suppress_out: Option to suppress output to stdout. Default True. - :return: Path to files as a list + :return: Path to files and directories as a list """ if platform.system() == 'Windows': if suppress_out is True: @@ -75,6 +75,12 @@ def list_iso(iso_link, suppress_out=True): 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() + for line in _cmd_out: + if '...' in line: + line = line.split() + _path = line[-1] + file_list.append(_path) + ''' for line in _cmd_out: line = line.split() if '.....' in line: @@ -85,6 +91,7 @@ def list_iso(iso_link, suppress_out=True): else: f_path = line[-1] file_list.append(f_path) + ''' return file_list diff --git a/scripts/distro.py b/scripts/distro.py index 60c4021..de88eee 100644 --- a/scripts/distro.py +++ b/scripts/distro.py @@ -71,7 +71,8 @@ def distro(iso_cfg_ext_dir, iso_link): return "redhat" elif re.search( r'slitaz|dban |ophcrack|tinycore|rescue.cpi|xpud|untangle|4mlinux|partition wizard|android-x86.png|' - r'riplinux|lebel dummy|http://pogostick.net/~pnh/ntpasswd/|AVG Rescue CD|lkrn', string, re.I): + r'riplinux|lebel dummy|http://pogostick.net/~pnh/ntpasswd/|AVG Rescue CD|AntivirusLiveCD|lkrn', + string, re.I): return "slitaz" elif re.search(r'minimal Slackware|Slackware-HOWTO', string, re.I): # for minimal slackware detection @@ -94,7 +95,7 @@ def distro(iso_cfg_ext_dir, iso_link): return "porteus" elif re.search(r'livecd=livecd|PCLinuxOS', string, re.I): return "pclinuxos" - elif re.search(r'looptype=squashfs', string, re.I): + elif re.search(r'looptype=squashfs|http://dee.su/liberte', string, re.I): return "gentoo" elif re.search(r'finnix', string, re.I): return "finnix" @@ -135,9 +136,17 @@ def distro(iso_cfg_ext_dir, iso_link): return 'pc-tool' elif re.search(r'vba32rescue', string, re.I): return 'grub2only' - + elif re.search(r'BOOT_IMAGE=rising', string, re.I): + return 'rising-av' + elif re.search(r'Avira Rescue System', string, re.I): + return 'Avira-RS' + elif any("alpine-release" in s.lower() for s in iso_file_list): + return 'alpine' + elif re.search(r'BOOT_IMAGE=insert', string, re.I): + return 'insert' distro = detect_iso_from_file_list(iso_link) + if distro: return distro # FIXME: See the below comments. diff --git a/scripts/gen.py b/scripts/gen.py index 3ac9548..8bbf24d 100644 --- a/scripts/gen.py +++ b/scripts/gen.py @@ -214,14 +214,16 @@ def copy_mbusb_dir_usb(usb_disk): 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 directory does not exist. Creating new.') + 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: - log('EFI directory could not be copied to ' + usb_mount_path) + except Exception as e: + log(e) result = False else: log('EFI directory already exist. Not copying.') diff --git a/scripts/grub.py b/scripts/grub.py index 0719ef5..58e7e09 100644 --- a/scripts/grub.py +++ b/scripts/grub.py @@ -12,6 +12,7 @@ from . import iso from . import _7zip from . import gen from .usb import bytes2human +from . import menus def mbusb_update_grub_cfg(): @@ -105,10 +106,19 @@ def mbusb_update_grub_cfg(): def write_custom_gurb_cfg(): - from . import menus + """ + Create custom grub loopback.cfg file for known distros. Custom menu entries are stored on munus.py module + :return: + """ loopback_cfg_path = os.path.join(config.usb_mount, 'multibootusb', iso.iso_basename(config.image_path), 'loopback.cfg') + menu = False if config.distro == 'pc-tool': menu = menus.pc_tool_config(syslinux=False, grub=True) + elif config.distro == 'rising-av': + menu = menus.rising(syslinux=False, grub=True) + + if menu is not False: + gen.log('Writing custom loopback.cfg file...') write_to_file(loopback_cfg_path, menu) diff --git a/scripts/install.py b/scripts/install.py index bea94a8..9cc94f1 100644 --- a/scripts/install.py +++ b/scripts/install.py @@ -52,12 +52,15 @@ def install_distro(): elif platform.system() == "Linux": log("Copying " + config.image_path + " to " + usb_mount) shutil.copy(config.image_path, usb_mount) - elif config.distro == "Windows" or config.distro == "alpine" or config.distro == 'pc-unlocker'\ + elif config.distro == "Windows" or config.distro == 'pc-unlocker'\ or config.distro == 'pc-tool' or config.distro == 'grub2only': log("Extracting iso to " + usb_mount) iso_extract_full(config.image_path, usb_mount) elif config.distro == "trinity-rescue": - iso.iso_extract_file(config.image_path, usb_mount, '*trk3') + iso_extract_full(config.image_path, install_dir) + if os.path.exists(os.path.join(usb_mount, 'trk3')): + shutil.rmtree(os.path.join(usb_mount, 'trk3')) + shutil.move(os.path.join(install_dir, 'trk3'), os.path.join(usb_mount)) elif config.distro == "ipfire": iso.iso_extract_file(config.image_path, usb_mount, '*.tlz') iso.iso_extract_file(config.image_path, usb_mount, 'distro.img') @@ -79,6 +82,9 @@ def install_distro(): #iso.iso_extract_full(config.image_path, usb_mount) config.status_text = "Copying ISO..." copy_iso(config.image_path, install_dir) + elif config.distro == "rising-av": + iso.iso_extract_file(config.image_path, install_dir, '*boot') + iso.iso_extract_file(config.image_path, usb_mount, '*rising') elif config.distro == 'sgrubd2': copy_iso(config.image_path, install_dir) elif config.distro == 'alt-linux': @@ -94,6 +100,28 @@ def install_distro(): iso_extract_full(config.image_path, usb_mount) elif config.distro == 'grub4dos_iso' or config.distro == 'raw_iso': copy_iso(config.image_path, install_dir) + elif config.distro == 'Avira-RS': + iso_extract_full(config.image_path, install_dir) + # we want following directories on root of the USB drive. Ensure the previous directories are removed before moving. + if os.path.exists(os.path.join(usb_mount, 'antivir')): + shutil.rmtree(os.path.join(usb_mount, 'antivir')) + shutil.move(os.path.join(install_dir, 'antivir'), os.path.join(usb_mount)) + if os.path.exists(os.path.join(usb_mount, 'avupdate')): + shutil.rmtree(os.path.join(usb_mount, 'avupdate')) + shutil.move(os.path.join(install_dir, 'avupdate'), os.path.join(usb_mount)) + if os.path.exists(os.path.join(usb_mount, 'system')): + shutil.rmtree(os.path.join(usb_mount, 'system')) + shutil.move(os.path.join(install_dir, 'system'), os.path.join(usb_mount)) + elif config.distro == 'alpine': + iso_extract_full(config.image_path, install_dir) + if os.path.exists(os.path.join(usb_mount, 'apks')): + shutil.rmtree(os.path.join(usb_mount, 'apks')) + shutil.move(os.path.join(install_dir, 'apks'), os.path.join(usb_mount)) + elif config.distro == 'insert': + iso_extract_full(config.image_path, install_dir) + if os.path.exists(os.path.join(usb_mount, 'INSERT')): + shutil.rmtree(os.path.join(usb_mount, 'INSERT')) + shutil.move(os.path.join(install_dir, 'INSERT'), os.path.join(usb_mount)) else: iso.iso_extract_full(config.image_path, install_dir) diff --git a/scripts/iso.py b/scripts/iso.py index 31d9ede..6c46fbf 100644 --- a/scripts/iso.py +++ b/scripts/iso.py @@ -168,12 +168,11 @@ def extract_cfg_file(iso_link): :param iso_link: Path to ISO file :return: """ - _pattern = ['.cfg', '.CFG', '.txt', '.TXT', 'isolinux.bin', 'ISOLINUX.BIN', '.lst'] + #_pattern = ['.cfg', '.CFG', '.txt', '.TXT', 'isolinux.bin', 'ISOLINUX.BIN', '.lst'] + _pattern = ['.cfg', '.txt', 'isolinux.bin', '.lst'] # file_list = iso_file_list(iso_link) for ext in _pattern: _7zip.extract_iso(iso_link, _iso_cfg_ext_dir, pattern='*' + ext) - #_7zip.extract_iso(iso_link, _iso_cfg_ext_dir, pattern='isolinux.bin ISOLINUX.BIN') - #_7zip.extract_iso(iso_link, _iso_cfg_ext_dir, pattern='*.cfg *.CFG *.txt *.TXT *.lst') def iso_extract_full(iso_link, dest_dir): diff --git a/scripts/mbusb_gui.py b/scripts/mbusb_gui.py index 279a5c8..8038d9f 100644 --- a/scripts/mbusb_gui.py +++ b/scripts/mbusb_gui.py @@ -209,8 +209,7 @@ 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)')[0] + config.image_path = QtWidgets.QFileDialog.getOpenFileName(self, 'Select an iso...', dir_path, 'ISO Files (*.iso);; Zip Files(*.zip)')[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 229fe36..dfdceac 100644 --- a/scripts/menus.py +++ b/scripts/menus.py @@ -9,6 +9,7 @@ from . import iso from . import config + def pc_tool_config(syslinux=True, grub=False): """ Menu entry for PC Tool ISO @@ -32,3 +33,16 @@ INITRD /multibootusb/grub/core.img TEXT HELP Switch to GRUB2 to select boot options. ENDTEXT\n""" + + +def rising(syslinux=True, grub=False): + """ + Menu entry for Raising Anti-virus. Only grub2 menu is required. Syslinux menu is automatically added + :param syslinux: + :param grub: + :return: + """ + if grub is True: + 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}""" diff --git a/scripts/syslinux.py b/scripts/syslinux.py index b9fab3d..96cc950 100644 --- a/scripts/syslinux.py +++ b/scripts/syslinux.py @@ -125,7 +125,7 @@ def syslinux_distro_dir(usb_disk, iso_link, distro): log('Distro uses really old isolinux. Installing version 3 instead of 2.') config.syslinux_version = '3' - if distro in ["generic", "alpine"]: + if distro in ["generic"]: install_dir = usb_mount distro_syslinux_install_dir = os.path.join(usb_mount, iso_linux_bin_dir.strip("/")).replace(usb_mount, "") distro_sys_install_bs = os.path.join(install_dir, iso_linux_bin_dir.strip("/"), distro + '.bs') diff --git a/scripts/uninstall_distro.py b/scripts/uninstall_distro.py index 85f0a86..76d0214 100644 --- a/scripts/uninstall_distro.py +++ b/scripts/uninstall_distro.py @@ -73,11 +73,14 @@ def delete_frm_file_list(): gen.log('Could not remove ldlinux.sys') if os.path.exists(os.path.join(usb_mount, f)): - if os.path.isfile(os.path.join(usb_mount, f)): - gen.log("Removing " + (os.path.join(usb_mount, f))) + + if os.path.isdir(os.path.join(usb_mount, f)): + gen.log("Removing directory " + (os.path.join(usb_mount, f))) + shutil.rmtree(os.path.join(usb_mount, f)) + + elif os.path.isfile(os.path.join(usb_mount, f)): + gen.log("Removing file " + (os.path.join(usb_mount, f))) os.remove(os.path.join(usb_mount, f)) - elif os.path.isdir(os.path.join(usb_mount, f)): - shutil.rmtree(os.path.join(usb_mount, f)) if os.path.exists(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "generic.cfg")): with open(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "generic.cfg"), "r") as generic_cfg: @@ -127,6 +130,7 @@ def uninstall_distro(): os.remove(os.path.join(usb_mount, config.uninstall_distro_dir_name + ".iso")) elif config.distro == "windows" or config.distro == "alpine" or config.distro == "generic": delete_frm_file_list() + if config.distro == "ipfire": files = os.listdir(usb_mount) for f in files: @@ -151,6 +155,7 @@ def uninstall_distro(): efi_grub_img = os.path.join(config.usb_mount, 'EFI', 'BOOT', 'bootx64.efi') if not os.path.exists(efi_grub_img): gen.log('EFI image does not exist. Copying now...') + os.makedirs(os.path.join(config.usb_mount, 'EFI', 'BOOT'), exist_ok=True) shutil.copy2(gen.resource_path(os.path.join("data", "EFI", "BOOT", "bootx64.efi")), os.path.join(config.usb_mount, 'EFI', 'BOOT')) elif not gen.grub_efi_exist(efi_grub_img): diff --git a/scripts/update_cfg_file.py b/scripts/update_cfg_file.py index 4b28d9d..c9c5bff 100644 --- a/scripts/update_cfg_file.py +++ b/scripts/update_cfg_file.py @@ -49,6 +49,9 @@ def update_distro_cfg_files(iso_link, usb_disk, distro, persistence=0): 'boot=casper cdrom-detect/try-usb=true floppy.allowed_drive_mask=0 ignore_uuid ' 'ignore_bootid root=UUID=' + usb_uuid + ' live-media-path=/multibootusb/' + iso_basename(iso_link) + '/casper', string) + # Point to correct .seed file + string = re.sub(r'/cdrom/preseed', '/preseed', string) + string = re.sub(r'live-media=\S*', 'live-media=/dev/disk/by-uuid/' + usb_uuid, string) string = re.sub(r'ui gfxboot', '#ui gfxboot', string) if persistence != 0: string = re.sub(r'boot=casper', 'boot=casper persistent persistent-path=/multibootusb/' + @@ -130,6 +133,10 @@ def update_distro_cfg_files(iso_link, usb_disk, distro, persistence=0): string = re.sub(r'append ', 'append real_root=' + usb_disk + ' slowusb subdir=/multibootusb/' + iso_basename(iso_link) + '/ ', string, flags=re.I) + string = re.sub(r'slowusb', 'slowusb loop=/multibootusb/' + + iso_basename(iso_link) + '/liberte/boot/root-x86.sfs', string, flags=re.I) + string = re.sub(r'cdroot_hash=\S*', '', string, flags=re.I) + elif distro == "systemrescuecd": rows = [] subdir = '/multibootusb/' + iso_basename(iso_link) @@ -219,6 +226,12 @@ def update_distro_cfg_files(iso_link, usb_disk, distro, persistence=0): elif distro == 'fsecure': string = re.sub(r'APPEND ramdisk_size', 'APPEND noprompt ' + 'knoppix_dir=/multibootusb/' + iso_basename(iso_link) + '/KNOPPIX ramdisk_size', string) + elif distro == 'alpine': + string = re.sub(r'modules', 'alpine_dev=usbdisk:vfat modules', string) + elif config.distro == 'trinity-rescue': + # USB disk must have volume label to work properly + string = re.sub(r'initrd=', 'vollabel=' + config.usb_label + ' initrd=', string) + string = re.sub(r'root=\S*', 'root=/dev/ram0', string, flags=re.I) config_file = open(cfg_file, "w") config_file.write(string) @@ -371,6 +384,9 @@ def update_mbusb_cfg_file(iso_link, usb_uuid, usb_mount, distro): if config.syslinux_version == '3': config_file.write("CONFIG /multibootusb/" + iso_basename(iso_link) + '/' + isolinux_bin_dir(iso_link).replace("\\", "/") + '/isolinux.cfg\n') config_file.write("APPEND /multibootusb/" + iso_basename(iso_link) + '/' + isolinux_bin_dir(iso_link).replace("\\", "/") + '\n') + config_file.write("# Delete or comment above two lines using # and remove # from below line if " + "you get not a COM module error.\n") + config_file.write("#BOOT " + distro_sys_install_bs.replace("//", "/") + "\n") else: config_file.write("BOOT " + distro_sys_install_bs.replace("//", "/") + "\n") diff --git a/setup.py b/setup.py index 6adf520..500fe61 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,15 @@ import os from scripts.gen import mbusb_version +Version = mbusb_version() + + def get_data(_dir): + """ + Get path to all files, including sub directories + :param _dir: Path to top level directory + :return: Path to files as list + """ data = [] for dirpath, dirnames, filenames in os.walk(_dir): for f in filenames: @@ -20,8 +28,21 @@ def get_data(_dir): data.append(cfg_file) return data -Version = mbusb_version() -print(Version) + +def root_files(_dir): + """ + Get path to all files of root directories + :param _dir: Path to a directory + :return: Path to files as list + """ + data = [] + for _file in os.listdir(_dir): + path = os.path.join(_dir, _file) + if not os.path.isdir(path): + data.append(path) + return data + + setup( name='multibootusb', version=Version, @@ -55,6 +76,7 @@ setup( ('/usr/share/multibootusb/data/multibootusb', ["data/multibootusb/menu.lst"]), ('/usr/share/multibootusb/data/multibootusb', ["data/multibootusb/syslinux.cfg"]), ('/usr/share/multibootusb/data/multibootusb', ["data/multibootusb/vesamenu.c32"]), - ('/usr/share/multibootusb/data/multibootusb/grub', get_data('data/multibootusb/grub')), + ('/usr/share/multibootusb/data/multibootusb/grub', root_files('data/multibootusb/grub')), + ('/usr/share/multibootusb/data/multibootusb/grub/i386-pc', get_data('data/multibootusb/grub')), ('/usr/share/multibootusb/data/tools/syslinux', get_data('data/tools/syslinux'))] )