From 890c2663420cf4d4d4fec5fd11f5e39b22792c16 Mon Sep 17 00:00:00 2001
From: mbusb
Step 3
")) - self.slider_persistence.setToolTip(_translate("Dialog", "Choose Persistence size. Not all distros supports persistence...")) - self.close.setText(_translate("Dialog", "Close")) - self.groupBox_11.setTitle(_translate("Dialog", "Detect USB")) - self.detect_usb.setText(_translate("Dialog", "Refresh USB")) + self.groupBox_11.setTitle(_translate("Dialog", "Detect")) + self.detect_usb.setText(_translate("Dialog", "Detect Drives")) + self.create.setText(_translate("Dialog", "Create")) self.labelstep1.setText(_translate("Dialog", "Step 1
")) self.labelstep2.setText(_translate("Dialog", "Step 2
")) - self.create.setText(_translate("Dialog", "Create")) + self.close.setText(_translate("Dialog", "Close")) + self.labelstep3.setText(_translate("Dialog", "Step 3
")) + self.slider_persistence.setToolTip(_translate("Dialog", "Choose Persistence size. Not all distros supports persistence...")) self.groupBox.setTitle(_translate("Dialog", "Uninstall (Optional)")) self.uninstall.setText(_translate("Dialog", "Uninstall Distro")) - self.browse_iso.setText(_translate("Dialog", "Browse ISO")) - self.label_persistence.setText(_translate("Dialog", "Persistence
")) self.groupBox_6.setTitle(_translate("Dialog", "USB Details")) self.usb_dev.setText(_translate("Dialog", "Drive ::")) self.usb_vendor.setText(_translate("Dialog", "Vendor ::")) self.usb_model.setText(_translate("Dialog", "Model::")) self.usb_size.setText(_translate("Dialog", "Size ::")) self.usb_mount.setText(_translate("Dialog", "Mount ::")) + self.browse_iso.setText(_translate("Dialog", "Browse ISO")) + self.label_persistence.setText(_translate("Dialog", "Persistence
")) + self.checkBox_all_drives.setText(_translate("Dialog", "All Drives")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("Dialog", "MultiBootUSB")) self.groupBox_7.setTitle(_translate("Dialog", "Imager")) self.groupBox_9.setTitle(_translate("Dialog", "-------------- USB details -------------------")) diff --git a/scripts/mbusb_gui.py b/scripts/mbusb_gui.py index 11a2ceed..6010fd87 100644 --- a/scripts/mbusb_gui.py +++ b/scripts/mbusb_gui.py @@ -40,6 +40,7 @@ def __init__(self): self.ui.setupUi(self) # Main Tab + self.ui.checkBox_all_drives.clicked.connect(self.add_device) self.ui.detect_usb.clicked.connect(self.onRefereshClick) self.ui.close.clicked.connect(self.on_close_Click) self.ui.browse_iso.clicked.connect(self.browse_iso) @@ -92,7 +93,11 @@ def add_device(self): Adds list of available USB devices to GUI combobox. :return: """ - detected_device = usb.list() + self.ui.comboBox.clear() + if self.ui.checkBox_all_drives.isChecked(): + detected_device = usb.list(partition=1, fixed=True) + else: + detected_device = usb.list() if bool(detected_device): for device in detected_device: self.ui.comboBox.addItem(str(device)) @@ -132,8 +137,12 @@ def update_gui_oncombobox(self, usb_disk): config.usb_mount = self.usb_details['mount_point'] self.ui.usb_dev.setText("Drive :: " + usb_disk) # self.label.setFont(QtGui.QFont("Times",weight=QtGui.QFont.Bold)) - self.ui.usb_vendor.setText("Vendor :: " + self.usb_details['vendor']) - self.ui.usb_model.setText("Model :: " + self.usb_details['model']) + if platform.system() == 'Windows': + self.ui.usb_vendor.setText("FileSystem :: " + self.usb_details['file_system']) + self.ui.usb_model.setText("Label :: " + self.usb_details['label']) + else: + self.ui.usb_vendor.setText("Vendor :: " + self.usb_details['vendor']) + self.ui.usb_model.setText("Model :: " + self.usb_details['model']) self.ui.usb_size.setText("Total Size :: " + str(usb.bytes2human(self.usb_details['size_total']))) self.ui.usb_mount.setText("Mount :: " + self.usb_details['mount_point']) self.update_list_box(usb_disk) @@ -206,6 +215,7 @@ def install_syslinux(self): os.system('sync') self.ui.status.clear() QtWidgets.QMessageBox.information(self, 'Finished...', iso_name(config.iso_link) + ' has been successfully installed.') + config.process_exist = None def onInstall_syslinuxClick(self): """ @@ -349,6 +359,7 @@ def onCreateClick(self): if reply == QtWidgets.QMessageBox.Yes: self.ui.slider_persistence.setEnabled(False) + config.process_exist = True self.progress_thread_install.start() else: @@ -374,6 +385,7 @@ def dd_finished(self): self.ui.pushButton.setEnabled(True) self.ui.imager_bootable.setText("Bootable ISO :: ") self.ui.imager_iso_size.setText("ISO Size :: ") + config.process_exist = None QtWidgets.QMessageBox.information(self, 'Finished...', 'ISO has been written to USB disk.\nPlease reboot your ' 'system to boot from USB.') @@ -420,6 +432,7 @@ def dd_write(self): if reply == QtWidgets.QMessageBox.Yes: self.dd_start() + config.process_exist = True self.progress_thread_dd.start() def on_close_Click(self): @@ -435,16 +448,20 @@ def closeEvent(self, event): :param event: Close event. :return: """ - reply = QtWidgets.QMessageBox.question(self, 'Exit MultiBootUSB...', - "Do you really want to quit multibootusb?", QtWidgets.QMessageBox.Yes, - QtWidgets.QMessageBox.No) - if reply == QtWidgets.QMessageBox.Yes: - print("Closing multibootusb...") + if config.process_exist == None: event.accept() - sys.exit(0) else: - print("Close event cancelled.") - event.ignore() + reply = QtWidgets.QMessageBox.question(self, 'Exit MultiBootUSB...', + "A process is still running.\n" + "Do you really want to quit multibootusb?", QtWidgets.QMessageBox.Yes, + QtWidgets.QMessageBox.No) + if reply == QtWidgets.QMessageBox.Yes: + print("Closing multibootusb...") + event.accept() + sys.exit(0) + else: + print("Close event cancelled.") + event.ignore() class GuiInstallProgress(QtCore.QThread): @@ -578,6 +595,20 @@ def run(self): self.function(*self.args, **self.kwargs) return + +def show_admin_info(): + """ + Show simple information box reminding user to run the software with admin/root privilege. + Only required under Linux as the windows executable always will start with admin privilege. + :return: + """ + msg = QtWidgets.QMessageBox() + msg.setIcon(QtWidgets.QMessageBox.Information) + msg.setText('Admin privilege is required to run multibootusb.\n If you are running from source try ' + '\'sudo python3 ./multibootusb\'\n or you can try \'multibootusb-pkexec\' (post install)') + msg.exec_() + + def main_gui(): app = QtWidgets.QApplication(sys.argv) window = AppGui() @@ -585,4 +616,7 @@ def main_gui(): window.show() window.setWindowTitle("MultiBootUSB - " + mbusb_version()) window.setWindowIcon(QtGui.QIcon(resource_path(os.path.join("data", "tools", "multibootusb.png")))) + if platform.system() == 'Linux': + if os.getuid() != 0: + show_admin_info() sys.exit(app.exec_()) diff --git a/scripts/qemu.py b/scripts/qemu.py index 2d6b85ee..9809c6ce 100644 --- a/scripts/qemu.py +++ b/scripts/qemu.py @@ -129,7 +129,7 @@ def qemu_iso_ram(self): elif self.ui.ram_iso_1024.isChecked(): return str(1024) elif self.ui.ram_iso_2048.isChecked(): - return str(2048) + return str(2047) else: return None @@ -147,7 +147,7 @@ def qemu_usb_ram(self): if self.ui.ram_usb_1024.isChecked(): return str(1024) if self.ui.ram_usb_2048.isChecked(): - return str(2048) + return str(2047) else: return None @@ -174,6 +174,7 @@ def check_qemu_exist(self): print(resource_path(os.path.join("data", "tools", "qemu", "qemu-system-x86_64.exe"))) return resource_path(os.path.join("data", "tools", "qemu", "qemu-system-x86_64.exe")) + def get_physical_disk_number(self, usb_disk): """ Get the physical disk number as detected ny Windows. diff --git a/scripts/usb.py b/scripts/usb.py index 6d77057a..b29f3beb 100644 --- a/scripts/usb.py +++ b/scripts/usb.py @@ -12,6 +12,12 @@ import shutil import collections import ctypes +if platform.system() == 'Windows': + import psutil + import win32com.client + import win32com.client + import wmi + import pythoncom def is_block(usb_disk): @@ -74,7 +80,7 @@ def disk_usage(mount_path): raise NotImplementedError("Platform not supported.") -def list(partition=1): +def list(partition=1, fixed=None): """ List inserted USB devices. :return: USB devices as list. @@ -86,15 +92,19 @@ def list(partition=1): try: - # pyudev is good enough to detect USB devices on modern Linux - # machines. + # pyudev is good enough to detect USB devices on modern Linux machines. print("Using pyudev for detecting USB drives...") context = pyudev.Context() - for device in context.list_devices(subsystem='block', DEVTYPE='partition', - ID_FS_USAGE="filesystem", ID_TYPE="disk", - ID_BUS="usb"): - if device['ID_BUS'] == "usb" and device['DEVTYPE'] == "partition": - # print(device['DEVNAME']) + if fixed is None: + for device in context.list_devices(subsystem='block', DEVTYPE='partition', + ID_FS_USAGE="filesystem", ID_TYPE="disk", + ID_BUS="usb"): + # if device['ID_BUS'] == "usb" and device['DEVTYPE'] == "partition": + if device['ID_BUS'] in ("usb", "scsi") and device['DEVTYPE'] == "partition": + # print(device['DEVNAME']) + devices.append(str(device['DEVNAME'])) + else: + for device in context.list_devices(subsystem='block', DEVTYPE='partition'): devices.append(str(device['DEVNAME'])) except: bus = dbus.SystemBus() @@ -139,12 +149,28 @@ def list(partition=1): print("No USB device found...") elif platform.system() == "Windows": - import win32com.client - oFS = win32com.client.Dispatch("Scripting.FileSystemObject") - oDrives = oFS.Drives - for drive in oDrives: - if drive.DriveType == 1 and drive.IsReady: - devices.append(drive) + if fixed is not None: + for drive in psutil.disk_partitions(): + if 'cdrom' in drive.opts or drive.fstype == '': + # Skip cdrom drives or the disk with no filesystem + continue + devices.append(drive[0][:-1]) + else: + try: + # Try new method using psutil. It should also detect USB 3.0 (but not tested by me) + for drive in psutil.disk_partitions(): + if 'cdrom' in drive.opts or drive.fstype == '': + # Skip cdrom drives or the disk with no filesystem + continue + if 'removable' in drive.opts: + devices.append(drive[0][:-1]) + except: + # Revert back to old method if psutil fails (which is unlikely) + oFS = win32com.client.Dispatch("Scripting.FileSystemObject") + oDrives = oFS.Drives + for drive in oDrives: + if drive.DriveType == 1 and drive.IsReady: + devices.append(drive) if devices: return devices @@ -169,7 +195,8 @@ def details_udev(usb_disk_part): for device in context.list_devices(subsystem='block', DEVTYPE='partition', ID_FS_USAGE="filesystem", ID_TYPE="disk", ID_BUS="usb"): - if device['ID_BUS'] == "usb" and device['DEVTYPE'] == "partition": + # if device['ID_BUS'] == "usb" and device['DEVTYPE'] == "partition": + if device['ID_BUS'] in ("usb", "scsi") and device['DEVTYPE'] == "partition": if (device['DEVNAME']) == usb_disk_part: uuid = str(device['ID_FS_UUID']) file_system = str(device['ID_FS_TYPE']) @@ -279,13 +306,9 @@ def win_disk_details(disk_drive): :param disk_drive: USB disk like 'G:' :return: See the details(usb_disk_part) function for return values. """ - import win32com.client - import wmi - import pythoncom pythoncom.CoInitialize() vendor = 'Not_Found' model = 'Not_Found' - c = wmi.WMI() selected_usb_part = str(disk_drive) oFS = win32com.client.Dispatch("Scripting.FileSystemObject") d = oFS.GetDrive(oFS.GetDriveName(oFS.GetAbsolutePathName(selected_usb_part))) @@ -300,12 +323,18 @@ def win_disk_details(disk_drive): size_total = shutil.disk_usage(mount_point)[0] size_used = shutil.disk_usage(mount_point)[1] size_free = shutil.disk_usage(mount_point)[2] + ''' + # 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. + # Removing the code doesn't affect the functionality as it is only used to find vendor id and model of the drive. + c = wmi.WMI() for physical_disk in c.Win32_DiskDrive(InterfaceType="USB"): for partition in physical_disk.associators("Win32_DiskDriveToDiskPartition"): for logical_disk in partition.associators("Win32_LogicalDiskToPartition"): if logical_disk.Caption == disk_drive: vendor = (physical_disk.PNPDeviceID.split('&VEN_'))[1].split('&PROD_')[0] model = (physical_disk.PNPDeviceID.split('&PROD_'))[1].split('&REV_')[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,