Merge pull request #340 from shinji-s/corruption_check

Address filesystem corruption
pull/343/head
multibootusb 6 years ago committed by GitHub
commit adc5643723
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -184,33 +184,44 @@ if __name__ == '__main__':
sys.exit()
'''
if config.debug is True:
from scripts.debug import colors
log(colors.HEADER + "=== DEBUG ENABLED ===")
if gui is False:
check_admin()
if uninstall is True and config.usb_disk is not '':
cli_uninstall_distro()
elif uninstall is True and config.usb_disk is '':
log('\nYou must provide \'-t\' option to point to your USB disk for uninstalling a distro.\n'
'See the usage example below.')
usage()
elif config.image_path is '' and config.usb_disk is '':
log('\nNo option provided. See the usage below.')
usage()
elif config.cli_syslinux is True and config.usb_disk is not '':
cli_install_syslinux()
elif config.image_path is '' or config.usb_disk is '':
log('\nOptions \'-i\' and \'-t\' must be supplied together. See the usage below.')
usage()
elif config.cli_dd is True:
cli_dd()
else:
def main():
if config.debug is True:
from scripts.debug import colors
log(colors.HEADER + "=== DEBUG ENABLED ===")
if gui is False:
check_admin()
if uninstall is True and config.usb_disk is not '':
cli_uninstall_distro()
elif uninstall is True and config.usb_disk is '':
log('\nYou must provide \'-t\' option to point to your USB disk for uninstalling a distro.\n'
'See the usage example below.')
usage()
elif config.image_path is '' and config.usb_disk is '':
log('\nNo option provided. See the usage below.')
usage()
elif config.cli_syslinux is True and config.usb_disk is not '':
cli_install_syslinux()
elif config.image_path is '' or config.usb_disk is '':
log('\nOptions \'-i\' and \'-t\' must be supplied together. See the usage below.')
usage()
elif config.cli_dd is True:
cli_dd()
else:
running_from()
cli_install_distro()
elif gui is True:
running_from()
cli_install_distro()
start_gui()
elif gui is True:
running_from()
start_gui()
if __name__ == '__main__':
try:
main()
finally:
from scripts import usb
for p in config.remounted_partitions:
log('Unmouting %s at exit' % p)
usb.unmount(p)

@ -42,10 +42,11 @@ editors_linux = ["xdg-open", "gedit", "kate", "kwrite"]
editors_win = ["notepad++.exe", "notepad.exe"]
imager_usb_disk = []
remounted_partitions = []
debug = False
# protected_drives = ['C:','D:','E:', '/dev/sda', '/dev/sdb']
# protected_drives = ['C:','D:','E:', '/dev/sda', '/dev/sdb', '/dev/sdc']
# If turned off, qemu will be sought at a few preset locations
# first before deciding to use the bundled exe.
@ -59,3 +60,14 @@ qemu_use_builtin = True # Relevant on Windows only
# Bundled QEMU does not support this.
# See https://www.qemu.org/2017/11/22/haxm-usage-windows/ for setup.
qemu_use_haxm = not qemu_use_builtin # Relevant on Windows only
# qemu_use_kvm = False
# qemu_bios = 'OVMF.fd'
def update_usb_mount(new_usb_details):
global usb_mount, usb_details
usb_mount = new_usb_details['mount_point'].replace('\\x20', ' ')
usb_details = new_usb_details
def add_remounted(usb_disk):
if usb_disk not in remounted_partitions:
remounted_partitions.append(usb_disk)

@ -17,6 +17,7 @@ import tempfile
import re
import ctypes
from . import config
def scripts_dir_path():
return os.path.dirname(os.path.realpath(__file__))
@ -190,10 +191,8 @@ def copy_mbusb_dir_usb(usb_disk):
:param usb_mount_path: Path to USB mount.
:return:
"""
# from .iso import iso_size
from .usb import details
usb_details = details(usb_disk)
usb_details = config.usb_details
usb_mount_path = usb_details['mount_point']
result = ''
if not os.path.exists(os.path.join(usb_mount_path, "multibootusb")):
@ -299,9 +298,8 @@ def strings(filename, _min=4):
def size_not_enough(iso_link, usb_disk):
from .iso import iso_size
from .usb import details
isoSize = iso_size(iso_link)
usb_details = details(usb_disk)
usb_details = config.usb_details
usb_size = usb_details['size_free']
return bool(isoSize > usb_size)

@ -945,6 +945,56 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_fsck">
<property name="enabled">
<bool>true</bool>
</property>
<attribute name="title">
<string>Check Filesystem</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>242</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="run_fsck_repair">
<property name="text">
<string>Repair Filesystem</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="run_fsck_check">
<property name="text">
<string>Check Filesystem Integrity</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>241</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>

@ -238,6 +238,10 @@ class Ui_MainWindow(object):
self.gridLayout_9.addItem(spacerItem3, 0, 1, 1, 1)
spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_9.addItem(spacerItem4, 2, 1, 1, 1)
self.label_waning = QtWidgets.QLabel(self.tab_imager)
self.label_waning.setWordWrap(False)
self.label_waning.setObjectName("label_waning")
self.gridLayout_9.addWidget(self.label_waning, 3, 0, 1, 3)
self.horizontalLayout_7.addLayout(self.gridLayout_9)
self.tabWidget.addTab(self.tab_imager, "")
self.tab_syslinux = QtWidgets.QWidget()
@ -361,6 +365,22 @@ class Ui_MainWindow(object):
spacerItem13 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_2.addItem(spacerItem13)
self.tabWidget.addTab(self.tab_testboot, "")
self.tab_fsck = QtWidgets.QWidget()
self.tab_fsck.setEnabled(True)
self.tab_fsck.setObjectName("tab_fsck")
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.tab_fsck)
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
spacerItem14 = QtWidgets.QSpacerItem(242, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_6.addItem(spacerItem14)
self.run_fsck_repair = QtWidgets.QPushButton(self.tab_fsck)
self.run_fsck_repair.setObjectName("run_fsck_repair")
self.horizontalLayout_6.addWidget(self.run_fsck_repair)
self.run_fsck_check = QtWidgets.QPushButton(self.tab_fsck)
self.run_fsck_check.setObjectName("run_fsck_check")
self.horizontalLayout_6.addWidget(self.run_fsck_check)
spacerItem15 = QtWidgets.QSpacerItem(241, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_6.addItem(spacerItem15)
self.tabWidget.addTab(self.tab_fsck, "")
self.verticalLayout_7.addWidget(self.tabWidget)
self.progressbar = QtWidgets.QProgressBar(self.centralwidget)
self.progressbar.setProperty("value", 0)
@ -421,6 +441,7 @@ class Ui_MainWindow(object):
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_multibootusb), _translate("MainWindow", "MultiBootUSB"))
self.button_write_image_to_disk.setText(_translate("MainWindow", "Write image to USB"))
self.label_6.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:14pt; font-weight:600; color:#ff0000;\">WARNING!</span></p><p align=\"center\"><span style=\" color:#000000;\">This operation destroys </span><span style=\" font-weight:600; color:#000000;\">ALL</span><span style=\" color:#000000;\"> data on the selected disk.</span></p><p align=\"center\"><span style=\" color:#000000;\">Please select the destination disk carefully.</span></p></body></html>"))
self.label_waning.setText(_translate("MainWindow", "<html><head/><body><p align=\"justify\"><span style=\" font-weight:600; color:#ff0000;\">WARNING</span> : Any bootable USB made using<span style=\" font-weight:600;\"> ISO Imager will destroy all data </span>on the selected USB disk. </p><p align=\"justify\">Use it at your own risk. Developers are not responsile for loss of any data.</p></body></html>"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_imager), _translate("MainWindow", "Write Image to disk"))
self.groupBox_2.setTitle(_translate("MainWindow", "Install Syslinux"))
self.check_install_sys_only.setText(_translate("MainWindow", "Install only syslinu&x (existing configurations will not be altered)."))
@ -451,6 +472,9 @@ class Ui_MainWindow(object):
self.combo_iso_boot_ram.setItemText(5, _translate("MainWindow", "2048"))
self.label.setText(_translate("MainWindow", "MB"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_testboot), _translate("MainWindow", "Boot ISO/USB"))
self.run_fsck_repair.setText(_translate("MainWindow", "Repair Filesystem"))
self.run_fsck_check.setText(_translate("MainWindow", "Check Filesystem Integrity"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_fsck), _translate("MainWindow", "Check Filesystem"))
self.menuFile.setTitle(_translate("MainWindow", "&File"))
self.menu_Help.setTitle(_translate("MainWindow", "&Help"))
self.action_Quit.setText(_translate("MainWindow", "&Quit"))

@ -126,9 +126,6 @@ def install_distro():
else:
iso.iso_extract_full(config.image_path, install_dir)
if platform.system() == 'Linux':
log('ISO extracted successfully. Sync is in progress...')
os.sync()
if config.persistence != 0:
log('Creating persistence...')
@ -163,7 +160,7 @@ def install_progress():
"""
from . import progressbar
usb_details = details(config.usb_disk)
usb_details = config.usb_details
config.usb_mount = usb_details['mount_point']
usb_size_used = usb_details['size_used']
thrd = threading.Thread(target=install_distro, name="install_progress")
@ -241,8 +238,6 @@ def install_patch():
replace_syslinux_modules(config.syslinux_version, distro_install_dir)
elif config.distro == 'debian':
if platform.system() == 'Linux': # Need to syn under Linux. Otherwise, USB disk becomes random read only.
os.sync()
iso_file_list = iso.iso_file_list(config.image_path)
if not any(s.strip().lower().endswith("makeboot.sh")
for s in iso_file_list):

@ -5,7 +5,8 @@
# 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 io
import os
import platform
import sys
@ -13,7 +14,12 @@ import signal
from PyQt5 import QtCore, QtGui, QtWidgets
import subprocess
import time
import traceback
import webbrowser
if platform.system() == 'Linux':
import dbus
from scripts.gui.ui_multibootusb import Ui_MainWindow
from scripts.gui.ui_about import Ui_About
from . import usb
@ -80,6 +86,12 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
# self.ui.combo_iso_boot_ram.activated[str].connect(self.qemu_iso_ram)
# self.ui.combo_usb_boot_ram.activated[str].connect(self.qemu_usb_ram)
# self.ui.boot_usb_qemu.clicked.connect(lambda: self.on_Qemu_Boot_usb_Click(str(self.ui.combo_drives.currentText())))
self.ui.run_fsck_repair.clicked.connect(
partial(self.onFsckClick, usb.repair_vfat_filesystem))
self.ui.run_fsck_check.clicked.connect(
partial(self.onFsckClick, usb.check_vfat_filesystem))
# Update progressbar and status (Main ISO install)
self.progress_thread_install = GuiInstallProgress()
self.progress_thread_install.finished.connect(self.install_syslinux)
@ -98,6 +110,11 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
self.progress_thread_dd.finished.connect(self.dd_finished)
self.progress_thread_dd.status.connect(self.ui.statusbar.showMessage)
if platform.system() == 'Windows' or os.system('which fsck.vfat') != 0:
i = self.ui.tabWidget.indexOf(self.ui.tab_fsck)
if 0<=i:
self.ui.tabWidget.removeTab(i)
prepare_mbusb_host_dir()
self.onRefreshClick()
@ -120,6 +137,7 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
"Are you SURE you want to enable it?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.No:
self.ui.checkbox_all_drives.setChecked(False)
elif reply == QtWidgets.QMessageBox.Yes:
@ -148,18 +166,8 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
if config.usb_disk:
log("Selected device " + config.usb_disk)
config.usb_details = usb.details(config.usb_disk)
config.persistence_max_size = persistence.max_disk_persistence(config.usb_disk)
config.usb_mount = config.usb_details.get('mount_point', "")
self.ui.usb_dev.setText(config.usb_disk)
self.ui.usb_vendor.setText(config.usb_details.get('vendor', ""))
self.ui.usb_model.setText(config.usb_details.get('model', ""))
self.ui.usb_size.setText(str(usb.bytes2human(config.usb_details.get('size_total', ""))))
self.ui.usb_mount.setText(config.usb_details.get('mount_point', ""))
self.ui.usb_type.setText(config.usb_details.get('devtype', ""))
self.ui.usb_fs.setText(config.usb_details.get('file_system', ""))
self.update_target_info()
# Get the GPT status of the disk and store it on a variable
usb.gpt_device(config.usb_disk)
@ -174,7 +182,6 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
self.ui.usb_mount.clear()
self.ui.usb_type.clear()
self.ui.usb_fs.clear()
log("No USB disk found...")
def onRefreshClick(self):
@ -187,13 +194,14 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
detected_devices = usb.list_devices(fixed=True)
else:
detected_devices = usb.list_devices()
if not detected_devices:
return
return
protected_drives = getattr(config, 'protected_drives', [])
for device in detected_devices:
if all(not device.startswith(d) for d in protected_drives):
self.ui.combo_drives.addItem(str(device))
self.ui.combo_drives.setCurrentIndex(0)
self.ui.combo_drives.setCurrentIndex(0)
def update_list_box(self, usb_disk):
"""
@ -247,7 +255,7 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
# Detect supported distro
try:
clean_iso_cfg_ext_dir( # Need to be cleaned.
clean_iso_cfg_ext_dir( # Need to be cleaned.
os.path.join(multibootusb_host_dir(), "iso_cfg_ext_dir"))
extract_cfg_file(config.image_path)
config.distro = distro(iso_cfg_ext_dir(), config.image_path,
@ -323,21 +331,23 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
self.ui.label_persistence.setVisible(False)
self.ui.slider_persistence.setVisible(False)
def get_controls(self):
return [
self.ui.combo_drives,
self.ui.checkbox_all_drives,
self.ui.button_detect_drives,
self.ui.button_browse_image,
self.ui.image_path,
self.ui.tabWidget,
self.ui.button_install_distro,
self.ui.button_uninstall_distro,
]
def ui_disable_controls(self):
self.ui.combo_drives.setEnabled(False)
self.ui.checkbox_all_drives.setEnabled(False)
self.ui.button_detect_drives.setEnabled(False)
self.ui.button_browse_image.setEnabled(False)
self.ui.image_path.setEnabled(False)
self.ui.tabWidget.setEnabled(False)
[c.setEnabled(False) for c in self.get_controls()]
def ui_enable_controls(self):
self.ui.combo_drives.setEnabled(True)
self.ui.checkbox_all_drives.setEnabled(True)
self.ui.button_detect_drives.setEnabled(True)
self.ui.button_browse_image.setEnabled(True)
self.ui.image_path.setEnabled(True)
self.ui.tabWidget.setEnabled(True)
[c.setEnabled(True) for c in self.get_controls()]
def update_slider_text(self):
slide_value = self.ui.slider_persistence.value() * 1024 * 1024
@ -356,9 +366,6 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
update_distro_cfg_files(config.image_path, config.usb_disk,
config.distro, config.persistence)
self.update_list_box(config.usb_disk)
if sys.platform.startswith("linux"):
self.ui.statusbar.showMessage("Status: Sync is in progress...")
os.sync()
self.ui.statusbar.showMessage("Status: Idle")
self.ui_disable_persistence()
log(iso_name(config.image_path) + ' has been successfully installed.')
@ -416,9 +423,6 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
dest_fp)
QtWidgets.QMessageBox.information(self, 'Install Success...',
'Syslinux installed successfully on ' + config.usb_disk)
elif ret is True and self.ui.check_install_sys_only.isChecked():
QtWidgets.QMessageBox.information(self, 'Install Success...',
'Syslinux installed successfully on ' + config.usb_disk)
elif ret is False:
QtWidgets.QMessageBox.information(self, 'Install error...',
'Sorry. Syslinux failed to install on ' + config.usb_disk)
@ -428,6 +432,38 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
self.ui_enable_controls()
def onFsckClick(self, fsck_func):
try:
self.onFsckClick_impl(fsck_func)
except (KeyboardInterrupt, SystemExit):
raise
except:
o = io.StringIO()
traceback.print_exc(None, o)
QtWidgets.QMessageBox.information(
self, 'Failed to run fsck',
o.getvalue())
def onFsckClick_impl(self, fsck_func):
if not config.usb_disk:
QtWidgets.QMessageBox.information(
self, 'No partition is selected',
'Please select the partition to check.')
return
if not config.usb_disk[-1:].isdigit():
QtWidgets.QMessageBox.information(
self, 'Selected device is not partition',
'Please select a partition not a disk.')
return
output = []
with usb.UnmountedContext(config.usb_disk, self.update_usb_mount):
fsck_func(config.usb_disk, output)
for resultcode, msgout, cmd in output:
QtWidgets.QMessageBox.information(
self, 'Integrity Check',
cmd + ' said:\n' + str(msgout[0], 'utf-8'))
def onedit_syslinux(self):
"""
Function to edit main syslinux.cfg file.
@ -514,15 +550,21 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
# update_sys_cfg_file(config.uninstall_distro_dir_name)
self.update_list_box(config.usb_mount)
if sys.platform.startswith("linux"):
self.ui.statusbar.showMessage("Status: Sync in progress...")
os.sync()
self.ui.statusbar.showMessage("Status: Idle")
QtWidgets.QMessageBox.information(self, 'Uninstall Complete...',
config.uninstall_distro_dir_name + ' has been successfully removed.')
self.ui_enable_controls()
def onCreateClick(self):
installing = False
self.ui_disable_controls()
try:
installing = self.onCreateClick_impl()
finally:
if not installing:
self.ui_enable_controls()
def onCreateClick_impl(self):
"""
Main function to create bootable USB disk.
:param usb_disk: ComboBox text as detected USB disk.
@ -530,40 +572,56 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
:return:
"""
self.ui_disable_controls()
if not config.usb_disk:
log("ERROR: No USB device found.")
QtWidgets.QMessageBox.information(self, "No Device...",
"No USB device found.\n\nInsert USB and use Refresh USB button to detect USB.")
self.ui_enable_controls()
elif not config.image_path:
QtWidgets.QMessageBox.information(
self,"No Device...",
"No USB device found.\n\nInsert USB and "
"use Refresh USB button to detect USB.")
return False
if not config.image_path:
log("No ISO selected.")
QtWidgets.QMessageBox.information(self, "No ISO...", "No ISO found.\n\nPlease select an ISO.")
self.ui_enable_controls()
elif usb.details(config.usb_disk)['mount_point'] == 'No_Mount':
QtWidgets.QMessageBox.information(
self, "No ISO...",
"No ISO found.\n\nPlease select an ISO.")
return False
usb_details = config.usb_details
if usb_details['mount_point'] == 'No_Mount':
log("ERROR: USB disk is not mounted.")
QtWidgets.QMessageBox.information(self, "No Mount...", "USB disk is not mounted.\n"
"Please mount USB disk and press refresh USB button.")
self.ui_enable_controls()
elif platform.system() == 'Linux' and config.usb_disk[-1].isdigit() is False:
gen.log('Selected USB is a disk. Please select a disk partition from the drop down list')
QtWidgets.QMessageBox.information(self, 'No Partition...!',
'USB disk selected doesn\'t contain a partition.\n'
'Please select the partition (ending '
'with a digit eg. /dev/sdb1)\nfrom the drop down list.')
self.ui_enable_controls()
elif 0 < config.persistence and \
QtWidgets.QMessageBox.information(
self, "No Mount...",
"USB disk is not mounted.\n"
"Please mount USB disk and press refresh "
"USB button.")
return False
if platform.system() == 'Linux' and \
config.usb_disk[-1].isdigit() is False:
gen.log('Selected USB is a disk. Please select '
'a disk partition from the drop down list')
QtWidgets.QMessageBox.information(
self, 'No Partition...!',
'USB disk selected doesn\'t contain a '
'partition.\n'
'Please select the partition (ending '
'with a digit eg. /dev/sdb1)\n'
'from the drop down list.')
return False
if 0 < config.persistence and \
persistence.detect_missing_tools(config.distro):
QtWidgets.QMessageBox.information(
self, 'Missing tools...!',
persistence.detect_missing_tools(config.distro))
self.ui_enable_controls()
else:
persistence.detect_missing_tools(
config.distro))
return False
if not self.check_remount():
self.update_target_info()
return False
if 1: # Redundant if to keep indentation level.
# clean_iso_cfg_ext_dir(os.path.join(multibootusb_host_dir(), "iso_cfg_ext_dir")) # Need to be cleaned.
# extract_cfg_file(config.image_path) # Extract files from ISO
# config.distro = distro(iso_cfg_ext_dir(), config.image_path) # Detect supported distro
usb_details = usb.details(config.usb_disk)
# config.distro = distro(iso_cfg_ext_dir(), config.image_path) # Detect supported distro
log("MultiBoot Install: USB Disk: " + config.usb_disk)
log("MultiBoot Install: USB Label: " + config.usb_label)
log("MultiBoot Install: USB UUID: " + config.usb_uuid)
@ -576,61 +634,65 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
log("MultiBoot Install: Disk model: " + usb_details['model'])
log("MultiBoot Install: ISO file: " + iso_name(config.image_path))
if os.path.exists(config.image_path):
# self.ui.image_path.clear()
if config.distro:
log("MultiBoot Install: Distro type detected: " + config.distro)
if not os.path.exists(
os.path.join(config.usb_mount, "multibootusb", iso_basename(config.image_path))):
config.persistence = self.ui.slider_persistence.value() * 1024 * 1024
log("Persistence chosen is " + str(bytes2human(config.persistence)))
install_size = iso_size(config.image_path) + config.persistence
if install_size >= disk_usage(config.usb_mount).free:
log("ERROR: Not enough space available on " + config.usb_disk)
QtWidgets.QMessageBox.information(self, "No Space.",
"No space available on " + config.usb_disk)
self.ui_enable_controls()
else:
if config.distro == 'memdisk_iso':
reply = QtWidgets.QMessageBox.question(self, 'Review selection...',
'The ISO sleceted is not supported at the moment.\n'
'You can try booting ISO using memdisk.\n'
'Distro can be uninstalled anytime from main menu.\n\n'
'Proceed with installation?',
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
else:
reply = QtWidgets.QMessageBox.question(self, 'Review selection...',
'Selected USB disk: %s\n' % config.usb_disk +
'USB mount point: %s\n' % config.usb_mount +
'Selected distro: %s\n\n' % iso_name(
config.image_path) +
'Proceed with installation?',
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
self.ui.slider_persistence.setEnabled(False)
copy_mbusb_dir_usb(config.usb_disk)
config.process_exist = True
self.progress_thread_install.start()
elif reply == QtWidgets.QMessageBox.No:
self.ui_enable_controls()
else:
QtWidgets.QMessageBox.information(self, 'Already exists...',
os.path.basename(
config.image_path) + ' is already installed.')
self.ui_enable_controls()
if not os.path.exists(config.image_path):
return False
# self.ui.image_path.clear()
if not config.distro:
QtWidgets.QMessageBox.information(
self, 'No support...',
'Sorry.\n' + os.path.basename(config.image_path) +
' is not supported at the moment.\n'
'Please email this issue to '
'feedback.multibootusb@gmail.com')
return False
log("MultiBoot Install: Distro type detected: " + config.distro)
if os.path.exists(
os.path.join(config.usb_mount, "multibootusb", iso_basename(config.image_path))):
QtWidgets.QMessageBox.information(self, 'Already exists...',
os.path.basename(
config.image_path) + ' is already installed.')
return False
config.persistence = self.ui.slider_persistence.value() * 1024 * 1024
log("Persistence chosen is " + str(bytes2human(config.persistence)))
install_size = iso_size(config.image_path) + config.persistence
if install_size >= disk_usage(config.usb_mount).free:
log("ERROR: Not enough space available on " + config.usb_disk)
QtWidgets.QMessageBox.information(self, "No Space.",
"No space available on " + config.usb_disk)
return False
else:
if config.distro == 'memdisk_iso':
reply = QtWidgets.QMessageBox.question(self, 'Review selection...',
'The ISO sleceted is not supported at the moment.\n'
'You can try booting ISO using memdisk.\n'
'Distro can be uninstalled anytime from main menu.\n\n'
'Proceed with installation?',
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
else:
QtWidgets.QMessageBox.information(self, 'No support...',
'Sorry.\n' + os.path.basename(config.image_path) +
' is not supported at the moment.\n'
'Please email this issue to feedback.multibootusb@gmail.com')
self.ui_enable_controls()
# Added to refresh usb disk remaining size after distro installation
# self.update_gui_usb_info()
reply = QtWidgets.QMessageBox.question(self, 'Review selection...',
'Selected USB disk: %s\n' % config.usb_disk +
'USB mount point: %s\n' % config.usb_mount +
'Selected distro: %s\n\n' % iso_name(
config.image_path) +
'Proceed with installation?',
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No)
if reply == QtWidgets.QMessageBox.Yes:
self.ui.slider_persistence.setEnabled(False)
copy_mbusb_dir_usb(config.usb_disk)
config.process_exist = True
self.progress_thread_install.start()
return True
elif reply == QtWidgets.QMessageBox.No:
return False
# Added to refresh usb disk remaining size after distro installation
# self.update_gui_usb_info()
def dd_finished(self):
"""
@ -724,6 +786,39 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
"""
self.close()
def update_usb_mount(self, new_usb_details):
config.update_usb_mount(new_usb_details)
self.ui.usb_mount.setText(config.usb_mount)
def check_remount(self):
if config.usb_details['file_system'] != 'vfat':
return True
try:
with UnmountedContext(config.usb_disk,
self.update_usb_mount) as m:
pass
return True
except usb.RemountError:
QtWidgets.QMessageBox.critical(
self,"Remount failed.",
"Could not remount '{0}'. "
"Please make sure no process has open "
"handle(s) to previously mounted filesystem."
.format(config.usb_disk))
return False
def update_target_info(self):
config.persistence_max_size = persistence.max_disk_persistence(config.usb_disk)
config.usb_mount = config.usb_details.get('mount_point', "")
self.ui.usb_dev.setText(config.usb_disk)
self.ui.usb_vendor.setText(config.usb_details.get('vendor', ""))
self.ui.usb_model.setText(config.usb_details.get('model', ""))
self.ui.usb_size.setText(str(usb.bytes2human(config.usb_details.get('size_total', ""))))
self.ui.usb_mount.setText(config.usb_details.get('mount_point', ""))
self.ui.usb_type.setText(config.usb_details.get('devtype', ""))
self.ui.usb_fs.setText(config.usb_details.get('file_system', ""))
def closeEvent(self, event):
"""
To capture the main close event.
@ -746,7 +841,6 @@ class AppGui(qemu.Qemu, Imager, QtWidgets.QMainWindow, Ui_MainWindow):
log("Close event cancelled.")
event.ignore()
class GuiInstallProgress(QtCore.QThread):
"""
Update GUI thread during install.

@ -30,10 +30,11 @@ def max_disk_persistence(usb_disk):
config.usb_uuid = usb_details['uuid']
config.usb_label = usb_details['label']
if usb_details['file_system'] in ['vfat', 'FAT32'] and usb_details['size_free'] > fat_max_size:
_max_size = fat_max_size
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 = usb_details['size_free']
_max_size = size_free
return _max_size

@ -9,13 +9,14 @@
# under the terms of GNU General Public License, v.2 or above
import os
import subprocess
import platform
import subprocess
import traceback
from PyQt5 import QtWidgets
from .gui.ui_multibootusb import Ui_MainWindow
from .gen import *
from . import config
from . import usb
class Qemu(QtWidgets.QMainWindow, Ui_MainWindow):
"""
@ -27,35 +28,66 @@ class Qemu(QtWidgets.QMainWindow, Ui_MainWindow):
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def run_qemu(self, ram_size, qemu_more_params,
qemu_not_found_log_msg,
exec_error_title, exec_error_msg):
qemu = self.find_qemu()
if not qemu:
log(qemu_not_found_log_msg)
QtWidgets.QMessageBox.information(
self, 'No QEMU...',
'Please install qemu to use this feature.')
return
options = [] # '-bios', 'OVMF.fd']
if ram_size:
options.extend(['-m', ram_size])
if getattr(config, 'qemu_use_haxm', False):
options.extend(['-accel', 'hax'])
bios = getattr(config, 'qemu_bios', None)
if bios:
options.extend(['-bios', bios])
if platform.system()=='Linux' and getattr(config,'use_kvm', True):
options.append('-enable-kvm')
cmd = [qemu] + options + qemu_more_params
try:
new_wd = os.path.split(qemu)[0]
if new_wd:
old_wd = os.getcwd()
os.chdir(new_wd)
try:
with usb.UnmountedContext(config.usb_disk,
self.update_usb_mount):
log("Executing ==> %s" % cmd)
out = subprocess.check_output(cmd)
if out:
log('%s => %s' % (cmd, out))
finally:
if new_wd:
os.chdir(old_wd)
except (KeyboardInterrupt, SystemExit):
raise
except:
traceback.print_exc()
QtWidgets.QMessageBox.information(
self, exec_error_title, exec_error_msg)
def on_Qemu_Boot_iso_Click(self):
"""
Main function to boot a selected ISO.
:return:
"""
# if not self.ui.lineEdit_2.text():
if not config.image_path:
QtWidgets.QMessageBox.information(self, 'No ISO...', 'No ISO selected.\n\nPlease choose an ISO first.')
else:
qemu = self.check_qemu_exist()
qemu_iso_link = config.image_path
if not qemu:
log("ERROR: ISO Boot: qemu not found!")
QtWidgets.QMessageBox.information(self, 'No QEMU...', 'Please install qemu to use this feature.')
else:
ram = self.qemu_iso_ram()
if ram:
ram = " -m " + ram
else:
ram = ""
cmd = qemu + ram + ' -enable-kvm -boot d' + ' -cdrom "' + str(qemu_iso_link) + '"'
try:
log("Executing ==> " + cmd)
subprocess.Popen(cmd, shell=True)
except:
QtWidgets.QMessageBox.information(self, 'Error...', 'Error booting ISO\n'
'Unable to start QEMU.')
QtWidgets.QMessageBox.information(
self, 'No ISO...',
'No ISO selected.\n\nPlease choose an ISO first.')
return
self.run_qemu(
self.qemu_iso_ram(), ['-boot', 'd','-cdrom', config.image_path],
"ERROR: ISO Boot: qemu not found!",
'Error...', 'Error booting ISO\nUnable to start QEMU.')
def on_Qemu_Boot_usb_Click(self):
"""
@ -64,84 +96,47 @@ class Qemu(QtWidgets.QMainWindow, Ui_MainWindow):
:return:
"""
if not config.usb_disk:
QtWidgets.QMessageBox.information(self, 'No disk...', 'No USB disk selected.\n\nPlease choose a disk first.')
QtWidgets.QMessageBox.information(
self, 'No disk...',
'No USB disk selected.\n\nPlease choose a disk first.')
return
if platform.system() == "Windows":
disk_number = get_physical_disk_number(config.usb_disk)
qemu_more_params = ['-L', '.', '-boot', 'c', '-hda',
'//./PhysicalDrive' + str(disk_number)]
elif platform.system() == "Linux":
qemu_more_params = ['-hda', config.usb_disk.rstrip('0123456789'),
'-vga', 'std']
else:
qemu = self.check_qemu_exist()
if platform.system() == 'Linux' and config.usb_disk[-1].isdigit() is True:
qemu_usb_disk = config.usb_disk[:-1]
else:
qemu_usb_disk = config.usb_disk
assert False, "Unknown platform '%s'" % platform.system()
self.run_qemu(self.qemu_usb_ram(), qemu_more_params,
"ERROR: USB Boot: qemu not found!",
'Error...', 'Error booting USB\nUnable to start QEMU.')
if qemu is None:
log("ERROR: USB Boot: qemu not found!")
QtWidgets.QMessageBox.information(self, 'No QEMU...', 'Please install qemu to use this feature.')
else:
options = []
ram = self.qemu_usb_ram()
if ram:
options.extend(['-m', ram])
if getattr(config, 'qemu_use_haxm', False):
options.extend(['-accel', 'hax'])
bios = getattr(config, 'qemu_bios', None)
if bios:
options.extend(['-bios', bios])
optstr = (' ' + ' '.join(options)) if options else ''
if platform.system() == "Windows":
disk_number = get_physical_disk_number(qemu_usb_disk)
qemu_exe = find_qemu_exe()
qemu_dir = os.path.split(qemu_exe)[0]
parent_dir = os.getcwd()
os.chdir(qemu_dir)
cmd = quote(qemu_exe) + ' -L . -boot c' + optstr \
+ ' -hda //./PhysicalDrive' + str(disk_number)
try:
log("Executing ==> " + cmd)
subprocess.Popen(cmd, shell=True)
except:
QtWidgets.QMessageBox.information(
self, 'Error...',
'Error booting USB\nUnable to start QEMU.')
os.chdir(parent_dir)
elif platform.system() == "Linux":
cmd = qemu + ' -enable-kvm -hda "' + qemu_usb_disk + \
'"' + optstr + ' -vga std'
try:
log('Executing ==> ' + cmd)
subprocess.Popen(cmd, shell=True)
except:
QtWidgets.QMessageBox.information(self, 'Error...', 'Error booting USB\n\nUnable to start QEMU.')
def qemu_ram_size(self, combo, log_msg):
selected_ram = combo.currentText()
log(log_msg % selected_ram)
return selected_ram != 'Default' and selected_ram or None
def qemu_iso_ram(self):
"""
Choose a ram size for ISO booting.
:return: Ram size as string.
"""
selected_ram = self.ui.combo_iso_boot_ram.currentText()
log("QEMU: ISO RAM = " + selected_ram)
if selected_ram == "Default":
return None
else:
return selected_ram
return self.qemu_ram_size(self.ui.combo_iso_boot_ram,
"QEMU: ISO RAM = %s")
def qemu_usb_ram(self):
"""
Choose a ram size for USB booting.
:return: Ram size as string.
"""
selected_ram = self.ui.combo_usb_boot_ram.currentText()
log("QEMU: USB RAM = " + selected_ram)
if selected_ram == "Default":
return None
else:
return selected_ram
return self.qemu_ram_size(self.ui.combo_usb_boot_ram,
"QEMU: USB RAM = %s")
@staticmethod
def check_qemu_exist():
def find_qemu():
"""
Check if QEMU is available on host system.
Check if QEMU is available on host system and return path of the binary
:return: path to QEMU program or None otherwise.
"""
if platform.system() == "Linux":
@ -166,7 +161,7 @@ def find_qemu_exe():
exe_name = 'qemu-system-x86_64.exe'
if hasattr(config, 'qemu_exe_path'):
return config.qemu_exe_path
if (not hasattr(config, 'qemu_use_builtin')) or not config.qemu_use_builtin:
if not getattr(config, 'qemu_use_builtin', True):
for wellknown_path in [
r'c:\Program Files\qemu',
r'd:\Program Files\qemu',

@ -90,6 +90,32 @@ def set_boot_flag(usb_disk):
log("\nUnable to set legacy_boot flag on " + usb_disk[:-1], '\n')
return False
def linux_install_default_bootsector(usb_disk, mbr_install_cmd):
with usb.UnmountedContext(usb_disk, config.update_usb_mount):
syslinux_cmd = [syslinux_path, '-i', '-d', 'multibootusb', usb_disk]
if os.access(syslinux_path, os.X_OK) is False:
subprocess.call('chmod +x ' + syslinux_path)
log("\nExecuting ==> %s\n" % syslinux_cmd)
config.status_text = 'Installing default syslinux version 4...'
if subprocess.call(syslinux_cmd) == 0:
usb.repair_vfat_filesystem(usb_disk)
log("\nDefault syslinux install is success...\n")
config.status_text = 'Default syslinux successfully installed...'
log('\nExecuting ==> ' + mbr_install_cmd)
if subprocess.call(mbr_install_cmd, shell=True) == 0:
config.status_text = 'mbr install is success...'
log("\nmbr install is success...\n")
if set_boot_flag(usb_disk) is True:
return True
else:
log("\nFailed to install default syslinux...\n")
config.status_text = 'Failed to install default syslinux...'
return False
return None
def syslinux_default(usb_disk):
"""
@ -102,9 +128,9 @@ def syslinux_default(usb_disk):
usb_fs = usb_details['file_system']
usb_mount = usb_details['mount_point']
mbr_bin = get_mbr_bin_path(usb_disk)
if platform.system() == 'Linux':
mbr_install_cmd = 'dd bs=440 count=1 conv=notrunc if=' + mbr_bin + ' of=' + usb_disk[:-1]
mbr_install_cmd = 'dd bs=440 count=1 conv=notrunc if=' + mbr_bin \
+ ' of=' + usb_disk[:-1]
else:
win_usb_disk_no = get_physical_disk_number(config.usb_disk)
_windd = resource_path(os.path.join("data", "tools", "dd", "dd.exe"))
@ -132,25 +158,7 @@ def syslinux_default(usb_disk):
elif usb_fs in syslinux_fs:
if platform.system() == "Linux":
syslinux_cmd = syslinux_path + ' -i -d multibootusb ' + usb_disk
if os.access(syslinux_path, os.X_OK) is False:
subprocess.call('chmod +x ' + syslinux_path, shell=True)
log("\nExecuting ==> " + syslinux_cmd + "\n")
config.status_text = 'Installing default syslinux version 4...'
if subprocess.call(syslinux_cmd, shell=True) == 0:
log("\nDefault syslinux install is success...\n")
config.status_text = 'Default syslinux successfully installed...'
log('\nExecuting ==> ' + mbr_install_cmd)
if subprocess.call(mbr_install_cmd, shell=True) == 0:
config.status_text = 'mbr install is success...'
log("\nmbr install is success...\n")
if set_boot_flag(usb_disk) is True:
return True
else:
log("\nFailed to install default syslinux...\n")
config.status_text = 'Failed to install default syslinux...'
return False
return linux_install_default_bootsector(usb_disk, mbr_install_cmd)
elif platform.system() == "Windows":
syslinux = resource_path(os.path.join(multibootusb_host_dir(), "syslinux", "bin", "syslinux4.exe"))
config.status_text = 'Installing default syslinux version 4...'
@ -189,6 +197,52 @@ def syslinux_default(usb_disk):
return False
def build_distro_bootsector(usb_disk, options,
distro_syslinux_install_dir,
distro_sys_install_bs):
with usb.UnmountedContext(config.usb_disk, config.update_usb_mount):
tmp_bs = build_distro_bootsector_impl(
usb_disk, options, distro_syslinux_install_dir)
if tmp_bs:
shutil.copy(tmp_bs, distro_sys_install_bs)
def build_distro_bootsector_impl(usb_disk, options,
distro_syslinux_install_dir):
syslinux_path = os.path.join(
multibootusb_host_dir(), "syslinux", "bin", "syslinux") \
+ config.syslinux_version
if os.access(syslinux_path, os.X_OK) is False:
subprocess.call('chmod +x ' + syslinux_path, shell=True)
sys_cmd = [syslinux_path] + options + [
distro_syslinux_install_dir, usb_disk]
log("Executing ==> %s" % sys_cmd)
if subprocess.call(sys_cmd) == 0:
config.status_text = \
'Syslinux install on distro directory is successful...'
log("\nSyslinux install on distro directory is successful...\n")
usb.repair_vfat_filesystem(usb_disk)
tmp_bs_file = '/tmp/mbusb_temp.bs'
dd_cmd = ['dd', 'if=' + usb_disk, 'of=' + tmp_bs_file, 'count=1']
log('Executing ==> %s' % dd_cmd + '\n')
config.status_text = 'Copying boot sector...'
config.status_text = 'Installing distro specific syslinux...'
if subprocess.call(dd_cmd) == 0:
config.status_text = 'Bootsector copy is successful...'
log("\nBootsector copy is successful...\n")
else:
config.status_text = 'Failed to copy boot sector...'
log("\nFailed to copy boot sector...\n")
return tmp_bs_file
else:
config.status_text = 'Failed to install syslinux on distro directory...'
log("\nFailed to install syslinux on distro directory...\n")
return None
def syslinux_distro_dir(usb_disk, iso_link, distro):
"""
Install syslinux/extlinux on distro specific isolinux directory.
@ -214,12 +268,19 @@ def syslinux_distro_dir(usb_disk, iso_link, distro):
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')
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')
else:
install_dir = os.path.join(usb_mount, "multibootusb", iso_basename(iso_link))
distro_syslinux_install_dir = os.path.join(install_dir, iso_linux_bin_dir.strip("/")).replace(usb_mount, "")
distro_sys_install_bs = os.path.join(install_dir, iso_linux_bin_dir.strip("/"), distro + '.bs')
install_dir = os.path.join(usb_mount, "multibootusb",
iso_basename(iso_link))
distro_syslinux_install_dir = os.path.join(
install_dir, iso_linux_bin_dir.strip("/")
).replace(usb_mount, "")
distro_sys_install_bs = os.path.join(
install_dir, iso_linux_bin_dir.strip("/"), distro + '.bs')
# log(distro_sys_install_bs)
# log(distro_syslinux_install_dir)
@ -231,40 +292,21 @@ def syslinux_distro_dir(usb_disk, iso_link, distro):
options.append('-i')
if not (distro == "generic" and iso_linux_bin_dir == "/"):
options.append('-d')
option = ' ' + ' '.join(options) + ' '
if platform.system() == "Linux":
syslinux_path = os.path.join(multibootusb_host_dir(), "syslinux", "bin", "syslinux") + config.syslinux_version
if os.access(syslinux_path, os.X_OK) is False:
subprocess.call('chmod +x ' + syslinux_path, shell=True)
sys_cmd = syslinux_path + option + quote(distro_syslinux_install_dir) + ' ' + usb_disk
dd_cmd = 'dd if=' + usb_disk + ' ' + 'of=' + quote(distro_sys_install_bs) + ' count=1'
log("Executing ==> " + sys_cmd)
config.status_text = 'Installing distro specific syslinux...'
if subprocess.call(sys_cmd, shell=True) == 0:
config.status_text = 'Syslinux install on distro directory is successful...'
log("\nSyslinux install on distro directory is successful...\n")
log('Executing ==> ' + dd_cmd + '\n')
config.status_text = 'Copying boot sector...'
if subprocess.call(dd_cmd, shell=True) == 0:
config.status_text = 'Bootsector copy is successful...'
log("\nBootsector copy is successful...\n")
else:
config.status_text = 'Failed to copy boot sector...'
log("\nFailed to copy boot sector...\n")
else:
config.status_text = 'Failed to install syslinux on distro directory...'
log("\nFailed to install syslinux on distro directory...\n")
build_distro_bootsector(usb_disk, options,
distro_syslinux_install_dir,
distro_sys_install_bs)
elif platform.system() == "Windows":
syslinux_path = resource_path(os.path.join(multibootusb_host_dir(), "syslinux", "bin")) + \
"\syslinux" + config.syslinux_version + ".exe"
distro_syslinux_install_dir = "/" + distro_syslinux_install_dir.replace("\\", "/")
distro_sys_install_bs = distro_sys_install_bs.replace("/", "\\")
sys_cmd = syslinux_path + option + distro_syslinux_install_dir + ' ' + usb_disk + ' ' + \
distro_sys_install_bs
log("\nExecuting ==> " + sys_cmd + '\n')
sys_cmd = [syslinux_path] + options + \
[distro_syslinux_install_dir, usb_disk,
distro_sys_install_bs]
log("\nExecuting ==> %s" % sys_cmd )
config.status_text = 'Installing distro specific syslinux...'
if subprocess.call(sys_cmd, shell=True) == 0:
if subprocess.call(sys_cmd) == 0:
config.status_text = 'Syslinux install on distro directory is successful...'
log("\nSyslinux install was successful on distro directory...\n")
else:
@ -288,6 +330,8 @@ def syslinux_distro_dir(usb_disk, iso_link, distro):
log("\nFailed to install syslinux on distro directory...\n")
def replace_grub_binary():
"""
This function checks if correct binary is installed on grub and EFI directory.

@ -51,27 +51,24 @@ class UDisks(object):
return dbus.Interface(self.bus.get_object('org.freedesktop.UDisks',
devpath), 'org.freedesktop.UDisks.Device')
def mount(self, device_node_path):
def mount(self, device_node_path, remounted=None):
mp = node_mountpoint(str(device_node_path))
if mp:
return mp
d = self.device(device_node_path)
try:
return str(d.FilesystemMount('',
['auth_no_user_interaction', 'rw', 'noexec', 'nosuid',
r = str(d.FilesystemMount(
'', ['auth_no_user_interaction', 'rw', 'noexec', 'nosuid',
'nodev', 'uid=%d'%os.geteuid(), 'gid=%d'%os.getegid()]))
except:
# May be already mounted, check
mp = node_mountpoint(str(device_node_path))
if mp is None:
raise
return mp
if remounted is not None:
remounted.append(True)
return r
def unmount(self, device_node_path):
d = self.device(device_node_path)
d.FilesystemUnmount(['force'])
def eject(self, device_node_path):
parent = device_node_path
while parent[-1] in '0123456789':
parent = parent[:-1]
parent = device_node_path.rstrip('0123456789')
d = self.device(parent)
d.DriveEject([])
@ -132,24 +129,20 @@ class UDisks2(object):
raise ValueError('%r not known to UDisks2'%device_node_path)
def mount(self, device_node_path):
def mount(self, device_node_path, remounted=None):
mp = node_mountpoint(str(device_node_path))
if mp:
return mp
d = self.device(device_node_path)
mount_options = ['rw', 'noexec', 'nosuid', 'nodev']
try:
mp = str(d.Mount(
{
'auth.no_user_interaction':True,
'options':','.join(mount_options)
mp = str(d.Mount(
{
'auth.no_user_interaction':True,
'options':','.join(mount_options)
},
dbus_interface=self.FILESYSTEM))
print(mp)
except:
# May be already mounted, check
mp = node_mountpoint(str(device_node_path))
if mp is None:
raise
if remounted is not None:
remounted.append(True)
return mp
def unmount(self, device_node_path):

@ -21,7 +21,7 @@ def install_distro_list():
List all distro names installed by previous install
:return: List of distro names as list
"""
usb_details = details(config.usb_disk)
usb_details = config.usb_details
config.usb_mount = usb_details['mount_point']
sys_cfg_file = os.path.join(config.usb_mount, "multibootusb", "syslinux.cfg")
@ -54,7 +54,7 @@ def delete_frm_file_list(iso_file_list, uninstall_distro_dir_name):
:param config.uninstall_distro_dir_name: Directory where the distro is installed
:return:
"""
usb_details = details(config.usb_disk)
usb_details = config.usb_details
usb_mount = usb_details['mount_point']
if iso_file_list is not None:
for f in iso_file_list:
@ -89,9 +89,6 @@ def delete_frm_file_list(iso_file_list, uninstall_distro_dir_name):
if os.path.exists(os.path.join(usb_mount, generic.strip("/"))):
os.remove(os.path.join(usb_mount, generic.strip("/")))
gen.log('Removed files from ' + uninstall_distro_dir_name)
if platform.system() == 'Linux':
gen.log('Syncing....')
os.sync()
@ -104,11 +101,10 @@ def do_uninstall_distro(target_distro, uninstall_distro_dir_name):
:param uninstall_distro_dir_name: Directory where the distro is installed
:return:
"""
usb_details = details(config.usb_disk)
usb_details = config.usb_details
usb_mount = usb_details['mount_point']
if platform.system() == 'Linux':
os.sync()
# remove 'immutable' from files on ext2/3/4 fs
if usb_mount:
subprocess.call("chattr -i -R %s/* 2>/dev/null" % usb_mount, shell=True)
@ -149,8 +145,6 @@ def do_uninstall_distro(target_distro, uninstall_distro_dir_name):
shutil.rmtree(os.path.join(usb_mount, "trk3"))
if os.path.exists(uninstall_distro_dir_name_fullpath):
if platform.system() == 'Linux':
os.sync()
shutil.rmtree(uninstall_distro_dir_name_fullpath)
delete_frm_file_list(iso_file_list, uninstall_distro_dir_name)
@ -178,8 +172,6 @@ def update_sys_cfg_file(uninstall_distro_dir_name):
Main function to remove uninstall distro specific operations.
:return:
"""
if platform.system() == 'Linux':
os.sync()
sys_cfg_file = os.path.join(config.usb_mount, "multibootusb", "syslinux.cfg")
if not os.path.exists(sys_cfg_file):
@ -201,8 +193,6 @@ def update_grub_cfg_file(uninstall_distro_dir_name):
Main function to remove uninstall distro name from the grub.cfg file.
:return:
"""
if platform.system() == 'Linux':
os.sync()
grub_cfg_file = os.path.join(config.usb_mount, "multibootusb",
"grub", "grub.cfg")
@ -229,10 +219,8 @@ def uninstall_progress():
:return:
"""
from . import progressbar
usb_details = details(config.usb_disk)
usb_details = config.usb_details
usb_mount = usb_details['mount_point']
if platform.system() == 'Linux':
os.sync()
uninstall_distro_dir_name = config.uninstall_distro_dir_name \
.replace('\n', '')

@ -126,7 +126,7 @@ def update_distro_cfg_files(iso_link, usb_disk, distro, persistence=0):
Main function to modify/update distro specific strings on distro config files.
:return:
"""
usb_details = details(usb_disk)
usb_details = config.usb_details
usb_mount = usb_details['mount_point']
usb_uuid = usb_details['uuid']
usb_label = usb_details['label']
@ -423,8 +423,6 @@ def update_mbusb_cfg_file(iso_link, usb_uuid, usb_mount, distro):
Update main multibootusb suslinux.cfg file after distro is installed.
:return:
"""
if platform.system() == 'Linux':
os.sync()
log('Updating multibootusb config file...')
name_from_iso = iso_basename(iso_link)
name_of_iso = iso_name(iso_link)

@ -6,13 +6,18 @@
# 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 sys
import platform
import os
import shutil
import collections
import ctypes
import os
import platform
import shutil
import subprocess
import sys
import time
if platform.system()=='Linux':
import dbus
from . import config
from . import gen
if platform.system() == 'Linux':
@ -114,7 +119,6 @@ def list_devices(fixed=False):
except Exception as e:
gen.log(e)
import dbus
bus = dbus.SystemBus()
try:
# You should come here only if your system does'nt have udev installed.
@ -246,27 +250,29 @@ def details_udev(usb_disk_part):
str(usb_disk_part))
return None
if b'Extended' in fdisk_cmd_out:
detected_type = None
for keyword, ptype in [(b'Extended', 'extended partition'),
(b'swap', 'swap partition'),
(b'Linux LVM', 'lvm partition'),]:
if keyword in fdisk_cmd_out:
detected_type = ptype
break
if detected_type:
mount_point = ''
uuid = ''
file_system = ''
vendor = ''
model = ''
label = ''
devtype = "extended partition"
elif b'swap' in fdisk_cmd_out:
mount_point = ''
uuid = ''
file_system = ''
vendor = ''
model = ''
label = ''
devtype = "swap partition"
devtype = detected_type
elif device.get('DEVTYPE') == "partition":
uuid = device.get('ID_FS_UUID') or ""
file_system = device.get('ID_FS_TYPE') or ""
label = device.get('ID_FS_LABEL') or ""
mount_point = UDISKS.mount(usb_disk_part) or ""
remounted = []
mount_point = UDISKS.mount(usb_disk_part, remounted) or ""
if remounted and remounted[0]:
config.add_remounted(usb_disk_part)
mount_point = mount_point.replace('\\x20', ' ')
vendor = device.get('ID_VENDOR') or ""
model = device.get('ID_MODEL') or ""
@ -291,7 +297,7 @@ def details_udev(usb_disk_part):
' | grep "^Disk /" | sed -re "s/.*\s([0-9]+)\sbytes.*/\\1/"'
size_total = subprocess.check_output(fdisk_cmd, shell=True).strip()
size_used = ""
size_free = ""
size_free = 0
mount_point = ""
return {'uuid': uuid, 'file_system': file_system, 'label': label, 'mount_point': mount_point,
@ -332,6 +338,7 @@ def details_udisks2(usb_disk_part):
else:
try:
mount_point = UDISKS.mount(usb_disk_part)
config.add_remounted(usb_disk_part)
except:
mount_point = "No_Mount"
try:
@ -349,13 +356,12 @@ def details_udisks2(usb_disk_part):
except:
model = str('No_Model')
if not mount_point == "No_Mount":
size_total = shutil.disk_usage(mount_point)[0]
size_used = shutil.disk_usage(mount_point)[1]
size_free = shutil.disk_usage(mount_point)[2]
size_total, size_used, size_free = \
shutil.disk_usage(mount_point)[:3]
else:
size_total = str('No_Mount')
size_used = str('No_Mount')
size_free = str('No_Mount')
size_free = 0
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,
@ -410,6 +416,71 @@ def gpt_device(dev_name):
gen.log('Device ' + dev_name + ' is a GPT disk...')
return True
def unmount(usb_disk):
UDISKS.unmount(usb_disk)
class RemountError(Exception):
def __init__(self, caught_exception, *args, **kw):
super(RemountError, self).__init__(*args, **kw)
self.caught_exception = caught_exception
def __str__(self):
return "%s due to '%s'" % (
self.__class__.__name__, self.caught_exception)
class UnmountError(RemountError):
def __init__(self, *args, **kw):
super(UnmountError, self).__init__(*args, **kw)
class MountError(RemountError):
def __init__(self, *args, **kw):
super(MountError, self).__init__(*args, **kw)
class UnmountedContext:
def __init__(self, usb_disk, exit_callback):
self.usb_disk = usb_disk
self.exit_callback = exit_callback
self.is_relevant = platform.system() != 'Windows' and \
self.usb_disk[-1:].isdigit()
def assert_no_access(self):
p = subprocess.Popen(['lsof', self.usb_disk],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
output = p.communicate()
if len(output[0].strip()) != 0:
gen.log("Open handle exists.")
gen.log(output[0])
raise UnmountError(Exception('open handle exists.'))
def __enter__(self):
if not self.is_relevant:
return
self.assert_no_access()
try:
gen.log("Unmounting %s" % self.usb_disk)
UDISKS.unmount(self.usb_disk)
except dbus.exceptions.DBusException:
gen.log("Unmount of %s has failed." % self.usb_disk)
# This may get the partition mounted. Don't call!
# self.exit_callback(details(self.usb_disk))
raise UnmountError(e)
gen.log("Unmounted %s" % self.usb_disk)
os.sync()
return self
def __exit__(self, type, value, traceback_):
if not self.is_relevant:
return
os.sync() # This should not be strictly necessary
time.sleep(1) # Yikes, mount always fails without this sleep().
try:
mount_point = UDISKS.mount(self.usb_disk)
config.add_remounted(self.usb_disk)
self.exit_callback(details(self.usb_disk))
except dbus.exceptions.DBusException as e:
raise MountError(e)
gen.log("Mounted %s" % (self.usb_disk))
def win_disk_details(disk_drive):
"""
@ -436,9 +507,7 @@ def win_disk_details(disk_drive):
serno = "%X" % (int(d.SerialNumber) & 0xFFFFFFFF)
uuid = serno[:4] + '-' + serno[4:]
file_system = (d.FileSystem).strip()
size_total = shutil.disk_usage(mount_point)[0]
size_used = shutil.disk_usage(mount_point)[1]
size_free = shutil.disk_usage(mount_point)[2]
size_total, size_used, size_free = shutil.disk_usage(mount_point)[:3]
# The below code works only from vista and above. I have removed it as many people reported that the software
# was not working under windows xp. Even then, it is significantly slow if 'All Drives' option is checked.
@ -456,6 +525,34 @@ def win_disk_details(disk_drive):
'vendor': vendor, 'model': model, 'devtype': devtype}
def check_vfat_filesystem(usb_disk, result=None):
p = subprocess.Popen(['fsck.vfat', '-n', usb_disk],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
output = p.communicate()
gen.log("fsck.vfat -n returned %d" % p.returncode)
gen.log(b"fsck.vfat -n said:" + b'\n---\n'.join(f for f in output if f))
if result is not None:
result.append((p.returncode, output, 'fsck.vfat -n'))
return len(output[0].split(b'\n'))==3 and output[1]==b'' \
and p.returncode==0
def repair_vfat_filesystem(usb_disk, result=None):
for args, input_ in [
(['-a', usb_disk], None, ),
(['-r', usb_disk], b'1\ny\n', ),
]:
cmd = ['fsck.vfat'] + args
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=subprocess.PIPE)
output = p.communicate(input=input_)
gen.log("%s returned %d" % (' '.join(cmd), p.returncode))
gen.log(b"It said:" + b'\n---\n'.join(f for f in output if f))
if result is not None:
result.append((p.returncode, output, ' '.join(cmd)))
return None
def details(usb_disk_part):
"""
Populate and get details of an USB disk.

Loading…
Cancel
Save