diff --git a/.bin/Scripts/build-ufd b/.bin/Scripts/build-ufd index 1253472c..7d3c5234 100755 --- a/.bin/Scripts/build-ufd +++ b/.bin/Scripts/build-ufd @@ -143,11 +143,11 @@ function help () { [[ "${__usage+x}" ]] || read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered OPTIONS: -u --ufd-device [arg] Device to which the kit will be applied - -m --main-kit [arg] Path to the Main Kit -l --linux-iso [arg] Path to the Linux ISO - -w --winpe-iso [arg] Path to the WinPE ISO -e --extra-dir [arg] Path to the Extra folder (optional) + -m --main-kit [arg] Path to the Main Kit (optional) + -w --winpe-iso [arg] Path to the WinPE ISO (optional) -h --help This page ADVANCED: @@ -390,15 +390,11 @@ if [[ "${arg_h:?}" == 1 ]]; then else # Print warning line [[ "${arg_u:-}" ]] || echo " -u or --ufd-device is required" - [[ "${arg_m:-}" ]] || echo " -m or --main-kit is required" [[ "${arg_l:-}" ]] || echo " -l or --linux-iso is required" - [[ "${arg_w:-}" ]] || echo " -w or --winpe-iso is required" # Bail if necessary [[ "${arg_u:-}" ]] || help "${__usage_example}" [[ "${arg_l:-}" ]] || help "${__usage_example}" - [[ "${arg_m:-}" ]] || help "${__usage_example}" - [[ "${arg_w:-}" ]] || help "${__usage_example}" fi [[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. " @@ -492,9 +488,13 @@ echo "" # Verify sources [[ -b "${DEST_DEV}" ]] || abort "${DEST_DEV} is not a valid device." -[[ -d "${MAIN_KIT}/.bin" ]] || abort "Invalid Main Kit, ${MAIN_KIT}/.bin not found." [[ -e "${LINUX_ISO}" ]] || abort "Linux ISO not found." -[[ -e "${WINPE_ISO}" ]] || abort "WinPE ISO not found." +if [[ ! -z "${arg_m:-}" ]]; then + [[ -d "${MAIN_KIT}/.bin" ]] || abort "Invalid Main Kit, ${MAIN_KIT}/.bin not found." +fi +if [[ ! -z "${arg_w:-}" ]]; then + [[ -e "${WINPE_ISO}" ]] || abort "WinPE ISO not found." +fi if [[ ! -z "${arg_e:-}" ]]; then [[ -d "${EXTRA_DIR}" ]] || abort "Extra Dir not found." fi @@ -554,28 +554,59 @@ echo "Mounting sources and destination..." mkdir /mnt/{Dest,Linux,WinPE} -p >> "${LOG_FILE}" 2>&1 mount ${DEST_PAR} /mnt/Dest >> "${LOG_FILE}" 2>&1 mount "${LINUX_ISO}" /mnt/Linux -r >> "${LOG_FILE}" 2>&1 -mount "${WINPE_ISO}" /mnt/WinPE -r >> "${LOG_FILE}" 2>&1 +if [[ ! -z "${arg_w:-}" ]]; then + mount "${WINPE_ISO}" /mnt/WinPE -r >> "${LOG_FILE}" 2>&1 +fi + +# Find WinPE source +w_boot="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot")" +w_boot_bcd="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot/BCD")" +w_boot_sdi="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot/boot.sdi")" +w_bootmgr="$(find /mnt/WinPE -iwholename "/mnt/WinPE/bootmgr")" +w_bootmgr_efi="$(find /mnt/WinPE -iwholename "/mnt/WinPE/bootmgr.efi")" +w_efi_boot="$(find /mnt/WinPE -iwholename "/mnt/WinPE/EFI/Boot")" +w_efi_microsoft="$(find /mnt/WinPE -iwholename "/mnt/WinPE/EFI/Microsoft")" +w_en_us="$(find /mnt/WinPE -iwholename "/mnt/WinPE/en-us")" +w_sources="$(find /mnt/WinPE -iwholename "/mnt/WinPE/sources")" # Copy files echo "Copying Linux files..." rsync ${RSYNC_ARGS} /mnt/Linux/* /mnt/Dest/ >> "${LOG_FILE}" 2>&1 sed -i "s/${ISO_LABEL}/${UFD_LABEL}/" /mnt/Dest/EFI/boot/refind.conf -sed -i "s/#UFD#//" /mnt/Dest/EFI/boot/refind.conf sed -i "s/${ISO_LABEL}/${UFD_LABEL}/" /mnt/Dest/arch/boot/syslinux/*cfg -sed -i "s/#UFD#//" /mnt/Dest/arch/boot/syslinux/*cfg echo "Copying WinPE files..." -rsync ${RSYNC_ARGS} /mnt/WinPE/{Boot,bootmgr{,.efi},en-us,sources} /mnt/Dest/ >> "${LOG_FILE}" 2>&1 -rsync ${RSYNC_ARGS} /mnt/WinPE/EFI/Microsoft /mnt/Dest/EFI/ >> "${LOG_FILE}" 2>&1 -rsync ${RSYNC_ARGS} /mnt/WinPE/EFI/Boot/* /mnt/Dest/EFI/Microsoft/ >> "${LOG_FILE}" 2>&1 -rsync ${RSYNC_ARGS} /mnt/WinPE/{Boot/{BCD,boot.sdi},bootmgr} /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1 +if [[ ! -z "${arg_w:-}" ]]; then + rsync ${RSYNC_ARGS} \ + "${w_bootmgr}" "${w_bootmgr_efi}" "${w_en_us}" \ + /mnt/Dest/ >> "${LOG_FILE}" 2>&1 + rsync ${RSYNC_ARGS} \ + "${w_boot}"/* \ + /mnt/Dest/Boot/ >> "${LOG_FILE}" 2>&1 + rsync ${RSYNC_ARGS} \ + "${w_efi_boot}"/* "${w_efi_microsoft}"/* \ + /mnt/Dest/EFI/Microsoft/ >> "${LOG_FILE}" 2>&1 + rsync ${RSYNC_ARGS} \ + "${w_boot_bcd}" "${w_boot_sdi}" "${w_bootmgr}" "${w_sources}"/* \ + /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1 + + # Uncomment boot entries + sed -i "s/#UFD-WINPE#//" /mnt/Dest/EFI/boot/refind.conf + sed -i "s/#UFD-WINPE#//" /mnt/Dest/arch/boot/syslinux/*cfg +fi echo "Copying Main Kit..." -rsync ${RSYNC_ARGS} "${MAIN_KIT}/" "/mnt/Dest/${KIT_NAME_FULL}/" >> "${LOG_FILE}" 2>&1 +if [[ ! -z "${arg_m:-}" ]]; then + rsync ${RSYNC_ARGS} \ + "${MAIN_KIT}/" \ + "/mnt/Dest/${KIT_NAME_FULL}/" >> "${LOG_FILE}" 2>&1 +fi if [[ ! -z "${EXTRA_DIR:-}" ]]; then echo "Copying Extra files..." - rsync ${RSYNC_ARGS} "${EXTRA_DIR}"/ /mnt/Dest/ >> "${LOG_FILE}" 2>&1 + rsync ${RSYNC_ARGS} \ + "${EXTRA_DIR}"/ \ + /mnt/Dest/ >> "${LOG_FILE}" 2>&1 fi # Install syslinux diff --git a/.bin/Scripts/debug/hw_diags.py b/.bin/Scripts/debug/hw_diags.py new file mode 100644 index 00000000..87a35990 --- /dev/null +++ b/.bin/Scripts/debug/hw_diags.py @@ -0,0 +1,183 @@ +# Wizard Kit: Debug - HW Diagnostics + +import base64 +import requests + +from functions.common import * + +def debug_report_cpu(cpu_obj): + """Generate report for CpuObj, returns list.""" + report = [] + + # CPU Info + report.append('CPU: {}'.format(cpu_obj.name)) + report.append('lscpu:') + for k, v in sorted(cpu_obj.lscpu.items()): + report.append(' {}: {}'.format(k, v)) + + # Tests + report.append('Tests:') + for k, v in cpu_obj.tests.items(): + report.extend(debug_report_test(v, k)) + + # Done + return report + + +def debug_report_disk(disk_obj): + """Generate report for DiskObj, returns list.""" + report = [] + expand = [ + 'lsblk', + 'nvme_attributes', + 'nvme_smart_notes', + 'smart_attributes', + 'smart_self_test', + 'smartctl', + ] + skip = [ + 'add_nvme_smart_note', + 'calc_io_dd_values', + 'check_attributes', + 'check_smart_self_test', + 'description', + 'disable_test', + 'generate_attribute_report', + 'generate_disk_report', + 'get_details', + 'get_size', + 'get_smart_details', + 'name', + 'safety_check', + 'tests', + ] + + # Disk Info + report.append('Disk: {} {}'.format( + disk_obj.name, disk_obj.description)) + for a in dir(disk_obj): + if a.startswith('_') or a in skip: + continue + if a in expand: + report.append('{}:'.format(a)) + attr = getattr(disk_obj, a) + try: + for k, v in sorted(attr.items()): + report.append(' {}: {}'.format(k, v)) + except Exception: + # Ignore + pass + else: + report.append('{}: {}'.format(a, getattr(disk_obj, a))) + + # Tests + report.append('Tests:') + for k, v in disk_obj.tests.items(): + report.extend(debug_report_test(v, k)) + + # Done + return report + + +def debug_report_state(state): + """Generate report for State, returns list.""" + report = [] + + # Devs + report.append('CPU: {}'.format(state.cpu)) + report.append('Disks: {}'.format(state.disks)) + + # Settings + report.append('Progress Out: {}'.format(state.progress_out)) + report.append('Quick Mode: {}'.format(state.quick_mode)) + + # Tests + report.append('Tests:') + for k, v in state.tests.items(): + report.append(' {}:'.format(k)) + for k2, v2 in sorted(v.items()): + report.append(' {}: {}'.format(k2, v2)) + + # tmux + if hasattr(state, 'tmux_layout'): + report.append('tmux Layout:') + for k, v in state.tmux_layout.items(): + report.append(' {}: {}'.format(k, str(v))) + if hasattr(state, 'panes'): + report.append('tmux Panes:') + for k, v in state.panes.items(): + report.append(' {}: {}'.format(k, str(v))) + + # Done + return report + + +def debug_report_test(test_obj, test_name): + """Generate report for TestObj, returns list.""" + report = [' {}:'.format(test_name)] + skip = ['update_status'] + + # Attributes + for a in [a for a in dir(test_obj) if not a.startswith('_')]: + if a in skip: + continue + report.append(' {}: {}'.format(a, getattr(test_obj, a))) + + # Done + return report + + +def save_debug_reports(state, global_vars): + """Save debug reports if possible.""" + debug_dest = '{}/debug'.format(global_vars['LogDir']) + os.makedirs(debug_dest, exist_ok=True) + + # State + with open('{}/state.report'.format(debug_dest), 'a') as f: + for line in debug_report_state(state): + f.write('{}\n'.format(line)) + + # CPU + with open('{}/cpu.report'.format(debug_dest), 'a') as f: + for line in debug_report_cpu(state.cpu): + f.write('{}\n'.format(line)) + + # Disk(s) + for disk in state.disks: + with open('{}/disk_{}.report'.format(debug_dest, disk.name), 'a') as f: + for line in debug_report_disk(disk): + f.write('{}\n'.format(line)) + + +def upload_logdir(global_vars): + """Upload compressed LogDir to CRASH_SERVER.""" + source = global_vars['LogDir'] + source = source[source.rfind('/')+1:] + dest = '{}.txz'.format(source) + data = None + + # Compress LogDir + os.chdir('{}/..'.format(global_vars['LogDir'])) + cmd = ['tar', 'caf', dest, source] + run_program(cmd) + + # Read file + with open(dest, 'rb') as f: + data = f.read() + + # Upload data + url = '{}/Crash_{}.txz'.format(CRASH_SERVER['Url'], source) + r = requests.put( + url, + data=data, + headers={'X-Requested-With': 'XMLHttpRequest'}, + auth=(CRASH_SERVER['User'], CRASH_SERVER['Pass'])) + # Raise exception if upload NS + if not r.ok: + raise GenericError + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/functions/browsers.py b/.bin/Scripts/functions/browsers.py index 34c0252f..dcb0ed2f 100644 --- a/.bin/Scripts/functions/browsers.py +++ b/.bin/Scripts/functions/browsers.py @@ -2,6 +2,7 @@ from functions.common import * from operator import itemgetter +from settings.browsers import * # Define other_results for later try_and_print @@ -17,95 +18,6 @@ other_results = { } -# STATIC VARIABLES -DEFAULT_HOMEPAGE = 'https://www.google.com/' -IE_GALLERY = 'https://www.microsoft.com/en-us/iegallery' -MOZILLA_PREFS = { - 'browser.search.defaultenginename': '"Google"', - 'browser.search.defaultenginename.US': '"Google"', - 'browser.search.geoSpecificDefaults': 'false', - 'browser.startup.homepage': '"{}"'.format(DEFAULT_HOMEPAGE), - 'extensions.ui.lastCategory': '"addons://list/extension"', - } -UBO_CHROME = 'https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en' -UBO_CHROME_REG = r'Software\Wow6432Node\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm' -UBO_EXTRA_CHROME = 'https://chrome.google.com/webstore/detail/ublock-origin-extra/pgdnlhfefecpicbbihgmbmffkjpaplco?hl=en' -UBO_EXTRA_CHROME_REG = r'Software\Wow6432Node\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco' -UBO_MOZILLA = 'https://addons.mozilla.org/en-us/firefox/addon/ublock-origin/' -UBO_MOZZILA_PATH = r'{}\Mozilla Firefox\distribution\extensions\ublock_origin.xpi'.format(os.environ.get('PROGRAMFILES')) -UBO_MOZILLA_REG = r'Software\Mozilla\Firefox\Extensions' -UBO_MOZILLA_REG_NAME = 'uBlock0@raymondhill.net' -UBO_OPERA = 'https://addons.opera.com/en/extensions/details/ublock/?display=en' -SUPPORTED_BROWSERS = { - 'Internet Explorer': { - 'base': 'ie', - 'exe_name': 'iexplore.exe', - 'rel_install_path': 'Internet Explorer', - 'user_data_path': r'{USERPROFILE}\Favorites', - }, - 'Google Chrome': { - 'base': 'chromium', - 'exe_name': 'chrome.exe', - 'rel_install_path': r'Google\Chrome\Application', - 'user_data_path': r'{LOCALAPPDATA}\Google\Chrome\User Data', - }, - 'Google Chrome Canary': { - 'base': 'chromium', - 'exe_name': 'chrome.exe', - 'rel_install_path': r'Google\Chrome SxS\Application', - 'user_data_path': r'{LOCALAPPDATA}\Google\Chrome SxS\User Data', - }, - 'Mozilla Firefox': { - 'base': 'mozilla', - 'exe_name': 'firefox.exe', - 'rel_install_path': 'Mozilla Firefox', - 'user_data_path': r'{APPDATA}\Mozilla\Firefox\Profiles', - }, - 'Mozilla Firefox Dev': { - 'base': 'mozilla', - 'exe_name': 'firefox.exe', - 'rel_install_path': 'Firefox Developer Edition', - 'user_data_path': r'{APPDATA}\Mozilla\Firefox\Profiles', - }, - 'Opera': { - 'base': 'chromium', - 'exe_name': 'launcher.exe', - 'rel_install_path': 'Opera', - 'user_data_path': r'{APPDATA}\Opera Software\Opera Stable', - }, - 'Opera Beta': { - 'base': 'chromium', - 'exe_name': 'launcher.exe', - 'rel_install_path': 'Opera beta', - 'user_data_path': r'{APPDATA}\Opera Software\Opera Next', - }, - 'Opera Dev': { - 'base': 'chromium', - 'exe_name': 'launcher.exe', - 'rel_install_path': 'Opera developer', - 'user_data_path': r'{APPDATA}\Opera Software\Opera Developer', - }, - } - - -# Regex -REGEX_BACKUP = re.compile( - r'\.\w*bak.*', - re.IGNORECASE) -REGEX_CHROMIUM_PROFILE = re.compile( - r'^(Default|Profile)', - re.IGNORECASE) -REGEX_CHROMIUM_ITEMS = re.compile( - r'^(Bookmarks|Cookies|Favicons|Google Profile' - r'|History|Login Data|Top Sites|TransportSecurity' - r'|Visited Links|Web Data)', - re.IGNORECASE) -REGEX_MOZILLA = re.compile( - r'^(bookmarkbackups|(cookies|formhistory|places).sqlite' - r'|key3.db|logins.json|persdict.dat)$', - re.IGNORECASE) - - def archive_all_users(): """Create backups for all browsers for all users.""" users_root = r'{}\Users'.format(global_vars['Env']['SYSTEMDRIVE']) diff --git a/.bin/Scripts/functions/common.py b/.bin/Scripts/functions/common.py index 5a14a3cf..21a52022 100644 --- a/.bin/Scripts/functions/common.py +++ b/.bin/Scripts/functions/common.py @@ -27,11 +27,12 @@ global_vars = {} # STATIC VARIABLES COLORS = { 'CLEAR': '\033[0m', - 'RED': '\033[31m', + 'RED': '\033[31m', 'ORANGE': '\033[31;1m', 'GREEN': '\033[32m', 'YELLOW': '\033[33m', 'BLUE': '\033[34m', + 'PURPLE': '\033[35m', 'CYAN': '\033[36m', } try: @@ -114,6 +115,14 @@ def ask(prompt='Kotaero!'): return answer +def beep(repeat=1): + """Play system bell with optional repeat.""" + for i in range(repeat): + # Print bell char + print('\a') + sleep(0.5) + + def choice(choices, prompt='Kotaero!'): """Prompt the user with a choice question, returns str.""" answer = None diff --git a/.bin/Scripts/functions/data.py b/.bin/Scripts/functions/data.py index be8d7f02..3cbc9ed1 100644 --- a/.bin/Scripts/functions/data.py +++ b/.bin/Scripts/functions/data.py @@ -5,99 +5,7 @@ import json from functions.common import * from operator import itemgetter - - -# STATIC VARIABLES -FAST_COPY_EXCLUDES = [ - r'\*.esd', - r'\*.swm', - r'\*.wim', - r'\*.dd', - r'\*.dd.tgz', - r'\*.dd.txz', - r'\*.map', - r'\*.dmg', - r'\*.image', - r'$RECYCLE.BIN', - r'$Recycle.Bin', - r'.AppleDB', - r'.AppleDesktop', - r'.AppleDouble', - r'.com.apple.timemachine.supported', - r'.dbfseventsd', - r'.DocumentRevisions-V100*', - r'.DS_Store', - r'.fseventsd', - r'.PKInstallSandboxManager', - r'.Spotlight*', - r'.SymAV*', - r'.symSchedScanLockxz', - r'.TemporaryItems', - r'.Trash*', - r'.vol', - r'.VolumeIcon.icns', - r'desktop.ini', - r'Desktop?DB', - r'Desktop?DF', - r'hiberfil.sys', - r'lost+found', - r'Network?Trash?Folder', - r'pagefile.sys', - r'Recycled', - r'RECYCLER', - r'System?Volume?Information', - r'Temporary?Items', - r'Thumbs.db', - ] -FAST_COPY_ARGS = [ - '/cmd=noexist_only', - '/utf8', - '/skip_empty_dir', - '/linkdest', - '/no_ui', - '/auto_close', - '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), - ] -# Code borrowed from: https://stackoverflow.com/a/29075319 -SEM_NORMAL = ctypes.c_uint() -SEM_FAILCRITICALERRORS = 1 -SEM_NOOPENFILEERRORBOX = 0x8000 -SEM_FAIL = SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS - - -# Regex -REGEX_EXCL_ITEMS = re.compile( - r'^(\.(AppleDB|AppleDesktop|AppleDouble' - r'|com\.apple\.timemachine\.supported|dbfseventsd' - r'|DocumentRevisions-V100.*|DS_Store|fseventsd|PKInstallSandboxManager' - r'|Spotlight.*|SymAV.*|symSchedScanLockxz|TemporaryItems|Trash.*' - r'|vol|VolumeIcon\.icns)|desktop\.(ini|.*DB|.*DF)' - r'|(hiberfil|pagefile)\.sys|lost\+found|Network\.*Trash\.*Folder' - r'|Recycle[dr]|System\.*Volume\.*Information|Temporary\.*Items' - r'|Thumbs\.db)$', - re.IGNORECASE) -REGEX_EXCL_ROOT_ITEMS = re.compile( - r'^(boot(mgr|nxt)$|Config.msi' - r'|(eula|globdata|install|vc_?red)' - r'|.*.sys$|System Volume Information|RECYCLER?|\$Recycle\.bin' - r'|\$?Win(dows(.old.*|\. BT|)$|RE_)|\$GetCurrent|Windows10Upgrade' - r'|PerfLogs|Program Files|SYSTEM.SAV' - r'|.*\.(esd|swm|wim|dd|map|dmg|image)$)', - re.IGNORECASE) -REGEX_INCL_ROOT_ITEMS = re.compile( - r'^(AdwCleaner|(My\s*|)(Doc(uments?( and Settings|)|s?)|Downloads' - r'|Media|Music|Pic(ture|)s?|Vid(eo|)s?)' - r'|{prefix}(-?Info|-?Transfer|)' - r'|(ProgramData|Recovery|Temp.*|Users)$' - r'|.*\.(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)' - r''.format(prefix=KIT_NAME_SHORT), - re.IGNORECASE) -REGEX_WIM_FILE = re.compile( - r'\.wim$', - re.IGNORECASE) -REGEX_WINDOWS_OLD = re.compile( - r'^Win(dows|)\.old', - re.IGNORECASE) +from settings.data import * # Classes @@ -170,8 +78,7 @@ def find_core_storage_volumes(device_path=None): '--output', 'NAME,PARTTYPE'] if device_path: cmd.append(device_path) - result = run_program(cmd) - json_data = json.loads(result.stdout.decode()) + json_data = get_json_from_command(cmd) devs = json_data.get('blockdevices', []) devs = [d for d in devs if d.get('parttype', '') == corestorage_uuid] if devs: @@ -251,8 +158,7 @@ def get_mounted_volumes(): 'devtmpfs,hugetlbfs,mqueue,proc,pstore,securityfs,sysfs,tmpfs' ), '-o', 'SOURCE,TARGET,FSTYPE,LABEL,SIZE,AVAIL,USED'] - result = run_program(cmd) - json_data = json.loads(result.stdout.decode()) + json_data = get_json_from_command(cmd) mounted_volumes = [] for item in json_data.get('filesystems', []): mounted_volumes.append(item) @@ -277,8 +183,7 @@ def mount_volumes( find_core_storage_volumes(device_path) # Get list of block devices - result = run_program(cmd) - json_data = json.loads(result.stdout.decode()) + json_data = get_json_from_command(cmd) devs = json_data.get('blockdevices', []) # Get list of volumes diff --git a/.bin/Scripts/functions/ddrescue.py b/.bin/Scripts/functions/ddrescue.py index f6c30e0a..d37e3207 100644 --- a/.bin/Scripts/functions/ddrescue.py +++ b/.bin/Scripts/functions/ddrescue.py @@ -1,6 +1,5 @@ -# Wizard Kit: Functions - ddrescue +# Wizard Kit: Functions - ddrescue-tui -import json import pathlib import psutil import re @@ -11,37 +10,10 @@ import time from collections import OrderedDict from functions.data import * from functions.hw_diags import * +from functions.json import * from functions.tmux import * from operator import itemgetter - - -# STATIC VARIABLES -AUTO_PASS_1_THRESHOLD = 95 -AUTO_PASS_2_THRESHOLD = 98 -DDRESCUE_SETTINGS = { - '--binary-prefixes': {'Enabled': True, 'Hidden': True}, - '--data-preview': {'Enabled': True, 'Hidden': True, 'Value': '5'}, - '--idirect': {'Enabled': True}, - '--odirect': {'Enabled': True}, - '--max-read-rate': {'Enabled': False, 'Value': '1MiB'}, - '--min-read-rate': {'Enabled': True, 'Value': '64KiB'}, - '--reopen-on-error': {'Enabled': True}, - '--retry-passes': {'Enabled': True, 'Value': '0'}, - '--test-mode': {'Enabled': False, 'Value': 'test.map'}, - '--timeout': {'Enabled': True, 'Value': '5m'}, - '-vvvv': {'Enabled': True, 'Hidden': True}, - } -RECOMMENDED_FSTYPES = ['ext3', 'ext4', 'xfs'] -SIDE_PANE_WIDTH = 21 -TMUX_LAYOUT = OrderedDict({ - 'Source': {'y': 2, 'Check': True}, - 'Started': {'x': SIDE_PANE_WIDTH, 'Check': True}, - 'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True}, -}) -USAGE = """ {script_name} clone [source [destination]] - {script_name} image [source [destination]] - (e.g. {script_name} clone /dev/sda /dev/sdb) -""" +from settings.ddrescue import * # Clases @@ -374,15 +346,14 @@ class RecoveryState(): map_allowed_fstypes = RECOMMENDED_FSTYPES.copy() map_allowed_fstypes.extend(['cifs', 'ext2', 'vfat']) map_allowed_fstypes.sort() - json_data = {} + json_data = get_json_from_command(cmd) - # Avoid saving map to non-persistent filesystem - try: - result = run_program(cmd) - json_data = json.loads(result.stdout.decode()) - except Exception: + # Abort if json_data is empty + if not json_data: print_error('ERROR: Failed to verify map path') raise GenericAbort() + + # Avoid saving map to non-persistent filesystem fstype = json_data.get( 'filesystems', [{}])[0].get( 'fstype', 'unknown') @@ -575,21 +546,11 @@ def fix_tmux_panes(state, forced=False): def get_device_details(dev_path): """Get device details via lsblk, returns JSON dict.""" - try: - cmd = ( - 'lsblk', - '--json', - '--output-all', - '--paths', - dev_path) - result = run_program(cmd) - except CalledProcessError: - # Return empty dict and let calling section deal with the issue - return {} + cmd = ['lsblk', '--json', '--output-all', '--paths', dev_path] + json_data = get_json_from_command(cmd) - json_data = json.loads(result.stdout.decode()) # Just return the first device (there should only be one) - return json_data['blockdevices'][0] + return json_data.get('blockdevices', [{}])[0] def get_device_report(dev_path): @@ -622,17 +583,19 @@ def get_device_report(dev_path): def get_dir_details(dir_path): """Get dir details via findmnt, returns JSON dict.""" - try: - result = run_program([ - 'findmnt', '-J', - '-o', 'SOURCE,TARGET,FSTYPE,OPTIONS,SIZE,AVAIL,USED', - '-T', dir_path]) - json_data = json.loads(result.stdout.decode()) - except Exception: + cmd = [ + 'findmnt', '-J', + '-o', 'SOURCE,TARGET,FSTYPE,OPTIONS,SIZE,AVAIL,USED', + '-T', dir_path, + ] + json_data = get_json_from_command(cmd) + + # Raise exception if json_data is empty + if not json_data: raise GenericError( - 'Failed to get directory details for "{}".'.format(self.path)) - else: - return json_data['filesystems'][0] + 'Failed to get directory details for "{}".'.format(dir_path)) + + return json_data.get('filesystems', [{}])[0] def get_dir_report(dir_path): @@ -1238,14 +1201,8 @@ def select_path(skip_device=None): def select_device(description='device', skip_device=None): """Select device via a menu, returns DevObj.""" - cmd = ( - 'lsblk', - '--json', - '--nodeps', - '--output-all', - '--paths') - result = run_program(cmd) - json_data = json.loads(result.stdout.decode()) + cmd = ['lsblk', '--json', '--nodeps', '--output-all', '--paths'] + json_data = get_json_from_command(cmd) skip_names = [] if skip_device: skip_names.append(skip_device.path) @@ -1254,7 +1211,7 @@ def select_device(description='device', skip_device=None): # Build menu dev_options = [] - for dev in json_data['blockdevices']: + for dev in json_data.get('blockdevices', []): # Disable dev if in skip_names disabled = dev['name'] in skip_names or dev['pkname'] in skip_names diff --git a/.bin/Scripts/functions/hw_diags.py b/.bin/Scripts/functions/hw_diags.py index 2b16854b..ddc45bbf 100644 --- a/.bin/Scripts/functions/hw_diags.py +++ b/.bin/Scripts/functions/hw_diags.py @@ -1,96 +1,23 @@ # Wizard Kit: Functions - HW Diagnostics -import json import re import time from collections import OrderedDict +from functions.json import * from functions.osticket import * from functions.sensors import * from functions.threading import * from functions.tmux import * +from settings.hw_diags import * +if DEBUG_MODE: + from debug.hw_diags import * -# STATIC VARIABLES -ATTRIBUTES = { - 'NVMe': { - 'critical_warning': {'Error': 1, 'Critical': True}, - 'media_errors': {'Error': 1, 'Critical': True}, - 'power_on_hours': {'Warning': 12000, 'Error': 26298, 'Ignore': True}, - 'unsafe_shutdowns': {'Warning': 1}, - }, - 'SMART': { - 5: {'Hex': '05', 'Error': 1, 'Critical': True}, - 9: {'Hex': '09', 'Warning': 12000, 'Error': 26298, 'Ignore': True}, - 10: {'Hex': '0A', 'Error': 1}, - 184: {'Hex': 'B8', 'Error': 1}, - 187: {'Hex': 'BB', 'Error': 1}, - 188: {'Hex': 'BC', 'Error': 1}, - 196: {'Hex': 'C4', 'Error': 1}, - 197: {'Hex': 'C5', 'Error': 1, 'Critical': True}, - 198: {'Hex': 'C6', 'Error': 1, 'Critical': True}, - 199: {'Hex': 'C7', 'Error': 1, 'Ignore': True}, - 201: {'Hex': 'C9', 'Error': 1}, - }, - } -HW_OVERRIDES_FORCED = HW_OVERRIDES_FORCED and not HW_OVERRIDES_LIMITED -IO_VARS = { - 'Block Size': 512*1024, - 'Chunk Size': 32*1024**2, - 'Minimum Test Size': 10*1024**3, - 'Alt Test Size Factor': 0.01, - 'Progress Refresh Rate': 5, - 'Scale 8': [2**(0.56*(x+1))+(16*(x+1)) for x in range(8)], - 'Scale 16': [2**(0.56*(x+1))+(16*(x+1)) for x in range(16)], - 'Scale 32': [2**(0.56*(x+1)/2)+(16*(x+1)/2) for x in range(32)], - 'Threshold Graph Fail': 65*1024**2, - 'Threshold Graph Warn': 135*1024**2, - 'Threshold Graph Great': 750*1024**2, - 'Threshold HDD Min': 50*1024**2, - 'Threshold HDD High Avg': 75*1024**2, - 'Threshold HDD Low Avg': 65*1024**2, - 'Threshold SSD Min': 90*1024**2, - 'Threshold SSD High Avg': 135*1024**2, - 'Threshold SSD Low Avg': 100*1024**2, - 'Graph Horizontal': ('▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'), - 'Graph Horizontal Width': 40, - 'Graph Vertical': ( - '▏', '▎', '▍', '▌', - '▋', '▊', '▉', '█', - '█▏', '█▎', '█▍', '█▌', - '█▋', '█▊', '█▉', '██', - '██▏', '██▎', '██▍', '██▌', - '██▋', '██▊', '██▉', '███', - '███▏', '███▎', '███▍', '███▌', - '███▋', '███▊', '███▉', '████'), - } -KEY_NVME = 'nvme_smart_health_information_log' -KEY_SMART = 'ata_smart_attributes' -QUICK_LABEL = '{YELLOW}(Quick){CLEAR}'.format(**COLORS) -SIDE_PANE_WIDTH = 20 -STATUSES = { - 'RED': ['Denied', 'ERROR', 'FAIL', 'TimedOut'], - 'YELLOW': ['Aborted', 'N/A', 'OVERRIDE', 'Unknown', 'Working'], - 'GREEN': ['PASS'], -} -TESTS_CPU = ['Prime95'] -TESTS_DISK = [ - 'I/O Benchmark', - 'NVMe / SMART', - 'badblocks', - ] -TOP_PANE_TEXT = '{GREEN}Hardware Diagnostics{CLEAR}'.format(**COLORS) -TMUX_LAYOUT = OrderedDict({ - 'Top': {'y': 2, 'Check': True}, - 'Started': {'x': SIDE_PANE_WIDTH, 'Check': True}, - 'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True}, - # Testing panes - 'Prime95': {'y': 11, 'Check': False}, - 'Temps': {'y': 1000, 'Check': False}, - 'SMART': {'y': 3, 'Check': True}, - 'badblocks': {'y': 5, 'Check': True}, - 'I/O Benchmark': {'y': 1000, 'Check': False}, -}) +# Fix settings +OVERRIDES_FORCED = OVERRIDES_FORCED and not OVERRIDES_LIMITED +QUICK_LABEL = QUICK_LABEL.format(**COLORS) +TOP_PANE_TEXT = TOP_PANE_TEXT.format(**COLORS) # Regex @@ -115,15 +42,10 @@ class CpuObj(): def get_details(self): """Get CPU details from lscpu.""" cmd = ['lscpu', '--json'] - try: - result = run_program(cmd, check=False) - json_data = json.loads(result.stdout.decode()) - except Exception: - # Ignore and leave self.lscpu empty - return - for line in json_data.get('lscpu', []): - _field = line.get('field', None).replace(':', '') - _data = line.get('data', None) + json_data = get_json_from_command(cmd) + for line in json_data.get('lscpu', [{}]): + _field = line.get('field', '').replace(':', '') + _data = line.get('data', '') if not _field and not _data: # Skip print_warning(_field, _data) @@ -148,18 +70,21 @@ class DiskObj(): """Object for tracking disk specific data.""" def __init__(self, disk_path): self.checkbox = None + self.attr_type = 'UNKNOWN' self.disk_ok = True self.labels = [] self.lsblk = {} self.name = re.sub(r'^.*/(.*)', r'\1', disk_path) self.nvme_attributes = {} + self.nvme_smart_notes = {} + self.override_disabled = False self.path = disk_path self.smart_attributes = {} - self.smart_timeout = False self.smart_self_test = {} self.smartctl = {} self.tests = OrderedDict() self.get_details() + self.get_size() # Try enabling SMART run_program(['sudo', 'smartctl', '--smart=on', self.path], check=False) @@ -169,39 +94,39 @@ class DiskObj(): self.description = '{size} ({tran}) {model} {serial}'.format( **self.lsblk) - def calc_io_dd_values(self): - """Calcualte I/O benchmark dd values.""" - # Get real disk size - cmd = ['lsblk', - '--bytes', '--nodeps', '--noheadings', - '--output', 'size', self.path] - result = run_program(cmd) - self.size_bytes = int(result.stdout.decode().strip()) + def add_nvme_smart_note(self, note): + """Add note that will be included in the NVMe / SMART report.""" + # A dict is used to avoid duplicate notes + self.nvme_smart_notes[note] = None - # dd calculations - ## The minimum dev size is 'Graph Horizontal Width' * 'Chunk Size' - ## (e.g. 1.25 GB for a width of 40 and a chunk size of 32MB) - ## If the device is smaller than the minimum dd_chunks would be set - ## to zero which would cause a divide by zero error. - ## If the device is below the minimum size an Exception will be raised - ## - ## dd_size is the area to be read in bytes - ## If the dev is < 10Gb then it's the whole dev - ## Otherwise it's the larger of 10Gb or 1% of the dev - ## - ## dd_chunks is the number of groups of "Chunk Size" in self.dd_size - ## This number is reduced to a multiple of the graph width in - ## order to allow for the data to be condensed cleanly - ## - ## dd_chunk_blocks is the chunk size in number of blocks - ## (e.g. 64 if block size is 512KB and chunk size is 32MB - ## - ## dd_skip_blocks is the number of "Block Size" groups not tested - ## dd_skip_count is the number of blocks to skip per self.dd_chunk - ## dd_skip_extra is how often to add an additional skip block - ## This is needed to ensure an even testing across the dev - ## This is calculated by using the fractional amount left off - ## of the dd_skip_count variable + def calc_io_dd_values(self): + """Calcualte I/O benchmark dd values. + + Calculations + The minimum dev size is 'Graph Horizontal Width' * 'Chunk Size' + (e.g. 1.25 GB for a width of 40 and a chunk size of 32MB) + If the device is smaller than the minimum dd_chunks would be set + to zero which would cause a divide by zero error. + If the device is below the minimum size an Exception will be raised + + dd_size is the area to be read in bytes + If the dev is < 10Gb then it's the whole dev + Otherwise it's the larger of 10Gb or 1% of the dev + + dd_chunks is the number of groups of "Chunk Size" in self.dd_size + This number is reduced to a multiple of the graph width in + order to allow for the data to be condensed cleanly + + dd_chunk_blocks is the chunk size in number of blocks + (e.g. 64 if block size is 512KB and chunk size is 32MB + + dd_skip_blocks is the number of "Block Size" groups not tested + dd_skip_count is the number of blocks to skip per self.dd_chunk + dd_skip_extra is how often to add an additional skip block + This is needed to ensure an even testing across the dev + This is calculated by using the fractional amount left off + of the dd_skip_count variable + """ self.dd_size = min(IO_VARS['Minimum Test Size'], self.size_bytes) self.dd_size = max( self.dd_size, @@ -223,63 +148,72 @@ class DiskObj(): # self.dd_skip_extra == 0 is fine pass - def check_attributes(self, silent=False): - """Check NVMe / SMART attributes for errors.""" - override_disabled = False + def check_attributes(self): + """Check NVMe / SMART attributes for errors, returns bool.""" + attr_type = self.attr_type + disk_ok = True + + # Get updated attributes + self.get_smart_details() + + # Check attributes if self.nvme_attributes: - attr_type = 'NVMe' + self.add_nvme_smart_note( + ' {YELLOW}NVMe disk support is still experimental{CLEAR}'.format( + **COLORS)) items = self.nvme_attributes.items() elif self.smart_attributes: - attr_type = 'SMART' items = self.smart_attributes.items() for k, v in items: if k in ATTRIBUTES[attr_type]: - if 'Error' not in ATTRIBUTES[attr_type][k]: - # Only worried about error thresholds + if not ATTRIBUTES[attr_type][k]['Error']: + # Informational attribute, skip continue - if ATTRIBUTES[attr_type][k].get('Ignore', False): + if ATTRIBUTES[attr_type][k]['Ignore']: # Attribute is non-failing, skip continue if v['raw'] >= ATTRIBUTES[attr_type][k]['Error']: - self.disk_ok = False + if (ATTRIBUTES[attr_type][k]['Maximum'] + and v['raw'] >= ATTRIBUTES[attr_type][k]['Maximum']): + # Non-standard value, skip + continue + else: + disk_ok = False - # Disable override if necessary - override_disabled |= ATTRIBUTES[attr_type][k].get( - 'Critical', False) + # Disable override if necessary + self.override_disabled |= ATTRIBUTES[attr_type][k].get( + 'Critical', False) # SMART overall assessment ## NOTE: Only fail drives if the overall value exists and reports failed if not self.smartctl.get('smart_status', {}).get('passed', True): - self.disk_ok = False - override_disabled = True + disk_ok = False + self.override_disabled = True + self.add_nvme_smart_note( + ' {RED}SMART overall self-assessment: Failed{CLEAR}'.format(**COLORS)) - # Print errors - if not silent: - if self.disk_ok: - # 199/C7 warning - if self.smart_attributes.get(199, {}).get('raw', 0) > 0: - print_warning('199/C7 error detected') - print_standard(' (Have you tried swapping the disk cable?)') - else: - # Override? - show_report( - self.generate_attribute_report(description=True), - log_report=True) - print_warning(' {} error(s) detected.'.format(attr_type)) - if override_disabled: - print_standard('Tests disabled for this device') - pause() - elif not (len(self.tests) == 3 and HW_OVERRIDES_LIMITED): - if HW_OVERRIDES_FORCED or ask('Run tests on this device anyway?'): - self.disk_ok = True - if 'NVMe / SMART' in self.tests: - self.disable_test('NVMe / SMART', 'OVERRIDE') - if not self.nvme_attributes and self.smart_attributes: - # Re-enable for SMART short-tests - self.tests['NVMe / SMART'].disabled = False - else: - self.tests['NVMe / SMART'].failed = True - print_standard(' ') + # Done + return disk_ok + + def check_smart_self_test(self, silent=False): + """Check if a SMART self-test is currently running, returns bool.""" + msg = 'SMART self-test in progress' + test_running = 'remaining_percent' in self.smart_self_test.get('status', '') + + if test_running: + # Ask to abort + if not silent: + print_warning('WARNING: {}'.format(msg)) + print_standard(' ') + if ask('Abort HW Diagnostics?'): + raise GenericAbort('Bail') + + # Add warning note + self.add_nvme_smart_note( + ' {YELLOW}WARNING: {msg}{CLEAR}'.format(msg=msg, **COLORS)) + + # Done + return test_running def disable_test(self, name, status): """Disable test by name and update status.""" @@ -288,32 +222,21 @@ class DiskObj(): self.tests[name].disabled = True def generate_attribute_report( - self, description=False, short_test=False, timestamp=False): + self, description=False, timestamp=False): """Generate NVMe / SMART report, returns list.""" + attr_type = self.attr_type report = [] if description: report.append('{BLUE}Device ({name}){CLEAR}'.format( name=self.name, **COLORS)) report.append(' {}'.format(self.description)) - # Warnings - if self.nvme_attributes: - attr_type = 'NVMe' - report.append( - ' {YELLOW}NVMe disk support is still experimental{CLEAR}'.format( - **COLORS)) - elif self.smart_attributes: - attr_type = 'SMART' - else: - # No attribute data available, return short report + # Skip attributes if they don't exist + if not (self.nvme_attributes or self.smart_attributes): report.append( ' {YELLOW}No NVMe or SMART data available{CLEAR}'.format( **COLORS)) return report - if not self.smartctl.get('smart_status', {}).get('passed', True): - report.append( - ' {RED}SMART overall self-assessment: Failed{CLEAR}'.format( - **COLORS)) # Attributes report.append('{BLUE}{a} Attributes{YELLOW}{u:>23} {t}{CLEAR}'.format( @@ -342,10 +265,12 @@ class DiskObj(): n=v['name'][:28]) # Set color - for _t, _c in [['Warning', 'YELLOW'], ['Error', 'RED']]: - if _t in ATTRIBUTES[attr_type][k]: + for _t, _c in ATTRIBUTE_COLORS: + if ATTRIBUTES[attr_type][k][_t]: if v['raw'] >= ATTRIBUTES[attr_type][k][_t]: _color = COLORS[_c] + if _t == 'Maximum': + _note = '(invalid?)' # 199/C7 warning if str(k) == '199' and v['raw'] > 0: @@ -361,30 +286,21 @@ class DiskObj(): # Add line to report report.append(_line) - # SMART short-test - if short_test: - report.append('{BLUE}SMART Short self-test{CLEAR}'.format(**COLORS)) - report.append(' {}'.format( - self.smart_self_test['status'].get( - 'string', 'UNKNOWN').capitalize())) - if self.smart_timeout: - report.append(' {YELLOW}Timed out{CLEAR}'.format(**COLORS)) - # Done return report def generate_disk_report(self): """Generate disk report with data from all tests.""" report = [] - report.append('{BLUE}Device ({name}){CLEAR}'.format( - name=self.name, **COLORS)) - report.append(' {}'.format(self.description)) # Attributes - if 'NVMe / SMART' not in self.tests: - report.extend(self.generate_attribute_report()) - elif not self.tests['NVMe / SMART'].report: - report.extend(self.generate_attribute_report()) + report.extend(self.generate_attribute_report(description=True)) + + # Notes + if self.nvme_smart_notes: + report.append('{BLUE}{attr_type} Notes{CLEAR}'.format( + attr_type=self.attr_type, **COLORS)) + report.extend(sorted(self.nvme_smart_notes.keys())) # Tests for test in self.tests.values(): @@ -395,26 +311,25 @@ class DiskObj(): def get_details(self): """Get data from lsblk.""" cmd = ['lsblk', '--json', '--output-all', '--paths', self.path] - try: - result = run_program(cmd, check=False) - json_data = json.loads(result.stdout.decode()) - self.lsblk = json_data['blockdevices'][0] - except Exception: - # Leave self.lsblk empty - pass + json_data = get_json_from_command(cmd) + self.lsblk = json_data.get('blockdevices', [{}])[0] # Set necessary details self.lsblk['model'] = self.lsblk.get('model', 'Unknown Model') self.lsblk['name'] = self.lsblk.get('name', self.path) + self.lsblk['phy-sec'] = self.lsblk.get('phy-sec', -1) self.lsblk['rota'] = self.lsblk.get('rota', True) self.lsblk['serial'] = self.lsblk.get('serial', 'Unknown Serial') self.lsblk['size'] = self.lsblk.get('size', '???b') self.lsblk['tran'] = self.lsblk.get('tran', '???') - # Ensure certain attributes are strings + # Ensure certain attributes types for attr in ['model', 'name', 'rota', 'serial', 'size', 'tran']: if not isinstance(self.lsblk[attr], str): self.lsblk[attr] = str(self.lsblk[attr]) + for attr in ['phy-sec']: + if not isinstance(self.lsblk[attr], int): + self.lsblk[attr] = int(self.lsblk[attr]) self.lsblk['tran'] = self.lsblk['tran'].upper().replace('NVME', 'NVMe') # Build list of labels @@ -423,18 +338,26 @@ class DiskObj(): self.labels.append(disk.get('partlabel', '')) self.labels = [str(label) for label in self.labels if label] + def get_size(self): + """Get real disk size.""" + cmd = ['lsblk', + '--bytes', '--nodeps', '--noheadings', + '--output', 'size', self.path] + try: + result = run_program(cmd) + self.size_bytes = int(result.stdout.decode().strip()) + except Exception: + # Setting to impossible value for now + self.size_bytes = -1 + def get_smart_details(self): """Get data from smartctl.""" cmd = ['sudo', 'smartctl', '--all', '--json', self.path] - try: - result = run_program(cmd, check=False) - self.smartctl = json.loads(result.stdout.decode()) - except Exception: - # Leave self.smartctl empty - pass + self.smartctl = get_json_from_command(cmd) # Check for attributes if KEY_NVME in self.smartctl: + self.attr_type = 'NVMe' self.nvme_attributes = {} for k, v in self.smartctl[KEY_NVME].items(): try: @@ -447,6 +370,7 @@ class DiskObj(): # TODO: Limit this check pass elif KEY_SMART in self.smartctl: + self.attr_type = 'SMART' for a in self.smartctl[KEY_SMART].get('table', {}): try: _id = int(a.get('id', -1)) @@ -476,48 +400,57 @@ class DiskObj(): def safety_check(self, silent=False): """Run safety checks and disable tests if necessary.""" + test_running = False if self.nvme_attributes or self.smart_attributes: - self.check_attributes(silent) + disk_ok = self.check_attributes() + test_running = self.check_smart_self_test(silent) - # Check if a self-test is currently running - if 'remaining_percent' in self.smart_self_test.get('status', ''): - _msg = 'SMART self-test in progress, all tests disabled' - - # Ask to abort - if not silent: - print_warning('WARNING: {}'.format(_msg)) - print_standard(' ') - if ask('Abort HW Diagnostics?'): - exit_script() - - # Add warning to report - if 'NVMe / SMART' in self.tests: - self.tests['NVMe / SMART'].report = self.generate_attribute_report() - self.tests['NVMe / SMART'].report.append( - '{YELLOW}WARNING: {msg}{CLEAR}'.format(msg=_msg, **COLORS)) - - # Disable all tests for this disk - for t in self.tests.keys(): - self.disable_test(t, 'Denied') + # Show errors (unless a SMART self-test is running) + if not (silent or test_running): + if disk_ok: + # 199/C7 warning + if self.smart_attributes.get(199, {}).get('raw', 0) > 0: + print_warning('199/C7 error detected') + print_standard(' (Have you tried swapping the disk cable?)') + else: + # Override? + show_report( + self.generate_attribute_report(description=True), + log_report=True) + print_warning(' {} error(s) detected.'.format(self.attr_type)) + if self.override_disabled: + print_standard('Tests disabled for this device') + pause() + elif not (len(self.tests) == 3 and OVERRIDES_LIMITED): + if OVERRIDES_FORCED or ask('Run tests on this device anyway?'): + disk_ok = True + if 'NVMe / SMART' in self.tests: + self.disable_test('NVMe / SMART', 'OVERRIDE') + if not self.nvme_attributes and self.smart_attributes: + # Re-enable for SMART short-tests + self.tests['NVMe / SMART'].disabled = False + print_standard(' ') else: # No NVMe/SMART details self.disable_test('NVMe / SMART', 'N/A') if silent: - self.disk_ok = HW_OVERRIDES_FORCED + disk_ok = OVERRIDES_FORCED else: - print_info('Device ({})'.format(self.name)) - print_standard(' {}'.format(self.description)) - print_warning(' No NVMe or SMART data available') - self.disk_ok = HW_OVERRIDES_FORCED or ask( - 'Run tests on this device anyway?') + show_report( + self.generate_attribute_report(description=True), + log_report=True) + disk_ok = OVERRIDES_FORCED or ask('Run tests on this device anyway?') print_standard(' ') - if not self.disk_ok: - if 'NVMe / SMART' in self.tests: - # NOTE: This will not overwrite the existing status if set - self.disable_test('NVMe / SMART', 'FAIL') - if not self.tests['NVMe / SMART'].report: - self.tests['NVMe / SMART'].report = self.generate_attribute_report() + # Disable tests if necessary (statuses won't be overwritten) + if test_running: + if not silent: + # silent is only True in quick_mode + self.disable_test('NVMe / SMART', 'Denied') + for t in ['badblocks', 'I/O Benchmark']: + self.disable_test(t, 'Denied') + elif not disk_ok: + self.disable_test('NVMe / SMART', 'FAIL') for t in ['badblocks', 'I/O Benchmark']: self.disable_test(t, 'Denied') @@ -577,9 +510,8 @@ class State(): # Add block devices cmd = ['lsblk', '--json', '--nodeps', '--paths'] - result = run_program(cmd, check=False) - json_data = json.loads(result.stdout.decode()) - for disk in json_data['blockdevices']: + json_data = get_json_from_command(cmd) + for disk in json_data.get('blockdevices', []): skip_disk = False disk_obj = DiskObj(disk['name']) @@ -918,6 +850,8 @@ def run_audio_test(): def run_badblocks_test(state, test): """Run a read-only surface scan with badblocks.""" + dev = test.dev + # Bail early if test.disabled: return @@ -935,7 +869,7 @@ def run_badblocks_test(state, test): break # Prep - print_log('Starting badblocks test for {}'.format(test.dev.path)) + print_log('Starting badblocks test for {}'.format(dev.path)) test.started = True test.update_status() update_progress_pane(state) @@ -944,23 +878,30 @@ def run_badblocks_test(state, test): tmux_update_pane( state.panes['Top'], text='{}\n{}'.format( - TOP_PANE_TEXT, test.dev.description)) + TOP_PANE_TEXT, dev.description)) # Create monitor pane test.badblocks_out = '{}/badblocks_{}.out'.format( - global_vars['LogDir'], test.dev.name) + global_vars['LogDir'], dev.name) state.panes['badblocks'] = tmux_split_window( lines=5, vertical=True, watch=test.badblocks_out, watch_cmd='tail') # Show disk details clear_screen() - show_report(test.dev.generate_attribute_report()) + show_report(dev.generate_attribute_report()) print_standard(' ') + # Set read block size + if dev.lsblk['phy-sec'] == 4096 or dev.size_bytes >= BADBLOCKS_LARGE_DISK: + block_size = '4096' + else: + # Use default value + block_size = '1024' + # Start badblocks print_standard('Running badblocks test...') test.badblocks_proc = popen_program( - ['sudo', 'badblocks', '-sv', '-e', '1', test.dev.path], + ['sudo', 'badblocks', '-sv', '-b', block_size, '-e', '1', dev.path], pipe=True, bufsize=1) test.badblocks_nbsr = NonBlockingStreamReader(test.badblocks_proc.stderr) test.badblocks_stderr = '' @@ -999,7 +940,7 @@ def run_badblocks_test(state, test): # Disable other drive tests if necessary if not test.passed: - test.dev.disable_test('I/O Benchmark', 'Denied') + dev.disable_test('I/O Benchmark', 'Denied') # Update status if test.failed: @@ -1069,7 +1010,12 @@ def run_hw_tests(state): _disk_tests_enabled |= state.tests[k]['Enabled'] if _disk_tests_enabled: for disk in state.disks: - disk.safety_check(silent=state.quick_mode) + try: + disk.safety_check(silent=state.quick_mode) + except GenericAbort: + tmux_kill_pane(*state.panes.values()) + state.panes.clear() + return # Run tests ## Because state.tests is an OrderedDict and the disks were added @@ -1087,6 +1033,11 @@ def run_hw_tests(state): if k == TESTS_CPU[-1]: # Last CPU test run, post CPU results state.ost.post_device_results(state.cpu, state.ticket_id) + # Recheck attributes + if state.tests['NVMe / SMART']['Enabled']: + for test_obj in state.tests['NVMe / SMART']['Objects']: + run_nvme_smart_tests(state, test_obj, update_mode=True) + except GenericAbort: # Cleanup tmux_kill_pane(*state.panes.values()) @@ -1156,12 +1107,14 @@ def run_hw_tests(state): def run_io_benchmark(state, test): """Run a read-only I/O benchmark using dd.""" + dev = test.dev + # Bail early if test.disabled: return # Prep - print_log('Starting I/O benchmark test for {}'.format(test.dev.path)) + print_log('Starting I/O benchmark test for {}'.format(dev.path)) test.started = True test.update_status() update_progress_pane(state) @@ -1170,12 +1123,12 @@ def run_io_benchmark(state, test): tmux_update_pane( state.panes['Top'], text='{}\n{}'.format( - TOP_PANE_TEXT, test.dev.description)) + TOP_PANE_TEXT, dev.description)) state.tmux_layout['Current'] = {'y': 15, 'Check': True} # Create monitor pane test.io_benchmark_out = '{}/io_benchmark_{}.out'.format( - global_vars['LogDir'], test.dev.name) + global_vars['LogDir'], dev.name) state.panes['io_benchmark'] = tmux_split_window( percent=75, vertical=True, watch=test.io_benchmark_out, watch_cmd='tail') @@ -1183,7 +1136,7 @@ def run_io_benchmark(state, test): # Show disk details clear_screen() - show_report(test.dev.generate_attribute_report()) + show_report(dev.generate_attribute_report()) print_standard(' ') # Start I/O Benchmark @@ -1191,23 +1144,23 @@ def run_io_benchmark(state, test): try: test.merged_rates = [] test.read_rates = [] - test.dev.calc_io_dd_values() + dev.calc_io_dd_values() # Run dd read tests offset = 0 - for i in range(test.dev.dd_chunks): + for i in range(dev.dd_chunks): # Build cmd i += 1 - skip = test.dev.dd_skip_count - if test.dev.dd_skip_extra and i % test.dev.dd_skip_extra == 0: + skip = dev.dd_skip_count + if dev.dd_skip_extra and i % dev.dd_skip_extra == 0: skip += 1 cmd = [ 'sudo', 'dd', 'bs={}'.format(IO_VARS['Block Size']), 'skip={}'.format(offset+skip), - 'count={}'.format(test.dev.dd_chunk_blocks), + 'count={}'.format(dev.dd_chunk_blocks), 'iflag=direct', - 'if={}'.format(test.dev.path), + 'if={}'.format(dev.path), 'of=/dev/null'] # Run cmd and get read rate @@ -1221,12 +1174,12 @@ def run_io_benchmark(state, test): # Show progress if i % IO_VARS['Progress Refresh Rate'] == 0: update_io_progress( - percent=(i/test.dev.dd_chunks)*100, + percent=(i/dev.dd_chunks)*100, rate=cur_rate, progress_file=test.io_benchmark_out) # Update offset - offset += test.dev.dd_chunk_blocks + skip + offset += dev.dd_chunk_blocks + skip except DeviceTooSmallError: # Device too small, skipping test @@ -1252,7 +1205,7 @@ def run_io_benchmark(state, test): else: # Merge rates for horizontal graph offset = 0 - width = int(test.dev.dd_chunks / IO_VARS['Graph Horizontal Width']) + width = int(dev.dd_chunks / IO_VARS['Graph Horizontal Width']) for i in range(IO_VARS['Graph Horizontal Width']): test.merged_rates.append( sum(test.read_rates[offset:offset+width])/width) @@ -1273,7 +1226,7 @@ def run_io_benchmark(state, test): test.report.append(avg_min_max) # Compare read speeds to thresholds - if test.dev.lsblk['rota']: + if dev.lsblk['rota']: # Use HDD scale thresh_min = IO_VARS['Threshold HDD Min'] thresh_high_avg = IO_VARS['Threshold HDD High Avg'] @@ -1314,6 +1267,8 @@ def run_keyboard_test(): def run_mprime_test(state, test): """Test CPU with Prime95 and track temps.""" + dev = test.dev + # Bail early if test.disabled: return @@ -1329,7 +1284,7 @@ def run_mprime_test(state, test): # Update tmux layout tmux_update_pane( state.panes['Top'], - text='{}\n{}'.format(TOP_PANE_TEXT, test.dev.name)) + text='{}\n{}'.format(TOP_PANE_TEXT, dev.name)) # Start live sensor monitor test.sensors_out = '{}/sensors.out'.format(global_vars['TmpDir']) @@ -1360,13 +1315,12 @@ def run_mprime_test(state, test): # Stress CPU print_log('Starting Prime95') test.abort_msg = 'If running too hot, press CTRL+c to abort the test' - run_program(['apple-fans', 'max']) + run_program(['apple-fans', 'max'], check=False) tmux_update_pane( state.panes['Prime95'], command=['hw-diags-prime95', global_vars['TmpDir']], working_dir=global_vars['TmpDir']) - time_limit = int(MPRIME_LIMIT) * 60 - thermal_limit = int(THERMAL_LIMIT) + time_limit = MPRIME_LIMIT * 60 try: for i in range(time_limit): clear_screen() @@ -1383,7 +1337,7 @@ def run_mprime_test(state, test): # Not using print wrappers to avoid flooding the log print(_status_str) print('{YELLOW}{msg}{CLEAR}'.format(msg=test.abort_msg, **COLORS)) - update_sensor_data(test.sensor_data, thermal_limit) + update_sensor_data(test.sensor_data, THERMAL_LIMIT) # Wait sleep(1) @@ -1395,7 +1349,7 @@ def run_mprime_test(state, test): elif isinstance(err, ThermalLimitReachedError): test.failed = True test.thermal_abort = True - test.update_status('NS') + test.update_status('FAIL') update_progress_pane(state) # Restart live monitor @@ -1409,7 +1363,7 @@ def run_mprime_test(state, test): tmux_kill_pane(state.panes.pop('Prime95', None)) # Get cooldown temp - run_program(['apple-fans', 'auto']) + run_program(['apple-fans', 'auto'], check=False) clear_screen() try_and_print( message='Letting CPU cooldown for bit...', indent=0, @@ -1525,15 +1479,19 @@ def run_network_test(): pause('Press Enter to return to main menu... ') -def run_nvme_smart_tests(state, test): - """Run NVMe or SMART test for test.dev.""" +def run_nvme_smart_tests(state, test, update_mode=False): + """Run NVMe or SMART test for test.dev. + + Update mode is used to refresh the attributes and recheck them. + (i.e. no self-test and don't disable other tests)""" + dev = test.dev + # Bail early if test.disabled: return # Prep - print_log('Starting NVMe/SMART test for {}'.format(test.dev.path)) - _include_short_test = False + print_log('Starting NVMe/SMART test for {}'.format(dev.path)) test.started = True test.update_status() update_progress_pane(state) @@ -1542,122 +1500,122 @@ def run_nvme_smart_tests(state, test): tmux_update_pane( state.panes['Top'], text='{}\n{}'.format( - TOP_PANE_TEXT, test.dev.description)) + TOP_PANE_TEXT, dev.description)) - # NVMe - if test.dev.nvme_attributes: - # NOTE: Pass/Fail is just the attribute check - if test.dev.disk_ok: + # SMART short self-test + if dev.smart_attributes and not (state.quick_mode or update_mode): + run_smart_short_test(state, test) + + # Attribute check + dev.check_attributes() + + # Check results + if dev.nvme_attributes or state.quick_mode: + if dev.disk_ok: test.passed = True test.update_status('PASS') else: - # NOTE: Other test(s) should've been disabled by DiskObj.safety_check() test.failed = True test.update_status('FAIL') - - # SMART - elif test.dev.smart_attributes: - # NOTE: Pass/Fail based on both attributes and SMART short self-test - if not (test.dev.disk_ok or 'OVERRIDE' in test.status): + elif dev.smart_attributes: + if dev.disk_ok and dev.self_test_passed: + test.passed = True + test.update_status('PASS') + elif test.aborted: + test.update_status('Aborted') + raise GenericAbort('Aborted') + elif dev.self_test_timed_out: + test.update_status('TimedOut') + elif dev.override_disabled or 'OVERRIDE' not in test.status: + # override_disabled is set to True if one or more critical attributes + # have exceeded the Error threshold. This overrules an override. test.failed = True test.update_status('FAIL') - elif state.quick_mode: - if test.dev.disk_ok: - test.passed = True - test.update_status('PASS') - else: - test.failed = True - test.update_status('FAIL') - else: - # Prep - test.timeout = test.dev.smart_self_test['polling_minutes'].get( - 'short', 5) - test.timeout = int(test.timeout) + 5 - _include_short_test = True - _self_test_started = False - _self_test_finished = False + else: + # This dev lacks both NVMe and SMART data. This test should've been + # disabled during the safety_check(). + pass - # Create monitor pane - test.smart_out = '{}/smart_{}.out'.format( - global_vars['LogDir'], test.dev.name) - with open(test.smart_out, 'w') as f: - f.write('SMART self-test status:\n Starting...') - state.panes['SMART'] = tmux_split_window( - lines=3, vertical=True, watch=test.smart_out) - - # Show attributes - clear_screen() - show_report(test.dev.generate_attribute_report()) - print_standard(' ') - - # Start short test - print_standard('Running self-test...') - cmd = ['sudo', 'smartctl', '--test=short', test.dev.path] - run_program(cmd, check=False) - - # Monitor progress - try: - for i in range(int(test.timeout*60/5)): - sleep(5) - - # Update SMART data - test.dev.get_smart_details() - - if _self_test_started: - # Update progress file - with open(test.smart_out, 'w') as f: - f.write('SMART self-test status:\n {}'.format( - test.dev.smart_self_test['status'].get( - 'string', 'UNKNOWN').capitalize())) - - # Check if test has finished - if 'remaining_percent' not in test.dev.smart_self_test['status']: - _self_test_finished = True - break - - else: - # Check if test has started - if 'remaining_percent' in test.dev.smart_self_test['status']: - _self_test_started = True - - except KeyboardInterrupt: - test.aborted = True - test.report = test.dev.generate_attribute_report() - test.report.append('{BLUE}SMART Short self-test{CLEAR}'.format( - **COLORS)) - test.report.append(' {YELLOW}Aborted{CLEAR}'.format(**COLORS)) - test.update_status('Aborted') - raise GenericAbort('Aborted') - - # Check if timed out - if _self_test_finished: - if test.dev.smart_self_test['status'].get('passed', False): - if 'OVERRIDE' not in test.status: - test.passed = True - test.update_status('PASS') - else: - test.failed = True - test.update_status('FAIL') - else: - test.dev.smart_timeout = True - test.update_status('TimedOut') - - # Disable other drive tests if necessary - if test.failed: - for t in ['badblocks', 'I/O Benchmark']: - test.dev.disable_test(t, 'Denied') - - # Cleanup - tmux_kill_pane(state.panes.pop('SMART', None)) - - # Save report - test.report = test.dev.generate_attribute_report( - short_test=_include_short_test) + # Disable other disk tests if necessary + if test.failed and not update_mode: + for t in ['badblocks', 'I/O Benchmark']: + dev.disable_test(t, 'Denied') # Done update_progress_pane(state) +def run_smart_short_test(state, test): + """Run SMART short self-test for test.dev.""" + dev = test.dev + dev.self_test_started = False + dev.self_test_finished = False + dev.self_test_passed = False + dev.self_test_timed_out = False + test.timeout = dev.smart_self_test['polling_minutes'].get('short', 5) + test.timeout = int(test.timeout) + 5 + + # Create monitor pane + test.smart_out = '{}/smart_{}.out'.format(global_vars['LogDir'], dev.name) + with open(test.smart_out, 'w') as f: + f.write('SMART self-test status:\n Starting...') + state.panes['SMART'] = tmux_split_window( + lines=3, vertical=True, watch=test.smart_out) + + # Show attributes + clear_screen() + show_report(dev.generate_attribute_report()) + print_standard(' ') + + # Start short test + print_standard('Running self-test...') + cmd = ['sudo', 'smartctl', '--test=short', dev.path] + run_program(cmd, check=False) + + # Monitor progress + try: + for i in range(int(test.timeout*60/5)): + sleep(5) + + # Update SMART data + dev.get_smart_details() + + if dev.self_test_started: + # Update progress file + with open(test.smart_out, 'w') as f: + f.write('SMART self-test status:\n {}'.format( + dev.smart_self_test['status'].get( + 'string', 'UNKNOWN').capitalize())) + + # Check if test has finished + if 'remaining_percent' not in dev.smart_self_test['status']: + dev.self_test_finished = True + break + + else: + # Check if test has started + if 'remaining_percent' in dev.smart_self_test['status']: + dev.self_test_started = True + except KeyboardInterrupt: + # Will be handled in run_nvme_smart_tests() + test.aborted = True + + # Save report + test.report.append('{BLUE}SMART Short self-test{CLEAR}'.format(**COLORS)) + test.report.append(' {}'.format( + dev.smart_self_test['status'].get('string', 'UNKNOWN').capitalize())) + if dev.self_test_finished: + dev.self_test_passed = dev.smart_self_test['status'].get('passed', False) + elif test.aborted: + test.report.append(' {YELLOW}Aborted{CLEAR}'.format(**COLORS)) + else: + dev.self_test_timed_out = True + test.report.append(' {YELLOW}Timed out{CLEAR}'.format(**COLORS)) + + # Cleanup + tmux_kill_pane(state.panes.pop('SMART', None)) + + def secret_screensaver(screensaver=None): """Show screensaver.""" if screensaver == 'matrix': diff --git a/.bin/Scripts/functions/info.py b/.bin/Scripts/functions/info.py index ad71bce7..84d92663 100644 --- a/.bin/Scripts/functions/info.py +++ b/.bin/Scripts/functions/info.py @@ -3,57 +3,7 @@ from borrowed import knownpaths from functions.activation import * from operator import itemgetter - - -# STATIC VARIABLES -REG_PROFILE_LIST = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' -REG_SHELL_FOLDERS = r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders' -TMP_HIVE_PATH = 'TEMP_HIVE_MOUNT' -EXTRA_FOLDERS = [ - 'Dropbox', - 'Google Drive', - 'OneDrive', - 'SkyDrive', -] -SHELL_FOLDERS = { - #GUIDs from: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx - 'Desktop': ( - '{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}', - ), - 'Documents': ( - 'Personal', - '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}', - ), - 'Downloads': ( - '{374DE290-123F-4565-9164-39C4925E467B}', - ), - 'Favorites': ( - '{1777F761-68AD-4D8A-87BD-30B759FA33DD}', - ), - 'Music': ( - 'My Music', - '{4BD8D571-6D19-48D3-BE97-422220080E43}', - ), - 'Pictures': ( - 'My Pictures', - '{33E28130-4E1E-4676-835A-98395C3BC3BB}', - ), - 'Videos': ( - 'My Video', - '{18989B1D-99B5-455B-841C-AB7C74E4DDFC}', - ), -} - - -# Regex -REGEX_OFFICE = re.compile( - r'(Microsoft (Office\s+' - r'(365|Enterprise|Home|Pro(\s|fessional)' - r'|Single|Small|Standard|Starter|Ultimate|system)' - r'|Works[-\s\d]+\d)' - r'|(Libre|Open|Star)\s*Office' - r'|WordPerfect|Gnumeric|Abiword)', - re.IGNORECASE) +from settings.info import * def backup_file_list(): diff --git a/.bin/Scripts/functions/json.py b/.bin/Scripts/functions/json.py new file mode 100644 index 00000000..0c8b4170 --- /dev/null +++ b/.bin/Scripts/functions/json.py @@ -0,0 +1,32 @@ +# Wizard Kit: Functions - JSON + +import json + +from functions.common import * + +def get_json_from_command(cmd, ignore_errors=True): + """Capture JSON content from cmd output, returns dict. + + If the data can't be decoded then either an exception is raised + or an empty dict is returned depending on ignore_errors. + """ + errors = 'strict' + json_data = {} + + if ignore_errors: + errors = 'ignore' + + try: + result = run_program(cmd, encoding='utf-8', errors=errors) + json_data = json.loads(result.stdout) + except (subprocess.CalledProcessError, json.decoder.JSONDecodeError): + if not ignore_errors: + raise + + return json_data + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/functions/sensors.py b/.bin/Scripts/functions/sensors.py index e2676fca..8525deb8 100644 --- a/.bin/Scripts/functions/sensors.py +++ b/.bin/Scripts/functions/sensors.py @@ -4,19 +4,7 @@ import json import re from functions.tmux import * - - -# STATIC VARIABLES -TEMP_LIMITS = { - 'GREEN': 60, - 'YELLOW': 70, - 'ORANGE': 80, - 'RED': 90, - } - - -# REGEX -REGEX_COLORS = re.compile(r'\033\[\d+;?1?m') +from settings.sensors import * # Error Classes @@ -117,7 +105,7 @@ def get_raw_sensor_data(): # Get raw data try: result = run_program(cmd) - result = result.stdout.decode().splitlines() + result = result.stdout.decode('utf-8', errors='ignore').splitlines() except subprocess.CalledProcessError: # Assuming no sensors available, set to empty list result = [] diff --git a/.bin/Scripts/functions/setup.py b/.bin/Scripts/functions/setup.py index a54b1965..c7a8c6f7 100644 --- a/.bin/Scripts/functions/setup.py +++ b/.bin/Scripts/functions/setup.py @@ -1,174 +1,10 @@ # Wizard Kit: Functions - Setup from functions.update import * +from settings.setup import * from settings.sources import * -# STATIC VARIABLES -HKU = winreg.HKEY_USERS -HKCR = winreg.HKEY_CLASSES_ROOT -HKCU = winreg.HKEY_CURRENT_USER -HKLM = winreg.HKEY_LOCAL_MACHINE -MOZILLA_FIREFOX_UBO_PATH = r'{}\{}\ublock_origin.xpi'.format( - os.environ.get('PROGRAMFILES'), - r'Mozilla Firefox\distribution\extensions') -OTHER_RESULTS = { - 'Error': { - 'CalledProcessError': 'Unknown Error', - 'FileNotFoundError': 'File not found', - }, - 'Warning': {}} -SETTINGS_CLASSIC_START = { - r'Software\IvoSoft\ClassicShell\Settings': {}, - r'Software\IvoSoft\ClassicStartMenu': { - 'DWORD Items': {'ShowedStyle2': 1}, - }, - r'Software\IvoSoft\ClassicStartMenu\MRU': {}, - r'Software\IvoSoft\ClassicStartMenu\Settings': { - 'DWORD Items': {'SkipMetro': 1}, - 'SZ Items': { - 'MenuStyle': 'Win7', - 'RecentPrograms': 'Recent', - }, - }, - } -SETTINGS_ESET = { - r'Software\ESET\ESET Security\CurrentVersion\gui\UI_CONFIG': { - 'DWORD Items': { - 'FullScreenMode': 0, - 'ShowDesktopAlert': 0, - 'ShowSplash': 0, - }, - }, - } -SETTINGS_EXPLORER_SYSTEM = { - # Disable edge swipe - r'Software\Policies\Microsoft\Windows\EdgeUI': { - 'DWORD Items': {'AllowEdgeSwipe': 0}, - }, - # Disable Location Tracking - r'Software\Microsoft\Windows NT\CurrentVersion\Sensor\Overrides\{BFA794E4-F964-4FDB-90F6-51056BFE4B44}': { - 'DWORD Items': {'SensorPermissionState': 0}, - }, - r'System\CurrentControlSet\Services\lfsvc\Service\Configuration': { - 'Status': {'Value': 0}, - }, - # Disable Telemetry - r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': { - 'DWORD Items': {'AllowTelemetry': 0}, - }, - r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': { - 'DWORD Items': {'AllowTelemetry': 0}, - 'WOW64_32': True, - }, - r'Software\Policies\Microsoft\Windows\DataCollection': { - 'DWORD Items': {'AllowTelemetry': 0}, - }, - # Disable Wi-Fi Sense - r'Software\Microsoft\PolicyManager\default\WiFi\AllowWiFiHotSpotReporting': { - 'DWORD Items': {'Value': 0}, - }, - r'Software\Microsoft\PolicyManager\default\WiFi\AllowAutoConnectToWiFiSenseHotspots': { - 'DWORD Items': {'Value': 0}, - }, - } -SETTINGS_EXPLORER_USER = { - # Add This PC to Desktop - r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu': { - 'DWORD Items': {'{20D04FE0-3AEA-1069-A2D8-08002B30309D}': 0}, - }, - r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel': { - 'DWORD Items': {'{20D04FE0-3AEA-1069-A2D8-08002B30309D}': 0}, - }, - # Add Users Files to Desktop - r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu': { - 'DWORD Items': {'{59031a47-3f72-44a7-89c5-5595fe6b30ee}': 0}, - }, - r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel': { - 'DWORD Items': {'{59031a47-3f72-44a7-89c5-5595fe6b30ee}': 0}, - }, - # Explorer - r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced': { - 'DWORD Items': { - # Change default Explorer view to "Computer" - 'LaunchTo': 1, - # Launch Folder Windows in a Separate Process - 'SeparateProcess': 1, - }, - }, - r'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager': { - 'DWORD Items': { - # Disable silently installed apps - 'SilentInstalledAppsEnabled': 0, - # Disable Tips and Tricks - 'SoftLandingEnabled ': 0, - 'SubscribedContent-338389Enabled': 0, - }, - }, - # Hide People bar - r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People': { - 'DWORD Items': {'PeopleBand': 0}, - }, - # Hide Search button / box - r'Software\Microsoft\Windows\CurrentVersion\Search': { - 'DWORD Items': {'SearchboxTaskbarMode': 1}, - }, - } -SETTINGS_GOOGLE_CHROME = { - r'Software\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm': { - 'SZ Items': { - 'update_url': 'https://clients2.google.com/service/update2/crx'}, - 'WOW64_32': True, - }, - r'Software\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco': { - 'SZ Items': { - 'update_url': 'https://clients2.google.com/service/update2/crx'}, - 'WOW64_32': True, - }, - } -SETTINGS_MOZILLA_FIREFOX_32 = { - r'Software\Mozilla\Firefox\Extensions': { - 'SZ Items': { - 'uBlock0@raymondhill.net': MOZILLA_FIREFOX_UBO_PATH}, - 'WOW64_32': True, - }, - } -SETTINGS_MOZILLA_FIREFOX_64 = { - r'Software\Mozilla\Firefox\Extensions': { - 'SZ Items': { - 'uBlock0@raymondhill.net': MOZILLA_FIREFOX_UBO_PATH}, - }, - } -SETTINGS_REGBACK = { - # Enable RegBack - r'System\CurrentControlSet\Control\Session Manager\Configuration Manager': { - 'DWORD Items': {'EnablePeriodicBackup': 1}, - }, - } -VCR_REDISTS = [ - {'Name': 'Visual C++ 2010 x32...', - 'Cmd': [r'2010sp1\x32\vcredist.exe', '/passive', '/norestart']}, - {'Name': 'Visual C++ 2010 x64...', - 'Cmd': [r'2010sp1\x64\vcredist.exe', '/passive', '/norestart']}, - {'Name': 'Visual C++ 2012 Update 4 x32...', - 'Cmd': [r'2012u4\x32\vcredist.exe', '/passive', '/norestart']}, - {'Name': 'Visual C++ 2012 Update 4 x64...', - 'Cmd': [r'2012u4\x64\vcredist.exe', '/passive', '/norestart']}, - {'Name': 'Visual C++ 2013 x32...', - 'Cmd': [r'2013\x32\vcredist.exe', '/install', - '/passive', '/norestart']}, - {'Name': 'Visual C++ 2013 x64...', - 'Cmd': [r'2013\x64\vcredist.exe', '/install', - '/passive', '/norestart']}, - {'Name': 'Visual C++ 2017 x32...', - 'Cmd': [r'2017\x32\vcredist.exe', '/install', - '/passive', '/norestart']}, - {'Name': 'Visual C++ 2017 x64...', - 'Cmd': [r'2017\x64\vcredist.exe', '/install', - '/passive', '/norestart']}, - ] - - def config_classicstart(): """Configure ClassicStart.""" # User level, not system level diff --git a/.bin/Scripts/functions/sw_diags.py b/.bin/Scripts/functions/sw_diags.py index 100e5ad5..1b965766 100644 --- a/.bin/Scripts/functions/sw_diags.py +++ b/.bin/Scripts/functions/sw_diags.py @@ -1,31 +1,9 @@ -# Wizard Kit: Functions - Diagnostics +# Wizard Kit: Functions - SW Diagnostics import ctypes from functions.common import * - - -# STATIC VARIABLES -AUTORUNS_SETTINGS = { - r'Software\Sysinternals\AutoRuns': { - 'checkvirustotal': 1, - 'EulaAccepted': 1, - 'shownomicrosoft': 1, - 'shownowindows': 1, - 'showonlyvirustotal': 1, - 'submitvirustotal': 0, - 'verifysignatures': 1, - }, - r'Software\Sysinternals\AutoRuns\SigCheck': { - 'EulaAccepted': 1, - }, - r'Software\Sysinternals\AutoRuns\Streams': { - 'EulaAccepted': 1, - }, - r'Software\Sysinternals\AutoRuns\VirusTotal': { - 'VirusTotalTermsAccepted': 1, - }, - } +from settings.sw_diags import * def check_connection(): diff --git a/.bin/Scripts/functions/windows_setup.py b/.bin/Scripts/functions/windows_setup.py index e790a4b6..eabaac40 100644 --- a/.bin/Scripts/functions/windows_setup.py +++ b/.bin/Scripts/functions/windows_setup.py @@ -2,39 +2,7 @@ from functions.data import * from functions.disk import * - - -# STATIC VARIABLES -WINDOWS_VERSIONS = [ - {'Name': 'Windows 7 Home Basic', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 HOMEBASIC'}, - {'Name': 'Windows 7 Home Premium', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 HOMEPREMIUM'}, - {'Name': 'Windows 7 Professional', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 PROFESSIONAL'}, - {'Name': 'Windows 7 Ultimate', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 ULTIMATE'}, - - {'Name': 'Windows 8.1', - 'Image File': 'Win8', - 'Image Name': 'Windows 8.1', - 'CRLF': True}, - {'Name': 'Windows 8.1 Pro', - 'Image File': 'Win8', - 'Image Name': 'Windows 8.1 Pro'}, - - {'Name': 'Windows 10 Home', - 'Image File': 'Win10', - 'Image Name': 'Windows 10 Home', - 'CRLF': True}, - {'Name': 'Windows 10 Pro', - 'Image File': 'Win10', - 'Image Name': 'Windows 10 Pro'}, - ] +from settings.windows_setup import * def find_windows_image(windows_version): diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index 22df7449..08622e4e 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -3,53 +3,7 @@ from functions.backup import * from functions.disk import * from functions.windows_setup import * - - -# STATIC VARIABLES -FAST_COPY_PE_ARGS = [ - '/cmd=noexist_only', - '/utf8', - '/skip_empty_dir', - '/linkdest', - '/no_ui', - '/auto_close', - '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), - ] -PE_TOOLS = { - 'BlueScreenView': { - 'Path': r'BlueScreenView\BlueScreenView.exe', - }, - 'FastCopy': { - 'Path': r'FastCopy\FastCopy.exe', - 'Args': FAST_COPY_PE_ARGS, - }, - 'HWiNFO': { - 'Path': r'HWiNFO\HWiNFO.exe', - }, - 'NT Password Editor': { - 'Path': r'NT Password Editor\ntpwedit.exe', - }, - 'Notepad++': { - 'Path': r'NotepadPlusPlus\NotepadPlusPlus.exe', - }, - 'PhotoRec': { - 'Path': r'TestDisk\photorec_win.exe', - 'Args': ['-new_console:n'], - }, - 'Prime95': { - 'Path': r'Prime95\prime95.exe', - }, - 'ProduKey': { - 'Path': r'ProduKey\ProduKey.exe', - }, - 'Q-Dir': { - 'Path': r'Q-Dir\Q-Dir.exe', - }, - 'TestDisk': { - 'Path': r'TestDisk\testdisk_win.exe', - 'Args': ['-new_console:n'], - }, - } +from settings.winpe import * def check_pe_tools(): diff --git a/.bin/Scripts/hw-diags-menu b/.bin/Scripts/hw-diags-menu index 1c3cfc42..fa7f0cd8 100755 --- a/.bin/Scripts/hw-diags-menu +++ b/.bin/Scripts/hw-diags-menu @@ -26,8 +26,37 @@ if __name__ == '__main__': # Normal exit pass except: + # Cleanup tmux_kill_all_panes() - major_exception() + + if DEBUG_MODE: + # Custom major exception + print_standard(' ') + print_error('Major exception') + print_warning(SUPPORT_MESSAGE) + print(traceback.format_exc()) + print_log(traceback.format_exc()) + + # Save debug reports and upload data + try_and_print( + message='Saving debug reports...', + function=save_debug_reports, + state=state, global_vars=global_vars) + question = 'Upload crash details to {}?'.format(CRASH_SERVER['Name']) + if ENABLED_UPLOAD_DATA and ask(question): + try_and_print( + message='Uploading Data...', + function=upload_logdir, + global_vars=global_vars) + + # Done + sleep(10) + pause('Press Enter to exit...') + exit_script(1) + + else: + # "Normal" major exception + major_exception() # Done tmux_kill_all_panes() diff --git a/.bin/Scripts/settings/browsers.py b/.bin/Scripts/settings/browsers.py new file mode 100644 index 00000000..1c4e3188 --- /dev/null +++ b/.bin/Scripts/settings/browsers.py @@ -0,0 +1,98 @@ +# Wizard Kit: Settings - Browsers + +import re + +# General +DEFAULT_HOMEPAGE = 'https://www.google.com/' +IE_GALLERY = 'https://www.microsoft.com/en-us/iegallery' +MOZILLA_PREFS = { + 'browser.search.defaultenginename': '"Google"', + 'browser.search.defaultenginename.US': '"Google"', + 'browser.search.geoSpecificDefaults': 'false', + 'browser.startup.homepage': '"{}"'.format(DEFAULT_HOMEPAGE), + 'extensions.ui.lastCategory': '"addons://list/extension"', + } +SUPPORTED_BROWSERS = { + 'Internet Explorer': { + 'base': 'ie', + 'exe_name': 'iexplore.exe', + 'rel_install_path': 'Internet Explorer', + 'user_data_path': r'{USERPROFILE}\Favorites', + }, + 'Google Chrome': { + 'base': 'chromium', + 'exe_name': 'chrome.exe', + 'rel_install_path': r'Google\Chrome\Application', + 'user_data_path': r'{LOCALAPPDATA}\Google\Chrome\User Data', + }, + 'Google Chrome Canary': { + 'base': 'chromium', + 'exe_name': 'chrome.exe', + 'rel_install_path': r'Google\Chrome SxS\Application', + 'user_data_path': r'{LOCALAPPDATA}\Google\Chrome SxS\User Data', + }, + 'Mozilla Firefox': { + 'base': 'mozilla', + 'exe_name': 'firefox.exe', + 'rel_install_path': 'Mozilla Firefox', + 'user_data_path': r'{APPDATA}\Mozilla\Firefox\Profiles', + }, + 'Mozilla Firefox Dev': { + 'base': 'mozilla', + 'exe_name': 'firefox.exe', + 'rel_install_path': 'Firefox Developer Edition', + 'user_data_path': r'{APPDATA}\Mozilla\Firefox\Profiles', + }, + 'Opera': { + 'base': 'chromium', + 'exe_name': 'launcher.exe', + 'rel_install_path': 'Opera', + 'user_data_path': r'{APPDATA}\Opera Software\Opera Stable', + }, + 'Opera Beta': { + 'base': 'chromium', + 'exe_name': 'launcher.exe', + 'rel_install_path': 'Opera beta', + 'user_data_path': r'{APPDATA}\Opera Software\Opera Next', + }, + 'Opera Dev': { + 'base': 'chromium', + 'exe_name': 'launcher.exe', + 'rel_install_path': 'Opera developer', + 'user_data_path': r'{APPDATA}\Opera Software\Opera Developer', + }, + } + +# Regex +REGEX_BACKUP = re.compile( + r'\.\w*bak.*', + re.IGNORECASE) +REGEX_CHROMIUM_PROFILE = re.compile( + r'^(Default|Profile)', + re.IGNORECASE) +REGEX_CHROMIUM_ITEMS = re.compile( + r'^(Bookmarks|Cookies|Favicons|Google Profile' + r'|History|Login Data|Top Sites|TransportSecurity' + r'|Visited Links|Web Data)', + re.IGNORECASE) +REGEX_MOZILLA = re.compile( + r'^(bookmarkbackups|(cookies|formhistory|places).sqlite' + r'|key3.db|logins.json|persdict.dat)$', + re.IGNORECASE) + +# uBlock Origin +UBO_CHROME = 'https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en' +UBO_CHROME_REG = r'Software\Wow6432Node\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm' +UBO_EXTRA_CHROME = 'https://chrome.google.com/webstore/detail/ublock-origin-extra/pgdnlhfefecpicbbihgmbmffkjpaplco?hl=en' +UBO_EXTRA_CHROME_REG = r'Software\Wow6432Node\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco' +UBO_MOZILLA = 'https://addons.mozilla.org/en-us/firefox/addon/ublock-origin/' +UBO_MOZZILA_PATH = r'{}\Mozilla Firefox\distribution\extensions\ublock_origin.xpi'.format(os.environ.get('PROGRAMFILES')) +UBO_MOZILLA_REG = r'Software\Mozilla\Firefox\Extensions' +UBO_MOZILLA_REG_NAME = 'uBlock0@raymondhill.net' +UBO_OPERA = 'https://addons.opera.com/en/extensions/details/ublock/?display=en' + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 tw=0 diff --git a/.bin/Scripts/settings/data.py b/.bin/Scripts/settings/data.py new file mode 100644 index 00000000..38602994 --- /dev/null +++ b/.bin/Scripts/settings/data.py @@ -0,0 +1,103 @@ +# Wizard Kit: Settings - Data + +import ctypes +import re + +# FastCopy +FAST_COPY_EXCLUDES = [ + r'\*.esd', + r'\*.swm', + r'\*.wim', + r'\*.dd', + r'\*.dd.tgz', + r'\*.dd.txz', + r'\*.map', + r'\*.dmg', + r'\*.image', + r'$RECYCLE.BIN', + r'$Recycle.Bin', + r'.AppleDB', + r'.AppleDesktop', + r'.AppleDouble', + r'.com.apple.timemachine.supported', + r'.dbfseventsd', + r'.DocumentRevisions-V100*', + r'.DS_Store', + r'.fseventsd', + r'.PKInstallSandboxManager', + r'.Spotlight*', + r'.SymAV*', + r'.symSchedScanLockxz', + r'.TemporaryItems', + r'.Trash*', + r'.vol', + r'.VolumeIcon.icns', + r'desktop.ini', + r'Desktop?DB', + r'Desktop?DF', + r'hiberfil.sys', + r'lost+found', + r'Network?Trash?Folder', + r'pagefile.sys', + r'Recycled', + r'RECYCLER', + r'System?Volume?Information', + r'Temporary?Items', + r'Thumbs.db', + ] +FAST_COPY_ARGS = [ + '/cmd=noexist_only', + '/utf8', + '/skip_empty_dir', + '/linkdest', + '/no_ui', + '/auto_close', + '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), + ] + +# Regex +REGEX_EXCL_ITEMS = re.compile( + r'^(\.(AppleDB|AppleDesktop|AppleDouble' + r'|com\.apple\.timemachine\.supported|dbfseventsd' + r'|DocumentRevisions-V100.*|DS_Store|fseventsd|PKInstallSandboxManager' + r'|Spotlight.*|SymAV.*|symSchedScanLockxz|TemporaryItems|Trash.*' + r'|vol|VolumeIcon\.icns)|desktop\.(ini|.*DB|.*DF)' + r'|(hiberfil|pagefile)\.sys|lost\+found|Network\.*Trash\.*Folder' + r'|Recycle[dr]|System\.*Volume\.*Information|Temporary\.*Items' + r'|Thumbs\.db)$', + re.IGNORECASE) +REGEX_EXCL_ROOT_ITEMS = re.compile( + r'^(boot(mgr|nxt)$|Config.msi' + r'|(eula|globdata|install|vc_?red)' + r'|.*.sys$|System Volume Information|RECYCLER?|\$Recycle\.bin' + r'|\$?Win(dows(.old.*|\. BT|)$|RE_)|\$GetCurrent|Windows10Upgrade' + r'|PerfLogs|Program Files|SYSTEM.SAV' + r'|.*\.(esd|swm|wim|dd|map|dmg|image)$)', + re.IGNORECASE) +REGEX_INCL_ROOT_ITEMS = re.compile( + r'^(AdwCleaner|(My\s*|)(Doc(uments?( and Settings|)|s?)|Downloads' + r'|Media|Music|Pic(ture|)s?|Vid(eo|)s?)' + r'|{prefix}(-?Info|-?Transfer|)' + r'|(ProgramData|Recovery|Temp.*|Users)$' + r'|.*\.(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)' + r''.format(prefix=KIT_NAME_SHORT), + re.IGNORECASE) +REGEX_WIM_FILE = re.compile( + r'\.wim$', + re.IGNORECASE) +REGEX_WINDOWS_OLD = re.compile( + r'^Win(dows|)\.old', + re.IGNORECASE) + +# Thread error modes +## Code borrowed from: https://stackoverflow.com/a/29075319 +SEM_NORMAL = ctypes.c_uint() +SEM_FAILCRITICALERRORS = 1 +SEM_NOOPENFILEERRORBOX = 0x8000 +SEM_FAIL = SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/settings/ddrescue.py b/.bin/Scripts/settings/ddrescue.py new file mode 100644 index 00000000..620b7214 --- /dev/null +++ b/.bin/Scripts/settings/ddrescue.py @@ -0,0 +1,39 @@ +# Wizard Kit: Settings - ddrescue-tui + +# General +RECOMMENDED_FSTYPES = ['ext3', 'ext4', 'xfs'] +USAGE = """ {script_name} clone [source [destination]] + {script_name} image [source [destination]] + (e.g. {script_name} clone /dev/sda /dev/sdb) +""" + +# Layout +SIDE_PANE_WIDTH = 21 +TMUX_LAYOUT = OrderedDict({ + 'Source': {'y': 2, 'Check': True}, + 'Started': {'x': SIDE_PANE_WIDTH, 'Check': True}, + 'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True}, +}) + +# ddrescue +AUTO_PASS_1_THRESHOLD = 95 +AUTO_PASS_2_THRESHOLD = 98 +DDRESCUE_SETTINGS = { + '--binary-prefixes': {'Enabled': True, 'Hidden': True, }, + '--data-preview': {'Enabled': True, 'Value': '5', 'Hidden': True, }, + '--idirect': {'Enabled': True, }, + '--odirect': {'Enabled': True, }, + '--max-read-rate': {'Enabled': False, 'Value': '1MiB', }, + '--min-read-rate': {'Enabled': True, 'Value': '64KiB', }, + '--reopen-on-error': {'Enabled': True, }, + '--retry-passes': {'Enabled': True, 'Value': '0', }, + '--test-mode': {'Enabled': False, 'Value': 'test.map', }, + '--timeout': {'Enabled': True, 'Value': '5m', }, + '-vvvv': {'Enabled': True, 'Hidden': True, }, + } + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/settings/hw_diags.py b/.bin/Scripts/settings/hw_diags.py new file mode 100644 index 00000000..9f0e1391 --- /dev/null +++ b/.bin/Scripts/settings/hw_diags.py @@ -0,0 +1,112 @@ +# Wizard Kit: Settings - HW Diagnostics + +from collections import OrderedDict + +# General +DEBUG_MODE = True +OVERRIDES_FORCED = False +OVERRIDES_LIMITED = True # If True this disables OVERRIDE_FORCED +STATUSES = { + 'RED': ['Denied', 'ERROR', 'FAIL', 'TimedOut'], + 'YELLOW': ['Aborted', 'N/A', 'OVERRIDE', 'Unknown', 'Working'], + 'GREEN': ['PASS'], +} +TESTS_CPU = ['Prime95'] +TESTS_DISK = [ + 'I/O Benchmark', + 'NVMe / SMART', + 'badblocks', + ] + +# Layout +## NOTE: Colors will be applied in functions/hw_diags.py +QUICK_LABEL = '{YELLOW}(Quick){CLEAR}' +SIDE_PANE_WIDTH = 20 +TOP_PANE_TEXT = '{GREEN}Hardware Diagnostics{CLEAR}' +TMUX_LAYOUT = OrderedDict({ + 'Top': {'y': 2, 'Check': True}, + 'Started': {'x': SIDE_PANE_WIDTH, 'Check': True}, + 'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True}, + # Testing panes + 'Prime95': {'y': 11, 'Check': False}, + 'Temps': {'y': 1000, 'Check': False}, + 'SMART': {'y': 3, 'Check': True}, + 'badblocks': {'y': 5, 'Check': True}, + 'I/O Benchmark': {'y': 1000, 'Check': False}, +}) + +# Tests: badblocks +## NOTE: Force 4K read block size for disks >= to 3TB +BADBLOCKS_LARGE_DISK = 3*1024**4 + +# Tests: I/O Benchmark +IO_VARS = { + 'Block Size': 512*1024, + 'Chunk Size': 32*1024**2, + 'Minimum Test Size': 10*1024**3, + 'Alt Test Size Factor': 0.01, + 'Progress Refresh Rate': 5, + 'Scale 8': [2**(0.56*(x+1))+(16*(x+1)) for x in range(8)], + 'Scale 16': [2**(0.56*(x+1))+(16*(x+1)) for x in range(16)], + 'Scale 32': [2**(0.56*(x+1)/2)+(16*(x+1)/2) for x in range(32)], + 'Threshold Graph Fail': 65*1024**2, + 'Threshold Graph Warn': 135*1024**2, + 'Threshold Graph Great': 750*1024**2, + 'Threshold HDD Min': 50*1024**2, + 'Threshold HDD High Avg': 75*1024**2, + 'Threshold HDD Low Avg': 65*1024**2, + 'Threshold SSD Min': 90*1024**2, + 'Threshold SSD High Avg': 135*1024**2, + 'Threshold SSD Low Avg': 100*1024**2, + 'Graph Horizontal': ('▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'), + 'Graph Horizontal Width': 40, + 'Graph Vertical': ( + '▏', '▎', '▍', '▌', + '▋', '▊', '▉', '█', + '█▏', '█▎', '█▍', '█▌', + '█▋', '█▊', '█▉', '██', + '██▏', '██▎', '██▍', '██▌', + '██▋', '██▊', '██▉', '███', + '███▏', '███▎', '███▍', '███▌', + '███▋', '███▊', '███▉', '████'), + } + +# Tests: NVMe/SMART +ATTRIBUTES = { + 'NVMe': { + 'critical_warning': {'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, }, + 'media_errors': {'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, }, + 'power_on_hours': {'Critical': False, 'Ignore': True, 'Warning': 17532, 'Error': 26298, 'Maximum': None, }, + 'unsafe_shutdowns': {'Critical': False, 'Ignore': True, 'Warning': 1, 'Error': None, 'Maximum': None, }, + }, + 'SMART': { + 5: {'Hex': '05', 'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, }, + 9: {'Hex': '09', 'Critical': False, 'Ignore': True, 'Warning': 17532, 'Error': 26298, 'Maximum': None, }, + 10: {'Hex': '10', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, }, + 184: {'Hex': 'B8', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, }, + 187: {'Hex': 'BB', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, }, + 188: {'Hex': 'BC', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, }, + 196: {'Hex': 'C4', 'Critical': False, 'Ignore': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, }, + 197: {'Hex': 'C5', 'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, }, + 198: {'Hex': 'C6', 'Critical': True, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': None, }, + 199: {'Hex': 'C7', 'Critical': False, 'Ignore': True, 'Warning': None, 'Error': 1, 'Maximum': None, }, + 201: {'Hex': 'C9', 'Critical': False, 'Ignore': False, 'Warning': None, 'Error': 1, 'Maximum': 10000, }, + }, + } +ATTRIBUTE_COLORS = ( + ('Error', 'RED'), + ('Maximum', 'PURPLE'), + ('Warning', 'YELLOW'), + ) +KEY_NVME = 'nvme_smart_health_information_log' +KEY_SMART = 'ata_smart_attributes' + +# Tests: Prime95 +MPRIME_LIMIT = 7 # of minutes to run Prime95 +THERMAL_LIMIT = 99 # Abort temperature in Celsius + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 tw=0 diff --git a/.bin/Scripts/settings/info.py b/.bin/Scripts/settings/info.py new file mode 100644 index 00000000..bb1f1421 --- /dev/null +++ b/.bin/Scripts/settings/info.py @@ -0,0 +1,58 @@ +# Wizard Kit: Settings - Information + +import re + +# General +REG_PROFILE_LIST = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' +REG_SHELL_FOLDERS = r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders' +TMP_HIVE_PATH = 'TEMP_HIVE_MOUNT' +EXTRA_FOLDERS = [ + 'Dropbox', + 'Google Drive', + 'OneDrive', + 'SkyDrive', +] +SHELL_FOLDERS = { + #GUIDs from: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx + 'Desktop': ( + '{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}', + ), + 'Documents': ( + 'Personal', + '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}', + ), + 'Downloads': ( + '{374DE290-123F-4565-9164-39C4925E467B}', + ), + 'Favorites': ( + '{1777F761-68AD-4D8A-87BD-30B759FA33DD}', + ), + 'Music': ( + 'My Music', + '{4BD8D571-6D19-48D3-BE97-422220080E43}', + ), + 'Pictures': ( + 'My Pictures', + '{33E28130-4E1E-4676-835A-98395C3BC3BB}', + ), + 'Videos': ( + 'My Video', + '{18989B1D-99B5-455B-841C-AB7C74E4DDFC}', + ), +} + +# Regex +REGEX_OFFICE = re.compile( + r'(Microsoft (Office\s+' + r'(365|Enterprise|Home|Pro(\s|fessional)' + r'|Single|Small|Standard|Starter|Ultimate|system)' + r'|Works[-\s\d]+\d)' + r'|(Libre|Open|Star)\s*Office' + r'|WordPerfect|Gnumeric|Abiword)', + re.IGNORECASE) + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/settings/launchers.py b/.bin/Scripts/settings/launchers.py index 5272b64d..0360aac1 100644 --- a/.bin/Scripts/settings/launchers.py +++ b/.bin/Scripts/settings/launchers.py @@ -737,6 +737,7 @@ LAUNCHERS = { }, } + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/settings/main.py b/.bin/Scripts/settings/main.py index 22e90a3e..c104a45f 100644 --- a/.bin/Scripts/settings/main.py +++ b/.bin/Scripts/settings/main.py @@ -4,8 +4,6 @@ ENABLED_OPEN_LOGS = False ENABLED_TICKET_NUMBERS = False ENABLED_UPLOAD_DATA = True -HW_OVERRIDES_FORCED = False -HW_OVERRIDES_LIMITED = True # If True this disables HW_OVERRIDE_FORCED # STATIC VARIABLES (also used by BASH and BATCH files) ## NOTE: There are no spaces around the = for easier parsing in BASH and BATCH @@ -17,8 +15,6 @@ SUPPORT_MESSAGE='Please let support know by opening an issue on Gogs' # imgur IMGUR_CLIENT_ID='3d1ee1d38707b85' # Live Linux -MPRIME_LIMIT='7' # of minutes to run Prime95 during hw-diags -THERMAL_LIMIT='99' # Prime95 abort temperature in Celsius ROOT_PASSWORD='1201 loves computers!' TECH_PASSWORD='Sorted1201' # Root Certificate Authority @@ -92,6 +88,7 @@ WINDOWS_SERVER = { 'RW-Pass': '1201 loves computers!', } + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/settings/music.py b/.bin/Scripts/settings/music.py index 37f5d178..63163a40 100644 --- a/.bin/Scripts/settings/music.py +++ b/.bin/Scripts/settings/music.py @@ -66,6 +66,7 @@ MUSIC_SNES = [ 'zamn' ] + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/settings/partition_uids.py b/.bin/Scripts/settings/partition_uids.py index f4b21df0..29817b2c 100644 --- a/.bin/Scripts/settings/partition_uids.py +++ b/.bin/Scripts/settings/partition_uids.py @@ -319,6 +319,7 @@ PARTITION_UIDS = { 'BC13C2FF-59E6-4262-A352-B275FD6F7172': {'OS': 'Freedesktop', 'Description': 'Extended Boot Partition ($BOOT)'}, } + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/settings/sensors.py b/.bin/Scripts/settings/sensors.py new file mode 100644 index 00000000..cdfdf708 --- /dev/null +++ b/.bin/Scripts/settings/sensors.py @@ -0,0 +1,21 @@ +# Wizard Kit: Settings - Sensors + +import re + +# General +TEMP_LIMITS = { + 'GREEN': 60, + 'YELLOW': 70, + 'ORANGE': 80, + 'RED': 90, + } + + +# Regex +REGEX_COLORS = re.compile(r'\033\[\d+;?1?m') + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/settings/setup.py b/.bin/Scripts/settings/setup.py new file mode 100644 index 00000000..969d126d --- /dev/null +++ b/.bin/Scripts/settings/setup.py @@ -0,0 +1,184 @@ +# Wizard Kit: Settings - Setup + +# General +HKU = winreg.HKEY_USERS +HKCR = winreg.HKEY_CLASSES_ROOT +HKCU = winreg.HKEY_CURRENT_USER +HKLM = winreg.HKEY_LOCAL_MACHINE +OTHER_RESULTS = { + 'Error': { + 'CalledProcessError': 'Unknown Error', + 'FileNotFoundError': 'File not found', + }, + 'Warning': {}, + } + +# Browsers +MOZILLA_FIREFOX_UBO_PATH = r'{}\{}\ublock_origin.xpi'.format( + os.environ.get('PROGRAMFILES'), + r'Mozilla Firefox\distribution\extensions') +SETTINGS_GOOGLE_CHROME = { + r'Software\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm': { + 'SZ Items': { + 'update_url': 'https://clients2.google.com/service/update2/crx'}, + 'WOW64_32': True, + }, + r'Software\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco': { + 'SZ Items': { + 'update_url': 'https://clients2.google.com/service/update2/crx'}, + 'WOW64_32': True, + }, + } +SETTINGS_MOZILLA_FIREFOX_32 = { + r'Software\Mozilla\Firefox\Extensions': { + 'SZ Items': { + 'uBlock0@raymondhill.net': MOZILLA_FIREFOX_UBO_PATH}, + 'WOW64_32': True, + }, + } +SETTINGS_MOZILLA_FIREFOX_64 = { + r'Software\Mozilla\Firefox\Extensions': { + 'SZ Items': { + 'uBlock0@raymondhill.net': MOZILLA_FIREFOX_UBO_PATH}, + }, + } + +# Classic Start +SETTINGS_CLASSIC_START = { + r'Software\IvoSoft\ClassicShell\Settings': {}, + r'Software\IvoSoft\ClassicStartMenu': { + 'DWORD Items': {'ShowedStyle2': 1}, + }, + r'Software\IvoSoft\ClassicStartMenu\MRU': {}, + r'Software\IvoSoft\ClassicStartMenu\Settings': { + 'DWORD Items': {'SkipMetro': 1}, + 'SZ Items': { + 'MenuStyle': 'Win7', + 'RecentPrograms': 'Recent', + }, + }, + } + +# ESET +SETTINGS_ESET = { + r'Software\ESET\ESET Security\CurrentVersion\gui\UI_CONFIG': { + 'DWORD Items': { + 'FullScreenMode': 0, + 'ShowDesktopAlert': 0, + 'ShowSplash': 0, + }, + }, + } + +# Explorer +SETTINGS_EXPLORER_SYSTEM = { + # Disable edge swipe + r'Software\Policies\Microsoft\Windows\EdgeUI': { + 'DWORD Items': {'AllowEdgeSwipe': 0}, + }, + # Disable Location Tracking + r'Software\Microsoft\Windows NT\CurrentVersion\Sensor\Overrides\{BFA794E4-F964-4FDB-90F6-51056BFE4B44}': { + 'DWORD Items': {'SensorPermissionState': 0}, + }, + r'System\CurrentControlSet\Services\lfsvc\Service\Configuration': { + 'Status': {'Value': 0}, + }, + # Disable Telemetry + r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': { + 'DWORD Items': {'AllowTelemetry': 0}, + }, + r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': { + 'DWORD Items': {'AllowTelemetry': 0}, + 'WOW64_32': True, + }, + r'Software\Policies\Microsoft\Windows\DataCollection': { + 'DWORD Items': {'AllowTelemetry': 0}, + }, + # Disable Wi-Fi Sense + r'Software\Microsoft\PolicyManager\default\WiFi\AllowWiFiHotSpotReporting': { + 'DWORD Items': {'Value': 0}, + }, + r'Software\Microsoft\PolicyManager\default\WiFi\AllowAutoConnectToWiFiSenseHotspots': { + 'DWORD Items': {'Value': 0}, + }, + } +SETTINGS_EXPLORER_USER = { + # Add This PC to Desktop + r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu': { + 'DWORD Items': {'{20D04FE0-3AEA-1069-A2D8-08002B30309D}': 0}, + }, + r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel': { + 'DWORD Items': {'{20D04FE0-3AEA-1069-A2D8-08002B30309D}': 0}, + }, + # Add Users Files to Desktop + r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu': { + 'DWORD Items': {'{59031a47-3f72-44a7-89c5-5595fe6b30ee}': 0}, + }, + r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel': { + 'DWORD Items': {'{59031a47-3f72-44a7-89c5-5595fe6b30ee}': 0}, + }, + # Explorer + r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced': { + 'DWORD Items': { + # Change default Explorer view to "Computer" + 'LaunchTo': 1, + # Launch Folder Windows in a Separate Process + 'SeparateProcess': 1, + }, + }, + r'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager': { + 'DWORD Items': { + # Disable silently installed apps + 'SilentInstalledAppsEnabled': 0, + # Disable Tips and Tricks + 'SoftLandingEnabled ': 0, + 'SubscribedContent-338389Enabled': 0, + }, + }, + # Hide People bar + r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People': { + 'DWORD Items': {'PeopleBand': 0}, + }, + # Hide Search button / box + r'Software\Microsoft\Windows\CurrentVersion\Search': { + 'DWORD Items': {'SearchboxTaskbarMode': 1}, + }, + } + +# Registry +SETTINGS_REGBACK = { + # Enable RegBack + r'System\CurrentControlSet\Control\Session Manager\Configuration Manager': { + 'DWORD Items': {'EnablePeriodicBackup': 1}, + }, + } + +# Visual C++ Runtimes +VCR_REDISTS = [ + {'Name': 'Visual C++ 2010 x32...', + 'Cmd': [r'2010sp1\x32\vcredist.exe', '/passive', '/norestart']}, + {'Name': 'Visual C++ 2010 x64...', + 'Cmd': [r'2010sp1\x64\vcredist.exe', '/passive', '/norestart']}, + {'Name': 'Visual C++ 2012 Update 4 x32...', + 'Cmd': [r'2012u4\x32\vcredist.exe', '/passive', '/norestart']}, + {'Name': 'Visual C++ 2012 Update 4 x64...', + 'Cmd': [r'2012u4\x64\vcredist.exe', '/passive', '/norestart']}, + {'Name': 'Visual C++ 2013 x32...', + 'Cmd': [r'2013\x32\vcredist.exe', '/install', + '/passive', '/norestart']}, + {'Name': 'Visual C++ 2013 x64...', + 'Cmd': [r'2013\x64\vcredist.exe', '/install', + '/passive', '/norestart']}, + {'Name': 'Visual C++ 2017 x32...', + 'Cmd': [r'2017\x32\vcredist.exe', '/install', + '/passive', '/norestart']}, + {'Name': 'Visual C++ 2017 x64...', + 'Cmd': [r'2017\x64\vcredist.exe', '/install', + '/passive', '/norestart']}, + ] + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/settings/sources.py b/.bin/Scripts/settings/sources.py index cc77f066..4ab58c02 100644 --- a/.bin/Scripts/settings/sources.py +++ b/.bin/Scripts/settings/sources.py @@ -204,6 +204,7 @@ RST_SOURCES = { 'SetupRST_16.8.exe': 'https://downloadmirror.intel.com/28400/eng/SetupRST.exe', } + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/settings/sw_diags.py b/.bin/Scripts/settings/sw_diags.py new file mode 100644 index 00000000..00892943 --- /dev/null +++ b/.bin/Scripts/settings/sw_diags.py @@ -0,0 +1,29 @@ +# Wizard Kit: Settings - SW Diagnostics + +# General +AUTORUNS_SETTINGS = { + r'Software\Sysinternals\AutoRuns': { + 'checkvirustotal': 1, + 'EulaAccepted': 1, + 'shownomicrosoft': 1, + 'shownowindows': 1, + 'showonlyvirustotal': 1, + 'submitvirustotal': 0, + 'verifysignatures': 1, + }, + r'Software\Sysinternals\AutoRuns\SigCheck': { + 'EulaAccepted': 1, + }, + r'Software\Sysinternals\AutoRuns\Streams': { + 'EulaAccepted': 1, + }, + r'Software\Sysinternals\AutoRuns\VirusTotal': { + 'VirusTotalTermsAccepted': 1, + }, + } + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/settings/tools.py b/.bin/Scripts/settings/tools.py index 0ee74dec..dd3812e1 100644 --- a/.bin/Scripts/settings/tools.py +++ b/.bin/Scripts/settings/tools.py @@ -52,6 +52,7 @@ TOOLS = { '32': r'XMPlay\xmplay.exe'}, } + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/settings/windows_builds.py b/.bin/Scripts/settings/windows_builds.py index 216be21f..08521921 100644 --- a/.bin/Scripts/settings/windows_builds.py +++ b/.bin/Scripts/settings/windows_builds.py @@ -189,6 +189,7 @@ WINDOWS_BUILDS = { '18305': ('10', None, '19H1', None, 'preview build'), } + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/settings/windows_setup.py b/.bin/Scripts/settings/windows_setup.py new file mode 100644 index 00000000..2f01c506 --- /dev/null +++ b/.bin/Scripts/settings/windows_setup.py @@ -0,0 +1,39 @@ +# Wizard Kit: Settings - Windows Setup + +# General +WINDOWS_VERSIONS = [ + {'Name': 'Windows 7 Home Basic', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEBASIC'}, + {'Name': 'Windows 7 Home Premium', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEPREMIUM'}, + {'Name': 'Windows 7 Professional', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 PROFESSIONAL'}, + {'Name': 'Windows 7 Ultimate', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 ULTIMATE'}, + + {'Name': 'Windows 8.1', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1', + 'CRLF': True}, + {'Name': 'Windows 8.1 Pro', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1 Pro'}, + + {'Name': 'Windows 10 Home', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Home', + 'CRLF': True}, + {'Name': 'Windows 10 Pro', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Pro'}, + ] + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.bin/Scripts/settings/winpe.py b/.bin/Scripts/settings/winpe.py new file mode 100644 index 00000000..6fb33b8e --- /dev/null +++ b/.bin/Scripts/settings/winpe.py @@ -0,0 +1,55 @@ +# Wizard Kit: Settings - WinPE + +# General +PE_TOOLS = { + 'BlueScreenView': { + 'Path': r'BlueScreenView\BlueScreenView.exe', + }, + 'FastCopy': { + 'Path': r'FastCopy\FastCopy.exe', + 'Args': FAST_COPY_PE_ARGS, + }, + 'HWiNFO': { + 'Path': r'HWiNFO\HWiNFO.exe', + }, + 'NT Password Editor': { + 'Path': r'NT Password Editor\ntpwedit.exe', + }, + 'Notepad++': { + 'Path': r'NotepadPlusPlus\NotepadPlusPlus.exe', + }, + 'PhotoRec': { + 'Path': r'TestDisk\photorec_win.exe', + 'Args': ['-new_console:n'], + }, + 'Prime95': { + 'Path': r'Prime95\prime95.exe', + }, + 'ProduKey': { + 'Path': r'ProduKey\ProduKey.exe', + }, + 'Q-Dir': { + 'Path': r'Q-Dir\Q-Dir.exe', + }, + 'TestDisk': { + 'Path': r'TestDisk\testdisk_win.exe', + 'Args': ['-new_console:n'], + }, + } + +# FastCopy +FAST_COPY_PE_ARGS = [ + '/cmd=noexist_only', + '/utf8', + '/skip_empty_dir', + '/linkdest', + '/no_ui', + '/auto_close', + '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), + ] + + +if __name__ == '__main__': + print("This file is not meant to be called directly.") + +# vim: sts=2 sw=2 ts=2 diff --git a/.linux_items/include/EFI/boot/refind.conf b/.linux_items/include/EFI/boot/refind.conf index 86b1a835..e7dcbfb6 100644 --- a/.linux_items/include/EFI/boot/refind.conf +++ b/.linux_items/include/EFI/boot/refind.conf @@ -33,11 +33,11 @@ menuentry "Linux" { add_options "loglevel=4 nomodeset nox" } } -#UFD#menuentry "WindowsPE" { -#UFD# ostype windows -#UFD# icon /EFI/boot/icons/wk_win.png -#UFD# loader /EFI/microsoft/bootx64.efi -#UFD#} +#UFD-WINPE#menuentry "WindowsPE" { +#UFD-WINPE# ostype windows +#UFD-WINPE# icon /EFI/boot/icons/wk_win.png +#UFD-WINPE# loader /EFI/microsoft/bootx64.efi +#UFD-WINPE#} #UFD#menuentry "ESET SysRescue Live" { #UFD# icon /EFI/boot/icons/1201_eset.png #UFD# loader /EFI/ESET/grubx64.efi diff --git a/.linux_items/include/syslinux/wk_pxe.cfg b/.linux_items/include/syslinux/wk_pxe.cfg index f8a78220..10112666 100644 --- a/.linux_items/include/syslinux/wk_pxe.cfg +++ b/.linux_items/include/syslinux/wk_pxe.cfg @@ -2,7 +2,7 @@ INCLUDE boot/syslinux/wk_head.cfg MENU BACKGROUND pxelinux.png INCLUDE boot/syslinux/wk_pxe_linux.cfg -#UFD#INCLUDE boot/syslinux/wk_pxe_winpe.cfg +#UFD-WINPE#INCLUDE boot/syslinux/wk_pxe_winpe.cfg #DISABLED_UPSTREAM_BUG#INCLUDE boot/syslinux/wk_hdt.cfg INCLUDE boot/syslinux/wk_tail.cfg diff --git a/.linux_items/include/syslinux/wk_sys.cfg b/.linux_items/include/syslinux/wk_sys.cfg index af388ed3..442ec2a3 100644 --- a/.linux_items/include/syslinux/wk_sys.cfg +++ b/.linux_items/include/syslinux/wk_sys.cfg @@ -1,9 +1,8 @@ INCLUDE boot/syslinux/wk_head.cfg INCLUDE boot/syslinux/wk_sys_linux.cfg -#UFD#INCLUDE boot/syslinux/wk_sys_winpe.cfg +#UFD-WINPE#INCLUDE boot/syslinux/wk_sys_winpe.cfg #UFD#INCLUDE boot/syslinux/1201_hdclone.cfg #UFD#INCLUDE boot/syslinux/1201_eset.cfg - #DISABLED_UPSTREAM_BUG#INCLUDE boot/syslinux/wk_hdt.cfg INCLUDE boot/syslinux/wk_tail.cfg diff --git a/Build Linux b/Build Linux index 4ccd1729..8ed965b5 100755 --- a/Build Linux +++ b/Build Linux @@ -170,6 +170,9 @@ function update_live_env() { rsync -aI "/usr/share/refind/icons/" "$LIVE_DIR/EFI/boot/icons/" --exclude "/usr/share/refind/icons/svg" sed -i "s/%ARCHISO_LABEL%/${label}/" "$LIVE_DIR/EFI/boot/refind.conf" + # Customize_airootfs.sh + sed -i -r 's/set -e -u/set -o errexit\nset -o errtrace\nset -o nounset\nset -o pipefail/' "$LIVE_DIR/airootfs/root/customize_airootfs.sh" + # Memtest86 mkdir -p "$LIVE_DIR/EFI/memtest86/Benchmark" mkdir -p "$TEMP_DIR/memtest86"