Compare commits

..

No commits in common. "dev" and "winget" have entirely different histories.
dev ... winget

126 changed files with 6055 additions and 6272 deletions

View file

@ -1,4 +1,4 @@
Copyright (c) 2023 Alan Mason Copyright (c) 2021 Alan Mason
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -61,14 +61,14 @@ BASE_MENUS = {
), ),
'Manual Steps': ( 'Manual Steps': (
MenuEntry('AdwCleaner', 'auto_adwcleaner'), MenuEntry('AdwCleaner', 'auto_adwcleaner'),
MenuEntry('Bulk Crap Uninstaller', 'auto_bcuninstaller'), MenuEntry('UninstallView', 'auto_uninstallview'),
MenuEntry('Enable Windows Updates', 'auto_windows_updates_enable'), MenuEntry('Enable Windows Updates', 'auto_windows_updates_enable'),
), ),
}, },
'Options': ( 'Options': (
MenuEntry('Kill Explorer', selected=False), MenuEntry('Kill Explorer', selected=False),
MenuEntry('Run AVRemover (once)'),
MenuEntry('Run RKill'), MenuEntry('Run RKill'),
MenuEntry('Run TDSSKiller (once)'),
MenuEntry('Sync Clock'), MenuEntry('Sync Clock'),
MenuEntry('Use Autologon', selected=False), MenuEntry('Use Autologon', selected=False),
), ),
@ -83,6 +83,7 @@ PRESETS = {
'Default': { # Will be expanded at runtime using BASE_MENUS 'Default': { # Will be expanded at runtime using BASE_MENUS
'Options': ( 'Options': (
'Run RKill', 'Run RKill',
'Run TDSSKiller (once)',
'Sync Clock', 'Sync Clock',
), ),
}, },

View file

