mirror of
https://github.com/mbusb/multibootusb
synced 2024-11-01 15:40:16 +00:00
Pull from master
This commit is contained in:
parent
f6b6d1c0e5
commit
52c66ca7cd
@ -3,6 +3,7 @@ Version - 8.5.0
|
|||||||
* Added Solus OS
|
* Added Solus OS
|
||||||
* Added Ka OS
|
* Added Ka OS
|
||||||
* Added PC Unlocker
|
* Added PC Unlocker
|
||||||
|
* Added Acronis True Image
|
||||||
* Fixed bug - Same drives appearing multiple times under imager tab
|
* Fixed bug - Same drives appearing multiple times under imager tab
|
||||||
* Fixed HBCD boot issue
|
* Fixed HBCD boot issue
|
||||||
* Fix crash when using ISO Imager option to write ISO files (fix by bagage)
|
* Fix crash when using ISO Imager option to write ISO files (fix by bagage)
|
||||||
|
74
MANIFEST
Normal file
74
MANIFEST
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# file GENERATED by distutils, do NOT edit
|
||||||
|
multibootusb
|
||||||
|
multibootusb-pkexec
|
||||||
|
org.debian.pkexec.run-multibootusb.policy
|
||||||
|
setup.py
|
||||||
|
data/multibootusb.desktop
|
||||||
|
data/version.txt
|
||||||
|
data/multibootusb/bg.png
|
||||||
|
data/multibootusb/chain.c32
|
||||||
|
data/multibootusb/extlinux.cfg
|
||||||
|
data/multibootusb/grub.exe
|
||||||
|
data/multibootusb/memdisk
|
||||||
|
data/multibootusb/menu.c32
|
||||||
|
data/multibootusb/menu.lst
|
||||||
|
data/multibootusb/syslinux.cfg
|
||||||
|
data/multibootusb/vesamenu.c32
|
||||||
|
data/tools/mbr.bin
|
||||||
|
data/tools/multibootusb.png
|
||||||
|
data/tools/dd/dd.exe
|
||||||
|
data/tools/dd/diskio.dll
|
||||||
|
data/tools/mkfs/mke2fs.exe
|
||||||
|
data/tools/syslinux/syslinux_linux.zip
|
||||||
|
data/tools/syslinux/syslinux_linux_64.zip
|
||||||
|
data/tools/syslinux/syslinux_modules.zip
|
||||||
|
data/tools/syslinux/syslinux_windows.zip
|
||||||
|
scripts/_7zip.py
|
||||||
|
scripts/__init__.py
|
||||||
|
scripts/admin.py
|
||||||
|
scripts/config.py
|
||||||
|
scripts/distro.py
|
||||||
|
scripts/gen.py
|
||||||
|
scripts/imager.py
|
||||||
|
scripts/install.py
|
||||||
|
scripts/iso.py
|
||||||
|
scripts/isodump3.py
|
||||||
|
scripts/mbusb_cli.py
|
||||||
|
scripts/mbusb_gui.py
|
||||||
|
scripts/persistence.py
|
||||||
|
scripts/qemu.py
|
||||||
|
scripts/syslinux.py
|
||||||
|
scripts/udisks.py
|
||||||
|
scripts/uninstall_distro.py
|
||||||
|
scripts/update_cfg_file.py
|
||||||
|
scripts/usb.py
|
||||||
|
scripts/gui/__init__.py
|
||||||
|
scripts/gui/ui_multibootusb.py
|
||||||
|
scripts/progressbar/__init__.py
|
||||||
|
scripts/progressbar/compat.py
|
||||||
|
scripts/progressbar/progressbar.py
|
||||||
|
scripts/progressbar/widgets.py
|
||||||
|
scripts/pyudev/__init__.py
|
||||||
|
scripts/pyudev/_compat.py
|
||||||
|
scripts/pyudev/_errors.py
|
||||||
|
scripts/pyudev/_qt_base.py
|
||||||
|
scripts/pyudev/_util.py
|
||||||
|
scripts/pyudev/core.py
|
||||||
|
scripts/pyudev/discover.py
|
||||||
|
scripts/pyudev/glib.py
|
||||||
|
scripts/pyudev/monitor.py
|
||||||
|
scripts/pyudev/pyqt4.py
|
||||||
|
scripts/pyudev/pyqt5.py
|
||||||
|
scripts/pyudev/pyside.py
|
||||||
|
scripts/pyudev/version.py
|
||||||
|
scripts/pyudev/wx.py
|
||||||
|
scripts/pyudev/_ctypeslib/__init__.py
|
||||||
|
scripts/pyudev/_ctypeslib/_errorcheckers.py
|
||||||
|
scripts/pyudev/_ctypeslib/libc.py
|
||||||
|
scripts/pyudev/_ctypeslib/libudev.py
|
||||||
|
scripts/pyudev/_ctypeslib/utils.py
|
||||||
|
scripts/pyudev/_os/__init__.py
|
||||||
|
scripts/pyudev/_os/pipe.py
|
||||||
|
scripts/pyudev/_os/poll.py
|
||||||
|
scripts/pyudev/device/__init__.py
|
||||||
|
scripts/pyudev/device/_device.py
|
10
deb_dist/multibootusb-8.5.0/PKG-INFO
Normal file
10
deb_dist/multibootusb-8.5.0/PKG-INFO
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Metadata-Version: 1.0
|
||||||
|
Name: multibootusb
|
||||||
|
Version: 8.5.0
|
||||||
|
Summary: Create multi boot live Linux on a USB disk...
|
||||||
|
Home-page: http://multibootusb.org/
|
||||||
|
Author: Sundar
|
||||||
|
Author-email: feedback.multibootusb@gmail.com
|
||||||
|
License: General Public License (GPL)
|
||||||
|
Description: multibootusb is an advanced cross-platform application for installing/uninstalling Linux operating systems on to a single USB flash drives.
|
||||||
|
Platform: Linux
|
8
deb_dist/multibootusb-8.5.0/data/multibootusb.desktop
Normal file
8
deb_dist/multibootusb-8.5.0/data/multibootusb.desktop
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=multibootusb
|
||||||
|
Comment=Install multiple Linux Operating System on USB
|
||||||
|
Icon=multibootusb
|
||||||
|
Exec=multibootusb-pkexec
|
||||||
|
Categories=System;
|
||||||
|
StartupNotify=true
|
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/bg.png
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/chain.c32
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/chain.c32
Normal file
Binary file not shown.
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/grub.exe
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/grub.exe
Normal file
Binary file not shown.
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/memdisk
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/memdisk
Normal file
Binary file not shown.
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/menu.c32
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/menu.c32
Normal file
Binary file not shown.
1
deb_dist/multibootusb-8.5.0/data/multibootusb/menu.lst
Normal file
1
deb_dist/multibootusb-8.5.0/data/multibootusb/menu.lst
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
35
deb_dist/multibootusb-8.5.0/data/multibootusb/syslinux.cfg
Normal file
35
deb_dist/multibootusb-8.5.0/data/multibootusb/syslinux.cfg
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# This file is created by MultiBootUSB.
|
||||||
|
default vesamenu.c32
|
||||||
|
prompt 0
|
||||||
|
menu title MultiBootUSB
|
||||||
|
MENU BACKGROUND /multibootusb/bg.png
|
||||||
|
TIMEOUT 300
|
||||||
|
MENU WIDTH 80
|
||||||
|
MENU MARGIN 10
|
||||||
|
MENU PASSWORDMARGIN 3
|
||||||
|
MENU ROWS 12
|
||||||
|
MENU TABMSGROW 18
|
||||||
|
MENU CMDLINEROW 18
|
||||||
|
MENU ENDROW -1
|
||||||
|
MENU PASSWORDROW 11
|
||||||
|
MENU TIMEOUTROW 20
|
||||||
|
MENU HELPMSGROW 22
|
||||||
|
MENU HELPMSGENDROW -1
|
||||||
|
MENU HIDDENROW -2
|
||||||
|
MENU HSHIFT 0
|
||||||
|
MENU VSHIFT 0
|
||||||
|
MENU COLOR border 30;44 #40ffffff #a0000000 std
|
||||||
|
MENU COLOR title 1;36;44 #9033ccff #a0000000 std
|
||||||
|
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
|
||||||
|
MENU COLOR unsel 37;44 #50ffffff #a0000000 std
|
||||||
|
MENU COLOR help 37;40 #c0ffffff #a0000000 std
|
||||||
|
MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
|
||||||
|
MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
|
||||||
|
MENU COLOR msg07 37;40 #90ffffff #a0000000 std
|
||||||
|
MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
|
||||||
|
label Boot from Hard Drive
|
||||||
|
MENU LABEL Boot from Hard Disk
|
||||||
|
KERNEL chain.c32
|
||||||
|
APPEND hd1
|
||||||
|
MENU DEFAULT
|
||||||
|
|
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/vesamenu.c32
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/multibootusb/vesamenu.c32
Normal file
Binary file not shown.
BIN
deb_dist/multibootusb-8.5.0/data/tools/dd/dd.exe
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/tools/dd/dd.exe
Normal file
Binary file not shown.
BIN
deb_dist/multibootusb-8.5.0/data/tools/dd/diskio.dll
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/tools/dd/diskio.dll
Normal file
Binary file not shown.
BIN
deb_dist/multibootusb-8.5.0/data/tools/mbr.bin
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/tools/mbr.bin
Normal file
Binary file not shown.
BIN
deb_dist/multibootusb-8.5.0/data/tools/mkfs/mke2fs.exe
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/tools/mkfs/mke2fs.exe
Normal file
Binary file not shown.
BIN
deb_dist/multibootusb-8.5.0/data/tools/multibootusb.png
Normal file
BIN
deb_dist/multibootusb-8.5.0/data/tools/multibootusb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
deb_dist/multibootusb-8.5.0/data/version.txt
Normal file
1
deb_dist/multibootusb-8.5.0/data/version.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
8.5.0
|
5
deb_dist/multibootusb-8.5.0/debian/changelog
Normal file
5
deb_dist/multibootusb-8.5.0/debian/changelog
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
multibootusb (8.5.0-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* source package automatically created by stdeb 0.8.2
|
||||||
|
|
||||||
|
-- Sundar <feedback.multibootusb@gmail.com> Sun, 05 Feb 2017 15:32:06 +0530
|
1
deb_dist/multibootusb-8.5.0/debian/compat
Normal file
1
deb_dist/multibootusb-8.5.0/debian/compat
Normal file
@ -0,0 +1 @@
|
|||||||
|
9
|
14
deb_dist/multibootusb-8.5.0/debian/control
Normal file
14
deb_dist/multibootusb-8.5.0/debian/control
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Source: multibootusb
|
||||||
|
Maintainer: Sundar <feedback.multibootusb@gmail.com>
|
||||||
|
Section: system
|
||||||
|
Priority: optional
|
||||||
|
Build-Depends: python3-all, debhelper (>= 9), python3-all
|
||||||
|
Standards-Version: 3.9.1
|
||||||
|
X-Python-Version: = 3.5
|
||||||
|
|
||||||
|
Package: python3-multibootusb
|
||||||
|
Architecture: all
|
||||||
|
Depends: ${misc:Depends}, ${python3:Depends}, python3-pyqt5, parted, util-linux, mtools, python3-dbus, p7zip-full, python3-six
|
||||||
|
Description: Create multi boot live Linux on a USB disk...
|
||||||
|
multibootusb is an advanced cross-platform application for installing/uninstalling Linux operating systems on to a single USB flash drives.
|
||||||
|
|
8
deb_dist/multibootusb-8.5.0/debian/rules
Normal file
8
deb_dist/multibootusb-8.5.0/debian/rules
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
# This file was automatically generated by stdeb 0.8.2 at
|
||||||
|
# Sun, 05 Feb 2017 15:32:06 +0530
|
||||||
|
export PYBUILD_NAME=multibootusb
|
||||||
|
%:
|
||||||
|
dh $@ --with python3 --buildsystem=pybuild
|
||||||
|
|
1
deb_dist/multibootusb-8.5.0/debian/source/format
Normal file
1
deb_dist/multibootusb-8.5.0/debian/source/format
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.0 (quilt)
|
105
deb_dist/multibootusb-8.5.0/multibootusb
Normal file
105
deb_dist/multibootusb-8.5.0/multibootusb
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: multibootusb
|
||||||
|
# Purpose: Main file which will determine if cli or gui is to be opened
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import getopt
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
|
||||||
|
# Had trouble in importing scripts directory. Had to add few lines below to ensure it works on source as well as
|
||||||
|
# post install
|
||||||
|
try:
|
||||||
|
from scripts.mbusb_cli import *
|
||||||
|
from scripts import admin
|
||||||
|
from scripts import gen
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
from .scripts.mbusb_cli import *
|
||||||
|
from .scripts import admin
|
||||||
|
from .scripts import gen
|
||||||
|
except:
|
||||||
|
import scripts
|
||||||
|
|
||||||
|
gui = True
|
||||||
|
iso_link = None
|
||||||
|
usb_disk = None
|
||||||
|
uninstall = False
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print('\nAn advanced multi boot live usb creator using command line.')
|
||||||
|
print('\nUsage: python3 multibootusb -c -i /path/to/iso [option(s)] -t /path/to/device\n')
|
||||||
|
print('[option(s)] are :\n')
|
||||||
|
print(' -h or --help : Print this help message and exit')
|
||||||
|
print(' -i or --iso : Path to ISO file')
|
||||||
|
print(' -t or --target : Path to target USB device partition (example /dev/sdb1)\n')
|
||||||
|
print(' -c or --command : This option is must for invoking multibootusb from command line\n')
|
||||||
|
print(' -u or --uninstall : List and uninstall distro from USB disk')
|
||||||
|
print(' Command line example for making a bootable USB from command line should look like this:-\n')
|
||||||
|
print(' python3 multibootusb -c -i ../../favourite.iso -t /dev/sdb1\n')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
|
||||||
|
def start_gui():
|
||||||
|
from scripts import mbusb_gui
|
||||||
|
gen.log('Starting multibootusb GUI...')
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
if os.getuid() != 0:
|
||||||
|
gen.log('\n\nAdmin 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)\n\n',
|
||||||
|
info=False, debug=True)
|
||||||
|
mbusb_gui.main_gui()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
if not admin.isUserAdmin():
|
||||||
|
admin.runAsAdmin()
|
||||||
|
sys.exit(0)
|
||||||
|
try:
|
||||||
|
opts, args = getopt.getopt(sys.argv[1:], 'i:t:vhcu',
|
||||||
|
['iso=', 'target=', 'version', 'help', 'command', 'uninstall'])
|
||||||
|
except getopt.GetoptError:
|
||||||
|
usage()
|
||||||
|
sys.exit(2)
|
||||||
|
for opt, arg in opts:
|
||||||
|
if opt in ('-h', '--help'):
|
||||||
|
usage()
|
||||||
|
sys.exit(2)
|
||||||
|
elif opt in ('-v', '--version'):
|
||||||
|
print_version()
|
||||||
|
sys.exit()
|
||||||
|
elif opt in ('-i', '--iso'):
|
||||||
|
config.iso_link = arg
|
||||||
|
elif opt in ('-t', '--target'):
|
||||||
|
config.usb_disk = arg
|
||||||
|
elif opt in ('-c', '--command'):
|
||||||
|
gui = False
|
||||||
|
elif opt in ('-u', '--uninstall'):
|
||||||
|
uninstall = True
|
||||||
|
else:
|
||||||
|
gui = True
|
||||||
|
#start_gui()
|
||||||
|
'''
|
||||||
|
usage()
|
||||||
|
sys.exit()
|
||||||
|
'''
|
||||||
|
|
||||||
|
if gui is False:
|
||||||
|
if uninstall is True and config.usb_disk is not None:
|
||||||
|
cli_uninstall_distro()
|
||||||
|
elif config.iso_link is None and config.usb_disk is None:
|
||||||
|
usage()
|
||||||
|
elif config.iso_link is None or config.usb_disk is None:
|
||||||
|
print('\nOptions \'-i\' and \'t\' must be supplied together. See the usage below.')
|
||||||
|
usage()
|
||||||
|
else:
|
||||||
|
cli_install_distro()
|
||||||
|
|
||||||
|
elif gui is True:
|
||||||
|
start_gui()
|
6
deb_dist/multibootusb-8.5.0/multibootusb-pkexec
Normal file
6
deb_dist/multibootusb-8.5.0/multibootusb-pkexec
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [ $(which pkexec) ]; then
|
||||||
|
pkexec --disable-internal-agent "/usr/bin/multibootusb" "$@"
|
||||||
|
else
|
||||||
|
/usr/bin/multibootusb "$@"
|
||||||
|
fi
|
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE policyconfig PUBLIC
|
||||||
|
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
|
||||||
|
<policyconfig>
|
||||||
|
|
||||||
|
<action id="org.debian.pkexec.run-multibootusb">
|
||||||
|
<description>Run the multibootusb program</description>
|
||||||
|
<message>Authentication is required to run the multibootusb</message>
|
||||||
|
<defaults>
|
||||||
|
<allow_any>auth_admin</allow_any>
|
||||||
|
<allow_inactive>auth_admin</allow_inactive>
|
||||||
|
<allow_active>auth_admin</allow_active>
|
||||||
|
</defaults>
|
||||||
|
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/multibootusb</annotate>
|
||||||
|
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
|
||||||
|
</action>
|
||||||
|
|
||||||
|
</policyconfig>
|
130
deb_dist/multibootusb-8.5.0/scripts/_7zip.py
Normal file
130
deb_dist/multibootusb-8.5.0/scripts/_7zip.py
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: 7zip.py
|
||||||
|
# Purpose: Wrapper module to list and extract ISO files using 7zip
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import subprocess
|
||||||
|
from . import config
|
||||||
|
from . import gen
|
||||||
|
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
_7zip = gen.quote(gen.resource_path(os.path.join('data', 'tools', '7zip', '7z.exe')))
|
||||||
|
else:
|
||||||
|
_7zip = '7z'
|
||||||
|
|
||||||
|
|
||||||
|
def extract_iso(src, dst, pattern=None, suppress_out=True):
|
||||||
|
"""
|
||||||
|
Simple wrapper function to extract ISO file to destination
|
||||||
|
:param src: Path to ISO file
|
||||||
|
:param dst: Path to directory where the files are to be extracted
|
||||||
|
:param patter: The pattern to match the files to be extracted
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# 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).
|
||||||
|
if suppress_out != '':
|
||||||
|
# suppress_out = ' 2> nul'
|
||||||
|
suppress_out = ''
|
||||||
|
else:
|
||||||
|
cli_option = ''
|
||||||
|
if suppress_out != '':
|
||||||
|
suppress_out = ' 2> /dev/null'
|
||||||
|
|
||||||
|
if not os.path.exists(src):
|
||||||
|
gen.log('ISO file could not be found on the location specified.')
|
||||||
|
return False
|
||||||
|
if not os.path.exists(dst):
|
||||||
|
os.makedirs(dst, exist_ok=True)
|
||||||
|
|
||||||
|
if pattern is None:
|
||||||
|
_cmd = _7zip + cli_option + ' x -y -o' + gen.quote(dst) + ' ' + gen.quote(src) + suppress_out
|
||||||
|
else:
|
||||||
|
_cmd = _7zip + ' -y x ' + gen.quote(src) + ' -o' + dst + ' ' + gen.quote(pattern) + ' -r' + suppress_out
|
||||||
|
# gen.log('Executing', _cmd)
|
||||||
|
_7zip_process = subprocess.Popen(_cmd, universal_newlines=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE, shell=True)
|
||||||
|
config.status_text = 'Extracting ' + os.path.basename(src)
|
||||||
|
while True:
|
||||||
|
line = _7zip_process.stdout.readline()
|
||||||
|
# gen.log(line)
|
||||||
|
if line.startswith('- '):
|
||||||
|
config.status_text = 'Extracting ' + line[2:]
|
||||||
|
elif platform.system() == 'Linux': # line.startswith('Extracting'): # Under Linux it prints directly all the process (may be due to version diff).
|
||||||
|
config.status_text = line
|
||||||
|
if line == '' and _7zip_process.poll() != None:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def list_iso(iso_link, suppress_out=True):
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
if suppress_out is True:
|
||||||
|
suppress_out = ' 2> nul'
|
||||||
|
else:
|
||||||
|
if suppress_out is True:
|
||||||
|
suppress_out = ' 2> /dev/null'
|
||||||
|
if not os.path.exists(iso_link):
|
||||||
|
gen.log('Path to ISO link does not exist.')
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
file_list = []
|
||||||
|
_cmd = _7zip + ' l ' + gen.quote(iso_link) + suppress_out
|
||||||
|
# gen.log('Executing', _cmd)
|
||||||
|
_cmd_out = subprocess.check_output(_cmd, universal_newlines=True, stderr=subprocess.PIPE, shell=True).splitlines()
|
||||||
|
for line in _cmd_out:
|
||||||
|
line = line.split()
|
||||||
|
if '.....' in line:
|
||||||
|
file_list.append(line[-1])
|
||||||
|
|
||||||
|
return file_list
|
||||||
|
|
||||||
|
|
||||||
|
def test_iso(iso_link, suppress_out=True):
|
||||||
|
"""
|
||||||
|
Function to test if ISO file is corrupted. Relying only on 7zip.
|
||||||
|
:param iso_link: Path to ISO file
|
||||||
|
:return: True if test is positive
|
||||||
|
"""
|
||||||
|
# 7z t /path/to/iso/file.iso
|
||||||
|
# return value : 0 No error
|
||||||
|
# return value : 1 Warning (Non fatal error(s))
|
||||||
|
# return value : 2 Fatal error
|
||||||
|
# return value : 7 Command line error
|
||||||
|
# return value : 8 Not enough memory for operation
|
||||||
|
# return value : 255 User stopped the process
|
||||||
|
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
if suppress_out is True:
|
||||||
|
suppress_out = ' > nul'
|
||||||
|
else:
|
||||||
|
if suppress_out is True:
|
||||||
|
suppress_out = ' > /dev/null'
|
||||||
|
|
||||||
|
_cmd = _7zip + ' t ' + iso_link + suppress_out
|
||||||
|
|
||||||
|
# gen.log('Executing', _cmd)
|
||||||
|
|
||||||
|
rc = subprocess.call(_cmd, shell=True)
|
||||||
|
|
||||||
|
if rc == 0 or rc == 1:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# slitaz-4.0.iso
|
||||||
|
# ubuntu-16.04-desktop-amd64.iso
|
||||||
|
# avg_arl_cdi_all_120_160420a12074.iso
|
||||||
|
# haiku-nightly.iso
|
||||||
|
# Hiren_BootCD.iso
|
||||||
|
file_list = list_iso('../../ubuntu_14_04_backup/Downloads/clonezilla-live-2.4.2-32-amd64.iso')
|
||||||
|
for f in file_list:
|
||||||
|
print(f)
|
10
deb_dist/multibootusb-8.5.0/scripts/__init__.py
Normal file
10
deb_dist/multibootusb-8.5.0/scripts/__init__.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Author(s) information
|
||||||
|
__authors__ = ['Sundar']
|
||||||
|
__author__ = ','.join(__authors__)
|
||||||
|
__credits__ = ['Ian Bruce', 'Lee']
|
||||||
|
__copyright__ = 'Copyright (c) 2014'
|
||||||
|
__license__ = 'GPL'
|
||||||
|
|
||||||
|
# Maintanence information
|
||||||
|
__maintainer__ = 'Sundar'
|
||||||
|
__email__ = 'feedback.multibootusb@gmail.com'
|
167
deb_dist/multibootusb-8.5.0/scripts/admin.py
Normal file
167
deb_dist/multibootusb-8.5.0/scripts/admin.py
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8; mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
|
||||||
|
# vim: fileencoding=utf-8 tabstop=4 expandtab shiftwidth=4
|
||||||
|
# Name: admin.py
|
||||||
|
# Purpose: Module to ask for admin rights under Linux and Windows
|
||||||
|
# Authors: Originally developed by Preston Landers (for windows) and modified for multibootusb by Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of the same license as Python 2.6.5
|
||||||
|
|
||||||
|
##
|
||||||
|
## (C) COPYRIGHT © Preston Landers 2010
|
||||||
|
## Released under the same license as Python 2.6.5
|
||||||
|
##
|
||||||
|
|
||||||
|
"""
|
||||||
|
User Access Control for Microsoft Windows Vista and higher. This is
|
||||||
|
only for the Windows platform.
|
||||||
|
|
||||||
|
This will relaunch either the current script - with all the same command
|
||||||
|
line parameters - or else you can provide a different script/program to
|
||||||
|
run. If the current user doesn't normally have admin rights, he'll be
|
||||||
|
prompted for an admin password. Otherwise he just gets the UAC prompt.
|
||||||
|
|
||||||
|
This is meant to be used something like this::
|
||||||
|
|
||||||
|
if not pyuac.isUserAdmin():
|
||||||
|
return pyuac.runAsAdmin()
|
||||||
|
|
||||||
|
# otherwise carry on doing whatever...
|
||||||
|
|
||||||
|
See L{runAsAdmin} for the main interface.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
import types
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
from . import gen
|
||||||
|
|
||||||
|
|
||||||
|
def isUserAdmin():
|
||||||
|
"""
|
||||||
|
@return: True if the current user is an 'Admin' whatever that means
|
||||||
|
(root on Unix), otherwise False.
|
||||||
|
|
||||||
|
Warning: The inner function fails unless you have Windows XP SP2 or
|
||||||
|
higher. The failure causes a traceback to be gen.loged and this
|
||||||
|
function to return False.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
import ctypes
|
||||||
|
# WARNING: requires Windows XP SP2 or higher!
|
||||||
|
try:
|
||||||
|
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
gen.log("Admin check failed, assuming not an admin.")
|
||||||
|
return False
|
||||||
|
elif platform.system() == "Linux":
|
||||||
|
return os.getuid() == 0
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Unsupported operating system for this module: %s" % (os.name,))
|
||||||
|
|
||||||
|
|
||||||
|
def runAsAdmin(cmdLine=None, wait=True):
|
||||||
|
"""
|
||||||
|
Attempt to relaunch the current script as an admin using the same
|
||||||
|
command line parameters. Pass cmdLine in to override and set a new
|
||||||
|
command. It must be a list of [command, arg1, arg2...] format.
|
||||||
|
|
||||||
|
Set wait to False to avoid waiting for the sub-process to finish. You
|
||||||
|
will not be able to fetch the exit code of the process if wait is
|
||||||
|
False.
|
||||||
|
|
||||||
|
Returns the sub-process return code, unless wait is False in which
|
||||||
|
case it returns None.
|
||||||
|
|
||||||
|
@WARNING: this function only works on Windows.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#if os.name == 'nt':
|
||||||
|
# raise RuntimeError, "This function is only implemented on Windows."
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
|
||||||
|
import win32api, win32con, win32event, win32process
|
||||||
|
from win32com.shell.shell import ShellExecuteEx
|
||||||
|
from win32com.shell import shellcon
|
||||||
|
|
||||||
|
python_exe = sys.executable
|
||||||
|
|
||||||
|
if cmdLine is None:
|
||||||
|
cmdLine = [python_exe] + sys.argv
|
||||||
|
elif type(cmdLine) not in (types.TupleType, types.ListType):
|
||||||
|
raise ValueError("cmdLine is not a sequence.")
|
||||||
|
cmd = '"%s"' % (cmdLine[0],)
|
||||||
|
# XXX TODO: isn't there a function or something we can call to massage command line params?
|
||||||
|
params = " ".join(['"%s"' % (x,) for x in cmdLine[1:]])
|
||||||
|
cmdDir = ''
|
||||||
|
showCmd = win32con.SW_SHOWNORMAL
|
||||||
|
#showCmd = win32con.SW_HIDE
|
||||||
|
lpVerb = 'runas' # causes UAC elevation prompt.
|
||||||
|
|
||||||
|
#gen.log("Running", cmd, params)
|
||||||
|
|
||||||
|
# ShellExecute() doesn't seem to allow us to fetch the PID or handle
|
||||||
|
# of the process, so we can't get anything useful from it. Therefore
|
||||||
|
# the more complex ShellExecuteEx() must be used.
|
||||||
|
|
||||||
|
# procHandle = win32api.ShellExecute(0, lpVerb, cmd, params, cmdDir, showCmd)
|
||||||
|
|
||||||
|
procInfo = ShellExecuteEx(nShow=showCmd,
|
||||||
|
fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
|
||||||
|
lpVerb=lpVerb,
|
||||||
|
lpFile=cmd,
|
||||||
|
lpParameters=params)
|
||||||
|
|
||||||
|
if wait:
|
||||||
|
procHandle = procInfo['hProcess']
|
||||||
|
obj = win32event.WaitForSingleObject(procHandle, win32event.INFINITE)
|
||||||
|
rc = win32process.GetExitCodeProcess(procHandle)
|
||||||
|
#gen.log "Process handle %s returned code %s" % (procHandle, rc)
|
||||||
|
else:
|
||||||
|
rc = None
|
||||||
|
|
||||||
|
return rc
|
||||||
|
|
||||||
|
|
||||||
|
def adminCmd(cmd, fork=False, gui=False):
|
||||||
|
"""
|
||||||
|
This simple function checks for a sudo command and runs a command using it.
|
||||||
|
This function tries to launch given script with root access using pkexec/gksu/gksudo/kdesu/kdesudo,
|
||||||
|
if one of them is already installed.
|
||||||
|
PyQt4 is used as GUI.
|
||||||
|
Author : sundar
|
||||||
|
"""
|
||||||
|
sudo_cmd = ''
|
||||||
|
if os.getuid() == 0:
|
||||||
|
sudo_cmd = cmd
|
||||||
|
else:
|
||||||
|
if os.system('which pkexec') == 0:
|
||||||
|
if gui:
|
||||||
|
cmd = ['export DISPLAY=$DISPLAY; export XAUTHORITY=$XAUTHORITY; '] + cmd # By default, pkexec disallows X11 apps. Restore DISPLAY & XAUTHORITY to allow it. man 1 pkexec/"SECURITY NOTES" section
|
||||||
|
sudo_cmd = ['pkexec', '/bin/sh', '-c']
|
||||||
|
elif os.system('which gksudo') == 0:
|
||||||
|
sudo_cmd = ["gksudo", "--", "/bin/sh", "-c"]
|
||||||
|
elif os.system('which gksu') == 0:
|
||||||
|
sudo_cmd = ["gksu"]
|
||||||
|
elif os.system('which kdesudo') == 0:
|
||||||
|
sudo_cmd = ["kdesudo", "-t", "-c"] # http://www.unix.com/man-page/debian/1/kdesudo/
|
||||||
|
elif os.system('which kdesu') == 0:
|
||||||
|
sudo_cmd = ["kdesu", "-t", "-c"] # http://linux.die.net/man/1/kdesu
|
||||||
|
else:
|
||||||
|
QtWidgets.QMessageBox.information('No root...',
|
||||||
|
'Could not find any of: pkexec, sudo, gksu, kdesu, gksudo, or kdesudo. Please install one then restart multibootusb.')
|
||||||
|
sys.exit(0)
|
||||||
|
final_cmd = ' '.join(sudo_cmd + ['"' + ' '.join(cmd).replace('"', '\\"') + '"'])
|
||||||
|
gen.log("Executing ==> " + final_cmd)
|
||||||
|
if fork:
|
||||||
|
return subprocess.Popen(final_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1, shell=True)
|
||||||
|
else:
|
||||||
|
ret = subprocess.call(final_cmd, shell=True)
|
||||||
|
gen.log("Process returned ==> " + str(ret))
|
||||||
|
return ret
|
36
deb_dist/multibootusb-8.5.0/scripts/config.py
Normal file
36
deb_dist/multibootusb-8.5.0/scripts/config.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Name: config.py
|
||||||
|
# Purpose: Module to share important variables between various modules. Mainly included so as not to call many
|
||||||
|
# functions again and again
|
||||||
|
# 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
|
||||||
|
|
||||||
|
iso_link = ""
|
||||||
|
usb_disk = ""
|
||||||
|
usb_mount = ""
|
||||||
|
usb_uuid = ""
|
||||||
|
usb_label = ""
|
||||||
|
persistence = 0
|
||||||
|
distro = ""
|
||||||
|
status_text = ""
|
||||||
|
percentage = 0
|
||||||
|
syslinux_version = ''
|
||||||
|
uninstall_distro_dir_name = ""
|
||||||
|
uninstall_distro_dir_path = ""
|
||||||
|
iso_file_list = ''
|
||||||
|
|
||||||
|
process_exist = None
|
||||||
|
|
||||||
|
imager_iso_link = ""
|
||||||
|
imager_usb_disk_selected = ""
|
||||||
|
imager_lock = ""
|
||||||
|
imager_percentage = ""
|
||||||
|
imager_status_text = ""
|
||||||
|
|
||||||
|
install_size = ""
|
||||||
|
|
||||||
|
editors_linux = ["gedit", "kate", "kwrite"]
|
||||||
|
editors_win = ["notepad++.exe", "notepad.exe"]
|
||||||
|
|
||||||
|
imager_usb_disk = []
|
176
deb_dist/multibootusb-8.5.0/scripts/distro.py
Normal file
176
deb_dist/multibootusb-8.5.0/scripts/distro.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: distro.py
|
||||||
|
# Purpose: Module to detect if distro types supported by multibootusb (by extracting specific files)
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import string
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
from .iso import *
|
||||||
|
from .isodump3 import ISO9660
|
||||||
|
from .gen import *
|
||||||
|
from . import _7zip
|
||||||
|
from . import config
|
||||||
|
|
||||||
|
|
||||||
|
def distro(iso_cfg_ext_dir, iso_link):
|
||||||
|
"""
|
||||||
|
Detect if distro is supported by multibootusb.
|
||||||
|
:param iso_cfg_ext_dir: Directory where *.cfg files are extracted.
|
||||||
|
:return: Detected distro name as string.
|
||||||
|
"""
|
||||||
|
iso9660fs = ISO9660(iso_link)
|
||||||
|
# iso_file_list = iso9660fs.readDir("/")
|
||||||
|
iso_file_list = _7zip.list_iso(iso_link)
|
||||||
|
if platform.system() == "Linux" or platform.system() == "Windows":
|
||||||
|
for path, subdirs, files in os.walk(iso_cfg_ext_dir):
|
||||||
|
for name in files:
|
||||||
|
if name.endswith('.cfg') or name.endswith('.CFG') or name.endswith('.txt') or name.endswith('.TXT') \
|
||||||
|
or name.endswith('.lst'):
|
||||||
|
try:
|
||||||
|
# errors='ignore' is required as some files also contain non utf character
|
||||||
|
string = open(os.path.join(path, name), errors='ignore').read()
|
||||||
|
except IOError:
|
||||||
|
return "Read Error."
|
||||||
|
else:
|
||||||
|
if any("f4ubcd" in s.lower() for s in iso_file_list):
|
||||||
|
return "f4ubcd"
|
||||||
|
if re.search(r'ubcd', string, re.I):
|
||||||
|
return "ubcd"
|
||||||
|
elif re.search(r'Super Grub Disk', string, re.I):
|
||||||
|
return "sgrubd2"
|
||||||
|
elif re.search(r'hbcd', string, re.I):
|
||||||
|
return "hbcd"
|
||||||
|
elif re.search(r'systemrescuecd', string, re.I):
|
||||||
|
return "systemrescuecd"
|
||||||
|
elif re.search(r'pmagic|partedmagic', string, re.I) and isolinux_bin_exist(iso_link):
|
||||||
|
return "parted-magic"
|
||||||
|
elif re.search(r'mgalive', string, re.I): # mounting fat filesystem hard coded in to initrd.
|
||||||
|
# Can be modified only under linux.
|
||||||
|
return "mageialive"
|
||||||
|
elif re.search(r'archisolabel|misolabel', string, re.I):
|
||||||
|
return "arch"
|
||||||
|
elif re.search(r'chakraisolabel', string, re.I):
|
||||||
|
return "chakra"
|
||||||
|
elif re.search(r'kdeosisolabel', string, re.I):
|
||||||
|
return "kaos"
|
||||||
|
elif re.search(r'boot=live', string, re.I) and isolinux_bin_exist(iso_link):
|
||||||
|
return "debian"
|
||||||
|
elif re.search(r'debian-installer', string, re.I) and isolinux_bin_exist(iso_link):
|
||||||
|
return "debian-install"
|
||||||
|
elif re.search(r'solydx', string, re.I):
|
||||||
|
return "solydx"
|
||||||
|
elif re.search(r'knoppix', string, re.I):
|
||||||
|
return "knoppix"
|
||||||
|
elif re.search(r'root=live:CDLABEL=', string, re.I):
|
||||||
|
return "fedora"
|
||||||
|
elif re.search(r'redhat', string, re.I):
|
||||||
|
return "redhat"
|
||||||
|
# elif re.search(r'suse', string, re.I):
|
||||||
|
# return "suse"
|
||||||
|
elif re.search(r'opensuse', string, re.I):
|
||||||
|
return "opensuse"
|
||||||
|
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', string, re.I):
|
||||||
|
return "slitaz"
|
||||||
|
elif re.search(r'boot=casper', string, re.I):
|
||||||
|
return "ubuntu"
|
||||||
|
elif re.search(r'wifislax', string, re.I):
|
||||||
|
return "wifislax"
|
||||||
|
elif re.search(r'slax', string, re.I):
|
||||||
|
return "slax"
|
||||||
|
elif re.search(r'sms|vector|autoexec', string, re.I) and isolinux_bin_exist(iso_link):
|
||||||
|
return "sms"
|
||||||
|
elif re.search(r'antix', string, re.I):
|
||||||
|
return "antix"
|
||||||
|
elif re.search(r'porteus', string, re.I):
|
||||||
|
return "porteus"
|
||||||
|
elif re.search(r'livecd=livecd|PCLinuxOS', string, re.I):
|
||||||
|
return "pclinuxos"
|
||||||
|
elif re.search(r'looptype=squashfs', string, re.I):
|
||||||
|
return "gentoo"
|
||||||
|
elif re.search(r'finnix', string, re.I):
|
||||||
|
return "finnix"
|
||||||
|
elif re.search(r'wifiway', string, re.I):
|
||||||
|
return "wifiway"
|
||||||
|
elif re.search(r'puppy|quirky', string, re.I):
|
||||||
|
return "puppy"
|
||||||
|
elif re.search(r'ipcop', string, re.I):
|
||||||
|
return "ipcop"
|
||||||
|
elif re.search(r'ipfire', string, re.I):
|
||||||
|
return "ipfire"
|
||||||
|
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):
|
||||||
|
return "zenwalk"
|
||||||
|
elif re.search(r'ubuntu server', string, re.I):
|
||||||
|
return "ubuntu-server"
|
||||||
|
elif re.search(r'Welcome to CentOS', string, re.I):
|
||||||
|
return "centos-net-minimal"
|
||||||
|
elif re.search(r'Trinity Rescue Kit', string, re.I):
|
||||||
|
return "trinity-rescue"
|
||||||
|
elif re.search(r'alpine', string, re.I):
|
||||||
|
return "alpine"
|
||||||
|
elif re.search(r'http://support.kaspersky.com', string, re.I):
|
||||||
|
return "kaspersky"
|
||||||
|
elif re.search(r'ALT Linux', string, re.I):
|
||||||
|
return "alt-linux"
|
||||||
|
elif re.search(r'Sergei Strelec', string, re.I):
|
||||||
|
return "Windows"
|
||||||
|
elif re.search(r'ReactOS', string, re.I):
|
||||||
|
return "ReactOS"
|
||||||
|
elif re.search(r'fsecure', string, re.I):
|
||||||
|
return "fsecure"
|
||||||
|
elif re.search(r'default rwp', string, re.I):
|
||||||
|
return "pc-unlocker"
|
||||||
|
|
||||||
|
|
||||||
|
distro = detect_iso_from_file_list(iso_link)
|
||||||
|
if distro:
|
||||||
|
return distro
|
||||||
|
# FIXME: See the below comments.
|
||||||
|
'''
|
||||||
|
else:
|
||||||
|
# FIXME: The idea of detecting as generic is to work like a unetbootin if other methods fails.
|
||||||
|
# This simply extracts distro to root of the USB and install syslinux on isolinux.bin directory.
|
||||||
|
# All works fine but unable to boot the distro successfully. Also, see the generic section from
|
||||||
|
# syslinux, update_cfg and install_distro modules.
|
||||||
|
if self.isolinux_bin_exist():
|
||||||
|
return "generic"
|
||||||
|
'''
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def detect_iso_from_file_list(iso_link):
|
||||||
|
"""
|
||||||
|
Fallback detection script from the content of an ISO.
|
||||||
|
:return: supported distro as string
|
||||||
|
"""
|
||||||
|
if os.path.exists(iso_link):
|
||||||
|
iso_file_list = _7zip.list_iso(iso_link)
|
||||||
|
if any("sources" in s.lower() for s in iso_file_list) and any("boot.wim" in s.lower() for s in iso_file_list):
|
||||||
|
return "Windows"
|
||||||
|
elif any("config.isoclient" in s.lower() for s in iso_file_list):
|
||||||
|
return "opensuse"
|
||||||
|
elif any("dban" in s.lower() for s in iso_file_list):
|
||||||
|
return "slitaz"
|
||||||
|
elif any("memtest.img" in s.lower() for s in iso_file_list):
|
||||||
|
return "mentest"
|
||||||
|
elif any("menu.lst" in s.lower() for s in iso_file_list):
|
||||||
|
return "grub4dos"
|
||||||
|
elif any("bootwiz.cfg" in s.lower() for s in iso_file_list) and any("bootmenu_logo.png" in s.lower() for s in iso_file_list):
|
||||||
|
return "grub4dos_iso"
|
||||||
|
else:
|
||||||
|
log(iso_file_list)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
iso_cfg_ext_dir = os.path.join(multibootusb_host_dir(), "iso_cfg_ext_dir")
|
||||||
|
iso_link = 'Downloads/clonezilla-live-2.4.2-32-amd64.iso'
|
||||||
|
iso_extract_file(iso_link, iso_cfg_ext_dir, 'cfg')
|
||||||
|
log(distro(iso_cfg_ext_dir))
|
320
deb_dist/multibootusb-8.5.0/scripts/gen.py
Normal file
320
deb_dist/multibootusb-8.5.0/scripts/gen.py
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*
|
||||||
|
# Name: log.py
|
||||||
|
# Purpose: This 'general' module contain many functions required to be called at many places
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import shutil
|
||||||
|
import string
|
||||||
|
import zipfile
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
|
def scripts_dir_path():
|
||||||
|
return os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
def log(message, info=True, error=False, debug=False):
|
||||||
|
"""
|
||||||
|
Dirty function to log messages to file and also print on screen.
|
||||||
|
:param message:
|
||||||
|
:param info:
|
||||||
|
:param error:
|
||||||
|
:param debug:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# LOG_FILE_PATH = os.path.join(multibootusb_host_dir(), 'multibootusb.log')
|
||||||
|
LOG_FILE_PATH = mbusb_log_file()
|
||||||
|
if os.path.exists(LOG_FILE_PATH):
|
||||||
|
log_file_size = os.path.getsize(LOG_FILE_PATH) / (1024.0 * 1024.0)
|
||||||
|
if log_file_size > 1:
|
||||||
|
print('Removing log file as it crosses beyond 1mb')
|
||||||
|
os.remove(LOG_FILE_PATH)
|
||||||
|
logging.basicConfig(filename=LOG_FILE_PATH,
|
||||||
|
filemode='a',
|
||||||
|
format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
|
||||||
|
datefmt='%H:%M:%S',
|
||||||
|
level=logging.DEBUG)
|
||||||
|
print(message)
|
||||||
|
if info is True:
|
||||||
|
logging.info(message)
|
||||||
|
elif error is not False:
|
||||||
|
logging.error(message)
|
||||||
|
elif debug is not False:
|
||||||
|
logging.debug(message)
|
||||||
|
|
||||||
|
def resource_path(relativePath):
|
||||||
|
"""
|
||||||
|
Function to detect the correct path of file when working with sourcecode/install or binary.
|
||||||
|
:param relativePath: Path to file/data.
|
||||||
|
:return: Modified path to file/data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
basePath = sys._MEIPASS # Try if we are running as standalone executable
|
||||||
|
# log('Running stand alone executable.')
|
||||||
|
except:
|
||||||
|
basePath = '/usr/share/multibootusb' # Check if we run in installed environment
|
||||||
|
#if os.path.exists('/usr/share/multibootusb'):
|
||||||
|
#log('Running from installed machine.')
|
||||||
|
if not os.path.exists(basePath):
|
||||||
|
#basePath = os.path.abspath(".")
|
||||||
|
basePath = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(basePath, relativePath)):
|
||||||
|
path = os.path.join(basePath, relativePath)
|
||||||
|
return path
|
||||||
|
elif not os.path.exists(os.path.join(basePath, relativePath)):
|
||||||
|
if os.path.exists(os.path.join(os.path.abspath("."), relativePath)):
|
||||||
|
basePath = os.path.abspath(".")
|
||||||
|
elif os.path.exists(os.path.join(os.path.abspath(".."), relativePath)):
|
||||||
|
basePath = os.path.abspath("..")
|
||||||
|
path = os.path.join(basePath, relativePath)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def print_version():
|
||||||
|
"""
|
||||||
|
Simple log the version number of the multibootusb application
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
log('multibootusb version : ', mbusb_version())
|
||||||
|
|
||||||
|
|
||||||
|
def quote(text):
|
||||||
|
"""
|
||||||
|
Function to quote the input word or sentence.
|
||||||
|
:param text: Any word or sentence.
|
||||||
|
:return: Quoted text or sentence. If already quoted the same text is returned.
|
||||||
|
"""
|
||||||
|
if not is_quoted(text):
|
||||||
|
return '"' + text + '"'
|
||||||
|
else:
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def is_quoted(text):
|
||||||
|
"""
|
||||||
|
Function to check if word is quoted.
|
||||||
|
:param text: Any word or sentence with or without quote.
|
||||||
|
:return: True if text is quoted else False.
|
||||||
|
"""
|
||||||
|
if text.startswith("""") and text.endswith("""):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def has_digit(word):
|
||||||
|
"""
|
||||||
|
Useful function to detect if input word contain digit.
|
||||||
|
:param word: Any alphanumeric word.
|
||||||
|
:return: True if the word has a digit else False.
|
||||||
|
"""
|
||||||
|
return any(char.isdigit() for char in word)
|
||||||
|
|
||||||
|
|
||||||
|
def sys_64bits():
|
||||||
|
"""
|
||||||
|
Detect if the host system is 64 bit.
|
||||||
|
:return: True if system is 64 bit.
|
||||||
|
"""
|
||||||
|
return sys.maxsize > 2**32
|
||||||
|
|
||||||
|
|
||||||
|
def mbusb_log_file():
|
||||||
|
"""
|
||||||
|
Function to genrate path to log file.
|
||||||
|
Under linux path is created as /tmp/multibootusb.log
|
||||||
|
Under Windows the file is created under
|
||||||
|
"""
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
home_dir = os.path.expanduser('~')
|
||||||
|
# log_file = os.path.join(home_dir, "multibootusb.log")
|
||||||
|
log_file = os.path.join(tempfile.gettempdir(), "multibootusb.log")
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
# log_file = os.path.join(tempfile.gettempdir(), "multibootusb", "multibootusb.log")
|
||||||
|
log_file = os.path.join("multibootusb.log")
|
||||||
|
|
||||||
|
return log_file
|
||||||
|
|
||||||
|
|
||||||
|
def multibootusb_host_dir():
|
||||||
|
"""
|
||||||
|
Cross platform way to detect multibootusb directory on host system.
|
||||||
|
:return: Path to multibootusb directory of host system.
|
||||||
|
"""
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
home_dir = os.path.expanduser('~')
|
||||||
|
mbusb_dir = os.path.join(home_dir, ".multibootusb")
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
mbusb_dir = os.path.join(tempfile.gettempdir(), "multibootusb")
|
||||||
|
|
||||||
|
return mbusb_dir
|
||||||
|
|
||||||
|
|
||||||
|
def iso_cfg_ext_dir():
|
||||||
|
"""
|
||||||
|
Function to return the path to ISO configuration file extraction directory.
|
||||||
|
:return: Path to directory where ISO config files will be extracted.
|
||||||
|
"""
|
||||||
|
return os.path.join(multibootusb_host_dir(), 'iso_cfg_ext_dir')
|
||||||
|
|
||||||
|
|
||||||
|
def clean_iso_cfg_ext_dir(iso_cfg_ext_dir):
|
||||||
|
"""
|
||||||
|
Clean old ISO config files extracted by previous use of multibootusb.
|
||||||
|
:param iso_cfg_ext_dir: Path to config extract directory.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if os.path.exists(iso_cfg_ext_dir):
|
||||||
|
filelist = [f for f in os.listdir(iso_cfg_ext_dir)]
|
||||||
|
for f in filelist:
|
||||||
|
if os.path.isdir(os.path.join(iso_cfg_ext_dir, f)):
|
||||||
|
shutil.rmtree(os.path.join(iso_cfg_ext_dir, f))
|
||||||
|
else:
|
||||||
|
os.remove(os.path.join(iso_cfg_ext_dir, f))
|
||||||
|
else:
|
||||||
|
log('iso_cfg_ext_dir directory does not exist.')
|
||||||
|
|
||||||
|
|
||||||
|
def copy_mbusb_dir_usb(usb_disk):
|
||||||
|
"""
|
||||||
|
Copy the multibootusb directory to USB mount path.
|
||||||
|
:param usb_mount_path: Path to USB mount.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
from .iso import iso_size
|
||||||
|
from .usb import details
|
||||||
|
|
||||||
|
usb_details = details(usb_disk)
|
||||||
|
usb_mount_path = usb_details['mount_point']
|
||||||
|
if not os.path.exists(os.path.join(usb_mount_path, "multibootusb")):
|
||||||
|
try:
|
||||||
|
log('Copying multibootusb directory to ' + usb_mount_path)
|
||||||
|
shutil.copytree(resource_path(os.path.join("data", "multibootusb")), os.path.join(usb_mount_path, "multibootusb"))
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
log('multibootus directory already exist. Not copying.')
|
||||||
|
|
||||||
|
|
||||||
|
def read_input_yes():
|
||||||
|
"""
|
||||||
|
List option and read user input
|
||||||
|
:return: True if user selected yes or else false
|
||||||
|
"""
|
||||||
|
yes_list = ['Y', 'y', 'Yes', 'yes', 'YES']
|
||||||
|
no_list = ['N', 'n', 'No', 'no', 'NO']
|
||||||
|
response = input("Please enter the option listed above : ")
|
||||||
|
if response in yes_list:
|
||||||
|
return True
|
||||||
|
elif response in no_list:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def strings(filename, min=4):
|
||||||
|
with open(filename, errors="ignore") as f:
|
||||||
|
result = ""
|
||||||
|
for c in f.read():
|
||||||
|
if c in string.printable:
|
||||||
|
result += c
|
||||||
|
continue
|
||||||
|
if len(result) >= min:
|
||||||
|
yield result
|
||||||
|
result = ""
|
||||||
|
if len(result) >= min: # catch result at EOF
|
||||||
|
yield result
|
||||||
|
|
||||||
|
|
||||||
|
def size_not_enough(iso_link, usb_disk):
|
||||||
|
from .iso import iso_size
|
||||||
|
from .usb import details
|
||||||
|
isoSize = iso_size(iso_link)
|
||||||
|
usb_details = details(usb_disk)
|
||||||
|
usb_size = usb_details['size_free']
|
||||||
|
if isoSize > usb_size:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def mbusb_version():
|
||||||
|
version = open(resource_path(os.path.join("data", "version.txt")), 'r').read().strip()
|
||||||
|
return version
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_mbusb_host_dir():
|
||||||
|
"""
|
||||||
|
Prepare multibootusb host directory and extract data files for use.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
home = multibootusb_host_dir()
|
||||||
|
if not os.path.exists(home):
|
||||||
|
os.makedirs(home)
|
||||||
|
else:
|
||||||
|
log("Cleaning old multibootusb directory...")
|
||||||
|
shutil.rmtree(home)
|
||||||
|
os.makedirs(home)
|
||||||
|
|
||||||
|
if not os.path.exists(os.path.join(home, "preference")):
|
||||||
|
os.makedirs(os.path.join(home, "preference"))
|
||||||
|
|
||||||
|
if not os.path.exists(os.path.join(home, "iso_cfg_ext_dir")):
|
||||||
|
os.makedirs(os.path.join(home, "iso_cfg_ext_dir"))
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(home, "syslinux", "bin", "syslinux4")):
|
||||||
|
log("Syslinux exist in multibootusb directory...")
|
||||||
|
else:
|
||||||
|
log("Extracting syslinux to multibootusb directory...")
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
if sys_64bits() is True:
|
||||||
|
log('Host OS is 64 bit...')
|
||||||
|
log("Extracting syslinux 64 bit...")
|
||||||
|
# log(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_linux_64.zip")))
|
||||||
|
with zipfile.ZipFile(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_linux_64.zip")), "r") as z:
|
||||||
|
z.extractall(home)
|
||||||
|
else:
|
||||||
|
log("Extracting syslinux 32 bit...")
|
||||||
|
with zipfile.ZipFile(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_linux.zip")), "r") as z:
|
||||||
|
z.extractall(home)
|
||||||
|
else:
|
||||||
|
with zipfile.ZipFile(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_windows.zip")), "r") as z:
|
||||||
|
z.extractall(home)
|
||||||
|
log("Extracting syslinux modules to multibootusb directory...")
|
||||||
|
with zipfile.ZipFile(resource_path(os.path.join("data", "tools", "syslinux", "syslinux_modules.zip")), "r") as z:
|
||||||
|
z.extractall(os.path.join(home, "syslinux"))
|
||||||
|
|
||||||
|
if os.listdir(os.path.join(home, "iso_cfg_ext_dir")):
|
||||||
|
log(os.listdir(os.path.join(home, "iso_cfg_ext_dir")))
|
||||||
|
log("iso extract directory is not empty.")
|
||||||
|
log("Removing junk files...")
|
||||||
|
for files in os.listdir(os.path.join(home, "iso_cfg_ext_dir")):
|
||||||
|
if os.path.isdir(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files))):
|
||||||
|
log (os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
|
||||||
|
os.chmod(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)), 0o777)
|
||||||
|
shutil.rmtree(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
log (os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
|
||||||
|
os.chmod(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)), 0o777)
|
||||||
|
os.unlink(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
|
||||||
|
os.remove(os.path.join(os.path.join(home, "iso_cfg_ext_dir", files)))
|
||||||
|
except OSError:
|
||||||
|
log("Can't remove the file. Skipping it.")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
log(quote("""Test-string"""))
|
||||||
|
log(has_digit("test-string-with-01-digit"))
|
||||||
|
log(sys_64bits())
|
||||||
|
log(multibootusb_host_dir())
|
||||||
|
log(iso_cfg_ext_dir())
|
||||||
|
strings_test = strings('../../text-stings.bin')
|
||||||
|
log(strings_test)
|
0
deb_dist/multibootusb-8.5.0/scripts/gui/__init__.py
Normal file
0
deb_dist/multibootusb-8.5.0/scripts/gui/__init__.py
Normal file
455
deb_dist/multibootusb-8.5.0/scripts/gui/ui_multibootusb.py
Normal file
455
deb_dist/multibootusb-8.5.0/scripts/gui/ui_multibootusb.py
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'scripts\gui\multibootusb.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt5 UI code generator 5.6
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
class Ui_Dialog(object):
|
||||||
|
def setupUi(self, Dialog):
|
||||||
|
Dialog.setObjectName("Dialog")
|
||||||
|
Dialog.resize(644, 516)
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.tabWidget = QtWidgets.QTabWidget(Dialog)
|
||||||
|
self.tabWidget.setObjectName("tabWidget")
|
||||||
|
self.tab_3 = QtWidgets.QWidget()
|
||||||
|
self.tab_3.setObjectName("tab_3")
|
||||||
|
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.tab_3)
|
||||||
|
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||||
|
self.gridLayout = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout.setObjectName("gridLayout")
|
||||||
|
self.label_persistence_value = QtWidgets.QLabel(self.tab_3)
|
||||||
|
self.label_persistence_value.setObjectName("label_persistence_value")
|
||||||
|
self.gridLayout.addWidget(self.label_persistence_value, 5, 2, 1, 1)
|
||||||
|
self.verticalLayout_11 = QtWidgets.QVBoxLayout()
|
||||||
|
self.verticalLayout_11.setObjectName("verticalLayout_11")
|
||||||
|
self.groupBox_11 = QtWidgets.QGroupBox(self.tab_3)
|
||||||
|
self.groupBox_11.setObjectName("groupBox_11")
|
||||||
|
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.groupBox_11)
|
||||||
|
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
|
||||||
|
self.detect_usb = QtWidgets.QPushButton(self.groupBox_11)
|
||||||
|
self.detect_usb.setObjectName("detect_usb")
|
||||||
|
self.horizontalLayout_8.addWidget(self.detect_usb)
|
||||||
|
self.verticalLayout_11.addWidget(self.groupBox_11)
|
||||||
|
self.gridLayout.addLayout(self.verticalLayout_11, 1, 3, 1, 2)
|
||||||
|
self.listWidget = QtWidgets.QListWidget(self.tab_3)
|
||||||
|
self.listWidget.setObjectName("listWidget")
|
||||||
|
self.gridLayout.addWidget(self.listWidget, 0, 0, 4, 3)
|
||||||
|
self.progressBar = QtWidgets.QProgressBar(self.tab_3)
|
||||||
|
self.progressBar.setProperty("value", 0)
|
||||||
|
self.progressBar.setObjectName("progressBar")
|
||||||
|
self.gridLayout.addWidget(self.progressBar, 7, 0, 1, 6)
|
||||||
|
self.create = QtWidgets.QPushButton(self.tab_3)
|
||||||
|
self.create.setObjectName("create")
|
||||||
|
self.gridLayout.addWidget(self.create, 5, 4, 1, 1)
|
||||||
|
self.comboBox = QtWidgets.QComboBox(self.tab_3)
|
||||||
|
self.comboBox.setObjectName("comboBox")
|
||||||
|
self.gridLayout.addWidget(self.comboBox, 0, 3, 1, 1)
|
||||||
|
self.labelstep1 = QtWidgets.QLabel(self.tab_3)
|
||||||
|
self.labelstep1.setObjectName("labelstep1")
|
||||||
|
self.gridLayout.addWidget(self.labelstep1, 0, 5, 1, 1)
|
||||||
|
self.labelstep2 = QtWidgets.QLabel(self.tab_3)
|
||||||
|
self.labelstep2.setObjectName("labelstep2")
|
||||||
|
self.gridLayout.addWidget(self.labelstep2, 4, 5, 1, 1)
|
||||||
|
self.close = QtWidgets.QPushButton(self.tab_3)
|
||||||
|
self.close.setObjectName("close")
|
||||||
|
self.gridLayout.addWidget(self.close, 5, 3, 1, 1)
|
||||||
|
self.labelstep3 = QtWidgets.QLabel(self.tab_3)
|
||||||
|
self.labelstep3.setObjectName("labelstep3")
|
||||||
|
self.gridLayout.addWidget(self.labelstep3, 5, 5, 1, 1)
|
||||||
|
self.slider_persistence = QtWidgets.QSlider(self.tab_3)
|
||||||
|
self.slider_persistence.setEnabled(False)
|
||||||
|
self.slider_persistence.setAutoFillBackground(False)
|
||||||
|
self.slider_persistence.setOrientation(QtCore.Qt.Horizontal)
|
||||||
|
self.slider_persistence.setTickPosition(QtWidgets.QSlider.TicksBothSides)
|
||||||
|
self.slider_persistence.setTickInterval(0)
|
||||||
|
self.slider_persistence.setObjectName("slider_persistence")
|
||||||
|
self.gridLayout.addWidget(self.slider_persistence, 5, 1, 1, 1)
|
||||||
|
self.groupBox = QtWidgets.QGroupBox(self.tab_3)
|
||||||
|
self.groupBox.setObjectName("groupBox")
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox)
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.gridLayout_5 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_5.setObjectName("gridLayout_5")
|
||||||
|
self.uninstall = QtWidgets.QPushButton(self.groupBox)
|
||||||
|
self.uninstall.setObjectName("uninstall")
|
||||||
|
self.gridLayout_5.addWidget(self.uninstall, 0, 0, 1, 1)
|
||||||
|
self.verticalLayout.addLayout(self.gridLayout_5)
|
||||||
|
self.gridLayout.addWidget(self.groupBox, 3, 3, 1, 2)
|
||||||
|
self.lineEdit = QtWidgets.QLineEdit(self.tab_3)
|
||||||
|
self.lineEdit.setObjectName("lineEdit")
|
||||||
|
self.gridLayout.addWidget(self.lineEdit, 4, 0, 1, 4)
|
||||||
|
self.groupBox_6 = QtWidgets.QGroupBox(self.tab_3)
|
||||||
|
self.groupBox_6.setObjectName("groupBox_6")
|
||||||
|
self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.groupBox_6)
|
||||||
|
self.verticalLayout_5.setObjectName("verticalLayout_5")
|
||||||
|
self.usb_dev = QtWidgets.QLabel(self.groupBox_6)
|
||||||
|
self.usb_dev.setObjectName("usb_dev")
|
||||||
|
self.verticalLayout_5.addWidget(self.usb_dev)
|
||||||
|
self.usb_vendor = QtWidgets.QLabel(self.groupBox_6)
|
||||||
|
self.usb_vendor.setObjectName("usb_vendor")
|
||||||
|
self.verticalLayout_5.addWidget(self.usb_vendor)
|
||||||
|
self.usb_model = QtWidgets.QLabel(self.groupBox_6)
|
||||||
|
self.usb_model.setObjectName("usb_model")
|
||||||
|
self.verticalLayout_5.addWidget(self.usb_model)
|
||||||
|
self.usb_size = QtWidgets.QLabel(self.groupBox_6)
|
||||||
|
self.usb_size.setObjectName("usb_size")
|
||||||
|
self.verticalLayout_5.addWidget(self.usb_size)
|
||||||
|
self.usb_mount = QtWidgets.QLabel(self.groupBox_6)
|
||||||
|
self.usb_mount.setObjectName("usb_mount")
|
||||||
|
self.verticalLayout_5.addWidget(self.usb_mount)
|
||||||
|
self.gridLayout.addWidget(self.groupBox_6, 2, 3, 1, 3)
|
||||||
|
self.browse_iso = QtWidgets.QPushButton(self.tab_3)
|
||||||
|
self.browse_iso.setObjectName("browse_iso")
|
||||||
|
self.gridLayout.addWidget(self.browse_iso, 4, 4, 1, 1)
|
||||||
|
self.label_persistence = QtWidgets.QLabel(self.tab_3)
|
||||||
|
self.label_persistence.setObjectName("label_persistence")
|
||||||
|
self.gridLayout.addWidget(self.label_persistence, 5, 0, 1, 1)
|
||||||
|
self.checkBox_all_drives = QtWidgets.QCheckBox(self.tab_3)
|
||||||
|
self.checkBox_all_drives.setObjectName("checkBox_all_drives")
|
||||||
|
self.gridLayout.addWidget(self.checkBox_all_drives, 0, 4, 1, 1)
|
||||||
|
self.status = QtWidgets.QLabel(self.tab_3)
|
||||||
|
self.status.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
|
self.status.setAcceptDrops(False)
|
||||||
|
self.status.setAutoFillBackground(False)
|
||||||
|
self.status.setFrameShadow(QtWidgets.QFrame.Plain)
|
||||||
|
self.status.setText("")
|
||||||
|
self.status.setTextFormat(QtCore.Qt.AutoText)
|
||||||
|
self.status.setScaledContents(False)
|
||||||
|
self.status.setObjectName("status")
|
||||||
|
self.gridLayout.addWidget(self.status, 6, 0, 1, 6)
|
||||||
|
self.horizontalLayout_2.addLayout(self.gridLayout)
|
||||||
|
self.tabWidget.addTab(self.tab_3, "")
|
||||||
|
self.imager = QtWidgets.QWidget()
|
||||||
|
self.imager.setObjectName("imager")
|
||||||
|
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.imager)
|
||||||
|
self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
|
||||||
|
self.gridLayout_9 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_9.setObjectName("gridLayout_9")
|
||||||
|
self.groupBox_7 = QtWidgets.QGroupBox(self.imager)
|
||||||
|
self.groupBox_7.setObjectName("groupBox_7")
|
||||||
|
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox_7)
|
||||||
|
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||||
|
self.gridLayout_11 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_11.setObjectName("gridLayout_11")
|
||||||
|
self.groupBox_9 = QtWidgets.QGroupBox(self.groupBox_7)
|
||||||
|
self.groupBox_9.setObjectName("groupBox_9")
|
||||||
|
self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.groupBox_9)
|
||||||
|
self.verticalLayout_8.setObjectName("verticalLayout_8")
|
||||||
|
self.comboBox_2 = QtWidgets.QComboBox(self.groupBox_9)
|
||||||
|
self.comboBox_2.setObjectName("comboBox_2")
|
||||||
|
self.verticalLayout_8.addWidget(self.comboBox_2)
|
||||||
|
self.pushbtn_imager_refreshusb = QtWidgets.QPushButton(self.groupBox_9)
|
||||||
|
self.pushbtn_imager_refreshusb.setObjectName("pushbtn_imager_refreshusb")
|
||||||
|
self.verticalLayout_8.addWidget(self.pushbtn_imager_refreshusb)
|
||||||
|
self.imager_disk_label = QtWidgets.QLabel(self.groupBox_9)
|
||||||
|
self.imager_disk_label.setObjectName("imager_disk_label")
|
||||||
|
self.verticalLayout_8.addWidget(self.imager_disk_label)
|
||||||
|
self.imager_total_size = QtWidgets.QLabel(self.groupBox_9)
|
||||||
|
self.imager_total_size.setObjectName("imager_total_size")
|
||||||
|
self.verticalLayout_8.addWidget(self.imager_total_size)
|
||||||
|
self.imager_uuid = QtWidgets.QLabel(self.groupBox_9)
|
||||||
|
self.imager_uuid.setObjectName("imager_uuid")
|
||||||
|
self.verticalLayout_8.addWidget(self.imager_uuid)
|
||||||
|
self.gridLayout_11.addWidget(self.groupBox_9, 0, 0, 1, 1)
|
||||||
|
self.groupBox_10 = QtWidgets.QGroupBox(self.groupBox_7)
|
||||||
|
self.groupBox_10.setObjectName("groupBox_10")
|
||||||
|
self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.groupBox_10)
|
||||||
|
self.verticalLayout_9.setObjectName("verticalLayout_9")
|
||||||
|
self.pushButton = QtWidgets.QPushButton(self.groupBox_10)
|
||||||
|
self.pushButton.setObjectName("pushButton")
|
||||||
|
self.verticalLayout_9.addWidget(self.pushButton)
|
||||||
|
self.lineEdit_3 = QtWidgets.QLineEdit(self.groupBox_10)
|
||||||
|
self.lineEdit_3.setObjectName("lineEdit_3")
|
||||||
|
self.verticalLayout_9.addWidget(self.lineEdit_3)
|
||||||
|
self.imager_bootable = QtWidgets.QLabel(self.groupBox_10)
|
||||||
|
self.imager_bootable.setObjectName("imager_bootable")
|
||||||
|
self.verticalLayout_9.addWidget(self.imager_bootable)
|
||||||
|
self.imager_iso_size = QtWidgets.QLabel(self.groupBox_10)
|
||||||
|
self.imager_iso_size.setObjectName("imager_iso_size")
|
||||||
|
self.verticalLayout_9.addWidget(self.imager_iso_size)
|
||||||
|
self.gridLayout_11.addWidget(self.groupBox_10, 0, 1, 1, 1)
|
||||||
|
self.verticalLayout_6.addLayout(self.gridLayout_11)
|
||||||
|
self.gridLayout_9.addWidget(self.groupBox_7, 1, 0, 1, 1)
|
||||||
|
self.groupBox_8 = QtWidgets.QGroupBox(self.imager)
|
||||||
|
self.groupBox_8.setObjectName("groupBox_8")
|
||||||
|
self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox_8)
|
||||||
|
self.verticalLayout_7.setObjectName("verticalLayout_7")
|
||||||
|
self.imager_label_status = QtWidgets.QLabel(self.groupBox_8)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.imager_label_status.sizePolicy().hasHeightForWidth())
|
||||||
|
self.imager_label_status.setSizePolicy(sizePolicy)
|
||||||
|
self.imager_label_status.setText("")
|
||||||
|
self.imager_label_status.setObjectName("imager_label_status")
|
||||||
|
self.verticalLayout_7.addWidget(self.imager_label_status)
|
||||||
|
self.gridLayout_12 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_12.setObjectName("gridLayout_12")
|
||||||
|
self.imager_write = QtWidgets.QPushButton(self.groupBox_8)
|
||||||
|
self.imager_write.setObjectName("imager_write")
|
||||||
|
self.gridLayout_12.addWidget(self.imager_write, 2, 2, 1, 1)
|
||||||
|
self.imager_close = QtWidgets.QPushButton(self.groupBox_8)
|
||||||
|
self.imager_close.setObjectName("imager_close")
|
||||||
|
self.gridLayout_12.addWidget(self.imager_close, 2, 1, 1, 1)
|
||||||
|
self.label_10 = QtWidgets.QLabel(self.groupBox_8)
|
||||||
|
self.label_10.setObjectName("label_10")
|
||||||
|
self.gridLayout_12.addWidget(self.label_10, 1, 0, 1, 3)
|
||||||
|
self.imager_progressbar = QtWidgets.QProgressBar(self.groupBox_8)
|
||||||
|
self.imager_progressbar.setProperty("value", 0)
|
||||||
|
self.imager_progressbar.setObjectName("imager_progressbar")
|
||||||
|
self.gridLayout_12.addWidget(self.imager_progressbar, 0, 0, 1, 3)
|
||||||
|
self.verticalLayout_7.addLayout(self.gridLayout_12)
|
||||||
|
self.gridLayout_9.addWidget(self.groupBox_8, 2, 0, 1, 1)
|
||||||
|
self.horizontalLayout_7.addLayout(self.gridLayout_9)
|
||||||
|
self.tabWidget.addTab(self.imager, "")
|
||||||
|
self.syslinux_ab = QtWidgets.QWidget()
|
||||||
|
self.syslinux_ab.setObjectName("syslinux_ab")
|
||||||
|
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.syslinux_ab)
|
||||||
|
self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||||
|
self.gridLayout_2 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||||
|
self.groupBox_2 = QtWidgets.QGroupBox(self.syslinux_ab)
|
||||||
|
self.groupBox_2.setAutoFillBackground(False)
|
||||||
|
self.groupBox_2.setObjectName("groupBox_2")
|
||||||
|
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.groupBox_2)
|
||||||
|
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||||
|
self.gridLayout_3 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||||
|
self.install_syslinux = QtWidgets.QPushButton(self.groupBox_2)
|
||||||
|
self.install_syslinux.setObjectName("install_syslinux")
|
||||||
|
self.gridLayout_3.addWidget(self.install_syslinux, 2, 1, 1, 1)
|
||||||
|
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
self.gridLayout_3.addItem(spacerItem, 2, 0, 1, 1)
|
||||||
|
self.install_sys_all = QtWidgets.QRadioButton(self.groupBox_2)
|
||||||
|
self.install_sys_all.setObjectName("install_sys_all")
|
||||||
|
self.gridLayout_3.addWidget(self.install_sys_all, 1, 0, 1, 2)
|
||||||
|
self.install_sys_only = QtWidgets.QRadioButton(self.groupBox_2)
|
||||||
|
self.install_sys_only.setObjectName("install_sys_only")
|
||||||
|
self.gridLayout_3.addWidget(self.install_sys_only, 0, 0, 1, 2)
|
||||||
|
self.horizontalLayout_4.addLayout(self.gridLayout_3)
|
||||||
|
self.gridLayout_2.addWidget(self.groupBox_2, 0, 0, 1, 1)
|
||||||
|
self.groupBox_3 = QtWidgets.QGroupBox(self.syslinux_ab)
|
||||||
|
self.groupBox_3.setObjectName("groupBox_3")
|
||||||
|
self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.groupBox_3)
|
||||||
|
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
|
||||||
|
self.gridLayout_4 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||||
|
self.edit_syslinux = QtWidgets.QPushButton(self.groupBox_3)
|
||||||
|
self.edit_syslinux.setObjectName("edit_syslinux")
|
||||||
|
self.gridLayout_4.addWidget(self.edit_syslinux, 1, 1, 1, 1)
|
||||||
|
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
self.gridLayout_4.addItem(spacerItem1, 1, 0, 1, 1)
|
||||||
|
self.label_2 = QtWidgets.QLabel(self.groupBox_3)
|
||||||
|
self.label_2.setObjectName("label_2")
|
||||||
|
self.gridLayout_4.addWidget(self.label_2, 0, 0, 1, 2)
|
||||||
|
self.horizontalLayout_5.addLayout(self.gridLayout_4)
|
||||||
|
self.gridLayout_2.addWidget(self.groupBox_3, 1, 0, 1, 1)
|
||||||
|
self.horizontalLayout_3.addLayout(self.gridLayout_2)
|
||||||
|
self.tabWidget.addTab(self.syslinux_ab, "")
|
||||||
|
self.tab = QtWidgets.QWidget()
|
||||||
|
self.tab.setObjectName("tab")
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab)
|
||||||
|
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.groupBox_5 = QtWidgets.QGroupBox(self.tab)
|
||||||
|
self.groupBox_5.setObjectName("groupBox_5")
|
||||||
|
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_5)
|
||||||
|
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||||
|
self.gridLayout_7 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_7.setObjectName("gridLayout_7")
|
||||||
|
self.ram_iso_2048 = QtWidgets.QRadioButton(self.groupBox_5)
|
||||||
|
self.ram_iso_2048.setObjectName("ram_iso_2048")
|
||||||
|
self.gridLayout_7.addWidget(self.ram_iso_2048, 4, 4, 1, 1)
|
||||||
|
self.ram_iso_1024 = QtWidgets.QRadioButton(self.groupBox_5)
|
||||||
|
self.ram_iso_1024.setObjectName("ram_iso_1024")
|
||||||
|
self.gridLayout_7.addWidget(self.ram_iso_1024, 4, 3, 1, 1)
|
||||||
|
self.ram_iso_256 = QtWidgets.QRadioButton(self.groupBox_5)
|
||||||
|
self.ram_iso_256.setObjectName("ram_iso_256")
|
||||||
|
self.gridLayout_7.addWidget(self.ram_iso_256, 4, 0, 1, 1)
|
||||||
|
self.browse_iso_qemu = QtWidgets.QPushButton(self.groupBox_5)
|
||||||
|
self.browse_iso_qemu.setObjectName("browse_iso_qemu")
|
||||||
|
self.gridLayout_7.addWidget(self.browse_iso_qemu, 2, 4, 1, 1)
|
||||||
|
self.label_7 = QtWidgets.QLabel(self.groupBox_5)
|
||||||
|
self.label_7.setObjectName("label_7")
|
||||||
|
self.gridLayout_7.addWidget(self.label_7, 0, 0, 1, 5)
|
||||||
|
self.ram_iso_512 = QtWidgets.QRadioButton(self.groupBox_5)
|
||||||
|
self.ram_iso_512.setObjectName("ram_iso_512")
|
||||||
|
self.gridLayout_7.addWidget(self.ram_iso_512, 4, 1, 1, 1)
|
||||||
|
self.boot_iso_qemu = QtWidgets.QPushButton(self.groupBox_5)
|
||||||
|
self.boot_iso_qemu.setObjectName("boot_iso_qemu")
|
||||||
|
self.gridLayout_7.addWidget(self.boot_iso_qemu, 6, 4, 1, 1)
|
||||||
|
self.ram_iso_768 = QtWidgets.QRadioButton(self.groupBox_5)
|
||||||
|
self.ram_iso_768.setObjectName("ram_iso_768")
|
||||||
|
self.gridLayout_7.addWidget(self.ram_iso_768, 4, 2, 1, 1)
|
||||||
|
self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox_5)
|
||||||
|
self.lineEdit_2.setObjectName("lineEdit_2")
|
||||||
|
self.gridLayout_7.addWidget(self.lineEdit_2, 2, 0, 1, 4)
|
||||||
|
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
self.gridLayout_7.addItem(spacerItem2, 3, 1, 1, 1)
|
||||||
|
self.label_3 = QtWidgets.QLabel(self.groupBox_5)
|
||||||
|
self.label_3.setObjectName("label_3")
|
||||||
|
self.gridLayout_7.addWidget(self.label_3, 6, 0, 1, 4)
|
||||||
|
spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
self.gridLayout_7.addItem(spacerItem3, 5, 0, 1, 1)
|
||||||
|
spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
self.gridLayout_7.addItem(spacerItem4, 1, 0, 1, 1)
|
||||||
|
self.verticalLayout_3.addLayout(self.gridLayout_7)
|
||||||
|
self.verticalLayout_2.addWidget(self.groupBox_5)
|
||||||
|
spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
self.verticalLayout_2.addItem(spacerItem5)
|
||||||
|
self.gridLayout_6 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_6.setObjectName("gridLayout_6")
|
||||||
|
self.groupBox_4 = QtWidgets.QGroupBox(self.tab)
|
||||||
|
self.groupBox_4.setObjectName("groupBox_4")
|
||||||
|
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox_4)
|
||||||
|
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||||
|
self.gridLayout_8 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_8.setObjectName("gridLayout_8")
|
||||||
|
self.ram_usb_768 = QtWidgets.QRadioButton(self.groupBox_4)
|
||||||
|
self.ram_usb_768.setObjectName("ram_usb_768")
|
||||||
|
self.gridLayout_8.addWidget(self.ram_usb_768, 2, 2, 1, 1)
|
||||||
|
self.ram_usb_256 = QtWidgets.QRadioButton(self.groupBox_4)
|
||||||
|
self.ram_usb_256.setObjectName("ram_usb_256")
|
||||||
|
self.gridLayout_8.addWidget(self.ram_usb_256, 2, 0, 1, 1)
|
||||||
|
self.label_6 = QtWidgets.QLabel(self.groupBox_4)
|
||||||
|
self.label_6.setObjectName("label_6")
|
||||||
|
self.gridLayout_8.addWidget(self.label_6, 0, 0, 1, 5)
|
||||||
|
self.ram_usb_1024 = QtWidgets.QRadioButton(self.groupBox_4)
|
||||||
|
self.ram_usb_1024.setObjectName("ram_usb_1024")
|
||||||
|
self.gridLayout_8.addWidget(self.ram_usb_1024, 2, 3, 1, 1)
|
||||||
|
self.label_4 = QtWidgets.QLabel(self.groupBox_4)
|
||||||
|
self.label_4.setObjectName("label_4")
|
||||||
|
self.gridLayout_8.addWidget(self.label_4, 4, 0, 1, 4)
|
||||||
|
self.ram_usb_512 = QtWidgets.QRadioButton(self.groupBox_4)
|
||||||
|
self.ram_usb_512.setObjectName("ram_usb_512")
|
||||||
|
self.gridLayout_8.addWidget(self.ram_usb_512, 2, 1, 1, 1)
|
||||||
|
self.boot_usb_qemu = QtWidgets.QPushButton(self.groupBox_4)
|
||||||
|
self.boot_usb_qemu.setObjectName("boot_usb_qemu")
|
||||||
|
self.gridLayout_8.addWidget(self.boot_usb_qemu, 4, 4, 1, 1)
|
||||||
|
self.ram_usb_2048 = QtWidgets.QRadioButton(self.groupBox_4)
|
||||||
|
self.ram_usb_2048.setObjectName("ram_usb_2048")
|
||||||
|
self.gridLayout_8.addWidget(self.ram_usb_2048, 2, 4, 1, 1)
|
||||||
|
spacerItem6 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
self.gridLayout_8.addItem(spacerItem6, 1, 1, 1, 1)
|
||||||
|
spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
self.gridLayout_8.addItem(spacerItem7, 3, 2, 1, 1)
|
||||||
|
spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||||
|
self.gridLayout_8.addItem(spacerItem8, 5, 0, 1, 1)
|
||||||
|
self.verticalLayout_4.addLayout(self.gridLayout_8)
|
||||||
|
self.gridLayout_6.addWidget(self.groupBox_4, 0, 0, 1, 1)
|
||||||
|
self.verticalLayout_2.addLayout(self.gridLayout_6)
|
||||||
|
self.tabWidget.addTab(self.tab, "")
|
||||||
|
self.tab_2 = QtWidgets.QWidget()
|
||||||
|
self.tab_2.setObjectName("tab_2")
|
||||||
|
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.tab_2)
|
||||||
|
self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
|
||||||
|
self.gridLayout_10 = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout_10.setObjectName("gridLayout_10")
|
||||||
|
spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
self.gridLayout_10.addItem(spacerItem9, 0, 1, 1, 1)
|
||||||
|
spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
self.gridLayout_10.addItem(spacerItem10, 1, 0, 1, 1)
|
||||||
|
spacerItem11 = QtWidgets.QSpacerItem(20, 30, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
self.gridLayout_10.addItem(spacerItem11, 2, 1, 1, 1)
|
||||||
|
self.label_5 = QtWidgets.QLabel(self.tab_2)
|
||||||
|
self.label_5.setObjectName("label_5")
|
||||||
|
self.gridLayout_10.addWidget(self.label_5, 1, 1, 1, 1)
|
||||||
|
spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
self.gridLayout_10.addItem(spacerItem12, 1, 2, 1, 1)
|
||||||
|
self.horizontalLayout_6.addLayout(self.gridLayout_10)
|
||||||
|
self.tabWidget.addTab(self.tab_2, "")
|
||||||
|
self.horizontalLayout.addWidget(self.tabWidget)
|
||||||
|
|
||||||
|
self.retranslateUi(Dialog)
|
||||||
|
self.tabWidget.setCurrentIndex(0)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, Dialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
Dialog.setWindowTitle(_translate("Dialog", "multibootusb"))
|
||||||
|
self.label_persistence_value.setText(_translate("Dialog", "0 MB"))
|
||||||
|
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", "<html><head/><body><p align=\"center\"><span style=\" font-weight:600;\">Step 1</span></p></body></html>"))
|
||||||
|
self.labelstep2.setText(_translate("Dialog", "<html><head/><body><p align=\"center\"><span style=\" font-weight:600;\">Step 2</span></p></body></html>"))
|
||||||
|
self.close.setText(_translate("Dialog", "Close"))
|
||||||
|
self.labelstep3.setText(_translate("Dialog", "<html><head/><body><p align=\"center\"><span style=\" font-weight:600;\">Step 3</span></p></body></html>"))
|
||||||
|
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.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", "<html><head/><body><p><span style=\" font-weight:600;\">Persistence</span></p></body></html>"))
|
||||||
|
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 -------------------"))
|
||||||
|
self.pushbtn_imager_refreshusb.setText(_translate("Dialog", "Refresh USB"))
|
||||||
|
self.imager_disk_label.setText(_translate("Dialog", "Disk Label ::"))
|
||||||
|
self.imager_total_size.setText(_translate("Dialog", "Disk Size"))
|
||||||
|
self.imager_uuid.setText(_translate("Dialog", "Disk Label ::"))
|
||||||
|
self.groupBox_10.setTitle(_translate("Dialog", "------------------------------ ISO details ----------------------------------"))
|
||||||
|
self.pushButton.setText(_translate("Dialog", "Browse ISO"))
|
||||||
|
self.imager_bootable.setText(_translate("Dialog", "Bootable ISO"))
|
||||||
|
self.imager_iso_size.setText(_translate("Dialog", "ISO Size"))
|
||||||
|
self.groupBox_8.setTitle(_translate("Dialog", "Imager Progress"))
|
||||||
|
self.imager_write.setText(_translate("Dialog", "Write/Create"))
|
||||||
|
self.imager_close.setText(_translate("Dialog", "Close"))
|
||||||
|
self.label_10.setText(_translate("Dialog", "<html><head/><body><p><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>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.imager), _translate("Dialog", "ISO Imager"))
|
||||||
|
self.groupBox_2.setTitle(_translate("Dialog", "Install Syslinux"))
|
||||||
|
self.install_syslinux.setText(_translate("Dialog", "Install"))
|
||||||
|
self.install_sys_all.setText(_translate("Dialog", "Install syslinux and copy all required files."))
|
||||||
|
self.install_sys_only.setText(_translate("Dialog", "Install only syslinux (existing configurations will not be altred)."))
|
||||||
|
self.groupBox_3.setTitle(_translate("Dialog", "Edit syslinux.cfg"))
|
||||||
|
self.edit_syslinux.setText(_translate("Dialog", "Edit"))
|
||||||
|
self.label_2.setText(_translate("Dialog", "<html><head/><body><p align=\"justify\">Using this option user can edit syslinux.cfg file directly. It directly uses </p><p align=\"justify\">default editor of host system. Be careful while editing syslinux.cfg file.</p></body></html>"))
|
||||||
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.syslinux_ab), _translate("Dialog", "Syslinux"))
|
||||||
|
self.groupBox_5.setTitle(_translate("Dialog", "Boot ISO"))
|
||||||
|
self.ram_iso_2048.setText(_translate("Dialog", "2048 MB"))
|
||||||
|
self.ram_iso_1024.setText(_translate("Dialog", "1024 MB"))
|
||||||
|
self.ram_iso_256.setText(_translate("Dialog", "256 MB"))
|
||||||
|
self.browse_iso_qemu.setText(_translate("Dialog", "Browse ISO"))
|
||||||
|
self.label_7.setText(_translate("Dialog", "<html><head/><body><p>Best way to test your downloaded ISOs. </p></body></html>"))
|
||||||
|
self.ram_iso_512.setText(_translate("Dialog", "512 MB"))
|
||||||
|
self.boot_iso_qemu.setText(_translate("Dialog", "Boot ISO"))
|
||||||
|
self.ram_iso_768.setText(_translate("Dialog", "768 MB"))
|
||||||
|
self.label_3.setText(_translate("Dialog", "Choose desired RAM and click on Boot ISO button."))
|
||||||
|
self.groupBox_4.setTitle(_translate("Dialog", "Boot USB"))
|
||||||
|
self.ram_usb_768.setText(_translate("Dialog", "768 MB"))
|
||||||
|
self.ram_usb_256.setText(_translate("Dialog", "256 MB"))
|
||||||
|
self.label_6.setText(_translate("Dialog", "<html><head/><body><p align=\"justify\">Use this option if you want to check USB installation without reboot.</p></body></html>"))
|
||||||
|
self.ram_usb_1024.setText(_translate("Dialog", "1024 MB"))
|
||||||
|
self.label_4.setText(_translate("Dialog", "Choose desired RAM and click on Boot USB button."))
|
||||||
|
self.ram_usb_512.setText(_translate("Dialog", "512 MB"))
|
||||||
|
self.boot_usb_qemu.setText(_translate("Dialog", "Boot USB"))
|
||||||
|
self.ram_usb_2048.setText(_translate("Dialog", "2048 MB"))
|
||||||
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Dialog", "QEMU"))
|
||||||
|
self.label_5.setText(_translate("Dialog", "<html><head/><body><p align=\"center\">An advanced bootable usb creator with option to install/uninstall </p><p align=\"center\">multiple distros. This software is written in python and pyqt. </p><p align=\"center\">Copyright 2010-2016 Sundar</p><p align=\"center\"><span style=\" font-weight:600; text-decoration: underline;\">Author(s)</span>: Sundar, Ian Bruce, Lee</p><p align=\"center\"><span style=\" font-weight:600; text-decoration: underline;\">Licence:</span> GPL version 2 or later</p><p align=\"center\"><span style=\" font-weight:600; text-decoration: underline;\">Home page</span>: <a href=\" http://multibootusb.org\"><span style=\" text-decoration: underline; color:#0000ff;\">http://multibootusb.org</span></a></p><p align=\"center\"><span style=\" font-weight:600; text-decoration: underline;\">Help/Email:</span> feedback.multibootusb@gmail.com</p><p align=\"center\"><span style=\" font-weight:600; text-decoration: underline;\">Source Code:</span><span style=\" font-weight:600;\"/><a href=\"https://github.com/mbusb/multibootusb\"><span style=\" text-decoration: underline; color:#0000ff;\">https://github.com/mbusb/multibootusb</span></a></p><p><br/></p></body></html>"))
|
||||||
|
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Dialog", "About"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
Dialog = QtWidgets.QDialog()
|
||||||
|
ui = Ui_Dialog()
|
||||||
|
ui.setupUi(Dialog)
|
||||||
|
Dialog.show()
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
226
deb_dist/multibootusb-8.5.0/scripts/imager.py
Normal file
226
deb_dist/multibootusb-8.5.0/scripts/imager.py
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: imager.py
|
||||||
|
# Purpose: Module to write ISO image to selected USB disk. Uses dd as backend.
|
||||||
|
# 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
|
||||||
|
# WARNING : Any boot-able USB made using this module will destroy data stored on USB disk.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import collections
|
||||||
|
import platform
|
||||||
|
import signal
|
||||||
|
from PyQt5 import QtGui
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
from PyQt5 import QtCore
|
||||||
|
from .gui.ui_multibootusb import Ui_Dialog
|
||||||
|
from .gen import *
|
||||||
|
from . import iso
|
||||||
|
from . import usb
|
||||||
|
from . import config
|
||||||
|
from . import progressbar
|
||||||
|
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
import win32com.client
|
||||||
|
|
||||||
|
|
||||||
|
def dd_linux():
|
||||||
|
import time
|
||||||
|
input = "if=" + config.imager_iso_link
|
||||||
|
in_file_size = float(os.path.getsize(config.imager_iso_link))
|
||||||
|
output = "of=" + config.imager_usb_disk
|
||||||
|
os.system("umount " + config.imager_usb_disk + "1")
|
||||||
|
command = ['dd', input, output, "bs=1M"]
|
||||||
|
log("Executing ==> " + " ".join(command))
|
||||||
|
dd_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
|
||||||
|
pbar = progressbar.ProgressBar(maxval=100).start() # bar = progressbar.ProgressBar(redirect_stdout=True)
|
||||||
|
while dd_process.poll() is None:
|
||||||
|
time.sleep(.1) # If this time delay is not given, the Popen does not execute the actual command
|
||||||
|
dd_process.send_signal(signal.SIGUSR1)
|
||||||
|
dd_process.stderr.flush()
|
||||||
|
while True:
|
||||||
|
out_error = dd_process.stderr.readline().decode()
|
||||||
|
if out_error:
|
||||||
|
if 'bytes' in out_error:
|
||||||
|
copied = int(out_error.split(' ', 1)[0])
|
||||||
|
config.imager_percentage = round((float(copied) / float(in_file_size) * 100))
|
||||||
|
pbar.update(config.imager_percentage)
|
||||||
|
break
|
||||||
|
|
||||||
|
if dd_process.poll() is not None:
|
||||||
|
log("Executing ==> sync")
|
||||||
|
os.system("sync")
|
||||||
|
log("ISO has been written to USB disk...")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def dd_win():
|
||||||
|
|
||||||
|
windd = resource_path(os.path.join("data", "tools", "dd", "dd.exe"))
|
||||||
|
if os.path.exists(resource_path(os.path.join("data", "tools", "dd", "dd.exe"))):
|
||||||
|
log("dd exist")
|
||||||
|
input = "if=" + config.imager_iso_link
|
||||||
|
in_file_size = float(os.path.getsize(config.imager_iso_link) / 1024 / 1024)
|
||||||
|
output = "of=\\\.\\" + config.imager_usb_disk
|
||||||
|
command = [windd, input, output, "bs=1M", "--progress"]
|
||||||
|
log("Executing ==> " + " ".join(command))
|
||||||
|
dd_process = subprocess.Popen(command, universal_newlines=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||||
|
shell=False)
|
||||||
|
while dd_process.poll() is None:
|
||||||
|
for line in iter(dd_process.stderr.readline, ''):
|
||||||
|
line = line.strip()
|
||||||
|
if 'error' in line.lower() or 'invalid' in line.lower():
|
||||||
|
log("Error writing to disk...")
|
||||||
|
break
|
||||||
|
if line and line[-1] == 'M':
|
||||||
|
copied = float(line.strip('M').replace(',', ''))
|
||||||
|
config.imager_percentage = round((copied / float(in_file_size) * 100))
|
||||||
|
|
||||||
|
log("ISO has been written to USB disk...")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class Imager(QtWidgets.QDialog, Ui_Dialog):
|
||||||
|
"""
|
||||||
|
Raw write to USB disk using dd.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
QtWidgets.QDialog.__init__(self)
|
||||||
|
self.ui = Ui_Dialog()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
def on_Imager_Browse_iso_Click(self):
|
||||||
|
"""
|
||||||
|
Browse and choose an ISO.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.ui.lineEdit_3.clear()
|
||||||
|
config.imager_iso_link = QtWidgets.QFileDialog.getOpenFileName(self, 'Select an iso...', "", "ISO Files (*.iso)")[0]
|
||||||
|
if config.imager_iso_link:
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
if "/" in config.imager_iso_link:
|
||||||
|
config.imager_iso_link = config.imager_iso_link.strip().replace("/", "\\")
|
||||||
|
self.ui.lineEdit_3.insert(str(config.imager_iso_link))
|
||||||
|
self.add_iso_gui_label_text()
|
||||||
|
else:
|
||||||
|
log("File not selected...")
|
||||||
|
|
||||||
|
def add_iso_gui_label_text(self):
|
||||||
|
"""
|
||||||
|
Simple function to add text label to GUI widgets.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
log("Testing ISO...")
|
||||||
|
if iso.is_bootable(config.imager_iso_link) is True:
|
||||||
|
self.ui.imager_bootable.setText("Bootable ISO :: Yes")
|
||||||
|
log("ISO is bootable.")
|
||||||
|
else:
|
||||||
|
self.ui.imager_bootable.setText("Bootable ISO :: No")
|
||||||
|
log("ISO is not bootable.")
|
||||||
|
|
||||||
|
if os.path.exists(config.imager_iso_link):
|
||||||
|
log("Path " + config.imager_iso_link + " is exist...")
|
||||||
|
self.iso_size = str(round(os.path.getsize(config.imager_iso_link) / 1024 / 1024))
|
||||||
|
self.ui.imager_iso_size.setText("ISO Size :: " + self.iso_size + " MB")
|
||||||
|
log("ISO Size is " + self.iso_size + " MB")
|
||||||
|
|
||||||
|
def onImagerComboChange(self):
|
||||||
|
config.imager_usb_disk = str(self.ui.comboBox_2.currentText())
|
||||||
|
if bool(config.imager_usb_disk):
|
||||||
|
self.ui.imager_disk_label.setText("Disk Type :: " + self.imager_usb_detail(config.imager_usb_disk,
|
||||||
|
partition=0).usb_type)
|
||||||
|
self.ui.imager_total_size.setText("Disk Size :: " + usb.bytes2human(int(self.imager_usb_detail
|
||||||
|
(config.imager_usb_disk,
|
||||||
|
partition=0).total_size)))
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
self.ui.imager_uuid.setText("Disk Model :: " + str(self.imager_usb_detail(config.imager_usb_disk,
|
||||||
|
partition=0).model))
|
||||||
|
else:
|
||||||
|
self.ui.imager_uuid.setText("Disk Label :: " + self.imager_usb_detail(config.imager_usb_disk,
|
||||||
|
partition=0).model)
|
||||||
|
|
||||||
|
def imager_list_usb(self, partition=1):
|
||||||
|
"""
|
||||||
|
Function to detect whole USB disk. It uses lsblk package on Linux.
|
||||||
|
:param partition: What to return. By default partition is set.
|
||||||
|
:return: USB disk/partition as list
|
||||||
|
"""
|
||||||
|
disk = []
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
output = subprocess.check_output("lsblk -i", shell=True)
|
||||||
|
if not partition == 1:
|
||||||
|
for line in output.splitlines():
|
||||||
|
line = line.split()
|
||||||
|
if (line[2].strip()) == b'1' and (line[5].strip()) == b'disk':
|
||||||
|
disk.append(str("/dev/" + str(line[0].strip().decode())))
|
||||||
|
elif partition == 1:
|
||||||
|
for line in output.splitlines():
|
||||||
|
line = line.split()
|
||||||
|
if (line[2].strip()) == b'1' and line[5].strip() == b'part':
|
||||||
|
disk.append(str("/dev/" + str(line[0].strip()[2:])))
|
||||||
|
else:
|
||||||
|
if partition == 1 or not partition == 1:
|
||||||
|
oFS = win32com.client.Dispatch("Scripting.FileSystemObject")
|
||||||
|
oDrives = oFS.Drives
|
||||||
|
for drive in oDrives:
|
||||||
|
if drive.DriveType == 1 and drive.IsReady:
|
||||||
|
disk.append(drive)
|
||||||
|
return disk
|
||||||
|
|
||||||
|
def imager_usb_detail(self, usb_disk, partition=1):
|
||||||
|
"""
|
||||||
|
Function to detect details of USB disk using lsblk
|
||||||
|
:param usb_disk: path to usb disk
|
||||||
|
:param partition: by default partition is set (but yet to code for it)
|
||||||
|
:return: details of size, type and model as tuples
|
||||||
|
"""
|
||||||
|
_ntuple_diskusage = collections.namedtuple('usage', 'total_size usb_type model')
|
||||||
|
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
output = subprocess.check_output("lsblk -ib " + usb_disk, shell=True)
|
||||||
|
for line in output.splitlines():
|
||||||
|
line = line.split()
|
||||||
|
if not partition == 1:
|
||||||
|
if line[2].strip() == b'1' and line[5].strip() == b'disk':
|
||||||
|
total_size = line[3]
|
||||||
|
if not total_size:
|
||||||
|
total_size = "Unknown"
|
||||||
|
usb_type = "Removable"
|
||||||
|
model = subprocess.check_output("lsblk -in -f -o MODEL " + usb_disk, shell=True).decode()
|
||||||
|
if not model:
|
||||||
|
model = "Unknown"
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
selected_usb_part = str(usb_disk)
|
||||||
|
oFS = win32com.client.Dispatch("Scripting.FileSystemObject")
|
||||||
|
d = oFS.GetDrive(oFS.GetDriveName(oFS.GetAbsolutePathName(selected_usb_part)))
|
||||||
|
selected_usb_device = d.DriveLetter
|
||||||
|
label = (d.VolumeName).strip()
|
||||||
|
if not label.strip():
|
||||||
|
label = "No label."
|
||||||
|
total_size = d.TotalSize
|
||||||
|
usb_type = "Removable"
|
||||||
|
model = label
|
||||||
|
except:
|
||||||
|
log("Error detecting USB details.")
|
||||||
|
|
||||||
|
return _ntuple_diskusage(total_size, usb_type, model)
|
||||||
|
|
||||||
|
def get_usb_size(self, usb_disk):
|
||||||
|
"""
|
||||||
|
Function to detect USB disk space. Useful but not used in multibootusb as of now.
|
||||||
|
:param usb_disk: USB disk like "/dev/sdb"
|
||||||
|
:return: Size of the disk as integer
|
||||||
|
"""
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
cat_output = subprocess.check_output("cat /proc/partitions | grep " + usb_disk[5:], shell=True)
|
||||||
|
usb_size = int(cat_output.split()[2]) * 1024
|
||||||
|
# log(usb_size)
|
||||||
|
return usb_size
|
||||||
|
else:
|
||||||
|
usb_size = self.usb.disk_usage(self.usb.get_usb(usb_disk).mount).total
|
||||||
|
return usb_size
|
192
deb_dist/multibootusb-8.5.0/scripts/install.py
Normal file
192
deb_dist/multibootusb-8.5.0/scripts/install.py
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: install.py
|
||||||
|
# Purpose: This module contain functions to install ISO files to USB disk non destructively.
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import platform
|
||||||
|
import threading
|
||||||
|
import subprocess
|
||||||
|
from .usb import *
|
||||||
|
from .gen import *
|
||||||
|
# from .iso import *
|
||||||
|
from . import iso
|
||||||
|
from scripts.update_cfg_file import *
|
||||||
|
from . import config
|
||||||
|
from . import persistence
|
||||||
|
|
||||||
|
|
||||||
|
def install_distro():
|
||||||
|
"""
|
||||||
|
Install selected ISO to USB disk.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
usb_mount = config.usb_mount
|
||||||
|
install_dir = os.path.join(usb_mount, "multibootusb", iso_basename(config.iso_link))
|
||||||
|
_iso_file_list = iso.iso_file_list(config.iso_link)
|
||||||
|
|
||||||
|
if not os.path.exists(os.path.join(usb_mount, "multibootusb")):
|
||||||
|
log("Copying multibootusb directory to " + usb_mount)
|
||||||
|
shutil.copytree(resource_path(os.path.join("data", "tools", "multibootusb")),
|
||||||
|
os.path.join(config.usb_mount, "multibootusb"))
|
||||||
|
|
||||||
|
if not os.path.exists(install_dir):
|
||||||
|
os.makedirs(install_dir)
|
||||||
|
with open(os.path.join(install_dir, "multibootusb.cfg"), "w") as f:
|
||||||
|
f.write(config.distro)
|
||||||
|
with open(os.path.join(install_dir, "iso_file_list.cfg"), 'w') as f:
|
||||||
|
for file_path in _iso_file_list:
|
||||||
|
f.write(file_path + "\n")
|
||||||
|
log("Installing " + iso_name(config.iso_link) + " on " + install_dir)
|
||||||
|
|
||||||
|
if config.distro == "opensuse":
|
||||||
|
iso.iso_extract_file(config.iso_link, install_dir, 'boot')
|
||||||
|
status_text = "Copying ISO..."
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
subprocess.call(["xcopy", config.iso_link, usb_mount], shell=True) # Have to use xcopy as python file copy is dead slow.
|
||||||
|
elif platform.system() == "Linux":
|
||||||
|
log("Copying " + config.iso_link + " to " + usb_mount)
|
||||||
|
shutil.copy(config.iso_link, usb_mount)
|
||||||
|
elif config.distro == "Windows" or config.distro == "alpine" or config.distro == 'pc-unlocker':
|
||||||
|
log("Extracting iso to " + usb_mount)
|
||||||
|
iso_extract_full(config.iso_link, usb_mount)
|
||||||
|
elif config.distro == "trinity-rescue":
|
||||||
|
iso.iso_extract_file(config.iso_link, usb_mount, '*trk3')
|
||||||
|
elif config.distro == "ipfire":
|
||||||
|
iso.iso_extract_file(config.iso_link, usb_mount, '*.tlz')
|
||||||
|
iso.iso_extract_file(config.iso_link, usb_mount, 'distro.img')
|
||||||
|
iso.iso_extract_file(config.iso_link, install_dir, 'boot')
|
||||||
|
elif config.distro == "zenwalk":
|
||||||
|
config.status_text = "Copying ISO..."
|
||||||
|
iso.iso_extract_file(config.iso_link, install_dir, "kernel")
|
||||||
|
copy_iso(config.iso_link, install_dir)
|
||||||
|
elif config.distro == "salix-live":
|
||||||
|
# iso.iso_extract_file(config.iso_link, install_dir, "boot")
|
||||||
|
iso.iso_extract_file(config.iso_link, install_dir, '*syslinux')
|
||||||
|
iso.iso_extract_file(config.iso_link, install_dir, '*menus')
|
||||||
|
iso.iso_extract_file(config.iso_link, install_dir, '*vmlinuz')
|
||||||
|
iso.iso_extract_file(config.iso_link, install_dir, '*initrd*')
|
||||||
|
iso.iso_extract_file(config.iso_link, usb_mount, '*modules')
|
||||||
|
iso.iso_extract_file(config.iso_link, usb_mount, '*packages')
|
||||||
|
iso.iso_extract_file(config.iso_link, usb_mount, '*optional')
|
||||||
|
iso.iso_extract_file(config.iso_link, usb_mount, '*liveboot')
|
||||||
|
#iso.iso_extract_full(config.iso_link, usb_mount)
|
||||||
|
# config.status_text = "Copying ISO..."
|
||||||
|
# copy_iso(config.iso_link, install_dir)
|
||||||
|
elif config.distro == 'sgrubd2':
|
||||||
|
copy_iso(config.iso_link, install_dir)
|
||||||
|
elif config.distro == 'alt-linux':
|
||||||
|
iso.iso_extract_file(config.iso_link, install_dir, '-xr!*rescue')
|
||||||
|
iso.iso_extract_file(config.iso_link, config.usb_mount, 'rescue')
|
||||||
|
elif config.distro == "generic":
|
||||||
|
#with open(os.path.join(install_dir, "generic.cfg"), "w") as f:
|
||||||
|
# f.write(os.path.join(isolinux_bin_dir(config.iso_link), "generic") + ".bs")
|
||||||
|
iso_extract_full(config.iso_link, usb_mount)
|
||||||
|
elif config.distro == 'grub4dos':
|
||||||
|
iso_extract_full(config.iso_link, usb_mount)
|
||||||
|
elif config.distro == 'ReactOS':
|
||||||
|
iso_extract_full(config.iso_link, usb_mount)
|
||||||
|
elif config.distro == 'grub4dos_iso':
|
||||||
|
copy_iso(config.iso_link, install_dir)
|
||||||
|
else:
|
||||||
|
iso.iso_extract_full(config.iso_link, install_dir)
|
||||||
|
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
log('ISO extracted successfully. Sync is in progress...')
|
||||||
|
os.system('sync')
|
||||||
|
|
||||||
|
if config.persistence != 0:
|
||||||
|
log('Creating Persistence...')
|
||||||
|
config.status_text = 'Creating Persistence...'
|
||||||
|
persistence.create_persistence()
|
||||||
|
|
||||||
|
install_patch()
|
||||||
|
|
||||||
|
|
||||||
|
def copy_iso(src, dst):
|
||||||
|
"""
|
||||||
|
A simple wrapper for copying larger files. This is necessary as
|
||||||
|
shutil copy files is much slower under Windows platform
|
||||||
|
:param src: Path to source file
|
||||||
|
:param dst: Destination directory
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
subprocess.call("xcopy " + src + " " + dst, shell=True)
|
||||||
|
elif platform.system() == "Linux":
|
||||||
|
shutil.copy(src, dst)
|
||||||
|
|
||||||
|
def install_progress():
|
||||||
|
"""
|
||||||
|
Function to calculate progress percentage of install.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
from . import progressbar
|
||||||
|
|
||||||
|
usb_details = details(config.usb_disk)
|
||||||
|
usb_mount = usb_details['mount_point']
|
||||||
|
usb_size_used = usb_details['size_used']
|
||||||
|
thrd = threading.Thread(target=install_distro, name="install_progress")
|
||||||
|
# thrd.daemon()
|
||||||
|
# install_size = usb_size_used / 1024
|
||||||
|
install_size = iso_size(config.iso_link) / 1024
|
||||||
|
final_size = (usb_size_used + iso_size(config.iso_link)) + config.persistence
|
||||||
|
thrd.start()
|
||||||
|
pbar = progressbar.ProgressBar(maxval=100).start() # bar = progressbar.ProgressBar(redirect_stdout=True)
|
||||||
|
while thrd.is_alive():
|
||||||
|
current_size = details(config.usb_disk)['size_used']
|
||||||
|
percentage = int((current_size / final_size) * 100)
|
||||||
|
if percentage > 100:
|
||||||
|
percentage = 100
|
||||||
|
config.percentage = percentage
|
||||||
|
pbar.update(percentage)
|
||||||
|
|
||||||
|
|
||||||
|
def install_patch():
|
||||||
|
"""
|
||||||
|
Function to certain distros which uses makeboot.sh script for making bootable usb disk.
|
||||||
|
This is required to make sure that same version (32/64 bit) of modules present is the isolinux directory
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if config.distro == 'debian':
|
||||||
|
if platform.system() == 'Linux': # Need to syn under Linux. Otherwise, USB disk becomes random read only.
|
||||||
|
os.system('sync')
|
||||||
|
iso_cfg_ext_dir = os.path.join(multibootusb_host_dir(), "iso_cfg_ext_dir")
|
||||||
|
isolinux_path = os.path.join(iso_cfg_ext_dir, isolinux_bin_path(config.iso_link))
|
||||||
|
iso_linux_bin_dir = isolinux_bin_dir(config.iso_link)
|
||||||
|
config.syslinux_version = isolinux_version(isolinux_path)
|
||||||
|
iso_file_list = iso.iso_file_list(config.iso_link)
|
||||||
|
os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link), isolinux_bin_dir(config.iso_link))
|
||||||
|
if any("makeboot.sh" in s.lower() for s in iso_file_list):
|
||||||
|
for module in os.listdir(os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link),
|
||||||
|
isolinux_bin_dir(config.iso_link))):
|
||||||
|
if module.endswith(".c32"):
|
||||||
|
if os.path.exists(os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link),
|
||||||
|
isolinux_bin_dir(config.iso_link), module)):
|
||||||
|
try:
|
||||||
|
os.remove(os.path.join(config.usb_mount, "multibootusb",
|
||||||
|
iso_basename(config.iso_link), isolinux_bin_dir(config.iso_link), module))
|
||||||
|
log("Copying " + module)
|
||||||
|
log((resource_path(
|
||||||
|
os.path.join(multibootusb_host_dir(), "syslinux", "modules", config.syslinux_version, module)),
|
||||||
|
os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link),
|
||||||
|
isolinux_bin_dir(config.iso_link), module)))
|
||||||
|
shutil.copy(resource_path(
|
||||||
|
os.path.join(multibootusb_host_dir(), "syslinux", "modules", config.syslinux_version, module)),
|
||||||
|
os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link),
|
||||||
|
isolinux_bin_dir(config.iso_link), module))
|
||||||
|
except Exception as err:
|
||||||
|
log(err)
|
||||||
|
log("Could not copy " + module)
|
||||||
|
else:
|
||||||
|
log('Patch not required...')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
config.iso_link = '../../../DISTROS/2016/slitaz-4.0.iso'
|
||||||
|
install_distro()
|
214
deb_dist/multibootusb-8.5.0/scripts/iso.py
Normal file
214
deb_dist/multibootusb-8.5.0/scripts/iso.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*
|
||||||
|
# Name: iso.py
|
||||||
|
# Purpose: Module to manupulate ISO file
|
||||||
|
# Authors: Sundar
|
||||||
|
# Depends: isodump3.py (Authored by Johni Lee for MultiBootUSB)
|
||||||
|
# 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 os
|
||||||
|
import string
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
from .gen import *
|
||||||
|
from .isodump3 import ISO9660
|
||||||
|
from . import _7zip
|
||||||
|
|
||||||
|
|
||||||
|
_iso_cfg_ext_dir = iso_cfg_ext_dir()
|
||||||
|
|
||||||
|
|
||||||
|
def iso_name(iso_link):
|
||||||
|
"""
|
||||||
|
Find the name of an ISO.
|
||||||
|
:return: Name of an ISO (with extension) as string. Returns If not returns None.
|
||||||
|
"""
|
||||||
|
if os.path.exists(iso_link):
|
||||||
|
try:
|
||||||
|
name = os.path.basename(str(iso_link))
|
||||||
|
except:
|
||||||
|
name = None
|
||||||
|
else:
|
||||||
|
name = None
|
||||||
|
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
def iso_basename(iso_link):
|
||||||
|
"""
|
||||||
|
Find the base name of an ISO.
|
||||||
|
:return: Base name (without extension) of a selected ISO as string. If not returns None.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
dir_name = str(os.path.splitext(os.path.basename(str(iso_link)))[0])
|
||||||
|
except:
|
||||||
|
dir_name = None
|
||||||
|
|
||||||
|
return dir_name
|
||||||
|
|
||||||
|
|
||||||
|
def isolinux_bin_exist(iso_link):
|
||||||
|
"""
|
||||||
|
Check if an "isolinux.bin" file exist.
|
||||||
|
:return: True if "isolinux.bin" file exist of False if not.
|
||||||
|
"""
|
||||||
|
if os.path.exists(iso_link):
|
||||||
|
iso_file_list = _7zip.list_iso(iso_link)
|
||||||
|
if any("isolinux.bin" in s.lower() for s in iso_file_list):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def iso_size(iso_link):
|
||||||
|
return os.path.getsize(iso_link)
|
||||||
|
|
||||||
|
|
||||||
|
def is_bootable(iso_link):
|
||||||
|
"""
|
||||||
|
Check if an ISO has the ability to boot.
|
||||||
|
:return: True if ISO is bootable and False if not.
|
||||||
|
"""
|
||||||
|
iso9660fs = ISO9660(iso_link)
|
||||||
|
isBootable = iso9660fs.checkISOBootable()
|
||||||
|
if isBootable:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def isolinux_bin_dir(iso_link):
|
||||||
|
"""
|
||||||
|
Detects "isolinux.bin" directory.
|
||||||
|
:return: path of "isolinux.bin" directory as string.
|
||||||
|
"""
|
||||||
|
if os.path.exists(iso_link):
|
||||||
|
bin_dir = False
|
||||||
|
iso_file_list = _7zip.list_iso(iso_link)
|
||||||
|
if any("isolinux.bin" in s.lower() for s in iso_file_list):
|
||||||
|
for f in iso_file_list:
|
||||||
|
if 'isolinux.bin' in f.lower():
|
||||||
|
if 'efi' not in f.lower(): # Certain distros place their isolinux.bin in to /EFI/BOOT director and we don't want to include them
|
||||||
|
bin_dir = os.path.dirname(f)
|
||||||
|
break
|
||||||
|
|
||||||
|
return bin_dir
|
||||||
|
|
||||||
|
|
||||||
|
def isolinux_bin_path(iso_link):
|
||||||
|
"""
|
||||||
|
Detects pat to "isolinux.bin".
|
||||||
|
:return: path of "isolinux.bin" as a string.
|
||||||
|
"""
|
||||||
|
iso_bin_path = False
|
||||||
|
if isolinux_bin_exist(iso_link) is not False:
|
||||||
|
iso_file_list = _7zip.list_iso(iso_link)
|
||||||
|
for f in iso_file_list:
|
||||||
|
if 'isolinux.bin' in f.lower():
|
||||||
|
iso_bin_path = f
|
||||||
|
break
|
||||||
|
|
||||||
|
return iso_bin_path
|
||||||
|
|
||||||
|
|
||||||
|
def iso_menu_lst_path(iso_link):
|
||||||
|
"""
|
||||||
|
Detects pat to "menu.lst" of grub4dos.
|
||||||
|
:return: path of "menu.lst" as a string.
|
||||||
|
"""
|
||||||
|
menu_lst_path = False
|
||||||
|
iso_file_list = _7zip.list_iso(iso_link)
|
||||||
|
for f in iso_file_list:
|
||||||
|
if 'menu.lst' in f.lower():
|
||||||
|
menu_lst_path = f
|
||||||
|
break
|
||||||
|
|
||||||
|
return menu_lst_path
|
||||||
|
|
||||||
|
|
||||||
|
def integrity(iso_link):
|
||||||
|
"""
|
||||||
|
Check the integrity of an ISO.
|
||||||
|
:return: True if integrity passes or False if it fails.
|
||||||
|
"""
|
||||||
|
return _7zip.test_iso(iso_link)
|
||||||
|
|
||||||
|
|
||||||
|
def iso_file_list(iso_link):
|
||||||
|
"""
|
||||||
|
Function to return the content of an ISO.
|
||||||
|
:return: List of files of an ISO as list.
|
||||||
|
"""
|
||||||
|
return _7zip.list_iso(iso_link)
|
||||||
|
|
||||||
|
|
||||||
|
def isolinux_version(isolinux_bin_path):
|
||||||
|
"""
|
||||||
|
Detect isolinux version shipped by distros.
|
||||||
|
:param isolinux_path: Path to "isolinux.bin"
|
||||||
|
:return: Version number as string.
|
||||||
|
"""
|
||||||
|
version = ["3", "4", "5", "6"]
|
||||||
|
if isolinux_bin_path is not None:
|
||||||
|
sl = list(strings(isolinux_bin_path))
|
||||||
|
for strin in sl:
|
||||||
|
if re.search(r'isolinux ', strin, re.I):
|
||||||
|
for number in version:
|
||||||
|
if re.search(r'isolinux ' + number, strin, re.I):
|
||||||
|
log("\n\nFound syslinux version " + number + "\n\n")
|
||||||
|
return str(number)
|
||||||
|
|
||||||
|
|
||||||
|
def iso_extract_file(iso_link, dest_dir, filter):
|
||||||
|
"""
|
||||||
|
Extract the specific file(s) from an ISO
|
||||||
|
:param dest_dir: Path to destination directory.
|
||||||
|
:param filter: Filter to extract particular file(s)
|
||||||
|
:return: Extract file(s) to destination.
|
||||||
|
"""
|
||||||
|
_7zip.extract_iso(iso_link, dest_dir, filter)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_cfg_file(iso_link):
|
||||||
|
"""
|
||||||
|
Function to extract certain files for auto detecting supported distros
|
||||||
|
:param iso_link: Path to ISO file
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
_pattern = ['.cfg', '.CFG', '.txt', '.TXT', 'isolinux.bin', '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)
|
||||||
|
|
||||||
|
|
||||||
|
def iso_extract_full(iso_link, dest_dir):
|
||||||
|
"""
|
||||||
|
Extract an ISO to destination directory
|
||||||
|
:param dest_dir: Destination path as string.
|
||||||
|
:return: False if it fails or extract ISO files to destination directory.
|
||||||
|
"""
|
||||||
|
_7zip.extract_iso(iso_link, dest_dir)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
#iso_path = '../../../DISTROS/2016/debian-live-8.3.0-amd64-lxde-desktop.iso'
|
||||||
|
iso_path = '../../../DISTROS/2015/super_grub2_disk_hybrid_2.02s3.iso'
|
||||||
|
test_iso_bin_path = os.path.join('test', 'isolinux', 'isolinux.bin')
|
||||||
|
log('iso_name(iso_path) : ', iso_name(iso_path))
|
||||||
|
log('iso_basename(iso_path) : ', iso_basename(iso_path))
|
||||||
|
log('Integrity of ISO is : ', integrity(iso_path))
|
||||||
|
f_list = (iso_file_list(iso_path))
|
||||||
|
if f_list:
|
||||||
|
for f in f_list:
|
||||||
|
log(f)
|
||||||
|
log('isolinux_bin_exist(iso_path) : ', isolinux_bin_exist(iso_path))
|
||||||
|
#log('is_bootable : ', is_bootable(iso_path))
|
||||||
|
log('isolinux_bin_dir() : ', isolinux_bin_dir(iso_path))
|
||||||
|
log('isolinux_bin_path(iso_path) : ', isolinux_bin_path(iso_path))
|
||||||
|
iso_extract_full(iso_path, 'test')
|
||||||
|
iso_extract_file(iso_path, 'test', 'isolinux.bin')
|
||||||
|
log(isolinux_version(test_iso_bin_path))
|
||||||
|
|
806
deb_dist/multibootusb-8.5.0/scripts/isodump3.py
Normal file
806
deb_dist/multibootusb-8.5.0/scripts/isodump3.py
Normal file
@ -0,0 +1,806 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*
|
||||||
|
# Name: isodump3.py
|
||||||
|
# Purpose: Module to list and extract iso files.
|
||||||
|
# Authors: LiQiong Lee (written exclusively for multibootusb)
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License version 3
|
||||||
|
# Credit : I am grateful to LiQiong Lee. He not only wrote this module for multibootusb, but also extended the same
|
||||||
|
# to python3 within short time after request.
|
||||||
|
|
||||||
|
""" ISO9660fs
|
||||||
|
Dump raw meta data of iso9660 file system.
|
||||||
|
Extract directories and files.
|
||||||
|
"""
|
||||||
|
##
|
||||||
|
## Extract directory or file from iso.
|
||||||
|
## Support RRIP.
|
||||||
|
##
|
||||||
|
|
||||||
|
# Author : joni <joni.kartore.lee@gmail.com>
|
||||||
|
# version : 1.0
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import struct
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import stat
|
||||||
|
from ctypes import *
|
||||||
|
from . import config
|
||||||
|
from . import gen
|
||||||
|
|
||||||
|
|
||||||
|
BLOCK_SIZE = 2048
|
||||||
|
S_IFSOCKET = 0o140000
|
||||||
|
S_IFLINK = 0o120000
|
||||||
|
S_IFREG = 0o100000
|
||||||
|
S_IFBLK = 0o060000
|
||||||
|
S_IFCHR = 0o020000
|
||||||
|
S_IFDIR = 0o040000
|
||||||
|
S_IFIFO = 0o010000
|
||||||
|
|
||||||
|
E_SUCCESS = 0
|
||||||
|
E_FAILURE = -1
|
||||||
|
E_DEVICEFILE = -2 # can't write device file
|
||||||
|
|
||||||
|
class PrimaryVolume(Structure):
|
||||||
|
def __init__(self):
|
||||||
|
self.sysIdentifier = ""
|
||||||
|
self.volIdentifier = ""
|
||||||
|
self.volSize = 0
|
||||||
|
self.volSeq = 0
|
||||||
|
self.blockSize = 0
|
||||||
|
self.ptSize = 0
|
||||||
|
self.ptLRd = 0
|
||||||
|
self.fsVer = 0
|
||||||
|
self.rootLoc = 0
|
||||||
|
self.rootTotal = 0
|
||||||
|
|
||||||
|
class Rrip(Structure):
|
||||||
|
def __init__(self):
|
||||||
|
self.offset = -1
|
||||||
|
self.altname = ""
|
||||||
|
self.devH = 0
|
||||||
|
self.devL = 0
|
||||||
|
self.fMode = 0
|
||||||
|
|
||||||
|
class DirRecord(Structure):
|
||||||
|
def __init__(self):
|
||||||
|
self.lenDr = 0
|
||||||
|
self.lenEattr = 0
|
||||||
|
self.locExtent= 0
|
||||||
|
self.lenData = 0
|
||||||
|
self.dtYear = 0
|
||||||
|
self.dtMonth = 0
|
||||||
|
self.dtHour = 0
|
||||||
|
self.dtMinute = 0
|
||||||
|
self.dtSecond = 0
|
||||||
|
self.dtOffset = 0
|
||||||
|
self.fFlag = 0
|
||||||
|
self.fUnitSize= 0
|
||||||
|
self.gapSize = 0
|
||||||
|
self.volSeqNr = 0
|
||||||
|
self.lenFi = 0
|
||||||
|
self.fIdentifier = ""
|
||||||
|
self.sysUseStar = 0
|
||||||
|
self.suspBuf = ""
|
||||||
|
self.rrip = None
|
||||||
|
|
||||||
|
class PathTabelItem(Structure):
|
||||||
|
def __init__(self):
|
||||||
|
self.lenDi = 0
|
||||||
|
self.lenEattr = 0
|
||||||
|
self.locExtenti = 0
|
||||||
|
self.pdirNr = 0
|
||||||
|
self.fIdentifier = ""
|
||||||
|
|
||||||
|
class ISO9660:
|
||||||
|
"""
|
||||||
|
This class can dump iso9660 file system meta data and extract files.
|
||||||
|
Support:
|
||||||
|
RRIP extension.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, isofile):
|
||||||
|
try:
|
||||||
|
f = open(isofile, 'rb')
|
||||||
|
except(IOError):
|
||||||
|
sys.stderr.write("can't open {0}".format(isofile))
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
self.isoFile = f
|
||||||
|
self.priVol = None
|
||||||
|
self.rootDir = None
|
||||||
|
self.rripOffset = -1
|
||||||
|
|
||||||
|
desc_nr = 0
|
||||||
|
while True:
|
||||||
|
desc_nr = desc_nr + 1
|
||||||
|
try:
|
||||||
|
self.isoFile.seek(BLOCK_SIZE*(15+desc_nr))
|
||||||
|
volume_dsc = self.isoFile.read(BLOCK_SIZE)
|
||||||
|
flag = struct.unpack('B',volume_dsc[0:1])[0]
|
||||||
|
if flag == 1:
|
||||||
|
self.__readPrimaryVolume__(volume_dsc)
|
||||||
|
continue
|
||||||
|
if flag == 255:
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
gen.log("Got exception when init iso file:", sys.exc_info()[0])
|
||||||
|
self.priVol = None
|
||||||
|
self.rootDir = None
|
||||||
|
break
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.isoFile.close()
|
||||||
|
|
||||||
|
def __readPrimaryVolume__(self, volume_dsc):
|
||||||
|
""" Dump primary volume descriptor """
|
||||||
|
global BLOCK_SIZE
|
||||||
|
priVol = PrimaryVolume()
|
||||||
|
priVol.sysIdentifier = volume_dsc[8:40]
|
||||||
|
priVol.volIdentifier = volume_dsc[40:72]
|
||||||
|
priVol.volSize = struct.unpack('<L',volume_dsc[80:84])[0]
|
||||||
|
priVol.volSeq = struct.unpack('<H',volume_dsc[124:126])[0]
|
||||||
|
priVol.blockSize = struct.unpack('<H',volume_dsc[128:130])[0]
|
||||||
|
priVol.ptSize = struct.unpack('<L',volume_dsc[132:136])[0]
|
||||||
|
priVol.ptLRd = struct.unpack('<L',volume_dsc[140:144])[0]
|
||||||
|
priVol.fsVer = struct.unpack('B', volume_dsc[881:882])[0]
|
||||||
|
dirRec = self.readDirrecord(volume_dsc[156:190])
|
||||||
|
priVol.rootLoc = dirRec.locExtent
|
||||||
|
priVol.rootTotal = dirRec.lenData
|
||||||
|
BLOCK_SIZE = priVol.blockSize
|
||||||
|
|
||||||
|
# Check RRIP
|
||||||
|
#gen.log ("loc extent(%d)"%(dirRec.locExtent))
|
||||||
|
self.priVol = priVol # readDirItems will use self.priVol
|
||||||
|
root_dir = self.readDirItems(dirRec.locExtent, priVol.rootTotal)[0]
|
||||||
|
rripNode = self.__rripLoop__(root_dir.suspBuf, root_dir.lenDr-root_dir.sysUseStar)
|
||||||
|
if rripNode.offset != -1:
|
||||||
|
self.rripOffset = rripNode.offset
|
||||||
|
#gen.log ("RRIP: rrip_offset %d"%(self.rripOffset))
|
||||||
|
else:
|
||||||
|
gen.log (" This disc don't support RRIP")
|
||||||
|
self.rootDir = root_dir
|
||||||
|
|
||||||
|
# Rrip extension
|
||||||
|
def __rripLoop__(self, desc_buf, len_buf):
|
||||||
|
|
||||||
|
if self.rripOffset > 0:
|
||||||
|
entry_buf = desc_buf[self.rripOffset:]
|
||||||
|
gen.log ("__rripLoop__ offset:%d"%(self.rripOffset))
|
||||||
|
else:
|
||||||
|
entry_buf = desc_buf
|
||||||
|
|
||||||
|
rr = Rrip()
|
||||||
|
while True:
|
||||||
|
ce_blk = 0
|
||||||
|
ce_len = 0
|
||||||
|
ce_off = 0
|
||||||
|
head = 0
|
||||||
|
len_entry = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
#gen.log (("\n%d, %d\n")%(len_buf, head))
|
||||||
|
head += len_entry
|
||||||
|
if len_buf - head < 4: # less than one entry
|
||||||
|
break
|
||||||
|
entry_buf = entry_buf[len_entry:]
|
||||||
|
|
||||||
|
sig1 = struct.unpack("B", entry_buf[0:1])[0]
|
||||||
|
sig2 = struct.unpack("B", entry_buf[1:2])[0]
|
||||||
|
len_entry = struct.unpack("B", entry_buf[2:3])[0]
|
||||||
|
ver = struct.unpack("B", entry_buf[3:4])[0]
|
||||||
|
#if len_entry == 0:
|
||||||
|
# gen.log "Got a entry in __rripLoop__ (%c,%c) of SUSP with length:(%d),version:(%d)-->"%(sig1,sig2,len_entry, ver),
|
||||||
|
if len_entry == 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
if sig1 == ord('S') and sig2 == ord('P'):
|
||||||
|
ck1 = struct.unpack("B", entry_buf[4:5])[0]
|
||||||
|
ck2 = struct.unpack("B", entry_buf[5:6])[0]
|
||||||
|
skip = struct.unpack("B", entry_buf[6:7])[0]
|
||||||
|
#gen.log "-->(0x%x==0xBE,0x%x==EF,%d)" %(ck1, ck2, skip)
|
||||||
|
if ck1 == 0xBE and ck2 == 0xEF:
|
||||||
|
rr.offset = skip
|
||||||
|
continue
|
||||||
|
|
||||||
|
if sig1 == ord('C') and sig2 == ord('E'):
|
||||||
|
ce_blk = struct.unpack("<L", entry_buf[4:8])[0]
|
||||||
|
ce_off = struct.unpack("<L", entry_buf[12:16])[0]
|
||||||
|
ce_len = struct.unpack("<L", entry_buf[20:24])[0]
|
||||||
|
#gen.log "-->(%d,%d,%d)" %(ce_blk, ce_off, ce_len)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if sig1 == ord('N') and sig2 == ord('M'):
|
||||||
|
flag = struct.unpack("B", entry_buf[4:5])[0]
|
||||||
|
#gen.log "-->(flag:(0x%x), name:(%s))" %(flag, entry_buf[5:len_entry])
|
||||||
|
if flag == 0x02: # FLAG_CURRENT
|
||||||
|
rr.altname += "."
|
||||||
|
elif flag == 0x04: # FLAG_PARENT
|
||||||
|
rr.altname += ".."
|
||||||
|
elif flag == 0x01 or flag ==0: # 1:FLAG_CONTINUE
|
||||||
|
rr.altname += entry_buf[5:len_entry].decode()
|
||||||
|
continue
|
||||||
|
|
||||||
|
if sig1 == ord('P') and sig2 == ord('N'):
|
||||||
|
rr.devH = struct.unpack("<L", entry_buf[4:8])[0]
|
||||||
|
rr.devL = struct.unpack("<L", entry_buf[12:16])[0]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if sig1 == ord('E') and sig2 == ord('R'):
|
||||||
|
len_id = struct.unpack("B", entry_buf[4:5])[0]
|
||||||
|
len_des = struct.unpack("B", entry_buf[5:6])[0]
|
||||||
|
len_src = struct.unpack("B", entry_buf[6:7])[0]
|
||||||
|
ext_ver = struct.unpack("B", entry_buf[7:8])[0]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if sig1 == ord('P') and sig2 == ord('X'):
|
||||||
|
rr.fMode = struct.unpack("<L", entry_buf[4:8])[0]
|
||||||
|
s_link = struct.unpack("<L", entry_buf[12:16])[0]
|
||||||
|
uid = struct.unpack("<L", entry_buf[20:24])[0]
|
||||||
|
gid = struct.unpack("<L", entry_buf[28:32])[0]
|
||||||
|
continue
|
||||||
|
|
||||||
|
if sig1 == ord('S') and sig2 == ord('T'):
|
||||||
|
return rr
|
||||||
|
|
||||||
|
#gen.log "\n"
|
||||||
|
# while (True) end #
|
||||||
|
|
||||||
|
if ce_len > 0:
|
||||||
|
#gen.log " Read CE block, (%d, %d, %d)"%(ce_blk, ce_len, ce_off)
|
||||||
|
self.isoFile.seek(ce_blk*BLOCK_SIZE + ce_off)
|
||||||
|
entry_buf = self.isoFile.read(ce_len)
|
||||||
|
len_buf = ce_len
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
# while (True) end #
|
||||||
|
return rr
|
||||||
|
|
||||||
|
def checkISOBootable(self):
|
||||||
|
""" Struct of a classical generic MBR.
|
||||||
|
|
||||||
|
0x0000 Bootstrap Code area
|
||||||
|
-----------------------------------------
|
||||||
|
0x01BE
|
||||||
|
.. Partition table
|
||||||
|
0x01EE
|
||||||
|
------------------------------------------
|
||||||
|
0x01FE 55h
|
||||||
|
Boot signature
|
||||||
|
0x01FF AAh
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.isoFile.seek(0x01FE)
|
||||||
|
h = self.isoFile.read(2)
|
||||||
|
s1 = struct.unpack('B', h[0:1])[0]
|
||||||
|
s2 = struct.unpack('B', h[1:2])[0]
|
||||||
|
|
||||||
|
#gen.log "-->(0x%x,0x%x)" %(s1, s2)
|
||||||
|
|
||||||
|
if (s1 == 0x55) and (s2 == 0xAA):
|
||||||
|
result = True # "Bootable"
|
||||||
|
else:
|
||||||
|
result = False # "Not bootable"
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def searchDir(self, path):
|
||||||
|
# /root/abc/ - ['', 'root', 'abc', '']
|
||||||
|
# /root/abc - ['', 'root', 'abc']
|
||||||
|
# / - ['', '']
|
||||||
|
dircomps = path.split('/')
|
||||||
|
if dircomps[-1] == '':
|
||||||
|
dircomps.pop()
|
||||||
|
if dircomps == []:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.priVol == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(dircomps) == 1:
|
||||||
|
return self.rootDir
|
||||||
|
|
||||||
|
pdir_loc = self.priVol.rootLoc
|
||||||
|
pdir_len = self.priVol.rootTotal
|
||||||
|
i_dircomp = 1
|
||||||
|
|
||||||
|
while True:
|
||||||
|
found = False
|
||||||
|
dirs = self.readDirItems(pdir_loc, pdir_len)
|
||||||
|
for item in dirs:
|
||||||
|
if item.fIdentifier == dircomps[i_dircomp]:
|
||||||
|
pdir_loc = item.locExtent
|
||||||
|
pdir_len = item.lenData
|
||||||
|
found = True
|
||||||
|
#gen.log "found (%s)"%(dircomps[i_dircomp])
|
||||||
|
break
|
||||||
|
if found: # advacne
|
||||||
|
if i_dircomp < len(dircomps)-1:
|
||||||
|
i_dircomp = i_dircomp + 1
|
||||||
|
else:
|
||||||
|
return item
|
||||||
|
else:
|
||||||
|
gen.log ("can't find " + dircomps[i_dircomp])
|
||||||
|
return None
|
||||||
|
|
||||||
|
def readDirrecord(self, desc_buf):
|
||||||
|
""" Dump file dirctory record
|
||||||
|
Return a directory record reading from a Directory Descriptors.
|
||||||
|
"""
|
||||||
|
dirRec = DirRecord()
|
||||||
|
try:
|
||||||
|
dirRec.lenDr = struct.unpack("B", desc_buf[0:1])[0]
|
||||||
|
if dirRec.lenDr == 0:
|
||||||
|
return None
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
dirRec.lenEattr = struct.unpack("B", desc_buf[1:2])[0]
|
||||||
|
dirRec.locExtent = struct.unpack("<L", desc_buf[2:6])[0]
|
||||||
|
dirRec.lenData = struct.unpack("<L", desc_buf[10:14])[0]
|
||||||
|
dirRec.fFlag = struct.unpack("B", desc_buf[25:26])[0]
|
||||||
|
dirRec.fUnitSize = struct.unpack("B", desc_buf[26:27])[0]
|
||||||
|
dirRec.gapSize = struct.unpack("B", desc_buf[27:28])[0]
|
||||||
|
dirRec.volSeqNr = struct.unpack("<H", desc_buf[28:30])[0]
|
||||||
|
dirRec.lenFi = struct.unpack("B", desc_buf[32:33])[0]
|
||||||
|
dirRec.fIdentifier = ""
|
||||||
|
if dirRec.lenFi == 1:
|
||||||
|
dirRec.fIdentifier = struct.unpack("B", desc_buf[33:34])[0]
|
||||||
|
if dirRec.fIdentifier == 0:
|
||||||
|
dirRec.fIdentifier = "."
|
||||||
|
elif dirRec.fIdentifier == 1:
|
||||||
|
dirRec.fIdentifier = ".."
|
||||||
|
else:
|
||||||
|
dirRec.fIdentifier = desc_buf[33:33+dirRec.lenFi].decode()
|
||||||
|
idx = dirRec.fIdentifier.rfind(";")
|
||||||
|
if idx != -1:
|
||||||
|
dirRec.fIdentifier = dirRec.fIdentifier[0:idx]
|
||||||
|
|
||||||
|
dirRec.suspBuf = ""
|
||||||
|
dirRec.sysUseStar = 34 + dirRec.lenFi -1
|
||||||
|
if dirRec.lenFi % 2 == 0:
|
||||||
|
dirRec.sysUseStar += 1
|
||||||
|
|
||||||
|
# Extension Attribute
|
||||||
|
if dirRec.lenDr > dirRec.sysUseStar+4:
|
||||||
|
if dirRec.locExtent == self.priVol.rootLoc:
|
||||||
|
dirRec.suspBuf = desc_buf[dirRec.sysUseStar:dirRec.lenDr]
|
||||||
|
suspBuf = desc_buf[dirRec.sysUseStar:dirRec.lenDr]
|
||||||
|
if self.rripOffset != -1:
|
||||||
|
rripNode = self.__rripLoop__(suspBuf, dirRec.lenDr-dirRec.sysUseStar)
|
||||||
|
dirRec.rrip = rripNode
|
||||||
|
if rripNode != None:
|
||||||
|
if rripNode.altname != "":
|
||||||
|
dirRec.fIdentifier = rripNode.altname
|
||||||
|
dirRec.lenFi = len(rripNode.altname)
|
||||||
|
#gen.log "rrip_altname: %s"%(dirRec.fIdentifier)
|
||||||
|
# if rripNode end #
|
||||||
|
# if self.rripOffset != -1 end #
|
||||||
|
# if dirRec.lenDr > .. end #
|
||||||
|
return dirRec
|
||||||
|
|
||||||
|
def readDirItems(self, block_nr=None, total=None):
|
||||||
|
""" Read file dirctory records
|
||||||
|
Read dirctory records from 'block_nr' with a length of 'total'.
|
||||||
|
Return a list containing directory records(DirRecord).
|
||||||
|
"""
|
||||||
|
dirs = []
|
||||||
|
total_blk = (total+BLOCK_SIZE-1)//BLOCK_SIZE
|
||||||
|
i_blk = 0
|
||||||
|
while i_blk < total_blk:
|
||||||
|
self.isoFile.seek((block_nr+i_blk)*BLOCK_SIZE)
|
||||||
|
desc_buf = self.isoFile.read(BLOCK_SIZE)
|
||||||
|
i_blk = i_blk + 1
|
||||||
|
while True:
|
||||||
|
dirItem = self.readDirrecord(desc_buf)
|
||||||
|
if dirItem == None:
|
||||||
|
break
|
||||||
|
|
||||||
|
dirs.append(dirItem)
|
||||||
|
if desc_buf.__len__() > dirItem.lenDr:
|
||||||
|
desc_buf = desc_buf[dirItem.lenDr:]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return dirs
|
||||||
|
|
||||||
|
def readPathtableL(self):
|
||||||
|
""" Read path table of L typde """
|
||||||
|
if self.priVol == None:
|
||||||
|
return
|
||||||
|
block_nr = self.priVol.ptLRd
|
||||||
|
total = self.priVol.ptSize
|
||||||
|
|
||||||
|
path_table = []
|
||||||
|
self.isoFile.seek(block_nr*BLOCK_SIZE)
|
||||||
|
ptbuf = self.isoFile.read((BLOCK_SIZE * ((total+BLOCK_SIZE-1)//BLOCK_SIZE)))
|
||||||
|
i = 0
|
||||||
|
r_size = 0
|
||||||
|
while True :
|
||||||
|
i = i+1
|
||||||
|
t = PathTabelItem()
|
||||||
|
|
||||||
|
t.lenDi = struct.unpack('B', ptbuf[0:1])[0]
|
||||||
|
t.lenEattr = struct.unpack('B', ptbuf[1:2])[0]
|
||||||
|
t.locExtent = struct.unpack('<L', ptbuf[2:6])[0]
|
||||||
|
t.pdirNr = struct.unpack('<H', ptbuf[6:8])[0]
|
||||||
|
t.fIdentifier = ptbuf[8:8+t.lenDi].decode()
|
||||||
|
path_table.append(t)
|
||||||
|
if t.lenDi % 2 :
|
||||||
|
len_pd = 1
|
||||||
|
else:
|
||||||
|
len_pd = 0
|
||||||
|
|
||||||
|
r_size += 9+t.lenDi-1+len_pd
|
||||||
|
if r_size >= total:
|
||||||
|
break
|
||||||
|
ptbuf = ptbuf[9+t.lenDi-1+len_pd:]
|
||||||
|
# while True
|
||||||
|
return path_table
|
||||||
|
|
||||||
|
# @path -- path within iso file system.
|
||||||
|
# @output -- what local path you want write to.
|
||||||
|
# @pattern -- regular expression.
|
||||||
|
# @r -- recursion flag, write the whole sub-directories or not.
|
||||||
|
# @all_type -- which file type should be writed.
|
||||||
|
# False: Write regular type files only.
|
||||||
|
# True: Wirte all types files (regular, device file, link, socket, etc)
|
||||||
|
def writeDir(self, path, output, pattern="", r=True, all_type=False):
|
||||||
|
""" Extract a directory
|
||||||
|
Return 0 means success otherwise failure.
|
||||||
|
"""
|
||||||
|
d = self.searchDir(path)
|
||||||
|
if d != None:
|
||||||
|
if output.endswith("/"):
|
||||||
|
output = output[0:-1]
|
||||||
|
# Try to make target directory.
|
||||||
|
if not os.path.exists(output):
|
||||||
|
try:
|
||||||
|
os.makedirs(output)
|
||||||
|
except(OSError):
|
||||||
|
sys.stderr.write("can't make dirs({0})\n".format(output))
|
||||||
|
return E_FAILURE
|
||||||
|
pp = None
|
||||||
|
if pattern != "":
|
||||||
|
p = r'{0}'.format(pattern)
|
||||||
|
pp = re.compile(p)
|
||||||
|
#gen.log "writeDir: flag(%x)"%(d.fFlag)
|
||||||
|
if d.fFlag & 0x02 == 0x02:
|
||||||
|
# Check if a clean directory.
|
||||||
|
#try:
|
||||||
|
# if len(os.listdir(output)) > 0:
|
||||||
|
# sys.stderr.write("The target directory is not empty\n")
|
||||||
|
# return E_FAILURE
|
||||||
|
#except(OSError):
|
||||||
|
# sys.stderr.write("can't access dirs({0})\n".format(p))
|
||||||
|
# return E_FAILURE
|
||||||
|
self.writeDir_r(output, d, pp, r, all_type)
|
||||||
|
return E_SUCCESS
|
||||||
|
else:
|
||||||
|
return self.writeFile(d, output+path, all_type)
|
||||||
|
else:
|
||||||
|
return E_FAILURE
|
||||||
|
|
||||||
|
def writeDir_r(self, det_dir, dire, pp, r, all_type):
|
||||||
|
#gen.log "writeDir_r:(%s)"%(det_dir)
|
||||||
|
dirs = self.readDirItems(dire.locExtent, dire.lenData)
|
||||||
|
for d in dirs:
|
||||||
|
if not d.fIdentifier in [".", ".."]:
|
||||||
|
if (pp != None) and (pp.search(d.fIdentifier) == None):
|
||||||
|
match = False
|
||||||
|
else:
|
||||||
|
match = True
|
||||||
|
#gen.log "mathing %s, %s, (%x)"%(match, d.fIdentifier, d.fFlag)
|
||||||
|
p = det_dir + "/" + d.fIdentifier
|
||||||
|
if d.fFlag & 0x02 == 0x02:
|
||||||
|
if not os.path.exists(p):
|
||||||
|
os.makedirs(p, 0o777)
|
||||||
|
if r:
|
||||||
|
if match:
|
||||||
|
self.writeDir_r(p, d, None, r, all_type) # Don't need to match subdirectory.
|
||||||
|
else:
|
||||||
|
self.writeDir_r(p, d, pp, r, all_type)
|
||||||
|
elif match:
|
||||||
|
self.writeFile(d, p, all_type)
|
||||||
|
# if not d.fIdentifier end #
|
||||||
|
# for d in dirs end #
|
||||||
|
|
||||||
|
def writeFile(self, dirRec, detFile, all_type):
|
||||||
|
""" Write a file to detFile
|
||||||
|
Return 0 means success otherwise failure.
|
||||||
|
"""
|
||||||
|
global file_out
|
||||||
|
if detFile == "" or dirRec == None:
|
||||||
|
sys.stderr.write("can't write file\n")
|
||||||
|
return E_FAILURE
|
||||||
|
|
||||||
|
#gen.log "write file (%s)"%(detFile)
|
||||||
|
config.status_text = detFile
|
||||||
|
|
||||||
|
dirname = os.path.dirname(detFile)
|
||||||
|
if not os.path.exists(dirname):
|
||||||
|
try:
|
||||||
|
os.makedirs(dirname, 0o777)
|
||||||
|
except(OSError):
|
||||||
|
sys.stderr.write("can't makedirs\n")
|
||||||
|
return E_FAILURE
|
||||||
|
|
||||||
|
if all_type == True:
|
||||||
|
# device file
|
||||||
|
if dirRec.rrip != None and (dirRec.rrip.devH != 0 or dirRec.rrip.devL != 0):
|
||||||
|
#fFlag == 0
|
||||||
|
high = dirRec.rrip.devH
|
||||||
|
low = dirRec.rrip.devL
|
||||||
|
if high == 0:
|
||||||
|
device = os.makedev(os.major(low), os.minor(low))
|
||||||
|
else:
|
||||||
|
device = os.makedev(high, os.minor(low))
|
||||||
|
try:
|
||||||
|
mode = dirRec.rrip.fMode & 0o770000
|
||||||
|
if mode == S_IFCHR:
|
||||||
|
os.mknod(detFile, 0o777|stat.S_IFCHR, device)
|
||||||
|
elif mode == S_IFBLK:
|
||||||
|
os.mknod(detFile, 0o777|stat.S_IFBLK, device)
|
||||||
|
except(OSError):
|
||||||
|
sys.stderr.write("can't mknode, maybe no permission\n")
|
||||||
|
return E_DEVICEFILE
|
||||||
|
|
||||||
|
return E_SUCCESS
|
||||||
|
|
||||||
|
loc = dirRec.locExtent
|
||||||
|
length = dirRec.lenData
|
||||||
|
self.isoFile.seek(BLOCK_SIZE * loc)
|
||||||
|
#gen.log "file length(%d)"%(length)
|
||||||
|
r_size = BLOCK_SIZE*1024*50 #100M cache
|
||||||
|
|
||||||
|
try:
|
||||||
|
f_output = open(detFile, 'wb', r_size)
|
||||||
|
except(IOError):
|
||||||
|
sys.stderr.write("can't open{0} for write\n".format(detFile))
|
||||||
|
return E_FAILURE
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if length == 0:
|
||||||
|
break
|
||||||
|
elif length <= r_size:
|
||||||
|
r_size = length
|
||||||
|
length = 0
|
||||||
|
else:
|
||||||
|
length = length - r_size
|
||||||
|
|
||||||
|
buf = self.isoFile.read(r_size)
|
||||||
|
f_output.write(buf)
|
||||||
|
f_output.flush()
|
||||||
|
# while True end.
|
||||||
|
f_output.close()
|
||||||
|
return E_SUCCESS
|
||||||
|
|
||||||
|
def readDir(self, dir_path, r=True):
|
||||||
|
file_list = []
|
||||||
|
d = self.searchDir(dir_path)
|
||||||
|
if d != None:
|
||||||
|
if (d.fFlag & 0x02) == 0x02:
|
||||||
|
#gen.log "readDir (%x, %x)"%(d.locExtent, d.lenData)
|
||||||
|
if dir_path.endswith("/"):
|
||||||
|
dir_path = dir_path[0:-1]
|
||||||
|
self.readDir_r(file_list, dir_path, d, r)
|
||||||
|
# if (d.fFlag & 0x02) == 0x02: #
|
||||||
|
# if d != None:
|
||||||
|
return file_list
|
||||||
|
|
||||||
|
def readDir_r(self, file_list, dir_path, dire, r):
|
||||||
|
if (dire.fFlag & 0x02) != 0x02:
|
||||||
|
return
|
||||||
|
dirs = self.readDirItems(dire.locExtent, dire.lenData)
|
||||||
|
for d in dirs:
|
||||||
|
if not d.fIdentifier in [".", ".."]:
|
||||||
|
p = dir_path + "/" + d.fIdentifier
|
||||||
|
file_list.append(p)
|
||||||
|
if r:
|
||||||
|
self.readDir_r(file_list, p, d, r)
|
||||||
|
# if not d.fIdentifier #
|
||||||
|
# for d in dirs: #
|
||||||
|
|
||||||
|
def checkIntegrity(self):
|
||||||
|
if self.priVol == None: # no primary volume
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.priVol.ptSize == 0: # empty ?
|
||||||
|
return True
|
||||||
|
|
||||||
|
path_table = self.readPathtableL()
|
||||||
|
if path_table == []: # pathtable record is broken.
|
||||||
|
return False
|
||||||
|
|
||||||
|
# find last file item to check
|
||||||
|
for dr in reversed(path_table):
|
||||||
|
#gen.log dr.fIdentifier
|
||||||
|
dirs = self.readDirItems(dr.locExtent, BLOCK_SIZE)
|
||||||
|
if len(dirs) > 2:
|
||||||
|
dot = dirs[0]
|
||||||
|
dirs2 = self.readDirItems(dot.locExtent, dot.lenData) # get the whole items.
|
||||||
|
for dr2 in reversed(dirs2): # search last file item.
|
||||||
|
if dr2.fFlag == 0:
|
||||||
|
#gen.log "get last file(%s)"%(dr2.fIdentifier)
|
||||||
|
try:
|
||||||
|
#self.isoFile.seek(BLOCK_SIZE * dr2.locExtent+dr2.lenData)
|
||||||
|
lastfile_end = BLOCK_SIZE * dr2.locExtent + dr2.lenData
|
||||||
|
self.isoFile.seek(0, os.SEEK_END)
|
||||||
|
iso_end = self.isoFile.tell()
|
||||||
|
#gen.log ("%d-->%d")%(lastfile_end, iso_end)
|
||||||
|
if iso_end >= lastfile_end:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except(IOError):
|
||||||
|
#gen.log "exception when seek. iso is broken"
|
||||||
|
return False
|
||||||
|
elif len(dirs) < 2: # Dir record is broken. At least, should have two entries.
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
def dump_dir_record(dirs):
|
||||||
|
""" Dump all the file dirctory records contained in desc_buf """
|
||||||
|
|
||||||
|
gen.log("Dump file/deirectory record")
|
||||||
|
gen.log("===========================", end="\n")
|
||||||
|
if dirs != None:
|
||||||
|
for f in dirs:
|
||||||
|
gen.log("length of directory record:(0x%x), length of extend attribute:(%d), \
|
||||||
|
location of record:(%d)BLOCK->(0x%x), data length(%d) size of file unit:(%d), \
|
||||||
|
interleave gap size:(%d), file flag:(0x%x),name length:(%d) identify:(%s)\n" \
|
||||||
|
%(f.lenDr, f.lenEattr, f.locExtent, f.locExtent*BLOCK_SIZE,f.lenData, \
|
||||||
|
f.fUnitSize, f.gapSize, f.fFlag, f.lenFi, f.fIdentifier))
|
||||||
|
|
||||||
|
def dump_pathtable_L(path_table):
|
||||||
|
""" Dump path table of L typde """
|
||||||
|
|
||||||
|
gen.log("Dump path table")
|
||||||
|
gen.log("================", end="\n")
|
||||||
|
#path_table = readPathtableL()
|
||||||
|
i = 0
|
||||||
|
for t in path_table:
|
||||||
|
i = i + 1
|
||||||
|
if t.lenDi == 1:
|
||||||
|
if t.fIdentifier in [0, 1]:
|
||||||
|
gen.log("is a root directory(%d)" %(is_root))
|
||||||
|
gen.log("%d->length of identify:(%d), length of extend attribute:(%d), \
|
||||||
|
local:(%d)->(0x%x), parent dir number:(%d), identify:(%s)\n" \
|
||||||
|
%(i, t.lenDi, t.lenEattr, t.locExtent, t.locExtent*BLOCK_SIZE, t.pdirNr, t.fIdentifier))
|
||||||
|
|
||||||
|
def dump_primary_volume(privol=None):
|
||||||
|
""" Dump primary volume descriptor """
|
||||||
|
|
||||||
|
if privol == None:
|
||||||
|
gen.log("Can't dump, maybe iso is broken")
|
||||||
|
return
|
||||||
|
gen.log("===== Dump primary volume descriptor ==")
|
||||||
|
|
||||||
|
gen.log("System Identifier:(%s)" %(privol.sysIdentifier.decode()))
|
||||||
|
gen.log("Volume Identifier:(%s)" %privol.volIdentifier.decode())
|
||||||
|
gen.log("Volume Space size:(0x%x)BLOCKS(2kB)" %privol.volSize)
|
||||||
|
gen.log("Volume sequence number:(%d)" %(privol.volSeq))
|
||||||
|
gen.log("logic block size:(0x%x)" %(privol.blockSize))
|
||||||
|
gen.log("Volume path talbe L's BLOCK number is :(0x%x-->0x%x), size(%d)" %(privol.ptLRd, privol.ptLRd*BLOCK_SIZE, privol.ptSize))
|
||||||
|
# gen.log "Abstract File Identifier: (%s)" %(volume_dsc[739:776])
|
||||||
|
# gen.log "Bibliographic File Identifier: (%s)" %(volume_dsc[776:813])
|
||||||
|
gen.log("pathtable locate (%d)" %(privol.ptLRd))
|
||||||
|
gen.log("File Structure Version:(%d)" %(privol.fsVer))
|
||||||
|
gen.log("Root directory is at (%d)block, have(0x%x)bytes" %(privol.rootLoc, privol.rootTotal))
|
||||||
|
# dump_dir_record(None, 23, 1)
|
||||||
|
|
||||||
|
def dump_boot_record(volume_dsc):
|
||||||
|
""" Dump boot record """
|
||||||
|
|
||||||
|
gen.log("===== Dump boot record ==")
|
||||||
|
std_identifier = volume_dsc[1:6]
|
||||||
|
gen.log("Standard Identifier:(%s)" %std_identifier)
|
||||||
|
|
||||||
|
vol_ver = struct.unpack('B', volume_dsc[6])
|
||||||
|
gen.log("Volume descriptor version:(%d)" %vol_ver)
|
||||||
|
|
||||||
|
bootsys_identifier = volume_dsc[7:39]
|
||||||
|
gen.log("boot system identifier(%s)" %bootsys_identifier)
|
||||||
|
|
||||||
|
boot_identifier = volume_dsc[39:71]
|
||||||
|
gen.log("boot identifier(%s)" %boot_identifier)
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
""" Prompt user how to use """
|
||||||
|
gen.log("""
|
||||||
|
Usage: isodump dump-what [options] iso-file
|
||||||
|
[dump-what]
|
||||||
|
-----------
|
||||||
|
boot - Dump boot record.
|
||||||
|
primary-volume - Dump primary volume.
|
||||||
|
pathtable - Dump path table.
|
||||||
|
dir-record [block number] [length] - Dump a raw data of a Directory Record
|
||||||
|
|
||||||
|
iso:/dir [-r] [-o output] [-p pattern] - Dump a dirctory or file to [output]
|
||||||
|
-r recursively visit directory.
|
||||||
|
-p spcify a Regular expression pattern for re.search(pattern,).
|
||||||
|
|
||||||
|
isodump xx.iso - Dump the root directory
|
||||||
|
isodump pathtable xx.iso - Dump the path table record.
|
||||||
|
|
||||||
|
isodump iso:/ -r xx.iso
|
||||||
|
-- Dump the root directory of xx.iso recursively.
|
||||||
|
|
||||||
|
isodump iso:/ -r -o /tmp/iso xx.iso
|
||||||
|
-- Extract the iso to /tmp/iso/.
|
||||||
|
|
||||||
|
isodump iso:/boot -o /tmp/iso/boot xx.iso
|
||||||
|
-- Extract the /boot directory of xx.iso to /tmp/iso/boot.
|
||||||
|
|
||||||
|
isodump iso:/boot/grup.cfg -o /tmp/grub.cfg xx.iso
|
||||||
|
-- Extract the file "grup.cfg" to "/tmp/grub.cfg"
|
||||||
|
|
||||||
|
isodump iso:/boot -r -o /tmp/iso -p "*.cfg" xx.iso
|
||||||
|
-- Extract any files or directories under /boot maching "*.cfg" to /tmp/iso/.
|
||||||
|
""")
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
argv = sys.argv
|
||||||
|
if len(argv) < 3:
|
||||||
|
usage()
|
||||||
|
|
||||||
|
iso9660fs = ISO9660(argv[-1])
|
||||||
|
integrity = iso9660fs.checkIntegrity()
|
||||||
|
if integrity == False:
|
||||||
|
gen.log("iso file is broken")
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
dump_what = argv[1]
|
||||||
|
|
||||||
|
if dump_what == "primary-volume":
|
||||||
|
dump_primary_volume(iso9660fs.priVol)
|
||||||
|
elif dump_what == "pathtable":
|
||||||
|
path_table = iso9660fs.readPathtableL()
|
||||||
|
dump_pathtable_L(path_table)
|
||||||
|
if dump_what == "dir-record":
|
||||||
|
if len(argv) == 5:
|
||||||
|
gen.log("dump dir-record (%s, %s)"%(argv[2], argv[3]))
|
||||||
|
dirs = iso9660fs.readDirItems(int(argv[2]), int(argv[3]))
|
||||||
|
dump_dir_record(dirs)
|
||||||
|
else:
|
||||||
|
usage()
|
||||||
|
elif dump_what.startswith("iso:"):
|
||||||
|
o_path = ""
|
||||||
|
r = False
|
||||||
|
o = False
|
||||||
|
p = False
|
||||||
|
pattern = ""
|
||||||
|
for arg in argv[2:-1]:
|
||||||
|
if arg == "-r":
|
||||||
|
r = True
|
||||||
|
o = False
|
||||||
|
p = False
|
||||||
|
elif arg == "-o":
|
||||||
|
o = True
|
||||||
|
p = False
|
||||||
|
elif arg == "-p":
|
||||||
|
o = False
|
||||||
|
p = True
|
||||||
|
elif o == True:
|
||||||
|
o_path = arg
|
||||||
|
o = False
|
||||||
|
elif p == True:
|
||||||
|
pattern = arg
|
||||||
|
p = False
|
||||||
|
|
||||||
|
isodir = dump_what[4:]
|
||||||
|
if o_path == "":
|
||||||
|
gen.log("dump_dir(%s)"%(isodir))
|
||||||
|
filelist = iso9660fs.readDir(isodir, r)
|
||||||
|
if filelist == []:
|
||||||
|
gen.log("can't read any file from (%s)"%(isodir))
|
||||||
|
else:
|
||||||
|
for f in filelist:
|
||||||
|
gen.log(f)
|
||||||
|
else:
|
||||||
|
gen.log("writeDir(%s)->(%s) with pattern(%s)"%(isodir, o_path, pattern))
|
||||||
|
sys.exit(iso9660fs.writeDir(isodir, o_path, pattern, r, True))
|
||||||
|
|
85
deb_dist/multibootusb-8.5.0/scripts/mbusb_cli.py
Normal file
85
deb_dist/multibootusb-8.5.0/scripts/mbusb_cli.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: mbusb_cli.py
|
||||||
|
# Purpose: Module to handle command line options of multibootusb
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
from . import usb
|
||||||
|
from . import gen
|
||||||
|
from .iso import *
|
||||||
|
from .uninstall_distro import *
|
||||||
|
from .distro import *
|
||||||
|
from .syslinux import *
|
||||||
|
from .install import *
|
||||||
|
|
||||||
|
|
||||||
|
def read_input_uninstall():
|
||||||
|
response = False
|
||||||
|
try:
|
||||||
|
response = int(input("Please enter the number against the distro you need to uninstall: "))
|
||||||
|
except ValueError:
|
||||||
|
log('\nPlease provide valid integer from the above list.\n')
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def cli_install_distro():
|
||||||
|
'''
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
if os.getuid() != 0:
|
||||||
|
exit("You need to have root privileges to run this script.\nPlease try again using 'sudo'. Exiting.")
|
||||||
|
elif platform.system() == 'Windows':
|
||||||
|
|
||||||
|
if admin.isUserAdmin():
|
||||||
|
admin.elevate()
|
||||||
|
'''
|
||||||
|
|
||||||
|
log('Starting multibootusb from Command line...')
|
||||||
|
if usb.is_block(config.usb_disk) is False:
|
||||||
|
log(config.usb_disk, 'is not a valid device partition...')
|
||||||
|
exit(1)
|
||||||
|
elif integrity(config.iso_link) is not True:
|
||||||
|
log(config.iso_link, ' failed to pass integrity check...')
|
||||||
|
exit(1)
|
||||||
|
elif size_not_enough(config.iso_link, config.usb_disk) is True:
|
||||||
|
log(config.usb_disk, 'does not have enough space...')
|
||||||
|
else:
|
||||||
|
prepare_mbusb_host_dir()
|
||||||
|
extract_cfg_file(config.iso_link)
|
||||||
|
_distro = distro(iso_cfg_ext_dir(), config.iso_link)
|
||||||
|
log('Detected distro type is', _distro)
|
||||||
|
if _distro is not None:
|
||||||
|
log('\nSelected ISO is :', quote(iso_name(config.iso_link)))
|
||||||
|
log('Selected target device is:', quote(config.usb_disk), '\n')
|
||||||
|
log('Please confirm the option.')
|
||||||
|
log('Y/y/Yes/yes/YES or N/n/No/no/NO')
|
||||||
|
if read_input_yes() is True:
|
||||||
|
config.distro = _distro
|
||||||
|
copy_mbusb_dir_usb(config.usb_disk)
|
||||||
|
install_progress()
|
||||||
|
syslinux_distro_dir(config.usb_disk, config.iso_link, _distro)
|
||||||
|
syslinux_default(config.usb_disk)
|
||||||
|
update_distro_cfg_files(config.iso_link, config.usb_disk, _distro)
|
||||||
|
else:
|
||||||
|
log('Sorry', iso_name(config.iso_link), 'is not supported at the moment\n'
|
||||||
|
'Please report tissue at https://github.com/mbusb/multibootusb/issues')
|
||||||
|
|
||||||
|
|
||||||
|
def cli_uninstall_distro():
|
||||||
|
distro_list = install_distro_list()
|
||||||
|
if distro_list is not None:
|
||||||
|
for index, _distro_dir in enumerate(distro_list):
|
||||||
|
log(index, '--->>', _distro_dir)
|
||||||
|
user_input = read_input_uninstall()
|
||||||
|
if user_input is not False:
|
||||||
|
for index, _distro_dir in enumerate(distro_list):
|
||||||
|
if index == user_input:
|
||||||
|
config.uninstall_distro_dir_name = _distro_dir
|
||||||
|
unin_distro()
|
||||||
|
else:
|
||||||
|
log('No distro installed on', config.usb_disk)
|
640
deb_dist/multibootusb-8.5.0/scripts/mbusb_gui.py
Normal file
640
deb_dist/multibootusb-8.5.0/scripts/mbusb_gui.py
Normal file
@ -0,0 +1,640 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: mbusb_gui.py
|
||||||
|
# Purpose: Module to handle multibootusb through gui
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from scripts.gui.ui_multibootusb import Ui_Dialog
|
||||||
|
from . import usb
|
||||||
|
from .gen import *
|
||||||
|
from .install import *
|
||||||
|
from .uninstall_distro import *
|
||||||
|
from .syslinux import *
|
||||||
|
from .distro import *
|
||||||
|
from .iso import *
|
||||||
|
from .imager import Imager, dd_linux, dd_win
|
||||||
|
from . import persistence
|
||||||
|
from . import config
|
||||||
|
from . import admin
|
||||||
|
from . import qemu
|
||||||
|
from .update_cfg_file import update_distro_cfg_files
|
||||||
|
|
||||||
|
|
||||||
|
class AppGui(qemu.Qemu, Imager, QtWidgets.QDialog, Ui_Dialog):
|
||||||
|
"""
|
||||||
|
Main multibootusb GUI manipulation class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
QtWidgets.QDialog.__init__(self)
|
||||||
|
self.ui = Ui_Dialog()
|
||||||
|
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)
|
||||||
|
self.ui.comboBox.activated[str].connect(self.onComboChange)
|
||||||
|
# self.ui.create.clicked.connect(self.update_progress)
|
||||||
|
self.ui.create.clicked.connect(self.onCreateClick)
|
||||||
|
self.ui.slider_persistence.valueChanged.connect(self.update_slider_text)
|
||||||
|
self.ui.uninstall.clicked.connect(self.OnUninstallClick)
|
||||||
|
|
||||||
|
# ISO Imager Tab
|
||||||
|
self.ui.pushButton.clicked.connect(self.on_Imager_Browse_iso_Click)
|
||||||
|
self.ui.comboBox_2.activated[str].connect(self.onImagerComboChange)
|
||||||
|
self.ui.pushbtn_imager_refreshusb.clicked.connect(self.onRefereshClick)
|
||||||
|
self.ui.imager_close.clicked.connect(self.on_close_Click)
|
||||||
|
self.ui.imager_write.clicked.connect(self.dd_write)
|
||||||
|
|
||||||
|
# Syslinux Tab
|
||||||
|
self.ui.install_syslinux.clicked.connect(self.onInstall_syslinuxClick)
|
||||||
|
self.ui.edit_syslinux.clicked.connect(self.onedit_syslinux)
|
||||||
|
|
||||||
|
# QEMU Tab
|
||||||
|
self.ui.browse_iso_qemu.clicked.connect(self.on_Qemu_Browse_iso_Click)
|
||||||
|
self.ui.boot_iso_qemu.clicked.connect(self.on_Qemu_Boot_iso_Click)
|
||||||
|
self.ui.boot_usb_qemu.clicked.connect(lambda: self.on_Qemu_Boot_usb_Click(str(self.ui.comboBox.currentText())))
|
||||||
|
# self.ui.tabWidget.removeTab(3)
|
||||||
|
|
||||||
|
# Update progressbar and status (Main ISO install)
|
||||||
|
self.progress_thread_install = GuiInstallProgress()
|
||||||
|
self.progress_thread_install.finished.connect(self.install_syslinux)
|
||||||
|
self.progress_thread_install.update.connect(self.ui.progressBar.setValue)
|
||||||
|
self.progress_thread_install.status.connect(self.ui.status.setText)
|
||||||
|
|
||||||
|
# Update progressbar and status (Uninstall from previous install)
|
||||||
|
self.progress_thread_uninstall = GuiUninstallProgress()
|
||||||
|
self.progress_thread_uninstall.finished.connect(self.uninstall_sys_file_update)
|
||||||
|
self.progress_thread_uninstall.update.connect(self.ui.progressBar.setValue)
|
||||||
|
self.progress_thread_uninstall.status.connect(self.ui.status.setText)
|
||||||
|
|
||||||
|
# Update progressbar and status (dd ISO)
|
||||||
|
self.progress_thread_dd = DD_Progress()
|
||||||
|
self.progress_thread_dd.update.connect(self.ui.imager_progressbar.setValue)
|
||||||
|
self.progress_thread_dd.finished.connect(self.dd_finished)
|
||||||
|
self.progress_thread_dd.status.connect(self.ui.imager_label_status.setText)
|
||||||
|
|
||||||
|
self.add_device()
|
||||||
|
prepare_mbusb_host_dir()
|
||||||
|
|
||||||
|
def add_device(self):
|
||||||
|
"""
|
||||||
|
Adds list of available USB devices to GUI combobox.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.ui.comboBox.clear()
|
||||||
|
self.ui.comboBox_2.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))
|
||||||
|
if self.ui.comboBox.currentText():
|
||||||
|
self.onComboChange()
|
||||||
|
|
||||||
|
imager_detected_device = self.imager_list_usb(partition=0)
|
||||||
|
if bool(imager_detected_device):
|
||||||
|
for disk in imager_detected_device:
|
||||||
|
self.ui.comboBox_2.addItem(str(disk))
|
||||||
|
self.onImagerComboChange()
|
||||||
|
|
||||||
|
def onComboChange(self):
|
||||||
|
"""
|
||||||
|
Detects and updates GUI with populated USB device details.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.ui.listWidget.clear()
|
||||||
|
config.usb_disk = str(self.ui.comboBox.currentText())
|
||||||
|
config.imager_usb_disk = str(self.ui.comboBox_2.currentText())
|
||||||
|
if bool(config.usb_disk):
|
||||||
|
self.update_gui_oncombobox(config.usb_disk)
|
||||||
|
else:
|
||||||
|
log("No USB disk found...")
|
||||||
|
|
||||||
|
def onRefereshClick(self):
|
||||||
|
"""
|
||||||
|
Calls function to detect USB devices.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.ui.comboBox.clear()
|
||||||
|
self.ui.comboBox_2.clear()
|
||||||
|
self.add_device()
|
||||||
|
|
||||||
|
def update_gui_oncombobox(self, usb_disk):
|
||||||
|
self.usb_details = usb.details(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))
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
def update_list_box(self, usb_disk):
|
||||||
|
"""
|
||||||
|
Updates listbox with installed distros on selected USB disk.
|
||||||
|
:param usb_mount: Selected USB disk from combobox.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
distro_list = install_distro_list()
|
||||||
|
#sys_cfg_file = os.path.join(str(usb_mount), "multibootusb", "syslinux.cfg")
|
||||||
|
if distro_list is not None:
|
||||||
|
self.ui.listWidget.clear()
|
||||||
|
for name in distro_list:
|
||||||
|
self.ui.listWidget.addItem(name)
|
||||||
|
else:
|
||||||
|
if config.usb_mount == 'No_Mount':
|
||||||
|
log("UBS disk is not mounted and can't update list widget...")
|
||||||
|
#QtWidgets.QMessageBox.information(self, 'No Install...',
|
||||||
|
# 'syslinux.cfg does not exist for updating list widget.')
|
||||||
|
|
||||||
|
def browse_iso(self):
|
||||||
|
if str(self.ui.lineEdit.text()):
|
||||||
|
self.ui.lineEdit.clear()
|
||||||
|
config.iso_link = QtWidgets.QFileDialog.getOpenFileName(self, 'Select an iso...', '', 'ISO Files (*.iso)')[0]
|
||||||
|
if config.iso_link:
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
if "/" in config.iso_link:
|
||||||
|
config.iso_link = config.iso_link.strip().replace("/", "\\")
|
||||||
|
self.ui.lineEdit.insert(str(config.iso_link))
|
||||||
|
if os.path.exists(config.iso_link):
|
||||||
|
clean_iso_cfg_ext_dir(os.path.join(multibootusb_host_dir(), "iso_cfg_ext_dir")) # Need to be cleaned.
|
||||||
|
extract_cfg_file(config.iso_link)
|
||||||
|
config.distro = distro(iso_cfg_ext_dir(), config.iso_link) # Detect supported distro
|
||||||
|
if config.distro:
|
||||||
|
per_availability = persistence.persistence_distro(config.distro, config.usb_disk, config.iso_link)[0]
|
||||||
|
per_max_size = persistence.persistence_distro(config.distro, config.usb_disk, config.iso_link)[1]
|
||||||
|
if per_availability is not None:
|
||||||
|
self.ui.slider_persistence.setEnabled(True)
|
||||||
|
self.ui.slider_persistence.setTickInterval(10)
|
||||||
|
self.ui.slider_persistence.setSingleStep(10)
|
||||||
|
ui_per_max_size = per_max_size / 1024 / 1024
|
||||||
|
# config.persistence = per_max_size
|
||||||
|
self.ui.slider_persistence.setMaximum(ui_per_max_size)
|
||||||
|
log('Persistence Max Size: ' + str(bytes2human(per_max_size)))
|
||||||
|
else:
|
||||||
|
log('Persistence is not available for ' + iso_name(config.iso_link))
|
||||||
|
else:
|
||||||
|
log("File not selected...")
|
||||||
|
|
||||||
|
def update_slider_text(self):
|
||||||
|
slide_value = self.ui.slider_persistence.value() * 1024 * 1024
|
||||||
|
self.ui.label_persistence_value.setText(bytes2human(slide_value))
|
||||||
|
config.persistence = slide_value
|
||||||
|
|
||||||
|
def install_syslinux(self):
|
||||||
|
"""
|
||||||
|
Function to install syslinux on distro directory and on selected USB disks.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.ui.status.setText(str("Installing Syslinux..."))
|
||||||
|
syslinux_distro_dir(config.usb_disk, config.iso_link, config.distro)
|
||||||
|
syslinux_default(config.usb_disk)
|
||||||
|
update_distro_cfg_files(config.iso_link, config.usb_disk, config.distro, config.persistence)
|
||||||
|
self.update_list_box(config.usb_disk)
|
||||||
|
if sys.platform.startswith("linux"):
|
||||||
|
self.ui.status.setText("Sync is in progress...")
|
||||||
|
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):
|
||||||
|
"""
|
||||||
|
Function to install syslinux/extlinux on selected USB disk.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if platform.system() == "Linux" or platform.system() == "Windows":
|
||||||
|
|
||||||
|
if self.ui.install_sys_all.isChecked() or self.ui.install_sys_only.isChecked():
|
||||||
|
log("Installing default syslinux on ", config.usb_disk)
|
||||||
|
ret = syslinux_default(config.usb_disk)
|
||||||
|
if ret is True:
|
||||||
|
if self.ui.install_sys_all.isChecked():
|
||||||
|
log("Copying multibootusb directory to " + config.usb_mount)
|
||||||
|
for dirpath, dirnames, filenames in os.walk(resource_path(os.path.join("tools", "multibootusb"))):
|
||||||
|
for f in filenames:
|
||||||
|
log("Copying " + f)
|
||||||
|
shutil.copy(resource_path(os.path.join(dirpath, f)), os.path.join(self.usb.get_usb(config.usb_disk).mount, "multibootusb"))
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No selection...',
|
||||||
|
'Please select one of the option from above.')
|
||||||
|
|
||||||
|
def onedit_syslinux(self):
|
||||||
|
"""
|
||||||
|
Function to edit main syslinux.cfg file.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# Function to edit syslinux.cfg file on editors like gedit, notepad etc.
|
||||||
|
# Suggest me more editor which can be included in to this function.
|
||||||
|
sys_cfg_file = os.path.join(config.usb_mount, "multibootusb", "syslinux.cfg")
|
||||||
|
log("Locating " + sys_cfg_file)
|
||||||
|
editor = ''
|
||||||
|
if not os.path.exists(sys_cfg_file):
|
||||||
|
log("syslinux.cfg file not found...")
|
||||||
|
QtWidgets.QMessageBox.information(self, 'File not found...', 'Sorry. Unable to locate syslinux.cfg file.\n'
|
||||||
|
'You can only edit syslinux.cfg file generated by multibootusb.')
|
||||||
|
else:
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
for e in config.editors_linux:
|
||||||
|
if subprocess.call('which ' + e, shell=True) == 0:
|
||||||
|
log("Editor found is " + e)
|
||||||
|
editor = e
|
||||||
|
break
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
for e in config.editors_win:
|
||||||
|
if not shutil.which(e) is None:
|
||||||
|
log("Editor found is " + e)
|
||||||
|
editor = e
|
||||||
|
break
|
||||||
|
if not editor:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'Editor not found...',
|
||||||
|
'Sorry. Installed editor is not supported by multibootusb\n'
|
||||||
|
'Edit ' + sys_cfg_file + ' manually.\n')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
subprocess.Popen(editor + " '" + sys_cfg_file + "'", shell=True).pid
|
||||||
|
except OSError:
|
||||||
|
QtWidgets.QMessageBox.warning(self, 'Error...',
|
||||||
|
'Failed to open syslinux.cfg file.\n'
|
||||||
|
'Edit syslinux.cfg file manually.\n')
|
||||||
|
|
||||||
|
def OnUninstallClick(self):
|
||||||
|
"""
|
||||||
|
Triggers a function to uninstall a selected distro.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if self.ui.listWidget.currentItem() is None:
|
||||||
|
log("Please select a distro from the list.")
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No selection.', 'Please select a distro from the list.')
|
||||||
|
else:
|
||||||
|
config.uninstall_distro_dir_name = str(self.ui.listWidget.currentItem().text()).strip()
|
||||||
|
reply = QtWidgets.QMessageBox.question(self, "Review selection...",
|
||||||
|
"Are you sure to uninstall " + config.uninstall_distro_dir_name,
|
||||||
|
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||||
|
|
||||||
|
if reply == QtWidgets.QMessageBox.Yes:
|
||||||
|
|
||||||
|
if not os.path.exists(os.path.join(config.usb_mount, 'multibootusb', config.uninstall_distro_dir_name)):
|
||||||
|
log("Distro install directory not found. Just updating syslinux.cfg file.")
|
||||||
|
update_sys_cfg_file()
|
||||||
|
#self.uninstall.update_sys_cfg_file()
|
||||||
|
else:
|
||||||
|
self.progress_thread_uninstall.start()
|
||||||
|
|
||||||
|
def uninstall_sys_file_update(self):
|
||||||
|
"""
|
||||||
|
Function to remove and update uninstall distro text.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
update_sys_cfg_file()
|
||||||
|
self.update_list_box(config.usb_mount)
|
||||||
|
if sys.platform.startswith("linux"):
|
||||||
|
self.ui.status.setText("Sync is in progress...")
|
||||||
|
os.system('sync')
|
||||||
|
self.ui.status.clear()
|
||||||
|
QtWidgets.QMessageBox.information(self, 'Uninstall Complete...',
|
||||||
|
config.uninstall_distro_dir_name + ' has been successfully removed.')
|
||||||
|
|
||||||
|
def onCreateClick(self):
|
||||||
|
"""
|
||||||
|
Main function to create bootable USB disk.
|
||||||
|
:param usb_disk: ComboBox text as detected USB disk.
|
||||||
|
:param iso_link: LineEdit text as selected ISO link.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not config.usb_disk:
|
||||||
|
log("No USB device found.\n\nInsert USB and use Refresh USB button to detect USB.")
|
||||||
|
QtWidgets.QMessageBox.information(self, "No Device...",
|
||||||
|
"No USB device found.\n\nInsert USB and use Refresh USB button to detect USB.")
|
||||||
|
elif not config.iso_link:
|
||||||
|
log("No ISO found.\n\nPlease use step 2 to choose an ISO.")
|
||||||
|
QtWidgets.QMessageBox.information(self, "No ISO...", "No ISO found.\n\nPlease use step 2 to choose an ISO.")
|
||||||
|
elif usb.details(config.usb_disk)['mount_point'] == 'No_Mount':
|
||||||
|
log("USB disk is not mounted.\nPlease mount USB disk and press refresh USB button.")
|
||||||
|
QtWidgets.QMessageBox.information(self, "No Mount...", "USB disk is not mounted.\n"
|
||||||
|
"Please mount USB disk and press refresh USB button.")
|
||||||
|
else:
|
||||||
|
# clean_iso_cfg_ext_dir(os.path.join(multibootusb_host_dir(), "iso_cfg_ext_dir")) # Need to be cleaned.
|
||||||
|
# extract_cfg_file(config.iso_link) # Extract files from ISO
|
||||||
|
# config.distro = distro(iso_cfg_ext_dir(), config.iso_link) # Detect supported distro
|
||||||
|
usb_details = usb.details(config.usb_disk)
|
||||||
|
log("USB Disk is " + config.usb_disk)
|
||||||
|
log("USB Label is " + config.usb_label)
|
||||||
|
log("USB UUID is " + config.usb_uuid)
|
||||||
|
log("USB Mount path is " + config.usb_mount)
|
||||||
|
log("Total size of the disk is " + str(usb.bytes2human(usb_details['size_total'])))
|
||||||
|
log("Total used size is " + str(usb.bytes2human(usb_details['size_used'])))
|
||||||
|
log("Total size left on the disk is " + str(usb.bytes2human(usb_details['size_free'])))
|
||||||
|
log("FileSystem is " + usb_details['file_system'])
|
||||||
|
log("Vendor is " + usb_details['vendor'])
|
||||||
|
log("Model is " + usb_details['model'])
|
||||||
|
log("Name of the ISO file is " + iso_name(config.iso_link))
|
||||||
|
|
||||||
|
if os.path.exists(config.iso_link):
|
||||||
|
self.ui.lineEdit.clear()
|
||||||
|
if config.distro:
|
||||||
|
log("Distro type detected is " + config.distro)
|
||||||
|
copy_mbusb_dir_usb(config.usb_disk)
|
||||||
|
if not os.path.exists(os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link))):
|
||||||
|
config.persistence = self.ui.slider_persistence.value() * 1024 * 1024
|
||||||
|
install_size = iso_size(config.iso_link) + config.persistence
|
||||||
|
log("Persistence choosen is " + str(config.persistence) + " MB")
|
||||||
|
if install_size >= disk_usage(config.usb_mount).free:
|
||||||
|
QtWidgets.QMessageBox.information(self, "No Space.", "No space available on " +
|
||||||
|
config.usb_disk)
|
||||||
|
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.iso_link) +
|
||||||
|
'Would you like to proceed for installation?',
|
||||||
|
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||||
|
|
||||||
|
if reply == QtWidgets.QMessageBox.Yes:
|
||||||
|
self.ui.slider_persistence.setEnabled(False)
|
||||||
|
config.process_exist = True
|
||||||
|
self.progress_thread_install.start()
|
||||||
|
|
||||||
|
else:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'Already Exist...',
|
||||||
|
os.path.basename(config.iso_link) + ' is already installed.')
|
||||||
|
else:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No support...',
|
||||||
|
'Sorry.\n' + os.path.basename(config.iso_link) +
|
||||||
|
' is not supported at the moment.\n'
|
||||||
|
'Please email this issue to feedback.multibootusb@gmail.com')
|
||||||
|
|
||||||
|
# Added to refresh usb disk remaining size after distro installation
|
||||||
|
# self.update_gui_usb_info()
|
||||||
|
|
||||||
|
def dd_finished(self):
|
||||||
|
"""
|
||||||
|
Re-enable the blocked widgets for newer use.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.ui.imager_progressbar.setValue(0)
|
||||||
|
self.ui.imager_label_status.clear()
|
||||||
|
self.ui.comboBox_2.setEnabled(True)
|
||||||
|
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.')
|
||||||
|
|
||||||
|
def dd_start(self):
|
||||||
|
"""
|
||||||
|
Function to block the widgets under ISO Imager tab...
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.ui.imager_progressbar.setValue(0)
|
||||||
|
self.ui.imager_label_status.clear()
|
||||||
|
self.ui.lineEdit_3.clear()
|
||||||
|
self.ui.pushButton.setEnabled(False)
|
||||||
|
self.ui.comboBox_2.setEnabled(False)
|
||||||
|
self.ui.pushbtn_imager_refreshusb.setEnabled(False)
|
||||||
|
status_text = ("<b>Writing " + os.path.basename(config.imager_iso_link) + "</b>" + " to " + "<b>" +
|
||||||
|
config.imager_usb_disk_selected + "</b>")
|
||||||
|
self.ui.imager_label_status.setText(status_text)
|
||||||
|
|
||||||
|
def dd_quit(self):
|
||||||
|
self.ui.imager_progressbar.setValue(0)
|
||||||
|
self.ui.imager_label_status.clear()
|
||||||
|
self.ui.comboBox_2.setEnabled(True)
|
||||||
|
self.ui.pushButton.setEnabled(True)
|
||||||
|
QtWidgets.QMessageBox.information(self, 'Failed!', 'Writing ISO failed.')
|
||||||
|
|
||||||
|
def dd_write(self):
|
||||||
|
if not config.imager_usb_disk:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No USB...', 'Please Insert USB disk and rerun multibootusb.')
|
||||||
|
elif not config.imager_iso_link:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No ISO...', 'Please select an ISO.')
|
||||||
|
else:
|
||||||
|
usb_disk_size = int(self.imager_usb_detail(config.imager_usb_disk, partition=0).total_size)
|
||||||
|
self.iso_size = os.path.getsize(config.imager_iso_link)
|
||||||
|
if self.iso_size >= usb_disk_size:
|
||||||
|
QtWidgets.QMessageBox.information(self, "No Space.", os.path.basename(config.imager_iso_link) +
|
||||||
|
" size is larger than the size of " + config.imager_usb_disk)
|
||||||
|
else:
|
||||||
|
reply = QtWidgets.QMessageBox.question \
|
||||||
|
(self, 'Review selection...',
|
||||||
|
'Selected USB disk:: %s\n' % config.imager_usb_disk +
|
||||||
|
'Selected distro:: %s\n\n' % os.path.basename(config.imager_iso_link) +
|
||||||
|
'Would you like to proceed for installation?',
|
||||||
|
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||||
|
|
||||||
|
if reply == QtWidgets.QMessageBox.Yes:
|
||||||
|
self.dd_start()
|
||||||
|
config.process_exist = True
|
||||||
|
self.progress_thread_dd.start()
|
||||||
|
|
||||||
|
def on_close_Click(self):
|
||||||
|
"""
|
||||||
|
Closes main GUI.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
"""
|
||||||
|
To capture the main close event.
|
||||||
|
:param event: Close event.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if config.process_exist == None:
|
||||||
|
event.accept()
|
||||||
|
else:
|
||||||
|
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:
|
||||||
|
log("Closing multibootusb...")
|
||||||
|
event.accept()
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
log("Close event cancelled.")
|
||||||
|
event.ignore()
|
||||||
|
|
||||||
|
|
||||||
|
class GuiInstallProgress(QtCore.QThread):
|
||||||
|
"""
|
||||||
|
Update GUI thread during install.
|
||||||
|
"""
|
||||||
|
update = QtCore.pyqtSignal(int)
|
||||||
|
status = QtCore.pyqtSignal(str)
|
||||||
|
finished = QtCore.pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
QtCore.QThread.__init__(self)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
install_dir = os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link))
|
||||||
|
self.thread = GenericThread(install_progress)
|
||||||
|
status_text = ""
|
||||||
|
self.thread.start()
|
||||||
|
while self.thread.isRunning():
|
||||||
|
if config.status_text.strip():
|
||||||
|
config.status_text = config.status_text.replace(install_dir + "/", "Extracting ")
|
||||||
|
self.update.emit(config.percentage)
|
||||||
|
self.status.emit(config.status_text)
|
||||||
|
if not self.thread.isFinished() and config.percentage == 100:
|
||||||
|
config.status_text = ""
|
||||||
|
self.status.emit("Please wait...")
|
||||||
|
|
||||||
|
self.update.emit(100)
|
||||||
|
self.update.emit(0)
|
||||||
|
|
||||||
|
self.status.emit("Installing boot loader...")
|
||||||
|
|
||||||
|
if self.thread.isFinished():
|
||||||
|
config.status_text = ""
|
||||||
|
self.finished.emit()
|
||||||
|
|
||||||
|
log("Distro extraction completed...")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class GuiUninstallProgress(QtCore.QThread):
|
||||||
|
"""
|
||||||
|
Update GUI thread during uninstall.
|
||||||
|
"""
|
||||||
|
update = QtCore.pyqtSignal(int)
|
||||||
|
status = QtCore.pyqtSignal(str)
|
||||||
|
finished = QtCore.pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
QtCore.QThread.__init__(self)
|
||||||
|
self.thread = GenericThread(uninstall_progress)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.thread.start()
|
||||||
|
while self.thread.isRunning():
|
||||||
|
self.update.emit(config.percentage)
|
||||||
|
self.status.emit(config.status_text)
|
||||||
|
if not self.thread.isFinished() and config.percentage == 100:
|
||||||
|
config.status_text = "Please wait..."
|
||||||
|
self.update.emit(100)
|
||||||
|
self.update.emit(0)
|
||||||
|
config.percentage = 0
|
||||||
|
self.status.emit("Updating syslinux.cfg file...")
|
||||||
|
|
||||||
|
if self.thread.isFinished():
|
||||||
|
config.status_text = ""
|
||||||
|
self.finished.emit()
|
||||||
|
|
||||||
|
log("Distro uninstall is complete...")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class DD_Progress(QtCore.QThread):
|
||||||
|
"""
|
||||||
|
Update GUI progress bar without blocking rest of GUI element when dd process is in progress.
|
||||||
|
"""
|
||||||
|
update = QtCore.pyqtSignal(int)
|
||||||
|
status = QtCore.pyqtSignal(str)
|
||||||
|
finished = QtCore.pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
QtCore.QThread.__init__(self)
|
||||||
|
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
self.thread = GenericThread(dd_linux)
|
||||||
|
elif platform.system() == 'Windows':
|
||||||
|
self.thread = GenericThread(dd_win)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.thread.start()
|
||||||
|
while self.thread.isRunning():
|
||||||
|
if config.imager_percentage:
|
||||||
|
self.update.emit(config.imager_percentage)
|
||||||
|
if not self.thread.isFinished() and config.percentage == 100:
|
||||||
|
config.imager_status_text = ""
|
||||||
|
self.status.emit("Please wait...")
|
||||||
|
|
||||||
|
self.update.emit(100)
|
||||||
|
self.update.emit(0)
|
||||||
|
|
||||||
|
if self.thread.isFinished():
|
||||||
|
config.status_text = ""
|
||||||
|
self.finished.emit()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class GenericThread(QtCore.QThread):
|
||||||
|
|
||||||
|
def __init__(self, function, *args, **kwargs):
|
||||||
|
QtCore.QThread.__init__(self)
|
||||||
|
self.function = function
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
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()
|
||||||
|
ui = Ui_Dialog()
|
||||||
|
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_())
|
111
deb_dist/multibootusb-8.5.0/scripts/persistence.py
Normal file
111
deb_dist/multibootusb-8.5.0/scripts/persistence.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: persistence.py
|
||||||
|
# Purpose: Module to deal with persistence of a selected distro.
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import tarfile
|
||||||
|
import subprocess
|
||||||
|
from . import usb
|
||||||
|
from . import iso
|
||||||
|
from . import gen
|
||||||
|
from . import config
|
||||||
|
|
||||||
|
|
||||||
|
def persistence_distro(distro, usb_disk, iso_link):
|
||||||
|
"""
|
||||||
|
Function to detect if distro can have persistence option.
|
||||||
|
:param distro: Detected distro name.
|
||||||
|
:return: Distro name as string or None otherwise.
|
||||||
|
"""
|
||||||
|
iso_size = iso.iso_size(iso_link)
|
||||||
|
fat_max_size = (4096 * 1024 * 1024)
|
||||||
|
usb_details = usb.details(usb_disk)
|
||||||
|
usb_sf = usb_details['file_system']
|
||||||
|
usb_free_size = usb_details['size_free']
|
||||||
|
config.usb_uuid = usb_details['uuid']
|
||||||
|
config.usb_label = usb_details['label']
|
||||||
|
if usb_sf == 'vfat' or 'FAT32':
|
||||||
|
if usb_free_size > fat_max_size:
|
||||||
|
_max_size = fat_max_size
|
||||||
|
else:
|
||||||
|
_max_size = usb_free_size
|
||||||
|
else:
|
||||||
|
_max_size = usb_free_size
|
||||||
|
if distro == "ubuntu":
|
||||||
|
gen.log("Persistence option is available.")
|
||||||
|
return "ubuntu", _max_size
|
||||||
|
# FIXME to get debian persistence workable...
|
||||||
|
# Able to add successfully but unable to keep persistence data.
|
||||||
|
elif distro == "debian" or distro == "debian-install":
|
||||||
|
gen.log("Persistence option is available.")
|
||||||
|
return "debian", _max_size
|
||||||
|
elif distro == "fedora":
|
||||||
|
gen.log("Persistence option is available.")
|
||||||
|
return "fedora", _max_size
|
||||||
|
else:
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
def create_persistence():
|
||||||
|
if config.distro == "ubuntu":
|
||||||
|
fs_name = 'casper-rw'
|
||||||
|
elif config.distro == 'debian' or config.distro == "debian-install":
|
||||||
|
fs_name = 'live-rw'
|
||||||
|
elif config.distro == 'fedora':
|
||||||
|
fs_name = 'overlay-' + config.usb_label + '-' + config.usb_uuid
|
||||||
|
|
||||||
|
persistence = config.persistence / 1024 / 1024
|
||||||
|
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
mkfs = 'mkfs.ext3'
|
||||||
|
dd = 'dd'
|
||||||
|
persistence_mkfs_cmd = mkfs + ' -F ' + os.path.join(config.usb_mount, 'multibootusb',
|
||||||
|
iso.iso_basename(config.iso_link),
|
||||||
|
fs_name)
|
||||||
|
elif platform.system() == 'Windows':
|
||||||
|
mkfs = gen.quote(gen.resource_path(os.path.join("data", "tools", "mkfs", "mke2fs.exe")))
|
||||||
|
dd = gen.quote(gen.resource_path(os.path.join("data", "tools", "dd", "dd.exe")))
|
||||||
|
persistence_mkfs_cmd = 'echo y|' + mkfs + ' -b 1024 -L ' + fs_name + ' ' + os.path.join(config.usb_mount, 'multibootusb',
|
||||||
|
iso.iso_basename(config.iso_link), fs_name)
|
||||||
|
|
||||||
|
if config.distro == 'fedora':
|
||||||
|
persistence_dd_cmd = dd + ' if=/dev/zero ' \
|
||||||
|
'of=' + os.path.join(config.usb_mount, 'multibootusb',
|
||||||
|
iso.iso_basename(config.iso_link), 'LiveOS', fs_name) + \
|
||||||
|
' bs=1M count=' + str(int(persistence))
|
||||||
|
else:
|
||||||
|
persistence_dd_cmd = dd + ' if=/dev/zero of=' + os.path.join(config.usb_mount, 'multibootusb',
|
||||||
|
iso.iso_basename(config.iso_link), fs_name) +\
|
||||||
|
' bs=1M count=' + str(int(persistence))
|
||||||
|
|
||||||
|
gen.log('Executing ==>' + persistence_dd_cmd)
|
||||||
|
config.status_text = 'Creating persistence file...'
|
||||||
|
|
||||||
|
if subprocess.call(persistence_dd_cmd, shell=True) == 0:
|
||||||
|
gen.log("\nSuccessfully created persistence file...\n")
|
||||||
|
|
||||||
|
if not config.distro == 'fedora':
|
||||||
|
gen.log('Applying filesystem to persistence file...')
|
||||||
|
gen.log('Executing ==> ' + persistence_mkfs_cmd)
|
||||||
|
config.status_text = 'Applying filesystem to persistence file...'
|
||||||
|
if subprocess.call(persistence_mkfs_cmd, shell=True) == 0:
|
||||||
|
gen.log("\nSuccessfully applied filesystem...\n")
|
||||||
|
|
||||||
|
|
||||||
|
def extract_file(file_path, install_dir):
|
||||||
|
"""
|
||||||
|
Function to extract persistence files to distro install directory.
|
||||||
|
:param file_path: Path to persistence file.
|
||||||
|
:param install_dir: Path to distro install directory.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
tar = tarfile.open(file_path, "r:bz2")
|
||||||
|
tar.extractall(install_dir)
|
||||||
|
tar.close()
|
||||||
|
|
49
deb_dist/multibootusb-8.5.0/scripts/progressbar/__init__.py
Normal file
49
deb_dist/multibootusb-8.5.0/scripts/progressbar/__init__.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# progressbar - Text progress bar library for Python.
|
||||||
|
# Copyright (c) 2005 Nilton Volpato
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""Text progress bar library for Python.
|
||||||
|
|
||||||
|
A text progress bar is typically used to display the progress of a long
|
||||||
|
running operation, providing a visual cue that processing is underway.
|
||||||
|
|
||||||
|
The ProgressBar class manages the current progress, and the format of the line
|
||||||
|
is given by a number of widgets. A widget is an object that may display
|
||||||
|
differently depending on the state of the progress bar. There are three types
|
||||||
|
of widgets:
|
||||||
|
- a string, which always shows itself
|
||||||
|
|
||||||
|
- a ProgressBarWidget, which may return a different value every time its
|
||||||
|
update method is called
|
||||||
|
|
||||||
|
- a ProgressBarWidgetHFill, which is like ProgressBarWidget, except it
|
||||||
|
expands to fill the remaining width of the line.
|
||||||
|
|
||||||
|
The progressbar module is very easy to use, yet very powerful. It will also
|
||||||
|
automatically enable features like auto-resizing when the system supports it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'Nilton Volpato'
|
||||||
|
__author_email__ = 'first-name dot last-name @ gmail.com'
|
||||||
|
__date__ = '2011-05-14'
|
||||||
|
__version__ = '2.3'
|
||||||
|
|
||||||
|
from .compat import *
|
||||||
|
from .widgets import *
|
||||||
|
from .progressbar import *
|
44
deb_dist/multibootusb-8.5.0/scripts/progressbar/compat.py
Normal file
44
deb_dist/multibootusb-8.5.0/scripts/progressbar/compat.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# progressbar - Text progress bar library for Python.
|
||||||
|
# Copyright (c) 2005 Nilton Volpato
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""Compatibility methods and classes for the progressbar module."""
|
||||||
|
|
||||||
|
|
||||||
|
# Python 3.x (and backports) use a modified iterator syntax
|
||||||
|
# This will allow 2.x to behave with 3.x iterators
|
||||||
|
try:
|
||||||
|
next
|
||||||
|
except NameError:
|
||||||
|
def next(iter):
|
||||||
|
try:
|
||||||
|
# Try new style iterators
|
||||||
|
return iter.__next__()
|
||||||
|
except AttributeError:
|
||||||
|
# Fallback in case of a "native" iterator
|
||||||
|
return iter.next()
|
||||||
|
|
||||||
|
|
||||||
|
# Python < 2.5 does not have "any"
|
||||||
|
try:
|
||||||
|
any
|
||||||
|
except NameError:
|
||||||
|
def any(iterator):
|
||||||
|
for item in iterator:
|
||||||
|
if item: return True
|
||||||
|
return False
|
306
deb_dist/multibootusb-8.5.0/scripts/progressbar/progressbar.py
Normal file
306
deb_dist/multibootusb-8.5.0/scripts/progressbar/progressbar.py
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# progressbar - Text progress bar library for Python.
|
||||||
|
# Copyright (c) 2005 Nilton Volpato
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""Main ProgressBar class."""
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
from fcntl import ioctl
|
||||||
|
from array import array
|
||||||
|
import termios
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
from .compat import * # for: any, next
|
||||||
|
from . import widgets
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownLength: pass
|
||||||
|
|
||||||
|
|
||||||
|
class ProgressBar(object):
|
||||||
|
"""The ProgressBar class which updates and prints the bar.
|
||||||
|
|
||||||
|
A common way of using it is like:
|
||||||
|
>>> pbar = ProgressBar().start()
|
||||||
|
>>> for i in range(100):
|
||||||
|
... # do something
|
||||||
|
... pbar.update(i+1)
|
||||||
|
...
|
||||||
|
>>> pbar.finish()
|
||||||
|
|
||||||
|
You can also use a ProgressBar as an iterator:
|
||||||
|
>>> progress = ProgressBar()
|
||||||
|
>>> for i in progress(some_iterable):
|
||||||
|
... # do something
|
||||||
|
...
|
||||||
|
|
||||||
|
Since the progress bar is incredibly customizable you can specify
|
||||||
|
different widgets of any type in any order. You can even write your own
|
||||||
|
widgets! However, since there are already a good number of widgets you
|
||||||
|
should probably play around with them before moving on to create your own
|
||||||
|
widgets.
|
||||||
|
|
||||||
|
The term_width parameter represents the current terminal width. If the
|
||||||
|
parameter is set to an integer then the progress bar will use that,
|
||||||
|
otherwise it will attempt to determine the terminal width falling back to
|
||||||
|
80 columns if the width cannot be determined.
|
||||||
|
|
||||||
|
When implementing a widget's update method you are passed a reference to
|
||||||
|
the current progress bar. As a result, you have access to the
|
||||||
|
ProgressBar's methods and attributes. Although there is nothing preventing
|
||||||
|
you from changing the ProgressBar you should treat it as read only.
|
||||||
|
|
||||||
|
Useful methods and attributes include (Public API):
|
||||||
|
- currval: current progress (0 <= currval <= maxval)
|
||||||
|
- maxval: maximum (and final) value
|
||||||
|
- finished: True if the bar has finished (reached 100%)
|
||||||
|
- start_time: the time when start() method of ProgressBar was called
|
||||||
|
- seconds_elapsed: seconds elapsed since start_time and last call to
|
||||||
|
update
|
||||||
|
- percentage(): progress in percent [0..100]
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ('currval', 'fd', 'finished', 'last_update_time',
|
||||||
|
'left_justify', 'maxval', 'next_update', 'num_intervals',
|
||||||
|
'poll', 'seconds_elapsed', 'signal_set', 'start_time',
|
||||||
|
'term_width', 'update_interval', 'widgets', '_time_sensitive',
|
||||||
|
'__iterable')
|
||||||
|
|
||||||
|
_DEFAULT_MAXVAL = 100
|
||||||
|
_DEFAULT_TERMSIZE = 80
|
||||||
|
_DEFAULT_WIDGETS = [widgets.Percentage(), ' ', widgets.Bar()]
|
||||||
|
|
||||||
|
def __init__(self, maxval=None, widgets=None, term_width=None, poll=1,
|
||||||
|
left_justify=True, fd=sys.stderr):
|
||||||
|
"""Initializes a progress bar with sane defaults."""
|
||||||
|
|
||||||
|
# Don't share a reference with any other progress bars
|
||||||
|
if widgets is None:
|
||||||
|
widgets = list(self._DEFAULT_WIDGETS)
|
||||||
|
|
||||||
|
self.maxval = maxval
|
||||||
|
self.widgets = widgets
|
||||||
|
self.fd = fd
|
||||||
|
self.left_justify = left_justify
|
||||||
|
|
||||||
|
self.signal_set = False
|
||||||
|
if term_width is not None:
|
||||||
|
self.term_width = term_width
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self._handle_resize()
|
||||||
|
signal.signal(signal.SIGWINCH, self._handle_resize)
|
||||||
|
self.signal_set = True
|
||||||
|
except (SystemExit, KeyboardInterrupt): raise
|
||||||
|
except:
|
||||||
|
self.term_width = self._env_size()
|
||||||
|
|
||||||
|
self.__iterable = None
|
||||||
|
self._update_widgets()
|
||||||
|
self.currval = 0
|
||||||
|
self.finished = False
|
||||||
|
self.last_update_time = None
|
||||||
|
self.poll = poll
|
||||||
|
self.seconds_elapsed = 0
|
||||||
|
self.start_time = None
|
||||||
|
self.update_interval = 1
|
||||||
|
self.next_update = 0
|
||||||
|
|
||||||
|
|
||||||
|
def __call__(self, iterable):
|
||||||
|
"""Use a ProgressBar to iterate through an iterable."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.maxval = len(iterable)
|
||||||
|
except:
|
||||||
|
if self.maxval is None:
|
||||||
|
self.maxval = UnknownLength
|
||||||
|
|
||||||
|
self.__iterable = iter(iterable)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
try:
|
||||||
|
value = next(self.__iterable)
|
||||||
|
if self.start_time is None:
|
||||||
|
self.start()
|
||||||
|
else:
|
||||||
|
self.update(self.currval + 1)
|
||||||
|
return value
|
||||||
|
except StopIteration:
|
||||||
|
if self.start_time is None:
|
||||||
|
self.start()
|
||||||
|
self.finish()
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
# Create an alias so that Python 2.x won't complain about not being
|
||||||
|
# an iterator.
|
||||||
|
next = __next__
|
||||||
|
|
||||||
|
|
||||||
|
def _env_size(self):
|
||||||
|
"""Tries to find the term_width from the environment."""
|
||||||
|
|
||||||
|
return int(os.environ.get('COLUMNS', self._DEFAULT_TERMSIZE)) - 1
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_resize(self, signum=None, frame=None):
|
||||||
|
"""Tries to catch resize signals sent from the terminal."""
|
||||||
|
|
||||||
|
h, w = array('h', ioctl(self.fd, termios.TIOCGWINSZ, '\0' * 8))[:2]
|
||||||
|
self.term_width = w
|
||||||
|
|
||||||
|
|
||||||
|
def percentage(self):
|
||||||
|
"""Returns the progress as a percentage."""
|
||||||
|
if self.currval >= self.maxval:
|
||||||
|
return 100.0
|
||||||
|
return (self.currval * 100.0 / self.maxval) if self.maxval else 100.00
|
||||||
|
|
||||||
|
percent = property(percentage)
|
||||||
|
|
||||||
|
|
||||||
|
def _format_widgets(self):
|
||||||
|
result = []
|
||||||
|
expanding = []
|
||||||
|
width = self.term_width
|
||||||
|
|
||||||
|
for index, widget in enumerate(self.widgets):
|
||||||
|
if isinstance(widget, widgets.WidgetHFill):
|
||||||
|
result.append(widget)
|
||||||
|
expanding.insert(0, index)
|
||||||
|
else:
|
||||||
|
widget = widgets.format_updatable(widget, self)
|
||||||
|
result.append(widget)
|
||||||
|
width -= len(widget)
|
||||||
|
|
||||||
|
count = len(expanding)
|
||||||
|
while count:
|
||||||
|
portion = max(int(math.ceil(width * 1. / count)), 0)
|
||||||
|
index = expanding.pop()
|
||||||
|
count -= 1
|
||||||
|
|
||||||
|
widget = result[index].update(self, portion)
|
||||||
|
width -= len(widget)
|
||||||
|
result[index] = widget
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _format_line(self):
|
||||||
|
"""Joins the widgets and justifies the line."""
|
||||||
|
|
||||||
|
widgets = ''.join(self._format_widgets())
|
||||||
|
|
||||||
|
if self.left_justify: return widgets.ljust(self.term_width)
|
||||||
|
else: return widgets.rjust(self.term_width)
|
||||||
|
|
||||||
|
|
||||||
|
def _need_update(self):
|
||||||
|
"""Returns whether the ProgressBar should redraw the line."""
|
||||||
|
if self.currval >= self.next_update or self.finished: return True
|
||||||
|
|
||||||
|
delta = time.time() - self.last_update_time
|
||||||
|
return self._time_sensitive and delta > self.poll
|
||||||
|
|
||||||
|
|
||||||
|
def _update_widgets(self):
|
||||||
|
"""Checks all widgets for the time sensitive bit."""
|
||||||
|
|
||||||
|
self._time_sensitive = any(getattr(w, 'TIME_SENSITIVE', False)
|
||||||
|
for w in self.widgets)
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, value=None):
|
||||||
|
"""Updates the ProgressBar to a new value."""
|
||||||
|
|
||||||
|
if value is not None and value is not UnknownLength:
|
||||||
|
if (self.maxval is not UnknownLength
|
||||||
|
and not 0 <= value <= self.maxval):
|
||||||
|
|
||||||
|
raise ValueError('Value out of range')
|
||||||
|
|
||||||
|
self.currval = value
|
||||||
|
|
||||||
|
|
||||||
|
if not self._need_update(): return
|
||||||
|
if self.start_time is None:
|
||||||
|
raise RuntimeError('You must call "start" before calling "update"')
|
||||||
|
|
||||||
|
now = time.time()
|
||||||
|
self.seconds_elapsed = now - self.start_time
|
||||||
|
self.next_update = self.currval + self.update_interval
|
||||||
|
self.fd.write(self._format_line() + '\r')
|
||||||
|
self.fd.flush()
|
||||||
|
self.last_update_time = now
|
||||||
|
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Starts measuring time, and prints the bar at 0%.
|
||||||
|
|
||||||
|
It returns self so you can use it like this:
|
||||||
|
>>> pbar = ProgressBar().start()
|
||||||
|
>>> for i in range(100):
|
||||||
|
... # do something
|
||||||
|
... pbar.update(i+1)
|
||||||
|
...
|
||||||
|
>>> pbar.finish()
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.maxval is None:
|
||||||
|
self.maxval = self._DEFAULT_MAXVAL
|
||||||
|
|
||||||
|
self.num_intervals = max(100, self.term_width)
|
||||||
|
self.next_update = 0
|
||||||
|
|
||||||
|
if self.maxval is not UnknownLength:
|
||||||
|
if self.maxval < 0: raise ValueError('Value out of range')
|
||||||
|
self.update_interval = self.maxval / self.num_intervals
|
||||||
|
|
||||||
|
|
||||||
|
self.start_time = self.last_update_time = time.time()
|
||||||
|
self.update(0)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
"""Puts the ProgressBar bar in the finished state."""
|
||||||
|
|
||||||
|
if self.finished:
|
||||||
|
return
|
||||||
|
self.finished = True
|
||||||
|
self.update(self.maxval)
|
||||||
|
self.fd.write('\n')
|
||||||
|
if self.signal_set:
|
||||||
|
signal.signal(signal.SIGWINCH, signal.SIG_DFL)
|
355
deb_dist/multibootusb-8.5.0/scripts/progressbar/widgets.py
Normal file
355
deb_dist/multibootusb-8.5.0/scripts/progressbar/widgets.py
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# progressbar - Text progress bar library for Python.
|
||||||
|
# Copyright (c) 2005 Nilton Volpato
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""Default ProgressBar widgets."""
|
||||||
|
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import math
|
||||||
|
|
||||||
|
try:
|
||||||
|
from abc import ABCMeta, abstractmethod
|
||||||
|
except ImportError:
|
||||||
|
AbstractWidget = object
|
||||||
|
abstractmethod = lambda fn: fn
|
||||||
|
else:
|
||||||
|
AbstractWidget = ABCMeta('AbstractWidget', (object,), {})
|
||||||
|
|
||||||
|
|
||||||
|
def format_updatable(updatable, pbar):
|
||||||
|
if hasattr(updatable, 'update'): return updatable.update(pbar)
|
||||||
|
else: return updatable
|
||||||
|
|
||||||
|
|
||||||
|
class Widget(AbstractWidget):
|
||||||
|
"""The base class for all widgets.
|
||||||
|
|
||||||
|
The ProgressBar will call the widget's update value when the widget should
|
||||||
|
be updated. The widget's size may change between calls, but the widget may
|
||||||
|
display incorrectly if the size changes drastically and repeatedly.
|
||||||
|
|
||||||
|
The boolean TIME_SENSITIVE informs the ProgressBar that it should be
|
||||||
|
updated more often because it is time sensitive.
|
||||||
|
"""
|
||||||
|
|
||||||
|
TIME_SENSITIVE = False
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update(self, pbar):
|
||||||
|
"""Updates the widget.
|
||||||
|
|
||||||
|
pbar - a reference to the calling ProgressBar
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetHFill(Widget):
|
||||||
|
"""The base class for all variable width widgets.
|
||||||
|
|
||||||
|
This widget is much like the \\hfill command in TeX, it will expand to
|
||||||
|
fill the line. You can use more than one in the same line, and they will
|
||||||
|
all have the same width, and together will fill the line.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update(self, pbar, width):
|
||||||
|
"""Updates the widget providing the total width the widget must fill.
|
||||||
|
|
||||||
|
pbar - a reference to the calling ProgressBar
|
||||||
|
width - The total width the widget must fill
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class Timer(Widget):
|
||||||
|
"""Widget which displays the elapsed seconds."""
|
||||||
|
|
||||||
|
__slots__ = ('format_string',)
|
||||||
|
TIME_SENSITIVE = True
|
||||||
|
|
||||||
|
def __init__(self, format='Elapsed Time: %s'):
|
||||||
|
self.format_string = format
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def format_time(seconds):
|
||||||
|
"""Formats time as the string "HH:MM:SS"."""
|
||||||
|
|
||||||
|
return str(datetime.timedelta(seconds=int(seconds)))
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
"""Updates the widget to show the elapsed time."""
|
||||||
|
|
||||||
|
return self.format_string % self.format_time(pbar.seconds_elapsed)
|
||||||
|
|
||||||
|
|
||||||
|
class ETA(Timer):
|
||||||
|
"""Widget which attempts to estimate the time of arrival."""
|
||||||
|
|
||||||
|
TIME_SENSITIVE = True
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
"""Updates the widget to show the ETA or total time when finished."""
|
||||||
|
|
||||||
|
if pbar.currval == 0:
|
||||||
|
return 'ETA: --:--:--'
|
||||||
|
elif pbar.finished:
|
||||||
|
return 'Time: %s' % self.format_time(pbar.seconds_elapsed)
|
||||||
|
else:
|
||||||
|
elapsed = pbar.seconds_elapsed
|
||||||
|
eta = elapsed * pbar.maxval / pbar.currval - elapsed
|
||||||
|
return 'ETA: %s' % self.format_time(eta)
|
||||||
|
|
||||||
|
|
||||||
|
class AdaptiveETA(Timer):
|
||||||
|
"""Widget which attempts to estimate the time of arrival.
|
||||||
|
|
||||||
|
Uses a weighted average of two estimates:
|
||||||
|
1) ETA based on the total progress and time elapsed so far
|
||||||
|
2) ETA based on the progress as per the last 10 update reports
|
||||||
|
|
||||||
|
The weight depends on the current progress so that to begin with the
|
||||||
|
total progress is used and at the end only the most recent progress is
|
||||||
|
used.
|
||||||
|
"""
|
||||||
|
|
||||||
|
TIME_SENSITIVE = True
|
||||||
|
NUM_SAMPLES = 10
|
||||||
|
|
||||||
|
def _update_samples(self, currval, elapsed):
|
||||||
|
sample = (currval, elapsed)
|
||||||
|
if not hasattr(self, 'samples'):
|
||||||
|
self.samples = [sample] * (self.NUM_SAMPLES + 1)
|
||||||
|
else:
|
||||||
|
self.samples.append(sample)
|
||||||
|
return self.samples.pop(0)
|
||||||
|
|
||||||
|
def _eta(self, maxval, currval, elapsed):
|
||||||
|
return elapsed * maxval / float(currval) - elapsed
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
"""Updates the widget to show the ETA or total time when finished."""
|
||||||
|
if pbar.currval == 0:
|
||||||
|
return 'ETA: --:--:--'
|
||||||
|
elif pbar.finished:
|
||||||
|
return 'Time: %s' % self.format_time(pbar.seconds_elapsed)
|
||||||
|
else:
|
||||||
|
elapsed = pbar.seconds_elapsed
|
||||||
|
currval1, elapsed1 = self._update_samples(pbar.currval, elapsed)
|
||||||
|
eta = self._eta(pbar.maxval, pbar.currval, elapsed)
|
||||||
|
if pbar.currval > currval1:
|
||||||
|
etasamp = self._eta(pbar.maxval - currval1,
|
||||||
|
pbar.currval - currval1,
|
||||||
|
elapsed - elapsed1)
|
||||||
|
weight = (pbar.currval / float(pbar.maxval)) ** 0.5
|
||||||
|
eta = (1 - weight) * eta + weight * etasamp
|
||||||
|
return 'ETA: %s' % self.format_time(eta)
|
||||||
|
|
||||||
|
|
||||||
|
class FileTransferSpeed(Widget):
|
||||||
|
"""Widget for showing the transfer speed (useful for file transfers)."""
|
||||||
|
|
||||||
|
FORMAT = '%6.2f %s%s/s'
|
||||||
|
PREFIXES = ' kMGTPEZY'
|
||||||
|
__slots__ = ('unit',)
|
||||||
|
|
||||||
|
def __init__(self, unit='B'):
|
||||||
|
self.unit = unit
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
"""Updates the widget with the current SI prefixed speed."""
|
||||||
|
|
||||||
|
if pbar.seconds_elapsed < 2e-6 or pbar.currval < 2e-6: # =~ 0
|
||||||
|
scaled = power = 0
|
||||||
|
else:
|
||||||
|
speed = pbar.currval / pbar.seconds_elapsed
|
||||||
|
power = int(math.log(speed, 1000))
|
||||||
|
scaled = speed / 1000.**power
|
||||||
|
|
||||||
|
return self.FORMAT % (scaled, self.PREFIXES[power], self.unit)
|
||||||
|
|
||||||
|
|
||||||
|
class AnimatedMarker(Widget):
|
||||||
|
"""An animated marker for the progress bar which defaults to appear as if
|
||||||
|
it were rotating.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ('markers', 'curmark')
|
||||||
|
|
||||||
|
def __init__(self, markers='|/-\\'):
|
||||||
|
self.markers = markers
|
||||||
|
self.curmark = -1
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
"""Updates the widget to show the next marker or the first marker when
|
||||||
|
finished"""
|
||||||
|
|
||||||
|
if pbar.finished: return self.markers[0]
|
||||||
|
|
||||||
|
self.curmark = (self.curmark + 1) % len(self.markers)
|
||||||
|
return self.markers[self.curmark]
|
||||||
|
|
||||||
|
# Alias for backwards compatibility
|
||||||
|
RotatingMarker = AnimatedMarker
|
||||||
|
|
||||||
|
|
||||||
|
class Counter(Widget):
|
||||||
|
"""Displays the current count."""
|
||||||
|
|
||||||
|
__slots__ = ('format_string',)
|
||||||
|
|
||||||
|
def __init__(self, format='%d'):
|
||||||
|
self.format_string = format
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
return self.format_string % pbar.currval
|
||||||
|
|
||||||
|
|
||||||
|
class Percentage(Widget):
|
||||||
|
"""Displays the current percentage as a number with a percent sign."""
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
return '%3d%%' % pbar.percentage()
|
||||||
|
|
||||||
|
|
||||||
|
class FormatLabel(Timer):
|
||||||
|
"""Displays a formatted label."""
|
||||||
|
|
||||||
|
mapping = {
|
||||||
|
'elapsed': ('seconds_elapsed', Timer.format_time),
|
||||||
|
'finished': ('finished', None),
|
||||||
|
'last_update': ('last_update_time', None),
|
||||||
|
'max': ('maxval', None),
|
||||||
|
'seconds': ('seconds_elapsed', None),
|
||||||
|
'start': ('start_time', None),
|
||||||
|
'value': ('currval', None)
|
||||||
|
}
|
||||||
|
|
||||||
|
__slots__ = ('format_string',)
|
||||||
|
def __init__(self, format):
|
||||||
|
self.format_string = format
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
context = {}
|
||||||
|
for name, (key, transform) in self.mapping.items():
|
||||||
|
try:
|
||||||
|
value = getattr(pbar, key)
|
||||||
|
|
||||||
|
if transform is None:
|
||||||
|
context[name] = value
|
||||||
|
else:
|
||||||
|
context[name] = transform(value)
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
return self.format_string % context
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleProgress(Widget):
|
||||||
|
"""Returns progress as a count of the total (e.g.: "5 of 47")."""
|
||||||
|
|
||||||
|
__slots__ = ('sep',)
|
||||||
|
|
||||||
|
def __init__(self, sep=' of '):
|
||||||
|
self.sep = sep
|
||||||
|
|
||||||
|
def update(self, pbar):
|
||||||
|
return '%d%s%d' % (pbar.currval, self.sep, pbar.maxval)
|
||||||
|
|
||||||
|
|
||||||
|
class Bar(WidgetHFill):
|
||||||
|
"""A progress bar which stretches to fill the line."""
|
||||||
|
|
||||||
|
__slots__ = ('marker', 'left', 'right', 'fill', 'fill_left')
|
||||||
|
|
||||||
|
def __init__(self, marker='#', left='|', right='|', fill=' ',
|
||||||
|
fill_left=True):
|
||||||
|
"""Creates a customizable progress bar.
|
||||||
|
|
||||||
|
marker - string or updatable object to use as a marker
|
||||||
|
left - string or updatable object to use as a left border
|
||||||
|
right - string or updatable object to use as a right border
|
||||||
|
fill - character to use for the empty part of the progress bar
|
||||||
|
fill_left - whether to fill from the left or the right
|
||||||
|
"""
|
||||||
|
self.marker = marker
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
self.fill = fill
|
||||||
|
self.fill_left = fill_left
|
||||||
|
|
||||||
|
|
||||||
|
def update(self, pbar, width):
|
||||||
|
"""Updates the progress bar and its subcomponents."""
|
||||||
|
|
||||||
|
left, marked, right = (format_updatable(i, pbar) for i in
|
||||||
|
(self.left, self.marker, self.right))
|
||||||
|
|
||||||
|
width -= len(left) + len(right)
|
||||||
|
# Marked must *always* have length of 1
|
||||||
|
if pbar.maxval:
|
||||||
|
marked *= int(pbar.currval / pbar.maxval * width)
|
||||||
|
else:
|
||||||
|
marked = ''
|
||||||
|
|
||||||
|
if self.fill_left:
|
||||||
|
return '%s%s%s' % (left, marked.ljust(width, self.fill), right)
|
||||||
|
else:
|
||||||
|
return '%s%s%s' % (left, marked.rjust(width, self.fill), right)
|
||||||
|
|
||||||
|
|
||||||
|
class ReverseBar(Bar):
|
||||||
|
"""A bar which has a marker which bounces from side to side."""
|
||||||
|
|
||||||
|
def __init__(self, marker='#', left='|', right='|', fill=' ',
|
||||||
|
fill_left=False):
|
||||||
|
"""Creates a customizable progress bar.
|
||||||
|
|
||||||
|
marker - string or updatable object to use as a marker
|
||||||
|
left - string or updatable object to use as a left border
|
||||||
|
right - string or updatable object to use as a right border
|
||||||
|
fill - character to use for the empty part of the progress bar
|
||||||
|
fill_left - whether to fill from the left or the right
|
||||||
|
"""
|
||||||
|
self.marker = marker
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
self.fill = fill
|
||||||
|
self.fill_left = fill_left
|
||||||
|
|
||||||
|
|
||||||
|
class BouncingBar(Bar):
|
||||||
|
def update(self, pbar, width):
|
||||||
|
"""Updates the progress bar and its subcomponents."""
|
||||||
|
|
||||||
|
left, marker, right = (format_updatable(i, pbar) for i in
|
||||||
|
(self.left, self.marker, self.right))
|
||||||
|
|
||||||
|
width -= len(left) + len(right)
|
||||||
|
|
||||||
|
if pbar.finished: return '%s%s%s' % (left, width * marker, right)
|
||||||
|
|
||||||
|
position = int(pbar.currval % (width * 2 - 1))
|
||||||
|
if position > width: position = width * 2 - position
|
||||||
|
lpad = self.fill * (position - 1)
|
||||||
|
rpad = self.fill * (width - len(marker) - len(lpad))
|
||||||
|
|
||||||
|
# Swap if we want to bounce the other way
|
||||||
|
if not self.fill_left: rpad, lpad = lpad, rpad
|
||||||
|
|
||||||
|
return '%s%s%s%s%s' % (left, lpad, marker, rpad, right)
|
69
deb_dist/multibootusb-8.5.0/scripts/pyudev/__init__.py
Normal file
69
deb_dist/multibootusb-8.5.0/scripts/pyudev/__init__.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011, 2012 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev
|
||||||
|
======
|
||||||
|
|
||||||
|
A binding to libudev.
|
||||||
|
|
||||||
|
The :class:`Context` provides the connection to the udev device database
|
||||||
|
and enumerates devices. Individual devices are represented by the
|
||||||
|
:class:`Device` class.
|
||||||
|
|
||||||
|
Device monitoring is provided by :class:`Monitor` and
|
||||||
|
:class:`MonitorObserver`. With :mod:`pyudev.pyqt4`, :mod:`pyudev.pyside`,
|
||||||
|
:mod:`pyudev.glib` and :mod:`pyudev.wx` device monitoring can be integrated
|
||||||
|
into the event loop of various GUI toolkits.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from ._errors import DeviceNotFoundAtPathError
|
||||||
|
from ._errors import DeviceNotFoundByFileError
|
||||||
|
from ._errors import DeviceNotFoundByNameError
|
||||||
|
from ._errors import DeviceNotFoundByNumberError
|
||||||
|
from ._errors import DeviceNotFoundError
|
||||||
|
from ._errors import DeviceNotFoundInEnvironmentError
|
||||||
|
|
||||||
|
from .device import Attributes
|
||||||
|
from .device import Device
|
||||||
|
from .device import Devices
|
||||||
|
from .device import Tags
|
||||||
|
|
||||||
|
from .discover import DeviceFileHypothesis
|
||||||
|
from .discover import DeviceNameHypothesis
|
||||||
|
from .discover import DeviceNumberHypothesis
|
||||||
|
from .discover import DevicePathHypothesis
|
||||||
|
from .discover import Discovery
|
||||||
|
|
||||||
|
from .core import Context
|
||||||
|
from .core import Enumerator
|
||||||
|
|
||||||
|
from .monitor import Monitor
|
||||||
|
from .monitor import MonitorObserver
|
||||||
|
|
||||||
|
from .version import __version__
|
||||||
|
from .version import __version_info__
|
||||||
|
|
||||||
|
from ._util import udev_version
|
44
deb_dist/multibootusb-8.5.0/scripts/pyudev/_compat.py
Normal file
44
deb_dist/multibootusb-8.5.0/scripts/pyudev/_compat.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2011 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._compat
|
||||||
|
==============
|
||||||
|
|
||||||
|
Compatibility for Python versions, that lack certain functions.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import (print_function, division, unicode_literals,
|
||||||
|
absolute_import)
|
||||||
|
|
||||||
|
from subprocess import Popen, CalledProcessError, PIPE
|
||||||
|
|
||||||
|
|
||||||
|
def check_output(command):
|
||||||
|
"""
|
||||||
|
Compatibility with :func:`subprocess.check_output` from Python 2.7 and
|
||||||
|
upwards.
|
||||||
|
"""
|
||||||
|
proc = Popen(command, stdout=PIPE)
|
||||||
|
output = proc.communicate()[0]
|
||||||
|
if proc.returncode != 0:
|
||||||
|
raise CalledProcessError(proc.returncode, command)
|
||||||
|
return output
|
@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2015 mulhern <amulhern@redhat.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._ctypeslib
|
||||||
|
=================
|
||||||
|
|
||||||
|
Wrappers for libraries.
|
||||||
|
|
||||||
|
.. moduleauthor:: mulhern <amulhern@redhat.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from . import libc
|
||||||
|
from . import libudev
|
@ -0,0 +1,108 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._ctypeslib._errorcheckers
|
||||||
|
================================
|
||||||
|
|
||||||
|
Error checkers for ctypes wrappers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import errno
|
||||||
|
from ctypes import get_errno
|
||||||
|
|
||||||
|
|
||||||
|
ERRNO_EXCEPTIONS = {
|
||||||
|
errno.ENOMEM: MemoryError,
|
||||||
|
errno.EOVERFLOW: OverflowError,
|
||||||
|
errno.EINVAL: ValueError
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def exception_from_errno(errnum):
|
||||||
|
"""Create an exception from ``errnum``.
|
||||||
|
|
||||||
|
``errnum`` is an integral error number.
|
||||||
|
|
||||||
|
Return an exception object appropriate to ``errnum``.
|
||||||
|
|
||||||
|
"""
|
||||||
|
exception = ERRNO_EXCEPTIONS.get(errnum)
|
||||||
|
errorstr = os.strerror(errnum)
|
||||||
|
if exception is not None:
|
||||||
|
return exception(errorstr)
|
||||||
|
else:
|
||||||
|
return EnvironmentError(errnum, errorstr)
|
||||||
|
|
||||||
|
|
||||||
|
def check_negative_errorcode(result, func, *args):
|
||||||
|
"""Error checker for funtions, which return negative error codes.
|
||||||
|
|
||||||
|
If ``result`` is smaller than ``0``, it is interpreted as negative error
|
||||||
|
code, and an appropriate exception is raised:
|
||||||
|
|
||||||
|
- ``-ENOMEM`` raises a :exc:`~exceptions.MemoryError`
|
||||||
|
- ``-EOVERFLOW`` raises a :exc:`~exceptions.OverflowError`
|
||||||
|
- all other error codes raise :exc:`~exceptions.EnvironmentError`
|
||||||
|
|
||||||
|
If result is greater or equal to ``0``, it is returned unchanged.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if result < 0:
|
||||||
|
# udev returns the *negative* errno code at this point
|
||||||
|
errnum = -result
|
||||||
|
raise exception_from_errno(errnum)
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def check_errno_on_nonzero_return(result, func, *args):
|
||||||
|
"""Error checker to check the system ``errno`` as returned by
|
||||||
|
:func:`ctypes.get_errno()`.
|
||||||
|
|
||||||
|
If ``result`` is not ``0``, an exception according to this errno is raised.
|
||||||
|
Otherwise nothing happens.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if result != 0:
|
||||||
|
errnum = get_errno()
|
||||||
|
if errnum != 0:
|
||||||
|
raise exception_from_errno(errnum)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def check_errno_on_null_pointer_return(result, func, *args):
|
||||||
|
"""Error checker to check the system ``errno`` as returned by
|
||||||
|
:func:`ctypes.get_errno()`.
|
||||||
|
|
||||||
|
If ``result`` is a null pointer, an exception according to this errno is
|
||||||
|
raised. Otherwise nothing happens.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
if not result:
|
||||||
|
errnum = get_errno()
|
||||||
|
if errnum != 0:
|
||||||
|
raise exception_from_errno(errnum)
|
||||||
|
return result
|
@ -0,0 +1,46 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._ctypeslib.libc
|
||||||
|
======================
|
||||||
|
|
||||||
|
Wrappers for libc.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from ctypes import c_int
|
||||||
|
|
||||||
|
from ._errorcheckers import check_errno_on_nonzero_return
|
||||||
|
|
||||||
|
|
||||||
|
fd_pair = c_int * 2
|
||||||
|
|
||||||
|
|
||||||
|
SIGNATURES = dict(
|
||||||
|
pipe2=([fd_pair, c_int], c_int),
|
||||||
|
)
|
||||||
|
|
||||||
|
ERROR_CHECKERS = dict(
|
||||||
|
pipe2=check_errno_on_nonzero_return,
|
||||||
|
)
|
283
deb_dist/multibootusb-8.5.0/scripts/pyudev/_ctypeslib/libudev.py
Normal file
283
deb_dist/multibootusb-8.5.0/scripts/pyudev/_ctypeslib/libudev.py
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011, 2012, 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._ctypeslib.libudev
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Wrapper types for libudev. Use ``libudev`` attribute to access libudev
|
||||||
|
functions.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from ctypes import c_char
|
||||||
|
from ctypes import c_char_p
|
||||||
|
from ctypes import c_int
|
||||||
|
from ctypes import c_uint
|
||||||
|
from ctypes import c_ulonglong
|
||||||
|
from ctypes import CDLL
|
||||||
|
from ctypes import Structure
|
||||||
|
from ctypes import POINTER
|
||||||
|
|
||||||
|
from ctypes.util import find_library
|
||||||
|
|
||||||
|
from ._errorcheckers import check_errno_on_nonzero_return
|
||||||
|
from ._errorcheckers import check_errno_on_null_pointer_return
|
||||||
|
from ._errorcheckers import check_negative_errorcode
|
||||||
|
|
||||||
|
|
||||||
|
class udev(Structure): # pylint: disable=invalid-name
|
||||||
|
"""
|
||||||
|
Dummy for ``udev`` structure.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
pass
|
||||||
|
|
||||||
|
udev_p = POINTER(udev) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
|
class udev_enumerate(Structure): # pylint: disable=invalid-name
|
||||||
|
"""
|
||||||
|
Dummy for ``udev_enumerate`` structure.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
pass
|
||||||
|
|
||||||
|
udev_enumerate_p = POINTER(udev_enumerate) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
|
class udev_list_entry(Structure): # pylint: disable=invalid-name
|
||||||
|
"""
|
||||||
|
Dummy for ``udev_list_entry`` structure.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
pass
|
||||||
|
|
||||||
|
udev_list_entry_p = POINTER(udev_list_entry) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
|
class udev_device(Structure): # pylint: disable=invalid-name
|
||||||
|
"""
|
||||||
|
Dummy for ``udev_device`` structure.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
pass
|
||||||
|
|
||||||
|
udev_device_p = POINTER(udev_device) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
|
class udev_monitor(Structure): # pylint: disable=invalid-name
|
||||||
|
"""
|
||||||
|
Dummy for ``udev_device`` structure.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
pass
|
||||||
|
|
||||||
|
udev_monitor_p = POINTER(udev_monitor) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
class udev_hwdb(Structure): # pylint: disable=invalid-name
|
||||||
|
"""
|
||||||
|
Dummy for ``udev_hwdb`` structure.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
pass
|
||||||
|
|
||||||
|
udev_hwdb_p = POINTER(udev_hwdb) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
|
dev_t = c_ulonglong # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
|
SIGNATURES = dict(
|
||||||
|
# context
|
||||||
|
udev_new=([], udev_p),
|
||||||
|
udev_unref=([udev_p], None),
|
||||||
|
udev_ref=([udev_p], udev_p),
|
||||||
|
udev_get_sys_path=([udev_p], c_char_p),
|
||||||
|
udev_get_dev_path=([udev_p], c_char_p),
|
||||||
|
udev_get_run_path=([udev_p], c_char_p),
|
||||||
|
udev_get_log_priority=([udev_p], c_int),
|
||||||
|
udev_set_log_priority=([udev_p, c_int], None),
|
||||||
|
udev_enumerate_new=([udev_p], udev_enumerate_p),
|
||||||
|
udev_enumerate_ref=([udev_enumerate_p], udev_enumerate_p),
|
||||||
|
udev_enumerate_unref=([udev_enumerate_p], None),
|
||||||
|
udev_enumerate_add_match_subsystem=([udev_enumerate_p, c_char_p], c_int),
|
||||||
|
udev_enumerate_add_nomatch_subsystem=([udev_enumerate_p, c_char_p], c_int),
|
||||||
|
udev_enumerate_add_match_property=(
|
||||||
|
[udev_enumerate_p, c_char_p, c_char_p],
|
||||||
|
c_int
|
||||||
|
),
|
||||||
|
udev_enumerate_add_match_sysattr=(
|
||||||
|
[udev_enumerate_p, c_char_p, c_char_p],
|
||||||
|
c_int
|
||||||
|
),
|
||||||
|
udev_enumerate_add_nomatch_sysattr=(
|
||||||
|
[udev_enumerate_p, c_char_p, c_char_p],
|
||||||
|
c_int
|
||||||
|
),
|
||||||
|
udev_enumerate_add_match_tag=([udev_enumerate_p, c_char_p], c_int),
|
||||||
|
udev_enumerate_add_match_sysname=([udev_enumerate_p, c_char_p], c_int),
|
||||||
|
udev_enumerate_add_match_parent=([udev_enumerate_p, udev_device_p], c_int),
|
||||||
|
udev_enumerate_add_match_is_initialized=([udev_enumerate_p], c_int),
|
||||||
|
udev_enumerate_scan_devices=([udev_enumerate_p], c_int),
|
||||||
|
udev_enumerate_get_list_entry=([udev_enumerate_p], udev_list_entry_p),
|
||||||
|
# list entries
|
||||||
|
udev_list_entry_get_next=([udev_list_entry_p], udev_list_entry_p),
|
||||||
|
udev_list_entry_get_name=([udev_list_entry_p], c_char_p),
|
||||||
|
udev_list_entry_get_value=([udev_list_entry_p], c_char_p),
|
||||||
|
# devices
|
||||||
|
udev_device_ref=([udev_device_p], udev_device_p),
|
||||||
|
udev_device_unref=([udev_device_p], None),
|
||||||
|
udev_device_new_from_syspath=([udev_p, c_char_p], udev_device_p),
|
||||||
|
udev_device_new_from_subsystem_sysname=(
|
||||||
|
[udev_p, c_char_p, c_char_p],
|
||||||
|
udev_device_p
|
||||||
|
),
|
||||||
|
udev_device_new_from_devnum=([udev_p, c_char, dev_t], udev_device_p),
|
||||||
|
udev_device_new_from_device_id=([udev_p, c_char_p], udev_device_p),
|
||||||
|
udev_device_new_from_environment=([udev_p], udev_device_p),
|
||||||
|
udev_device_get_parent=([udev_device_p], udev_device_p),
|
||||||
|
udev_device_get_parent_with_subsystem_devtype=(
|
||||||
|
[udev_device_p, c_char_p, c_char_p],
|
||||||
|
udev_device_p
|
||||||
|
),
|
||||||
|
udev_device_get_devpath=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_subsystem=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_syspath=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_sysnum=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_sysname=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_driver=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_devtype=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_devnode=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_property_value=([udev_device_p, c_char_p], c_char_p),
|
||||||
|
udev_device_get_sysattr_value=([udev_device_p, c_char_p], c_char_p),
|
||||||
|
udev_device_get_devnum=([udev_device_p], dev_t),
|
||||||
|
udev_device_get_action=([udev_device_p], c_char_p),
|
||||||
|
udev_device_get_seqnum=([udev_device_p], c_ulonglong),
|
||||||
|
udev_device_get_is_initialized=([udev_device_p], c_int),
|
||||||
|
udev_device_get_usec_since_initialized=([udev_device_p], c_ulonglong),
|
||||||
|
udev_device_get_devlinks_list_entry=([udev_device_p], udev_list_entry_p),
|
||||||
|
udev_device_get_tags_list_entry=([udev_device_p], udev_list_entry_p),
|
||||||
|
udev_device_get_properties_list_entry=([udev_device_p], udev_list_entry_p),
|
||||||
|
udev_device_get_sysattr_list_entry=([udev_device_p], udev_list_entry_p),
|
||||||
|
udev_device_set_sysattr_value=([udev_device_p, c_char_p, c_char_p], c_int),
|
||||||
|
udev_device_has_tag=([udev_device_p, c_char_p], c_int),
|
||||||
|
# monitoring
|
||||||
|
udev_monitor_ref=([udev_monitor_p], udev_monitor_p),
|
||||||
|
udev_monitor_unref=([udev_monitor_p], None),
|
||||||
|
udev_monitor_new_from_netlink=([udev_p, c_char_p], udev_monitor_p),
|
||||||
|
udev_monitor_enable_receiving=([udev_monitor_p], c_int),
|
||||||
|
udev_monitor_set_receive_buffer_size=([udev_monitor_p, c_int], c_int),
|
||||||
|
udev_monitor_get_fd=([udev_monitor_p], c_int),
|
||||||
|
udev_monitor_receive_device=([udev_monitor_p], udev_device_p),
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype=(
|
||||||
|
[udev_monitor_p, c_char_p, c_char_p], c_int),
|
||||||
|
udev_monitor_filter_add_match_tag=([udev_monitor_p, c_char_p], c_int),
|
||||||
|
udev_monitor_filter_update=([udev_monitor_p], c_int),
|
||||||
|
udev_monitor_filter_remove=([udev_monitor_p], c_int),
|
||||||
|
# hwdb
|
||||||
|
udev_hwdb_ref=([udev_hwdb_p], udev_hwdb_p),
|
||||||
|
udev_hwdb_unref=([udev_hwdb_p], None),
|
||||||
|
udev_hwdb_new=([udev_p], udev_hwdb_p),
|
||||||
|
udev_hwdb_get_properties_list_entry=(
|
||||||
|
[udev_hwdb_p, c_char_p, c_uint],
|
||||||
|
udev_list_entry_p
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
ERROR_CHECKERS = dict(
|
||||||
|
udev_device_get_action=None,
|
||||||
|
udev_device_get_devlinks_list_entry=None,
|
||||||
|
udev_device_get_devnode=None,
|
||||||
|
udev_device_get_devnum=None,
|
||||||
|
udev_device_get_devpath=None,
|
||||||
|
udev_device_get_devtype=None,
|
||||||
|
udev_device_get_driver=None,
|
||||||
|
udev_device_get_is_initialized=None,
|
||||||
|
udev_device_get_parent=None,
|
||||||
|
udev_device_get_parent_with_subsystem_devtype=None,
|
||||||
|
udev_device_get_properties_list_entry=None,
|
||||||
|
udev_device_get_property_value=None,
|
||||||
|
udev_device_get_seqnum=None,
|
||||||
|
udev_device_get_subsystem=None,
|
||||||
|
udev_device_get_sysattr_list_entry=None,
|
||||||
|
udev_device_get_sysattr_value=None,
|
||||||
|
udev_device_get_sysname=None,
|
||||||
|
udev_device_get_sysnum=None,
|
||||||
|
udev_device_get_syspath=None,
|
||||||
|
udev_device_get_tags_list_entry=None,
|
||||||
|
udev_device_get_usec_since_initialized=None,
|
||||||
|
udev_device_has_tag=None,
|
||||||
|
udev_device_new_from_device_id=None,
|
||||||
|
udev_device_new_from_devnum=None,
|
||||||
|
udev_device_new_from_environment=None,
|
||||||
|
udev_device_new_from_subsystem_sysname=None,
|
||||||
|
udev_device_new_from_syspath=None,
|
||||||
|
udev_device_ref=None,
|
||||||
|
udev_device_unref=None,
|
||||||
|
udev_device_set_sysattr_value=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_match_parent=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_match_subsystem=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_nomatch_subsystem=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_match_property=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_match_sysattr=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_nomatch_sysattr=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_match_tag=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_match_sysname=check_negative_errorcode,
|
||||||
|
udev_enumerate_add_match_is_initialized=check_negative_errorcode,
|
||||||
|
udev_enumerate_get_list_entry=None,
|
||||||
|
udev_enumerate_new=None,
|
||||||
|
udev_enumerate_ref=None,
|
||||||
|
udev_enumerate_scan_devices=None,
|
||||||
|
udev_enumerate_unref=None,
|
||||||
|
udev_get_dev_path=None,
|
||||||
|
udev_get_log_priority=None,
|
||||||
|
udev_get_run_path=None,
|
||||||
|
udev_get_sys_path=None,
|
||||||
|
udev_hwdb_get_properties_list_entry=None,
|
||||||
|
udev_hwdb_new=None,
|
||||||
|
udev_hwdb_ref=None,
|
||||||
|
udev_hwdb_unref=None,
|
||||||
|
udev_list_entry_get_name=None,
|
||||||
|
udev_list_entry_get_next=None,
|
||||||
|
udev_list_entry_get_value=None,
|
||||||
|
udev_monitor_set_receive_buffer_size=check_errno_on_nonzero_return,
|
||||||
|
# libudev doc says, enable_receiving returns a negative errno, but tests
|
||||||
|
# show that this is not reliable, so query the real error code
|
||||||
|
udev_monitor_enable_receiving=check_errno_on_nonzero_return,
|
||||||
|
udev_monitor_receive_device=check_errno_on_null_pointer_return,
|
||||||
|
udev_monitor_ref=None,
|
||||||
|
udev_monitor_filter_add_match_subsystem_devtype=check_negative_errorcode,
|
||||||
|
udev_monitor_filter_add_match_tag=check_negative_errorcode,
|
||||||
|
udev_monitor_filter_update=check_errno_on_nonzero_return,
|
||||||
|
udev_monitor_filter_remove=check_errno_on_nonzero_return,
|
||||||
|
udev_monitor_get_fd=None,
|
||||||
|
udev_monitor_new_from_netlink=None,
|
||||||
|
udev_monitor_unref=None,
|
||||||
|
udev_new=None,
|
||||||
|
udev_ref=None,
|
||||||
|
udev_set_log_priority=None,
|
||||||
|
udev_unref=None
|
||||||
|
)
|
@ -0,0 +1,68 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._ctypeslib.utils
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Utilities for loading ctypeslib.
|
||||||
|
|
||||||
|
.. moduleauthor:: Anne Mulhern <amulhern@redhat.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from ctypes import CDLL
|
||||||
|
from ctypes.util import find_library
|
||||||
|
|
||||||
|
|
||||||
|
def load_ctypes_library(name, signatures, error_checkers):
|
||||||
|
"""
|
||||||
|
Load library ``name`` and return a :class:`ctypes.CDLL` object for it.
|
||||||
|
|
||||||
|
:param str name: the library name
|
||||||
|
:param signatures: signatures of methods
|
||||||
|
:type signatures: dict of str * (tuple of (list of type) * type)
|
||||||
|
:param error_checkers: error checkers for methods
|
||||||
|
:type error_checkers: dict of str * ((int * ptr * arglist) -> int)
|
||||||
|
|
||||||
|
The library has errno handling enabled.
|
||||||
|
Important functions are given proper signatures and return types to support
|
||||||
|
type checking and argument conversion.
|
||||||
|
|
||||||
|
:returns: a loaded library
|
||||||
|
:rtype: ctypes.CDLL
|
||||||
|
:raises ImportError: if the library is not found
|
||||||
|
"""
|
||||||
|
library_name = find_library(name)
|
||||||
|
if not library_name:
|
||||||
|
raise ImportError('No library named %s' % name)
|
||||||
|
lib = CDLL(library_name, use_errno=True)
|
||||||
|
# Add function signatures
|
||||||
|
for funcname, signature in signatures.items():
|
||||||
|
function = getattr(lib, funcname, None)
|
||||||
|
if function:
|
||||||
|
argtypes, restype = signature
|
||||||
|
function.argtypes = argtypes
|
||||||
|
function.restype = restype
|
||||||
|
errorchecker = error_checkers.get(funcname)
|
||||||
|
if errorchecker:
|
||||||
|
function.errcheck = errorchecker
|
||||||
|
return lib
|
187
deb_dist/multibootusb-8.5.0/scripts/pyudev/_errors.py
Normal file
187
deb_dist/multibootusb-8.5.0/scripts/pyudev/_errors.py
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2015 mulhern <amulhern@redhat.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.device._errors
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Errors raised by Device methods.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
|
from six import add_metaclass
|
||||||
|
|
||||||
|
@add_metaclass(abc.ABCMeta)
|
||||||
|
class DeviceError(Exception):
|
||||||
|
"""
|
||||||
|
Any error raised when messing around w/ or trying to discover devices.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@add_metaclass(abc.ABCMeta)
|
||||||
|
class DeviceNotFoundError(DeviceError):
|
||||||
|
"""
|
||||||
|
An exception indicating that no :class:`Device` was found.
|
||||||
|
|
||||||
|
.. versionchanged:: 0.5
|
||||||
|
Rename from ``NoSuchDeviceError`` to its current name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceNotFoundAtPathError(DeviceNotFoundError):
|
||||||
|
"""
|
||||||
|
A :exc:`DeviceNotFoundError` indicating that no :class:`Device` was
|
||||||
|
found at a given path.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, sys_path):
|
||||||
|
DeviceNotFoundError.__init__(self, sys_path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sys_path(self):
|
||||||
|
"""
|
||||||
|
The path that caused this error as string.
|
||||||
|
"""
|
||||||
|
return self.args[0]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'No device at {0!r}'.format(self.sys_path)
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceNotFoundByFileError(DeviceNotFoundError):
|
||||||
|
"""
|
||||||
|
A :exc:`DeviceNotFoundError` indicating that no :class:`Device` was
|
||||||
|
found from the given filename.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class DeviceNotFoundByInterfaceIndexError(DeviceNotFoundError):
|
||||||
|
"""
|
||||||
|
A :exc:`DeviceNotFoundError` indicating that no :class:`Device` was found
|
||||||
|
from the given interface index.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class DeviceNotFoundByKernelDeviceError(DeviceNotFoundError):
|
||||||
|
"""
|
||||||
|
A :exc:`DeviceNotFoundError` indicating that no :class:`Device` was found
|
||||||
|
from the given kernel device string.
|
||||||
|
|
||||||
|
The format of the kernel device string is defined in the
|
||||||
|
systemd.journal-fields man pages.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceNotFoundByNameError(DeviceNotFoundError):
|
||||||
|
"""
|
||||||
|
A :exc:`DeviceNotFoundError` indicating that no :class:`Device` was
|
||||||
|
found with a given name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, subsystem, sys_name):
|
||||||
|
DeviceNotFoundError.__init__(self, subsystem, sys_name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def subsystem(self):
|
||||||
|
"""
|
||||||
|
The subsystem that caused this error as string.
|
||||||
|
"""
|
||||||
|
return self.args[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sys_name(self):
|
||||||
|
"""
|
||||||
|
The sys name that caused this error as string.
|
||||||
|
"""
|
||||||
|
return self.args[1]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'No device {0.sys_name!r} in {0.subsystem!r}'.format(self)
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceNotFoundByNumberError(DeviceNotFoundError):
|
||||||
|
"""
|
||||||
|
A :exc:`DeviceNotFoundError` indicating, that no :class:`Device` was found
|
||||||
|
for a given device number.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, typ, number):
|
||||||
|
DeviceNotFoundError.__init__(self, typ, number)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_type(self):
|
||||||
|
"""
|
||||||
|
The device type causing this error as string. Either ``'char'`` or
|
||||||
|
``'block'``.
|
||||||
|
"""
|
||||||
|
return self.args[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_number(self):
|
||||||
|
"""
|
||||||
|
The device number causing this error as integer.
|
||||||
|
"""
|
||||||
|
return self.args[1]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ('No {0.device_type} device with number '
|
||||||
|
'{0.device_number}'.format(self))
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceNotFoundInEnvironmentError(DeviceNotFoundError):
|
||||||
|
"""
|
||||||
|
A :exc:`DeviceNotFoundError` indicating, that no :class:`Device` could
|
||||||
|
be constructed from the process environment.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'No device found in environment'
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceValueError(DeviceError):
|
||||||
|
"""
|
||||||
|
Raised when a parameter has an unacceptable value.
|
||||||
|
|
||||||
|
May also be raised when the parameter has an unacceptable type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_FMT_STR = "value '%s' for parameter %s is unacceptable"
|
||||||
|
|
||||||
|
def __init__(self, value, param, msg=None):
|
||||||
|
""" Initializer.
|
||||||
|
|
||||||
|
:param object value: the value
|
||||||
|
:param str param: the parameter
|
||||||
|
:param str msg: an explanatory message
|
||||||
|
"""
|
||||||
|
# pylint: disable=super-init-not-called
|
||||||
|
self._value = value
|
||||||
|
self._param = param
|
||||||
|
self._msg = msg
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self._msg:
|
||||||
|
fmt_str = self._FMT_STR + ": %s"
|
||||||
|
return fmt_str % (self._value, self._param, self._msg)
|
||||||
|
else:
|
||||||
|
return self._FMT_STR % (self._value, self._param)
|
28
deb_dist/multibootusb-8.5.0/scripts/pyudev/_os/__init__.py
Normal file
28
deb_dist/multibootusb-8.5.0/scripts/pyudev/_os/__init__.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2015 mulhern <amulhern@redhat.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._os
|
||||||
|
==========
|
||||||
|
|
||||||
|
Extras to compensate for deficiencies in python os module.
|
||||||
|
|
||||||
|
.. moduleauthor:: mulhern <amulhern@redhat.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from . import pipe
|
||||||
|
from . import poll
|
159
deb_dist/multibootusb-8.5.0/scripts/pyudev/_os/pipe.py
Normal file
159
deb_dist/multibootusb-8.5.0/scripts/pyudev/_os/pipe.py
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._os.pipe
|
||||||
|
===============
|
||||||
|
|
||||||
|
Fallback implementations for pipe.
|
||||||
|
|
||||||
|
1. pipe2 from python os module
|
||||||
|
2. pipe2 from libc
|
||||||
|
3. pipe from python os module
|
||||||
|
|
||||||
|
The Pipe class wraps the chosen implementation.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
|
import fcntl
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from .._ctypeslib.libc import fd_pair
|
||||||
|
from .._ctypeslib.libc import ERROR_CHECKERS
|
||||||
|
from .._ctypeslib.libc import SIGNATURES
|
||||||
|
from .._ctypeslib.utils import load_ctypes_library
|
||||||
|
|
||||||
|
# Define O_CLOEXEC, if not present in os already
|
||||||
|
O_CLOEXEC = getattr(os, 'O_CLOEXEC', 0o2000000)
|
||||||
|
|
||||||
|
|
||||||
|
def _pipe2_ctypes(libc, flags):
|
||||||
|
"""A ``pipe2`` implementation using ``pipe2`` from ctypes.
|
||||||
|
|
||||||
|
``libc`` is a :class:`ctypes.CDLL` object for libc. ``flags`` is an
|
||||||
|
integer providing the flags to ``pipe2``.
|
||||||
|
|
||||||
|
Return a pair of file descriptors ``(r, w)``.
|
||||||
|
|
||||||
|
"""
|
||||||
|
fds = fd_pair()
|
||||||
|
libc.pipe2(fds, flags)
|
||||||
|
return fds[0], fds[1]
|
||||||
|
|
||||||
|
|
||||||
|
def _pipe2_by_pipe(flags):
|
||||||
|
"""A ``pipe2`` implementation using :func:`os.pipe`.
|
||||||
|
|
||||||
|
``flags`` is an integer providing the flags to ``pipe2``.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
This implementation is not atomic!
|
||||||
|
|
||||||
|
Return a pair of file descriptors ``(r, w)``.
|
||||||
|
|
||||||
|
"""
|
||||||
|
fds = os.pipe()
|
||||||
|
if flags & os.O_NONBLOCK != 0:
|
||||||
|
for fd in fds:
|
||||||
|
set_fd_status_flag(fd, os.O_NONBLOCK)
|
||||||
|
if flags & O_CLOEXEC != 0:
|
||||||
|
for fd in fds:
|
||||||
|
set_fd_flag(fd, O_CLOEXEC)
|
||||||
|
return fds
|
||||||
|
|
||||||
|
|
||||||
|
def _get_pipe2_implementation():
|
||||||
|
"""Find the appropriate implementation for ``pipe2``.
|
||||||
|
|
||||||
|
Return a function implementing ``pipe2``."""
|
||||||
|
if hasattr(os, 'pipe2'):
|
||||||
|
return os.pipe2 # pylint: disable=no-member
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
libc = load_ctypes_library("libc", SIGNATURES, ERROR_CHECKERS)
|
||||||
|
return (partial(_pipe2_ctypes, libc)
|
||||||
|
if hasattr(libc, 'pipe2') else
|
||||||
|
_pipe2_by_pipe)
|
||||||
|
except ImportError:
|
||||||
|
return _pipe2_by_pipe
|
||||||
|
|
||||||
|
|
||||||
|
_PIPE2 = _get_pipe2_implementation()
|
||||||
|
|
||||||
|
|
||||||
|
def set_fd_flag(fd, flag):
|
||||||
|
"""Set a flag on a file descriptor.
|
||||||
|
|
||||||
|
``fd`` is the file descriptor or file object, ``flag`` the flag as integer.
|
||||||
|
|
||||||
|
"""
|
||||||
|
flags = fcntl.fcntl(fd, fcntl.F_GETFD, 0)
|
||||||
|
fcntl.fcntl(fd, fcntl.F_SETFD, flags | flag)
|
||||||
|
|
||||||
|
|
||||||
|
def set_fd_status_flag(fd, flag):
|
||||||
|
"""Set a status flag on a file descriptor.
|
||||||
|
|
||||||
|
``fd`` is the file descriptor or file object, ``flag`` the flag as integer.
|
||||||
|
|
||||||
|
"""
|
||||||
|
flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0)
|
||||||
|
fcntl.fcntl(fd, fcntl.F_SETFL, flags | flag)
|
||||||
|
|
||||||
|
|
||||||
|
class Pipe(object):
|
||||||
|
"""A unix pipe.
|
||||||
|
|
||||||
|
A pipe object provides two file objects: :attr:`source` is a readable file
|
||||||
|
object, and :attr:`sink` a writeable. Bytes written to :attr:`sink` appear
|
||||||
|
at :attr:`source`.
|
||||||
|
|
||||||
|
Open a pipe with :meth:`open()`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def open(cls):
|
||||||
|
"""Open and return a new :class:`Pipe`.
|
||||||
|
|
||||||
|
The pipe uses non-blocking IO."""
|
||||||
|
source, sink = _PIPE2(os.O_NONBLOCK | O_CLOEXEC)
|
||||||
|
return cls(source, sink)
|
||||||
|
|
||||||
|
def __init__(self, source_fd, sink_fd):
|
||||||
|
"""Create a new pipe object from the given file descriptors.
|
||||||
|
|
||||||
|
``source_fd`` is a file descriptor for the readable side of the pipe,
|
||||||
|
``sink_fd`` is a file descriptor for the writeable side."""
|
||||||
|
self.source = os.fdopen(source_fd, 'rb', 0)
|
||||||
|
self.sink = os.fdopen(sink_fd, 'wb', 0)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Closes both sides of the pipe."""
|
||||||
|
try:
|
||||||
|
self.source.close()
|
||||||
|
finally:
|
||||||
|
self.sink.close()
|
119
deb_dist/multibootusb-8.5.0/scripts/pyudev/_os/poll.py
Normal file
119
deb_dist/multibootusb-8.5.0/scripts/pyudev/_os/poll.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._os.poll
|
||||||
|
===============
|
||||||
|
|
||||||
|
Operating system interface for pyudev.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import select
|
||||||
|
|
||||||
|
from .._util import eintr_retry_call
|
||||||
|
|
||||||
|
|
||||||
|
class Poll(object):
|
||||||
|
"""A poll object.
|
||||||
|
|
||||||
|
This object essentially provides a more convenient interface around
|
||||||
|
:class:`select.poll`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_EVENT_TO_MASK = {'r': select.POLLIN,
|
||||||
|
'w': select.POLLOUT}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _has_event(events, event):
|
||||||
|
return events & event != 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def for_events(cls, *events):
|
||||||
|
"""Listen for ``events``.
|
||||||
|
|
||||||
|
``events`` is a list of ``(fd, event)`` pairs, where ``fd`` is a file
|
||||||
|
descriptor or file object and ``event`` either ``'r'`` or ``'w'``. If
|
||||||
|
``r``, listen for whether that is ready to be read. If ``w``, listen
|
||||||
|
for whether the channel is ready to be written to.
|
||||||
|
|
||||||
|
"""
|
||||||
|
notifier = eintr_retry_call(select.poll)
|
||||||
|
for fd, event in events:
|
||||||
|
mask = cls._EVENT_TO_MASK.get(event)
|
||||||
|
if not mask:
|
||||||
|
raise ValueError('Unknown event type: {0!r}'.format(event))
|
||||||
|
notifier.register(fd, mask)
|
||||||
|
return cls(notifier)
|
||||||
|
|
||||||
|
def __init__(self, notifier):
|
||||||
|
"""Create a poll object for the given ``notifier``.
|
||||||
|
|
||||||
|
``notifier`` is the :class:`select.poll` object wrapped by the new poll
|
||||||
|
object.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self._notifier = notifier
|
||||||
|
|
||||||
|
def poll(self, timeout=None):
|
||||||
|
"""Poll for events.
|
||||||
|
|
||||||
|
``timeout`` is an integer specifying how long to wait for events (in
|
||||||
|
milliseconds). If omitted, ``None`` or negative, wait until an event
|
||||||
|
occurs.
|
||||||
|
|
||||||
|
Return a list of all events that occurred before ``timeout``, where
|
||||||
|
each event is a pair ``(fd, event)``. ``fd`` is the integral file
|
||||||
|
descriptor, and ``event`` a string indicating the event type. If
|
||||||
|
``'r'``, there is data to read from ``fd``. If ``'w'``, ``fd`` is
|
||||||
|
writable without blocking now. If ``'h'``, the file descriptor was
|
||||||
|
hung up (i.e. the remote side of a pipe was closed).
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Return a list to allow clients to determine whether there are any
|
||||||
|
# events at all with a simple truthiness test.
|
||||||
|
return list(self._parse_events(eintr_retry_call(self._notifier.poll, timeout)))
|
||||||
|
|
||||||
|
def _parse_events(self, events):
|
||||||
|
"""Parse ``events``.
|
||||||
|
|
||||||
|
``events`` is a list of events as returned by
|
||||||
|
:meth:`select.poll.poll()`.
|
||||||
|
|
||||||
|
Yield all parsed events.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for fd, event_mask in events:
|
||||||
|
if self._has_event(event_mask, select.POLLNVAL):
|
||||||
|
raise IOError('File descriptor not open: {0!r}'.format(fd))
|
||||||
|
elif self._has_event(event_mask, select.POLLERR):
|
||||||
|
raise IOError('Error while polling fd: {0!r}'.format(fd))
|
||||||
|
|
||||||
|
if self._has_event(event_mask, select.POLLIN):
|
||||||
|
yield fd, 'r'
|
||||||
|
if self._has_event(event_mask, select.POLLOUT):
|
||||||
|
yield fd, 'w'
|
||||||
|
if self._has_event(event_mask, select.POLLHUP):
|
||||||
|
yield fd, 'h'
|
207
deb_dist/multibootusb-8.5.0/scripts/pyudev/_qt_base.py
Normal file
207
deb_dist/multibootusb-8.5.0/scripts/pyudev/_qt_base.py
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011, 2012, 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._qt_base
|
||||||
|
===============
|
||||||
|
|
||||||
|
Base mixin class for Qt4,Qt5 support.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
from pyudev.device import Device
|
||||||
|
|
||||||
|
class MonitorObserverMixin(object):
|
||||||
|
"""
|
||||||
|
Base mixin for pyqt monitor observers.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
|
def _setup_notifier(self, monitor, notifier_class):
|
||||||
|
self.monitor = monitor
|
||||||
|
self.notifier = notifier_class(
|
||||||
|
monitor.fileno(), notifier_class.Read, self)
|
||||||
|
self.notifier.activated[int].connect(self._process_udev_event)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
"""
|
||||||
|
Whether this observer is enabled or not.
|
||||||
|
|
||||||
|
If ``True`` (the default), this observer is enabled, and emits events.
|
||||||
|
Otherwise it is disabled and does not emit any events. This merely
|
||||||
|
reflects the state of the ``enabled`` property of the underlying
|
||||||
|
:attr:`notifier`.
|
||||||
|
|
||||||
|
.. versionadded:: 0.14
|
||||||
|
"""
|
||||||
|
return self.notifier.isEnabled()
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, value):
|
||||||
|
self.notifier.setEnabled(value)
|
||||||
|
|
||||||
|
def _process_udev_event(self):
|
||||||
|
"""
|
||||||
|
Attempt to receive a single device event from the monitor, process
|
||||||
|
the event and emit corresponding signals.
|
||||||
|
|
||||||
|
Called by ``QSocketNotifier``, if data is available on the udev
|
||||||
|
monitoring socket.
|
||||||
|
"""
|
||||||
|
device = self.monitor.poll(timeout=0)
|
||||||
|
if device is not None:
|
||||||
|
self._emit_event(device)
|
||||||
|
|
||||||
|
def _emit_event(self, device):
|
||||||
|
self.deviceEvent.emit(device)
|
||||||
|
|
||||||
|
|
||||||
|
class QUDevMonitorObserverMixin(MonitorObserverMixin):
|
||||||
|
"""
|
||||||
|
Obsolete monitor observer mixin.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
|
def _setup_notifier(self, monitor, notifier_class):
|
||||||
|
MonitorObserverMixin._setup_notifier(self, monitor, notifier_class)
|
||||||
|
self._action_signal_map = {
|
||||||
|
'add': self.deviceAdded, 'remove': self.deviceRemoved,
|
||||||
|
'change': self.deviceChanged, 'move': self.deviceMoved,
|
||||||
|
}
|
||||||
|
import warnings
|
||||||
|
warnings.warn('Will be removed in 1.0. '
|
||||||
|
'Use pyudev.pyqt4.MonitorObserver instead.',
|
||||||
|
DeprecationWarning)
|
||||||
|
|
||||||
|
def _emit_event(self, device):
|
||||||
|
self.deviceEvent.emit(device.action, device)
|
||||||
|
signal = self._action_signal_map.get(device.action)
|
||||||
|
if signal is not None:
|
||||||
|
signal.emit(device)
|
||||||
|
|
||||||
|
def make_init(qobject, socket_notifier):
|
||||||
|
"""
|
||||||
|
Generates an initializer to observer the given ``monitor``
|
||||||
|
(a :class:`~pyudev.Monitor`):
|
||||||
|
|
||||||
|
``parent`` is the parent :class:`~PyQt{4,5}.QtCore.QObject` of this
|
||||||
|
object. It is passed unchanged to the inherited constructor of
|
||||||
|
:class:`~PyQt{4,5}.QtCore.QObject`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, monitor, parent=None):
|
||||||
|
qobject.__init__(self, parent)
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
self._setup_notifier(monitor, socket_notifier)
|
||||||
|
|
||||||
|
return __init__
|
||||||
|
|
||||||
|
|
||||||
|
class MonitorObserverGenerator(object):
|
||||||
|
"""
|
||||||
|
Class to generate a MonitorObserver class.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def make_monitor_observer(qobject, signal, socket_notifier):
|
||||||
|
"""Generates an observer for device events integrating into the
|
||||||
|
PyQt{4,5} mainloop.
|
||||||
|
|
||||||
|
This class inherits :class:`~PyQt{4,5}.QtCore.QObject` to turn device
|
||||||
|
events into Qt signals:
|
||||||
|
|
||||||
|
>>> from pyudev import Context, Monitor
|
||||||
|
>>> from pyudev.pyqt4 import MonitorObserver
|
||||||
|
>>> context = Context()
|
||||||
|
>>> monitor = Monitor.from_netlink(context)
|
||||||
|
>>> monitor.filter_by(subsystem='input')
|
||||||
|
>>> observer = MonitorObserver(monitor)
|
||||||
|
>>> def device_event(device):
|
||||||
|
... print('event {0} on device {1}'.format(device.action, device))
|
||||||
|
>>> observer.deviceEvent.connect(device_event)
|
||||||
|
>>> monitor.start()
|
||||||
|
|
||||||
|
This class is a child of :class:`~{PySide, PyQt{4,5}}.QtCore.QObject`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return type(
|
||||||
|
str("MonitorObserver"),
|
||||||
|
(qobject, MonitorObserverMixin),
|
||||||
|
{
|
||||||
|
str("__init__") : make_init(qobject, socket_notifier),
|
||||||
|
str("deviceEvent") : signal(Device)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class QUDevMonitorObserverGenerator(object):
|
||||||
|
"""
|
||||||
|
Class to generate a MonitorObserver class.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def make_monitor_observer(qobject, signal, socket_notifier):
|
||||||
|
"""Generates an observer for device events integrating into the
|
||||||
|
PyQt{4,5} mainloop.
|
||||||
|
|
||||||
|
This class inherits :class:`~PyQt{4,5}.QtCore.QObject` to turn device
|
||||||
|
events into Qt signals:
|
||||||
|
|
||||||
|
>>> from pyudev import Context, Monitor
|
||||||
|
>>> from pyudev.pyqt4 import MonitorObserver
|
||||||
|
>>> context = Context()
|
||||||
|
>>> monitor = Monitor.from_netlink(context)
|
||||||
|
>>> monitor.filter_by(subsystem='input')
|
||||||
|
>>> observer = MonitorObserver(monitor)
|
||||||
|
>>> def device_event(device):
|
||||||
|
... print('event {0} on device {1}'.format(device.action, device))
|
||||||
|
>>> observer.deviceEvent.connect(device_event)
|
||||||
|
>>> monitor.start()
|
||||||
|
|
||||||
|
This class is a child of :class:`~{PyQt{4,5}, PySide}.QtCore.QObject`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return type(
|
||||||
|
str("QUDevMonitorObserver"),
|
||||||
|
(qobject, QUDevMonitorObserverMixin),
|
||||||
|
{
|
||||||
|
str("__init__") : make_init(qobject, socket_notifier),
|
||||||
|
#: emitted upon arbitrary device events
|
||||||
|
str("deviceEvent") : signal(six.text_type, Device),
|
||||||
|
#: emitted if a device was added
|
||||||
|
str("deviceAdded") : signal(Device),
|
||||||
|
#: emitted if a device was removed
|
||||||
|
str("deviceRemoved") : signal(Device),
|
||||||
|
#: emitted if a device was changed
|
||||||
|
str("deviceChanged") : signal(Device),
|
||||||
|
#: emitted if a device was moved
|
||||||
|
str("deviceMoved") : signal(Device)
|
||||||
|
}
|
||||||
|
)
|
202
deb_dist/multibootusb-8.5.0/scripts/pyudev/_util.py
Normal file
202
deb_dist/multibootusb-8.5.0/scripts/pyudev/_util.py
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011, 2012 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev._util
|
||||||
|
============
|
||||||
|
|
||||||
|
Internal utilities
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import (print_function, division, unicode_literals,
|
||||||
|
absolute_import)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from subprocess import check_output
|
||||||
|
except ImportError:
|
||||||
|
from pyudev._compat import check_output
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import stat
|
||||||
|
import errno
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_byte_string(value):
|
||||||
|
"""
|
||||||
|
Return the given ``value`` as bytestring.
|
||||||
|
|
||||||
|
If the given ``value`` is not a byte string, but a real unicode string, it
|
||||||
|
is encoded with the filesystem encoding (as in
|
||||||
|
:func:`sys.getfilesystemencoding()`).
|
||||||
|
"""
|
||||||
|
if not isinstance(value, bytes):
|
||||||
|
value = value.encode(sys.getfilesystemencoding())
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_unicode_string(value):
|
||||||
|
"""
|
||||||
|
Return the given ``value`` as unicode string.
|
||||||
|
|
||||||
|
If the given ``value`` is not a unicode string, but a byte string, it is
|
||||||
|
decoded with the filesystem encoding (as in
|
||||||
|
:func:`sys.getfilesystemencoding()`).
|
||||||
|
"""
|
||||||
|
if not isinstance(value, six.text_type):
|
||||||
|
value = value.decode(sys.getfilesystemencoding())
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def property_value_to_bytes(value):
|
||||||
|
"""
|
||||||
|
Return a byte string, which represents the given ``value`` in a way
|
||||||
|
suitable as raw value of an udev property.
|
||||||
|
|
||||||
|
If ``value`` is a boolean object, it is converted to ``'1'`` or ``'0'``,
|
||||||
|
depending on whether ``value`` is ``True`` or ``False``. If ``value`` is a
|
||||||
|
byte string already, it is returned unchanged. Anything else is simply
|
||||||
|
converted to a unicode string, and then passed to
|
||||||
|
:func:`ensure_byte_string`.
|
||||||
|
"""
|
||||||
|
# udev represents boolean values as 1 or 0, therefore an explicit
|
||||||
|
# conversion to int is required for boolean values
|
||||||
|
if isinstance(value, bool):
|
||||||
|
value = int(value)
|
||||||
|
if isinstance(value, bytes):
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
return ensure_byte_string(six.text_type(value))
|
||||||
|
|
||||||
|
|
||||||
|
def string_to_bool(value):
|
||||||
|
"""
|
||||||
|
Convert the given unicode string ``value`` to a boolean object.
|
||||||
|
|
||||||
|
If ``value`` is ``'1'``, ``True`` is returned. If ``value`` is ``'0'``,
|
||||||
|
``False`` is returned. Any other value raises a
|
||||||
|
:exc:`~exceptions.ValueError`.
|
||||||
|
"""
|
||||||
|
if value not in ('1', '0'):
|
||||||
|
raise ValueError('Not a boolean value: {0!r}'.format(value))
|
||||||
|
return value == '1'
|
||||||
|
|
||||||
|
|
||||||
|
def udev_list_iterate(libudev, entry):
|
||||||
|
"""
|
||||||
|
Iteration helper for udev list entry objects.
|
||||||
|
|
||||||
|
Yield a tuple ``(name, value)``. ``name`` and ``value`` are bytestrings
|
||||||
|
containing the name and the value of the list entry. The exact contents
|
||||||
|
depend on the list iterated over.
|
||||||
|
"""
|
||||||
|
while entry:
|
||||||
|
name = libudev.udev_list_entry_get_name(entry)
|
||||||
|
value = libudev.udev_list_entry_get_value(entry)
|
||||||
|
yield (name, value)
|
||||||
|
entry = libudev.udev_list_entry_get_next(entry)
|
||||||
|
|
||||||
|
|
||||||
|
def get_device_type(filename):
|
||||||
|
"""
|
||||||
|
Get the device type of a device file.
|
||||||
|
|
||||||
|
``filename`` is a string containing the path of a device file.
|
||||||
|
|
||||||
|
Return ``'char'`` if ``filename`` is a character device, or ``'block'`` if
|
||||||
|
``filename`` is a block device. Raise :exc:`~exceptions.ValueError` if
|
||||||
|
``filename`` is no device file at all. Raise
|
||||||
|
:exc:`~exceptions.EnvironmentError` if ``filename`` does not exist or if
|
||||||
|
its metadata was inaccessible.
|
||||||
|
|
||||||
|
.. versionadded:: 0.15
|
||||||
|
"""
|
||||||
|
mode = os.stat(filename).st_mode
|
||||||
|
if stat.S_ISCHR(mode):
|
||||||
|
return 'char'
|
||||||
|
elif stat.S_ISBLK(mode):
|
||||||
|
return 'block'
|
||||||
|
else:
|
||||||
|
raise ValueError('not a device file: {0!r}'.format(filename))
|
||||||
|
|
||||||
|
|
||||||
|
def eintr_retry_call(func, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Handle interruptions to an interruptible system call.
|
||||||
|
|
||||||
|
Run an interruptible system call in a loop and retry if it raises EINTR.
|
||||||
|
The signal calls that may raise EINTR prior to Python 3.5 are listed in
|
||||||
|
PEP 0475. Any calls to these functions must be wrapped in eintr_retry_call
|
||||||
|
in order to handle EINTR returns in older versions of Python.
|
||||||
|
|
||||||
|
This function is safe to use under Python 3.5 and newer since the wrapped
|
||||||
|
function will simply return without raising EINTR.
|
||||||
|
|
||||||
|
This function is based on _eintr_retry_call in python's subprocess.py.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# select.error inherits from Exception instead of OSError in Python 2
|
||||||
|
import select
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
except (OSError, IOError, select.error) as err:
|
||||||
|
# If this is not an IOError or OSError, it's the old select.error
|
||||||
|
# type, which means that the errno is only accessible via subscript
|
||||||
|
if isinstance(err, (OSError, IOError)):
|
||||||
|
error_code = err.errno
|
||||||
|
else:
|
||||||
|
error_code = err.args[0]
|
||||||
|
|
||||||
|
if error_code == errno.EINTR:
|
||||||
|
continue
|
||||||
|
raise
|
||||||
|
|
||||||
|
def udev_version():
|
||||||
|
"""
|
||||||
|
Get the version of the underlying udev library.
|
||||||
|
|
||||||
|
udev doesn't use a standard major-minor versioning scheme, but instead
|
||||||
|
labels releases with a single consecutive number. Consequently, the
|
||||||
|
version number returned by this function is a single integer, and not a
|
||||||
|
tuple (like for instance the interpreter version in
|
||||||
|
:data:`sys.version_info`).
|
||||||
|
|
||||||
|
As libudev itself does not provide a function to query the version number,
|
||||||
|
this function calls the ``udevadm`` utility, so be prepared to catch
|
||||||
|
:exc:`~exceptions.EnvironmentError` and
|
||||||
|
:exc:`~subprocess.CalledProcessError` if you call this function.
|
||||||
|
|
||||||
|
Return the version number as single integer. Raise
|
||||||
|
:exc:`~exceptions.ValueError`, if the version number retrieved from udev
|
||||||
|
could not be converted to an integer. Raise
|
||||||
|
:exc:`~exceptions.EnvironmentError`, if ``udevadm`` was not found, or could
|
||||||
|
not be executed. Raise :exc:`subprocess.CalledProcessError`, if
|
||||||
|
``udevadm`` returned a non-zero exit code. On Python 2.7 or newer, the
|
||||||
|
``output`` attribute of this exception is correctly set.
|
||||||
|
|
||||||
|
.. versionadded:: 0.8
|
||||||
|
"""
|
||||||
|
output = ensure_unicode_string(check_output(['udevadm', '--version']))
|
||||||
|
return int(output.strip())
|
394
deb_dist/multibootusb-8.5.0/scripts/pyudev/core.py
Normal file
394
deb_dist/multibootusb-8.5.0/scripts/pyudev/core.py
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.core
|
||||||
|
===========
|
||||||
|
|
||||||
|
Core types and functions of :mod:`pyudev`.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import (print_function, division, unicode_literals,
|
||||||
|
absolute_import)
|
||||||
|
|
||||||
|
from .device import Devices
|
||||||
|
from ._errors import DeviceNotFoundAtPathError
|
||||||
|
from ._ctypeslib.libudev import ERROR_CHECKERS
|
||||||
|
from ._ctypeslib.libudev import SIGNATURES
|
||||||
|
from ._ctypeslib.utils import load_ctypes_library
|
||||||
|
|
||||||
|
from ._util import ensure_byte_string
|
||||||
|
from ._util import ensure_unicode_string
|
||||||
|
from ._util import property_value_to_bytes
|
||||||
|
from ._util import udev_list_iterate
|
||||||
|
|
||||||
|
|
||||||
|
class Context(object):
|
||||||
|
"""
|
||||||
|
A device database connection.
|
||||||
|
|
||||||
|
This class represents a connection to the udev device database, and is
|
||||||
|
really *the* central object to access udev. You need an instance of this
|
||||||
|
class for almost anything else in pyudev.
|
||||||
|
|
||||||
|
This class itself gives access to various udev configuration data (e.g.
|
||||||
|
:attr:`sys_path`, :attr:`device_path`), and provides device enumeration
|
||||||
|
(:meth:`list_devices()`).
|
||||||
|
|
||||||
|
Instances of this class can directly be given as ``udev *`` to functions
|
||||||
|
wrapped through :mod:`ctypes`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""
|
||||||
|
Create a new context.
|
||||||
|
"""
|
||||||
|
self._libudev = load_ctypes_library('udev', SIGNATURES, ERROR_CHECKERS)
|
||||||
|
self._as_parameter_ = self._libudev.udev_new()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._libudev.udev_unref(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sys_path(self):
|
||||||
|
"""
|
||||||
|
The ``sysfs`` mount point defaulting to ``/sys'`` as unicode string.
|
||||||
|
"""
|
||||||
|
if hasattr(self._libudev, 'udev_get_sys_path'):
|
||||||
|
return ensure_unicode_string(self._libudev.udev_get_sys_path(self))
|
||||||
|
else:
|
||||||
|
# Fixed path since udev 183
|
||||||
|
return '/sys'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_path(self):
|
||||||
|
"""
|
||||||
|
The device directory path defaulting to ``/dev`` as unicode string.
|
||||||
|
"""
|
||||||
|
if hasattr(self._libudev, 'udev_get_dev_path'):
|
||||||
|
return ensure_unicode_string(self._libudev.udev_get_dev_path(self))
|
||||||
|
else:
|
||||||
|
# Fixed path since udev 183
|
||||||
|
return '/dev'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def run_path(self):
|
||||||
|
"""
|
||||||
|
The run runtime directory path defaulting to ``/run`` as unicode
|
||||||
|
string.
|
||||||
|
|
||||||
|
.. udevversion:: 167
|
||||||
|
|
||||||
|
.. versionadded:: 0.10
|
||||||
|
"""
|
||||||
|
if hasattr(self._libudev, 'udev_get_run_path'):
|
||||||
|
return ensure_unicode_string(self._libudev.udev_get_run_path(self))
|
||||||
|
else:
|
||||||
|
return '/run/udev'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log_priority(self):
|
||||||
|
"""
|
||||||
|
The logging priority of the interal logging facitility of udev as
|
||||||
|
integer with a standard :mod:`syslog` priority. Assign to this
|
||||||
|
property to change the logging priority.
|
||||||
|
|
||||||
|
UDev uses the standard :mod:`syslog` priorities. Constants for these
|
||||||
|
priorities are defined in the :mod:`syslog` module in the standard
|
||||||
|
library:
|
||||||
|
|
||||||
|
>>> import syslog
|
||||||
|
>>> context = pyudev.Context()
|
||||||
|
>>> context.log_priority = syslog.LOG_DEBUG
|
||||||
|
|
||||||
|
.. versionadded:: 0.9
|
||||||
|
"""
|
||||||
|
return self._libudev.udev_get_log_priority(self)
|
||||||
|
|
||||||
|
@log_priority.setter
|
||||||
|
def log_priority(self, value):
|
||||||
|
"""
|
||||||
|
Set the log priority.
|
||||||
|
|
||||||
|
:param int value: the log priority.
|
||||||
|
"""
|
||||||
|
self._libudev.udev_set_log_priority(self, value)
|
||||||
|
|
||||||
|
def list_devices(self, **kwargs):
|
||||||
|
"""
|
||||||
|
List all available devices.
|
||||||
|
|
||||||
|
The arguments of this method are the same as for
|
||||||
|
:meth:`Enumerator.match()`. In fact, the arguments are simply passed
|
||||||
|
straight to method :meth:`~Enumerator.match()`.
|
||||||
|
|
||||||
|
This function creates and returns an :class:`Enumerator` object,
|
||||||
|
that can be used to filter the list of devices, and eventually
|
||||||
|
retrieve :class:`Device` objects representing matching devices.
|
||||||
|
|
||||||
|
.. versionchanged:: 0.8
|
||||||
|
Accept keyword arguments now for easy matching.
|
||||||
|
"""
|
||||||
|
return Enumerator(self).match(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class Enumerator(object):
|
||||||
|
"""
|
||||||
|
A filtered iterable of devices.
|
||||||
|
|
||||||
|
To retrieve devices, simply iterate over an instance of this class.
|
||||||
|
This operation yields :class:`Device` objects representing the available
|
||||||
|
devices.
|
||||||
|
|
||||||
|
Before iteration the device list can be filtered by subsystem or by
|
||||||
|
property values using :meth:`match_subsystem` and
|
||||||
|
:meth:`match_property`. Multiple subsystem (property) filters are
|
||||||
|
combined using a logical OR, filters of different types are combined
|
||||||
|
using a logical AND. The following filter for instance::
|
||||||
|
|
||||||
|
devices.match_subsystem('block').match_property(
|
||||||
|
'ID_TYPE', 'disk').match_property('DEVTYPE', 'disk')
|
||||||
|
|
||||||
|
means the following::
|
||||||
|
|
||||||
|
subsystem == 'block' and (ID_TYPE == 'disk' or DEVTYPE == 'disk')
|
||||||
|
|
||||||
|
Once added, a filter cannot be removed anymore. Create a new object
|
||||||
|
instead.
|
||||||
|
|
||||||
|
Instances of this class can directly be given as given ``udev_enumerate *``
|
||||||
|
to functions wrapped through :mod:`ctypes`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, context):
|
||||||
|
"""
|
||||||
|
Create a new enumerator with the given ``context`` (a
|
||||||
|
:class:`Context` instance).
|
||||||
|
|
||||||
|
While you can create objects of this class directly, this is not
|
||||||
|
recommended. Call :method:`Context.list_devices()` instead.
|
||||||
|
"""
|
||||||
|
if not isinstance(context, Context):
|
||||||
|
raise TypeError('Invalid context object')
|
||||||
|
self.context = context
|
||||||
|
self._as_parameter_ = context._libudev.udev_enumerate_new(context)
|
||||||
|
self._libudev = context._libudev
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._libudev.udev_enumerate_unref(self)
|
||||||
|
|
||||||
|
def match(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Include devices according to the rules defined by the keyword
|
||||||
|
arguments. These keyword arguments are interpreted as follows:
|
||||||
|
|
||||||
|
- The value for the keyword argument ``subsystem`` is forwarded to
|
||||||
|
:meth:`match_subsystem()`.
|
||||||
|
- The value for the keyword argument ``sys_name`` is forwared to
|
||||||
|
:meth:`match_sys_name()`.
|
||||||
|
- The value for the keyword argument ``tag`` is forwared to
|
||||||
|
:meth:`match_tag()`.
|
||||||
|
- The value for the keyword argument ``parent`` is forwared to
|
||||||
|
:meth:`match_parent()`.
|
||||||
|
- All other keyword arguments are forwareded one by one to
|
||||||
|
:meth:`match_property()`. The keyword argument itself is interpreted
|
||||||
|
as property name, the value of the keyword argument as the property
|
||||||
|
value.
|
||||||
|
|
||||||
|
All keyword arguments are optional, calling this method without no
|
||||||
|
arguments at all is simply a noop.
|
||||||
|
|
||||||
|
Return the instance again.
|
||||||
|
|
||||||
|
.. versionadded:: 0.8
|
||||||
|
|
||||||
|
.. versionchanged:: 0.13
|
||||||
|
Add ``parent`` keyword.
|
||||||
|
"""
|
||||||
|
subsystem = kwargs.pop('subsystem', None)
|
||||||
|
if subsystem is not None:
|
||||||
|
self.match_subsystem(subsystem)
|
||||||
|
sys_name = kwargs.pop('sys_name', None)
|
||||||
|
if sys_name is not None:
|
||||||
|
self.match_sys_name(sys_name)
|
||||||
|
tag = kwargs.pop('tag', None)
|
||||||
|
if tag is not None:
|
||||||
|
self.match_tag(tag)
|
||||||
|
parent = kwargs.pop('parent', None)
|
||||||
|
if parent is not None:
|
||||||
|
self.match_parent(parent)
|
||||||
|
for prop, value in kwargs.items():
|
||||||
|
self.match_property(prop, value)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def match_subsystem(self, subsystem, nomatch=False):
|
||||||
|
"""
|
||||||
|
Include all devices, which are part of the given ``subsystem``.
|
||||||
|
|
||||||
|
``subsystem`` is either a unicode string or a byte string, containing
|
||||||
|
the name of the subsystem. If ``nomatch`` is ``True`` (default is
|
||||||
|
``False``), the match is inverted: A device is only included if it is
|
||||||
|
*not* part of the given ``subsystem``.
|
||||||
|
|
||||||
|
Note that, if a device has no subsystem, it is not included either
|
||||||
|
with value of ``nomatch`` True or with value of ``nomatch`` False.
|
||||||
|
|
||||||
|
Return the instance again.
|
||||||
|
"""
|
||||||
|
match = self._libudev.udev_enumerate_add_nomatch_subsystem \
|
||||||
|
if nomatch else self._libudev.udev_enumerate_add_match_subsystem
|
||||||
|
match(self, ensure_byte_string(subsystem))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def match_sys_name(self, sys_name):
|
||||||
|
"""
|
||||||
|
Include all devices with the given name.
|
||||||
|
|
||||||
|
``sys_name`` is a byte or unicode string containing the device name.
|
||||||
|
|
||||||
|
Return the instance again.
|
||||||
|
|
||||||
|
.. versionadded:: 0.8
|
||||||
|
"""
|
||||||
|
self._libudev.udev_enumerate_add_match_sysname(
|
||||||
|
self, ensure_byte_string(sys_name))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def match_property(self, prop, value):
|
||||||
|
"""
|
||||||
|
Include all devices, whose ``prop`` has the given ``value``.
|
||||||
|
|
||||||
|
``prop`` is either a unicode string or a byte string, containing
|
||||||
|
the name of the property to match. ``value`` is a property value,
|
||||||
|
being one of the following types:
|
||||||
|
|
||||||
|
- :func:`int`
|
||||||
|
- :func:`bool`
|
||||||
|
- A byte string
|
||||||
|
- Anything convertable to a unicode string (including a unicode string
|
||||||
|
itself)
|
||||||
|
|
||||||
|
Return the instance again.
|
||||||
|
"""
|
||||||
|
self._libudev.udev_enumerate_add_match_property(
|
||||||
|
self, ensure_byte_string(prop), property_value_to_bytes(value))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def match_attribute(self, attribute, value, nomatch=False):
|
||||||
|
"""
|
||||||
|
Include all devices, whose ``attribute`` has the given ``value``.
|
||||||
|
|
||||||
|
``attribute`` is either a unicode string or a byte string, containing
|
||||||
|
the name of a sys attribute to match. ``value`` is an attribute value,
|
||||||
|
being one of the following types:
|
||||||
|
|
||||||
|
- :func:`int`,
|
||||||
|
- :func:`bool`
|
||||||
|
- A byte string
|
||||||
|
- Anything convertable to a unicode string (including a unicode string
|
||||||
|
itself)
|
||||||
|
|
||||||
|
If ``nomatch`` is ``True`` (default is ``False``), the match is
|
||||||
|
inverted: A device is include if the ``attribute`` does *not* match
|
||||||
|
the given ``value``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
If ``nomatch`` is ``True``, devices which do not have the given
|
||||||
|
``attribute`` at all are also included. In other words, with
|
||||||
|
``nomatch=True`` the given ``attribute`` is *not* guaranteed to
|
||||||
|
exist on all returned devices.
|
||||||
|
|
||||||
|
Return the instance again.
|
||||||
|
"""
|
||||||
|
match = (self._libudev.udev_enumerate_add_match_sysattr
|
||||||
|
if not nomatch else
|
||||||
|
self._libudev.udev_enumerate_add_nomatch_sysattr)
|
||||||
|
match(self, ensure_byte_string(attribute),
|
||||||
|
property_value_to_bytes(value))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def match_tag(self, tag):
|
||||||
|
"""
|
||||||
|
Include all devices, which have the given ``tag`` attached.
|
||||||
|
|
||||||
|
``tag`` is a byte or unicode string containing the tag name.
|
||||||
|
|
||||||
|
Return the instance again.
|
||||||
|
|
||||||
|
.. udevversion:: 154
|
||||||
|
|
||||||
|
.. versionadded:: 0.6
|
||||||
|
"""
|
||||||
|
self._libudev.udev_enumerate_add_match_tag(self, ensure_byte_string(tag))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def match_is_initialized(self):
|
||||||
|
"""
|
||||||
|
Include only devices, which are initialized.
|
||||||
|
|
||||||
|
Initialized devices have properly set device node permissions and
|
||||||
|
context, and are (in case of network devices) fully renamed.
|
||||||
|
|
||||||
|
Currently this will not affect devices which do not have device nodes
|
||||||
|
and are not network interfaces.
|
||||||
|
|
||||||
|
Return the instance again.
|
||||||
|
|
||||||
|
.. seealso:: :attr:`Device.is_initialized`
|
||||||
|
|
||||||
|
.. udevversion:: 165
|
||||||
|
|
||||||
|
.. versionadded:: 0.8
|
||||||
|
"""
|
||||||
|
self._libudev.udev_enumerate_add_match_is_initialized(self)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def match_parent(self, parent):
|
||||||
|
"""
|
||||||
|
Include all devices on the subtree of the given ``parent`` device.
|
||||||
|
|
||||||
|
The ``parent`` device itself is also included.
|
||||||
|
|
||||||
|
``parent`` is a :class:`~pyudev.Device`.
|
||||||
|
|
||||||
|
Return the instance again.
|
||||||
|
|
||||||
|
.. udevversion:: 172
|
||||||
|
|
||||||
|
.. versionadded:: 0.13
|
||||||
|
"""
|
||||||
|
self._libudev.udev_enumerate_add_match_parent(self, parent)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""
|
||||||
|
Iterate over all matching devices.
|
||||||
|
|
||||||
|
Yield :class:`Device` objects.
|
||||||
|
"""
|
||||||
|
self._libudev.udev_enumerate_scan_devices(self)
|
||||||
|
entry = self._libudev.udev_enumerate_get_list_entry(self)
|
||||||
|
for name, _ in udev_list_iterate(self._libudev, entry):
|
||||||
|
try:
|
||||||
|
yield Devices.from_sys_path(self.context, name)
|
||||||
|
except DeviceNotFoundAtPathError:
|
||||||
|
continue
|
@ -0,0 +1,31 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2015 mulhern <amulhern@redhat.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.device
|
||||||
|
=============
|
||||||
|
|
||||||
|
Device class implementation of :mod:`pyudev`.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from ._device import Attributes
|
||||||
|
from ._device import Device
|
||||||
|
from ._device import Devices
|
||||||
|
from ._device import Tags
|
1282
deb_dist/multibootusb-8.5.0/scripts/pyudev/device/_device.py
Normal file
1282
deb_dist/multibootusb-8.5.0/scripts/pyudev/device/_device.py
Normal file
File diff suppressed because it is too large
Load Diff
391
deb_dist/multibootusb-8.5.0/scripts/pyudev/discover.py
Normal file
391
deb_dist/multibootusb-8.5.0/scripts/pyudev/discover.py
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2015 mulhern <amulhern@redhat.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.discover
|
||||||
|
===============
|
||||||
|
|
||||||
|
Tools to discover a device given limited information.
|
||||||
|
|
||||||
|
.. moduleauthor:: mulhern <amulhern@redhat.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import abc
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import six
|
||||||
|
|
||||||
|
from ._errors import DeviceNotFoundError
|
||||||
|
|
||||||
|
from .device import Devices
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_exception(func):
|
||||||
|
"""
|
||||||
|
Allow Device discovery methods to return None instead of raising an
|
||||||
|
exception.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@functools.wraps(func)
|
||||||
|
def the_func(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Returns result of calling ``func`` on ``args``, ``kwargs``.
|
||||||
|
Returns None if ``func`` raises :exc:`DeviceNotFoundError`.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
except DeviceNotFoundError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return the_func
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class Hypothesis(object):
|
||||||
|
"""
|
||||||
|
Represents a hypothesis about the meaning of the device identifier.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def match(cls, value): # pragma: no cover
|
||||||
|
"""
|
||||||
|
Match the given string according to the hypothesis.
|
||||||
|
|
||||||
|
The purpose of this method is to obtain a value corresponding to
|
||||||
|
``value`` if that is possible. It may use a regular expression, but
|
||||||
|
in general it should just return ``value`` and let the lookup method
|
||||||
|
sort out the rest.
|
||||||
|
|
||||||
|
:param str value: the string to inspect
|
||||||
|
:returns: the matched thing or None if unmatched
|
||||||
|
:rtype: the type of lookup's key parameter or NoneType
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@abc.abstractmethod
|
||||||
|
def lookup(cls, context, key): # pragma: no cover
|
||||||
|
"""
|
||||||
|
Lookup the given string according to the hypothesis.
|
||||||
|
|
||||||
|
:param Context context: the pyudev context
|
||||||
|
:param key: a key with which to lookup the device
|
||||||
|
:type key: the type of match's return value if not None
|
||||||
|
:returns: a list of Devices obtained
|
||||||
|
:rtype: frozenset of :class:`Device`
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup(cls, context):
|
||||||
|
"""
|
||||||
|
A potentially expensive method that may allow an :class:`Hypothesis`
|
||||||
|
to find devices more rapidly or to find a device that it would
|
||||||
|
otherwise miss.
|
||||||
|
|
||||||
|
:param Context context: the pyudev context
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_devices(cls, context, value):
|
||||||
|
"""
|
||||||
|
Get any devices that may correspond to the given string.
|
||||||
|
|
||||||
|
:param Context context: the pyudev context
|
||||||
|
:param str value: the value to look for
|
||||||
|
:returns: a list of devices obtained
|
||||||
|
:rtype: set of :class:`Device`
|
||||||
|
"""
|
||||||
|
key = cls.match(value)
|
||||||
|
return cls.lookup(context, key) if key is not None else frozenset()
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceNumberHypothesis(Hypothesis):
|
||||||
|
"""
|
||||||
|
Represents the hypothesis that the device is a device number.
|
||||||
|
|
||||||
|
The device may be separated into major/minor number or a composite number.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _match_major_minor(cls, value):
|
||||||
|
"""
|
||||||
|
Match the number under the assumption that it is a major,minor pair.
|
||||||
|
|
||||||
|
:param str value: value to match
|
||||||
|
:returns: the device number or None
|
||||||
|
:rtype: int or NoneType
|
||||||
|
"""
|
||||||
|
major_minor_re = re.compile(
|
||||||
|
r'^(?P<major>\d+)(\D+)(?P<minor>\d+)$'
|
||||||
|
)
|
||||||
|
match = major_minor_re.match(value)
|
||||||
|
return match and os.makedev(
|
||||||
|
int(match.group('major')),
|
||||||
|
int(match.group('minor'))
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _match_number(cls, value):
|
||||||
|
"""
|
||||||
|
Match the number under the assumption that it is a single number.
|
||||||
|
|
||||||
|
:param str value: value to match
|
||||||
|
:returns: the device number or None
|
||||||
|
:rtype: int or NoneType
|
||||||
|
"""
|
||||||
|
number_re = re.compile(r'^(?P<number>\d+)$')
|
||||||
|
match = number_re.match(value)
|
||||||
|
return match and int(match.group('number'))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def match(cls, value):
|
||||||
|
"""
|
||||||
|
Match the number under the assumption that it is a device number.
|
||||||
|
|
||||||
|
:returns: the device number or None
|
||||||
|
:rtype: int or NoneType
|
||||||
|
"""
|
||||||
|
return cls._match_major_minor(value) or cls._match_number(value)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def find_subsystems(cls, context):
|
||||||
|
"""
|
||||||
|
Find subsystems in /sys/dev.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
:returns: a lis of available subsystems
|
||||||
|
:rtype: list of str
|
||||||
|
"""
|
||||||
|
sys_path = context.sys_path
|
||||||
|
return os.listdir(os.path.join(sys_path, 'dev'))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def lookup(cls, context, key):
|
||||||
|
"""
|
||||||
|
Lookup by the device number.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
:param int key: the device number
|
||||||
|
:returns: a list of matching devices
|
||||||
|
:rtype: frozenset of :class:`Device`
|
||||||
|
"""
|
||||||
|
func = wrap_exception(Devices.from_device_number)
|
||||||
|
res = (func(context, s, key) for s in cls.find_subsystems(context))
|
||||||
|
return frozenset(r for r in res if r is not None)
|
||||||
|
|
||||||
|
|
||||||
|
class DevicePathHypothesis(Hypothesis):
|
||||||
|
"""
|
||||||
|
Discover the device assuming the identifier is a device path.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def match(cls, value):
|
||||||
|
"""
|
||||||
|
Match ``value`` under the assumption that it is a device path.
|
||||||
|
|
||||||
|
:returns: the device path or None
|
||||||
|
:rtype: str or NoneType
|
||||||
|
"""
|
||||||
|
return value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def lookup(cls, context, key):
|
||||||
|
"""
|
||||||
|
Lookup by the path.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
:param str key: the device path
|
||||||
|
:returns: a list of matching devices
|
||||||
|
:rtype: frozenset of :class:`Device`
|
||||||
|
"""
|
||||||
|
res = wrap_exception(Devices.from_path)(context, key)
|
||||||
|
return frozenset((res,)) if res is not None else frozenset()
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceNameHypothesis(Hypothesis):
|
||||||
|
"""
|
||||||
|
Discover the device assuming the input is a device name.
|
||||||
|
|
||||||
|
Try every available subsystem.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def find_subsystems(cls, context):
|
||||||
|
"""
|
||||||
|
Find all subsystems in sysfs.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
:rtype: frozenset
|
||||||
|
:returns: subsystems in sysfs
|
||||||
|
"""
|
||||||
|
sys_path = context.sys_path
|
||||||
|
dirnames = ('bus', 'class', 'subsystem')
|
||||||
|
absnames = (os.path.join(sys_path, name) for name in dirnames)
|
||||||
|
realnames = (d for d in absnames if os.path.isdir(d))
|
||||||
|
return frozenset(n for d in realnames for n in os.listdir(d))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def match(cls, value):
|
||||||
|
"""
|
||||||
|
Match ``value`` under the assumption that it is a device name.
|
||||||
|
|
||||||
|
:returns: the device path or None
|
||||||
|
:rtype: str or NoneType
|
||||||
|
"""
|
||||||
|
return value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def lookup(cls, context, key):
|
||||||
|
"""
|
||||||
|
Lookup by the path.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
:param str key: the device path
|
||||||
|
:returns: a list of matching devices
|
||||||
|
:rtype: frozenset of :class:`Device`
|
||||||
|
"""
|
||||||
|
func = wrap_exception(Devices.from_name)
|
||||||
|
res = (func(context, s, key) for s in cls.find_subsystems(context))
|
||||||
|
return frozenset(r for r in res if r is not None)
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceFileHypothesis(Hypothesis):
|
||||||
|
"""
|
||||||
|
Discover the device assuming the value is some portion of a device file.
|
||||||
|
|
||||||
|
The device file may be a link to a device node.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_LINK_DIRS = [
|
||||||
|
'/dev',
|
||||||
|
'/dev/disk/by-id',
|
||||||
|
'/dev/disk/by-label',
|
||||||
|
'/dev/disk/by-partlabel',
|
||||||
|
'/dev/disk/by-partuuid',
|
||||||
|
'/dev/disk/by-path',
|
||||||
|
'/dev/disk/by-uuid',
|
||||||
|
'/dev/input/by-path',
|
||||||
|
'/dev/mapper',
|
||||||
|
'/dev/md',
|
||||||
|
'/dev/vg'
|
||||||
|
]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_link_dirs(cls, context):
|
||||||
|
"""
|
||||||
|
Get all directories that may contain links to device nodes.
|
||||||
|
|
||||||
|
This method checks the device links of every device, so it is very
|
||||||
|
expensive.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
:returns: a sorted list of directories that contain device links
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
devices = context.list_devices()
|
||||||
|
devices_with_links = (d for d in devices if list(d.device_links))
|
||||||
|
links = (l for d in devices_with_links for l in d.device_links)
|
||||||
|
return sorted(set(os.path.dirname(l) for l in links))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup(cls, context):
|
||||||
|
"""
|
||||||
|
Set the link directories to be used when discovering by file.
|
||||||
|
|
||||||
|
Uses `get_link_dirs`, so is as expensive as it is.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
"""
|
||||||
|
cls._LINK_DIRS = cls.get_link_dirs(context)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def match(cls, value):
|
||||||
|
return value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def lookup(cls, context, key):
|
||||||
|
"""
|
||||||
|
Lookup the device under the assumption that the key is part of
|
||||||
|
the name of a device file.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
:param str key: a portion of the device file name
|
||||||
|
|
||||||
|
It is assumed that either it is the whole name of the device file
|
||||||
|
or it is the basename.
|
||||||
|
|
||||||
|
A device file may be a device node or a device link.
|
||||||
|
"""
|
||||||
|
func = wrap_exception(Devices.from_device_file)
|
||||||
|
if '/' in key:
|
||||||
|
device = func(context, key)
|
||||||
|
return frozenset((device,)) if device is not None else frozenset()
|
||||||
|
else:
|
||||||
|
files = (os.path.join(ld, key) for ld in cls._LINK_DIRS)
|
||||||
|
devices = (func(context, f) for f in files)
|
||||||
|
return frozenset(d for d in devices if d is not None)
|
||||||
|
|
||||||
|
|
||||||
|
class Discovery(object):
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
"""
|
||||||
|
Provides discovery methods for devices.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_HYPOTHESES = [
|
||||||
|
DeviceFileHypothesis,
|
||||||
|
DeviceNameHypothesis,
|
||||||
|
DeviceNumberHypothesis,
|
||||||
|
DevicePathHypothesis
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._hypotheses = self._HYPOTHESES
|
||||||
|
|
||||||
|
def setup(self, context):
|
||||||
|
"""
|
||||||
|
Set up individual hypotheses.
|
||||||
|
|
||||||
|
May be an expensive call.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
"""
|
||||||
|
for hyp in self._hypotheses:
|
||||||
|
hyp.setup(context)
|
||||||
|
|
||||||
|
def get_devices(self, context, value):
|
||||||
|
"""
|
||||||
|
Get the devices corresponding to value.
|
||||||
|
|
||||||
|
:param Context context: the context
|
||||||
|
:param str value: some identifier of the device
|
||||||
|
:returns: a list of corresponding devices
|
||||||
|
:rtype: frozenset of :class:`Device`
|
||||||
|
"""
|
||||||
|
return frozenset(
|
||||||
|
d for h in self._hypotheses for d in h.get_devices(context, value)
|
||||||
|
)
|
169
deb_dist/multibootusb-8.5.0/scripts/pyudev/glib.py
Normal file
169
deb_dist/multibootusb-8.5.0/scripts/pyudev/glib.py
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011, 2012, 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""pyudev.glib
|
||||||
|
===========
|
||||||
|
|
||||||
|
Glib integration.
|
||||||
|
|
||||||
|
:class:`MonitorObserver` integrates device monitoring into the Glib
|
||||||
|
mainloop by turing device events into Glib signals.
|
||||||
|
|
||||||
|
:mod:`glib` and :mod:`gobject` from PyGObject_ must be available when
|
||||||
|
importing this module. PyGtk is not required.
|
||||||
|
|
||||||
|
.. _PyGObject: http://www.pygtk.org/
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
.. versionadded:: 0.7
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import (print_function, division, unicode_literals,
|
||||||
|
absolute_import)
|
||||||
|
|
||||||
|
# thanks to absolute imports, this really imports the glib binding and not this
|
||||||
|
# module again
|
||||||
|
import glib
|
||||||
|
import gobject
|
||||||
|
|
||||||
|
|
||||||
|
class _ObserverMixin(object):
|
||||||
|
"""Mixin to provide observer behavior to the old and the new API."""
|
||||||
|
# pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
|
def _setup_observer(self, monitor):
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
|
self.monitor = monitor
|
||||||
|
self.event_source = None
|
||||||
|
self.enabled = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
"""
|
||||||
|
Whether this observer is enabled or not.
|
||||||
|
|
||||||
|
If ``True`` (the default), this observer is enabled, and emits events.
|
||||||
|
Otherwise it is disabled and does not emit any events.
|
||||||
|
|
||||||
|
.. versionadded:: 0.14
|
||||||
|
"""
|
||||||
|
return self.event_source is not None
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, value):
|
||||||
|
if value and self.event_source is None:
|
||||||
|
# pylint: disable=attribute-defined-outside-init
|
||||||
|
self.event_source = glib.io_add_watch(
|
||||||
|
self.monitor, glib.IO_IN, self._process_udev_event)
|
||||||
|
elif not value and self.event_source is not None:
|
||||||
|
glib.source_remove(self.event_source)
|
||||||
|
|
||||||
|
def _process_udev_event(self, source, condition):
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
if condition == glib.IO_IN:
|
||||||
|
device = self.monitor.poll(timeout=0)
|
||||||
|
if device is not None:
|
||||||
|
self._emit_event(device)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _emit_event(self, device):
|
||||||
|
self.emit('device-event', device)
|
||||||
|
|
||||||
|
|
||||||
|
class MonitorObserver(gobject.GObject, _ObserverMixin):
|
||||||
|
"""
|
||||||
|
An observer for device events integrating into the :mod:`glib` mainloop.
|
||||||
|
|
||||||
|
This class inherits :class:`~gobject.GObject` to turn device events into
|
||||||
|
glib signals.
|
||||||
|
|
||||||
|
>>> from pyudev import Context, Monitor
|
||||||
|
>>> from pyudev.glib import MonitorObserver
|
||||||
|
>>> context = Context()
|
||||||
|
>>> monitor = Monitor.from_netlink(context)
|
||||||
|
>>> monitor.filter_by(subsystem='input')
|
||||||
|
>>> observer = MonitorObserver(monitor)
|
||||||
|
>>> def device_event(observer, device):
|
||||||
|
... print('event {0} on device {1}'.format(device.action, device))
|
||||||
|
>>> observer.connect('device-event', device_event)
|
||||||
|
>>> monitor.start()
|
||||||
|
|
||||||
|
This class is a child of :class:`gobject.GObject`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__gsignals__ = {
|
||||||
|
# explicitly convert the signal to str, because glib expects the
|
||||||
|
# *native* string type of the corresponding python version as type of
|
||||||
|
# signal name, and str() is the name of the native string type of both
|
||||||
|
# python versions. We could also remove the "unicode_literals" import,
|
||||||
|
# but I don't want to make exceptions to the standard set of future
|
||||||
|
# imports used throughout pyudev for the sake of consistency.
|
||||||
|
str('device-event'): (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||||
|
(gobject.TYPE_PYOBJECT,)),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, monitor):
|
||||||
|
gobject.GObject.__init__(self)
|
||||||
|
self._setup_observer(monitor)
|
||||||
|
|
||||||
|
|
||||||
|
gobject.type_register(MonitorObserver)
|
||||||
|
|
||||||
|
|
||||||
|
class GUDevMonitorObserver(gobject.GObject, _ObserverMixin):
|
||||||
|
"""
|
||||||
|
An observer for device events integrating into the :mod:`glib` mainloop.
|
||||||
|
|
||||||
|
.. deprecated:: 0.17
|
||||||
|
Will be removed in 1.0. Use :class:`MonitorObserver` instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_action_signal_map = {
|
||||||
|
'add': 'device-added', 'remove': 'device-removed',
|
||||||
|
'change': 'device-changed', 'move': 'device-moved'}
|
||||||
|
|
||||||
|
__gsignals__ = {
|
||||||
|
str('device-event'): (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||||
|
(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)),
|
||||||
|
str('device-added'): (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||||
|
(gobject.TYPE_PYOBJECT,)),
|
||||||
|
str('device-removed'): (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||||
|
(gobject.TYPE_PYOBJECT,)),
|
||||||
|
str('device-changed'): (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||||
|
(gobject.TYPE_PYOBJECT,)),
|
||||||
|
str('device-moved'): (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
|
||||||
|
(gobject.TYPE_PYOBJECT,)),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, monitor):
|
||||||
|
gobject.GObject.__init__(self)
|
||||||
|
self._setup_observer(monitor)
|
||||||
|
import warnings
|
||||||
|
warnings.warn('Will be removed in 1.0. '
|
||||||
|
'Use pyudev.glib.MonitorObserver instead.',
|
||||||
|
DeprecationWarning)
|
||||||
|
|
||||||
|
def _emit_event(self, device):
|
||||||
|
self.emit('device-event', device.action, device)
|
||||||
|
signal = self._action_signal_map.get(device.action)
|
||||||
|
if signal is not None:
|
||||||
|
self.emit(signal, device)
|
||||||
|
|
||||||
|
|
||||||
|
gobject.type_register(GUDevMonitorObserver)
|
582
deb_dist/multibootusb-8.5.0/scripts/pyudev/monitor.py
Normal file
582
deb_dist/multibootusb-8.5.0/scripts/pyudev/monitor.py
Normal file
@ -0,0 +1,582 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011, 2012, 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.monitor
|
||||||
|
==============
|
||||||
|
|
||||||
|
Monitor implementation.
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import (print_function, division, unicode_literals,
|
||||||
|
absolute_import)
|
||||||
|
|
||||||
|
import os
|
||||||
|
import errno
|
||||||
|
from threading import Thread
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from .device import Device
|
||||||
|
|
||||||
|
from ._util import eintr_retry_call
|
||||||
|
from ._util import ensure_byte_string
|
||||||
|
|
||||||
|
from ._os import pipe
|
||||||
|
from ._os import poll
|
||||||
|
|
||||||
|
|
||||||
|
class Monitor(object):
|
||||||
|
"""
|
||||||
|
A synchronous device event monitor.
|
||||||
|
|
||||||
|
A :class:`Monitor` objects connects to the udev daemon and listens for
|
||||||
|
changes to the device list. A monitor is created by connecting to the
|
||||||
|
kernel daemon through netlink (see :meth:`from_netlink`):
|
||||||
|
|
||||||
|
>>> from pyudev import Context, Monitor
|
||||||
|
>>> context = Context()
|
||||||
|
>>> monitor = Monitor.from_netlink(context)
|
||||||
|
|
||||||
|
Once the monitor is created, you can add a filter using :meth:`filter_by()`
|
||||||
|
or :meth:`filter_by_tag()` to drop incoming events in subsystems, which are
|
||||||
|
not of interest to the application:
|
||||||
|
|
||||||
|
>>> monitor.filter_by('input')
|
||||||
|
|
||||||
|
When the monitor is eventually set up, you can either poll for events
|
||||||
|
synchronously:
|
||||||
|
|
||||||
|
>>> device = monitor.poll(timeout=3)
|
||||||
|
>>> if device:
|
||||||
|
... print('{0.action}: {0}'.format(device))
|
||||||
|
...
|
||||||
|
|
||||||
|
Or you can monitor events asynchronously with :class:`MonitorObserver`.
|
||||||
|
|
||||||
|
To integrate into various event processing frameworks, the monitor provides
|
||||||
|
a :func:`selectable <select.select>` file description by :meth:`fileno()`.
|
||||||
|
However, do *not* read or write directly on this file descriptor.
|
||||||
|
|
||||||
|
Instances of this class can directly be given as ``udev_monitor *`` to
|
||||||
|
functions wrapped through :mod:`ctypes`.
|
||||||
|
|
||||||
|
.. versionchanged:: 0.16
|
||||||
|
Remove :meth:`from_socket()` which is deprecated, and even removed in
|
||||||
|
recent udev versions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, context, monitor_p):
|
||||||
|
self.context = context
|
||||||
|
self._as_parameter_ = monitor_p
|
||||||
|
self._libudev = context._libudev
|
||||||
|
self._started = False
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._libudev.udev_monitor_unref(self)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_netlink(cls, context, source='udev'):
|
||||||
|
"""
|
||||||
|
Create a monitor by connecting to the kernel daemon through netlink.
|
||||||
|
|
||||||
|
``context`` is the :class:`Context` to use. ``source`` is a string,
|
||||||
|
describing the event source. Two sources are available:
|
||||||
|
|
||||||
|
``'udev'`` (the default)
|
||||||
|
Events emitted after udev as registered and configured the device.
|
||||||
|
This is the absolutely recommended source for applications.
|
||||||
|
|
||||||
|
``'kernel'``
|
||||||
|
Events emitted directly after the kernel has seen the device. The
|
||||||
|
device has not yet been configured by udev and might not be usable
|
||||||
|
at all. **Never** use this, unless you know what you are doing.
|
||||||
|
|
||||||
|
Return a new :class:`Monitor` object, which is connected to the
|
||||||
|
given source. Raise :exc:`~exceptions.ValueError`, if an invalid
|
||||||
|
source has been specified. Raise
|
||||||
|
:exc:`~exceptions.EnvironmentError`, if the creation of the monitor
|
||||||
|
failed.
|
||||||
|
"""
|
||||||
|
if source not in ('kernel', 'udev'):
|
||||||
|
raise ValueError('Invalid source: {0!r}. Must be one of "udev" '
|
||||||
|
'or "kernel"'.format(source))
|
||||||
|
monitor = context._libudev.udev_monitor_new_from_netlink(
|
||||||
|
context, ensure_byte_string(source))
|
||||||
|
if not monitor:
|
||||||
|
raise EnvironmentError('Could not create udev monitor')
|
||||||
|
return cls(context, monitor)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def started(self):
|
||||||
|
"""
|
||||||
|
``True``, if this monitor was started, ``False`` otherwise. Readonly.
|
||||||
|
|
||||||
|
.. seealso:: :meth:`start()`
|
||||||
|
.. versionadded:: 0.16
|
||||||
|
"""
|
||||||
|
return self._started
|
||||||
|
|
||||||
|
def fileno(self):
|
||||||
|
# pylint: disable=anomalous-backslash-in-string
|
||||||
|
"""
|
||||||
|
Return the file description associated with this monitor as integer.
|
||||||
|
|
||||||
|
This is really a real file descriptor ;), which can be watched and
|
||||||
|
:func:`select.select`\ ed.
|
||||||
|
"""
|
||||||
|
return self._libudev.udev_monitor_get_fd(self)
|
||||||
|
|
||||||
|
def filter_by(self, subsystem, device_type=None):
|
||||||
|
"""
|
||||||
|
Filter incoming events.
|
||||||
|
|
||||||
|
``subsystem`` is a byte or unicode string with the name of a
|
||||||
|
subsystem (e.g. ``'input'``). Only events originating from the
|
||||||
|
given subsystem pass the filter and are handed to the caller.
|
||||||
|
|
||||||
|
If given, ``device_type`` is a byte or unicode string specifying the
|
||||||
|
device type. Only devices with the given device type are propagated
|
||||||
|
to the caller. If ``device_type`` is not given, no additional
|
||||||
|
filter for a specific device type is installed.
|
||||||
|
|
||||||
|
These filters are executed inside the kernel, and client processes
|
||||||
|
will usually not be woken up for device, that do not match these
|
||||||
|
filters.
|
||||||
|
|
||||||
|
.. versionchanged:: 0.15
|
||||||
|
This method can also be after :meth:`start()` now.
|
||||||
|
"""
|
||||||
|
subsystem = ensure_byte_string(subsystem)
|
||||||
|
if device_type is not None:
|
||||||
|
device_type = ensure_byte_string(device_type)
|
||||||
|
self._libudev.udev_monitor_filter_add_match_subsystem_devtype(
|
||||||
|
self, subsystem, device_type)
|
||||||
|
self._libudev.udev_monitor_filter_update(self)
|
||||||
|
|
||||||
|
def filter_by_tag(self, tag):
|
||||||
|
"""
|
||||||
|
Filter incoming events by the given ``tag``.
|
||||||
|
|
||||||
|
``tag`` is a byte or unicode string with the name of a tag. Only
|
||||||
|
events for devices which have this tag attached pass the filter and are
|
||||||
|
handed to the caller.
|
||||||
|
|
||||||
|
Like with :meth:`filter_by` this filter is also executed inside the
|
||||||
|
kernel, so that client processes are usually not woken up for devices
|
||||||
|
without the given ``tag``.
|
||||||
|
|
||||||
|
.. udevversion:: 154
|
||||||
|
|
||||||
|
.. versionadded:: 0.9
|
||||||
|
|
||||||
|
.. versionchanged:: 0.15
|
||||||
|
This method can also be after :meth:`start()` now.
|
||||||
|
"""
|
||||||
|
self._libudev.udev_monitor_filter_add_match_tag(
|
||||||
|
self, ensure_byte_string(tag))
|
||||||
|
self._libudev.udev_monitor_filter_update(self)
|
||||||
|
|
||||||
|
def remove_filter(self):
|
||||||
|
"""
|
||||||
|
Remove any filters installed with :meth:`filter_by()` or
|
||||||
|
:meth:`filter_by_tag()` from this monitor.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Up to udev 181 (and possibly even later versions) the underlying
|
||||||
|
``udev_monitor_filter_remove()`` seems to be broken. If used with
|
||||||
|
affected versions this method always raises
|
||||||
|
:exc:`~exceptions.ValueError`.
|
||||||
|
|
||||||
|
Raise :exc:`~exceptions.EnvironmentError` if removal of installed
|
||||||
|
filters failed.
|
||||||
|
|
||||||
|
.. versionadded:: 0.15
|
||||||
|
"""
|
||||||
|
self._libudev.udev_monitor_filter_remove(self)
|
||||||
|
self._libudev.udev_monitor_filter_update(self)
|
||||||
|
|
||||||
|
def enable_receiving(self):
|
||||||
|
"""
|
||||||
|
Switch the monitor into listing mode.
|
||||||
|
|
||||||
|
Connect to the event source and receive incoming events. Only after
|
||||||
|
calling this method, the monitor listens for incoming events.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This method is implicitly called by :meth:`__iter__`. You don't
|
||||||
|
need to call it explicitly, if you are iterating over the
|
||||||
|
monitor.
|
||||||
|
|
||||||
|
.. deprecated:: 0.16
|
||||||
|
Will be removed in 1.0. Use :meth:`start()` instead.
|
||||||
|
"""
|
||||||
|
import warnings
|
||||||
|
warnings.warn('Will be removed in 1.0. Use Monitor.start() instead.',
|
||||||
|
DeprecationWarning)
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""
|
||||||
|
Start this monitor.
|
||||||
|
|
||||||
|
The monitor will not receive events until this method is called. This
|
||||||
|
method does nothing if called on an already started :class:`Monitor`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Typically you don't need to call this method. It is implicitly
|
||||||
|
called by :meth:`poll()` and :meth:`__iter__()`.
|
||||||
|
|
||||||
|
.. seealso:: :attr:`started`
|
||||||
|
.. versionchanged:: 0.16
|
||||||
|
This method does nothing if the :class:`Monitor` was already
|
||||||
|
started.
|
||||||
|
"""
|
||||||
|
if not self._started:
|
||||||
|
self._libudev.udev_monitor_enable_receiving(self)
|
||||||
|
# Force monitor FD into non-blocking mode
|
||||||
|
pipe.set_fd_status_flag(self, os.O_NONBLOCK)
|
||||||
|
self._started = True
|
||||||
|
|
||||||
|
def set_receive_buffer_size(self, size):
|
||||||
|
"""
|
||||||
|
Set the receive buffer ``size``.
|
||||||
|
|
||||||
|
``size`` is the requested buffer size in bytes, as integer.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The CAP_NET_ADMIN capability must be contained in the effective
|
||||||
|
capability set of the caller for this method to succeed. Otherwise
|
||||||
|
:exc:`~exceptions.EnvironmentError` will be raised, with ``errno``
|
||||||
|
set to :data:`~errno.EPERM`. Unprivileged processes typically lack
|
||||||
|
this capability. You can check the capabilities of the current
|
||||||
|
process with the python-prctl_ module:
|
||||||
|
|
||||||
|
>>> import prctl
|
||||||
|
>>> prctl.cap_effective.net_admin
|
||||||
|
|
||||||
|
Raise :exc:`~exceptions.EnvironmentError`, if the buffer size could not
|
||||||
|
bet set.
|
||||||
|
|
||||||
|
.. versionadded:: 0.13
|
||||||
|
|
||||||
|
.. _python-prctl: http://packages.python.org/python-prctl
|
||||||
|
"""
|
||||||
|
self._libudev.udev_monitor_set_receive_buffer_size(self, size)
|
||||||
|
|
||||||
|
def _receive_device(self):
|
||||||
|
"""Receive a single device from the monitor.
|
||||||
|
|
||||||
|
Return the received :class:`Device`, or ``None`` if no device could be
|
||||||
|
received.
|
||||||
|
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
device_p = self._libudev.udev_monitor_receive_device(self)
|
||||||
|
return Device(self.context, device_p) if device_p else None
|
||||||
|
except EnvironmentError as error:
|
||||||
|
if error.errno in (errno.EAGAIN, errno.EWOULDBLOCK):
|
||||||
|
# No data available
|
||||||
|
return None
|
||||||
|
elif error.errno == errno.EINTR:
|
||||||
|
# Try again if our system call was interrupted
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def poll(self, timeout=None):
|
||||||
|
"""
|
||||||
|
Poll for a device event.
|
||||||
|
|
||||||
|
You can use this method together with :func:`iter()` to synchronously
|
||||||
|
monitor events in the current thread::
|
||||||
|
|
||||||
|
for device in iter(monitor.poll, None):
|
||||||
|
print('{0.action} on {0.device_path}'.format(device))
|
||||||
|
|
||||||
|
Since this method will never return ``None`` if no ``timeout`` is
|
||||||
|
specified, this is effectively an endless loop. With
|
||||||
|
:func:`functools.partial()` you can also create a loop that only waits
|
||||||
|
for a specified time::
|
||||||
|
|
||||||
|
for device in iter(partial(monitor.poll, 3), None):
|
||||||
|
print('{0.action} on {0.device_path}'.format(device))
|
||||||
|
|
||||||
|
This loop will only wait three seconds for a new device event. If no
|
||||||
|
device event occurred after three seconds, the loop will exit.
|
||||||
|
|
||||||
|
``timeout`` is a floating point number that specifies a time-out in
|
||||||
|
seconds. If omitted or ``None``, this method blocks until a device
|
||||||
|
event is available. If ``0``, this method just polls and will never
|
||||||
|
block.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This method implicitly calls :meth:`start()`.
|
||||||
|
|
||||||
|
Return the received :class:`Device`, or ``None`` if a timeout
|
||||||
|
occurred. Raise :exc:`~exceptions.EnvironmentError` if event retrieval
|
||||||
|
failed.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:attr:`Device.action`
|
||||||
|
The action that created this event.
|
||||||
|
|
||||||
|
:attr:`Device.sequence_number`
|
||||||
|
The sequence number of this event.
|
||||||
|
|
||||||
|
.. versionadded:: 0.16
|
||||||
|
"""
|
||||||
|
if timeout is not None and timeout > 0:
|
||||||
|
# .poll() takes timeout in milliseconds
|
||||||
|
timeout = int(timeout * 1000)
|
||||||
|
self.start()
|
||||||
|
if eintr_retry_call(poll.Poll.for_events((self, 'r')).poll, timeout):
|
||||||
|
return self._receive_device()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def receive_device(self):
|
||||||
|
"""
|
||||||
|
Receive a single device from the monitor.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
You *must* call :meth:`start()` before calling this method.
|
||||||
|
|
||||||
|
The caller must make sure, that there are events available in the
|
||||||
|
event queue. The call blocks, until a device is available.
|
||||||
|
|
||||||
|
If a device was available, return ``(action, device)``. ``device``
|
||||||
|
is the :class:`Device` object describing the device. ``action`` is
|
||||||
|
a string describing the action. Usual actions are:
|
||||||
|
|
||||||
|
``'add'``
|
||||||
|
A device has been added (e.g. a USB device was plugged in)
|
||||||
|
``'remove'``
|
||||||
|
A device has been removed (e.g. a USB device was unplugged)
|
||||||
|
``'change'``
|
||||||
|
Something about the device changed (e.g. a device property)
|
||||||
|
``'online'``
|
||||||
|
The device is online now
|
||||||
|
``'offline'``
|
||||||
|
The device is offline now
|
||||||
|
|
||||||
|
Raise :exc:`~exceptions.EnvironmentError`, if no device could be
|
||||||
|
read.
|
||||||
|
|
||||||
|
.. deprecated:: 0.16
|
||||||
|
Will be removed in 1.0. Use :meth:`Monitor.poll()` instead.
|
||||||
|
"""
|
||||||
|
import warnings
|
||||||
|
warnings.warn('Will be removed in 1.0. Use Monitor.poll() instead.',
|
||||||
|
DeprecationWarning)
|
||||||
|
device = self.poll()
|
||||||
|
return device.action, device
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""
|
||||||
|
Wait for incoming events and receive them upon arrival.
|
||||||
|
|
||||||
|
This methods implicitly calls :meth:`start()`, and starts polling the
|
||||||
|
:meth:`fileno` of this monitor. If a event comes in, it receives the
|
||||||
|
corresponding device and yields it to the caller.
|
||||||
|
|
||||||
|
The returned iterator is endless, and continues receiving devices
|
||||||
|
without ever stopping.
|
||||||
|
|
||||||
|
Yields ``(action, device)`` (see :meth:`receive_device` for a
|
||||||
|
description).
|
||||||
|
|
||||||
|
.. deprecated:: 0.16
|
||||||
|
Will be removed in 1.0. Use an explicit loop over :meth:`poll()`
|
||||||
|
instead, or monitor asynchronously with :class:`MonitorObserver`.
|
||||||
|
"""
|
||||||
|
import warnings
|
||||||
|
warnings.warn('Will be removed in 1.0. Use an explicit loop over '
|
||||||
|
'"poll()" instead, or monitor asynchronously with '
|
||||||
|
'"MonitorObserver".', DeprecationWarning)
|
||||||
|
self.start()
|
||||||
|
while True:
|
||||||
|
device = self.poll()
|
||||||
|
if device is not None:
|
||||||
|
yield device.action, device
|
||||||
|
|
||||||
|
|
||||||
|
class MonitorObserver(Thread):
|
||||||
|
"""
|
||||||
|
An asynchronous observer for device events.
|
||||||
|
|
||||||
|
This class subclasses :class:`~threading.Thread` class to asynchronously
|
||||||
|
observe a :class:`Monitor` in a background thread:
|
||||||
|
|
||||||
|
>>> from pyudev import Context, Monitor, MonitorObserver
|
||||||
|
>>> context = Context()
|
||||||
|
>>> monitor = Monitor.from_netlink(context)
|
||||||
|
>>> monitor.filter_by(subsystem='input')
|
||||||
|
>>> def print_device_event(device):
|
||||||
|
... print('background event {0.action}: {0.device_path}'.format(device))
|
||||||
|
>>> observer = MonitorObserver(monitor, callback=print_device_event, name='monitor-observer')
|
||||||
|
>>> observer.daemon
|
||||||
|
True
|
||||||
|
>>> observer.start()
|
||||||
|
|
||||||
|
In the above example, input device events will be printed in background,
|
||||||
|
until :meth:`stop()` is called on ``observer``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Instances of this class are always created as daemon thread. If you do
|
||||||
|
not want to use daemon threads for monitoring, you need explicitly set
|
||||||
|
:attr:`~threading.Thread.daemon` to ``False`` before invoking
|
||||||
|
:meth:`~threading.Thread.start()`.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:attr:`Device.action`
|
||||||
|
The action that created this event.
|
||||||
|
|
||||||
|
:attr:`Device.sequence_number`
|
||||||
|
The sequence number of this event.
|
||||||
|
|
||||||
|
.. versionadded:: 0.14
|
||||||
|
|
||||||
|
.. versionchanged:: 0.15
|
||||||
|
:meth:`Monitor.start()` is implicitly called when the thread is started.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, monitor, event_handler=None, callback=None, *args,
|
||||||
|
**kwargs):
|
||||||
|
"""
|
||||||
|
Create a new observer for the given ``monitor``.
|
||||||
|
|
||||||
|
``monitor`` is the :class:`Monitor` to observe. ``callback`` is the
|
||||||
|
callable to invoke on events, with the signature ``callback(device)``
|
||||||
|
where ``device`` is the :class:`Device` that caused the event.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
``callback`` is invoked in the observer thread, hence the observer
|
||||||
|
is blocked while callback executes.
|
||||||
|
|
||||||
|
``args`` and ``kwargs`` are passed unchanged to the constructor of
|
||||||
|
:class:`~threading.Thread`.
|
||||||
|
|
||||||
|
.. deprecated:: 0.16
|
||||||
|
The ``event_handler`` argument will be removed in 1.0. Use
|
||||||
|
the ``callback`` argument instead.
|
||||||
|
.. versionchanged:: 0.16
|
||||||
|
Add ``callback`` argument.
|
||||||
|
"""
|
||||||
|
if callback is None and event_handler is None:
|
||||||
|
raise ValueError('callback missing')
|
||||||
|
elif callback is not None and event_handler is not None:
|
||||||
|
raise ValueError('Use either callback or event handler')
|
||||||
|
|
||||||
|
Thread.__init__(self, *args, **kwargs)
|
||||||
|
self.monitor = monitor
|
||||||
|
# observer threads should not keep the interpreter alive
|
||||||
|
self.daemon = True
|
||||||
|
self._stop_event = None
|
||||||
|
if event_handler is not None:
|
||||||
|
import warnings
|
||||||
|
warnings.warn('"event_handler" argument will be removed in 1.0. '
|
||||||
|
'Use Monitor.poll() instead.', DeprecationWarning)
|
||||||
|
callback = lambda d: event_handler(d.action, d)
|
||||||
|
self._callback = callback
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Start the observer thread."""
|
||||||
|
if not self.is_alive():
|
||||||
|
self._stop_event = pipe.Pipe.open()
|
||||||
|
Thread.start(self)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.monitor.start()
|
||||||
|
notifier = poll.Poll.for_events(
|
||||||
|
(self.monitor, 'r'), (self._stop_event.source, 'r'))
|
||||||
|
while True:
|
||||||
|
for file_descriptor, event in eintr_retry_call(notifier.poll):
|
||||||
|
if file_descriptor == self._stop_event.source.fileno():
|
||||||
|
# in case of a stop event, close our pipe side, and
|
||||||
|
# return from the thread
|
||||||
|
self._stop_event.source.close()
|
||||||
|
return
|
||||||
|
elif file_descriptor == self.monitor.fileno() and event == 'r':
|
||||||
|
read_device = partial(eintr_retry_call, self.monitor.poll, timeout=0)
|
||||||
|
for device in iter(read_device, None):
|
||||||
|
self._callback(device)
|
||||||
|
else:
|
||||||
|
raise EnvironmentError('Observed monitor hung up')
|
||||||
|
|
||||||
|
def send_stop(self):
|
||||||
|
"""
|
||||||
|
Send a stop signal to the background thread.
|
||||||
|
|
||||||
|
The background thread will eventually exit, but it may still be running
|
||||||
|
when this method returns. This method is essentially the asynchronous
|
||||||
|
equivalent to :meth:`stop()`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The underlying :attr:`monitor` is *not* stopped.
|
||||||
|
"""
|
||||||
|
if self._stop_event is None:
|
||||||
|
return
|
||||||
|
with self._stop_event.sink:
|
||||||
|
# emit a stop event to the thread
|
||||||
|
eintr_retry_call(self._stop_event.sink.write, b'\x01')
|
||||||
|
self._stop_event.sink.flush()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""
|
||||||
|
Synchronously stop the background thread.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This method can safely be called from the observer thread. In this
|
||||||
|
case it is equivalent to :meth:`send_stop()`.
|
||||||
|
|
||||||
|
Send a stop signal to the backgroud (see :meth:`send_stop`), and waits
|
||||||
|
for the background thread to exit (see :meth:`~threading.Thread.join`)
|
||||||
|
if the current thread is *not* the observer thread.
|
||||||
|
|
||||||
|
After this method returns in a thread *that is not the observer
|
||||||
|
thread*, the ``callback`` is guaranteed to not be invoked again
|
||||||
|
anymore.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The underlying :attr:`monitor` is *not* stopped.
|
||||||
|
|
||||||
|
.. versionchanged:: 0.16
|
||||||
|
This method can be called from the observer thread.
|
||||||
|
"""
|
||||||
|
self.send_stop()
|
||||||
|
try:
|
||||||
|
self.join()
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
64
deb_dist/multibootusb-8.5.0/scripts/pyudev/pyqt4.py
Normal file
64
deb_dist/multibootusb-8.5.0/scripts/pyudev/pyqt4.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011, 2012, 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
# pylint: disable=anomalous-backslash-in-string
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.pyqt4
|
||||||
|
============
|
||||||
|
|
||||||
|
PyQt4 integration.
|
||||||
|
|
||||||
|
:class:`MonitorObserver` integrates device monitoring into the PyQt4\_
|
||||||
|
mainloop by turning device events into Qt signals.
|
||||||
|
|
||||||
|
:mod:`PyQt4.QtCore` from PyQt4\_ must be available when importing this
|
||||||
|
module.
|
||||||
|
|
||||||
|
.. _PyQt4: http://riverbankcomputing.co.uk/software/pyqt/intro
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
|
from ._qt_base import MonitorObserverGenerator
|
||||||
|
from ._qt_base import QUDevMonitorObserverGenerator
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
MonitorObserver = MonitorObserverGenerator.make_monitor_observer(
|
||||||
|
QtCore.QObject,
|
||||||
|
QtCore.pyqtSignal,
|
||||||
|
QtCore.QSocketNotifier
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
.. deprecated:: 0.17
|
||||||
|
Will be removed in 1.0. Use :class:`MonitorObserver` instead.
|
||||||
|
"""
|
||||||
|
QUDevMonitorObserver = QUDevMonitorObserverGenerator.make_monitor_observer(
|
||||||
|
QtCore.QObject,
|
||||||
|
QtCore.pyqtSignal,
|
||||||
|
QtCore.QSocketNotifier
|
||||||
|
)
|
49
deb_dist/multibootusb-8.5.0/scripts/pyudev/pyqt5.py
Normal file
49
deb_dist/multibootusb-8.5.0/scripts/pyudev/pyqt5.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.pyqt5
|
||||||
|
============
|
||||||
|
|
||||||
|
PyQt5 integration.
|
||||||
|
|
||||||
|
:class:`MonitorObserver` integrates device monitoring into the PyQt5_
|
||||||
|
mainloop by turning device events into Qt signals.
|
||||||
|
|
||||||
|
:mod:`PyQt5.QtCore` from PyQt5_ must be available when importing this
|
||||||
|
module.
|
||||||
|
|
||||||
|
.. _gPyQt5: http://riverbankcomputing.co.uk/software/pyqt/intro
|
||||||
|
|
||||||
|
.. moduleauthor:: Tobias Gehring <mail@tobiasgehring.de>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
|
from ._qt_base import MonitorObserverGenerator
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
MonitorObserver = MonitorObserverGenerator.make_monitor_observer(
|
||||||
|
QtCore.QObject,
|
||||||
|
QtCore.pyqtSignal,
|
||||||
|
QtCore.QSocketNotifier
|
||||||
|
)
|
63
deb_dist/multibootusb-8.5.0/scripts/pyudev/pyside.py
Normal file
63
deb_dist/multibootusb-8.5.0/scripts/pyudev/pyside.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2010, 2011, 2012, 2013 Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
# pylint: disable=anomalous-backslash-in-string
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.pyside
|
||||||
|
=============
|
||||||
|
|
||||||
|
PySide integration.
|
||||||
|
|
||||||
|
:class:`QUDevMonitorObserver` integrates device monitoring into the PySide\_
|
||||||
|
mainloop by turing device events into Qt signals.
|
||||||
|
|
||||||
|
:mod:`PySide.QtCore` from PySide\_ must be available when importing this
|
||||||
|
module.
|
||||||
|
|
||||||
|
.. _PySide: http://www.pyside.org
|
||||||
|
|
||||||
|
.. moduleauthor:: Sebastian Wiesner <lunaryorn@gmail.com>
|
||||||
|
.. versionadded:: 0.6
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from PySide import QtCore
|
||||||
|
|
||||||
|
from ._qt_base import MonitorObserverGenerator
|
||||||
|
from ._qt_base import QUDevMonitorObserverGenerator
|
||||||
|
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
MonitorObserver = MonitorObserverGenerator.make_monitor_observer(
|
||||||
|
QtCore.QObject,
|
||||||
|
QtCore.Signal,
|
||||||
|
QtCore.QSocketNotifier
|
||||||
|
)
|
||||||
|
|
||||||
|
"""
|
||||||
|
.. deprecated:: 0.17
|
||||||
|
Will be removed in 1.0. Use :class:`MonitorObserver` instead.
|
||||||
|
"""
|
||||||
|
QUDevMonitorObserver = QUDevMonitorObserverGenerator.make_monitor_observer(
|
||||||
|
QtCore.QObject,
|
||||||
|
QtCore.Signal,
|
||||||
|
QtCore.QSocketNotifier
|
||||||
|
)
|
33
deb_dist/multibootusb-8.5.0/scripts/pyudev/version.py
Normal file
33
deb_dist/multibootusb-8.5.0/scripts/pyudev/version.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (C) 2015 mulhern <amulhern@redhat.com>
|
||||||
|
|
||||||
|
# This library is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
pyudev.version
|
||||||
|
==============
|
||||||
|
|
||||||
|
Version information.
|
||||||
|
|
||||||
|
.. moduleauthor:: mulhern <amulhern@redhat.com>
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version_info__ = (0, 21, 0, '')
|
||||||
|
__version__ = "%s%s" % \
|
||||||
|
(
|
||||||
|
".".join(str(x) for x in __version_info__[:3]),
|
||||||
|
"".join(str(x) for x in __version_info__[3:])
|
||||||
|
)
|
150
deb_dist/multibootusb-8.5.0/scripts/pyudev/wx.py
Normal file
150
deb_dist/multibootusb-8.5.0/scripts/pyudev/wx.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
# option) any later version.
|
||||||
|
|
||||||
|
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with this library; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
# pylint: disable=anomalous-backslash-in-string
|
||||||
|
|
||||||
|
"""pyudev.wx
|
||||||
|
=========
|
||||||
|
|
||||||
|
Wx integration.
|
||||||
|
|
||||||
|
:class:`MonitorObserver` integrates device monitoring into the wxPython\_
|
||||||
|
mainloop by turing device events into wx events.
|
||||||
|
|
||||||
|
:mod:`wx` from wxPython\_ must be available when importing this module.
|
||||||
|
|
||||||
|
.. _wxPython: http://wxpython.org/
|
||||||
|
|
||||||
|
.. moduleauthor:: Tobias Eberle <tobias.eberle@gmx.de>
|
||||||
|
.. versionadded:: 0.14
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import (print_function, division, unicode_literals,
|
||||||
|
absolute_import)
|
||||||
|
|
||||||
|
from wx import EvtHandler, PostEvent
|
||||||
|
from wx.lib.newevent import NewEvent
|
||||||
|
|
||||||
|
import pyudev
|
||||||
|
|
||||||
|
|
||||||
|
DeviceEvent, EVT_DEVICE_EVENT = NewEvent()
|
||||||
|
|
||||||
|
|
||||||
|
class MonitorObserver(EvtHandler):
|
||||||
|
"""
|
||||||
|
An observer for device events integrating into the :mod:`wx` mainloop.
|
||||||
|
|
||||||
|
This class inherits :class:`~wx.EvtHandler` to turn device events into
|
||||||
|
wx events:
|
||||||
|
|
||||||
|
>>> from pyudev import Context, Monitor
|
||||||
|
>>> from pyudev.wx import MonitorObserver
|
||||||
|
>>> context = Context()
|
||||||
|
>>> monitor = Monitor.from_netlink(context)
|
||||||
|
>>> monitor.filter_by(subsystem='input')
|
||||||
|
>>> observer = MonitorObserver(monitor)
|
||||||
|
>>> def device_event(event):
|
||||||
|
... print('action {0} on device {1}'.format(event.device.action, event.device))
|
||||||
|
>>> observer.Bind(EVT_DEVICE_EVENT, device_event)
|
||||||
|
>>> monitor.start()
|
||||||
|
|
||||||
|
This class is a child of :class:`wx.EvtHandler`.
|
||||||
|
|
||||||
|
.. versionadded:: 0.17
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, monitor):
|
||||||
|
EvtHandler.__init__(self)
|
||||||
|
self.monitor = monitor
|
||||||
|
self._observer_thread = None
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
"""
|
||||||
|
Whether this observer is enabled or not.
|
||||||
|
|
||||||
|
If ``True`` (the default), this observer is enabled, and emits events.
|
||||||
|
Otherwise it is disabled and does not emit any events.
|
||||||
|
"""
|
||||||
|
return self._observer_thread is not None
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, value):
|
||||||
|
if value:
|
||||||
|
self.start()
|
||||||
|
else:
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""
|
||||||
|
Enable this observer.
|
||||||
|
|
||||||
|
Do nothing, if the observer is already enabled.
|
||||||
|
"""
|
||||||
|
if self._observer_thread is not None:
|
||||||
|
return
|
||||||
|
self._observer_thread = pyudev.MonitorObserver(
|
||||||
|
self.monitor, callback=self._emit_event,
|
||||||
|
name='wx-observer-thread')
|
||||||
|
self._observer_thread.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""
|
||||||
|
Disable this observer.
|
||||||
|
|
||||||
|
Do nothing, if the observer is already disabled.
|
||||||
|
"""
|
||||||
|
if self._observer_thread is None:
|
||||||
|
return
|
||||||
|
self._observer_thread.stop()
|
||||||
|
|
||||||
|
def _emit_event(self, device):
|
||||||
|
PostEvent(self, DeviceEvent(device=device))
|
||||||
|
|
||||||
|
|
||||||
|
DeviceAddedEvent, EVT_DEVICE_ADDED = NewEvent()
|
||||||
|
DeviceRemovedEvent, EVT_DEVICE_REMOVED = NewEvent()
|
||||||
|
DeviceChangedEvent, EVT_DEVICE_CHANGED = NewEvent()
|
||||||
|
DeviceMovedEvent, EVT_DEVICE_MOVED = NewEvent()
|
||||||
|
|
||||||
|
|
||||||
|
class WxUDevMonitorObserver(MonitorObserver):
|
||||||
|
"""An observer for device events integrating into the :mod:`wx` mainloop.
|
||||||
|
|
||||||
|
.. deprecated:: 0.17
|
||||||
|
Will be removed in 1.0. Use :class:`MonitorObserver` instead.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_action_event_map = {
|
||||||
|
'add': DeviceAddedEvent,
|
||||||
|
'remove': DeviceRemovedEvent,
|
||||||
|
'change': DeviceChangedEvent,
|
||||||
|
'move': DeviceMovedEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, monitor):
|
||||||
|
MonitorObserver.__init__(self, monitor)
|
||||||
|
import warnings
|
||||||
|
warnings.warn('Will be removed in 1.0. '
|
||||||
|
'Use pyudev.wx.MonitorObserver instead.',
|
||||||
|
DeprecationWarning)
|
||||||
|
|
||||||
|
def _emit_event(self, device):
|
||||||
|
PostEvent(self, DeviceEvent(action=device.action, device=device))
|
||||||
|
event_class = self._action_event_map.get(device.action)
|
||||||
|
if event_class is not None:
|
||||||
|
PostEvent(self, event_class(device=device))
|
196
deb_dist/multibootusb-8.5.0/scripts/qemu.py
Normal file
196
deb_dist/multibootusb-8.5.0/scripts/qemu.py
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: qemu.py
|
||||||
|
# Purpose: Module to boot ISO and USB disks using QEMU.
|
||||||
|
# Depends: QEMU must be installed under Linux for availing this feature. For windows, QEMU package is shipped
|
||||||
|
# along with executable file
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import platform
|
||||||
|
from .admin import adminCmd
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
from .gui.ui_multibootusb import Ui_Dialog
|
||||||
|
from .gen import *
|
||||||
|
|
||||||
|
|
||||||
|
class Qemu(QtWidgets.QDialog, Ui_Dialog):
|
||||||
|
"""
|
||||||
|
ISO and USB booting using QEMU.
|
||||||
|
"""
|
||||||
|
def on_Qemu_Browse_iso_Click(self):
|
||||||
|
"""
|
||||||
|
Browse and choose an ISO.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.ui.lineEdit_2.clear()
|
||||||
|
|
||||||
|
qemu = self.check_qemu_exist()
|
||||||
|
|
||||||
|
if not qemu is None:
|
||||||
|
|
||||||
|
qemu_iso_link = QtWidgets.QFileDialog.getOpenFileName(self, 'Select an iso...', "", "ISO Files (*.iso)")[0]
|
||||||
|
else:
|
||||||
|
log("QEMU does not exist.\nPlease install qemu package to avail this feature.")
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No QEMU...', 'Please install qemu package to avail this feature.')
|
||||||
|
qemu_iso_link = None
|
||||||
|
|
||||||
|
if not qemu_iso_link is None:
|
||||||
|
self.ui.lineEdit_2.insert(qemu_iso_link)
|
||||||
|
else:
|
||||||
|
log ("File not selected.")
|
||||||
|
|
||||||
|
def on_Qemu_Boot_iso_Click(self):
|
||||||
|
"""
|
||||||
|
Main function to boot a selected ISO.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not self.ui.lineEdit_2.text():
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No ISO...', 'No ISO selected.\n\nPlease choose an iso and click Boot ISO.')
|
||||||
|
else:
|
||||||
|
qemu = self.check_qemu_exist()
|
||||||
|
qemu_iso_link = str(self.ui.lineEdit_2.text())
|
||||||
|
if qemu is None:
|
||||||
|
log("QEMU does not exist.\nPlease install qemu package to avail this feature.")
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No QEMU...', 'Please install qemu to avail this feature.')
|
||||||
|
else:
|
||||||
|
ram = self.qemu_iso_ram()
|
||||||
|
if not ram is None:
|
||||||
|
self.ui.lineEdit_2.clear()
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
try:
|
||||||
|
log("Executing ==> " + qemu + " -cdrom " + str(qemu_iso_link) + " -boot d -m " + ram)
|
||||||
|
subprocess.Popen(qemu + " -cdrom " + str(qemu_iso_link) + " -boot d -m " + ram, shell=True)
|
||||||
|
except:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'Error...', 'Unable to start QEMU.')
|
||||||
|
else:
|
||||||
|
log(qemu + ' -m ' + ram + ' -cdrom ' + str(qemu_iso_link) + ' -boot d')
|
||||||
|
try:
|
||||||
|
log("Executing ==> " + qemu + " -cdrom " + str(qemu_iso_link) + " -boot d -m " + ram)
|
||||||
|
subprocess.Popen(qemu + " -cdrom " + str(qemu_iso_link) + " -boot d -m " + ram, shell=True)
|
||||||
|
except:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'Error...', 'Error booting ISO\n'
|
||||||
|
'Unable to start QEMU.')
|
||||||
|
else:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No ram...', 'No ram selected.\n\nPlease choose any ram value and click Boot ISO.')
|
||||||
|
|
||||||
|
|
||||||
|
def on_Qemu_Boot_usb_Click(self, usb_disk):
|
||||||
|
"""
|
||||||
|
Main function to boot a selected USB disk.
|
||||||
|
:param usb_disk: Path to usb disk.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
qemu = self.check_qemu_exist()
|
||||||
|
|
||||||
|
if qemu is None:
|
||||||
|
log("QEMU does not exist.\nPlease install qemu package to avail this feature.")
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No QEMU...', 'Please install qemu to avail this feature.')
|
||||||
|
else:
|
||||||
|
ram = self.qemu_usb_ram()
|
||||||
|
if ram is None:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'No ram...', 'No ram selected.\n\nPlease choose any ram value and click Boot USB.')
|
||||||
|
else:
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
disk_number = self.get_physical_disk_number(usb_disk)
|
||||||
|
parent_dir = os.getcwd()
|
||||||
|
os.chdir(resource_path(os.path.join("data", "tools", "qemu")))
|
||||||
|
try:
|
||||||
|
log("Executing ==> " + qemu + " -L . -boot c -m " + ram + " -hda //./PhysicalDrive" + disk_number)
|
||||||
|
subprocess.Popen("qemu-system-x86_64.exe -L . -boot c -m " + ram + " -hda //./PhysicalDrive" + disk_number, shell=True)
|
||||||
|
except:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'Error...', 'Error booting USB\n'
|
||||||
|
'Unable to start QEMU.')
|
||||||
|
os.chdir(parent_dir)
|
||||||
|
elif platform.system() == "Linux":
|
||||||
|
try:
|
||||||
|
qemu_cmd = qemu + ' -hda ' + usb_disk[:-1] + ' -m ' + ram + ' -vga std'
|
||||||
|
log('Executing ==> ' + qemu_cmd)
|
||||||
|
# adminCmd([qemu, '-hda', usb_disk[:-1], '-m', ram, '-vga std'], gui=True)
|
||||||
|
subprocess.Popen(qemu_cmd, shell=True)
|
||||||
|
# adminCmd(qemu_cmd, gui=True)
|
||||||
|
except:
|
||||||
|
QtWidgets.QMessageBox.information(self, 'Error...', 'Error booting USB\n\nUnable to start QEMU.')
|
||||||
|
|
||||||
|
def qemu_iso_ram(self):
|
||||||
|
"""
|
||||||
|
Choose a ram size for ISO booting.
|
||||||
|
:return: Ram size as string.
|
||||||
|
"""
|
||||||
|
if self.ui.ram_iso_256.isChecked():
|
||||||
|
return str(256)
|
||||||
|
elif self.ui.ram_iso_512.isChecked():
|
||||||
|
return str(512)
|
||||||
|
elif self.ui.ram_iso_768.isChecked():
|
||||||
|
return str(768)
|
||||||
|
elif self.ui.ram_iso_1024.isChecked():
|
||||||
|
return str(1024)
|
||||||
|
elif self.ui.ram_iso_2048.isChecked():
|
||||||
|
return str(2047)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def qemu_usb_ram(self):
|
||||||
|
"""
|
||||||
|
Choose a ram size for USB booting.
|
||||||
|
:return: Ram size as string.
|
||||||
|
"""
|
||||||
|
if self.ui.ram_usb_256.isChecked():
|
||||||
|
return str(256)
|
||||||
|
if self.ui.ram_usb_512.isChecked():
|
||||||
|
return str(512)
|
||||||
|
if self.ui.ram_usb_768.isChecked():
|
||||||
|
return str(768)
|
||||||
|
if self.ui.ram_usb_1024.isChecked():
|
||||||
|
return str(1024)
|
||||||
|
if self.ui.ram_usb_2048.isChecked():
|
||||||
|
return str(2047)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_qemu_exist(self):
|
||||||
|
"""
|
||||||
|
Check if QEMU is available on host system.
|
||||||
|
:return: path to QEMU program or None otherwise.
|
||||||
|
"""
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
if subprocess.call('which qemu-system-x86_64', shell=True) == 0:
|
||||||
|
log("qemu-system-x86_64 exists...")
|
||||||
|
qemu = "qemu-system-x86_64"
|
||||||
|
elif subprocess.call('which qemu', shell=True) == 0:
|
||||||
|
log("qemu exists")
|
||||||
|
qemu = "qemu"
|
||||||
|
else:
|
||||||
|
qemu = None
|
||||||
|
|
||||||
|
if qemu:
|
||||||
|
return qemu
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
log(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.
|
||||||
|
:param usb_disk: USB disk (Like F:)
|
||||||
|
:return: Disk number.
|
||||||
|
"""
|
||||||
|
import wmi
|
||||||
|
c = wmi.WMI ()
|
||||||
|
for physical_disk in c.Win32_DiskDrive ():
|
||||||
|
for partition in physical_disk.associators ("Win32_DiskDriveToDiskPartition"):
|
||||||
|
for logical_disk in partition.associators ("Win32_LogicalDiskToPartition"):
|
||||||
|
if logical_disk.Caption == usb_disk:
|
||||||
|
"""
|
||||||
|
log physical_disk.Caption
|
||||||
|
log partition.Caption
|
||||||
|
log logical_disk.Caption
|
||||||
|
"""
|
||||||
|
log("Physical Device Number is " + partition.Caption[6:-14])
|
||||||
|
return str(partition.Caption[6:-14])
|
189
deb_dist/multibootusb-8.5.0/scripts/syslinux.py
Normal file
189
deb_dist/multibootusb-8.5.0/scripts/syslinux.py
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: syslinux.py
|
||||||
|
# Purpose: Module to install syslinux and extlinux on selected USB disk.
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import platform
|
||||||
|
from .gen import *
|
||||||
|
from . import usb
|
||||||
|
from .iso import *
|
||||||
|
from . import config
|
||||||
|
|
||||||
|
extlinux_path = os.path.join(multibootusb_host_dir(), "syslinux", "bin", "extlinux4")
|
||||||
|
syslinux_path = os.path.join(multibootusb_host_dir(), "syslinux", "bin", "syslinux4")
|
||||||
|
extlinux_fs = ["ext2", "ext3", "ext4", "Btrfs"]
|
||||||
|
syslinux_fs = ["vfat", "ntfs", "FAT32", "NTFS"]
|
||||||
|
mbr_bin = resource_path(os.path.join("data", "tools", "mbr.bin"))
|
||||||
|
|
||||||
|
|
||||||
|
def set_boot_flag(usb_disk):
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
log ("\nChecking boot flag on " + usb_disk[:-1], '\n')
|
||||||
|
cmd_out = subprocess.check_output("parted -m -s " + usb_disk[:-1] + " print", shell=True)
|
||||||
|
if b'boot' in cmd_out:
|
||||||
|
log ("\nDisk " + usb_disk[:-1] + " already has boot flag.\n")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
log ("\nExecuting ==> parted " + usb_disk[:-1] + " set 1 boot on", '\n')
|
||||||
|
if subprocess.call("parted " + usb_disk[:-1] + " set 1 boot on", shell=True) == 0:
|
||||||
|
log ("\nBoot flag set to bootable " + usb_disk[:-1], '\n')
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
log ("\nUnable to set boot flag on " + usb_disk[:-1], '\n')
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def syslinux_default(usb_disk, version=4):
|
||||||
|
"""
|
||||||
|
Install Syslinux of a selected drive
|
||||||
|
:param usb_disk: '/dev/sdx' on linux and 'E:' on Windows
|
||||||
|
:version: Default version is 4. Change it if you wish. But necessary files needs to be copied accordingly
|
||||||
|
:return: Bootable USB disk :-)
|
||||||
|
"""
|
||||||
|
usb_details = usb.details(usb_disk)
|
||||||
|
usb_fs = usb_details['file_system']
|
||||||
|
usb_mount = usb_details['mount_point']
|
||||||
|
mbr_install_cmd = 'dd bs=440 count=1 conv=notrunc if=' + mbr_bin + ' of=' + usb_disk[:-1]
|
||||||
|
# log (usb_fs)
|
||||||
|
if usb_fs in extlinux_fs:
|
||||||
|
extlinu_cmd = extlinux_path + ' --install ' + os.path.join(usb_mount, 'multibootusb')
|
||||||
|
if os.access(extlinux_path, os.X_OK) is False:
|
||||||
|
subprocess.call('chmod +x ' + extlinux_path, shell=True)
|
||||||
|
log ("\nExecuting ==> " + extlinu_cmd)
|
||||||
|
if subprocess.call(extlinu_cmd, shell=True) == 0:
|
||||||
|
log ("\nDefault Extlinux install is success...\n")
|
||||||
|
log ('\nExecuting ==> ' + mbr_install_cmd)
|
||||||
|
if subprocess.call(mbr_install_cmd, shell=True) == 0:
|
||||||
|
log ("\nmbr install is success...\n")
|
||||||
|
if set_boot_flag(usb_disk) is True:
|
||||||
|
return True
|
||||||
|
|
||||||
|
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")
|
||||||
|
if subprocess.call(syslinux_cmd, shell=True) == 0:
|
||||||
|
log ("\nDefault syslinux install is success...\n")
|
||||||
|
if subprocess.call(mbr_install_cmd, shell=True) == 0:
|
||||||
|
log ("\nmbr install is success...\n")
|
||||||
|
if set_boot_flag(usb_disk) is True:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
log ("\nFailed to install default syslinux...\n")
|
||||||
|
return False
|
||||||
|
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
syslinux = resource_path(os.path.join(multibootusb_host_dir(), "syslinux", "bin", "syslinux4.exe"))
|
||||||
|
log ('Executing ==>' + syslinux + ' -maf -d multibootusb ' + usb_disk)
|
||||||
|
if subprocess.call(syslinux + ' -maf -d multibootusb ' + usb_disk, shell=True) == 0:
|
||||||
|
log ("\nDefault syslinux install is success...\n")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
log ("\nFailed to install default syslinux...\n")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def syslinux_distro_dir(usb_disk, iso_link, distro):
|
||||||
|
"""
|
||||||
|
Install syslinux/extlinux on distro specific isolinux directory.
|
||||||
|
:param usb_disk: '/dev/sdx' on linux and 'E:' on Windows
|
||||||
|
:param iso_link: Path to ISO file
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
usb_details = usb.details(usb_disk)
|
||||||
|
usb_fs = usb_details['file_system']
|
||||||
|
usb_mount = usb_details['mount_point']
|
||||||
|
isolinux_bin_dir(iso_link)
|
||||||
|
if isolinux_bin_exist(iso_link) is False:
|
||||||
|
log ('Distro does not use isolinux for booting ISO.')
|
||||||
|
else:
|
||||||
|
# iso_cfg_ext_dir = os.path.join(multibootusb_host_dir(), "iso_cfg_ext_dir")
|
||||||
|
_iso_cfg_ext_dir = iso_cfg_ext_dir()
|
||||||
|
isolinux_path = os.path.join(_iso_cfg_ext_dir, isolinux_bin_path(iso_link))
|
||||||
|
iso_linux_bin_dir = isolinux_bin_dir(iso_link)
|
||||||
|
config.syslinux_version = isolinux_version(isolinux_path)
|
||||||
|
|
||||||
|
if distro == "generic" or distro == "alpine":
|
||||||
|
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')
|
||||||
|
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')
|
||||||
|
log (distro_sys_install_bs)
|
||||||
|
#log (distro_syslinux_install_dir)
|
||||||
|
|
||||||
|
if usb_fs in syslinux_fs:
|
||||||
|
if config.syslinux_version == str(3):
|
||||||
|
if distro == "generic" and iso_linux_bin_dir == "/":
|
||||||
|
option = ""
|
||||||
|
else:
|
||||||
|
option = " -d "
|
||||||
|
else:
|
||||||
|
if distro == "generic" and iso_linux_bin_dir == "/":
|
||||||
|
option = " -i "
|
||||||
|
else:
|
||||||
|
option = " -i -d "
|
||||||
|
|
||||||
|
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) == 0
|
||||||
|
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)
|
||||||
|
if subprocess.call(sys_cmd, shell=True) == 0:
|
||||||
|
log ("\nSyslinux install on distro directory is success...\n")
|
||||||
|
log ('Executing ==> ' + dd_cmd + '\n')
|
||||||
|
if subprocess.call(dd_cmd, shell=True) == 0:
|
||||||
|
log ("\nBootsector copy is success...\n")
|
||||||
|
else:
|
||||||
|
log ("\nFailed to copy boot sector...\n")
|
||||||
|
else:
|
||||||
|
log ("\nFailed to install syslinux on distro directory...\n")
|
||||||
|
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')
|
||||||
|
if subprocess.call(sys_cmd, shell=True) == 0:
|
||||||
|
log ("\nSyslinux install was successful on distro directory...\n")
|
||||||
|
else:
|
||||||
|
log ("\nFailed to install syslinux on distro directory...\n")
|
||||||
|
elif usb_fs in extlinux_fs:
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
distro_syslinux_install_dir = os.path.join(install_dir, iso_linux_bin_dir.strip("/"))
|
||||||
|
syslinux_path = os.path.join(multibootusb_host_dir(), "syslinux", "bin", "extlinux") + config.syslinux_version
|
||||||
|
ext_cmd = syslinux_path + " --install " + distro_syslinux_install_dir
|
||||||
|
dd_cmd = 'dd if=' + usb_disk + ' ' + 'of=' + usb_mount + quote(distro_sys_install_bs) + ' count=1'
|
||||||
|
if os.access(syslinux_path, os.X_OK) is False:
|
||||||
|
subprocess.call('chmod +x ' + syslinux_path, shell=True) == 0
|
||||||
|
log ("Executing ==> " + ext_cmd)
|
||||||
|
if subprocess.call(ext_cmd, shell=True) == 0:
|
||||||
|
log ("\nSyslinux install on distro directory is success...\n")
|
||||||
|
log ('Executing ==> ' + dd_cmd, '\n')
|
||||||
|
if subprocess.call(dd_cmd, shell=True) == 0:
|
||||||
|
log ("\nBootsector copy is success...\n")
|
||||||
|
else:
|
||||||
|
log ("\nFailed to install syslinux on distro directory...\n")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
log ('Please running this script with sudo/root/admin privilage.')
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
syslinux_distro_dir('/dev/sdb1', '../../../DISTROS/2016/debian-live-8.3.0-amd64-lxde-desktop.iso', 'debian')
|
||||||
|
syslinux_default('/dev/sdb1')
|
223
deb_dist/multibootusb-8.5.0/scripts/udisks.py
Normal file
223
deb_dist/multibootusb-8.5.0/scripts/udisks.py
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
# Name: udisks.py
|
||||||
|
# Purpose: Module to mount unmount and eject using dbus and udisk
|
||||||
|
# Authors: Original author is Kovid Goyal <kovid@kovidgoyal.net> and python3
|
||||||
|
# supporte by Sundar for multibootusb project
|
||||||
|
# Licence: 'GPL v3' as per original Licence
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
# from __future__ import print_function
|
||||||
|
import os, re
|
||||||
|
|
||||||
|
|
||||||
|
def node_mountpoint(node):
|
||||||
|
|
||||||
|
def de_mangle(raw):
|
||||||
|
return raw.replace('\\040', ' ').replace('\\011', '\t').replace('\\012',
|
||||||
|
'\n').replace('\\0134', '\\')
|
||||||
|
|
||||||
|
for line in open('/proc/mounts').readlines():
|
||||||
|
line = line.split()
|
||||||
|
if line[0] == node:
|
||||||
|
return de_mangle(line[1])
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class NoUDisks1(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UDisks(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
import dbus
|
||||||
|
self.bus = dbus.SystemBus()
|
||||||
|
try:
|
||||||
|
self.main = dbus.Interface(self.bus.get_object('org.freedesktop.UDisks',
|
||||||
|
'/org/freedesktop/UDisks'), 'org.freedesktop.UDisks')
|
||||||
|
except dbus.exceptions.DBusException as e:
|
||||||
|
if getattr(e, '_dbus_error_name', None) == 'org.freedesktop.DBus.Error.ServiceUnknown':
|
||||||
|
raise NoUDisks1()
|
||||||
|
raise
|
||||||
|
|
||||||
|
def device(self, device_node_path):
|
||||||
|
import dbus
|
||||||
|
devpath = self.main.FindDeviceByDeviceFile(device_node_path)
|
||||||
|
return dbus.Interface(self.bus.get_object('org.freedesktop.UDisks',
|
||||||
|
devpath), 'org.freedesktop.UDisks.Device')
|
||||||
|
|
||||||
|
def mount(self, device_node_path):
|
||||||
|
d = self.device(device_node_path)
|
||||||
|
try:
|
||||||
|
return 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
|
||||||
|
|
||||||
|
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]
|
||||||
|
d = self.device(parent)
|
||||||
|
d.DriveEject([])
|
||||||
|
|
||||||
|
|
||||||
|
class NoUDisks2(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UDisks2(object):
|
||||||
|
|
||||||
|
BLOCK = 'org.freedesktop.UDisks2.Block'
|
||||||
|
FILESYSTEM = 'org.freedesktop.UDisks2.Filesystem'
|
||||||
|
DRIVE = 'org.freedesktop.UDisks2.Drive'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
import dbus
|
||||||
|
self.bus = dbus.SystemBus()
|
||||||
|
try:
|
||||||
|
self.bus.get_object('org.freedesktop.UDisks2',
|
||||||
|
'/org/freedesktop/UDisks2')
|
||||||
|
except dbus.exceptions.DBusException as e:
|
||||||
|
if getattr(e, '_dbus_error_name', None) == 'org.freedesktop.DBus.Error.ServiceUnknown':
|
||||||
|
raise NoUDisks2()
|
||||||
|
raise
|
||||||
|
|
||||||
|
def device(self, device_node_path):
|
||||||
|
device_node_path = os.path.realpath(device_node_path)
|
||||||
|
devname = device_node_path.split('/')[-1]
|
||||||
|
|
||||||
|
# First we try a direct object path
|
||||||
|
bd = self.bus.get_object('org.freedesktop.UDisks2',
|
||||||
|
'/org/freedesktop/UDisks2/block_devices/%s'%devname)
|
||||||
|
try:
|
||||||
|
device = bd.Get(self.BLOCK, 'Device',
|
||||||
|
dbus_interface='org.freedesktop.DBus.Properties')
|
||||||
|
device = bytearray(device).replace(b'\x00', b'').decode('utf-8')
|
||||||
|
except:
|
||||||
|
device = None
|
||||||
|
|
||||||
|
if device == device_node_path:
|
||||||
|
return bd
|
||||||
|
|
||||||
|
# Enumerate all devices known to UDisks
|
||||||
|
devs = self.bus.get_object('org.freedesktop.UDisks2',
|
||||||
|
'/org/freedesktop/UDisks2/block_devices')
|
||||||
|
xml = devs.Introspect(dbus_interface='org.freedesktop.DBus.Introspectable')
|
||||||
|
for dev in re.finditer(r'name=[\'"](.+?)[\'"]', type('')(xml)):
|
||||||
|
bd = self.bus.get_object('org.freedesktop.UDisks2',
|
||||||
|
'/org/freedesktop/UDisks2/block_devices/%s2'%dev.group(1))
|
||||||
|
try:
|
||||||
|
device = bd.Get(self.BLOCK, 'Device',
|
||||||
|
dbus_interface='org.freedesktop.DBus.Properties')
|
||||||
|
device = bytearray(device).replace(b'\x00', b'').decode('utf-8')
|
||||||
|
except:
|
||||||
|
device = None
|
||||||
|
if device == device_node_path:
|
||||||
|
return bd
|
||||||
|
|
||||||
|
raise ValueError('%r not known to UDisks2'%device_node_path)
|
||||||
|
|
||||||
|
def mount(self, device_node_path):
|
||||||
|
d = self.device(device_node_path)
|
||||||
|
mount_options = ['rw', 'noexec', 'nosuid',
|
||||||
|
'nodev', 'uid=%d'%os.geteuid(), 'gid=%d'%os.getegid()]
|
||||||
|
try:
|
||||||
|
return str(d.Mount(
|
||||||
|
{
|
||||||
|
'auth.no_user_interaction':True,
|
||||||
|
'options':','.join(mount_options)
|
||||||
|
},
|
||||||
|
dbus_interface=self.FILESYSTEM))
|
||||||
|
except:
|
||||||
|
# May be already mounted, check
|
||||||
|
mp = node_mountpoint(str(device_node_path))
|
||||||
|
if mp is None:
|
||||||
|
raise
|
||||||
|
return mp
|
||||||
|
|
||||||
|
def unmount(self, device_node_path):
|
||||||
|
d = self.device(device_node_path)
|
||||||
|
d.Unmount({'force':True, 'auth.no_user_interaction':True},
|
||||||
|
dbus_interface=self.FILESYSTEM)
|
||||||
|
|
||||||
|
def drive_for_device(self, device):
|
||||||
|
drive = device.Get(self.BLOCK, 'Drive',
|
||||||
|
dbus_interface='org.freedesktop.DBus.Properties')
|
||||||
|
return self.bus.get_object('org.freedesktop.UDisks2', drive)
|
||||||
|
|
||||||
|
def eject(self, device_node_path):
|
||||||
|
drive = self.drive_for_device(self.device(device_node_path))
|
||||||
|
drive.Eject({'auth.no_user_interaction':True},
|
||||||
|
dbus_interface=self.DRIVE)
|
||||||
|
|
||||||
|
|
||||||
|
def get_udisks(ver=None):
|
||||||
|
if ver is None:
|
||||||
|
try:
|
||||||
|
u = UDisks2()
|
||||||
|
except NoUDisks2:
|
||||||
|
u = UDisks()
|
||||||
|
return u
|
||||||
|
return UDisks2() if ver == 2 else UDisks()
|
||||||
|
|
||||||
|
|
||||||
|
def get_udisks1():
|
||||||
|
u = None
|
||||||
|
try:
|
||||||
|
u = UDisks()
|
||||||
|
except NoUDisks1:
|
||||||
|
try:
|
||||||
|
u = UDisks2()
|
||||||
|
except NoUDisks2:
|
||||||
|
pass
|
||||||
|
if u is None:
|
||||||
|
raise EnvironmentError('UDisks not available on your system')
|
||||||
|
return u
|
||||||
|
|
||||||
|
|
||||||
|
def mount(node_path):
|
||||||
|
u = get_udisks1()
|
||||||
|
u.mount(node_path)
|
||||||
|
|
||||||
|
|
||||||
|
def eject(node_path):
|
||||||
|
u = get_udisks1()
|
||||||
|
u.eject(node_path)
|
||||||
|
|
||||||
|
|
||||||
|
def umount(node_path):
|
||||||
|
u = get_udisks1()
|
||||||
|
u.unmount(node_path)
|
||||||
|
|
||||||
|
|
||||||
|
def test_udisks(ver=None):
|
||||||
|
import sys
|
||||||
|
dev = sys.argv[1]
|
||||||
|
print('Testing with node', dev)
|
||||||
|
u = get_udisks(ver=ver)
|
||||||
|
print('Using Udisks:', u.__class__.__name__)
|
||||||
|
print('Mounted at:', u.mount(dev))
|
||||||
|
print('Unmounting')
|
||||||
|
u.unmount(dev)
|
||||||
|
print('Mounting')
|
||||||
|
u.mount(dev)
|
||||||
|
print('Ejecting:')
|
||||||
|
u.eject(dev)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print('Run test here...')
|
||||||
|
# test_udisks()
|
222
deb_dist/multibootusb-8.5.0/scripts/uninstall_distro.py
Normal file
222
deb_dist/multibootusb-8.5.0/scripts/uninstall_distro.py
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: uninstall_distro.py
|
||||||
|
# Purpose: Module to uninstall distros installed by multibootusb
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import threading
|
||||||
|
import platform
|
||||||
|
from .usb import *
|
||||||
|
from . import config
|
||||||
|
from . import gen
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
config.usb_mount = usb_details['mount_point']
|
||||||
|
sys_cfg_file = os.path.join(config.usb_mount, "multibootusb", "syslinux.cfg")
|
||||||
|
|
||||||
|
if os.path.exists(sys_cfg_file):
|
||||||
|
distro_list = []
|
||||||
|
for line in open(sys_cfg_file):
|
||||||
|
if "#start " in line:
|
||||||
|
distro_list.append(line[7:])
|
||||||
|
return distro_list
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def unin_distro():
|
||||||
|
usb_details = details(config.usb_disk)
|
||||||
|
usb_mount = usb_details['mount_point']
|
||||||
|
config.uninstall_distro_dir_name = config.uninstall_distro_dir_name.replace('\n', '')
|
||||||
|
gen.log(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "multibootusb.cfg"))
|
||||||
|
if os.path.exists(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "multibootusb.cfg")):
|
||||||
|
with open(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "multibootusb.cfg"), "r") as multibootusb_cfg:
|
||||||
|
config.distro = multibootusb_cfg.read().replace('\n', '')
|
||||||
|
if config.distro:
|
||||||
|
uninstall_distro()
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def delete_frm_file_list():
|
||||||
|
"""
|
||||||
|
Generic way to remove files from USB disk.
|
||||||
|
:param config.usb_disk:
|
||||||
|
:param iso_file_list: List of files installed in the USB disk
|
||||||
|
:param config.uninstall_distro_dir_name: Directory where the distro is installed
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
usb_details = details(config.usb_disk)
|
||||||
|
usb_mount = usb_details['mount_point']
|
||||||
|
if config.iso_file_list is not None:
|
||||||
|
for f in config.iso_file_list:
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
f = f.replace('\n', '').strip("/").replace("/", "\\")
|
||||||
|
else:
|
||||||
|
f = f.replace('\n', '').strip("/")
|
||||||
|
if os.path.exists(os.path.join(usb_mount, "ldlinux.sys")):
|
||||||
|
os.chmod(os.path.join(usb_mount, "ldlinux.sys"), 0o777)
|
||||||
|
os.unlink(os.path.join(usb_mount, "ldlinux.sys"))
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(usb_mount, f)):
|
||||||
|
gen.log("Removing " + (os.path.join(usb_mount, f)))
|
||||||
|
if os.path.isfile(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:
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
generic = generic_cfg.read().replace('\n', '').replace("/", "\\")
|
||||||
|
else:
|
||||||
|
generic = generic_cfg.read().replace('\n', '')
|
||||||
|
if os.path.exists(os.path.join(usb_mount, generic.strip("/"))):
|
||||||
|
os.remove(os.path.join(usb_mount, generic.strip("/")))
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
gen.log('Removed files from' + config.uninstall_distro_dir_name)
|
||||||
|
gen.log('Syncing....')
|
||||||
|
os.system('sync')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def uninstall_distro():
|
||||||
|
"""
|
||||||
|
Uninstall selected distro from selected USB disk.
|
||||||
|
:param config.usb_disk: Path of the USB disk
|
||||||
|
:param config.uninstall_distro_dir_name: Directory where the distro is installed
|
||||||
|
:param _distro: Generic name applied to distro install by multibootusb
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
usb_details = details(config.usb_disk)
|
||||||
|
usb_mount = usb_details['mount_point']
|
||||||
|
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
os.system('sync')
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "iso_file_list.cfg")):
|
||||||
|
with open(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "iso_file_list.cfg"), "r") as f:
|
||||||
|
config.iso_file_list = f.readlines()
|
||||||
|
# gen.log iso_file_list
|
||||||
|
|
||||||
|
for path, subdirs, files in os.walk(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name)):
|
||||||
|
for name in files:
|
||||||
|
if name.endswith('ldlinux.sys') or name.endswith('ldlinux.c32'):
|
||||||
|
os.chmod(os.path.join(path, name), 0o777)
|
||||||
|
os.unlink(os.path.join(path, name))
|
||||||
|
if config.distro == "opensuse":
|
||||||
|
if os.path.exists(os.path.join(usb_mount, config.uninstall_distro_dir_name + ".iso")):
|
||||||
|
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:
|
||||||
|
if f.endswith('.tlz'):
|
||||||
|
os.remove(os.path.join(usb_mount, f))
|
||||||
|
if os.path.exists(os.path.join(usb_mount, "distro.img")):
|
||||||
|
os.remove(os.path.join(usb_mount, "distro.img"))
|
||||||
|
elif config.distro == "trinity-rescue":
|
||||||
|
shutil.rmtree(os.path.join(usb_mount, "trk3"))
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name)):
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
os.system('sync')
|
||||||
|
shutil.rmtree(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name))
|
||||||
|
|
||||||
|
delete_frm_file_list()
|
||||||
|
|
||||||
|
update_sys_cfg_file()
|
||||||
|
|
||||||
|
|
||||||
|
def update_sys_cfg_file():
|
||||||
|
"""
|
||||||
|
Main function to remove uninstall distro specific operations.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
os.system('sync')
|
||||||
|
|
||||||
|
sys_cfg_file = os.path.join(config.usb_mount, "multibootusb", "syslinux.cfg")
|
||||||
|
if not os.path.exists(sys_cfg_file):
|
||||||
|
gen.log("syslinux.cfg file not found for updating changes.")
|
||||||
|
else:
|
||||||
|
gen.log("Updating syslinux.cfg file...")
|
||||||
|
string = open(sys_cfg_file).read()
|
||||||
|
string = re.sub(r'#start ' + config.uninstall_distro_dir_name + '.*?' + '#end ' + config.uninstall_distro_dir_name + '\s*', '', string, flags=re.DOTALL)
|
||||||
|
config_file = open(sys_cfg_file, "w")
|
||||||
|
config_file.write(string)
|
||||||
|
config_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
def uninstall_progress():
|
||||||
|
"""
|
||||||
|
Calculate uninstall progress percentage.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
from . import progressbar
|
||||||
|
usb_details = details(config.usb_disk)
|
||||||
|
usb_mount = usb_details['mount_point']
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
os.system('sync')
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "multibootusb.cfg")):
|
||||||
|
with open(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name, "multibootusb.cfg"),
|
||||||
|
"r") as multibootusb_cfg:
|
||||||
|
config.distro = multibootusb_cfg.read().replace('\n', '')
|
||||||
|
else:
|
||||||
|
config.distro = ""
|
||||||
|
gen.log("Installed distro type is " + config.distro)
|
||||||
|
|
||||||
|
if config.distro == "opensuse":
|
||||||
|
if os.path.exists(os.path.join(usb_mount, config.uninstall_distro_dir_name) + ".iso"):
|
||||||
|
folder_size_to_remove = os.path.getsize(os.path.join(usb_mount, config.uninstall_distro_dir_name) + ".iso")
|
||||||
|
else:
|
||||||
|
folder_size_to_remove = 0
|
||||||
|
folder_size_to_remove += disk_usage(str(usb_mount) + "/multibootusb/" + config.uninstall_distro_dir_name).used
|
||||||
|
elif config.distro == "windows" or config.distro == "Windows":
|
||||||
|
if os.path.exists(os.path.join(usb_mount, "SOURCES")):
|
||||||
|
folder_size_to_remove = disk_usage(str(usb_mount) + "/SOURCES").used
|
||||||
|
else:
|
||||||
|
folder_size_to_remove = disk_usage(str(usb_mount) + "/SSTR").used
|
||||||
|
elif config.distro == "ipfire":
|
||||||
|
folder_size_to_remove = disk_usage(str(usb_mount) + "/multibootusb/" + config.uninstall_distro_dir_name).used
|
||||||
|
files = os.listdir(os.path.join(str(usb_mount)))
|
||||||
|
for f in files:
|
||||||
|
if f.endswith('.tlz'):
|
||||||
|
folder_size_to_remove += os.path.getsize(os.path.join(config.usb_mount, f))
|
||||||
|
elif config.distro == "trinity-rescue":
|
||||||
|
folder_size_to_remove = disk_usage(os.path.join(usb_mount, "trk3")).used
|
||||||
|
folder_size_to_remove += disk_usage(usb_mount + "/multibootusb/" + config.uninstall_distro_dir_name).used
|
||||||
|
else:
|
||||||
|
|
||||||
|
folder_size_to_remove = disk_usage(os.path.join(usb_mount, "multibootusb", config.uninstall_distro_dir_name)).used
|
||||||
|
|
||||||
|
thrd = threading.Thread(target=unin_distro, name="uninstall_progress")
|
||||||
|
initial_usb_size = disk_usage(usb_mount).used
|
||||||
|
thrd.start()
|
||||||
|
config.status_text = "Uninstalling " + config.uninstall_distro_dir_name
|
||||||
|
pbar = progressbar.ProgressBar(maxval=100).start() # bar = progressbar.ProgressBar(redirect_stdout=True)
|
||||||
|
while thrd.is_alive():
|
||||||
|
current_size = disk_usage(usb_mount).used
|
||||||
|
diff_size = int(initial_usb_size - current_size)
|
||||||
|
config.percentage = round(float(diff_size) / folder_size_to_remove * 100)
|
||||||
|
if config.percentage > 100:
|
||||||
|
config.percentage = 100
|
||||||
|
|
||||||
|
pbar.update(config.percentage)
|
||||||
|
|
||||||
|
if not thrd.is_alive():
|
||||||
|
config.persistence = 0
|
||||||
|
config.status_text = ""
|
383
deb_dist/multibootusb-8.5.0/scripts/update_cfg_file.py
Normal file
383
deb_dist/multibootusb-8.5.0/scripts/update_cfg_file.py
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: update_cfg_file.py
|
||||||
|
# Purpose: Module to manipulate distro specific and main config files.
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
from .usb import *
|
||||||
|
from .gen import *
|
||||||
|
from .iso import *
|
||||||
|
from . import config
|
||||||
|
|
||||||
|
|
||||||
|
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_mount = usb_details['mount_point']
|
||||||
|
usb_uuid = usb_details['uuid']
|
||||||
|
usb_label = usb_details['label']
|
||||||
|
patch = None
|
||||||
|
iso_cfg_ext_dir = os.path.join(multibootusb_host_dir(), "iso_cfg_ext_dir")
|
||||||
|
if isolinux_bin_exist(config.iso_link):
|
||||||
|
isolinux_path = os.path.join(iso_cfg_ext_dir, isolinux_bin_path(iso_link)[1:])
|
||||||
|
config.status_text = "Updating config files..."
|
||||||
|
install_dir = os.path.join(usb_mount, "multibootusb", iso_basename(iso_link))
|
||||||
|
log('Updating distro specific config files...')
|
||||||
|
for dirpath, dirnames, filenames in os.walk(install_dir):
|
||||||
|
for f in filenames:
|
||||||
|
if f.endswith(".cfg") or f.endswith('.CFG') or f.endswith('.lst'):
|
||||||
|
cfg_file = os.path.join(dirpath, f)
|
||||||
|
try:
|
||||||
|
string = open(cfg_file, errors='ignore').read()
|
||||||
|
except IOError:
|
||||||
|
log("Unable to read ", cfg_file)
|
||||||
|
else:
|
||||||
|
if not distro == "generic":
|
||||||
|
replace_text = r'\1/multibootusb/' + iso_basename(iso_link) + '/'
|
||||||
|
string = re.sub(r'([ \t =,])/', replace_text, string)
|
||||||
|
if distro == "ubuntu":
|
||||||
|
string = re.sub(r'boot=casper',
|
||||||
|
'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)
|
||||||
|
string = re.sub(r'ui gfxboot', '#ui gfxboot', string)
|
||||||
|
if not persistence == 0:
|
||||||
|
string = re.sub(r'boot=casper', 'boot=casper persistent persistent-path=/multibootusb/' +
|
||||||
|
iso_basename(iso_link) + "/", string)
|
||||||
|
|
||||||
|
elif distro == "debian" or distro == "debian-install":
|
||||||
|
string = re.sub(r'boot=live', 'boot=live ignore_bootid live-media-path=/multibootusb/' +
|
||||||
|
iso_basename(iso_link) + '/live', string)
|
||||||
|
if not persistence == 0:
|
||||||
|
string = re.sub(r'boot=live', 'boot=live persistent persistent-path=/multibootusb/' +
|
||||||
|
iso_basename(iso_link) + "/", string)
|
||||||
|
|
||||||
|
elif distro == "ubuntu-server":
|
||||||
|
string = re.sub(r'file',
|
||||||
|
'cdrom-detect/try-usb=true floppy.allowed_drive_mask=0 ignore_uuid ignore_bootid root=UUID=' +
|
||||||
|
usb_uuid + ' file', string)
|
||||||
|
elif distro == "fedora":
|
||||||
|
string = re.sub(r'root=\S*', 'root=live:UUID=' + usb_uuid, string)
|
||||||
|
if re.search(r'liveimg', string, re.I):
|
||||||
|
string = re.sub(r'liveimg', 'liveimg live_dir=/multibootusb/' +
|
||||||
|
iso_basename(iso_link) + '/LiveOS', string)
|
||||||
|
elif re.search(r'rd.live.image', string, re.I):
|
||||||
|
string = re.sub(r'rd.live.image', 'rd.live.image rd.live.dir=/multibootusb/' +
|
||||||
|
iso_basename(iso_link) + '/LiveOS', string)
|
||||||
|
elif re.search(r'Solus', string, re.I):
|
||||||
|
string = re.sub(r'initrd=', 'rd.live.dir=/multibootusb/' + iso_basename(iso_link) +
|
||||||
|
'/LiveOS initrd=', string)
|
||||||
|
|
||||||
|
if not persistence == 0:
|
||||||
|
if re.search(r'liveimg', string, re.I):
|
||||||
|
string = re.sub(r'liveimg', 'liveimg overlay=UUID=' + usb_uuid, string)
|
||||||
|
elif re.search(r'rd.live.image', string, re.I):
|
||||||
|
string = re.sub(r'rd.live.image', 'rd.live.image rw rd.live.overlay=UUID=' + usb_uuid, string)
|
||||||
|
string = re.sub(r' ro ', '', string)
|
||||||
|
elif distro == 'kaspersky':
|
||||||
|
if not os.path.exists(os.path.join(usb_mount, 'multibootusb', iso_basename(iso_link), 'kaspersky.cfg')):
|
||||||
|
shutil.copyfile(resource_path(os.path.join('data', 'multibootusb', 'syslinux.cfg')),
|
||||||
|
os.path.join(usb_mount, 'multibootusb', iso_basename(iso_link), 'kaspersky.cfg'))
|
||||||
|
config_string = kaspersky_config('kaspersky')
|
||||||
|
config_string = config_string.replace('$INSTALL_DIR', '/multibootusb/' + iso_basename(iso_link))
|
||||||
|
config_string = re.sub(r'root=live:UUID=', 'root=live:UUID=' + usb_uuid, config_string)
|
||||||
|
with open(os.path.join(usb_mount, 'multibootusb', iso_basename(iso_link), 'kaspersky.cfg'), "a") as f:
|
||||||
|
f.write(config_string)
|
||||||
|
elif distro == "parted-magic":
|
||||||
|
if re.search(r'append', string, re.I):
|
||||||
|
string = re.sub(r'append', 'append directory=/multibootusb/' + iso_basename(iso_link), string,
|
||||||
|
flags=re.I)
|
||||||
|
string = re.sub(r'initrd=', 'directory=/multibootusb/' + iso_basename(iso_link) + '/ initrd=',
|
||||||
|
string)
|
||||||
|
elif distro == "ubcd":
|
||||||
|
string = re.sub(r'iso_filename=\S*', 'directory=/multibootusb/' + iso_basename(iso_link),
|
||||||
|
string, flags=re.I)
|
||||||
|
elif distro == 'f4ubcd':
|
||||||
|
if not 'multibootusb' in string:
|
||||||
|
string = re.sub(r'/HBCD', '/multibootusb/' + iso_basename(iso_link) + '/HBCD', string)
|
||||||
|
if not 'multibootusb' in string:
|
||||||
|
string = re.sub(r'/F4UBCD', '/multibootusb/' + iso_basename(iso_link) + '/F4UBCD', string)
|
||||||
|
elif distro == "ipcop":
|
||||||
|
string = re.sub(r'ipcopboot=cdrom\S*', 'ipcopboot=usb', string)
|
||||||
|
elif distro == "puppy":
|
||||||
|
string = re.sub(r'pmedia=cd\S*',
|
||||||
|
'pmedia=usbflash psubok=TRUE psubdir=/multibootusb/' + iso_basename(iso_link) + '/',
|
||||||
|
string)
|
||||||
|
elif distro == "slax":
|
||||||
|
string = re.sub(r'initrd=',
|
||||||
|
r'from=/multibootusb/' + iso_basename(iso_link) + '/slax fromusb initrd=', string)
|
||||||
|
elif distro == "knoppix":
|
||||||
|
string = re.sub(r'initrd=', 'knoppix_dir=/multibootusb/' + iso_basename(iso_link) + '/KNOPPIX initrd=', string)
|
||||||
|
#string = re.sub(r'(append)',
|
||||||
|
# r'\1 knoppix_dir=/multibootusb/' + iso_basename(iso_link) + '/KNOPPIX',
|
||||||
|
# string)
|
||||||
|
elif distro == "gentoo":
|
||||||
|
string = re.sub(r'append ',
|
||||||
|
'append real_root=' + usb_disk + ' slowusb subdir=/multibootusb/' +
|
||||||
|
iso_basename(iso_link) + '/ ', string, flags=re.I)
|
||||||
|
elif distro == "systemrescuecd":
|
||||||
|
rows = []
|
||||||
|
subdir = '/multibootusb/' + iso_basename(iso_link) + '/'
|
||||||
|
for line in string.splitlines(True):
|
||||||
|
addline = True
|
||||||
|
if re.match(r'append.*--.*', line, flags=re.I):
|
||||||
|
line = re.sub(r'(append)(.*)--(.*)', r'\1\2subdir=' + subdir + r' --\3 subdir=' + subdir,
|
||||||
|
line, flags=re.I)
|
||||||
|
elif re.match(r'append', line, flags=re.I):
|
||||||
|
line = re.sub(r'(append)', r'\1 subdir=' + subdir, line, flags=re.I)
|
||||||
|
elif re.match(r'label rescue(32|64)_1', line, flags=re.I):
|
||||||
|
rows.append(line)
|
||||||
|
rows.append('append subdir=%s\n' % (subdir,))
|
||||||
|
addline = False
|
||||||
|
|
||||||
|
if addline:
|
||||||
|
rows.append(line)
|
||||||
|
|
||||||
|
string = ''.join(rows)
|
||||||
|
elif distro == "arch" or distro == "chakra":
|
||||||
|
string = re.sub(r'isolabel=\S*',
|
||||||
|
'isodevice=/dev/disk/by-uuid/' + usb_uuid, string, flags=re.I)
|
||||||
|
string = re.sub(r'isobasedir=',
|
||||||
|
'isobasedir=/multibootusb/' + iso_basename(iso_link) + '/', string, flags=re.I)
|
||||||
|
string = re.sub(r'ui gfxboot', '# ui gfxboot', string) # Bug in the isolinux package
|
||||||
|
if 'manjaro' in string:
|
||||||
|
if not os.path.exists(os.path.join(usb_mount, '.miso')):
|
||||||
|
with open(os.path.join(usb_mount, '.miso'), "w") as f:
|
||||||
|
f.write('')
|
||||||
|
elif distro == "kaos":
|
||||||
|
string = re.sub(r'kdeosisolabel=\S*',
|
||||||
|
'kdeosisodevice=/dev/disk/by-uuid/' + usb_uuid, string, flags=re.I)
|
||||||
|
string = re.sub(r'append',
|
||||||
|
'append kdeosisobasedir=/multibootusb/' + iso_basename(iso_link) + '/kdeos/', string, flags=re.I)
|
||||||
|
string = re.sub(r'ui gfxboot', '# ui gfxboot', string) # Bug in the isolinux package
|
||||||
|
elif distro == "suse" or distro == "opensuse":
|
||||||
|
if re.search(r'opensuse_12', string, re.I):
|
||||||
|
string = re.sub(r'append',
|
||||||
|
'append loader=syslinux isofrom_system=/dev/disk/by-uuid/' + usb_uuid + ":/" +
|
||||||
|
iso_name(iso_link), string, flags=re.I)
|
||||||
|
else:
|
||||||
|
string = re.sub(r'append',
|
||||||
|
'append loader=syslinux isofrom_device=/dev/disk/by-uuid/' + usb_uuid +
|
||||||
|
' isofrom_system=/multibootusb/' + iso_basename(iso_link) + '/' + iso_name(iso_link),
|
||||||
|
string, flags=re.I)
|
||||||
|
elif distro == "pclinuxos":
|
||||||
|
string = re.sub(r'livecd=',
|
||||||
|
'fromusb livecd=' + '/multibootusb/' + iso_basename(iso_link) + '/',
|
||||||
|
string)
|
||||||
|
string = re.sub(r'prompt', '#prompt', string)
|
||||||
|
string = re.sub(r'ui gfxboot.com', '#ui gfxboot.com', string)
|
||||||
|
string = re.sub(r'timeout', '#timeout', string)
|
||||||
|
elif distro == "wifislax":
|
||||||
|
string = re.sub(r'vmlinuz',
|
||||||
|
'vmlinuz from=multibootusb/' + iso_basename(iso_link) + ' noauto', string)
|
||||||
|
string = re.sub(r'vmlinuz2',
|
||||||
|
'vmlinuz2 from=multibootusb/' + iso_basename(iso_link) + ' noauto', string)
|
||||||
|
elif distro == "porteus":
|
||||||
|
string = re.sub(r'APPEND',
|
||||||
|
'APPEND from=/multibootusb/' + iso_basename(iso_link) + ' noauto', string)
|
||||||
|
string = re.sub(r'vmlinuz2',
|
||||||
|
'vmlinuz2 from=multibootusb/' + iso_basename(iso_link) + ' noauto', string)
|
||||||
|
elif distro == "hbcd":
|
||||||
|
if not 'multibootusb' in string:
|
||||||
|
string = re.sub(r'/HBCD', '/multibootusb/' + iso_basename(iso_link) + '/HBCD', string)
|
||||||
|
elif distro == "zenwalk":
|
||||||
|
string = re.sub(r'initrd=',
|
||||||
|
'from=/multibootusb/' + iso_basename(iso_link) + '/' + iso_name(iso_link) + ' initrd=',
|
||||||
|
string)
|
||||||
|
elif distro == "mageialive":
|
||||||
|
string = re.sub(r'LABEL=\S*', 'LABEL=' + usb_label, string)
|
||||||
|
elif distro == "antix":
|
||||||
|
string = re.sub(r'APPEND', 'image_dir=/multibootusb/' + iso_basename(iso_link), string)
|
||||||
|
elif distro == "solydx":
|
||||||
|
string = re.sub(r'live-media-path=', 'live-media-path=/multibootusb/' + iso_basename(iso_link),
|
||||||
|
string)
|
||||||
|
elif distro == "salix-live":
|
||||||
|
string = re.sub(r'iso_path', '/multibootusb/' + iso_basename(iso_link) + '/' + iso_name(iso_link),
|
||||||
|
string)
|
||||||
|
#string = re.sub(r'initrd', 'from=/multibootusb/' + iso_basename(iso_link) + '/' + ' initrd', string)
|
||||||
|
elif distro == 'alt-linux':
|
||||||
|
string = re.sub(r':cdrom', ':disk', string)
|
||||||
|
elif distro == 'fsecure':
|
||||||
|
string = re.sub(r'APPEND ramdisk_size', 'APPEND noprompt ' + 'knoppix_dir=/multibootusb/' + iso_basename(iso_link)
|
||||||
|
+ '/KNOPPIX ramdisk_size', string)
|
||||||
|
|
||||||
|
config_file = open(cfg_file, "w")
|
||||||
|
config_file.write(string)
|
||||||
|
config_file.close()
|
||||||
|
|
||||||
|
update_mbusb_cfg_file(iso_link, usb_uuid, usb_mount, distro)
|
||||||
|
|
||||||
|
|
||||||
|
def update_mbusb_cfg_file(iso_link, usb_uuid, usb_mount, distro):
|
||||||
|
"""
|
||||||
|
Update main multibootusb suslinux.cfg file after distro is installed.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
log('Updating multibootusb config file...')
|
||||||
|
sys_cfg_file = os.path.join(usb_mount, "multibootusb", "syslinux.cfg")
|
||||||
|
install_dir = os.path.join(usb_mount, "multibootusb", iso_basename(iso_link))
|
||||||
|
if os.path.exists(sys_cfg_file):
|
||||||
|
|
||||||
|
if distro == "hbcd":
|
||||||
|
if os.path.exists(os.path.join(usb_mount, "multibootusb", "menu.lst")):
|
||||||
|
_config_file = os.path.join(usb_mount, "multibootusb", "menu.lst")
|
||||||
|
config_file = open(_config_file,"w")
|
||||||
|
string = re.sub(r'/HBCD', '/multibootusb/' + iso_basename(iso_link) + '/HBCD', _config_file)
|
||||||
|
config_file.write(string)
|
||||||
|
config_file.close()
|
||||||
|
with open(sys_cfg_file, "a") as f:
|
||||||
|
f.write("#start " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("LABEL " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("MENU LABEL " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("BOOT " + '/multibootusb/' + iso_basename(iso_link) + '/' + isolinux_bin_dir(iso_link).replace("\\", "/") + '/' + distro + '.bs' + "\n")
|
||||||
|
f.write("#end " + iso_basename(config.iso_link) + "\n")
|
||||||
|
elif distro == "Windows":
|
||||||
|
if os.path.exists(sys_cfg_file):
|
||||||
|
config_file = open(sys_cfg_file, "a")
|
||||||
|
config_file.write("#start " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("LABEL " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("MENU LABEL " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("KERNEL chain.c32 hd0 1 ntldr=/bootmgr" + "\n")
|
||||||
|
config_file.write("#end " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.close()
|
||||||
|
elif distro == 'f4ubcd':
|
||||||
|
if os.path.exists(sys_cfg_file):
|
||||||
|
config_file = open(sys_cfg_file, "a")
|
||||||
|
config_file.write("#start " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("LABEL " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("MENU LABEL " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("KERNEL grub.exe" + "\n")
|
||||||
|
config_file.write('APPEND --config-file=/multibootusb/' + iso_basename(config.iso_link) + '/menu.lst' + "\n")
|
||||||
|
config_file.write("#end " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.close()
|
||||||
|
elif distro == 'kaspersky':
|
||||||
|
if os.path.exists(sys_cfg_file):
|
||||||
|
config_file = open(sys_cfg_file, "a")
|
||||||
|
config_file.write("#start " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("LABEL " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("MENU LABEL " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("CONFIG " + '/multibootusb/' + iso_basename(config.iso_link) + '/kaspersky.cfg' + "\n")
|
||||||
|
config_file.write("#end " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.close()
|
||||||
|
elif distro == 'grub4dos':
|
||||||
|
update_menu_lst()
|
||||||
|
elif distro == 'grub4dos_iso':
|
||||||
|
update_grub4dos_iso_menu()
|
||||||
|
else:
|
||||||
|
# admin.adminCmd(["mount", "-o", "remount,rw", config.usb_disk])
|
||||||
|
config_file = open(sys_cfg_file, "a")
|
||||||
|
config_file.write("#start " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("LABEL " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.write("MENU LABEL " + iso_basename(iso_link) + "\n")
|
||||||
|
if distro == "salix-live":
|
||||||
|
if os.path.exists(os.path.join(config.usb_mount, 'multibootusb', iso_basename(iso_link), 'boot', 'grub2-linux.img')):
|
||||||
|
config_file.write(
|
||||||
|
"LINUX " + '/multibootusb/' + iso_basename(iso_link) + '/boot/grub2-linux.img' + "\n")
|
||||||
|
else:
|
||||||
|
config_file.write("BOOT " + '/multibootusb/' + iso_basename(iso_link) + '/' + isolinux_bin_dir(iso_link).replace("\\", "/") + '/' + distro + '.bs' + "\n")
|
||||||
|
elif distro == "pclinuxos":
|
||||||
|
config_file.write("kernel " + '/multibootusb/' + iso_basename(iso_link) + '/isolinux/vmlinuz' + "\n")
|
||||||
|
config_file.write("append livecd=livecd root=/dev/rd/3 acpi=on vga=788 keyb=us vmalloc=256M nokmsboot "
|
||||||
|
"fromusb root=UUID=" + usb_uuid + " bootfromiso=/multibootusb/" +
|
||||||
|
iso_basename(iso_link) + "/" + iso_name(iso_link) + " initrd=/multibootusb/"
|
||||||
|
+ iso_basename(iso_link) + '/isolinux/initrd.gz' + "\n")
|
||||||
|
elif distro == "mentest":
|
||||||
|
config_file.write("kernel " + '/multibootusb/' + iso_basename(iso_link) + '/BOOT/MEMTEST.IMG\n')
|
||||||
|
|
||||||
|
elif distro == "sgrubd2":
|
||||||
|
config_file.write("LINUX memdisk\n")
|
||||||
|
config_file.write("INITRD " + "/multibootusb/" + iso_basename(iso_link) + '/' + iso_name(iso_link) + '\n')
|
||||||
|
config_file.write("APPEND iso\n")
|
||||||
|
elif distro == 'ReactOS':
|
||||||
|
config_file.write("COM32 mboot.c32" + '\n')
|
||||||
|
config_file.write("APPEND /loader/setupldr.sys" + '\n')
|
||||||
|
elif distro == 'pc-unlocker':
|
||||||
|
config_file.write("kernel ../ldntldr" + '\n')
|
||||||
|
config_file.write("append initrd=../ntldr" + '\n')
|
||||||
|
else:
|
||||||
|
if isolinux_bin_exist(config.iso_link) is True:
|
||||||
|
if distro == "generic":
|
||||||
|
distro_syslinux_install_dir = isolinux_bin_dir(iso_link)
|
||||||
|
if not isolinux_bin_dir(iso_link) == "/":
|
||||||
|
distro_sys_install_bs = os.path.join(usb_mount, isolinux_bin_dir(iso_link)) + '/' + distro + '.bs'
|
||||||
|
else:
|
||||||
|
distro_sys_install_bs = '/' + distro + '.bs'
|
||||||
|
else:
|
||||||
|
distro_syslinux_install_dir = install_dir
|
||||||
|
distro_syslinux_install_dir = distro_syslinux_install_dir.replace(usb_mount, '')
|
||||||
|
distro_sys_install_bs = distro_syslinux_install_dir + '/' + isolinux_bin_dir(iso_link) + '/' + distro + '.bs'
|
||||||
|
|
||||||
|
distro_sys_install_bs = "/" + distro_sys_install_bs.replace("\\", "/") # Windows path issue.
|
||||||
|
|
||||||
|
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')
|
||||||
|
else:
|
||||||
|
config_file.write("BOOT " + distro_sys_install_bs.replace("//", "/") + "\n")
|
||||||
|
|
||||||
|
config_file.write("#end " + iso_basename(iso_link) + "\n")
|
||||||
|
config_file.close()
|
||||||
|
|
||||||
|
for dirpath, dirnames, filenames in os.walk(install_dir):
|
||||||
|
for f in filenames:
|
||||||
|
if f.endswith("isolinux.cfg") or f.endswith("ISOLINUX.CFG"):
|
||||||
|
if not os.path.exists(os.path.join(dirpath, "syslinux.cfg")) or not os.path.exists(os.path.join(dirpath, "SYSLINUX.CFG")):
|
||||||
|
shutil.copy2(os.path.join(dirpath, f), os.path.join(dirpath, "syslinux.cfg"))
|
||||||
|
|
||||||
|
|
||||||
|
def kaspersky_config(distro):
|
||||||
|
if distro == 'kaspersky':
|
||||||
|
return """
|
||||||
|
menu label Kaspersky Rescue Disk
|
||||||
|
kernel $INSTALL_DIR/boot/rescue
|
||||||
|
append root=live:UUID= live_dir=$INSTALL_DIR/rescue/LiveOS/ subdir=$INSTALL_DIR/rescue/LiveOS/ looptype=squashfs rootfstype=auto vga=791 init=/linuxrc loop=$INSTALL_DIR/rescue/LiveOS/squashfs.img initrd=$INSTALL_DIR/boot/rescue.igz lang=en udev liveimg splash quiet doscsi nomodeset
|
||||||
|
label text
|
||||||
|
menu label Kaspersky Rescue Disk - Text Mode
|
||||||
|
kernel $INSTALL_DIR/boot/rescue
|
||||||
|
append root=live:UUID= live_dir=$INSTALL_DIR/rescue/LiveOS/ subdir=$INSTALL_DIR/rescue/LiveOS/ rootfstype=auto vga=791 init=/linuxrc loop=/multiboot/rescue/LiveOS/squashfs.img initrd=$INSTALL_DIR/boot/rescue.igz SLUG_lang=en udev liveimg quiet nox shell noresume doscsi nomodeset
|
||||||
|
label hwinfo
|
||||||
|
menu label Kaspersky Hardware Info
|
||||||
|
kernel $INSTALL_DIR/boot/rescue
|
||||||
|
append root=live:UUID= live_dir=$INSTALL_DIR/rescue/LiveOS/ subdir=$INSTALL_DIR/rescue/LiveOS/ rootfstype=auto vga=791 init=/linuxrc loop=$INSTALL_DIR/rescue/LiveOS/squashfs.img initrd=$INSTALL_DIR/boot/rescue.igz SLUG_lang=en udev liveimg quiet softlevel=boot nox hwinfo noresume doscsi nomodeset """
|
||||||
|
|
||||||
|
|
||||||
|
def update_menu_lst():
|
||||||
|
sys_cfg_file = os.path.join(config.usb_mount, "multibootusb", "syslinux.cfg")
|
||||||
|
install_dir = os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link))
|
||||||
|
menu_lst = iso_menu_lst_path(config.iso_link).replace("\\", "/")
|
||||||
|
with open(sys_cfg_file, "a") as f:
|
||||||
|
f.write("#start " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("LABEL " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("MENU LABEL " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("KERNEL grub.exe" + "\n")
|
||||||
|
f.write('APPEND --config-file=/' + menu_lst + "\n")
|
||||||
|
f.write("#end " + iso_basename(config.iso_link) + "\n")
|
||||||
|
|
||||||
|
def update_grub4dos_iso_menu():
|
||||||
|
sys_cfg_file = os.path.join(config.usb_mount, "multibootusb", "syslinux.cfg")
|
||||||
|
install_dir = os.path.join(config.usb_mount, "multibootusb", iso_basename(config.iso_link))
|
||||||
|
menu_lst_file = os.path.join(install_dir, 'menu.lst')
|
||||||
|
with open(menu_lst_file, "w") as f:
|
||||||
|
f.write("title Boot " + iso_name(config.iso_link) + "\n")
|
||||||
|
f.write("find --set-root --ignore-floppies --ignore-cd /multibootusb/" + iso_basename(config.iso_link) + '/'
|
||||||
|
+ iso_name(config.iso_link) + "\n")
|
||||||
|
f.write("map --heads=0 --sectors-per-track=0 /multibootusb/" + iso_basename(config.iso_link)
|
||||||
|
+ '/' + iso_name(config.iso_link) + ' (hd32)' + "\n")
|
||||||
|
f.write("map --hook" + "\n")
|
||||||
|
f.write("chainloader (hd32)")
|
||||||
|
|
||||||
|
with open(sys_cfg_file, "a") as f:
|
||||||
|
f.write("#start " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("LABEL " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("MENU LABEL " + iso_basename(config.iso_link) + "\n")
|
||||||
|
f.write("KERNEL grub.exe" + "\n")
|
||||||
|
f.write('APPEND --config-file=/multibootusb/' + iso_basename(config.iso_link) + '/' + iso_name(config.iso_link) + "\n")
|
||||||
|
f.write("#end " + iso_basename(config.iso_link) + "\n")
|
417
deb_dist/multibootusb-8.5.0/scripts/usb.py
Normal file
417
deb_dist/multibootusb-8.5.0/scripts/usb.py
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: usb.py
|
||||||
|
# Purpose: Module to list USB devices and get details under Linux and Windows
|
||||||
|
# Authors: Sundar
|
||||||
|
# Licence: This file is a part of multibootusb package. You can redistribute it or modify
|
||||||
|
# under the terms of GNU General Public License, v.2 or above
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import platform
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import collections
|
||||||
|
import ctypes
|
||||||
|
import subprocess
|
||||||
|
from . import gen
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
from . import udisks
|
||||||
|
u = udisks.get_udisks(ver=None)
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
import psutil
|
||||||
|
import win32com.client
|
||||||
|
import win32com.client
|
||||||
|
import wmi
|
||||||
|
import pythoncom
|
||||||
|
|
||||||
|
|
||||||
|
def is_block(usb_disk):
|
||||||
|
"""
|
||||||
|
Function to detect if the USB is block device
|
||||||
|
:param usb_disk: USB disk path
|
||||||
|
:return: True is devie is block device else False
|
||||||
|
"""
|
||||||
|
import stat
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
if len(usb_disk) != 9:
|
||||||
|
return False
|
||||||
|
elif platform.system() == 'Windows':
|
||||||
|
if len(usb_disk) != 2:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
mode = os.stat(usb_disk).st_mode
|
||||||
|
gen.log(mode)
|
||||||
|
gen.log(stat.S_ISBLK(mode))
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return stat.S_ISBLK(mode)
|
||||||
|
|
||||||
|
|
||||||
|
def disk_usage(mount_path):
|
||||||
|
"""
|
||||||
|
Return disk usage statistics about the given path as a (total, used, free)
|
||||||
|
namedtuple. Values are expressed in bytes.
|
||||||
|
"""
|
||||||
|
# Author: Giampaolo Rodola' <g.rodola [AT] gmail [DOT] com>
|
||||||
|
# License: MIT
|
||||||
|
_ntuple_diskusage = collections.namedtuple('usage', 'total used free')
|
||||||
|
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
st = os.statvfs(mount_path)
|
||||||
|
free = st.f_bavail * st.f_frsize
|
||||||
|
total = st.f_blocks * st.f_frsize
|
||||||
|
used = (st.f_blocks - st.f_bfree) * st.f_frsize
|
||||||
|
|
||||||
|
return _ntuple_diskusage(total, used, free)
|
||||||
|
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
|
||||||
|
_, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), \
|
||||||
|
ctypes.c_ulonglong()
|
||||||
|
if sys.version_info >= (3,) or isinstance(mount_path, unicode):
|
||||||
|
fun = ctypes.windll.kernel32.GetDiskFreeSpaceExW
|
||||||
|
else:
|
||||||
|
fun = ctypes.windll.kernel32.GetDiskFreeSpaceExA
|
||||||
|
ret = fun(mount_path, ctypes.byref(_), ctypes.byref(total), ctypes.byref(free))
|
||||||
|
if ret == 0:
|
||||||
|
raise ctypes.WinError()
|
||||||
|
used = total.value - free.value
|
||||||
|
|
||||||
|
return _ntuple_diskusage(total.value, used, free.value)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError("Platform not supported.")
|
||||||
|
|
||||||
|
|
||||||
|
def list(partition=1, fixed=None):
|
||||||
|
"""
|
||||||
|
List inserted USB devices.
|
||||||
|
:return: USB devices as list.
|
||||||
|
"""
|
||||||
|
devices = []
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
from . import pyudev
|
||||||
|
import dbus
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
# pyudev is good enough to detect USB devices on modern Linux machines.
|
||||||
|
gen.log("Using pyudev for detecting USB drives...")
|
||||||
|
context = pyudev.Context()
|
||||||
|
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.get('ID_BUS') in ("usb", "scsi") and device.get('DEVTYPE') == "partition":
|
||||||
|
# gen.log(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()
|
||||||
|
try:
|
||||||
|
# You should come here only if your system does'nt have udev installed.
|
||||||
|
# We will use udiskd2 for now.
|
||||||
|
gen.log("Falling back to Udisks2..")
|
||||||
|
ud_manager_obj = bus.get_object(
|
||||||
|
'org.freedesktop.UDisks2', '/org/freedesktop/UDisks2')
|
||||||
|
ud_manager = dbus.Interface(
|
||||||
|
ud_manager_obj, 'org.freedesktop.DBus.ObjectManager')
|
||||||
|
for k, v in ud_manager.GetManagedObjects().iteritems():
|
||||||
|
drive_info = v.get('org.freedesktop.UDisks2.Block', {})
|
||||||
|
if drive_info.get('IdUsage') == "filesystem" and not drive_info.get(
|
||||||
|
'HintSystem') and not drive_info.get('ReadOnly'):
|
||||||
|
device = drive_info.get('Device')
|
||||||
|
device = bytearray(device).replace(
|
||||||
|
b'\x00', b'').decode('utf-8')
|
||||||
|
devices.append(device)
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
# You must be using really old distro. Otherwise, the code
|
||||||
|
# should not reach here.
|
||||||
|
gen.log("Falling back to Udisks1...")
|
||||||
|
ud_manager_obj = bus.get_object(
|
||||||
|
"org.freedesktop.UDisks", "/org/freedesktop/UDisks")
|
||||||
|
ud_manager = dbus.Interface(
|
||||||
|
ud_manager_obj, 'org.freedesktop.UDisks')
|
||||||
|
for dev in ud_manager.EnumerateDevices():
|
||||||
|
device_obj = bus.get_object(
|
||||||
|
"org.freedesktop.UDisks", dev)
|
||||||
|
device_props = dbus.Interface(
|
||||||
|
device_obj, dbus.PROPERTIES_IFACE)
|
||||||
|
if device_props.Get('org.freedesktop.UDisks.Device',
|
||||||
|
"DriveConnectionInterface") == "usb" and device_props.Get(
|
||||||
|
'org.freedesktop.UDisks.Device', "DeviceIsPartition"):
|
||||||
|
if device_props.Get('org.freedesktop.UDisks.Device', "DeviceIsMounted"):
|
||||||
|
device_file = device_props.Get(
|
||||||
|
'org.freedesktop.UDisks.Device', "DeviceFile")
|
||||||
|
devices.append(device_file)
|
||||||
|
except:
|
||||||
|
gen.log("No USB device found...")
|
||||||
|
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
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
|
||||||
|
else:
|
||||||
|
gen.log("No USB device found...")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def details_udev(usb_disk_part):
|
||||||
|
"""
|
||||||
|
Get details of USB partition using udev
|
||||||
|
"""
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
from . import pyudev
|
||||||
|
"""
|
||||||
|
Try with PyUdev to get the details of USB disks.
|
||||||
|
This is the easiest and reliable method to find USB details.
|
||||||
|
Also, it is a standalone package and no dependencies are required.
|
||||||
|
"""
|
||||||
|
# gen.log "Using PyUdev for detecting USB details..."
|
||||||
|
context = pyudev.Context()
|
||||||
|
for device in context.list_devices(subsystem='block', DEVTYPE='partition',
|
||||||
|
ID_FS_USAGE="filesystem", ID_TYPE="disk",
|
||||||
|
ID_BUS="usb"):
|
||||||
|
fdisk_cmd_out = subprocess.check_output('fdisk -l ' + usb_disk_part, shell=True)
|
||||||
|
if b'Extended' in fdisk_cmd_out:
|
||||||
|
mount_point = ''
|
||||||
|
uuid = 'No_UUID'
|
||||||
|
file_system = 'No_FS'
|
||||||
|
vendor = 'No_Vendor'
|
||||||
|
model = 'No_Model'
|
||||||
|
label = 'No_Label'
|
||||||
|
elif device.get('ID_BUS') in ("usb", "scsi") and device.get('DEVTYPE') == "partition":
|
||||||
|
if (device['DEVNAME']) == usb_disk_part:
|
||||||
|
uuid = str(device['ID_FS_UUID'])
|
||||||
|
file_system = str(device['ID_FS_TYPE'])
|
||||||
|
try:
|
||||||
|
label = str(device['ID_FS_LABEL'])
|
||||||
|
except:
|
||||||
|
label = "No_Label"
|
||||||
|
mount_point = u.mount(usb_disk_part)
|
||||||
|
# mount_point = os.popen('findmnt -nr -o target -S %s' % usb_disk_part).read().strip()
|
||||||
|
# Convert the hex string of space to empty space.
|
||||||
|
mount_point = mount_point.replace('\\x20', ' ')
|
||||||
|
try:
|
||||||
|
vendor = str(device['ID_VENDOR'])
|
||||||
|
except:
|
||||||
|
vendor = str('No_Vendor')
|
||||||
|
try:
|
||||||
|
model = str(device['ID_MODEL'])
|
||||||
|
except:
|
||||||
|
model = str('No_Model')
|
||||||
|
|
||||||
|
if not mount_point == '':
|
||||||
|
size_total = shutil.disk_usage(mount_point)[0]
|
||||||
|
size_used = shutil.disk_usage(mount_point)[1]
|
||||||
|
size_free = shutil.disk_usage(mount_point)[2]
|
||||||
|
|
||||||
|
else:
|
||||||
|
size_total = str('No_Mount')
|
||||||
|
size_used = str('No_Mount')
|
||||||
|
size_free = str('No_Mount')
|
||||||
|
mount_point = str('No_Mount')
|
||||||
|
|
||||||
|
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}
|
||||||
|
|
||||||
|
|
||||||
|
def details_udisks2(usb_disk_part):
|
||||||
|
"""
|
||||||
|
Get details of USB disk detail.
|
||||||
|
usb_disk_part: It is the partition of an USB removable disk.
|
||||||
|
"""
|
||||||
|
import dbus
|
||||||
|
bus = dbus.SystemBus()
|
||||||
|
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 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')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
mount_point = u.mount(usb_disk_part)
|
||||||
|
except:
|
||||||
|
mount_point = "No_Mount"
|
||||||
|
try:
|
||||||
|
label = bd.Get('org.freedesktop.UDisks2.Block', 'IdLabel', dbus_interface='org.freedesktop.DBus.Properties')
|
||||||
|
except:
|
||||||
|
label = "No_Label"
|
||||||
|
usb_drive_id = (bd.Get('org.freedesktop.UDisks2.Block', 'Drive', dbus_interface='org.freedesktop.DBus.Properties'))
|
||||||
|
bd1 = bus.get_object('org.freedesktop.UDisks2', usb_drive_id)
|
||||||
|
try:
|
||||||
|
vendor = bd1.Get('org.freedesktop.UDisks2.Drive', 'Vendor', dbus_interface='org.freedesktop.DBus.Properties')
|
||||||
|
except:
|
||||||
|
vendor = str('No_Vendor')
|
||||||
|
try:
|
||||||
|
model = bd1.Get('org.freedesktop.UDisks2.Drive', 'Model', dbus_interface='org.freedesktop.DBus.Properties')
|
||||||
|
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]
|
||||||
|
else:
|
||||||
|
size_total = str('No_Mount')
|
||||||
|
size_used = str('No_Mount')
|
||||||
|
size_free = str('No_Mount')
|
||||||
|
|
||||||
|
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}
|
||||||
|
|
||||||
|
|
||||||
|
def bytes2human(n):
|
||||||
|
"""
|
||||||
|
Convert the size to human readable format
|
||||||
|
Authored by 'Giampaolo Rodolà' and original link is:-
|
||||||
|
http://code.activestate.com/recipes/577972-disk-usage/
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
n = int(n)
|
||||||
|
except:
|
||||||
|
return 'Unknown'
|
||||||
|
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||||
|
prefix = {}
|
||||||
|
for i, s in enumerate(symbols):
|
||||||
|
prefix[s] = 1 << (i + 1) * 10
|
||||||
|
for s in reversed(symbols):
|
||||||
|
if n >= prefix[s]:
|
||||||
|
value = float(n) / prefix[s]
|
||||||
|
return '%.1f%s' % (value, s)
|
||||||
|
return "%sB" % n
|
||||||
|
|
||||||
|
|
||||||
|
def win_disk_details(disk_drive):
|
||||||
|
"""
|
||||||
|
Populate and get details of an USB disk under windows. Minimum required windows version is Vista.
|
||||||
|
:param disk_drive: USB disk like 'G:'
|
||||||
|
:return: See the details(usb_disk_part) function for return values.
|
||||||
|
"""
|
||||||
|
pythoncom.CoInitialize()
|
||||||
|
vendor = 'Not_Found'
|
||||||
|
model = 'Not_Found'
|
||||||
|
selected_usb_part = str(disk_drive)
|
||||||
|
oFS = win32com.client.Dispatch("Scripting.FileSystemObject")
|
||||||
|
d = oFS.GetDrive(oFS.GetDriveName(oFS.GetAbsolutePathName(selected_usb_part)))
|
||||||
|
selected_usb_device = d.DriveLetter
|
||||||
|
label = (d.VolumeName).strip()
|
||||||
|
if not label.strip():
|
||||||
|
label = "No_label"
|
||||||
|
mount_point = selected_usb_device + ":\\"
|
||||||
|
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]
|
||||||
|
'''
|
||||||
|
# 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,
|
||||||
|
'vendor': vendor, 'model': model}
|
||||||
|
|
||||||
|
|
||||||
|
def details(usb_disk_part):
|
||||||
|
"""
|
||||||
|
Populate and get details of an USB disk.
|
||||||
|
:param usb_disk_part: USB disk. Example.. "/dev/sdb1" on Linux and "D:\" on Windows.
|
||||||
|
:return: label == > returns name/label of an inserted USB device.
|
||||||
|
mount_point == > returns mount path of an inserted USB device.
|
||||||
|
uuid == > returns uuid of an inserted USB device.
|
||||||
|
file_system == > returns type of filesystem of an inserted USB device.
|
||||||
|
device == > returns device path of an inserted USB device.
|
||||||
|
size_total == > returns total size in MB/GB of an inserted USB device.
|
||||||
|
size_free == > returns free size in MB/GB of an inserted USB device.
|
||||||
|
size_used == > returns used size in MB/GB of an inserted USB device.
|
||||||
|
vendor == > returns the name of the manufacturer.
|
||||||
|
model == > returns the model name of the USB.
|
||||||
|
"""
|
||||||
|
if platform.system() == 'Linux':
|
||||||
|
try:
|
||||||
|
udev = details_udev(usb_disk_part)
|
||||||
|
uuid = udev['uuid']
|
||||||
|
file_system = udev['file_system']
|
||||||
|
label = udev['label']
|
||||||
|
mount_point = udev['mount_point']
|
||||||
|
size_total = udev['size_total']
|
||||||
|
size_used = udev['size_used']
|
||||||
|
size_free = udev['size_free']
|
||||||
|
vendor = udev['vendor']
|
||||||
|
model = udev['model']
|
||||||
|
except:
|
||||||
|
udisks2 = details_udisks2(usb_disk_part)
|
||||||
|
uuid = udisks2['uuid']
|
||||||
|
file_system = udisks2['file_system']
|
||||||
|
label = udisks2['label']
|
||||||
|
mount_point = udisks2['mount_point']
|
||||||
|
size_total = udisks2['size_total']
|
||||||
|
size_used = udisks2['size_used']
|
||||||
|
size_free = udisks2['size_free']
|
||||||
|
vendor = udisks2['vendor']
|
||||||
|
model = udisks2['model']
|
||||||
|
elif platform.system() == 'Windows':
|
||||||
|
win_details = win_disk_details(usb_disk_part)
|
||||||
|
uuid = win_details['uuid']
|
||||||
|
file_system = win_details['file_system']
|
||||||
|
label = win_details['label']
|
||||||
|
mount_point = win_details['mount_point']
|
||||||
|
size_total = win_details['size_total']
|
||||||
|
size_used = win_details['size_used']
|
||||||
|
size_free = win_details['size_free']
|
||||||
|
vendor = win_details['vendor']
|
||||||
|
model = win_details['model']
|
||||||
|
|
||||||
|
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}
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
usb_devices = list()
|
||||||
|
if usb_devices is not None:
|
||||||
|
for dev in usb_devices:
|
||||||
|
gen.log(details(dev))
|
53
deb_dist/multibootusb-8.5.0/setup.py
Normal file
53
deb_dist/multibootusb-8.5.0/setup.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Name: setup.py
|
||||||
|
# Purpose: Module to create packages or install multibootusb package from source
|
||||||
|
# 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 distutils.core import setup
|
||||||
|
#from setuptools import setup, find_packages
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from scripts.gen import mbusb_version
|
||||||
|
|
||||||
|
Version = mbusb_version()
|
||||||
|
print(Version)
|
||||||
|
setup(
|
||||||
|
name='multibootusb',
|
||||||
|
version=Version,
|
||||||
|
packages=['scripts', 'scripts.pyudev', 'scripts.pyudev.device', 'scripts.pyudev._ctypeslib', 'scripts.pyudev._os',
|
||||||
|
'scripts.gui', 'scripts.progressbar'],
|
||||||
|
#packages=find_packages(),
|
||||||
|
scripts=['multibootusb', 'multibootusb-pkexec'],
|
||||||
|
platforms=['Linux'],
|
||||||
|
url='http://multibootusb.org/',
|
||||||
|
license='General Public License (GPL)',
|
||||||
|
author='Sundar',
|
||||||
|
author_email='feedback.multibootusb@gmail.com',
|
||||||
|
description='Create multi boot live Linux on a USB disk...',
|
||||||
|
long_description='multibootusb is an advanced cross-platform application for installing/uninstalling Linux operating systems on to a single USB flash drives.',
|
||||||
|
data_files=[("/usr/share/applications", ["data/multibootusb.desktop"]),
|
||||||
|
('/usr/share/pixmaps', ["data/tools/multibootusb.png"]),
|
||||||
|
('/usr/share/polkit-1/actions/', ['org.debian.pkexec.run-multibootusb.policy']),
|
||||||
|
('/usr/share/multibootusb/data/tools', ["data/tools/mbr.bin"]),
|
||||||
|
('/usr/share/multibootusb/data', ["data/version.txt"]),
|
||||||
|
('/usr/share/multibootusb/data/tools', ["data/tools/multibootusb.png"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/dd', ["data/tools/dd/dd.exe"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/dd', ["data/tools/dd/diskio.dll"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/mkfs', ["data/tools/mkfs/mke2fs.exe"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/chain.c32"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/bg.png"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/extlinux.cfg"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/grub.exe"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/memdisk"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/menu.c32"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/menu.lst"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/syslinux.cfg"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/multibootusb', ["data/multibootusb/vesamenu.c32"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/syslinux', ["data/tools/syslinux/syslinux_modules.zip"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/syslinux', ["data/tools/syslinux/syslinux_linux.zip"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/syslinux', ["data/tools/syslinux/syslinux_linux_64.zip"]),
|
||||||
|
('/usr/share/multibootusb/data/tools/syslinux', ["data/tools/syslinux/syslinux_windows.zip"])]
|
||||||
|
)
|
BIN
deb_dist/multibootusb_8.5.0-1.debian.tar.xz
Normal file
BIN
deb_dist/multibootusb_8.5.0-1.debian.tar.xz
Normal file
Binary file not shown.
19
deb_dist/multibootusb_8.5.0-1.dsc
Normal file
19
deb_dist/multibootusb_8.5.0-1.dsc
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Format: 3.0 (quilt)
|
||||||
|
Source: multibootusb
|
||||||
|
Binary: python3-multibootusb
|
||||||
|
Architecture: all
|
||||||
|
Version: 8.5.0-1
|
||||||
|
Maintainer: Sundar <feedback.multibootusb@gmail.com>
|
||||||
|
Standards-Version: 3.9.1
|
||||||
|
Build-Depends: python3-all, debhelper (>= 9)
|
||||||
|
Package-List:
|
||||||
|
python3-multibootusb deb system optional arch=all
|
||||||
|
Checksums-Sha1:
|
||||||
|
e1295668fecdb279e3cdbc53078f08cadf2a4948 4544191 multibootusb_8.5.0.orig.tar.gz
|
||||||
|
0a0c598babb9369395d013ffafe88ffaf2b812bb 856 multibootusb_8.5.0-1.debian.tar.xz
|
||||||
|
Checksums-Sha256:
|
||||||
|
7dd7a86b1a980a044045e224aa3145ef6177089a5e7601b6ac12175c86a3d1fe 4544191 multibootusb_8.5.0.orig.tar.gz
|
||||||
|
38df7e3104f4ea0f14318854131e05ef0693bcfc4295d8fda4b0e5cdaaad1868 856 multibootusb_8.5.0-1.debian.tar.xz
|
||||||
|
Files:
|
||||||
|
1eeb4bec75be17aaa260bc55088ab8ca 4544191 multibootusb_8.5.0.orig.tar.gz
|
||||||
|
a291c997070dd3133d0e560d7e27acec 856 multibootusb_8.5.0-1.debian.tar.xz
|
10
deb_dist/tmp_sdist_dsc/multibootusb-8.5.0/PKG-INFO
Normal file
10
deb_dist/tmp_sdist_dsc/multibootusb-8.5.0/PKG-INFO
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Metadata-Version: 1.0
|
||||||
|
Name: multibootusb
|
||||||
|
Version: 8.5.0
|
||||||
|
Summary: Create multi boot live Linux on a USB disk...
|
||||||
|
Home-page: http://multibootusb.org/
|
||||||
|
Author: Sundar
|
||||||
|
Author-email: feedback.multibootusb@gmail.com
|
||||||
|
License: General Public License (GPL)
|
||||||
|
Description: multibootusb is an advanced cross-platform application for installing/uninstalling Linux operating systems on to a single USB flash drives.
|
||||||
|
Platform: Linux
|
@ -0,0 +1,8 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=multibootusb
|
||||||
|
Comment=Install multiple Linux Operating System on USB
|
||||||
|
Icon=multibootusb
|
||||||
|
Exec=multibootusb-pkexec
|
||||||
|
Categories=System;
|
||||||
|
StartupNotify=true
|
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
|
@ -0,0 +1,35 @@
|
|||||||
|
# This file is created by MultiBootUSB.
|
||||||
|
default vesamenu.c32
|
||||||
|
prompt 0
|
||||||
|
menu title MultiBootUSB
|
||||||
|
MENU BACKGROUND /multibootusb/bg.png
|
||||||
|
TIMEOUT 300
|
||||||
|
MENU WIDTH 80
|
||||||
|
MENU MARGIN 10
|
||||||
|
MENU PASSWORDMARGIN 3
|
||||||
|
MENU ROWS 12
|
||||||
|
MENU TABMSGROW 18
|
||||||
|
MENU CMDLINEROW 18
|
||||||
|
MENU ENDROW -1
|
||||||
|
MENU PASSWORDROW 11
|
||||||
|
MENU TIMEOUTROW 20
|
||||||
|
MENU HELPMSGROW 22
|
||||||
|
MENU HELPMSGENDROW -1
|
||||||
|
MENU HIDDENROW -2
|
||||||
|
MENU HSHIFT 0
|
||||||
|
MENU VSHIFT 0
|
||||||
|
MENU COLOR border 30;44 #40ffffff #a0000000 std
|
||||||
|
MENU COLOR title 1;36;44 #9033ccff #a0000000 std
|
||||||
|
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
|
||||||
|
MENU COLOR unsel 37;44 #50ffffff #a0000000 std
|
||||||
|
MENU COLOR help 37;40 #c0ffffff #a0000000 std
|
||||||
|
MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
|
||||||
|
MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
|
||||||
|
MENU COLOR msg07 37;40 #90ffffff #a0000000 std
|
||||||
|
MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
|
||||||
|
label Boot from Hard Drive
|
||||||
|
MENU LABEL Boot from Hard Disk
|
||||||
|
KERNEL chain.c32
|
||||||
|
APPEND hd1
|
||||||
|
MENU DEFAULT
|
||||||
|
|
Binary file not shown.
BIN
deb_dist/tmp_sdist_dsc/multibootusb-8.5.0/data/tools/dd/dd.exe
Normal file
BIN
deb_dist/tmp_sdist_dsc/multibootusb-8.5.0/data/tools/dd/dd.exe
Normal file
Binary file not shown.
Binary file not shown.
BIN
deb_dist/tmp_sdist_dsc/multibootusb-8.5.0/data/tools/mbr.bin
Normal file
BIN
deb_dist/tmp_sdist_dsc/multibootusb-8.5.0/data/tools/mbr.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user