@ -43,7 +43,6 @@ BASE_MENUS = {
), ),
'Configure System': ( 'Configure System': (
MenuEntry('Open Shell', 'auto_config_open_shell'), MenuEntry('Open Shell', 'auto_config_open_shell'),
MenuEntry('Disable Password Expiration', 'auto_disable_password_expiration'),
MenuEntry('Enable BSoD MiniDumps', 'auto_enable_bsod_minidumps'), MenuEntry('Enable BSoD MiniDumps', 'auto_enable_bsod_minidumps'),
MenuEntry('Enable RegBack', 'auto_enable_regback'), MenuEntry('Enable RegBack', 'auto_enable_regback'),
MenuEntry('Enable System Restore', 'auto_system_restore_enable'), MenuEntry('Enable System Restore', 'auto_system_restore_enable'),

View file

@ -1,13 +0,0 @@
# WizardKit: Check Antivirus
#Requires -Version 3.0
if (Test-Path Env:\DEBUG) {
Set-PSDebug -Trace 1
}
$Host.UI.RawUI.WindowTitle = "WizardKit: Check Antivirus"
$Host.UI.RawUI.BackgroundColor = "black"
$Host.UI.RawUI.ForegroundColor = "white"
$ProgressPreference = "SilentlyContinue"
# Main
Get-CimInstance -Namespace "root\SecurityCenter2" -ClassName AntivirusProduct | select displayName,productState | ConvertTo-Json

View file

@ -1,13 +0,0 @@
# WizardKit: Check Partition Alignment
#Requires -Version 3.0
if (Test-Path Env:\DEBUG) {
Set-PSDebug -Trace 1
}
$Host.UI.RawUI.WindowTitle = "WizardKit: Check Partition Alignment"
$Host.UI.RawUI.BackgroundColor = "black"
$Host.UI.RawUI.ForegroundColor = "white"
$ProgressPreference = "SilentlyContinue"
# Main
Get-CimInstance -Query "Select * from Win32_DiskPartition" | select Name,Size,StartingOffset | ConvertTo-Json

View file

@ -2,10 +2,19 @@
"""WizardKit: ddrescue TUI""" """WizardKit: ddrescue TUI"""
# vim: sts=2 sw=2 ts=2 # vim: sts=2 sw=2 ts=2
from docopt import docopt
import wk import wk
if __name__ == '__main__': if __name__ == '__main__':
try:
docopt(wk.clone.ddrescue.DOCSTRING)
except SystemExit:
print('')
wk.ui.cli.pause('Press Enter to exit...')
raise
try: try:
wk.clone.ddrescue.main() wk.clone.ddrescue.main()
except SystemExit: except SystemExit:

View file

@ -1,13 +0,0 @@
# WizardKit: Disable Password Expiration (Local Accounts)
#Requires -Version 3.0
if (Test-Path Env:\DEBUG) {
Set-PSDebug -Trace 1
}
$Host.UI.RawUI.WindowTitle = "Disable Password Expiration"
$Host.UI.RawUI.BackgroundColor = "black"
$Host.UI.RawUI.ForegroundColor = "white"
$ProgressPreference = "SilentlyContinue"
# Main
Get-LocalUser | Set-LocalUser -PasswordNeverExpires $true

View file

@ -5,17 +5,9 @@ python.exe -i embedded_python_env.py
""" """
# vim: sts=2 sw=2 ts=2 # vim: sts=2 sw=2 ts=2
import pickle
import wk import wk
# Functions
def load_state():
with open('debug/state.pickle', 'rb') as f:
return pickle.load(f)
# Main
wk.ui.cli.print_colored( wk.ui.cli.print_colored(
(wk.cfg.main.KIT_NAME_FULL, ': ', 'Debug Console'), (wk.cfg.main.KIT_NAME_FULL, ': ', 'Debug Console'),
('GREEN', None, 'YELLOW'), ('GREEN', None, 'YELLOW'),

View file

@ -2,10 +2,19 @@
"""WizardKit: Hardware Diagnostics""" """WizardKit: Hardware Diagnostics"""
# vim: sts=2 sw=2 ts=2 # vim: sts=2 sw=2 ts=2
from docopt import docopt
import wk import wk
if __name__ == '__main__': if __name__ == '__main__':
try:
docopt(wk.hw.diags.DOCSTRING)
except SystemExit:
print('')
wk.ui.cli.pause('Press Enter to exit...')
raise
try: try:
wk.hw.diags.main() wk.hw.diags.main()
except SystemExit: except SystemExit:

View file

@ -74,14 +74,6 @@ if __name__ == '__main__':
log_dir = wk.log.format_log_path(tool=True).parent log_dir = wk.log.format_log_path(tool=True).parent
USE_NETWORK = False USE_NETWORK = False
# Windows 11 workaround
if wk.os.win.OS_VERSION == 11:
appid_services = ['appid', 'appidsvc', 'applockerfltr']
for svc in appid_services:
wk.os.win.stop_service(svc)
if any([wk.os.win.get_service_status(s) != 'stopped' for s in appid_services]):
raise wk.std.GenericWarning('Failed to stop AppID services')
# Try to mount server # Try to mount server
try: try:
USE_NETWORK = use_network_sdio() USE_NETWORK = use_network_sdio()

View file

@ -7,6 +7,7 @@ from . import log
from . import main from . import main
from . import music from . import music
from . import net from . import net
from . import python
from . import repairs from . import repairs
from . import setup from . import setup
from . import sources from . import sources

View file

@ -37,7 +37,7 @@ DDRESCUE_SETTINGS = {
'--retry-passes': {'Selected': True, 'Value': '0', }, '--retry-passes': {'Selected': True, 'Value': '0', },
'--reverse': {'Selected': False, }, '--reverse': {'Selected': False, },
'--skip-size': {'Selected': True, 'Value': '0.001,0.02', }, # Percentages of source size '--skip-size': {'Selected': True, 'Value': '0.001,0.02', }, # Percentages of source size
'--test-mode': {'Selected': False, }, '--test-mode': {'Selected': False, 'Value': 'test.map', },
'--timeout': {'Selected': True, 'Value': '30m', }, '--timeout': {'Selected': True, 'Value': '30m', },
'-vvvv': {'Selected': True, 'Hidden': True, }, '-vvvv': {'Selected': True, 'Hidden': True, },
}, },

View file

@ -20,13 +20,8 @@ BADBLOCKS_REGEX = re.compile(
) )
BADBLOCKS_RESULTS_REGEX = re.compile(r'^(.*?)\x08.*\x08(.*)') BADBLOCKS_RESULTS_REGEX = re.compile(r'^(.*?)\x08.*\x08(.*)')
BADBLOCKS_SKIP_REGEX = re.compile(r'^(Checking|\[)', re.IGNORECASE) BADBLOCKS_SKIP_REGEX = re.compile(r'^(Checking|\[)', re.IGNORECASE)
CPU_TEMPS = { CPU_CRITICAL_TEMP = 100
'Cooling Delta': 25, CPU_FAILURE_TEMP = 90
'Cooling Low Cutoff': 50,
'Critical': 100,
'Idle Delta': 25,
'Idle High': 70,
}
CPU_TEST_MINUTES = 7 CPU_TEST_MINUTES = 7
IO_GRAPH_WIDTH = 40 IO_GRAPH_WIDTH = 40
IO_ALT_TEST_SIZE_FACTOR = 0.01 IO_ALT_TEST_SIZE_FACTOR = 0.01

View file

@ -69,12 +69,6 @@ LAUNCHERS = {
'L_PATH': 'BlueScreenView', 'L_PATH': 'BlueScreenView',
'L_ITEM': 'BlueScreenView.exe', 'L_ITEM': 'BlueScreenView.exe',
}, },
'BCUninstaller': {
'L_TYPE': 'Executable',
'L_PATH': 'BCUninstaller',
'L_ITEM': 'BCUninstaller.exe',
'L_ELEV': 'True',
},
'ConEmu (as ADMIN)': { 'ConEmu (as ADMIN)': {
'L_TYPE': 'Executable', 'L_TYPE': 'Executable',
'L_PATH': 'ConEmu', 'L_PATH': 'ConEmu',
@ -104,18 +98,6 @@ LAUNCHERS = {
'if /i "%PROCESSOR_ARCHITECTURE%" == "AMD64" set "ARCH=64"', 'if /i "%PROCESSOR_ARCHITECTURE%" == "AMD64" set "ARCH=64"',
], ],
}, },
'Device Cleanup': {
'L_TYPE': 'Executable',
'L_PATH': 'DeviceCleanup',
'L_ITEM': 'DeviceCleanup.exe',
'L_ELEV': 'True',
},
'Display Driver Uninstaller': {
'L_TYPE': 'Executable',
'L_PATH': 'DDU',
'L_ITEM': 'Display Driver Uninstaller.exe',
'L_ELEV': 'True',
},
'ERUNT': { 'ERUNT': {
'L_TYPE': 'Executable', 'L_TYPE': 'Executable',
'L_PATH': 'erunt', 'L_PATH': 'erunt',
@ -267,6 +249,12 @@ LAUNCHERS = {
'L_PATH': 'PuTTY', 'L_PATH': 'PuTTY',
'L_ITEM': 'PUTTY.EXE', 'L_ITEM': 'PUTTY.EXE',
}, },
'UninstallView': {
'L_TYPE': 'Executable',
'L_PATH': 'UninstallView',
'L_ITEM': 'UninstallView.exe',
'L_ELEV': 'True',
},
'WizTree': { 'WizTree': {
'L_TYPE': 'Executable', 'L_TYPE': 'Executable',
'L_PATH': 'WizTree', 'L_PATH': 'WizTree',

14
scripts/wk/cfg/python.py Normal file
View file

@ -0,0 +1,14 @@
"""WizardKit: Config - Python"""
# vim: sts=2 sw=2 ts=2
from sys import version_info
DATACLASS_DECORATOR_KWARGS = {}
if version_info.major >= 3 and version_info.minor >= 10:
DATACLASS_DECORATOR_KWARGS['slots'] = True
if __name__ == '__main__':
print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -29,14 +29,6 @@ REG_CHROME_UBLOCK_ORIGIN = {
) )
}, },
} }
REG_WINDOWS_BSOD_MINIDUMPS = {
'HKLM': {
# Enable small memory dumps
r'SYSTEM\CurrentControlSet\Control\CrashControl': (
('CrashDumpEnabled', 3, 'DWORD'),
)
}
}
REG_WINDOWS_EXPLORER = { REG_WINDOWS_EXPLORER = {
'HKLM': { 'HKLM': {
# Allow password sign-in for MS accounts # Allow password sign-in for MS accounts
@ -58,10 +50,6 @@ REG_WINDOWS_EXPLORER = {
r'Software\Policies\Microsoft\Windows\DataCollection': ( r'Software\Policies\Microsoft\Windows\DataCollection': (
('AllowTelemetry', 0, 'DWORD'), ('AllowTelemetry', 0, 'DWORD'),
), ),
# Disable floating Bing search widget
r'Software\Policies\Microsoft\Edge': (
('WebWidgetAllowed', 0, 'DWORD'),
),
# Disable Edge first run screen # Disable Edge first run screen
r'Software\Policies\Microsoft\MicrosoftEdge\Main': ( r'Software\Policies\Microsoft\MicrosoftEdge\Main': (
('PreventFirstRunPage', 1, 'DWORD'), ('PreventFirstRunPage', 1, 'DWORD'),
@ -125,7 +113,6 @@ REG_OPEN_SHELL_SETTINGS = {
('ShowedStyle2', 1, 'DWORD'), ('ShowedStyle2', 1, 'DWORD'),
), ),
r'Software\OpenShell\StartMenu\Settings': ( r'Software\OpenShell\StartMenu\Settings': (
('HighlightNew', 0, 'DWORD'),
('MenuStyle', 'Win7', 'SZ'), ('MenuStyle', 'Win7', 'SZ'),
('RecentPrograms', 'Recent', 'SZ'), ('RecentPrograms', 'Recent', 'SZ'),
('SkinW7', 'Fluent-Metro', 'SZ'), ('SkinW7', 'Fluent-Metro', 'SZ'),

View file

@ -22,34 +22,35 @@ SOURCES = {
'RKill': 'https://download.bleepingcomputer.com/grinler/rkill.exe', 'RKill': 'https://download.bleepingcomputer.com/grinler/rkill.exe',
'RegDelNull': 'https://live.sysinternals.com/RegDelNull.exe', 'RegDelNull': 'https://live.sysinternals.com/RegDelNull.exe',
'RegDelNull64': 'https://live.sysinternals.com/RegDelNull64.exe', 'RegDelNull64': 'https://live.sysinternals.com/RegDelNull64.exe',
'TDSSKiller': 'https://media.kaspersky.com/utilities/VirusUtilities/EN/tdsskiller.exe',
# Build Kit # Build Kit
'AIDA64': 'https://download.aida64.com/aida64engineer692.zip', 'AIDA64': 'https://download.aida64.com/aida64engineer675.zip',
'Adobe Reader DC': 'https://ardownload2.adobe.com/pub/adobe/reader/win/AcrobatDC/2300620360/AcroRdrDC2300620360_en_US.exe', 'Adobe Reader DC': 'https://ardownload2.adobe.com/pub/adobe/reader/win/AcrobatDC/2300320201/AcroRdrDC2300320201_en_US.exe',
'Aria2': 'https://github.com/aria2/aria2/releases/download/release-1.36.0/aria2-1.36.0-win-32bit-build1.zip', 'Aria2': 'https://github.com/aria2/aria2/releases/download/release-1.36.0/aria2-1.36.0-win-32bit-build1.zip',
'Autoruns32': 'http://live.sysinternals.com/Autoruns.exe', 'Autoruns32': 'http://live.sysinternals.com/Autoruns.exe',
'Autoruns64': 'http://live.sysinternals.com/Autoruns64.exe', 'Autoruns64': 'http://live.sysinternals.com/Autoruns64.exe',
'BleachBit': 'https://download.bleachbit.org/BleachBit-4.4.2-portable.zip', 'BleachBit': 'https://download.bleachbit.org/BleachBit-4.4.2-portable.zip',
'BlueScreenView32': 'http://www.nirsoft.net/utils/bluescreenview.zip', 'BlueScreenView32': 'http://www.nirsoft.net/utils/bluescreenview.zip',
'BlueScreenView64': 'http://www.nirsoft.net/utils/bluescreenview-x64.zip', 'BlueScreenView64': 'http://www.nirsoft.net/utils/bluescreenview-x64.zip',
'BCUninstaller': 'https://github.com/Klocman/Bulk-Crap-Uninstaller/releases/download/v5.7/BCUninstaller_5.7_portable.zip',
'DDU': 'https://www.wagnardsoft.com/DDU/download/DDU%20v18.0.6.8.exe',
'ERUNT': 'http://www.aumha.org/downloads/erunt.zip', 'ERUNT': 'http://www.aumha.org/downloads/erunt.zip',
'Everything32': 'https://www.voidtools.com/Everything-1.4.1.1024.x86.zip', 'Everything32': 'https://www.voidtools.com/Everything-1.4.1.1024.x86.zip',
'Everything64': 'https://www.voidtools.com/Everything-1.4.1.1024.x64.zip', 'Everything64': 'https://www.voidtools.com/Everything-1.4.1.1024.x64.zip',
'FastCopy': 'https://github.com/FastCopyLab/FastCopyDist2/raw/main/FastCopy5.4.2_installer.exe', 'FastCopy': 'https://download.softrepository.com/files/tools/FastCopy4.2.2_installer.exe',
'Fluent-Metro': 'https://github.com/bonzibudd/Fluent-Metro/releases/download/v1.5.3/Fluent-Metro_1.5.3.zip', 'Fluent-Metro': 'https://github.com/bonzibudd/Fluent-Metro/releases/download/v1.5.3/Fluent-Metro_1.5.3.zip',
'FurMark': 'https://geeks3d.com/dl/get/728', 'FurMark': 'https://geeks3d.com/dl/get/696',
'HWiNFO': 'https://www.sac.sk/download/utildiag/hwi_764.zip', 'HWiNFO': 'https://www.sac.sk/download/utildiag/hwi_746.zip',
'LibreOffice32': 'https://download.documentfoundation.org/libreoffice/stable/7.6.2/win/x86/LibreOffice_7.6.2_Win_x86.msi', 'LibreOffice32': 'https://download.documentfoundation.org/libreoffice/stable/7.5.4/win/x86/LibreOffice_7.5.4_Win_x86.msi',
'LibreOffice64': 'https://download.documentfoundation.org/libreoffice/stable/7.6.2/win/x86_64/LibreOffice_7.6.2_Win_x86-64.msi', 'LibreOffice64': 'https://download.documentfoundation.org/libreoffice/stable/7.5.4/win/x86_64/LibreOffice_7.5.4_Win_x64.msi',
'Macs Fan Control': 'https://www.crystalidea.com/downloads/macsfancontrol_setup.exe', 'Macs Fan Control': 'https://www.crystalidea.com/downloads/macsfancontrol_setup.exe',
'Neutron': 'http://keir.net/download/neutron.zip', 'Neutron': 'http://keir.net/download/neutron.zip',
'Notepad++': 'https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.5.8/npp.8.5.8.portable.minimalist.7z', 'Notepad++': 'https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.5.4/npp.8.5.4.portable.minimalist.7z',
'OpenShell': 'https://github.com/Open-Shell/Open-Shell-Menu/releases/download/v4.4.191/OpenShellSetup_4_4_191.exe', 'OpenShell': 'https://github.com/Open-Shell/Open-Shell-Menu/releases/download/v4.4.170/OpenShellSetup_4_4_170.exe',
'PuTTY': 'https://the.earth.li/~sgtatham/putty/latest/w32/putty.zip', 'PuTTY': 'https://the.earth.li/~sgtatham/putty/latest/w32/putty.zip',
'SDIO Torrent': 'https://www.glenn.delahoy.com/downloads/sdio/SDIO_Update.torrent', 'SDIO Torrent': 'https://www.glenn.delahoy.com/downloads/sdio/SDIO_Update.torrent',
'WizTree': 'https://diskanalyzer.com/files/wiztree_4_15_portable.zip', 'UninstallView32': 'https://www.nirsoft.net/utils/uninstallview.zip',
'UninstallView64': 'https://www.nirsoft.net/utils/uninstallview-x64.zip',
'WizTree': 'https://diskanalyzer.com/files/wiztree_4_14_portable.zip',
'XMPlay': 'https://support.xmplay.com/files/20/xmplay385.zip?v=47090', 'XMPlay': 'https://support.xmplay.com/files/20/xmplay385.zip?v=47090',
'XMPlay 7z': 'https://support.xmplay.com/files/16/xmp-7z.zip?v=800962', 'XMPlay 7z': 'https://support.xmplay.com/files/16/xmp-7z.zip?v=800962',
'XMPlay Game': 'https://support.xmplay.com/files/12/xmp-gme.zip?v=515637', 'XMPlay Game': 'https://support.xmplay.com/files/12/xmp-gme.zip?v=515637',

View file

@ -37,6 +37,8 @@ ITEMS = {
), ),
'Linux': ( 'Linux': (
('/arch', '/'), ('/arch', '/'),
('/EFI/boot', '/EFI/'),
('/syslinux', '/'),
), ),
'Main Kit': ( 'Main Kit': (
('/', f'/{KIT_NAME_FULL}/'), ('/', f'/{KIT_NAME_FULL}/'),
@ -54,25 +56,6 @@ ITEMS = {
('/sources/boot.wim', '/sources/'), ('/sources/boot.wim', '/sources/'),
), ),
} }
ITEMS_FROM_LIVE = {
'WizardKit UFD base': (
('/usr/share/WizardKit/', '/'),
),
'rEFInd': (
('/usr/share/refind/drivers_x64/', '/EFI/Boot/drivers_x64/'),
('/usr/share/refind/icons/', '/EFI/Boot/icons/'),
('/usr/share/refind/refind_x64.efi', '/EFI/Boot/'),
),
'Syslinux': (
('/usr/lib/syslinux/bios/', '/syslinux/'),
),
'Memtest86': (
('/usr/share/memtest86-efi/', '/EFI/Memtest86/'),
),
'Wimboot': (
('/usr/share/wimboot/', '/syslinux/'),
),
}
ITEMS_HIDDEN = ( ITEMS_HIDDEN = (
# Linux (all versions) # Linux (all versions)
'arch', 'arch',

View file

@ -38,6 +38,4 @@ WINDOWS_BUILDS = {
# Windows 11 # Windows 11
'10.0.22000': '21H2', '10.0.22000': '21H2',
'10.0.22621': '22H2', '10.0.22621': '22H2',
'10.0.22631': '23H2',
'10.0.26100': '24H2',
} }

View file

@ -1,7 +1,4 @@
"""WizardKit: ddrescue-tui module init""" """WizardKit: ddrescue-tui module init"""
from . import block_pair
from . import ddrescue from . import ddrescue
from . import image
from . import menus from . import menus
from . import state

View file

@ -1,575 +0,0 @@
"""WizardKit: ddrescue TUI - Block Pairs"""
# vim: sts=2 sw=2 ts=2
import logging
import math
import os
import pathlib
import plistlib
import re
import subprocess
from wk import cfg, exe, std
from wk.clone import menus
from wk.hw import disk as hw_disk
from wk.ui import ansi, cli
# STATIC VARIABLES
LOG = logging.getLogger(__name__)
DDRESCUE_LOG_REGEX = re.compile(
r'^\s*(?P<key>\S+):\s+'
r'(?P<size>\d+)\s+'
r'(?P<unit>[PTGMKB]i?B?)'
r'.*\(\s*(?P<percent>\d+\.?\d*)%\)$',
re.IGNORECASE,
)
# Classes
class BlockPair():
"""Object for tracking source to dest recovery data."""
def __init__(
self,
source_dev: hw_disk.Disk,
destination: pathlib.Path,
working_dir: pathlib.Path,
):
self.sector_size: int = source_dev.phy_sec
self.source: pathlib.Path = pathlib.Path(source_dev.path)
self.destination: pathlib.Path = destination
self.map_data: dict[str, bool | int] = {}
self.map_path: pathlib.Path = pathlib.Path()
self.size: int = source_dev.size
self.status: dict[str, float | int | str] = {
'read-skip': 'Pending',
'read-full': 'Pending',
'trim': 'Pending',
'scrape': 'Pending',
}
self.test_map: pathlib.Path | None = None
self.view_map: bool = 'DISPLAY' in os.environ or 'WAYLAND_DISPLAY' in os.environ
self.view_proc: subprocess.Popen | None = None
# Set map path
# e.g. '(Clone|Image)_Model_Serial[_p#]_Size[_Label].map'
map_name = f'{source_dev.model}_{source_dev.serial}'
if source_dev.bus == 'Image':
map_name = 'Image'
if source_dev.parent:
part_num = re.sub(r"^.*?(\d+)$", r"\1", self.source.name)
map_name += f'_p{part_num}'
size_str = std.bytes_to_string(
size=self.size,
use_binary=False,
)
map_name += f'_{size_str.replace(" ", "")}'
if source_dev.raw_details.get('label', ''):
map_name += f'_{source_dev.raw_details["label"]}'
map_name = map_name.replace(' ', '_')
map_name = map_name.replace('/', '_')
map_name = map_name.replace('\\', '_')
if destination.is_dir():
# Imaging
self.map_path = pathlib.Path(f'{destination}/Image_{map_name}.map')
self.destination = self.map_path.with_suffix('.dd')
self.destination.touch()
else:
# Cloning
self.map_path = pathlib.Path(f'{working_dir}/Clone_{map_name}.map')
# Create map file if needed
# NOTE: We need to set the domain size for --complete-only to work
if not self.map_path.exists():
self.map_path.write_text(
data=cfg.ddrescue.DDRESCUE_MAP_TEMPLATE.format(
name=cfg.main.KIT_NAME_FULL,
size=self.size,
),
encoding='utf-8',
)
# Set initial status
self.set_initial_status()
def __getstate__(self):
"""Override to allow pickling ddrescue.State() objects."""
bp_state = self.__dict__.copy()
del bp_state['view_proc']
return bp_state
def get_error_size(self) -> int:
"""Get error size in bytes, returns int."""
return self.size - self.get_rescued_size()
def get_percent_recovered(self) -> float:
"""Get percent rescued from map_data, returns float."""
return 100 * self.map_data.get('rescued', 0) / self.size
def get_rescued_size(self) -> int:
"""Get rescued size using map data.
NOTE: Returns 0 if no map data is available.
"""
self.load_map_data()
return self.map_data.get('rescued', 0)
def load_map_data(self) -> None:
"""Load map data from file.
NOTE: If the file is missing it is assumed that recovery hasn't
started yet so default values will be returned instead.
"""
data: dict[str, bool | int] = {'full recovery': False, 'pass completed': False}
# Get output from ddrescuelog
cmd = [
'ddrescuelog',
'--binary-prefixes',
'--show-status',
f'--size={self.size}',
self.map_path,
]
proc = exe.run_program(cmd, check=False)
# Parse output
for line in proc.stdout.splitlines():
_r = DDRESCUE_LOG_REGEX.search(line)
if _r:
if _r.group('key') == 'rescued' and _r.group('percent') == '100':
# Fix rounding errors from ddrescuelog output
data['rescued'] = self.size
else:
data[_r.group('key')] = std.string_to_bytes(
f'{_r.group("size")} {_r.group("unit")}',
)
data['pass completed'] = 'current status: finished' in line.lower()
# Check if 100% done (only if map is present and non-zero size
# NOTE: ddrescuelog returns 0 (i.e. 100% done) for empty files
if self.map_path.exists() and self.map_path.stat().st_size != 0:
cmd = [
'ddrescuelog',
'--done-status',
f'--size={self.size}',
self.map_path,
]
proc = exe.run_program(cmd, check=False)
data['full recovery'] = proc.returncode == 0
# Done
self.map_data.update(data)
def pass_complete(self, pass_name) -> bool:
"""Check if pass_name is complete based on map data, returns bool."""
pending_size = self.map_data['non-tried']
# Full recovery
if self.map_data.get('full recovery', False):
return True
# New recovery
if 'non-tried' not in self.map_data:
return False
# Initial read skip pass
if pass_name == 'read-skip':
pass_threshold = cfg.ddrescue.AUTO_PASS_THRESHOLDS[pass_name]
if self.get_percent_recovered() >= pass_threshold:
return True
# Recovery in progress
if pass_name in ('trim', 'scrape'):
pending_size += self.map_data['non-trimmed']
if pass_name == 'scrape':
pending_size += self.map_data['non-scraped']
if pending_size == 0:
# This is true when the previous and current passes are complete
return True
# This should never be reached
return False
def safety_check(self) -> None:
"""Run safety check and abort if necessary."""
# TODO: Expand section to support non-Linux systems
dest_size = -1
if self.destination.is_block_device():
cmd = [
'lsblk', '--bytes', '--json',
'--nodeps', '--noheadings', '--output=size',
self.destination,
]
json_data = exe.get_json_from_command(cmd)
dest_size = json_data['blockdevices'][0]['size']
del json_data
# Check destination size if cloning
if not self.destination.is_file() and dest_size < self.size:
cli.print_error(f'Invalid destination: {self.destination}')
raise std.GenericAbort()
def set_initial_status(self) -> None:
"""Read map data and set initial statuses."""
self.load_map_data()
percent = self.get_percent_recovered()
for name in self.status:
if self.pass_complete(name):
self.status[name] = percent
else:
# Stop checking
if percent > 0:
self.status[name] = percent
break
def skip_pass(self, pass_name) -> None:
"""Mark pass as skipped if applicable."""
if self.status[pass_name] == 'Pending':
self.status[pass_name] = 'Skipped'
def update_progress(self, pass_name) -> None:
"""Update progress via map data."""
self.load_map_data()
# Update status
percent = self.get_percent_recovered()
if percent > 0:
self.status[pass_name] = percent
# Mark future passes as skipped if applicable
if percent == 100:
status_keys = list(self.status.keys())
for pass_n in status_keys[status_keys.index(pass_name)+1:]:
self.status[pass_n] = 'Skipped'
# Functions
def add_clone_block_pairs(state) -> list[hw_disk.Disk]:
"""Add device to device block pairs and set settings if necessary."""
source_sep = get_partition_separator(state.source.path.name)
dest_sep = get_partition_separator(state.destination.path.name)
settings = {}
# Clone settings
settings = state.load_settings(discard_unused_settings=True)
# Add pairs from previous run
if settings['Partition Mapping']:
source_parts = []
for part_map in settings['Partition Mapping']:
bp_source = hw_disk.Disk(
f'{state.source.path}{source_sep}{part_map[0]}',
)
bp_dest = pathlib.Path(
f'{state.destination.path}{dest_sep}{part_map[1]}',
)
source_parts.append(bp_source)
state.add_block_pair(bp_source, bp_dest)
return source_parts
# Add pairs from selection
source_parts = menus.select_disk_parts('Clone', state.source)
if state.source.path.samefile(source_parts[0].path):
# Whole disk (or single partition via args), skip settings
bp_dest = state.destination.path
state.add_block_pair(state.source, bp_dest)
return source_parts
# New run, use new settings file
settings['Needs Format'] = True
offset = 0
user_choice = cli.choice(
'Format clone using GPT, MBR, or match Source type?',
['G', 'M', 'S'],
)
if user_choice == 'G':
settings['Table Type'] = 'GPT'
elif user_choice == 'M':
settings['Table Type'] = 'MBR'
else:
# Match source type
settings['Table Type'] = get_table_type(state.source.path)
if cli.ask('Create an empty Windows boot partition on the clone?'):
settings['Create Boot Partition'] = True
offset = 2 if settings['Table Type'] == 'GPT' else 1
# Add pairs
for dest_num, part in enumerate(source_parts):
dest_num += offset + 1
bp_dest = pathlib.Path(
f'{state.destination.path}{dest_sep}{dest_num}',
)
state.add_block_pair(part, bp_dest)
# Add to settings file
source_num = re.sub(r'^.*?(\d+)$', r'\1', part.path.name)
settings['Partition Mapping'].append([source_num, dest_num])
# Save settings
state.save_settings(settings)
# Done
return source_parts
def add_image_block_pairs(state) -> list[hw_disk.Disk]:
"""Add device to image file block pairs."""
source_parts = menus.select_disk_parts(state.mode, state.source)
for part in source_parts:
state.add_block_pair(part, state.destination)
# Done
return source_parts
def build_block_pair_report(block_pairs, settings) -> list:
"""Build block pair report, returns list."""
report = []
notes = []
if block_pairs:
report.append(ansi.color_string('Block Pairs', 'GREEN'))
else:
# Bail early
return report
# Show block pair mapping
if settings and settings['Create Boot Partition']:
if settings['Table Type'] == 'GPT':
report.append(f'{" —— ":<9} --> EFI System Partition')
report.append(f'{" —— ":<9} --> Microsoft Reserved Partition')
elif settings['Table Type'] == 'MBR':
report.append(f'{" —— ":<9} --> System Reserved')
for pair in block_pairs:
report.append(f'{pair.source.name:<9} --> {pair.destination.name}')
# Show resume messages as necessary
if settings:
if not settings['First Run']:
notes.append(
ansi.color_string(
['NOTE:', 'Clone settings loaded from previous run.'],
['BLUE', None],
),
)
if settings['Needs Format'] and settings['Table Type']:
msg = f'Destination will be formatted using {settings["Table Type"]}'
notes.append(
ansi.color_string(
['NOTE:', msg],
['BLUE', None],
),
)
if any(pair.get_rescued_size() > 0 for pair in block_pairs):
notes.append(
ansi.color_string(
['NOTE:', 'Resume data loaded from map file(s).'],
['BLUE', None],
),
)
# Add notes to report
if notes:
report.append(' ')
report.extend(notes)
# Done
return report
def build_sfdisk_partition_line(table_type, dev_path, size, details) -> str:
"""Build sfdisk partition line using passed details, returns str."""
line = f'{dev_path} : size={size}'
dest_type = ''
source_filesystem = str(details.get('fstype', '')).upper()
source_table_type = ''
source_type = details.get('parttype', '')
# Set dest type
if re.match(r'^0x\w+$', source_type):
# Source is a MBR type
source_table_type = 'MBR'
if table_type == 'MBR':
dest_type = source_type.replace('0x', '').lower()
elif re.match(r'^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$', source_type):
# Source is a GPT type
source_table_type = 'GPT'
if table_type == 'GPT':
dest_type = source_type.upper()
if not dest_type:
# Assuming changing table types, set based on FS
if source_filesystem in cfg.ddrescue.PARTITION_TYPES.get(table_type, {}):
dest_type = cfg.ddrescue.PARTITION_TYPES[table_type][source_filesystem]
line += f', type={dest_type}'
# Safety Check
if not dest_type:
cli.print_error(f'Failed to determine partition type for: {dev_path}')
raise std.GenericAbort()
# Add extra details
if details.get('partlabel', ''):
line += f', name="{details["partlabel"]}"'
if details.get('partuuid', '') and source_table_type == table_type:
# Only add UUID if source/dest table types match
line += f', uuid={details["partuuid"].upper()}'
# Done
return line
def get_partition_separator(name) -> str:
"""Get partition separator based on device name, returns str."""
separator = ''
if re.search(r'(loop|mmc|nvme)', name, re.IGNORECASE):
separator = 'p'
return separator
def get_table_type(disk_path) -> str:
"""Get disk partition table type, returns str.
NOTE: If resulting table type is not GPT or MBR
then an exception is raised.
"""
disk_path = str(disk_path)
table_type = None
# Linux
if std.PLATFORM == 'Linux':
cmd = f'lsblk --json --output=pttype --nodeps {disk_path}'.split()
json_data = exe.get_json_from_command(cmd)
table_type = json_data['blockdevices'][0].get('pttype', '').upper()
table_type = table_type.replace('DOS', 'MBR')
# macOS
if std.PLATFORM == 'Darwin':
cmd = ['diskutil', 'list', '-plist', disk_path]
proc = exe.run_program(cmd, check=False, encoding=None, errors=None)
try:
plist_data = plistlib.loads(proc.stdout)
except (TypeError, ValueError):
# Invalid / corrupt plist data? return empty dict to avoid crash
pass
else:
disk_details = plist_data.get('AllDisksAndPartitions', [{}])[0]
table_type = disk_details['Content']
table_type = table_type.replace('FDisk_partition_scheme', 'MBR')
table_type = table_type.replace('GUID_partition_scheme', 'GPT')
# Check type
if table_type not in ('GPT', 'MBR'):
cli.print_error(f'Unsupported partition table type: {table_type}')
raise std.GenericAbort()
# Done
return table_type
def prep_destination(
state,
source_parts: list[hw_disk.Disk],
dry_run: bool = True,
) -> None:
"""Prep destination as necessary."""
# TODO: Split into Linux and macOS
# logical sector size is not easily found under macOS
# It might be easier to rewrite this section using macOS tools
dest_prefix = str(state.destination.path)
dest_prefix += get_partition_separator(state.destination.path.name)
esp_type = 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B'
msr_type = 'E3C9E316-0B5C-4DB8-817D-F92DF00215AE'
part_num = 0
sfdisk_script = []
settings = state.load_settings()
# Bail early
if not settings['Needs Format']:
return
# Add partition table settings
if settings['Table Type'] == 'GPT':
sfdisk_script.append('label: gpt')
else:
sfdisk_script.append('label: dos')
sfdisk_script.append('unit: sectors')
sfdisk_script.append('')
# Add boot partition if requested
if settings['Create Boot Partition']:
if settings['Table Type'] == 'GPT':
part_num += 1
sfdisk_script.append(
build_sfdisk_partition_line(
table_type='GPT',
dev_path=f'{dest_prefix}{part_num}',
size='260MiB',
details={'parttype': esp_type, 'partlabel': 'EFI System'},
),
)
part_num += 1
sfdisk_script.append(
build_sfdisk_partition_line(
table_type=settings['Table Type'],
dev_path=f'{dest_prefix}{part_num}',
size='16MiB',
details={'parttype': msr_type, 'partlabel': 'Microsoft Reserved'},
),
)
elif settings['Table Type'] == 'MBR':
part_num += 1
sfdisk_script.append(
build_sfdisk_partition_line(
table_type='MBR',
dev_path=f'{dest_prefix}{part_num}',
size='100MiB',
details={'parttype': '0x7', 'partlabel': 'System Reserved'},
),
)
# Add selected partition(s)
for part in source_parts:
num_sectors = part.size / state.destination.log_sec
num_sectors = math.ceil(num_sectors)
part_num += 1
sfdisk_script.append(
build_sfdisk_partition_line(
table_type=settings['Table Type'],
dev_path=f'{dest_prefix}{part_num}',
size=num_sectors,
details=part.raw_details,
),
)
# Save sfdisk script
script_path = (
f'{state.working_dir}/'
f'sfdisk_{state.destination.path.name}.script'
)
with open(script_path, 'w', encoding='utf-8') as _f:
_f.write('\n'.join(sfdisk_script))
# Skip real format for dry runs
if dry_run:
LOG.info('Dry run, refusing to format destination')
return
# Format disk
LOG.warning('Formatting destination: %s', state.destination.path)
with open(script_path, 'r', encoding='utf-8') as _f:
proc = exe.run_program(
cmd=['sudo', 'sfdisk', state.destination.path],
stdin=_f,
check=False,
)
if proc.returncode != 0:
cli.print_error('Error(s) encoundtered while formatting destination')
raise std.GenericAbort()
# Update settings
settings['Needs Format'] = False
state.save_settings(settings)
if __name__ == '__main__':
print("This file is not meant to be called directly.")

File diff suppressed because it is too large Load diff

View file

@ -1,109 +0,0 @@
"""WizardKit: ddrescue TUI - State"""
# vim: sts=2 sw=2 ts=2
import atexit
import logging
import pathlib
import plistlib
import re
from wk import exe
from wk.std import PLATFORM
from wk.ui import cli
# STATIC VARIABLES
LOG = logging.getLogger(__name__)
# Functions
def mount_raw_image(path) -> pathlib.Path:
"""Mount raw image using OS specific methods, returns pathlib.Path."""
loopback_path = None
if PLATFORM == 'Darwin':
loopback_path = mount_raw_image_macos(path)
elif PLATFORM == 'Linux':
loopback_path = mount_raw_image_linux(path)
# Check
if not loopback_path:
cli.print_error(f'Failed to mount image: {path}')
# Register unmount atexit
atexit.register(unmount_loopback_device, loopback_path)
# Done
return loopback_path
def mount_raw_image_linux(path) -> pathlib.Path:
"""Mount raw image using losetup, returns pathlib.Path."""
loopback_path = None
# Mount using losetup
cmd = [
'sudo',
'losetup',
'--find',
'--partscan',
'--show',
path,
]
proc = exe.run_program(cmd, check=False)
# Check result
if proc.returncode == 0:
loopback_path = proc.stdout.strip()
# Done
return loopback_path
def mount_raw_image_macos(path) -> pathlib.Path:
"""Mount raw image using hdiutil, returns pathlib.Path."""
loopback_path = None
plist_data = {}
# Mount using hdiutil
# plistdata['system-entities'][{}...]
cmd = [
'hdiutil', 'attach',
'-imagekey', 'diskimage-class=CRawDiskImage',
'-nomount',
'-plist',
'-readonly',
path,
]
proc = exe.run_program(cmd, check=False, encoding=None, errors=None)
# Check result
try:
plist_data = plistlib.loads(proc.stdout)
except plistlib.InvalidFileException:
return None
for dev in plist_data.get('system-entities', []):
dev_path = dev.get('dev-entry', '')
if re.match(r'^/dev/disk\d+$', dev_path):
loopback_path = dev_path
# Done
return loopback_path
def unmount_loopback_device(path) -> None:
"""Unmount loopback device using OS specific methods."""
cmd = []
# Build OS specific cmd
if PLATFORM == 'Darwin':
cmd = ['hdiutil', 'detach', path]
elif PLATFORM == 'Linux':
cmd = ['sudo', 'losetup', '--detach', path]
# Unmount loopback device
exe.run_program(cmd, check=False)
if __name__ == '__main__':
print("This file is not meant to be called directly.")

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@ import re
import subprocess import subprocess
import time import time
from io import IOBase from io import BufferedReader, TextIOWrapper
from queue import Queue, Empty from queue import Queue, Empty
from threading import Thread from threading import Thread
from typing import Any, Callable, Iterable from typing import Any, Callable, Iterable
@ -28,11 +28,11 @@ class NonBlockingStreamReader():
## https://gist.github.com/EyalAr/7915597 ## https://gist.github.com/EyalAr/7915597
## https://stackoverflow.com/a/4896288 ## https://stackoverflow.com/a/4896288
def __init__(self, stream: IOBase): def __init__(self, stream: BufferedReader | TextIOWrapper):
self.stream: IOBase = stream self.stream: BufferedReader | TextIOWrapper = stream
self.queue: Queue = Queue() self.queue: Queue = Queue()
def populate_queue(stream: IOBase, queue: Queue) -> None: def populate_queue(stream: BufferedReader | TextIOWrapper, queue: Queue) -> None:
"""Collect lines from stream and put them in queue.""" """Collect lines from stream and put them in queue."""
while not stream.closed: while not stream.closed:
try: try:
@ -256,9 +256,8 @@ def run_program(
pipe=pipe, pipe=pipe,
shell=shell, shell=shell,
**kwargs) **kwargs)
check = cmd_kwargs.pop('check', True) # Avoids linting warning
try: try:
proc = subprocess.run(check=check, **cmd_kwargs) proc = subprocess.run(**cmd_kwargs)
except FileNotFoundError: except FileNotFoundError:
LOG.error('Command not found: %s', cmd) LOG.error('Command not found: %s', cmd)
raise raise

View file

@ -8,7 +8,7 @@ import subprocess
from typing import TextIO from typing import TextIO
from wk import exe from wk import exe
from wk.cfg.hw import CPU_TEMPS from wk.cfg.hw import CPU_FAILURE_TEMP
from wk.os.mac import set_fans as macos_set_fans from wk.os.mac import set_fans as macos_set_fans
from wk.std import PLATFORM from wk.std import PLATFORM
from wk.ui import ansi from wk.ui import ansi
@ -20,75 +20,32 @@ SysbenchType = tuple[subprocess.Popen, TextIO]
# Functions # Functions
def check_cooling_results(sensors, test_object) -> None: def check_cooling_results(test_obj, sensors, run_sysbench=False) -> None:
"""Check cooling result via sensor data.""" """Check cooling results and update test_obj."""
idle_temp = sensors.get_cpu_temp('Idle') max_temp = sensors.cpu_max_temp()
cooldown_temp = sensors.get_cpu_temp('Cooldown') temp_labels = ['Idle', 'Max', 'Cooldown']
max_temp = sensors.get_cpu_temp('Max') if run_sysbench:
test_object.report.append(ansi.color_string('Temps', 'BLUE')) temp_labels.append('Sysbench')
# Check temps # Check temps
if max_temp > CPU_TEMPS['Critical']: if not max_temp:
test_object.failed = True test_obj.set_status('Unknown')
test_object.set_status('Failed') elif max_temp >= CPU_FAILURE_TEMP:
test_object.report.extend([ test_obj.failed = True
ansi.color_string( test_obj.set_status('Failed')
f' WARNING: Critical CPU temp of {CPU_TEMPS["Critical"]} exceeded.', elif 'Aborted' not in test_obj.status:
'RED', test_obj.passed = True
), test_obj.set_status('Passed')
'',
])
elif idle_temp >= CPU_TEMPS['Idle High']:
test_object.failed = True
test_object.set_status('Failed')
test_object.report.extend([
ansi.color_string(
f' WARNING: Max idle temp of {CPU_TEMPS["Idle High"]} exceeded.',
'YELLOW',
),
'',
])
elif (
cooldown_temp <= CPU_TEMPS['Cooling Low Cutoff']
or max_temp - cooldown_temp >= CPU_TEMPS['Cooling Delta']
):
test_object.passed = True
test_object.set_status('Passed')
else:
test_object.passed = False
test_object.set_status('Unknown')
if cooldown_temp - idle_temp >= CPU_TEMPS['Idle Delta']:
test_object.report.extend([
ansi.color_string(
f' WARNING: Cooldown temp at least {CPU_TEMPS["Idle Delta"]}° over idle.',
'YELLOW',
),
'',
])
# Build report # Add temps to report
report_labels = ['Idle'] for line in sensors.generate_report(*temp_labels, only_cpu=True):
average_labels = [] test_obj.report.append(f' {line}')
if 'Sysbench' in sensors.temp_labels:
average_labels.append('Sysbench')
report_labels.extend(['Sysbench', 'Cooldown'])
if 'Prime95' in sensors.temp_labels:
average_labels.append('Prime95')
report_labels.append('Prime95')
if 'Cooldown' not in report_labels:
report_labels.append('Cooldown')
if len(sensors.temp_labels.intersection(['Prime95', 'Sysbench'])) < 1:
# Include overall max temp if needed
report_labels.append('Max')
for line in sensors.generate_report(
*report_labels, only_cpu=True, include_avg_for=average_labels):
test_object.report.append(f' {line}')
def check_mprime_results(test_obj, working_dir) -> None: def check_mprime_results(test_obj, working_dir) -> None:
"""Check mprime log files and update test_obj.""" """Check mprime log files and update test_obj."""
passing_lines = set() passing_lines = {}
warning_lines = set() warning_lines = {}
def _read_file(log_name) -> list[str]: def _read_file(log_name) -> list[str]:
"""Read file and split into lines, returns list.""" """Read file and split into lines, returns list."""
@ -106,7 +63,7 @@ def check_mprime_results(test_obj, working_dir) -> None:
for line in _read_file('results.txt'): for line in _read_file('results.txt'):
line = line.strip() line = line.strip()
if re.search(r'(error|fail)', line, re.IGNORECASE): if re.search(r'(error|fail)', line, re.IGNORECASE):
warning_lines.add(line) warning_lines[line] = None
# prime.log (check if passed) # prime.log (check if passed)
for line in _read_file('prime.log'): for line in _read_file('prime.log'):
@ -116,10 +73,10 @@ def check_mprime_results(test_obj, working_dir) -> None:
if match: if match:
if int(match.group(2)) + int(match.group(3)) > 0: if int(match.group(2)) + int(match.group(3)) > 0:
# Errors and/or warnings encountered # Errors and/or warnings encountered
warning_lines.add(match.group(1).capitalize()) warning_lines[match.group(1).capitalize()] = None
else: else:
# No errors/warnings # No errors/warnings
passing_lines.add(match.group(1).capitalize()) passing_lines[match.group(1).capitalize()] = None
# Update status # Update status
if warning_lines: if warning_lines:
@ -155,9 +112,7 @@ def start_mprime(working_dir, log_path) -> subprocess.Popen:
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
) )
proc_mprime.stdout.close() # type: ignore[reportOptionalMemberAccess] proc_mprime.stdout.close() # type: ignore[reportOptionalMemberAccess]
save_nbsr = exe.NonBlockingStreamReader( save_nbsr = exe.NonBlockingStreamReader(proc_grep.stdout)
proc_grep.stdout, # type: ignore[reportGeneralTypeIssues]
)
exe.start_thread( exe.start_thread(
save_nbsr.save_to_file, save_nbsr.save_to_file,
args=(proc_grep, log_path), args=(proc_grep, log_path),
@ -167,6 +122,35 @@ def start_mprime(working_dir, log_path) -> subprocess.Popen:
return proc_mprime return proc_mprime
def start_sysbench(sensors, sensors_out, log_path) -> SysbenchType:
"""Start sysbench, returns tuple with Popen object and file handle."""
set_apple_fan_speed('max')
sysbench_cmd = [
'sysbench',
f'--threads={exe.psutil.cpu_count()}',
'--cpu-max-prime=1000000000',
'cpu',
'run',
]
# Restart background monitor for Sysbench
sensors.stop_background_monitor()
sensors.start_background_monitor(
sensors_out,
alt_max='Sysbench',
thermal_action=('killall', 'sysbench', '-INT'),
)
# Start sysbench
filehandle_sysbench = open(
log_path, 'a', encoding='utf-8',
)
proc_sysbench = exe.popen_program(sysbench_cmd, stdout=filehandle_sysbench)
# Done
return (proc_sysbench, filehandle_sysbench)
def set_apple_fan_speed(speed) -> None: def set_apple_fan_speed(speed) -> None:
"""Set Apple fan speed.""" """Set Apple fan speed."""
cmd = None cmd = None
@ -190,27 +174,6 @@ def set_apple_fan_speed(speed) -> None:
exe.run_program(cmd, check=False) exe.run_program(cmd, check=False)
def start_sysbench(log_path) -> SysbenchType:
"""Start sysbench, returns tuple with Popen object and file handle."""
set_apple_fan_speed('max')
cmd = [
'sysbench',
f'--threads={exe.psutil.cpu_count()}',
'--cpu-max-prime=1000000000',
'cpu',
'run',
]
# Start sysbench
filehandle = open(
log_path, 'a', encoding='utf-8',
)
proc = exe.popen_program(cmd, stdout=filehandle)
# Done
return (proc, filehandle)
def stop_mprime(proc_mprime) -> None: def stop_mprime(proc_mprime) -> None:
"""Stop mprime gracefully, then forcefully as needed.""" """Stop mprime gracefully, then forcefully as needed."""
proc_mprime.terminate() proc_mprime.terminate()

View file

@ -1,12 +1,14 @@
"""WizardKit: Hardware diagnostics""" """WizardKit: Hardware diagnostics"""
# vim: sts=2 sw=2 ts=2 # vim: sts=2 sw=2 ts=2
import argparse
import atexit import atexit
import logging import logging
import os import os
import pathlib import pathlib
import subprocess import subprocess
import time
from docopt import docopt
from wk import cfg, debug, exe, log, std from wk import cfg, debug, exe, log, std
from wk.cfg.hw import STATUS_COLORS from wk.cfg.hw import STATUS_COLORS
@ -27,13 +29,23 @@ from wk.ui import ansi, cli, tui
# STATIC VARIABLES # STATIC VARIABLES
DOCSTRING = f'''{cfg.main.KIT_NAME_FULL}: Hardware Diagnostics
Usage:
hw-diags [options]
hw-diags (-h | --help)
Options:
-c --cli Force CLI mode
-h --help Show this page
-q --quick Skip menu and perform a quick check
-t --test-mode Run diags in test mode
'''
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
TEST_GROUPS = { TEST_GROUPS = {
# Also used to build the menu options # Also used to build the menu options
## NOTE: This needs to be above MENU_SETS ## NOTE: This needs to be above MENU_SETS
'CPU (Sysbench)': 'cpu_test_sysbench', 'CPU & Cooling': 'cpu_stress_tests',
'CPU (Prime95)': 'cpu_test_mprime',
'CPU (Cooling)': 'cpu_test_cooling',
'Disk Attributes': 'disk_attribute_check', 'Disk Attributes': 'disk_attribute_check',
'Disk Self-Test': 'disk_self_test', 'Disk Self-Test': 'disk_self_test',
'Disk Surface Scan': 'disk_surface_scan', 'Disk Surface Scan': 'disk_surface_scan',
@ -53,7 +65,6 @@ MENU_ACTIONS_SECRET = (
MENU_OPTIONS_QUICK = ('Disk Attributes',) MENU_OPTIONS_QUICK = ('Disk Attributes',)
MENU_SETS = { MENU_SETS = {
'Full Diagnostic': (*TEST_GROUPS,), 'Full Diagnostic': (*TEST_GROUPS,),
'CPU Diagnostic': (*[group for group in TEST_GROUPS if group.startswith('CPU')],),
'Disk Diagnostic': ( 'Disk Diagnostic': (
'Disk Attributes', 'Disk Attributes',
'Disk Self-Test', 'Disk Self-Test',
@ -74,7 +85,6 @@ class State():
self.disks: list[hw_disk.Disk] = [] self.disks: list[hw_disk.Disk] = []
self.log_dir: pathlib.Path | None = None self.log_dir: pathlib.Path | None = None
self.progress_file: pathlib.Path | None = None self.progress_file: pathlib.Path | None = None
self.sensors: hw_sensors.Sensors = hw_sensors.Sensors()
self.system: hw_system.System | None = None self.system: hw_system.System | None = None
self.test_groups: list[TestGroup] = [] self.test_groups: list[TestGroup] = []
self.title_text: str = ansi.color_string('Hardware Diagnostics', 'GREEN') self.title_text: str = ansi.color_string('Hardware Diagnostics', 'GREEN')
@ -112,21 +122,20 @@ class State():
# Reset objects # Reset objects
self.disks.clear() self.disks.clear()
self.sensors = hw_sensors.Sensors()
self.test_groups.clear() self.test_groups.clear()
# Set log # Set log
self.log_dir = log.format_log_path( self.log_dir = log.format_log_path()
log_name='main', self.log_dir = pathlib.Path(
sub_dir='Hardware-Diagnostics', f'{self.log_dir.parent}/'
f'Hardware-Diagnostics_{time.strftime("%Y-%m-%d_%H%M%S%z")}/'
) )
log.update_log_path( log.update_log_path(
dest_dir=self.log_dir.parent, dest_dir=self.log_dir,
dest_name=self.log_dir.stem, dest_name='main',
keep_history=False, keep_history=False,
timestamp=False, timestamp=False,
) )
self.log_dir = self.log_dir.parent
cli.clear_screen() cli.clear_screen()
cli.print_info('Initializing...') cli.print_info('Initializing...')
@ -149,9 +158,21 @@ class State():
continue continue
if 'CPU' in name: if 'CPU' in name:
# Create two Test objects which will both be used by cpu_stress_tests
# NOTE: Prime95 should be added first
self.system.tests.append( self.system.tests.append(
Test(dev=self.system, label=name[5:-1], name=name), Test(dev=self.system, label='Prime95', name=name),
) )
self.system.tests.append(
Test(dev=self.system, label='Cooling', name=name),
)
self.test_groups.append(
TestGroup(
name=name,
function=globals()[TEST_GROUPS[name]],
test_objects=self.system.tests,
),
)
if 'Disk' in name: if 'Disk' in name:
test_group = TestGroup( test_group = TestGroup(
@ -163,17 +184,6 @@ class State():
test_group.test_objects.append(test_obj) test_group.test_objects.append(test_obj)
self.test_groups.append(test_group) self.test_groups.append(test_group)
# Group CPU tests
if self.system.tests:
self.test_groups.insert(
0,
TestGroup(
name='CPU & Cooling',
function=run_cpu_tests,
test_objects=self.system.tests,
),
)
def reset_layout(self) -> None: def reset_layout(self) -> None:
"""Reset layout to avoid flickering.""" """Reset layout to avoid flickering."""
self.ui.clear_current_pane_height() self.ui.clear_current_pane_height()
@ -213,7 +223,7 @@ class State():
proc = exe.run_program(['smc', '-l']) proc = exe.run_program(['smc', '-l'])
data.extend(proc.stdout.splitlines()) data.extend(proc.stdout.splitlines())
except Exception: except Exception:
LOG.error('Error(s) encountered while exporting SMC data') LOG.ERROR('Error(s) encountered while exporting SMC data')
data = [line.strip() for line in data] data = [line.strip() for line in data]
with open(f'{debug_dir}/smc.data', 'a', encoding='utf-8') as _f: with open(f'{debug_dir}/smc.data', 'a', encoding='utf-8') as _f:
_f.write('\n'.join(data)) _f.write('\n'.join(data))
@ -251,36 +261,6 @@ class State():
# Functions # Functions
def argparse_helper() -> dict[str, bool]:
"""Helper function to setup and return args, returns dict.
NOTE: A dict is used to match the legacy code.
"""
parser = argparse.ArgumentParser(
prog='hw-diags',
description=f'{cfg.main.KIT_NAME_FULL}: Hardware Diagnostics',
)
parser.add_argument(
'-c', '--cli', action='store_true',
help='Force CLI mode',
)
parser.add_argument(
'-q', '--quick', action='store_true',
help='Skip menu and perform a quick check',
)
parser.add_argument(
'-t', '--test-mode', action='store_true',
help='Run diags in test mode',
)
args = parser.parse_args()
legacy_args = {
'--cli': args.cli,
'--quick': args.quick,
'--test-mode': args.test_mode,
}
return legacy_args
def build_menu(cli_mode=False, quick_mode=False) -> cli.Menu: def build_menu(cli_mode=False, quick_mode=False) -> cli.Menu:
"""Build main menu, returns wk.ui.cli.Menu.""" """Build main menu, returns wk.ui.cli.Menu."""
menu = cli.Menu(title='') menu = cli.Menu(title='')
@ -306,9 +286,7 @@ def build_menu(cli_mode=False, quick_mode=False) -> cli.Menu:
# Skip CPU tests for TestStations # Skip CPU tests for TestStations
if os.path.exists(cfg.hw.TESTSTATION_FILE): if os.path.exists(cfg.hw.TESTSTATION_FILE):
menu.options['CPU (Sysbench)']['Selected'] = False menu.options['CPU & Cooling']['Selected'] = False
menu.options['CPU (Prime95)']['Selected'] = False
menu.options['CPU (Cooling)']['Selected'] = False
# Add CLI actions if necessary # Add CLI actions if necessary
if cli_mode or 'DISPLAY' not in os.environ: if cli_mode or 'DISPLAY' not in os.environ:
@ -334,213 +312,140 @@ def build_menu(cli_mode=False, quick_mode=False) -> cli.Menu:
return menu return menu
def cpu_tests_init(state: State) -> None: def cpu_stress_tests(state, test_objects, test_mode=False) -> None:
"""Initialize CPU tests.""" """CPU & cooling check using Prime95 and Sysbench."""
LOG.info('CPU Test (Prime95)')
aborted = False
prime_log = pathlib.Path(f'{state.log_dir}/prime.log')
run_sysbench = False
sensors_out = pathlib.Path(f'{state.log_dir}/sensors.out') sensors_out = pathlib.Path(f'{state.log_dir}/sensors.out')
state.update_title_text(state.system.cpu_description) test_minutes = cfg.hw.CPU_TEST_MINUTES
if test_mode:
test_minutes = cfg.hw.TEST_MODE_CPU_LIMIT
test_mprime_obj, test_cooling_obj = test_objects
# Start monitor # Bail early
if test_cooling_obj.disabled or test_mprime_obj.disabled:
return
# Prep
state.update_title_text(test_mprime_obj.dev.cpu_description)
test_cooling_obj.set_status('Working')
test_mprime_obj.set_status('Working')
# Start sensors monitor
sensors = hw_sensors.Sensors()
sensors.start_background_monitor(
sensors_out,
thermal_action=('killall', 'mprime', '-INT'),
)
# Create monitor and worker panes
state.update_progress_file()
state.ui.add_worker_pane(lines=10, watch_cmd='tail', watch_file=prime_log)
if PLATFORM == 'Darwin': if PLATFORM == 'Darwin':
state.ui.add_info_pane( state.ui.add_info_pane(
percent=80, cmd='./hw-sensors', update_layout=False, percent=80, cmd='./hw-sensors', update_layout=False,
) )
elif PLATFORM == 'Linux': elif PLATFORM == 'Linux':
state.ui.add_info_pane( state.ui.add_info_pane(
percent=80, percent=80, watch_file=sensors_out, update_layout=False,
watch_file=pathlib.Path(f'{state.log_dir}/sensors.out'),
update_layout=False,
) )
state.sensors.start_background_monitor(sensors_out)
state.ui.set_current_pane_height(3) state.ui.set_current_pane_height(3)
# Save idle temps # Get idle temps
cli.print_standard('Saving idle temps...') cli.print_standard('Saving idle temps...')
state.sensors.save_average_temps(temp_label='Idle', seconds=5, save_history=False) sensors.save_average_temps(temp_label='Idle', seconds=5)
# Stress CPU
def cpu_tests_end(state: State) -> None:
"""End CPU tests."""
# Cleanup
state.sensors.clear_temps(next_label='Done')
state.sensors.stop_background_monitor()
state.ui.clear_current_pane_height()
state.ui.remove_all_info_panes()
state.ui.remove_all_worker_panes()
def cpu_test_cooling(state: State, test_object, test_mode=False) -> None:
"""CPU cooling test via sensor data assessment."""
_ = test_mode
LOG.info('CPU Test (Cooling)')
# Bail early
if test_object.disabled:
return
hw_cpu.check_cooling_results(state.sensors, test_object)
state.update_progress_file()
def cpu_test_mprime(state: State, test_object, test_mode=False) -> None:
"""CPU stress test using mprime."""
LOG.info('CPU Test (Prime95)')
aborted = False
log_path = pathlib.Path(f'{state.log_dir}/prime.log')
sensors_out = pathlib.Path(f'{state.log_dir}/sensors.out')
test_minutes = cfg.hw.CPU_TEST_MINUTES
if test_mode:
test_minutes = cfg.hw.TEST_MODE_CPU_LIMIT
# Bail early
if test_object.disabled:
return
if state.sensors.cpu_reached_critical_temp():
test_object.set_status('Denied')
test_object.disabled = True
return
# Prep
test_object.set_status('Working')
state.update_progress_file()
state.ui.clear_current_pane()
cli.print_info('Running stress test') cli.print_info('Running stress test')
print('')
# Start sensors monitor
state.sensors.clear_temps(next_label='Prime95')
state.sensors.stop_background_monitor()
state.sensors.start_background_monitor(
sensors_out,
alt_max='Prime95',
thermal_action=('killall', '-INT', 'mprime'),
)
# Run Prime95
hw_cpu.set_apple_fan_speed('max') hw_cpu.set_apple_fan_speed('max')
proc = hw_cpu.start_mprime(state.log_dir, log_path) proc_mprime = hw_cpu.start_mprime(state.log_dir, prime_log)
state.ui.add_worker_pane(lines=10, watch_cmd='tail', watch_file=log_path)
# Show countdown
print('')
try: try:
print_countdown(proc=proc, seconds=test_minutes*60) print_countdown(proc=proc_mprime, seconds=test_minutes*60)
except KeyboardInterrupt: except KeyboardInterrupt:
aborted = True aborted = True
# Stop Prime95 # Stop Prime95
hw_cpu.stop_mprime(proc) hw_cpu.stop_mprime(proc_mprime)
# Update progress if necessary
if sensors.cpu_reached_critical_temp() or aborted:
test_cooling_obj.set_status('Aborted')
test_mprime_obj.set_status('Aborted')
state.update_progress_file()
# Get cooldown temp # Get cooldown temp
if 'Cooldown' in state.sensors.temp_labels: state.ui.clear_current_pane()
# Give Prime95 time to save the results cli.print_standard('Letting CPU cooldown...')
std.sleep(1) std.sleep(5)
state.sensors.clear_temps(next_label='Cooldown') cli.print_standard('Saving cooldown temps...')
else: sensors.save_average_temps(temp_label='Cooldown', seconds=5)
# Save cooldown temp
state.ui.clear_current_pane()
cli.print_standard('Letting CPU cooldown...')
std.sleep(5)
cli.print_standard('Saving cooldown temps...')
state.sensors.save_average_temps(temp_label='Cooldown', seconds=5)
# Check Prime95 results # Check Prime95 results
test_object.report.append(ansi.color_string('Prime95', 'BLUE')) test_mprime_obj.report.append(ansi.color_string('Prime95', 'BLUE'))
hw_cpu.check_mprime_results(test_obj=test_object, working_dir=state.log_dir) hw_cpu.check_mprime_results(
test_obj=test_mprime_obj, working_dir=state.log_dir,
# Update progress
if state.sensors.cpu_reached_critical_temp() or aborted:
test_object.set_status('Aborted')
state.update_progress_file()
# Done
state.ui.remove_all_worker_panes()
if aborted:
cpu_tests_end(state)
raise std.GenericAbort('Aborted')
def cpu_test_sysbench(state: State, test_object, test_mode=False) -> None:
"""CPU stress test using Sysbench."""
LOG.info('CPU Test (Sysbench)')
aborted = False
log_path = pathlib.Path(f'{state.log_dir}/sysbench.log')
sensors_out = pathlib.Path(f'{state.log_dir}/sensors.out')
test_minutes = cfg.hw.CPU_TEST_MINUTES
if test_mode:
test_minutes = cfg.hw.TEST_MODE_CPU_LIMIT
# Bail early
if test_object.disabled:
return
# Prep
test_object.set_status('Working')
state.update_progress_file()
state.ui.clear_current_pane()
cli.print_info('Running stress test')
print('')
# Start sensors monitor
state.sensors.clear_temps(next_label='Sysbench')
state.sensors.stop_background_monitor()
state.sensors.start_background_monitor(
sensors_out,
alt_max='Sysbench',
thermal_action=('killall', '-INT', 'sysbench'),
) )
# Run sysbench # Run Sysbench test if necessary
state.ui.add_worker_pane(lines=10, watch_cmd='tail', watch_file=log_path) run_sysbench = (
proc, filehandle = hw_cpu.start_sysbench(log_path=log_path) not aborted and sensors.cpu_max_temp() >= cfg.hw.CPU_FAILURE_TEMP
try: )
print_countdown(proc=proc, seconds=test_minutes*60) if run_sysbench:
except AttributeError: LOG.info('CPU Test (Sysbench)')
# Assuming the sysbench process wasn't found and proc was set to None cli.print_standard('Letting CPU cooldown more...')
LOG.error('Failed to find sysbench process', exc_info=True) std.sleep(10)
except KeyboardInterrupt:
aborted = True
hw_cpu.stop_sysbench(proc, filehandle)
# Get cooldown temp
if 'Cooldown' in state.sensors.temp_labels:
state.sensors.clear_temps(next_label='Cooldown')
else:
state.ui.clear_current_pane() state.ui.clear_current_pane()
cli.print_standard('Letting CPU cooldown...') cli.print_info('Running alternate stress test')
std.sleep(5) print('')
cli.print_standard('Saving cooldown temps...') sysbench_log = prime_log.with_name('sysbench.log')
state.sensors.save_average_temps(temp_label='Cooldown', seconds=5) sysbench_log.touch()
state.ui.remove_all_worker_panes()
# Update progress state.ui.add_worker_pane(lines=10, watch_cmd='tail', watch_file=sysbench_log)
test_object.report.append(ansi.color_string('Sysbench', 'BLUE')) proc_sysbench, filehandle_sysbench = hw_cpu.start_sysbench(
if aborted: sensors,
test_object.set_status('Aborted') sensors_out,
test_object.report.append(ansi.color_string(' Aborted.', 'YELLOW')) log_path=sysbench_log,
state.update_progress_file()
elif state.sensors.cpu_reached_critical_temp():
test_object.set_status('Aborted')
test_object.report.append(
ansi.color_string(' Aborted due to temps.', 'YELLOW'),
) )
elif proc.returncode not in (-15, -2, 0): try:
# NOTE: Return codes: print_countdown(proc=proc_sysbench, seconds=test_minutes*60)
# 0 == Completed w/out issue except AttributeError:
# -2 == Stopped with INT signal # Assuming the sysbench process wasn't found and proc was set to None
# -15 == Stopped with TERM signal LOG.error('Failed to find sysbench process', exc_info=True)
test_object.set_status('Failed') except KeyboardInterrupt:
test_object.report.append(f' Failed with return code: {proc.returncode}') aborted = True
else: hw_cpu.stop_sysbench(proc_sysbench, filehandle_sysbench)
test_object.set_status('Passed')
test_object.report.append(' Completed without issue.') # Update progress
# NOTE: CPU critical temp check isn't really necessary
# Hard to imagine it wasn't hit during Prime95 but was in sysbench
if sensors.cpu_reached_critical_temp() or aborted:
test_cooling_obj.set_status('Aborted')
test_mprime_obj.set_status('Aborted')
state.update_progress_file()
# Check Cooling results
test_cooling_obj.report.append(ansi.color_string('Temps', 'BLUE'))
hw_cpu.check_cooling_results(test_cooling_obj, sensors, run_sysbench)
# Cleanup
state.update_progress_file() state.update_progress_file()
sensors.stop_background_monitor()
state.ui.clear_current_pane_height()
state.ui.remove_all_info_panes()
state.ui.remove_all_worker_panes()
# Done # Done
state.ui.remove_all_worker_panes()
if aborted: if aborted:
cpu_tests_end(state)
raise std.GenericAbort('Aborted') raise std.GenericAbort('Aborted')
def disk_attribute_check(state: State, test_objects, test_mode=False) -> None: def disk_attribute_check(state, test_objects, test_mode=False) -> None:
"""Disk attribute check.""" """Disk attribute check."""
_ = test_mode
LOG.info('Disk Attribute Check') LOG.info('Disk Attribute Check')
for test in test_objects: for test in test_objects:
disk_smart_status_check(test.dev, mid_run=False) disk_smart_status_check(test.dev, mid_run=False)
@ -616,9 +521,8 @@ def disk_io_benchmark(
raise std.GenericAbort('Aborted') raise std.GenericAbort('Aborted')
def disk_self_test(state: State, test_objects, test_mode=False) -> None: def disk_self_test(state, test_objects, test_mode=False) -> None:
"""Disk self-test if available.""" """Disk self-test if available."""
_ = test_mode
LOG.info('Disk Self-Test(s)') LOG.info('Disk Self-Test(s)')
aborted = False aborted = False
threads = [] threads = []
@ -709,7 +613,7 @@ def disk_smart_status_check(dev, mid_run=True) -> None:
dev.disable_disk_tests() dev.disable_disk_tests()
def disk_surface_scan(state: State, test_objects, test_mode=False) -> None: def disk_surface_scan(state, test_objects, test_mode=False) -> None:
"""Read-only disk surface scan using badblocks.""" """Read-only disk surface scan using badblocks."""
LOG.info('Disk Surface Scan (badblocks)') LOG.info('Disk Surface Scan (badblocks)')
aborted = False aborted = False
@ -765,12 +669,7 @@ def disk_surface_scan(state: State, test_objects, test_mode=False) -> None:
def main() -> None: def main() -> None:
"""Main function for hardware diagnostics.""" """Main function for hardware diagnostics."""
try: args = docopt(DOCSTRING)
args = argparse_helper()
except SystemExit:
print('')
cli.pause('Press Enter to exit...')
raise
log.update_log_path(dest_name='Hardware-Diagnostics', timestamp=True) log.update_log_path(dest_name='Hardware-Diagnostics', timestamp=True)
# Safety check # Safety check
@ -866,18 +765,8 @@ def print_countdown(proc, seconds) -> None:
# Done # Done
print('') print('')
def run_cpu_tests(state: State, test_objects, test_mode=False) -> None:
"""Run selected CPU test(s)."""
state.update_progress_file()
cpu_tests_init(state)
for obj in test_objects:
func = globals()[TEST_GROUPS[obj.name]]
func(state, obj, test_mode=test_mode)
cpu_tests_end(state)
state.update_progress_file()
def run_diags(state, menu, quick_mode=False, test_mode=False) -> None:
def run_diags(state: State, menu, quick_mode=False, test_mode=False) -> None:
"""Run selected diagnostics.""" """Run selected diagnostics."""
aborted = False aborted = False
atexit.register(state.save_debug_reports) atexit.register(state.save_debug_reports)
@ -930,7 +819,7 @@ def run_diags(state: State, menu, quick_mode=False, test_mode=False) -> None:
cli.pause('Press Enter to return to main menu...') cli.pause('Press Enter to return to main menu...')
def show_failed_attributes(state: State) -> None: def show_failed_attributes(state) -> None:
"""Show failed attributes for all disks.""" """Show failed attributes for all disks."""
for dev in state.disks: for dev in state.disks:
cli.print_colored([dev.name, dev.description], ['CYAN', None]) cli.print_colored([dev.name, dev.description], ['CYAN', None])
@ -940,7 +829,7 @@ def show_failed_attributes(state: State) -> None:
cli.print_standard('') cli.print_standard('')
def show_results(state: State) -> None: def show_results(state) -> None:
"""Show test results by device.""" """Show test results by device."""
std.sleep(0.5) std.sleep(0.5)
state.ui.clear_current_pane() state.ui.clear_current_pane()

View file

@ -1,6 +1,7 @@
"""WizardKit: Disk object and functions""" """WizardKit: Disk object and functions"""
# vim: sts=2 sw=2 ts=2 # vim: sts=2 sw=2 ts=2
import copy
import logging import logging
import pathlib import pathlib
import platform import platform
@ -11,6 +12,7 @@ from dataclasses import dataclass, field
from typing import Any from typing import Any
from wk.cfg.main import KIT_NAME_SHORT from wk.cfg.main import KIT_NAME_SHORT
from wk.cfg.python import DATACLASS_DECORATOR_KWARGS
from wk.exe import get_json_from_command, run_program from wk.exe import get_json_from_command, run_program
from wk.hw.test import Test from wk.hw.test import Test
from wk.hw.smart import ( from wk.hw.smart import (
@ -30,7 +32,7 @@ WK_LABEL_REGEX = re.compile(
# Classes # Classes
@dataclass(slots=True) @dataclass(**DATACLASS_DECORATOR_KWARGS)
class Disk: class Disk:
"""Object for tracking disk specific data.""" """Object for tracking disk specific data."""
attributes: dict[Any, dict] = field(init=False, default_factory=dict) attributes: dict[Any, dict] = field(init=False, default_factory=dict)
@ -38,7 +40,7 @@ class Disk:
children: list[dict] = field(init=False, default_factory=list) children: list[dict] = field(init=False, default_factory=list)
description: str = field(init=False) description: str = field(init=False)
filesystem: str = field(init=False) filesystem: str = field(init=False)
initial_attributes: dict[Any, dict] = field(init=False, default_factory=dict) initial_attributes: dict[Any, dict] = field(init=False)
known_attributes: dict[Any, dict] = field(init=False, default_factory=dict) known_attributes: dict[Any, dict] = field(init=False, default_factory=dict)
log_sec: int = field(init=False) log_sec: int = field(init=False)
model: str = field(init=False) model: str = field(init=False)
@ -55,12 +57,19 @@ class Disk:
ssd: bool = field(init=False) ssd: bool = field(init=False)
tests: list[Test] = field(init=False, default_factory=list) tests: list[Test] = field(init=False, default_factory=list)
trim: bool = field(init=False) trim: bool = field(init=False)
use_sat: bool = field(init=False, default=False)
def __post_init__(self): def __post_init__(self):
self.path = pathlib.Path(self.path_str).resolve() self.path = pathlib.Path(self.path_str).resolve()
self.update_details() self.update_details()
self.set_description() self.set_description()
self.known_attributes = get_known_disk_attributes(self.model) self.known_attributes = get_known_disk_attributes(self.model)
if not self.attributes and self.bus == 'USB':
# Try using SAT
LOG.warning('Using SAT for smartctl for %s', self.path)
self.notes = []
self.use_sat = True
self.initial_attributes = copy.deepcopy(self.attributes)
if not self.is_4k_aligned(): if not self.is_4k_aligned():
self.add_note('One or more partitions are not 4K aligned', 'YELLOW') self.add_note('One or more partitions are not 4K aligned', 'YELLOW')

View file

@ -6,12 +6,11 @@ import logging
import pathlib import pathlib
import re import re
from copy import deepcopy
from subprocess import CalledProcessError from subprocess import CalledProcessError
from threading import Thread from threading import Thread
from typing import Any from typing import Any
from wk.cfg.hw import CPU_TEMPS, SMC_IDS, TEMP_COLORS from wk.cfg.hw import CPU_CRITICAL_TEMP, SMC_IDS, TEMP_COLORS
from wk.exe import run_program, start_thread from wk.exe import run_program, start_thread
from wk.io import non_clobber_path from wk.io import non_clobber_path
from wk.std import PLATFORM, sleep from wk.std import PLATFORM, sleep
@ -37,83 +36,39 @@ class ThermalLimitReachedError(RuntimeError):
# Classes # Classes
class Sensors(): class Sensors():
"""Class for holding sensor specific data. """Class for holding sensor specific data."""
# Sensor data structure
#
# Section # CPUTemps / Other
# Adapters # coretemp / acpi / nvme / etc
# Sources # Core 1 / SODIMM / Sensor X / etc
# Label # temp1_input / etc (i.e. lm_sensor label)
# Max # 99.0
# X # 55.0 (where X is Idle/Current/Sysbench/etc)
# Temps # [39.0, 38.0, 40.0, 39.0, 38.0, ...]
#
# e.g.
# { 'CPUTemps': { 'coretemp-isa-0000': { 'Core 0': { 'Average': 44.5,
# 'Current': 44.0,
# 'Idle': 44.5,
# 'Label': 'temp2_input',
# 'Max': 45.0,
# 'Temps': [ 45.0,
# 45.0,
# ...,
# 42.0]}}}}
#
# Sensor history data structure
# [ ('Name of "run"', sensor_data_structure_described_above), ]
#
# e.g.
# [
# ( 'Idle',
# { 'CPUTemps': { 'coretemp-isa-0000': { 'Core 0': { 'Max': 45.0, ..., }}}}
# ),
# ( 'Sysbench',
# { 'CPUTemps': { 'coretemp-isa-0000': { 'Core 0': { 'Max': 85.0, ..., }}}}
# ),
# ]
"""
def __init__(self): def __init__(self):
self.background_thread: Thread | None = None self.background_thread: Thread | None = None
self.data: dict[Any, Any] = get_sensor_data() self.data: dict[Any, Any] = get_sensor_data()
self.history: list[tuple[str, dict]] = []
self.history_index: dict[str, int] = {}
self.history_next_label: str = 'Idle'
self.out_path: pathlib.Path | str | None = None self.out_path: pathlib.Path | str | None = None
self.temp_labels: set = set(['Current', 'Max'])
def clear_temps(self, next_label: str, save_history: bool = True) -> None: def clear_temps(self) -> None:
"""Clear saved temps but keep structure""" """Clear saved temps but keep structure"""
prev_label = self.history_next_label
self.history_next_label = next_label
# Save history
if save_history:
cur_data = deepcopy(self.data)
# Calculate averages
for adapters in cur_data.values():
for sources in adapters.values():
for name in sources:
temp_list = sources[name]['Temps']
try:
sources[name]['Average'] = sum(temp_list) / len(temp_list)
except ZeroDivisionError:
LOG.error('Failed to calculate averate temp for %s', name)
sources[name]['Average'] = 0
# Add to history
self.history.append((prev_label, cur_data))
self.history_index[prev_label] = len(self.history) - 1
# Clear data
for adapters in self.data.values(): for adapters in self.data.values():
for sources in adapters.values(): for sources in adapters.values():
for source_data in sources.values(): for source_data in sources.values():
source_data['Temps'] = [] source_data['Temps'] = []
def cpu_max_temp(self) -> float:
"""Get max temp from any CPU source, returns float.
NOTE: If no temps are found this returns zero.
"""
max_temp = 0.0
# Check all CPU Temps
for section, adapters in self.data.items():
if not section.startswith('CPU'):
continue
for sources in adapters.values():
for source_data in sources.values():
max_temp = max(max_temp, source_data.get('Max', 0))
# Done
return max_temp
def cpu_reached_critical_temp(self) -> bool: def cpu_reached_critical_temp(self) -> bool:
"""Check if CPU exceeded critical temp, returns bool.""" """Check if CPU reached CPU_CRITICAL_TEMP, returns bool."""
for section, adapters in self.data.items(): for section, adapters in self.data.items():
if not section.startswith('CPU'): if not section.startswith('CPU'):
# Limit to CPU temps # Limit to CPU temps
@ -122,22 +77,16 @@ class Sensors():
# Ugly section # Ugly section
for sources in adapters.values(): for sources in adapters.values():
for source_data in sources.values(): for source_data in sources.values():
if source_data.get('Max', -1) > CPU_TEMPS['Critical']: if source_data.get('Max', -1) >= CPU_CRITICAL_TEMP:
return True return True
# Didn't return above so temps are within the threshold # Didn't return above so temps are within the threshold
return False return False
def generate_report( def generate_report(
self, self, *temp_labels, colored=True, only_cpu=False) -> list[str]:
*temp_labels: str,
colored: bool = True,
only_cpu: bool = False,
include_avg_for: list[str] | None = None,
) -> list[str]:
"""Generate report based on given temp_labels, returns list.""" """Generate report based on given temp_labels, returns list."""
report = [] report = []
include_avg_for = include_avg_for if include_avg_for else []
for section, adapters in sorted(self.data.items()): for section, adapters in sorted(self.data.items()):
if only_cpu and not section.startswith('CPU'): if only_cpu and not section.startswith('CPU'):
@ -151,10 +100,6 @@ class Sensors():
for label in temp_labels: for label in temp_labels:
if label != 'Current': if label != 'Current':
line += f' {label.lower()}: ' line += f' {label.lower()}: '
if label in include_avg_for:
avg_temp = self.get_avg_temp(
label, section, adapter, source, colored)
line += f'{avg_temp} / '
line += get_temp_str( line += get_temp_str(
source_data.get(label, '???'), source_data.get(label, '???'),
colored=colored, colored=colored,
@ -174,32 +119,6 @@ class Sensors():
# Done # Done
return report return report
def get_avg_temp(self, label, section, adapter, source, colored) -> str:
"""Get average temp from history, return str."""
# NOTE: This is Super-ugly
label_index = self.history_index[label]
avg_temp = self.history[label_index][1][section][adapter][source]['Average']
return get_temp_str(avg_temp, colored=colored)
def get_cpu_temp(self, label) -> float:
"""Get temp for label from any CPU source, returns float.
NOTE: This returns the highest value for the label.
NOTE 2: If no temps are found this returns zero.
"""
max_temp = 0.0
# Check all CPU Temps
for section, adapters in self.data.items():
if not section.startswith('CPU'):
continue
for sources in adapters.values():
for source_data in sources.values():
max_temp = max(max_temp, source_data.get(label, 0))
# Done
return float(max_temp)
def monitor_to_file( def monitor_to_file(
self, out_path, alt_max=None, self, out_path, alt_max=None,
exit_on_thermal_limit=True, temp_labels=None, exit_on_thermal_limit=True, temp_labels=None,
@ -217,7 +136,6 @@ class Sensors():
temp_labels = ['Current', 'Max'] temp_labels = ['Current', 'Max']
if alt_max: if alt_max:
temp_labels.append(alt_max) temp_labels.append(alt_max)
self.temp_labels.add(alt_max)
# Start loop # Start loop
while True: while True:
@ -237,15 +155,9 @@ class Sensors():
# Sleep before next loop # Sleep before next loop
sleep(0.5) sleep(0.5)
def save_average_temps( def save_average_temps(self, temp_label, seconds=10) -> None:
self,
temp_label: str,
seconds: int = 10,
save_history: bool = True,
) -> None:
"""Save average temps under temp_label over provided seconds..""" """Save average temps under temp_label over provided seconds.."""
self.clear_temps(next_label=temp_label, save_history=save_history) self.clear_temps()
self.temp_labels.add(temp_label)
# Get temps # Get temps
for _ in range(seconds): for _ in range(seconds):
@ -288,10 +200,6 @@ class Sensors():
def stop_background_monitor(self) -> None: def stop_background_monitor(self) -> None:
"""Stop background thread.""" """Stop background thread."""
# Bail early
if self.background_thread is None:
return
self.out_path.with_suffix('.stop').touch() self.out_path.with_suffix('.stop').touch()
self.background_thread.join() self.background_thread.join()
@ -302,8 +210,6 @@ class Sensors():
def update_sensor_data( def update_sensor_data(
self, alt_max=None, exit_on_thermal_limit=True) -> None: self, alt_max=None, exit_on_thermal_limit=True) -> None:
"""Update sensor data via OS-specific means.""" """Update sensor data via OS-specific means."""
if alt_max:
self.temp_labels.add(alt_max)
if PLATFORM == 'Darwin': if PLATFORM == 'Darwin':
self.update_sensor_data_macos(alt_max, exit_on_thermal_limit) self.update_sensor_data_macos(alt_max, exit_on_thermal_limit)
elif PLATFORM == 'Linux': elif PLATFORM == 'Linux':
@ -330,7 +236,7 @@ class Sensors():
# Raise exception if thermal limit reached # Raise exception if thermal limit reached
if exit_on_thermal_limit and section == 'CPUTemps': if exit_on_thermal_limit and section == 'CPUTemps':
if source_data['Current'] > CPU_TEMPS['Critical']: if source_data['Current'] >= CPU_CRITICAL_TEMP:
raise ThermalLimitReachedError('CPU temps reached limit') raise ThermalLimitReachedError('CPU temps reached limit')
def update_sensor_data_macos( def update_sensor_data_macos(
@ -357,7 +263,7 @@ class Sensors():
# Raise exception if thermal limit reached # Raise exception if thermal limit reached
if exit_on_thermal_limit and section == 'CPUTemps': if exit_on_thermal_limit and section == 'CPUTemps':
if source_data['Current'] > CPU_TEMPS['Critical']: if source_data['Current'] >= CPU_CRITICAL_TEMP:
raise ThermalLimitReachedError('CPU temps reached limit') raise ThermalLimitReachedError('CPU temps reached limit')
@ -514,7 +420,7 @@ def get_sensor_data_macos() -> dict[Any, Any]:
def get_temp_str(temp, colored=True) -> str: def get_temp_str(temp, colored=True) -> str:
"""Get colored string based on temp, returns str.""" """Get colored string based on temp, returns str."""
temp_color = '' temp_color = None
# Safety check # Safety check
try: try:

View file

@ -104,7 +104,7 @@ def enable_smart(dev) -> None:
cmd = [ cmd = [
'sudo', 'sudo',
'smartctl', 'smartctl',
'--device=auto', f'--device={"sat,auto" if dev.use_sat else "auto"}',
'--tolerance=permissive', '--tolerance=permissive',
'--smart=on', '--smart=on',
dev.path, dev.path,
@ -461,7 +461,7 @@ def update_smart_details(dev) -> None:
cmd = [ cmd = [
'sudo', 'sudo',
'smartctl', 'smartctl',
'--device=auto', f'--device={"sat,auto" if dev.use_sat else "auto"}',
'--tolerance=verypermissive', '--tolerance=verypermissive',
'--all', '--all',
'--json', '--json',
@ -506,10 +506,6 @@ def update_smart_details(dev) -> None:
if not updated_attributes: if not updated_attributes:
dev.add_note('No NVMe or SMART data available', 'YELLOW') dev.add_note('No NVMe or SMART data available', 'YELLOW')
# Update iniital_attributes if needed
if not dev.initial_attributes:
dev.initial_attributes = copy.deepcopy(updated_attributes)
# Done # Done
dev.attributes.update(updated_attributes) dev.attributes.update(updated_attributes)

View file

@ -9,6 +9,7 @@ from dataclasses import dataclass, field
from typing import Any from typing import Any
from wk.cfg.hw import KNOWN_RAM_VENDOR_IDS from wk.cfg.hw import KNOWN_RAM_VENDOR_IDS
from wk.cfg.python import DATACLASS_DECORATOR_KWARGS
from wk.exe import get_json_from_command, run_program from wk.exe import get_json_from_command, run_program
from wk.hw.test import Test from wk.hw.test import Test
from wk.std import PLATFORM, bytes_to_string, string_to_bytes from wk.std import PLATFORM, bytes_to_string, string_to_bytes
@ -19,7 +20,7 @@ from wk.ui import ansi
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@dataclass(slots=True) @dataclass(**DATACLASS_DECORATOR_KWARGS)
class System: class System:
"""Object for tracking system specific hardware data.""" """Object for tracking system specific hardware data."""
cpu_description: str = field(init=False) cpu_description: str = field(init=False)

View file

@ -4,7 +4,9 @@
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any, Callable from typing import Any, Callable
@dataclass(slots=True) from wk.cfg.python import DATACLASS_DECORATOR_KWARGS
@dataclass(**DATACLASS_DECORATOR_KWARGS)
class Test: class Test:
"""Object for tracking test specific data.""" """Object for tracking test specific data."""
dev: Any dev: Any
@ -12,6 +14,7 @@ class Test:
name: str name: str
disabled: bool = field(init=False, default=False) disabled: bool = field(init=False, default=False)
failed: bool = field(init=False, default=False) failed: bool = field(init=False, default=False)
hidden: bool = False
passed: bool = field(init=False, default=False) passed: bool = field(init=False, default=False)
report: list[str] = field(init=False, default_factory=list) report: list[str] = field(init=False, default_factory=list)
status: str = field(init=False, default='Pending') status: str = field(init=False, default='Pending')
@ -25,7 +28,7 @@ class Test:
self.status = status self.status = status
@dataclass(slots=True) @dataclass(**DATACLASS_DECORATOR_KWARGS)
class TestGroup: class TestGroup:
"""Object for tracking groups of tests.""" """Object for tracking groups of tests."""
name: str name: str

View file

@ -43,7 +43,7 @@ def case_insensitive_search(
path = pathlib.Path(path).resolve() path = pathlib.Path(path).resolve()
given_path = path.joinpath(item) given_path = path.joinpath(item)
real_path = None real_path = None
regex = fr'^{item}$' regex = fr'^{item}'
# Quick check # Quick check
if given_path.exists(): if given_path.exists():

View file

@ -162,29 +162,6 @@ def download_bluescreenview() -> None:
delete_from_temp('bluescreenview64.zip') delete_from_temp('bluescreenview64.zip')
def download_ddu() -> None:
"""Download Display Driver Uninstaller."""
archive = download_to_temp('DDU.exe', SOURCES['DDU'])
out_path = BIN_DIR.joinpath('DDU')
extract_archive(archive, out_path, 'DDU*/*.*', mode='e')
out_path = out_path.joinpath('Settings')
for item in ('AMD', 'INTEL', 'Languages', 'NVIDIA', 'REALTEK'):
extract_archive(
archive,
out_path.joinpath(item),
f'DDU*/Settings/{item}/*',
mode='e',
)
delete_from_temp('DDU.exe')
def download_bcuninstaller() -> None:
"""Download Bulk Crap Uninstaller."""
archive = download_to_temp('BCU.zip', SOURCES['BCUninstaller'])
extract_to_bin(archive, 'BCUninstaller')
delete_from_temp('BCU.zip')
def download_erunt() -> None: def download_erunt() -> None:
"""Download ERUNT.""" """Download ERUNT."""
archive = download_to_temp('erunt.zip', SOURCES['ERUNT']) archive = download_to_temp('erunt.zip', SOURCES['ERUNT'])
@ -372,6 +349,21 @@ def download_snappy_driver_installer_origin() -> None:
delete_from_temp('fake.7z') delete_from_temp('fake.7z')
def download_uninstallview() -> None:
"""Download UninstallView."""
archive_32 = download_to_temp('uninstallview32.zip', SOURCES['UninstallView32'])
archive_64 = download_to_temp('uninstallview64.zip', SOURCES['UninstallView64'])
out_path = BIN_DIR.joinpath('UninstallView')
extract_archive(archive_64, out_path, 'UninstallView.exe')
rename_item(
out_path.joinpath('UninstallView.exe'),
out_path.joinpath('UninstallView64.exe'),
)
extract_archive(archive_32, out_path)
delete_from_temp('uninstallview32.zip')
delete_from_temp('uninstallview64.zip')
def download_wiztree() -> None: def download_wiztree() -> None:
"""Download WizTree.""" """Download WizTree."""
archive = download_to_temp('wiztree.zip', SOURCES['WizTree']) archive = download_to_temp('wiztree.zip', SOURCES['WizTree'])
@ -483,8 +475,6 @@ def build_kit() -> None:
try_print.run('BleachBit...', download_bleachbit) try_print.run('BleachBit...', download_bleachbit)
try_print.run('BlueScreenView...', download_bluescreenview) try_print.run('BlueScreenView...', download_bluescreenview)
try_print.run('ERUNT...', download_erunt) try_print.run('ERUNT...', download_erunt)
try_print.run('BulkCrapUninstaller...', download_bcuninstaller)
try_print.run('DDU...', download_ddu)
try_print.run('Everything...', download_everything) try_print.run('Everything...', download_everything)
try_print.run('FastCopy...', download_fastcopy) try_print.run('FastCopy...', download_fastcopy)
try_print.run('FurMark...', download_furmark) try_print.run('FurMark...', download_furmark)
@ -496,6 +486,7 @@ def build_kit() -> None:
try_print.run('OpenShell...', download_openshell) try_print.run('OpenShell...', download_openshell)
try_print.run('PuTTY...', download_putty) try_print.run('PuTTY...', download_putty)
try_print.run('Snappy Driver Installer...', download_snappy_driver_installer_origin) try_print.run('Snappy Driver Installer...', download_snappy_driver_installer_origin)
try_print.run('UninstallView...', download_uninstallview)
try_print.run('WizTree...', download_wiztree) try_print.run('WizTree...', download_wiztree)
try_print.run('XMPlay...', download_xmplay) try_print.run('XMPlay...', download_xmplay)
try_print.run('XMPlay Music...', download_xmplay_music) try_print.run('XMPlay Music...', download_xmplay_music)

View file

@ -1,15 +1,15 @@
"""WizardKit: UFD Functions""" """WizardKit: UFD Functions"""
# vim: sts=2 sw=2 ts=2 # vim: sts=2 sw=2 ts=2
import argparse
import logging import logging
import math import math
import os import os
import pathlib import pathlib
import re
import shutil import shutil
from subprocess import CalledProcessError from subprocess import CalledProcessError
from docopt import docopt
from wk import io, log from wk import io, log
from wk.cfg.main import KIT_NAME_FULL, KIT_NAME_SHORT from wk.cfg.main import KIT_NAME_FULL, KIT_NAME_SHORT
from wk.cfg.ufd import ( from wk.cfg.ufd import (
@ -17,7 +17,6 @@ from wk.cfg.ufd import (
BOOT_FILES, BOOT_FILES,
IMAGE_BOOT_ENTRIES, IMAGE_BOOT_ENTRIES,
ITEMS, ITEMS,
ITEMS_FROM_LIVE,
ITEMS_HIDDEN, ITEMS_HIDDEN,
SOURCES, SOURCES,
) )
@ -28,6 +27,30 @@ from wk.ui import cli as ui
# STATIC VARIABLES # STATIC VARIABLES
DOCSTRING = '''WizardKit: Build UFD
Usage:
build-ufd [options] --ufd-device PATH
[--linux PATH]
[--main-kit PATH]
[--winpe PATH]
[--extra-dir PATH]
[EXTRA_IMAGES...]
build-ufd (-h | --help)
Options:
-e PATH, --extra-dir PATH
-k PATH, --main-kit PATH
-l PATH, --linux PATH
-u PATH, --ufd-device PATH
-w PATH, --winpe PATH
-d --debug Enable debug mode
-h --help Show this page
-M --use-mbr Use real MBR instead of GPT w/ Protective MBR
-F --force Bypass all confirmation messages. USE WITH EXTREME CAUTION!
-U --update Don't format device, just update
'''
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
EXTRA_IMAGES_LIST = '/mnt/UFD/arch/extra_images.list' EXTRA_IMAGES_LIST = '/mnt/UFD/arch/extra_images.list'
MIB = 1024 ** 2 MIB = 1024 ** 2
@ -36,54 +59,6 @@ UFD_LABEL = f'{KIT_NAME_SHORT}_UFD'
# Functions # Functions
def argparse_helper() -> dict[str, None|bool|str]:
"""Helper function to setup and return args, returns dict.
NOTE: A dict is used to match the legacy code.
"""
parser = argparse.ArgumentParser(
prog='build-ufd',
description=f'{KIT_NAME_FULL}: Build UFD',
)
parser.add_argument('-u', '--ufd-device', required=True)
parser.add_argument('-l', '--linux', required=False)
parser.add_argument('-e', '--extra-dir', required=False)
parser.add_argument('-k', '--main-kit', required=False)
parser.add_argument('-w', '--winpe', required=False)
parser.add_argument(
'-d', '--debug', action='store_true',
help='Enable debug mode',
)
parser.add_argument(
'-M', '--use-mbr', action='store_true',
help='Use real MBR instead of GPT w/ Protective MBR',
)
parser.add_argument(
'-F', '--force', action='store_true',
help='Bypass all confirmation messages. USE WITH EXTREME CAUTION!',
)
parser.add_argument(
'-U', '--update', action='store_true',
help="Don't format device, just update",
)
parser.add_argument(
'EXTRA_IMAGES', nargs='*',
)
args = parser.parse_args()
legacy_args = {
'--debug': args.debug,
'--extra-dir': args.extra_dir,
'--force': args.force,
'--linux': args.linux,
'--main-kit': args.main_kit,
'--ufd-device': args.ufd_device,
'--update': args.update,
'--use-mbr': args.use_mbr,
'--winpe': args.winpe,
'EXTRA_IMAGES': args.EXTRA_IMAGES,
}
return legacy_args
def apply_image(part_path, image_path, hide_macos_boot=True) -> None: def apply_image(part_path, image_path, hide_macos_boot=True) -> None:
"""Apply raw image to dev_path using dd.""" """Apply raw image to dev_path using dd."""
cmd = [ cmd = [
@ -116,12 +91,7 @@ def apply_image(part_path, image_path, hide_macos_boot=True) -> None:
def build_ufd() -> None: def build_ufd() -> None:
"""Build UFD using selected sources.""" """Build UFD using selected sources."""
try: args = docopt(DOCSTRING)
args = argparse_helper()
except SystemExit:
print('')
ui.pause('Press Enter to exit...')
raise
if args['--debug']: if args['--debug']:
log.enable_debug_mode() log.enable_debug_mode()
if args['--update'] and args['EXTRA_IMAGES']: if args['--update'] and args['EXTRA_IMAGES']:
@ -152,7 +122,7 @@ def build_ufd() -> None:
if not args['--update']: if not args['--update']:
ui.print_info('Prep UFD') ui.print_info('Prep UFD')
try_print.run( try_print.run(
message='Zeroing first 1MiB...', message='Zeroing first 64MiB...',
function=zero_device, function=zero_device,
dev_path=ufd_dev, dev_path=ufd_dev,
) )
@ -175,13 +145,6 @@ def build_ufd() -> None:
dev_path=ufd_dev, dev_path=ufd_dev,
label=UFD_LABEL, label=UFD_LABEL,
) )
try_print.run(
message='Hiding extra partition(s)...',
function=hide_extra_partitions,
dev_path=ufd_dev,
num_parts=len(extra_images),
use_mbr=args['--use-mbr'],
)
ufd_dev_first_partition = find_first_partition(ufd_dev) ufd_dev_first_partition = find_first_partition(ufd_dev)
# Mount UFD # Mount UFD
@ -207,25 +170,14 @@ def build_ufd() -> None:
message='Removing Linux...', message='Removing Linux...',
function=remove_arch, function=remove_arch,
) )
# Copy boot files
ui.print_standard(' ')
ui.print_info('Boot Files')
for s_section, s_items in ITEMS_FROM_LIVE.items():
s_section = pathlib.Path(s_section)
try_print.run(
message=f'Copying {s_section}...',
function=copy_source,
source=s_section,
items=s_items,
from_live=True,
overwrite=True,
)
os.rename('/mnt/UFD/EFI/Boot/refind_x64.efi', '/mnt/UFD/EFI/Boot/bootx64.efi')
# Copy sources # Copy sources
ui.print_standard(' ') ui.print_standard(' ')
ui.print_info('Copy Sources') ui.print_info('Copy Sources')
try_print.run(
'Copying Memtest86...', io.recursive_copy,
'/usr/share/memtest86-efi/', '/mnt/UFD/EFI/Memtest86/', overwrite=True,
)
for s_label, s_path in sources.items(): for s_label, s_path in sources.items():
try_print.run( try_print.run(
message=f'Copying {s_label}...', message=f'Copying {s_label}...',
@ -321,9 +273,9 @@ def confirm_selections(update=False) -> None:
ui.print_standard(' ') ui.print_standard(' ')
def copy_source(source, items, from_live=False, overwrite=False) -> None: def copy_source(source, items, overwrite=False) -> None:
"""Copy source items to /mnt/UFD.""" """Copy source items to /mnt/UFD."""
is_image = not from_live and (source.is_file() or source.is_block_device()) is_image = source.is_file()
items_not_found = False items_not_found = False
# Mount source if necessary # Mount source if necessary
@ -332,14 +284,7 @@ def copy_source(source, items, from_live=False, overwrite=False) -> None:
# Copy items # Copy items
for i_source, i_dest in items: for i_source, i_dest in items:
if from_live: i_source = f'{"/mnt/Source" if is_image else source}{i_source}'
# Don't prepend source
pass
elif is_image:
i_source = f'/mnt/Source{i_source}'
else:
# Prepend source
i_source = f'{source}{i_source}'
i_dest = f'/mnt/UFD{i_dest}' i_dest = f'/mnt/UFD{i_dest}'
try: try:
io.recursive_copy(i_source, i_dest, overwrite=overwrite) io.recursive_copy(i_source, i_dest, overwrite=overwrite)
@ -385,7 +330,7 @@ def create_table(dev_path, use_mbr=False, images=None) -> None:
for part, real in zip(part_sizes, images): for part, real in zip(part_sizes, images):
end = start + real end = start + real
cmd.append( cmd.append(
f'mkpart primary "fat32" {start}B {end-1}B', f'mkpart primary {"fat32" if start==MIB else "hfs+"} {start}B {end-1}B',
) )
start += part start += part
@ -471,17 +416,6 @@ def hide_items(ufd_dev_first_partition, items) -> None:
run_program(cmd, shell=True, check=False) run_program(cmd, shell=True, check=False)
def hide_extra_partitions(dev_path, num_parts, use_mbr) -> None:
if use_mbr:
# Bail early
return
for part_id in range(num_parts):
part_id += 2 # Extra partitions start at 2
cmd = ['sfdisk', '--part-attrs', dev_path, str(part_id), 'RequiredPartition,62,63']
run_program(cmd, check=False)
def install_syslinux_to_dev(ufd_dev, use_mbr) -> None: def install_syslinux_to_dev(ufd_dev, use_mbr) -> None:
"""Install Syslinux to UFD (dev).""" """Install Syslinux to UFD (dev)."""
cmd = [ cmd = [
@ -519,7 +453,6 @@ def is_valid_path(path_obj, path_type) -> bool:
valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.img' valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.img'
elif path_type == 'ISO': elif path_type == 'ISO':
valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.iso' valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.iso'
valid_path = valid_path or re.match(r'^/dev/sr\d+$', str(path_obj))
elif path_type == 'UFD': elif path_type == 'UFD':
valid_path = path_obj.is_block_device() valid_path = path_obj.is_block_device()
@ -615,7 +548,7 @@ def update_boot_entries(ufd_dev, images=None) -> None:
'sed', 'sed',
'--in-place', '--in-place',
'--regexp-extended', '--regexp-extended',
f's/___+/{uuids[0]}/', f's#archisolabel={ISO_LABEL}#archisodevice=/dev/disk/by-uuid/{uuids[0]}#',
*configs, *configs,
] ]
run_program(cmd) run_program(cmd)
@ -719,12 +652,12 @@ def verify_ufd(dev_path) -> pathlib.Path:
def zero_device(dev_path) -> None: def zero_device(dev_path) -> None:
"""Zero-out first 1MB of device.""" """Zero-out first 64MB of device."""
cmd = [ cmd = [
'sudo', 'sudo',
'dd', 'dd',
'bs=1M', 'bs=4M',
'count=1', 'count=16',
'if=/dev/zero', 'if=/dev/zero',
f'of={dev_path}', f'of={dev_path}',
] ]

View file

@ -39,21 +39,16 @@ def enable_debug_mode() -> None:
def format_log_path( def format_log_path(
log_dir: pathlib.Path | str | None = None, log_dir: None | pathlib.Path | str = None,
log_name: str | None = None, log_name: None | str = None,
append: bool = False,
kit: bool = False,
sub_dir: str | None = None,
timestamp: bool = False, timestamp: bool = False,
tool: bool = False, kit: bool = False, tool: bool = False, append: bool = False,
) -> pathlib.Path: ) -> pathlib.Path:
"""Format path based on args passed, returns pathlib.Path obj.""" """Format path based on args passed, returns pathlib.Path obj."""
log_path = pathlib.Path( log_path = pathlib.Path(
f'{log_dir if log_dir else DEFAULT_LOG_DIR}/' f'{log_dir if log_dir else DEFAULT_LOG_DIR}/'
f'{cfg.main.KIT_NAME_FULL+"/" if kit else ""}' f'{cfg.main.KIT_NAME_FULL+"/" if kit else ""}'
f'{"Tools/" if tool else ""}' f'{"Tools/" if tool else ""}'
f'{sub_dir+"_" if sub_dir else ""}'
f'{time.strftime("%Y-%m-%d_%H%M%S%z") if sub_dir else ""}/'
f'{log_name if log_name else DEFAULT_LOG_NAME}' f'{log_name if log_name else DEFAULT_LOG_NAME}'
f'{"_" if timestamp else ""}' f'{"_" if timestamp else ""}'
f'{time.strftime("%Y-%m-%d_%H%M%S%z") if timestamp else ""}' f'{time.strftime("%Y-%m-%d_%H%M%S%z") if timestamp else ""}'
@ -132,11 +127,9 @@ def start(config: dict[str, str] | None = None) -> None:
def update_log_path( def update_log_path(
dest_dir: None | pathlib.Path | str = None, dest_dir: None | pathlib.Path | str = None,
dest_name: None | str = None, dest_name: None | str = None,
append: bool = False, keep_history: bool = True, timestamp: bool = True, append: bool = False,
keep_history: bool = True,
timestamp: bool = True,
) -> None: ) -> None:
"""Moves current log file to new path and updates the root logger.""" """Moves current log file to new path and updates the root logger."""
root_logger = logging.getLogger() root_logger = logging.getLogger()

View file

@ -6,6 +6,7 @@ import logging
import os import os
import pathlib import pathlib
import platform import platform
import re
from contextlib import suppress from contextlib import suppress
from typing import Any from typing import Any
@ -73,6 +74,9 @@ KNOWN_HIVE_NAMES = {
RAM_OK = 5.5 * 1024**3 # ~6 GiB assuming a bit of shared memory RAM_OK = 5.5 * 1024**3 # ~6 GiB assuming a bit of shared memory
RAM_WARNING = 3.5 * 1024**3 # ~4 GiB assuming a bit of shared memory RAM_WARNING = 3.5 * 1024**3 # ~4 GiB assuming a bit of shared memory
REG_MSISERVER = r'HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Network\MSIServer' REG_MSISERVER = r'HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Network\MSIServer'
REGEX_4K_ALIGNMENT = re.compile(
r'^(?P<description>.*?)\s+(?P<size>\d+)\s+(?P<offset>\d+)',
)
SLMGR = pathlib.Path(f'{os.environ.get("SYSTEMROOT")}/System32/slmgr.vbs') SLMGR = pathlib.Path(f'{os.environ.get("SYSTEMROOT")}/System32/slmgr.vbs')
SYSTEMDRIVE = os.environ.get('SYSTEMDRIVE') SYSTEMDRIVE = os.environ.get('SYSTEMDRIVE')
@ -165,23 +169,29 @@ def set_timezone(zone) -> None:
# Info Functions # Info Functions
def check_4k_alignment(show_alert=False) -> list[str]: def check_4k_alignment(show_alert=False) -> list[str]:
"""Check if all partitions are 4K aligned, returns list.""" """Check if all partitions are 4K aligned, returns list."""
script_path = find_kit_dir('Scripts').joinpath('check_partition_alignment.ps1') cmd = ['WMIC', 'partition', 'get', 'Caption,Size,StartingOffset']
cmd = ['PowerShell', '-ExecutionPolicy', 'Bypass', '-File', script_path]
json_data = get_json_from_command(cmd)
report = [] report = []
show_alert = False show_alert = False
# Check offsets # Check offsets
for part in json_data: proc = run_program(cmd)
if part['StartingOffset'] % 4096 != 0: for line in proc.stdout.splitlines():
report.append( line = line.strip()
ansi.color_string( if not line or not line.startswith('Disk'):
f'{part["Name"]}' continue
f' ({bytes_to_string(part["Size"], decimals=1)})' match = REGEX_4K_ALIGNMENT.match(line)
, if not match:
'RED' LOG.error('Failed to parse partition info for: %s', line)
) continue
) if int(match.group('offset')) % 4096 != 0:
report.append(
ansi.color_string(
f'{match.group("description")}'
f' ({bytes_to_string(match.group("size"), decimals=1)})'
,
'RED'
)
)
# Show alert # Show alert
if show_alert: if show_alert:
@ -193,7 +203,6 @@ def check_4k_alignment(show_alert=False) -> list[str]:
0, 0,
ansi.color_string('One or more partitions not 4K aligned', 'YELLOW'), ansi.color_string('One or more partitions not 4K aligned', 'YELLOW'),
) )
report.sort()
return report return report
@ -215,52 +224,45 @@ def export_bitlocker_info() -> None:
_f.write(f'{proc.stdout}\n\n') _f.write(f'{proc.stdout}\n\n')
def get_installed_antivirus() -> dict[str, dict]: def get_installed_antivirus() -> list[str]:
"""Get installed antivirus products and their status, returns dict."""
script_path = find_kit_dir('Scripts').joinpath('check_av.ps1')
cmd = ['PowerShell', '-ExecutionPolicy', 'Bypass', '-File', script_path]
json_data = get_json_from_command(cmd)
products = {}
# Check state and build dict
for p in json_data:
name = p['displayName']
state = p['productState']
enabled = ((state>>8) & 0x11) in (0x10, 0x11) # middle two hex digits
outdated = (state & 0x11) != 0x00 # last two hex digits
products[name] = {
'Enabled': enabled,
'Outdated': outdated,
'State': state,
}
return products
def list_installed_antivirus() -> list[str]:
"""Get list of installed antivirus programs, returns list.""" """Get list of installed antivirus programs, returns list."""
products = get_installed_antivirus() cmd = [
products_active = [] 'WMIC', r'/namespace:\\root\SecurityCenter2',
products_inactive = [] 'path', 'AntivirusProduct',
'get', 'displayName', '/value',
]
products = []
report = []
# Get list of products
proc = run_program(cmd)
for line in proc.stdout.splitlines():
line = line.strip()
if '=' in line:
products.append(line.split('=')[1])
# Check product(s) status # Check product(s) status
for name, details in products.items(): for product in sorted(products):
if details['Enabled']: cmd = [
if details['Outdated']: 'WMIC', r'/namespace:\\root\SecurityCenter2',
products_active.append(ansi.color_string(f'{name} [OUTDATED]', 'YELLOW')) 'path', 'AntivirusProduct',
else: 'where', f'displayName="{product}"',
products_active.append(name) 'get', 'productState', '/value',
]
proc = run_program(cmd)
state = proc.stdout.split('=')[1]
state = hex(int(state))
if str(state)[3:5] not in ['10', '11']:
report.append(ansi.color_string(f'[Disabled] {product}', 'YELLOW'))
else: else:
# Disabled report.append(product)
products_inactive.append(ansi.color_string(f'[Disabled] {name}', 'YELLOW'))
# Final check # Final check
if not (products_active or products_inactive): if not report:
products_inactive.append(ansi.color_string('No products detected', 'RED')) report.append(ansi.color_string('No products detected', 'RED'))
# Done # Done
products_active.sort() return report
products_inactive.sort()
return products_active + products_inactive
def get_installed_ram(as_list=False, raise_exceptions=False) -> list | str: def get_installed_ram(as_list=False, raise_exceptions=False) -> list | str:

View file

@ -298,7 +298,6 @@ def init_run(options) -> None:
def init_session(options) -> None: def init_session(options) -> None:
"""Initialize Auto Repairs session.""" """Initialize Auto Repairs session."""
_ = options # Suppress linting error and reserve for furture use
reg_set_value('HKCU', AUTO_REPAIR_KEY, 'SessionStarted', 1, 'DWORD') reg_set_value('HKCU', AUTO_REPAIR_KEY, 'SessionStarted', 1, 'DWORD')
reg_set_value('HKCU', AUTO_REPAIR_KEY, 'LogName', get_root_logger_path().stem, 'SZ') reg_set_value('HKCU', AUTO_REPAIR_KEY, 'LogName', get_root_logger_path().stem, 'SZ')
@ -312,11 +311,12 @@ def init_session(options) -> None:
set_timezone(WINDOWS_TIME_ZONE) set_timezone(WINDOWS_TIME_ZONE)
# One-time tasks # One-time tasks
if options['Run AVRemover (once)']['Selected']: TRY_PRINT.run(
TRY_PRINT.run( 'Run AVRemover...', run_tool, 'AVRemover', 'AVRemover',
'Run AVRemover...', run_tool, 'AVRemover', 'AVRemover', download=True, msg_good='DONE',
download=True, msg_good='DONE', )
) if options['Run TDSSKiller (once)']['Selected']:
TRY_PRINT.run('Running TDSSKiller...', run_tdsskiller, msg_good='DONE')
print('') print('')
reboot(30) reboot(30)
@ -649,14 +649,6 @@ def auto_bleachbit(group, name) -> None:
save_settings(group, name, result=result) save_settings(group, name, result=result)
def auto_bcuninstaller(group, name) -> None:
"""Run BCUninstaller."""
result = TRY_PRINT.run(
'BCUninstaller...', run_bcuninstaller, msg_good='DONE',
)
save_settings(group, name, result=result)
def auto_chkdsk(group, name) -> None: def auto_chkdsk(group, name) -> None:
"""Run CHKDSK repairs.""" """Run CHKDSK repairs."""
needs_reboot = False needs_reboot = False
@ -833,6 +825,14 @@ def auto_system_restore_set_size(group, name) -> None:
save_settings(group, name, result=result) save_settings(group, name, result=result)
def auto_uninstallview(group, name) -> None:
"""Run UninstallView."""
result = TRY_PRINT.run(
'UninstallView...', run_uninstallview, msg_good='DONE',
)
save_settings(group, name, result=result)
def auto_windows_updates_disable(group, name) -> None: def auto_windows_updates_disable(group, name) -> None:
"""Disable Windows Updates.""" """Disable Windows Updates."""
result = TRY_PRINT.run('Disable Windows Updates...', disable_windows_updates) result = TRY_PRINT.run('Disable Windows Updates...', disable_windows_updates)
@ -1058,11 +1058,6 @@ def run_bleachbit(cleaners, preview=True) -> None:
) )
def run_bcuninstaller() -> None:
"""Run BCUninstaller."""
run_tool('BCUninstaller', 'BCUninstaller')
def run_hitmanpro() -> None: def run_hitmanpro() -> None:
"""Run HitmanPro scan.""" """Run HitmanPro scan."""
log_path = format_log_path(log_name='HitmanPro', timestamp=True, tool=True) log_path = format_log_path(log_name='HitmanPro', timestamp=True, tool=True)
@ -1172,6 +1167,29 @@ def run_rkill() -> None:
run_tool('RKill', 'RKill', *cmd_args, download=True) run_tool('RKill', 'RKill', *cmd_args, download=True)
def run_tdsskiller() -> None:
"""Run TDSSKiller scan."""
log_path = format_log_path(log_name='TDSSKiller', timestamp=True, tool=True)
log_path.parent.mkdir(parents=True, exist_ok=True)
quarantine_path = set_quarantine_path('TDSSKiller')
quarantine_path.mkdir(parents=True, exist_ok=True)
cmd_args = (
'-accepteula',
'-accepteulaksn',
'-l', log_path,
'-qpath', quarantine_path,
'-qsus',
'-dcexact',
'-silent',
)
run_tool('TDSSKiller', 'TDSSKiller', *cmd_args, download=True)
def run_uninstallview() -> None:
"""Run UninstallView."""
run_tool('UninstallView', 'UninstallView')
# OS Built-in Functions # OS Built-in Functions
def create_custom_power_plan(enable_sleep=True, keep_display_on=False) -> None: def create_custom_power_plan(enable_sleep=True, keep_display_on=False) -> None:
"""Create new power plan and set as active.""" """Create new power plan and set as active."""

View file

@ -19,7 +19,6 @@ from wk.cfg.setup import (
REG_WINDOWS_EXPLORER, REG_WINDOWS_EXPLORER,
REG_OPEN_SHELL_SETTINGS, REG_OPEN_SHELL_SETTINGS,
REG_OPEN_SHELL_LOW_POWER_IDLE, REG_OPEN_SHELL_LOW_POWER_IDLE,
REG_WINDOWS_BSOD_MINIDUMPS,
UBLOCK_ORIGIN_URLS, UBLOCK_ORIGIN_URLS,
) )
from wk.exe import kill_procs, run_program, popen_program from wk.exe import kill_procs, run_program, popen_program
@ -37,18 +36,16 @@ from wk.os.win import (
OS_VERSION, OS_VERSION,
activate_with_bios, activate_with_bios,
check_4k_alignment, check_4k_alignment,
get_installed_antivirus,
get_installed_ram, get_installed_ram,
get_os_activation, get_os_activation,
get_os_name, get_os_name,
get_raw_disks, get_raw_disks,
get_service_status,
get_volume_usage, get_volume_usage,
is_activated, is_activated,
is_secure_boot_enabled, is_secure_boot_enabled,
list_installed_antivirus,
reg_set_value, reg_set_value,
reg_write_settings, reg_write_settings,
stop_service,
winget_check, winget_check,
winget_import, winget_import,
winget_upgrade, winget_upgrade,
@ -429,11 +426,6 @@ def auto_config_open_shell() -> None:
TRY_PRINT.run('Open Shell...', config_open_shell) TRY_PRINT.run('Open Shell...', config_open_shell)
def auto_disable_password_expiration() -> None:
"""Disable password expiration for all users."""
TRY_PRINT.run('Disable password expiration...', disable_password_expiration)
def auto_export_aida64_report() -> None: def auto_export_aida64_report() -> None:
"""Export AIDA64 reports.""" """Export AIDA64 reports."""
TRY_PRINT.run('AIDA64 Report...', export_aida64_report) TRY_PRINT.run('AIDA64 Report...', export_aida64_report)
@ -521,7 +513,7 @@ def auto_show_4k_alignment_check() -> None:
def auto_show_installed_antivirus() -> None: def auto_show_installed_antivirus() -> None:
"""Display installed antivirus.""" """Display installed antivirus."""
TRY_PRINT.run('Virus Protection...', list_installed_antivirus) TRY_PRINT.run('Virus Protection...', get_installed_antivirus)
def auto_show_installed_ram() -> None: def auto_show_installed_ram() -> None:
@ -628,16 +620,10 @@ def disable_chrome_notifications() -> None:
pref_file.write_text(json.dumps(pref_data, separators=(',', ':'))) pref_file.write_text(json.dumps(pref_data, separators=(',', ':')))
def disable_password_expiration() -> None:
"""Disable password expiration for all users."""
script_path = find_kit_dir('Scripts').joinpath('disable_password_expiration.ps1')
cmd = ['PowerShell', '-ExecutionPolicy', 'Bypass', '-File', script_path]
run_program(cmd)
def enable_bsod_minidumps() -> None: def enable_bsod_minidumps() -> None:
"""Enable saving minidumps during BSoDs.""" """Enable saving minidumps during BSoDs."""
reg_write_settings(REG_WINDOWS_BSOD_MINIDUMPS) cmd = ['wmic', 'RECOVEROS', 'set', 'DebugInfoType', '=', '3']
run_program(cmd)
def enable_ublock_origin() -> None: def enable_ublock_origin() -> None:
@ -792,7 +778,7 @@ def install_open_shell() -> None:
skin_zip = get_tool_path('OpenShell', 'Fluent-Metro', suffix='zip') skin_zip = get_tool_path('OpenShell', 'Fluent-Metro', suffix='zip')
# Bail early # Bail early
if OS_VERSION < 10: if OS_VERSION != 10:
raise GenericWarning('Unsupported OS') raise GenericWarning('Unsupported OS')
# Install OpenShell # Install OpenShell
@ -948,12 +934,6 @@ def open_microsoft_store_updates() -> None:
def open_snappy_driver_installer_origin() -> None: def open_snappy_driver_installer_origin() -> None:
"""Open Snappy Driver Installer Origin.""" """Open Snappy Driver Installer Origin."""
if OS_VERSION == 11:
appid_services = ['appid', 'appidsvc', 'applockerfltr']
for svc in appid_services:
stop_service(svc)
if any([get_service_status(s) != 'stopped' for s in appid_services]):
raise GenericWarning('Failed to stop AppID services')
run_tool('SDIO', 'SDIO', cwd=True, pipe=True, popen=True) run_tool('SDIO', 'SDIO', cwd=True, pipe=True, popen=True)

View file

@ -168,7 +168,7 @@ class Menu():
# Display item in YELLOW # Display item in YELLOW
disabled = True disabled = True
checkmark = '*' checkmark = '*'
if 'CONEMUPID' in os.environ or 'DISPLAY' in os.environ or PLATFORM == 'Darwin': if 'DISPLAY' in os.environ or PLATFORM == 'Darwin':
checkmark = '' checkmark = ''
display_name = f'{index if index else name[:1].upper()}: ' display_name = f'{index if index else name[:1].upper()}: '
if not (index and index >= 10): if not (index and index >= 10):

View file

@ -73,7 +73,7 @@ def fix_layout(
avail_vertical -= layout[group].get('height', 0) + 1 avail_vertical -= layout[group].get('height', 0) + 1
num_workers = len(layout['Workers']['Panes']) num_workers = len(layout['Workers']['Panes'])
avail_vertical -= num_workers * (layout['Workers'].get('height', 0) + 1) avail_vertical -= num_workers * (layout['Workers'].get('height', 0) + 1)
avail_horizontal -= layout['Progress']['width'] + 1 avail_horizontal -= layout['Started']['width'] + 1
# Fix heights # Fix heights
for group, data in layout.items(): for group, data in layout.items():
@ -89,17 +89,16 @@ def fix_layout(
) )
# Fix widths # Fix widths
resize_kwargs.append( for group in ('Started', 'Progress'):
{'pane_id': layout['Progress']['Panes'][0], 'width': layout['Progress']['width']} resize_kwargs.append(
) {'pane_id': layout[group]['Panes'][0], 'width': layout[group]['width']}
resize_kwargs.append( )
{'pane_id': layout['Started']['Panes'][0], 'height': layout['Started']['height']}
)
for group, data in layout.items(): for group, data in layout.items():
num_panes = len(data['Panes']) num_panes = len(data['Panes'])
if num_panes < 2 or group not in ('Title', 'Info'): if num_panes < 2 or group not in ('Title', 'Info'):
continue continue
pane_width, remainder = divmod(avail_horizontal - (num_panes-1), num_panes) avail_horizontal -= (num_panes - 1)
pane_width, remainder = divmod(avail_horizontal, num_panes)
for pane_id in data['Panes']: for pane_id in data['Panes']:
new_width = pane_width new_width = pane_width
if remainder > 0: if remainder > 0:
@ -118,7 +117,7 @@ def fix_layout(
def get_pane_size(pane_id: str | None = None) -> tuple[int, int]: def get_pane_size(pane_id: str | None = None) -> tuple[int, int]:
"""Get current or target pane size, returns tuple.""" """Get current or target pane size, returns tuple."""
cmd = ['tmux', 'display-message', '-p'] cmd = ['tmux', 'display', '-p']
if pane_id: if pane_id:
cmd.extend(['-t', pane_id]) cmd.extend(['-t', pane_id])
cmd.append('#{pane_width} #{pane_height}') cmd.append('#{pane_width} #{pane_height}')
@ -140,7 +139,7 @@ def get_pane_size(pane_id: str | None = None) -> tuple[int, int]:
def get_window_size() -> tuple[int, int]: def get_window_size() -> tuple[int, int]:
"""Get current window size, returns tuple.""" """Get current window size, returns tuple."""
cmd = ['tmux', 'display-message', '-p', '#{window_width} #{window_height}'] cmd = ['tmux', 'display', '-p', '#{window_width} #{window_height}']
# Get resolution # Get resolution
proc = run_program(cmd, check=False) proc = run_program(cmd, check=False)
@ -192,7 +191,7 @@ def layout_needs_fixed(layout: dict[str, dict[str, Any]]) -> bool:
def poll_pane(pane_id: str) -> bool: def poll_pane(pane_id: str) -> bool:
"""Check if pane exists, returns bool.""" """Check if pane exists, returns bool."""
cmd = ['tmux', 'list-panes', '-F', '#{pane_id}'] cmd = ['tmux', 'list-panes', '-F', '#D']
# Get list of panes # Get list of panes
proc = run_program(cmd, check=False) proc = run_program(cmd, check=False)
@ -314,7 +313,7 @@ def split_window(
target_id: str | None = None, target_id: str | None = None,
**action) -> str: **action) -> str:
"""Split tmux window, run action, and return pane_id as str.""" """Split tmux window, run action, and return pane_id as str."""
cmd = ['tmux', 'split-window', '-d', '-PF', '#{pane_id}'] cmd = ['tmux', 'split-window', '-d', '-PF', '#D']
# Safety checks # Safety checks
if not (lines or percent): if not (lines or percent):
@ -335,7 +334,7 @@ def split_window(
if lines: if lines:
cmd.extend(['-l', str(lines)]) cmd.extend(['-l', str(lines)])
elif percent: elif percent:
cmd.extend(['-l', f'{percent}%']) cmd.extend(['-p', str(percent)])
# New pane action # New pane action
cmd.extend(prep_action(**action)) cmd.extend(prep_action(**action))

View file

@ -22,7 +22,7 @@ TMUX_LAYOUT = { # NOTE: This needs to be in order from top to bottom
'Info': {'Panes': []}, 'Info': {'Panes': []},
'Current': {'Panes': [environ.get('TMUX_PANE', None)]}, 'Current': {'Panes': [environ.get('TMUX_PANE', None)]},
'Workers': {'Panes': []}, 'Workers': {'Panes': []},
'Started': {'Panes': [], 'height': TMUX_TITLE_HEIGHT}, 'Started': {'Panes': [], 'width': TMUX_SIDE_WIDTH},
'Progress': {'Panes': [], 'width': TMUX_SIDE_WIDTH}, 'Progress': {'Panes': [], 'width': TMUX_SIDE_WIDTH},
} }
@ -180,25 +180,6 @@ class TUI():
self.layout.clear() self.layout.clear()
self.layout.update(deepcopy(TMUX_LAYOUT)) self.layout.update(deepcopy(TMUX_LAYOUT))
# Progress
self.layout['Progress']['Panes'].append(tmux.split_window(
lines=TMUX_SIDE_WIDTH,
text=' ',
))
# Started
self.layout['Started']['Panes'].append(tmux.split_window(
behind=True,
lines=2,
target_id=self.layout['Progress']['Panes'][0],
text=ansi.color_string(
['Started', time.strftime("%Y-%m-%d %H:%M %Z")],
['BLUE', None],
sep='\n',
),
vertical=True,
))
# Title # Title
self.layout['Title']['Panes'].append(tmux.split_window( self.layout['Title']['Panes'].append(tmux.split_window(
behind=True, behind=True,
@ -211,8 +192,22 @@ class TUI():
), ),
)) ))
# Done # Started
sleep(0.2) self.layout['Started']['Panes'].append(tmux.split_window(
lines=TMUX_SIDE_WIDTH,
target_id=self.layout['Title']['Panes'][0],
text=ansi.color_string(
['Started', time.strftime("%Y-%m-%d %H:%M %Z")],
['BLUE', None],
sep='\n',
),
))
# Progress
self.layout['Progress']['Panes'].append(tmux.split_window(
lines=TMUX_SIDE_WIDTH,
text=' ',
))
def remove_all_info_panes(self) -> None: def remove_all_info_panes(self) -> None:
"""Remove all info panes and update layout.""" """Remove all info panes and update layout."""

View file

@ -80,21 +80,6 @@ function copy_live_env() {
mkdir -p "$PROFILE_DIR/airootfs/usr/local/bin" mkdir -p "$PROFILE_DIR/airootfs/usr/local/bin"
rsync -aI "$ROOT_DIR/scripts/" "$PROFILE_DIR/airootfs/usr/local/bin/" rsync -aI "$ROOT_DIR/scripts/" "$PROFILE_DIR/airootfs/usr/local/bin/"
echo "Copying WizardKit UFD files..."
rsync -aI --exclude="macOS-boot-icon.tar" "$ROOT_DIR/setup/ufd/" "$PROFILE_DIR/airootfs/usr/share/WizardKit/"
tar xaf "$ROOT_DIR/setup/ufd/macOS-boot-icon.tar" -C "$PROFILE_DIR/airootfs/usr/share/WizardKit"
cp "$ROOT_DIR/images/rEFInd.png" "$PROFILE_DIR/airootfs/usr/share/WizardKit/EFI/Boot/rEFInd.png"
cp "$ROOT_DIR/images/Syslinux.png" "$PROFILE_DIR/airootfs/usr/share/WizardKit/syslinux/syslinux.png"
echo "Copying Memtest86+ files..."
rsync -aI "/boot/memtest86+/memtest.bin" "$PROFILE_DIR/airootfs/usr/share/WizardKit/syslinux/"
rsync -aI "/boot/memtest86+/memtest.efi" "$PROFILE_DIR/airootfs/usr/share/WizardKit/EFI/Memtest86+/"
mv "$PROFILE_DIR/airootfs/usr/share/WizardKit/EFI/Memtest86+"/{memtest.efi,bootx64.efi}
# Pre-compile Python scripts
unset PYTHONPYCACHEPREFIX
python -m compileall "$PROFILE_DIR/airootfs/usr/local/bin/"
# Update profiledef.sh to set proper permissions for executable files # Update profiledef.sh to set proper permissions for executable files
for _file in $(find "$PROFILE_DIR/airootfs" -executable -type f | sed "s%$PROFILE_DIR/airootfs%%" | sort); do for _file in $(find "$PROFILE_DIR/airootfs" -executable -type f | sed "s%$PROFILE_DIR/airootfs%%" | sort); do
sed -i "\$i\ [\"$_file\"]=\"0:0:755\"" "$PROFILE_DIR/profiledef.sh" sed -i "\$i\ [\"$_file\"]=\"0:0:755\"" "$PROFILE_DIR/profiledef.sh"
@ -127,15 +112,48 @@ function update_live_env() {
username="tech" username="tech"
label="${KIT_NAME_SHORT}_LINUX" label="${KIT_NAME_SHORT}_LINUX"
# Boot config
cp "$ROOT_DIR/images/Syslinux.png" "$PROFILE_DIR/syslinux/splash.png"
sed -i -r "s/___+/${KIT_NAME_FULL}/" "$PROFILE_DIR/airootfs/usr/share/WizardKit/syslinux/syslinux.cfg"
# MOTD # MOTD
sed -i -r "s/KIT_NAME_SHORT/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh" sed -i -r "s/KIT_NAME_SHORT/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh"
sed -i -r "s/KIT_NAME_FULL/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh" sed -i -r "s/KIT_NAME_FULL/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh"
sed -i -r "s/SUPPORT_URL/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh" sed -i -r "s/SUPPORT_URL/$KIT_NAME_SHORT/" "$PROFILE_DIR/profiledef.sh"
# Boot config (legacy)
mkdir -p "$TEMP_DIR" 2>/dev/null
git clone --depth=1 https://github.com/ipxe/wimboot "$TEMP_DIR/wimboot"
rsync -aI "$TEMP_DIR/wimboot"/{LICENSE.txt,README.md,wimboot} "$PROFILE_DIR/syslinux/wimboot/"
cp "$ROOT_DIR/images/Pxelinux.png" "$PROFILE_DIR/syslinux/pxelinux.png"
cp "$ROOT_DIR/images/Syslinux.png" "$PROFILE_DIR/syslinux/syslinux.png"
sed -i -r "s/__+/$KIT_NAME_FULL/" "$PROFILE_DIR/syslinux/syslinux.cfg"
# Boot config (UEFI)
curl -Lo "$TEMP_DIR/refind.zip" "https://sourceforge.net/projects/refind/files/latest/download"
7z x -aoa "$TEMP_DIR/refind.zip" -o"$TEMP_DIR/refind"
cp "$ROOT_DIR/images/rEFInd.png" "$PROFILE_DIR/EFI/boot/rEFInd.png"
cp "$TEMP_DIR/refind"/refind*/"refind/refind_x64.efi" "$PROFILE_DIR/EFI/boot/bootx64.efi"
rsync -aI "$TEMP_DIR/refind"/refind*/refind/drivers_x64/ "$PROFILE_DIR/EFI/boot/drivers_x64/"
rsync -aI "$TEMP_DIR/refind"/refind*/refind/icons/ "$PROFILE_DIR/EFI/boot/icons/"
sed -i "s/%ARCHISO_LABEL%/${label}/" "$PROFILE_DIR/EFI/boot/refind.conf"
# Memtest86+ (Open Source)
mkdir -p "$PROFILE_DIR/EFI/memtest86+"
mkdir -p "$TEMP_DIR/memtest86+"
curl -Lo "$TEMP_DIR/memtest86+/memtest86-binaries.zip" "https://memtest.org/download/v6.10/mt86plus_6.10.binaries.zip"
7z e "$TEMP_DIR/memtest86+/memtest86-binaries.zip" -o"$TEMP_DIR/memtest86+" "memtest64.efi"
mv "$TEMP_DIR/memtest86+/memtest64.efi" "$PROFILE_DIR/EFI/memtest86+/bootx64.efi"
# Memtest86 (Passmark)
mkdir -p "$PROFILE_DIR/EFI/memtest86/Benchmark"
mkdir -p "$TEMP_DIR/memtest86"
curl -Lo "$TEMP_DIR/memtest86/memtest86-usb.zip" "https://www.memtest86.com/downloads/memtest86-usb.zip"
7z e -aoa "$TEMP_DIR/memtest86/memtest86-usb.zip" -o"$TEMP_DIR/memtest86" "memtest86-usb.img"
7z e -aoa "$TEMP_DIR/memtest86/memtest86-usb.img" -o"$TEMP_DIR/memtest86" "MemTest86.img"
7z x -aoa "$TEMP_DIR/memtest86/MemTest86.img" -o"$TEMP_DIR/memtest86"
rm "$TEMP_DIR/memtest86/EFI/BOOT/BOOTIA32.efi"
mv "$TEMP_DIR/memtest86/EFI/BOOT/BOOTX64.efi" "$PROFILE_DIR/EFI/memtest86/bootx64.efi"
mv "$TEMP_DIR/memtest86/EFI/BOOT"/* "$PROFILE_DIR/EFI/memtest86"/
mv "$TEMP_DIR/memtest86/help"/* "$PROFILE_DIR/EFI/memtest86"/
mv "$TEMP_DIR/memtest86/license.rtf" "$PROFILE_DIR/EFI/memtest86"/
# Hostname # Hostname
echo "$hostname" > "$PROFILE_DIR/airootfs/etc/hostname" echo "$hostname" > "$PROFILE_DIR/airootfs/etc/hostname"
echo "127.0.1.1 $hostname.localdomain $hostname" >> "$PROFILE_DIR/airootfs/etc/hosts" echo "127.0.1.1 $hostname.localdomain $hostname" >> "$PROFILE_DIR/airootfs/etc/hosts"
@ -154,6 +172,9 @@ function update_live_env() {
# MOTD # MOTD
sed -i -r "s/_+/$KIT_NAME_FULL Linux Environment/" "$PROFILE_DIR/airootfs/etc/motd" sed -i -r "s/_+/$KIT_NAME_FULL Linux Environment/" "$PROFILE_DIR/airootfs/etc/motd"
# Network
ln -s "/run/systemd/resolve/stub-resolv.conf" "$PROFILE_DIR/airootfs/etc/resolv.conf"
# Oh My ZSH # Oh My ZSH
git clone --depth=1 https://github.com/robbyrussell/oh-my-zsh.git "$SKEL_DIR/.oh-my-zsh" git clone --depth=1 https://github.com/robbyrussell/oh-my-zsh.git "$SKEL_DIR/.oh-my-zsh"
rm -Rf "$SKEL_DIR/.oh-my-zsh/.git" rm -Rf "$SKEL_DIR/.oh-my-zsh/.git"
@ -326,6 +347,16 @@ function build_iso() {
-v "$PROFILE_DIR" \ -v "$PROFILE_DIR" \
| tee -a "$LOG_DIR/$DATETIME.log" | tee -a "$LOG_DIR/$DATETIME.log"
# Build better ISO
rsync -aI "$PROFILE_DIR/EFI/" "${ISO_DIR:-safety}/EFI/"
rsync -aI --ignore-existing "$PROFILE_DIR/syslinux/" "${ISO_DIR:-safety}/syslinux/"
## Sketchy bit ##
. /usr/bin/mkarchiso -o "${OUT_DIR}" -w "${WORK_DIR}" "${PROFILE_DIR}"
isofs_dir="${ISO_DIR}"
image_name="${KIT_NAME_SHORT}-Linux-${DATE}-x86_64.iso"
rm "${OUT_DIR}/${image_name}"
_build_iso_image
# Cleanup # Cleanup
echo "Removing temp files..." echo "Removing temp files..."
rm "$TEMP_DIR/Linux" -Rf | tee -a "$LOG_DIR/$DATETIME.log" rm "$TEMP_DIR/Linux" -Rf | tee -a "$LOG_DIR/$DATETIME.log"

View file

@ -6,6 +6,10 @@
setlocal EnableDelayedExpansion setlocal EnableDelayedExpansion
title WizardKit: Build Tool title WizardKit: Build Tool
call :CheckFlags %* call :CheckFlags %*
rem TODO: Remove warning
echo "Windows PE build is currently under development"
echo " Proceeding will likely result in errors so be warned"
pause
call :CheckElevation || goto Exit call :CheckElevation || goto Exit
call :FindKitsRoot || goto ErrorKitNotFound call :FindKitsRoot || goto ErrorKitNotFound
@ -15,8 +19,14 @@ set "dandi_set_env=%adk_root%\Deployment Tools\DandISetEnv.bat"
if not exist "%dandi_set_env%" (goto ErrorKitNotFound) if not exist "%dandi_set_env%" (goto ErrorKitNotFound)
call "%dandi_set_env%" || goto ErrorUnknown call "%dandi_set_env%" || goto ErrorUnknown
:EnsureCRLF
rem Rewrite main.py using PowerShell to have CRLF/`r`n lineendings
set "script=%~dp0\.bin\Scripts\borrowed\set-eol.ps1"
set "main=%~dp0\.bin\Scripts\settings\main.py"
powershell -executionpolicy bypass -noprofile -file %script% -lineEnding win -file %main% || goto ErrorUnknown
:Launch :Launch
set "script=%~dp0\pe\build_pe.ps1" set "script=%~dp0\.bin\Scripts\build_pe.ps1"
powershell -executionpolicy bypass -noprofile -file %script% || goto ErrorUnknown powershell -executionpolicy bypass -noprofile -file %script% || goto ErrorUnknown
goto Exit goto Exit

View file

@ -11,4 +11,3 @@ smartmontools-svn
ttf-font-awesome-4 ttf-font-awesome-4
udevil udevil
wd719x-firmware wd719x-firmware
wimboot-bin

View file

@ -10,7 +10,6 @@ bc
bind bind
bluez bluez
bluez-utils bluez-utils
bolt
btrfs-progs btrfs-progs
cbatticon cbatticon
chntpw chntpw
@ -32,21 +31,15 @@ dosfstools
dunst dunst
e2fsprogs e2fsprogs
edk2-shell edk2-shell
efibootmgr
evince evince
exfatprogs exfatprogs
f2fs-tools
fatresize
feh feh
ffmpeg ffmpeg
firefox firefox
foot-terminfo
gnome-keyring gnome-keyring
gnu-netcat
gparted gparted
gpicview gpicview
gptfdisk gptfdisk
grub
gsmartcontrol gsmartcontrol
hardinfo-gtk3 hardinfo-gtk3
hexedit hexedit
@ -57,7 +50,6 @@ intel-ucode
iwd iwd
iwgtk iwgtk
jfsutils jfsutils
kitty-terminfo
ldns ldns
leafpad leafpad
less less
@ -65,77 +57,66 @@ lha
libewf libewf
libinput libinput
libldm libldm
libusb-compat
libxft libxft
linux linux
linux-firmware linux-firmware
linux-firmware-marvell
lm_sensors lm_sensors
lsscsi
lvm2 lvm2
lzip lzip
man-db man-db
man-pages man-pages
mdadm mdadm
mediainfo mediainfo
memtest86+
memtest86-efi memtest86-efi
mesa-demos mesa-demos
mesa-utils mesa-utils
mkinitcpio mkinitcpio
mkinitcpio-archiso mkinitcpio-archiso
mkinitcpio-nfs-utils
mkvtoolnix-cli mkvtoolnix-cli
mprime-bin mprime-bin
mpv mpv
mtools mtools
nano nano
nbd
ncdu ncdu
ndisc6
nfs-utils
nmap
noto-fonts noto-fonts
noto-fonts-cjk noto-fonts-cjk
ntfs-3g
numlockx numlockx
nvme-cli nvme-cli
open-iscsi
openbox openbox
openssh openssh
opensuperclone-git opensuperclone-git
otf-font-awesome-4 otf-font-awesome-4
p7zip p7zip
papirus-icon-theme papirus-icon-theme
parted
perl perl
picom picom
pipes.sh pipes.sh
pv pv
python python
python-docopt
python-prompt_toolkit python-prompt_toolkit
python-psutil python-psutil
python-pytz python-pytz
python-requests python-requests
qemu-guest-agent qemu-guest-agent
refind qemu-guest-agent
reiserfsprogs
reiserfsprogs reiserfsprogs
rfkill rfkill
rng-tools
rofi rofi
rsync rsync
rxvt-unicode rxvt-unicode
rxvt-unicode-terminfo rxvt-unicode-terminfo
sdparm
smartmontools-svn smartmontools-svn
sof-firmware
speedtest-cli speedtest-cli
spice-vdagent spice-vdagent
squashfs-tools
st st
sudo sudo
sysbench sysbench
sysfsutils sysfsutils
syslinux syslinux
systemd-resolvconf
systemd-sysvcompat systemd-sysvcompat
terminus-font terminus-font
testdisk testdisk
@ -145,8 +126,6 @@ tigervnc
tint2 tint2
tk tk
tmux tmux
tpm2-tools
tpm2-tss
tree tree
ttf-font-awesome-4 ttf-font-awesome-4
ttf-hack ttf-hack
@ -157,8 +136,6 @@ ufw
unarj unarj
unrar unrar
unzip unzip
usb_modeswitch
usbmuxd
usbutils usbutils
util-linux util-linux
veracrypt veracrypt
@ -166,9 +143,7 @@ vim
virtualbox-guest-utils virtualbox-guest-utils
volumeicon volumeicon
wd719x-firmware wd719x-firmware
wezterm-terminfo
which which
wimboot-bin
wimlib wimlib
wmctrl wmctrl
xarchiver xarchiver
@ -176,7 +151,6 @@ xf86-input-libinput
xf86-video-amdgpu xf86-video-amdgpu
xf86-video-fbdev xf86-video-fbdev
xf86-video-nouveau xf86-video-nouveau
xf86-video-qxl
xf86-video-vesa xf86-video-vesa
xfsprogs xfsprogs
xorg-server xorg-server

View file

@ -5,8 +5,6 @@ curl
dos2unix dos2unix
git git
gtk3 gtk3
memtest86+
memtest86+-efi
p7zip p7zip
perl-rename perl-rename
pv pv

View file

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

Before

Width:  |  Height:  |  Size: 338 KiB

After

Width:  |  Height:  |  Size: 338 KiB

View file

Before

Width:  |  Height:  |  Size: 373 KiB

After

Width:  |  Height:  |  Size: 373 KiB

View file

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 320 KiB

View file

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 116 KiB

View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -21,27 +21,21 @@ menuentry "Linux" {
initrd /arch/boot/intel_ucode.img initrd /arch/boot/intel_ucode.img
initrd /arch/boot/amd_ucode.img initrd /arch/boot/amd_ucode.img
initrd /arch/boot/x86_64/initramfs-linux.img initrd /arch/boot/x86_64/initramfs-linux.img
options "archisobasedir=arch archisodevice=/dev/disk/by-uuid/_______ copytoram loglevel=3" options "archisobasedir=arch archisolabel=%ARCHISO_LABEL% copytoram loglevel=3"
submenuentry "Linux (Safe Video)" {
add_options "nomodeset i915.modeset=0 nouveau.modeset=0"
}
submenuentry "Linux (CLI)" { submenuentry "Linux (CLI)" {
add_options "nox" add_options "nox"
} }
submenuentry "Linux (CLI w/ Safe Video)" {
add_options "nox nomodeset i915.modeset=0 nouveau.modeset=0"
}
} }
menuentry "MemTest86+" { menuentry "MemTest86+" {
icon /EFI/boot/icons/wk_memtest.png icon /EFI/boot/icons/wk_memtest.png
options "nobigstatus nopause" options "nobigstatus nopause"
loader /EFI/Memtest86+/bootx64.efi loader /EFI/memtest86+/bootx64.efi
submenuentry "Memtest86+ (Open Source)" { submenuentry "Memtest86+ (Open Source)" {
loader /EFI/Memtest86+/bootx64.efi loader /EFI/memtest86+/bootx64.efi
} }
submenuentry "Memtest86 (Passmark)" { submenuentry "Memtest86 (Passmark)" {
loader /EFI/Memtest86/bootx64.efi loader /EFI/memtest86/bootx64.efi
options options
} }
} }
@ -82,3 +76,12 @@ menuentry "MemTest86+" {
#UFD-WINPE# loader /EFI/microsoft/bootx64.efi #UFD-WINPE# loader /EFI/microsoft/bootx64.efi
#UFD-WINPE#} #UFD-WINPE#}
#UFD-DGPU#menuentry "Mac dGPU Disable Tool" {
#UFD-DGPU# icon /EFI/boot/icons/dgpu.png
#UFD-DGPU# loader /dgpu/vmlinuz-linux
#UFD-DGPU# initrd /arch/boot/intel_ucode.img
#UFD-DGPU# initrd /arch/boot/amd_ucode.img
#UFD-DGPU# initrd /dgpu/initramfs-linux.img
#UFD-DGPU# options "archisobasedir=dgpu archisolabel=%ARCHISO_LABEL% nomodeset"
#UFD-DGPU#}

View file

Before

Width:  |  Height:  |  Size: 538 B

After

Width:  |  Height:  |  Size: 538 B

View file

Before

Width:  |  Height:  |  Size: 720 B

After

Width:  |  Height:  |  Size: 720 B

View file

@ -1 +1 @@
LANG=C.UTF-8 LANG=en_US.UTF-8

View file

@ -0,0 +1,70 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
# vim:set ft=sh
# MODULES
# The following modules are loaded before any boot hooks are
# run. Advanced users may wish to specify all system modules
# in this array. For instance:
# MODULES=(piix ide_disk reiserfs)
MODULES=()
# BINARIES
# This setting includes any additional binaries a given user may
# wish into the CPIO image. This is run last, so it may be used to
# override the actual binaries included by a given hook
# BINARIES are dependency parsed, so you may safely ignore libraries
BINARIES=()
# FILES
# This setting is similar to BINARIES above, however, files are added
# as-is and are not parsed in any way. This is useful for config files.
FILES=()
# HOOKS
# This is the most important setting in this file. The HOOKS control the
# modules and scripts added to the image, and what happens at boot time.
# Order is important, and it is recommended that you do not change the
# order in which HOOKS are added. Run 'mkinitcpio -H <hook name>' for
# help on a given hook.
# 'base' is _required_ unless you know precisely what you are doing.
# 'udev' is _required_ in order to automatically load modules
# 'filesystems' is _required_ unless you specify your fs modules in MODULES
# Examples:
## This setup specifies all modules in the MODULES setting above.
## No raid, lvm2, or encrypted root is needed.
# HOOKS=(base)
#
## This setup will autodetect all modules for your system and should
## work as a sane default
# HOOKS=(base udev autodetect block filesystems)
#
## This setup will generate a 'full' image which supports most systems.
## No autodetection is done.
# HOOKS=(base udev block filesystems)
#
## This setup assembles a pata mdadm array with an encrypted root FS.
## Note: See 'mkinitcpio -H mdadm' for more information on raid devices.
# HOOKS=(base udev block mdadm encrypt filesystems)
#
## This setup loads an lvm2 volume group on a usb device.
# HOOKS=(base udev block lvm2 filesystems)
#
## NOTE: If you have /usr on a separate partition, you MUST include the
# usr, fsck and shutdown hooks.
HOOKS=(base udev modconf memdisk archiso_shutdown archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs archiso_kms block filesystems keyboard)
# COMPRESSION
# Use this to compress the initramfs image. By default, gzip compression
# is used. Use 'cat' to create an uncompressed image.
#COMPRESSION="gzip"
#COMPRESSION="bzip2"
#COMPRESSION="lzma"
COMPRESSION="xz"
#COMPRESSION="lzop"
#COMPRESSION="lz4"
#COMPRESSION="zstd"
# COMPRESSION_OPTIONS
# Additional options for the compressor
#COMPRESSION_OPTIONS=()

View file

@ -1,2 +0,0 @@
HOOKS=(base udev modconf kms memdisk archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs block filesystems keyboard)
COMPRESSION="xz"

View file

@ -0,0 +1,8 @@
# mkinitcpio preset file for the 'linux' package on archiso
PRESETS=('archiso')
ALL_kver='/boot/vmlinuz-linux'
ALL_config='/etc/mkinitcpio.conf'
archiso_image="/boot/initramfs-linux.img"

View file

@ -0,0 +1,13 @@
# remove from airootfs!
[Trigger]
Operation = Install
Type = Package
Target = glibc
[Action]
Description = Uncommenting en_US.UTF-8 locale and running locale-gen...
When = PostTransaction
Depends = glibc
Depends = sed
Depends = sh
Exec = /bin/sh -c "sed -i 's/#\(en_US\.UTF-8\)/\1/' /etc/locale.gen && locale-gen"

View file

@ -1,23 +0,0 @@
# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 127.0.0.53
options edns0 trust-ad
search .

View file

@ -12,6 +12,7 @@ alias fix-perms='find -type d -exec chmod 755 "{}" \; && find -type f -exec chmo
alias hexedit='hexedit --color' alias hexedit='hexedit --color'
alias hw-info='sudo hw-info | less -S' alias hw-info='sudo hw-info | less -S'
alias ip='ip -br -c' alias ip='ip -br -c'
alias journalctl-datarec="echo -e 'Monitoring journal output...\n' && journalctl -kf | grep -Ei 'ata|nvme|scsi|sd[a..z]+|usb|comreset|critical|error'"
alias less='less -S' alias less='less -S'
alias ls='ls --color=auto' alias ls='ls --color=auto'
alias mkdir='mkdir -p' alias mkdir='mkdir -p'

View file

@ -2,17 +2,8 @@
# #
## Calculate DPI, update settings if necessary, then start desktop apps ## Calculate DPI, update settings if necessary, then start desktop apps
MONITOR=$(xrandr --listmonitors | grep -E '^\s+[0-9]' | head -1 | sed -r 's/^.*\s+(.*)$/\1/')
REGEX_XRANDR='^.* ([0-9]+)x([0-9]+)\+[0-9]+\+[0-9]+.* ([0-9]+)mm x ([0-9]+)mm.*$' REGEX_XRANDR='^.* ([0-9]+)x([0-9]+)\+[0-9]+\+[0-9]+.* ([0-9]+)mm x ([0-9]+)mm.*$'
# Resize screen in VMs
if lsmod | grep -Eq 'qxl|virtio_gpu'; then
echo -n "Starting VM guest services..."
spice-vdagent
sleep 0.5
xrandr --output "${MONITOR}" --auto
fi
echo -n "Getting display details... " echo -n "Getting display details... "
# Get screen data # Get screen data

View file

@ -1,10 +1,5 @@
setterm -blank 0 -powerdown 0 2>/dev/null setterm -blank 0 -powerdown 0 2>/dev/null
if [ "$(fgconsole 2>/dev/null)" -eq "1" ]; then if [ "$(fgconsole 2>/dev/null)" -eq "1" ]; then
# VM guest init
if lsmod | grep -Eq 'qxl|virtio_gpu'; then
systemctl start spice-vdagentd.service
fi
# Set up teststation details # Set up teststation details
$HOME/.setup_teststation $HOME/.setup_teststation

View file

@ -1,2 +0,0 @@
[Network]
IPv6PrivacyExtensions=yes

View file

@ -1,21 +1,10 @@
[Match] [Match]
# Matching with "Type=ether" causes issues with containers because it also matches virtual Ethernet interfaces (veth*).
# See https://bugs.archlinux.org/task/70892
# Instead match by globbing the network interface name.
Name=en* Name=en*
Name=eth* Name=eth*
[Network] [Network]
DHCP=yes DHCP=yes
MulticastDNS=yes IPv6PrivacyExtensions=yes
# systemd-networkd does not set per-interface-type default route metrics [DHCP]
# https://github.com/systemd/systemd/issues/17698 RouteMetric=512
# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband.
# Use values from NetworkManager. From nm_device_get_route_metric_default in
# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c
[DHCPv4]
RouteMetric=100
[IPv6AcceptRA]
RouteMetric=100

View file

@ -0,0 +1,10 @@
[Match]
Name=wlp*
Name=wlan*
[Network]
DHCP=yes
IPv6PrivacyExtensions=yes
[DHCP]
RouteMetric=1024

View file

@ -1,17 +0,0 @@
[Match]
Name=wl*
[Network]
DHCP=yes
MulticastDNS=yes
# systemd-networkd does not set per-interface-type default route metrics
# https://github.com/systemd/systemd/issues/17698
# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband.
# Use values from NetworkManager. From nm_device_get_route_metric_default in
# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c
[DHCPv4]
RouteMetric=600
[IPv6AcceptRA]
RouteMetric=600

View file

@ -1,16 +0,0 @@
[Match]
Name=ww*
[Network]
DHCP=yes
# systemd-networkd does not set per-interface-type default route metrics
# https://github.com/systemd/systemd/issues/17698
# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband.
# Use values from NetworkManager. From nm_device_get_route_metric_default in
# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c
[DHCPv4]
RouteMetric=700
[IPv6AcceptRA]
RouteMetric=700

View file

@ -1,4 +0,0 @@
# Default systemd-resolved configuration for archiso
[Resolve]
MulticastDNS=yes

View file

@ -5,4 +5,4 @@ Description=Temporary /etc/pacman.d/gnupg directory
What=tmpfs What=tmpfs
Where=/etc/pacman.d/gnupg Where=/etc/pacman.d/gnupg
Type=tmpfs Type=tmpfs
Options=mode=0755,noswap Options=mode=0755

View file

@ -0,0 +1 @@
/usr/lib/systemd/system/rngd.service

View file

@ -1,15 +1,15 @@
[Unit] [Unit]
Description=Initializes Pacman keyring Description=Initializes Pacman keyring
Wants=haveged.service
After=haveged.service
Requires=etc-pacman.d-gnupg.mount Requires=etc-pacman.d-gnupg.mount
After=etc-pacman.d-gnupg.mount time-sync.target After=etc-pacman.d-gnupg.mount
BindsTo=etc-pacman.d-gnupg.mount
Before=archlinux-keyring-wkd-sync.service
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes RemainAfterExit=yes
ExecStart=/usr/bin/pacman-key --init ExecStart=/usr/bin/pacman-key --init
ExecStart=/usr/bin/pacman-key --populate ExecStart=/usr/bin/pacman-key --populate archlinux
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View file

@ -1,4 +0,0 @@
disable-ccid
disable-pinpad
pcsc-driver /usr/lib/libpcsclite.so
pcsc-shared

View file

@ -1,7 +1,7 @@
title %ARCHISO_LABEL% title %ARCHISO_LABEL%
sort-key 01 sort-key 01
linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
initrd /%INSTALL_DIR%/boot/intel-ucode.img initrd /%INSTALL_DIR%/boot/intel-ucode.img
initrd /%INSTALL_DIR%/boot/amd-ucode.img initrd /%INSTALL_DIR%/boot/amd-ucode.img
initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
options archisobasedir=%INSTALL_DIR% archisodevice=UUID=%ARCHISO_UUID% options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL%

View file

@ -0,0 +1,7 @@
title %ARCHISO_LABEL% (Copy to RAM)
sort-key 02
linux /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
initrd /%INSTALL_DIR%/boot/intel-ucode.img
initrd /%INSTALL_DIR%/boot/amd-ucode.img
initrd /%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
options archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram

View file

@ -1,109 +0,0 @@
# Load partition table and file system modules
insmod part_gpt
insmod part_msdos
insmod fat
insmod iso9660
insmod ntfs
insmod ntfscomp
insmod exfat
insmod udf
# Use graphics-mode output
if loadfont "${prefix}/fonts/unicode.pf2" ; then
insmod all_video
set gfxmode="auto"
terminal_input console
terminal_output console
fi
# Enable serial console
insmod serial
insmod usbserial_common
insmod usbserial_ftdi
insmod usbserial_pl2303
insmod usbserial_usbdebug
if serial --unit=0 --speed=115200; then
terminal_input --append serial
terminal_output --append serial
fi
# Search for the ISO volume
if [ -z "${ARCHISO_UUID}" ]; then
if [ -z "${ARCHISO_HINT}" ]; then
regexp --set=1:ARCHISO_HINT '^\(([^)]+)\)' "${cmdpath}"
fi
search --no-floppy --set=root --file '%ARCHISO_SEARCH_FILENAME%' --hint "${ARCHISO_HINT}"
probe --set ARCHISO_UUID --fs-uuid "${root}"
fi
# Get a human readable platform identifier
if [ "${grub_platform}" == 'efi' ]; then
archiso_platform='UEFI'
if [ "${grub_cpu}" == 'x86_64' ]; then
archiso_platform="x64 ${archiso_platform}"
elif [ "${grub_cpu}" == 'i386' ]; then
archiso_platform="IA32 ${archiso_platform}"
else
archiso_platform="${grub_cpu} ${archiso_platform}"
fi
elif [ "${grub_platform}" == 'pc' ]; then
archiso_platform='BIOS'
else
archiso_platform="${grub_cpu} ${grub_platform}"
fi
# Set default menu entry
default=archlinux
timeout=15
timeout_style=menu
# Menu entries
menuentry "%ARCHISO_LABEL% (${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
set gfxpayload=keep
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux archisobasedir=%INSTALL_DIR% archisodevice=UUID=${ARCHISO_UUID}
initrd /%INSTALL_DIR%/boot/intel-ucode.img /%INSTALL_DIR%/boot/amd-ucode.img /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
}
if [ "${grub_platform}" == 'efi' -a "${grub_cpu}" == 'x86_64' -a -f '/boot/memtest86+/memtest.efi' ]; then
menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class memtest --class gnu --class tool {
set gfxpayload=800x600,1024x768
linux /boot/memtest86+/memtest.efi
}
fi
if [ "${grub_platform}" == 'pc' -a -f '/boot/memtest86+/memtest' ]; then
menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class memtest --class gnu --class tool {
set gfxpayload=800x600,1024x768
linux /boot/memtest86+/memtest
}
fi
if [ "${grub_platform}" == 'efi' ]; then
if [ "${grub_cpu}" == 'x86_64' -a -f '/shellx64.efi' ]; then
menuentry 'UEFI Shell' --class efi {
chainloader /shellx64.efi
}
elif [ "${grub_cpu}" == "i386" -a -f '/shellia32.efi' ]; then
menuentry 'UEFI Shell' --class efi {
chainloader /shellia32.efi
}
fi
menuentry 'UEFI Firmware Settings' --id 'uefi-firmware' {
fwsetup
}
fi
menuentry 'System shutdown' --class shutdown --class poweroff {
echo 'System shutting down...'
halt
}
menuentry 'System restart' --class reboot --class restart {
echo 'System rebooting...'
reboot
}
# GRUB init tune for accessibility
play 600 988 1 1319 4

View file

@ -1,73 +0,0 @@
# https://www.supergrubdisk.org/wiki/Loopback.cfg
# Search for the ISO volume
search --no-floppy --set=archiso_img_dev --file "${iso_path}"
probe --set archiso_img_dev_uuid --fs-uuid "${archiso_img_dev}"
# Get a human readable platform identifier
if [ "${grub_platform}" == 'efi' ]; then
archiso_platform='UEFI'
if [ "${grub_cpu}" == 'x86_64' ]; then
archiso_platform="x64 ${archiso_platform}"
elif [ "${grub_cpu}" == 'i386' ]; then
archiso_platform="IA32 ${archiso_platform}"
else
archiso_platform="${grub_cpu} ${archiso_platform}"
fi
elif [ "${grub_platform}" == 'pc' ]; then
archiso_platform='BIOS'
else
archiso_platform="${grub_cpu} ${grub_platform}"
fi
# Set default menu entry
default=archlinux
timeout=15
timeout_style=menu
# Menu entries
menuentry "%ARCHISO_LABEL% (${archiso_platform})" --class arch --class gnu-linux --class gnu --class os --id 'archlinux' {
set gfxpayload=keep
linux /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux archisobasedir=%INSTALL_DIR% img_dev=UUID=${archiso_img_dev_uuid} img_loop="${iso_path}"
initrd /%INSTALL_DIR%/boot/intel-ucode.img /%INSTALL_DIR%/boot/amd-ucode.img /%INSTALL_DIR%/boot/%ARCH%/initramfs-linux.img
}
if [ "${grub_platform}" == 'efi' -a "${grub_cpu}" == 'x86_64' -a -f '/boot/memtest86+/memtest.efi' ]; then
menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class memtest --class gnu --class tool {
set gfxpayload=800x600,1024x768
linux /boot/memtest86+/memtest.efi
}
fi
if [ "${grub_platform}" == 'pc' -a -f '/boot/memtest86+/memtest' ]; then
menuentry 'Run Memtest86+ (RAM test)' --class memtest86 --class memtest --class gnu --class tool {
set gfxpayload=800x600,1024x768
linux /boot/memtest86+/memtest
}
fi
if [ "${grub_platform}" == 'efi' ]; then
if [ "${grub_cpu}" == 'x86_64' -a -f '/shellx64.efi' ]; then
menuentry 'UEFI Shell' --class efi {
chainloader /shellx64.efi
}
elif [ "${grub_cpu}" == "i386" -a -f '/shellia32.efi' ]; then
menuentry 'UEFI Shell' --class efi {
chainloader /shellia32.efi
}
fi
menuentry 'UEFI Firmware Settings' --id 'uefi-firmware' {
fwsetup
}
fi
menuentry 'System shutdown' --class shutdown --class poweroff {
echo 'System shutting down...'
halt
}
menuentry 'System restart' --class reboot --class restart {
echo 'System rebooting...'
reboot
}

View file

@ -8,19 +8,16 @@ iso_application="KIT_NAME_FULL Linux Environment"
iso_version="$(date +%Y-%m-%d)" iso_version="$(date +%Y-%m-%d)"
install_dir="arch" install_dir="arch"
buildmodes=('iso') buildmodes=('iso')
bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito')
'uefi-ia32.grub.esp' 'uefi-x64.grub.esp'
'uefi-ia32.grub.eltorito' 'uefi-x64.grub.eltorito')
arch="x86_64" arch="x86_64"
pacman_conf="pacman.conf" pacman_conf="pacman.conf"
airootfs_image_type="squashfs" airootfs_image_type="squashfs"
airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M') airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M')
file_permissions=( file_permissions=(
["/etc/gshadow"]="0:0:400" ["/root"]="0:0:750"
["/etc/shadow"]="0:0:400" ["/etc/shadow"]="0:0:400"
["/etc/gshadow"]="0:0:400"
["/etc/skel/.ssh"]="0:0:700" ["/etc/skel/.ssh"]="0:0:700"
["/etc/skel/.ssh/authorized_keys"]="0:0:600" ["/etc/skel/.ssh/authorized_keys"]="0:0:600"
["/etc/skel/.ssh/id_rsa"]="0:0:600" ["/etc/skel/.ssh/id_rsa"]="0:0:600"
["/root"]="0:0:750"
["/root/.gnupg"]="0:0:700"
) )

View file

@ -1,28 +0,0 @@
SERIAL 0 115200
UI vesamenu.c32
MENU TITLE Arch Linux
MENU BACKGROUND splash.png
MENU WIDTH 78
MENU MARGIN 4
MENU ROWS 7
MENU VSHIFT 10
MENU TABMSGROW 14
MENU CMDLINEROW 14
MENU HELPMSGROW 16
MENU HELPMSGENDROW 29
# Refer to https://wiki.syslinux.org/wiki/index.php/Comboot/menu.c32
MENU COLOR border 30;44 #40ffffff #a0000000 std
MENU COLOR title 1;36;44 #9033ccff #a0000000 std
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
MENU COLOR unsel 37;44 #50ffffff #a0000000 std
MENU COLOR help 37;40 #c0ffffff #a0000000 std
MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
MENU COLOR msg07 37;40 #90ffffff #a0000000 std
MENU COLOR tabmsg 31;40 #30ffffff #00000000 std
MENU CLEAR
MENU IMMEDIATE

View file

@ -1,32 +0,0 @@
LABEL arch64_nbd
TEXT HELP
Boot %ARCHISO_LABEL% using NBD.
* HW diagnostics, file-based backups, data recovery, etc
ENDTEXT
MENU LABEL %ARCHISO_LABEL% (NBD)
LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
APPEND archisobasedir=%INSTALL_DIR% archisodevice=UUID=%ARCHISO_UUID% archiso_nbd_srv=${pxeserver} cms_verify=y
SYSAPPEND 3
LABEL arch64_nfs
TEXT HELP
Boot %ARCHISO_LABEL% using NFS.
* HW diagnostics, file-based backups, data recovery, etc
ENDTEXT
MENU LABEL %ARCHISO_LABEL% (NFS)
LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
APPEND archisobasedir=%INSTALL_DIR% archiso_nfs_srv=${pxeserver}:/run/archiso/bootmnt cms_verify=y
SYSAPPEND 3
LABEL arch64_http
TEXT HELP
Boot %ARCHISO_LABEL% using HTTP.
* HW diagnostics, file-based backups, data recovery, etc
ENDTEXT
MENU LABEL %ARCHISO_LABEL% (HTTP)
LINUX ::/%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
INITRD ::/%INSTALL_DIR%/boot/intel-ucode.img,::/%INSTALL_DIR%/boot/amd-ucode.img,::/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
APPEND archisobasedir=%INSTALL_DIR% archiso_http_srv=http://${pxeserver}/ cms_verify=y
SYSAPPEND 3

View file

@ -1,5 +0,0 @@
INCLUDE archiso_head.cfg
INCLUDE archiso_pxe-linux.cfg
INCLUDE archiso_tail.cfg

View file

@ -1,9 +0,0 @@
LABEL arch64
TEXT HELP
Boot %ARCHISO_LABEL% on BIOS.
* HW diagnostics, file-based backups, data recovery, etc
ENDTEXT
MENU LABEL %ARCHISO_LABEL% (BIOS)
LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
APPEND archisobasedir=%INSTALL_DIR% archisodevice=UUID=%ARCHISO_UUID%

View file

@ -1,8 +0,0 @@
INCLUDE archiso_head.cfg
DEFAULT arch64
TIMEOUT 150
INCLUDE archiso_sys-linux.cfg
INCLUDE archiso_tail.cfg

View file

@ -1,35 +0,0 @@
LABEL existing
TEXT HELP
Boot an existing operating system.
Press TAB to edit the disk and partition number to boot.
ENDTEXT
MENU LABEL Boot existing OS
COM32 chain.c32
APPEND hd0 0
# https://www.memtest.org/
LABEL memtest
MENU LABEL Run Memtest86+ (RAM test)
LINUX /boot/memtest86+/memtest
# https://wiki.syslinux.org/wiki/index.php/Hdt_(Hardware_Detection_Tool)
LABEL hdt
MENU LABEL Hardware Information (HDT)
COM32 hdt.c32
APPEND modules_alias=hdt/modalias.gz pciids=hdt/pciids.gz
LABEL reboot
TEXT HELP
Reboot computer.
The computer's firmware must support APM.
ENDTEXT
MENU LABEL Reboot
COM32 reboot.c32
LABEL poweroff
TEXT HELP
Power off computer.
The computer's firmware must support APM.
ENDTEXT
MENU LABEL Power Off
COM32 poweroff.c32

View file

@ -0,0 +1,21 @@
LABEL wk_linux
TEXT HELP
A live Linux environment
* HW diagnostics, file-based backups, data recovery, etc
ENDTEXT
MENU LABEL Linux
LINUX /%INSTALL_DIR%/boot/%ARCH%/vmlinuz-linux
INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram loglevel=3
LABEL wk_linux_cli
TEXT HELP
A live Linux environment (CLI)
* HW diagnostics, file-based backups, data recovery, etc
ENDTEXT
MENU LABEL Linux (CLI)
LINUX /%INSTALL_DIR%/boot/x86_64/vmlinuz-linux
INITRD /%INSTALL_DIR%/boot/intel-ucode.img,/%INSTALL_DIR%/boot/amd-ucode.img,/%INSTALL_DIR%/boot/x86_64/initramfs-linux.img
APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram nox
SYSAPPEND 3

View file

@ -3,6 +3,6 @@ LABEL memtest
MENU LABEL Memtest86+ MENU LABEL Memtest86+
TEXT HELP TEXT HELP
Perform RAM diagnostics Perform RAM diagnostics
* This utility is not recommended for testing DDR4 RAM
ENDTEXT ENDTEXT
LINUX memtest.bin LINUX /%INSTALL_DIR%/boot/memtest
APPEND nobigstatus nopause

View file

View file

@ -1,11 +1,53 @@
DEFAULT select SERIAL 0 115200
UI vesamenu.c32
MENU TITLE _______
MENU BACKGROUND syslinux.png
LABEL select MENU WIDTH 80
COM32 whichsys.c32 MENU MARGIN 10
APPEND -pxe- pxe -sys- sys -iso- sys MENU ROWS 15
MENU VSHIFT 2
MENU TABMSGROW 22
MENU CMDLINEROW 22
MENU HELPMSGROW 24
MENU HELPMSGENDROW -1
MENU TABMSG
LABEL pxe # Refer to http://syslinux.zytor.com/wiki/index.php/Doc/menu
CONFIG archiso_pxe.cfg
LABEL sys MENU COLOR screen 30;44 #a0000000 #a0000000 none
CONFIG archiso_sys.cfg MENU COLOR border 30;44 #a0000000 #a0000000 none
MENU COLOR title 1;36;44 #9033ccff #a0000000 none
MENU COLOR sel 7;37;40 #e0ffffff #a0000000 std
MENU COLOR disabled 37;44 #50ffffff #a0000000 none
MENU COLOR unsel 37;44 #50ffffff #a0000000 none
MENU COLOR help 37;40 #c0ffffff #a0000000 none
MENU COLOR tabmsg 30;44 #a0000000 #a0000000 none
MENU COLOR cmdmark 1;36;44 #9033ccff #a0000000 none
MENU COLOR cmdline 37;40 #c0ffffff #a0000000 none
MENU COLOR timeout_msg 37;40 #80ffffff #a0000000 none
MENU COLOR timeout 1;37;40 #c0ffffff #a0000000 none
MENU COLOR msg07 37;40 #90ffffff #a0000000 none
MENU COLOR tabmsg 31;40 #30ffffff #a0000000 none
# Start entries
MENU SEPARATOR
MENU CLEAR
DEFAULT wk_linux
TIMEOUT 0
INCLUDE linux.cfg
INCLUDE memtest.cfg
#UFD-WINPE#INCLUDE winpe.cfg
MENU SEPARATOR
LABEL reboot
MENU LABEL Reboot
COM32 reboot.c32
LABEL poweroff
MENU LABEL Power Off
COM32 poweroff.c32

View file

@ -5,4 +5,4 @@ A live Windows environment
ENDTEXT ENDTEXT
MENU LABEL Windows PE MENU LABEL Windows PE
COM32 linux.c32 COM32 linux.c32
APPEND wimboot gui initrdfile=/sources/bootmgr,/sources/BCD,/sources/boot.sdi,/sources/boot.wim APPEND wimboot/wimboot gui initrdfile=/sources/bootmgr,/sources/BCD,/sources/boot.sdi,/sources/boot.wim

View file

@ -101,7 +101,7 @@ elif [[ "${OS_VERSION:0:5}" == "10.15" ]]; then
fi fi
# Python3 Packages # Python3 Packages
pip3 install mysql-connector NumPy psutil pylint pytz requests pip3 install docopt mysql-connector NumPy psutil pylint pytz requests
git clone https://github.com/yuyichao/gnuplot-py gnuplot-py git clone https://github.com/yuyichao/gnuplot-py gnuplot-py
cd gnuplot-py cd gnuplot-py

View file

@ -1,3 +1,3 @@
# WizardKit: WinPE # # WizardKit: WinPE #
Requires ADK for Windows 10, version 2004 _Under construction_

View file

@ -0,0 +1,6 @@
[LaunchApp]
[LaunchApps]
wpeinit
wpeutil updatebootinfo
cd /d "%SystemDrive%\.bin"
"%SystemDrive%\.bin\ConEmu\ConEmu.exe", /cmd cmd /k cd "%SystemDrive%\.bin" & python "%SystemDrive%\.bin\Scripts\winpe_root_menu.py"

View file

@ -0,0 +1,2 @@
@echo off
python "%SystemDrive%\.bin\Scripts\winpe_root_menu.py"

View file

@ -1,6 +0,0 @@
[LaunchApp]
[LaunchApps]
wpeinit
wpeutil InitializeNetwork
wpeutil UpdateBootInfo
"%SystemDrive%\Program Files\ConEmu\ConEmu64.exe", /cmd cmd

View file

@ -1,5 +0,0 @@
notepad="%ProgramFiles%\NotepadPlusPlus\notepad++.exe" $*
poweroff=wpeutil shutdown
reboot=wpeutil reboot
restart=wpeutil reboot
shutdown=wpeutil shutdown

View file

@ -0,0 +1,20 @@
[CPU-Z]
VERSION=1.7.7.0
TextFontName=
TextFontSize=14
TextFontColor=000080
LabelFontName=
LabelFontSize=14
ACPI=1
PCI=1
MaxPCIBus=256
DMI=1
Sensor=1
SMBus=1
Display=1
UseDisplayAPI=1
BusClock=1
Chipset=1
SPD=1
XOC=0
CheckUpdates=0

Some files were not shown because too many files have changed in this diff Show more