From 0a1de91a29b802962e123966e370befd3894cb6d Mon Sep 17 00:00:00 2001 From: Viorel Date: Mon, 1 Jan 2024 12:38:06 +0200 Subject: [PATCH 01/99] Add option for NVIDIA GPU support --- CMakeLists.txt | 13 ++++++++++--- src/detection/gpu/gpu_linux.c | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21f0051a8..c0dbe7f4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF) option(BUILD_TESTS "Build tests" OFF) # Also create test executables option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds +option(ENABLE_NVIDIA_GPU "Enable Nvidia NVML" ON) #################### # Compiler options # @@ -405,7 +406,6 @@ if(LINUX) src/detection/displayserver/linux/xlib.c src/detection/font/font_linux.c src/detection/gpu/gpu_linux.c - src/detection/gpu/gpu_nvidia.c src/detection/gtk_qt/gtk.c src/detection/host/host_linux.c src/detection/icons/icons_linux.c @@ -519,7 +519,6 @@ elseif(BSD) src/detection/displayserver/linux/xlib.c src/detection/font/font_linux.c src/detection/gpu/gpu_linux.c - src/detection/gpu/gpu_nvidia.c src/detection/gtk_qt/gtk.c src/detection/host/host_bsd.c src/detection/lm/lm_linux.c @@ -630,7 +629,6 @@ elseif(WIN32) src/detection/displayserver/displayserver_windows.c src/detection/font/font_windows.c src/detection/gpu/gpu_windows.c - src/detection/gpu/gpu_nvidia.c src/detection/gpu/gpu_intel.c src/detection/gpu/gpu_amd.c src/detection/host/host_windows.c @@ -676,6 +674,11 @@ if(ENABLE_DIRECTX_HEADERS) list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_wsl.cpp) endif() +if(ENABLE_NVIDIA_GPU AND (LINUX OR BSD OR WIN32)) + message(STATUS "Enabling Nvidia NVML") + list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_nvidia.c) +endif() + include(CheckFunctionExists) check_function_exists(wcwidth HAVE_WCWIDTH) if(NOT HAVE_WCWIDTH) @@ -699,6 +702,10 @@ add_library(libfastfetch OBJECT ${LIBFASTFETCH_SRC} ) +if(ENABLE_NVIDIA_GPU AND (LINUX OR BSD OR WIN32)) + target_compile_definitions(libfastfetch PRIVATE FF_HAVE_NVIDIA_GPU=1) +endif() + if(yyjson_FOUND) target_compile_definitions(libfastfetch PRIVATE FF_USE_SYSTEM_YYJSON) target_link_libraries(libfastfetch PRIVATE yyjson) diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index 1a7a19607..afdbac355 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -245,6 +245,7 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpu->temperature = FF_GPU_TEMP_UNSET; gpu->frequency = FF_GPU_FREQUENCY_UNSET; + #ifdef FF_HAVE_NVIDIA_GPU if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific)) { ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) { @@ -266,6 +267,7 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET) gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED; } + #endif #ifdef __linux__ if(options->temp && gpu->temperature != gpu->temperature) From 21353b825603fbfed4db6ad46b48d573ed9eccce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 2 Jan 2024 10:24:19 +0800 Subject: [PATCH 02/99] CMake (GPU): change `ENABLE_NVIDIA_GPU` to `ENABLE_PROPRIETARY_GPU_DRIVER_API` --- CMakeLists.txt | 20 ++++++++++++-------- src/common/init.c | 9 +++++++++ src/detection/gpu/gpu_linux.c | 9 ++++++--- src/detection/gpu/gpu_windows.c | 9 ++++++++- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0dbe7f4a..43d6459a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,9 +74,9 @@ cmake_dependent_option(ENABLE_PCI_MEMORY "Enable detecting GPU memory size with option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF) option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF) +option(ENABLE_PROPRIETARY_GPU_DRIVER_API "Enable proprietary GPU driver API (NVML, IGCL and AGS)" ON) option(BUILD_TESTS "Build tests" OFF) # Also create test executables option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds -option(ENABLE_NVIDIA_GPU "Enable Nvidia NVML" ON) #################### # Compiler options # @@ -629,8 +629,6 @@ elseif(WIN32) src/detection/displayserver/displayserver_windows.c src/detection/font/font_windows.c src/detection/gpu/gpu_windows.c - src/detection/gpu/gpu_intel.c - src/detection/gpu/gpu_amd.c src/detection/host/host_windows.c src/detection/icons/icons_windows.c src/detection/libc/libc_windows.cpp @@ -674,9 +672,15 @@ if(ENABLE_DIRECTX_HEADERS) list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_wsl.cpp) endif() -if(ENABLE_NVIDIA_GPU AND (LINUX OR BSD OR WIN32)) - message(STATUS "Enabling Nvidia NVML") - list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_nvidia.c) +if(ENABLE_PROPRIETARY_GPU_DRIVER_API AND (LINUX OR BSD OR WIN32)) + message(STATUS "Enabling proprietary GPU driver API") + if(LINUX OR BSD OR WIN32) + list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_nvidia.c) + endif() + if(WIN32) + list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_intel.c) + list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_amd.c) + endif() endif() include(CheckFunctionExists) @@ -702,8 +706,8 @@ add_library(libfastfetch OBJECT ${LIBFASTFETCH_SRC} ) -if(ENABLE_NVIDIA_GPU AND (LINUX OR BSD OR WIN32)) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_NVIDIA_GPU=1) +if(ENABLE_PROPRIETARY_GPU_DRIVER_API AND (LINUX OR BSD OR WIN32)) + target_compile_definitions(libfastfetch PRIVATE FF_USE_PROPRIETARY_GPU_DRIVER_API) endif() if(yyjson_FOUND) diff --git a/src/common/init.c b/src/common/init.c index 12724aa2d..358cc113d 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -244,6 +244,15 @@ void ffListFeatures(void) #ifdef FF_HAVE_DIRECTX_HEADERS "Directx Headers\n" #endif + #ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API + "Proprietary GPU driver API\n" + #endif + #ifdef FF_USE_SYSTEM_YYJSON + "System yyjson\n" + #endif + #ifdef FF_USE_PCI_MEMORY + "PCI memory\n" + #endif "" , stdout); } diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index afdbac355..340893090 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -1,7 +1,10 @@ #include "detection/gpu/gpu.h" -#include "detection/gpu/gpu_driver_specific.h" #include "detection/vulkan/vulkan.h" +#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API + #include "detection/gpu/gpu_driver_specific.h" +#endif + #ifdef FF_HAVE_LIBPCI #include "common/io/io.h" #include "common/library.h" @@ -245,7 +248,7 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpu->temperature = FF_GPU_TEMP_UNSET; gpu->frequency = FF_GPU_FREQUENCY_UNSET; - #ifdef FF_HAVE_NVIDIA_GPU + #ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific)) { ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) { @@ -267,7 +270,7 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET) gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED; } - #endif + #endif // FF_USE_PROPRIETARY_GPU_DRIVER_API #ifdef __linux__ if(options->temp && gpu->temperature != gpu->temperature) diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index 719d98a50..3096e0a52 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -1,8 +1,11 @@ #include "gpu.h" -#include "detection/gpu/gpu_driver_specific.h" #include "util/windows/unicode.h" #include "util/windows/registry.h" +#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API + #include "detection/gpu/gpu_driver_specific.h" +#endif + #include static int isGpuNameEqual(const FFGPUResult* gpu, const FFstrbuf* name) @@ -10,6 +13,7 @@ static int isGpuNameEqual(const FFGPUResult* gpu, const FFstrbuf* name) return ffStrbufEqual(&gpu->name, name); } +#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API static inline bool getDriverSpecificDetectionFn(const char* vendor, __typeof__(&ffDetectNvidiaGpuInfo)* pDetectFn, const char** pDllName) { if (vendor == FF_GPU_VENDOR_NAME_NVIDIA) @@ -44,6 +48,7 @@ static inline bool getDriverSpecificDetectionFn(const char* vendor, __typeof__(& return true; } +#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus) { @@ -139,6 +144,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* } } +#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API __typeof__(&ffDetectNvidiaGpuInfo) detectFn; const char* dllName; @@ -168,6 +174,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* ); } } +#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API } return NULL; From ab028964bffcdedf729a3568fd24518017f2bfc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 2 Jan 2024 18:47:06 +0800 Subject: [PATCH 03/99] GPU (WSL): add missing `FF_USE_PROPRIETARY_GPU_DRIVER_API` macro guards --- src/detection/gpu/gpu_wsl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detection/gpu/gpu_wsl.cpp b/src/detection/gpu/gpu_wsl.cpp index a847a53ec..91d67e54a 100644 --- a/src/detection/gpu/gpu_wsl.cpp +++ b/src/detection/gpu/gpu_wsl.cpp @@ -98,6 +98,7 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF const char* vendorStr = ffGetGPUVendorString((unsigned) hardwareId.vendorID); ffStrbufSetStatic(&gpu->vendor, vendorStr); + #ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && (options->driverSpecific || options->temp)) { FFGpuDriverCondition cond = { @@ -117,6 +118,7 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF .frequency = &gpu->frequency, }, "/usr/lib/wsl/lib/libnvidia-ml.so"); } + #endif } } From ff0f91dc3cb6d1a218a2c6b45b2c8d7b4aed3624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 3 Jan 2024 09:41:02 +0800 Subject: [PATCH 04/99] macOS: fix mem leaks --- CMakeLists.txt | 2 ++ src/detection/os/os_apple.m | 11 ++++------- src/detection/wifi/wifi_apple.m | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43d6459a4..de7abbfab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,8 @@ endif() if(WIN32) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--tsaware -Wl,--build-id -Wl,--subsystem,console:6.1,--major-os-version,6,--minor-os-version,1") +elseif(APPLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-arc") endif() # Used for dlopen finding dylibs installed by homebrew diff --git a/src/detection/os/os_apple.m b/src/detection/os/os_apple.m index 70687811e..dbb55539e 100644 --- a/src/detection/os/os_apple.m +++ b/src/detection/os/os_apple.m @@ -1,6 +1,8 @@ #include "os.h" +#include "common/io/io.h" #include "common/sysctl.h" #include "util/stringUtils.h" +#include "util/mallocHelper.h" #include #include @@ -72,11 +74,11 @@ static bool detectOSCodeName(FFOSResult* os) static void parseOSXSoftwareLicense(FFOSResult* os) { - FILE* rtf = fopen("/System/Library/CoreServices/Setup Assistant.app/Contents/Resources/en.lproj/OSXSoftwareLicense.rtf", "r"); + FF_AUTO_CLOSE_FILE FILE* rtf = fopen("/System/Library/CoreServices/Setup Assistant.app/Contents/Resources/en.lproj/OSXSoftwareLicense.rtf", "r"); if(rtf == NULL) return; - char* line = NULL; + FF_AUTO_FREE char* line = NULL; size_t len = 0; const char* searchStr = "\\f0\\b SOFTWARE LICENSE AGREEMENT FOR macOS "; while(getline(&line, &len, rtf) != EOF) @@ -89,11 +91,6 @@ static void parseOSXSoftwareLicense(FFOSResult* os) break; } } - - if(line != NULL) - free(line); - - fclose(rtf); } void ffDetectOSImpl(FFOSResult* os) diff --git a/src/detection/wifi/wifi_apple.m b/src/detection/wifi/wifi_apple.m index 4402b0170..64d90ccb2 100644 --- a/src/detection/wifi/wifi_apple.m +++ b/src/detection/wifi/wifi_apple.m @@ -17,7 +17,7 @@ static NSDictionary* getWifiInfoByApple80211(NSString* ifName) struct Apple80211* handle = NULL; if (Apple80211Open(&handle) < 0) return NULL; - if (Apple80211BindToInterface(handle, (CFStringRef)ifName) < 0) return NULL; + if (Apple80211BindToInterface(handle, (__bridge CFStringRef)ifName) < 0) return NULL; CFDictionaryRef result; if (Apple80211GetInfoCopy(handle, &result) < 0) return NULL; Apple80211Close(handle); From 83ce3e455446dbab64fbf54bc7e892204bf234f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 3 Jan 2024 10:12:37 +0800 Subject: [PATCH 05/99] Wallpaper (macOS): support Sonoma --- CMakeLists.txt | 2 +- src/detection/wallpaper/wallpaper_apple.c | 30 ---------- src/detection/wallpaper/wallpaper_apple.m | 72 +++++++++++++++++++++++ 3 files changed, 73 insertions(+), 31 deletions(-) delete mode 100644 src/detection/wallpaper/wallpaper_apple.c create mode 100644 src/detection/wallpaper/wallpaper_apple.m diff --git a/CMakeLists.txt b/CMakeLists.txt index de7abbfab..83d9105e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -601,7 +601,7 @@ elseif(APPLE) src/detection/theme/theme_nosupport.c src/detection/uptime/uptime_bsd.c src/detection/users/users_linux.c - src/detection/wallpaper/wallpaper_apple.c + src/detection/wallpaper/wallpaper_apple.m src/detection/wifi/wifi_apple.m src/detection/wm/wm_apple.c src/detection/de/de_nosupport.c diff --git a/src/detection/wallpaper/wallpaper_apple.c b/src/detection/wallpaper/wallpaper_apple.c deleted file mode 100644 index 87691abb4..000000000 --- a/src/detection/wallpaper/wallpaper_apple.c +++ /dev/null @@ -1,30 +0,0 @@ -#include "wallpaper.h" -#include "common/settings.h" -#include "util/apple/osascript.h" - -const char* ffDetectWallpaper(FFstrbuf* result) -{ - // https://stackoverflow.com/questions/301215/getting-desktop-background-on-mac - - #ifdef FF_HAVE_SQLITE3 - - FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&instance.state.platform.homeDir); - ffStrbufAppendS(&path, "Library/Application Support/Dock/desktoppicture.db"); - if (ffSettingsGetSQLite3String(path.chars, - "SELECT value\n" - "FROM preferences\n" - "JOIN data ON preferences.data_id=data.ROWID\n" - "JOIN pictures ON preferences.picture_id=pictures.ROWID\n" - "JOIN displays ON pictures.display_id=displays.ROWID\n" - "JOIN spaces ON pictures.space_id=spaces.ROWID\n" - "WHERE display_id=1 AND space_id=1 AND key=1", result) - ) - return NULL; - - #endif - - if (!ffOsascript("tell application \"Finder\" to get POSIX path of (get desktop picture as alias)", result)) - return "ffOsascript(get desktop picture) failed"; - - return NULL; -} diff --git a/src/detection/wallpaper/wallpaper_apple.m b/src/detection/wallpaper/wallpaper_apple.m new file mode 100644 index 000000000..eb330dda1 --- /dev/null +++ b/src/detection/wallpaper/wallpaper_apple.m @@ -0,0 +1,72 @@ +#include "wallpaper.h" +#include "common/settings.h" +#include "util/apple/osascript.h" + +#import + +const char* ffDetectWallpaper(FFstrbuf* result) +{ + { + // For Sonoma + // https://github.com/JohnCoates/Aerial/issues/1332 + NSError* error; + NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Application Support/com.apple.wallpaper/Store/Index.plist", instance.state.platform.homeDir.chars]; + NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName] + error:&error]; + if (!error) + { + NSArray* choices = [dict valueForKeyPath:@"SystemDefault.Desktop.Content.Choices"]; + if (choices.count > 0) + { + NSDictionary* choice = [choices objectAtIndex:0]; + NSArray* files = [choice valueForKey:@"Files"]; + if (files.count > 0) + { + NSString* file = [[files objectAtIndex: 0] valueForKey: @"relative"]; + ffStrbufAppendS(result, [NSURL URLWithString:file].path.UTF8String); + } + else + { + NSString* provider = [choice valueForKey:@"Provider"]; + NSString* builtinPrefix = @"com.apple.wallpaper.choice."; + if ([provider hasPrefix:builtinPrefix]) + provider = [provider substringFromIndex:builtinPrefix.length]; + if ([provider isEqualToString:@"sonoma"]) + ffStrbufSetStatic(result, "macOS Sonoma"); + else if ([provider isEqualToString:@"aerials"]) // Most builtin aerial wallpapers are private + ffStrbufSetStatic(result, "Built-in aerial photography"); + else + ffStrbufAppendF(result, "Built-in %s wallpaper", provider.UTF8String); + } + } + if (result->length > 0) + return NULL; + } + } + + #ifdef FF_HAVE_SQLITE3 + + { + // For Ventura + // https://stackoverflow.com/questions/301215/getting-desktop-background-on-mac + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&instance.state.platform.homeDir); + ffStrbufAppendS(&path, "Library/Application Support/Dock/desktoppicture.db"); + if (ffSettingsGetSQLite3String(path.chars, + "SELECT value\n" + "FROM preferences\n" + "JOIN data ON preferences.data_id=data.ROWID\n" + "JOIN pictures ON preferences.picture_id=pictures.ROWID\n" + "JOIN displays ON pictures.display_id=displays.ROWID\n" + "JOIN spaces ON pictures.space_id=spaces.ROWID\n" + "WHERE display_id=1 AND space_id=1 AND key=1", result) + ) + return NULL; + } + + #endif + + if (ffOsascript("tell application \"Finder\" to get POSIX path of (get desktop picture as alias)", result)) + return NULL; + + return "All detection methods failed"; +} From 66982834301fb79d7b29990df6ada31deea5ccf2 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 4 Jan 2024 10:29:02 +0800 Subject: [PATCH 06/99] GPU: fix vendor detection for asahi --- src/detection/gpu/gpu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/detection/gpu/gpu.c b/src/detection/gpu/gpu.c index 435d687aa..66e11c805 100644 --- a/src/detection/gpu/gpu.c +++ b/src/detection/gpu/gpu.c @@ -73,15 +73,17 @@ const char* detectByOpenGL(FFlist* gpus) if (!gpu->vendor.length) { - if (ffStrbufContainS(&result.renderer, "Apple")) + if (ffStrbufContainS(&gpu->name, "Apple")) ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE); - else if (ffStrbufContainS(&result.renderer, "Intel")) + else if (ffStrbufContainS(&gpu->name, "Intel")) ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL); - else if (ffStrbufContainS(&result.renderer, "AMD") || ffStrbufContainS(&result.renderer, "ATI")) + else if (ffStrbufContainS(&gpu->name, "AMD") || ffStrbufContainS(&gpu->name, "ATI")) ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD); - else if (ffStrbufContainS(&result.renderer, "NVIDIA")) + else if (ffStrbufContainS(&gpu->name, "NVIDIA")) ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA); } + if (ffStrbufEqualS(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE)) + gpu->type = FF_GPU_TYPE_INTEGRATED; } ffStrbufDestroy(&result.version); From cd0109c382d02eddd67e5739f3517b82d5681179 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 4 Jan 2024 14:18:06 +0800 Subject: [PATCH 07/99] Battery (Linux): remove option `--battery-dir` It was added in c5c3cecb935b86713e2b1fef741b9cf7ee2acccc but there was no comment or issues linked to indicate why it was necessary. `/sys/class/power_supply` is standardized in . I don't I want to support non-standard platform unless proper reason is given --- completions/bash | 1 - doc/json_schema.json | 4 ---- src/data/help.json | 9 --------- src/detection/battery/battery_linux.c | 7 +++---- src/modules/battery/battery.c | 29 +-------------------------- src/modules/battery/option.h | 4 +--- 6 files changed, 5 insertions(+), 49 deletions(-) diff --git a/completions/bash b/completions/bash index c6e7b26dc..71f21649d 100644 --- a/completions/bash +++ b/completions/bash @@ -384,7 +384,6 @@ __fastfetch_completion() "--lib-pulse" "--lib-ddcutil" "--lib-nm" - "--battery-dir" ) local FF_OPTIONS_LOGO=( diff --git a/doc/json_schema.json b/doc/json_schema.json index dd097dbe6..78a4116b0 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -804,10 +804,6 @@ "const": "battery", "description": "Print battery capacity, status, etc" }, - "dir": { - "description": "The directory where the battery folders are. Standard: `/sys/class/power_supply/`. Linux only", - "type": "string" - }, "useSetupApi": { "description": "Set if `SetupAPI` should be used on Windows to detect battery info, which supports multi batteries, but slower. Windows only", "type": "boolean", diff --git a/src/data/help.json b/src/data/help.json index 44f264caf..3af8895cc 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1026,15 +1026,6 @@ "default": "main" } }, - { - "long": "battery-dir", - "desc": "The directory where the battery folders are", - "remark": "Linux only", - "arg": { - "type": "path", - "default": "/sys/class/power_supply/" - } - }, { "long": "battery-use-setup-api", "desc": "Set if \"SetupAPI\" should be used on Windows to detect battery info", diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index 04b8a9a0a..e8bc4c223 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -101,14 +101,13 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) { FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64); - ffStrbufAppend(&baseDir, &options->dir); - ffStrbufEnsureEndsWithC(&baseDir, '/'); + ffStrbufAppend(&baseDir, "/sys/class/power_supply/"); uint32_t baseDirLength = baseDir.length; FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars); if(dirp == NULL) - return "opendir(batteryDir) == NULL"; + return "opendir(\"/sys/class/power_supply/\") == NULL"; struct dirent* entry; while((entry = readdir(dirp)) != NULL) @@ -122,7 +121,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) } if(results->length == 0) - return "batteryDir doesn't contain any battery folder"; + return "\"/sys/class/power_supply/\" doesn't contain any battery folder"; return NULL; } diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 0946ad0c0..28d44679e 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -115,14 +115,6 @@ bool ffParseBatteryCommandOptions(FFBatteryOptions* options, const char* key, co return true; } - #ifdef __linux__ - if (ffStrEqualsIgnCase(subKey, "dir")) - { - ffOptionParseString(key, value, &options->dir); - return true; - } - #endif - #ifdef _WIN32 if (ffStrEqualsIgnCase(subKey, "use-setup-api")) { @@ -147,14 +139,6 @@ void ffParseBatteryJsonObject(FFBatteryOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; - #ifdef __linux__ - if (ffStrEqualsIgnCase(key, "dir")) - { - ffStrbufSetS(&options->dir, yyjson_get_str(val)); - continue; - } - #endif - #ifdef _WIN32 if (ffStrEqualsIgnCase(key, "useSetupApi")) { @@ -180,11 +164,6 @@ void ffGenerateBatteryJsonConfig(FFBatteryOptions* options, yyjson_mut_doc* doc, ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); - #ifdef __linux__ - if (!ffStrbufEqual(&defaultOptions.dir, &options->dir)) - yyjson_mut_obj_add_strbuf(doc, module, "dir", &options->dir); - #endif - #ifdef _WIN32 if (defaultOptions.useSetupApi != options->useSetupApi) yyjson_mut_obj_add_bool(doc, module, "useSetupApi", options->useSetupApi); @@ -257,9 +236,7 @@ void ffInitBatteryOptions(FFBatteryOptions* options) ffOptionInitModuleArg(&options->moduleArgs); options->temp = false; - #ifdef __linux__ - ffStrbufInitStatic(&options->dir, "/sys/class/power_supply/"); - #elif defined(_WIN32) + #ifdef _WIN32 options->useSetupApi = false; #endif } @@ -267,8 +244,4 @@ void ffInitBatteryOptions(FFBatteryOptions* options) void ffDestroyBatteryOptions(FFBatteryOptions* options) { ffOptionDestroyModuleArg(&options->moduleArgs); - - #ifdef __linux__ - ffStrbufDestroy(&options->dir); - #endif } diff --git a/src/modules/battery/option.h b/src/modules/battery/option.h index 89f05bab4..401816ae7 100644 --- a/src/modules/battery/option.h +++ b/src/modules/battery/option.h @@ -11,9 +11,7 @@ typedef struct FFBatteryOptions bool temp; - #ifdef __linux__ - FFstrbuf dir; - #elif defined(_WIN32) + #ifdef _WIN32 bool useSetupApi; #endif } FFBatteryOptions; From b6b1993f6213ac172833bc0f841838e0820853ce Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 4 Jan 2024 14:31:11 +0800 Subject: [PATCH 08/99] Battery (Linux): code refactor, support serial number detection --- src/detection/battery/battery.h | 3 +- src/detection/battery/battery_linux.c | 63 ++++++++++++++------------- src/util/FFstrbuf.c | 7 +++ src/util/FFstrbuf.h | 1 + 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/detection/battery/battery.h b/src/detection/battery/battery.h index 6dfe6466b..8165d1961 100644 --- a/src/detection/battery/battery.h +++ b/src/detection/battery/battery.h @@ -9,8 +9,9 @@ typedef struct FFBatteryResult FFstrbuf manufacturer; FFstrbuf modelName; FFstrbuf technology; - double capacity; FFstrbuf status; + FFstrbuf serial; + double capacity; double temperature; uint32_t cycleCount; } FFBatteryResult; diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index e8bc4c223..d37f174d5 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -9,76 +9,77 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option { uint32_t dirLength = dir->length; - FF_STRBUF_AUTO_DESTROY testBatteryBuffer = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY tmpBuffer = ffStrbufCreate(); //type must exist and be "Battery" ffStrbufAppendS(dir, "/type"); - ffReadFileBuffer(dir->chars, &testBatteryBuffer); - ffStrbufTrimRightSpace(&testBatteryBuffer); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + ffStrbufTrimRightSpace(&tmpBuffer); ffStrbufSubstrBefore(dir, dirLength); - if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Battery") != 0) + if(!ffStrbufIgnCaseEqualS(&tmpBuffer, "Battery")) return; //scope may not exist or must not be "Device" ffStrbufAppendS(dir, "/scope"); - ffReadFileBuffer(dir->chars, &testBatteryBuffer); - ffStrbufTrimRightSpace(&testBatteryBuffer); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + ffStrbufTrimRightSpace(&tmpBuffer); ffStrbufSubstrBefore(dir, dirLength); - if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Device") == 0) + if(ffStrbufIgnCaseEqualS(&tmpBuffer, "Device")) return; - FFBatteryResult* result = ffListAdd(results); - //capacity must exist and be not empty ffStrbufAppendS(dir, "/capacity"); - bool available = ffReadFileBuffer(dir->chars, &testBatteryBuffer); + bool available = ffReadFileBuffer(dir->chars, &tmpBuffer); ffStrbufSubstrBefore(dir, dirLength); - if(available) - result->capacity = ffStrbufToDouble(&testBatteryBuffer); - if(!available) - { - result->capacity = 0.0/0.0; - --results->length; + if (!available) return; - } + + FFBatteryResult* result = ffListAdd(results); + result->capacity = ffStrbufToDouble(&tmpBuffer); //At this point, we have a battery. Try to get as much values as possible. ffStrbufInit(&result->manufacturer); ffStrbufAppendS(dir, "/manufacturer"); - ffReadFileBuffer(dir->chars, &result->manufacturer); - ffStrbufTrimRightSpace(&result->manufacturer); + if (ffReadFileBuffer(dir->chars, &result->manufacturer)) + ffStrbufTrimRightSpace(&result->manufacturer); + else if (ffStrEquals(id, "macsmc-battery")) // asahi + ffStrbufSetStatic(&result->manufacturer, "Apple Inc."); ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->modelName); ffStrbufAppendS(dir, "/model_name"); - ffReadFileBuffer(dir->chars, &result->modelName); - ffStrbufTrimRightSpace(&result->modelName); + if (ffReadFileBuffer(dir->chars, &result->modelName)) + ffStrbufTrimRightSpace(&result->modelName); ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->technology); ffStrbufAppendS(dir, "/technology"); - ffReadFileBuffer(dir->chars, &result->technology); - ffStrbufTrimRightSpace(&result->technology); + if (ffReadFileBuffer(dir->chars, &result->technology)) + ffStrbufTrimRightSpace(&result->technology); ffStrbufSubstrBefore(dir, dirLength); ffStrbufInit(&result->status); ffStrbufAppendS(dir, "/status"); - ffReadFileBuffer(dir->chars, &result->status); - ffStrbufTrimRightSpace(&result->status); + if (ffReadFileBuffer(dir->chars, &result->status)) + ffStrbufTrimRightSpace(&result->status); + ffStrbufSubstrBefore(dir, dirLength); + + ffStrbufInit(&result->serial); + ffStrbufAppendS(dir, "/serial_number"); + if (ffReadFileBuffer(dir->chars, &result->serial)) + ffStrbufTrimRightSpace(&result->serial); ffStrbufSubstrBefore(dir, dirLength); ffStrbufAppendS(dir, "/cycle_count"); - ffReadFileBuffer(dir->chars, &testBatteryBuffer); - ffStrbufTrimRightSpace(&testBatteryBuffer); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); ffStrbufSubstrBefore(dir, dirLength); - if (dir->length) + if (available) { - int64_t cycleCount = 0; - cycleCount = (int64_t) strtoll(testBatteryBuffer.chars, NULL, 10); + int64_t cycleCount = ffStrbufToSInt(&tmpBuffer, 0); result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount; } @@ -101,7 +102,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) { FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64); - ffStrbufAppend(&baseDir, "/sys/class/power_supply/"); + ffStrbufAppendS(&baseDir, "/sys/class/power_supply/"); uint32_t baseDirLength = baseDir.length; diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index 703b4055d..3637c6c44 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -470,6 +470,13 @@ uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue) return str_end == strbuf->chars ? defaultValue : (uint64_t)result; } +int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue) +{ + char* str_end; + long long result = strtoll(strbuf->chars, &str_end, 10); + return str_end == strbuf->chars ? defaultValue : (int64_t)result; +} + void ffStrbufUpperCase(FFstrbuf* strbuf) { for (uint32_t i = 0; i < strbuf->length; ++i) diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index df4a70951..7f67126af 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -83,6 +83,7 @@ void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file); void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file); FF_C_NODISCARD double ffStrbufToDouble(const FFstrbuf* strbuf); +FF_C_NODISCARD int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue); FF_C_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue); void ffStrbufUpperCase(FFstrbuf* strbuf); From 5c75e271ef6c51f417744f4d1fcab8d0a487bd52 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 4 Jan 2024 13:54:11 +0800 Subject: [PATCH 09/99] PowerAdapter (Linux): add support --- CMakeLists.txt | 2 +- src/detection/poweradapter/poweradapter.h | 2 +- .../poweradapter/poweradapter_apple.c | 2 +- .../poweradapter/poweradapter_linux.c | 96 +++++++++++++++++++ .../poweradapter/poweradapter_nosupport.c | 5 +- src/modules/poweradapter/poweradapter.c | 4 +- 6 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/detection/poweradapter/poweradapter_linux.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 83d9105e5..4e0624a46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -422,7 +422,7 @@ if(LINUX) src/detection/opengl/opengl_linux.c src/detection/os/os_linux.c src/detection/packages/packages_linux.c - src/detection/poweradapter/poweradapter_nosupport.c + src/detection/poweradapter/poweradapter_linux.c src/detection/processes/processes_linux.c src/detection/gtk_qt/qt.c src/detection/sound/sound_linux.c diff --git a/src/detection/poweradapter/poweradapter.h b/src/detection/poweradapter/poweradapter.h index 21c93b64a..405480690 100644 --- a/src/detection/poweradapter/poweradapter.h +++ b/src/detection/poweradapter/poweradapter.h @@ -11,7 +11,7 @@ typedef struct FFPowerAdapterResult int watts; } FFPowerAdapterResult; -const char* ffDetectPowerAdapterImpl(FFlist* results); +const char* ffDetectPowerAdapter(FFlist* results); #define FF_POWERADAPTER_UNSET -2 #define FF_POWERADAPTER_NOT_CONNECTED -1 diff --git a/src/detection/poweradapter/poweradapter_apple.c b/src/detection/poweradapter/poweradapter_apple.c index 435532ee4..7c17a4f0b 100644 --- a/src/detection/poweradapter/poweradapter_apple.c +++ b/src/detection/poweradapter/poweradapter_apple.c @@ -4,7 +4,7 @@ #include -const char* ffDetectPowerAdapterImpl(FFlist* results) +const char* ffDetectPowerAdapter(FFlist* results) { io_iterator_t iterator; if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess) diff --git a/src/detection/poweradapter/poweradapter_linux.c b/src/detection/poweradapter/poweradapter_linux.c new file mode 100644 index 000000000..b514c2590 --- /dev/null +++ b/src/detection/poweradapter/poweradapter_linux.c @@ -0,0 +1,96 @@ +#include "poweradapter.h" +#include "common/io/io.h" +#include "util/stringUtils.h" + +#include + +static void parsePowerAdapter(FFstrbuf* dir, FF_MAYBE_UNUSED const char* id, FFlist* results) +{ + uint32_t dirLength = dir->length; + + FF_STRBUF_AUTO_DESTROY tmpBuffer = ffStrbufCreate(); + + //type must exist and be "Mains" + ffStrbufAppendS(dir, "/type"); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + ffStrbufTrimRightSpace(&tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + + if(!ffStrbufIgnCaseEqualS(&tmpBuffer, "Mains")) + return; + + //scope may not exist or must not be "Device" (?) + ffStrbufAppendS(dir, "/scope"); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + ffStrbufTrimRightSpace(&tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + + if(ffStrbufIgnCaseEqualS(&tmpBuffer, "Device")) + return; + + //input_power_limit must exist and be not empty + ffStrbufAppendS(dir, "/input_power_limit"); + bool available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + + if (!available) + return; + + FFPowerAdapterResult* result = ffListAdd(results); + ffStrbufInit(&result->name); + ffStrbufInit(&result->description); + + ffStrbufAppendS(dir, "/online"); + char online = '1'; + ffReadFileData(dir->chars, sizeof(online), &online); + ffStrbufSubstrBefore(dir, dirLength); + + if (online == '0') + result->watts = FF_POWERADAPTER_NOT_CONNECTED; + else + result->watts = (int) (ffStrbufToDouble(&tmpBuffer) / 1e6 + 0.5); + + //At this point, we have a battery. Try to get as much values as possible. + + ffStrbufInit(&result->manufacturer); + ffStrbufAppendS(dir, "/manufacturer"); + if (ffReadFileBuffer(dir->chars, &result->manufacturer)) + ffStrbufTrimRightSpace(&result->manufacturer); + else if (ffStrEquals(id, "macsmc-ac")) // asahi + ffStrbufSetStatic(&result->manufacturer, "Apple Inc."); + ffStrbufSubstrBefore(dir, dirLength); + + ffStrbufInit(&result->modelName); + ffStrbufAppendS(dir, "/model_name"); + if (ffReadFileBuffer(dir->chars, &result->modelName)) + ffStrbufTrimRightSpace(&result->modelName); + ffStrbufSubstrBefore(dir, dirLength); +} + +const char* ffDetectPowerAdapter(FFlist* results) +{ + FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64); + ffStrbufAppendS(&baseDir, "/sys/class/power_supply/"); + + uint32_t baseDirLength = baseDir.length; + + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars); + if(dirp == NULL) + return "opendir(\"/sys/class/power_supply/\") == NULL"; + + struct dirent* entry; + while((entry = readdir(dirp)) != NULL) + { + if(ffStrEquals(entry->d_name, ".") || ffStrEquals(entry->d_name, "..")) + continue; + + ffStrbufAppendS(&baseDir, entry->d_name); + parsePowerAdapter(&baseDir, entry->d_name, results); + ffStrbufSubstrBefore(&baseDir, baseDirLength); + } + + if(results->length == 0) + return "\"/sys/class/power_supply/\" doesn't contain any power adapter folder"; + + return NULL; +} diff --git a/src/detection/poweradapter/poweradapter_nosupport.c b/src/detection/poweradapter/poweradapter_nosupport.c index 80730810d..1ae9d5395 100644 --- a/src/detection/poweradapter/poweradapter_nosupport.c +++ b/src/detection/poweradapter/poweradapter_nosupport.c @@ -1,7 +1,6 @@ -#include "fastfetch.h" +#include "poweradapter.h" -const char* ffDetectPowerAdapterImpl(FFlist* results) +const char* ffDetectPowerAdapter(FF_MAYBE_UNUSED FFlist* results) { - FF_UNUSED(results); return "Not supported on this platform"; } diff --git a/src/modules/poweradapter/poweradapter.c b/src/modules/poweradapter/poweradapter.c index 3ce00a771..a4f599d4b 100644 --- a/src/modules/poweradapter/poweradapter.c +++ b/src/modules/poweradapter/poweradapter.c @@ -11,7 +11,7 @@ void ffPrintPowerAdapter(FFPowerAdapterOptions* options) { FF_LIST_AUTO_DESTROY results = ffListCreate(sizeof(FFPowerAdapterResult)); - const char* error = ffDetectPowerAdapterImpl(&results); + const char* error = ffDetectPowerAdapter(&results); if (error) { @@ -99,7 +99,7 @@ void ffGeneratePowerAdapterJsonResult(FF_MAYBE_UNUSED FFPowerAdapterOptions* opt { FF_LIST_AUTO_DESTROY results = ffListCreate(sizeof(FFPowerAdapterResult)); - const char* error = ffDetectPowerAdapterImpl(&results); + const char* error = ffDetectPowerAdapter(&results); if (error) { From 1fef41241a7df3282ae7e568ae305bcaff44fa3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 3 Jan 2024 10:31:34 +0800 Subject: [PATCH 10/99] Presets: fix formatation --- presets/examples/9.jsonc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/presets/examples/9.jsonc b/presets/examples/9.jsonc index e2801c248..7c2db86bd 100644 --- a/presets/examples/9.jsonc +++ b/presets/examples/9.jsonc @@ -16,7 +16,10 @@ "separator", "memory", "swap", - "disk", + { + "type": "disk", + "folders": "/" + }, "battery", { "type": "colors", From 6bd909c89d15a02fd469c11abeb47662b48a7df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 3 Jan 2024 10:34:52 +0800 Subject: [PATCH 11/99] Doc: update changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fa519107..9c9c44c9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# 2.5.1 + +Features: +* Add `ENABLE_PROPRIETARY_GPU_DRIVER_API` cmake option to disable using of proprietary GPU driver APIs (GPU) + +Bugfixes: +* Fix support of macOS Sonoma (Wallpaper, macOS) +* Fix overall memory leaks (macOS) + # 2.5.0 Changes: From b5dc4f59f16720d4e195e8517d01c86ed8f6d26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 4 Jan 2024 16:04:34 +0800 Subject: [PATCH 12/99] Battery (macOS): detect serial number --- src/detection/battery/battery_apple.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index f301297f1..2c9db57e2 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -28,6 +28,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) battery->temperature = FF_BATTERY_TEMP_UNSET; ffStrbufInit(&battery->manufacturer); ffStrbufInit(&battery->modelName); + ffStrbufInit(&battery->serial); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->status); battery->capacity = 0.0/0.0; @@ -47,6 +48,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) battery->capacity = currentCapacity * 100.0 / maxCapacity; ffCfDictGetString(properties, CFSTR("DeviceName"), &battery->modelName); + ffCfDictGetString(properties, CFSTR("Serial"), &battery->serial); if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue) { From 10b2fe13bd6c6bcf7e23c47091d11b869a04f7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 4 Jan 2024 16:19:47 +0800 Subject: [PATCH 13/99] Battery (Windows): detect serial number --- src/detection/battery/battery_windows.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index 9deea532c..81e78162e 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -105,6 +105,14 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results ffStrbufSetWS(&battery->manufacturer, name); } + { + ffStrbufInit(&battery->serial); + bqi.InformationLevel = BatterySerialNumber; + wchar_t name[64]; + if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL)) + ffStrbufSetWS(&battery->serial, name); + } + battery->cycleCount = bi.CycleCount; battery->temperature = 0.0/0.0; @@ -150,6 +158,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF ffStrbufInit(&battery->manufacturer); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->status); + ffStrbufInit(&battery->serial); battery->temperature = FF_BATTERY_TEMP_UNSET; battery->cycleCount = 0; From f4f466d4ba7b196cc4a22e4a385e8562276341ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 4 Jan 2024 16:16:43 +0800 Subject: [PATCH 14/99] Battery: print serial number --- src/detection/battery/battery_bsd.c | 1 + src/modules/battery/battery.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/detection/battery/battery_bsd.c b/src/detection/battery/battery_bsd.c index 3edba2a62..cb1e3090e 100644 --- a/src/detection/battery/battery_bsd.c +++ b/src/detection/battery/battery_bsd.c @@ -39,6 +39,7 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r ffStrbufInit(&battery->modelName); ffStrbufInit(&battery->status); ffStrbufInit(&battery->technology); + ffStrbufInit(&battery->serial); battery->capacity = battio.battinfo.cap; if(battio.battinfo.state == ACPI_BATT_STAT_INVALID) diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 28d44679e..733983d20 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -6,7 +6,7 @@ #include "modules/battery/battery.h" #include "util/stringUtils.h" -#define FF_BATTERY_NUM_FORMAT_ARGS 7 +#define FF_BATTERY_NUM_FORMAT_ARGS 8 static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uint8_t index) { @@ -71,6 +71,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin {FF_FORMAT_ARG_TYPE_STRBUF, &result->status}, {FF_FORMAT_ARG_TYPE_DOUBLE, &result->temperature}, {FF_FORMAT_ARG_TYPE_UINT, &result->cycleCount}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->serial}, }); } } @@ -194,6 +195,7 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &battery->modelName); yyjson_mut_obj_add_strbuf(doc, obj, "status", &battery->status); yyjson_mut_obj_add_strbuf(doc, obj, "technology", &battery->technology); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &battery->serial); yyjson_mut_obj_add_real(doc, obj, "temperature", battery->temperature); yyjson_mut_obj_add_uint(doc, obj, "cycleCount", battery->cycleCount); } @@ -204,6 +206,7 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, ffStrbufDestroy(&battery->modelName); ffStrbufDestroy(&battery->technology); ffStrbufDestroy(&battery->status); + ffStrbufDestroy(&battery->serial); } } @@ -217,6 +220,7 @@ void ffPrintBatteryHelpFormat(void) "Battery status", "Battery temperature", "Battery cycle count", + "Battery serial number", }); } From d69e19377e6c6f635ffdd9f68c0bce2579774860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 4 Jan 2024 16:31:41 +0800 Subject: [PATCH 15/99] Doc: update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9c44c9e..5a0ce1b9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ # 2.5.1 +Changes: +* Remove support of option `--battery-dir`. We detect a lot of things in `/sys/class/*` and only module `Battery` supports specifying a custom directory for some reason, which is weird. + Features: * Add `ENABLE_PROPRIETARY_GPU_DRIVER_API` cmake option to disable using of proprietary GPU driver APIs (GPU) +* Add power adapter detection support for Asahi Linux (PowerAdapter, Linux) +* Add battery serial number detection (Battery) Bugfixes: * Fix support of macOS Sonoma (Wallpaper, macOS) From 0e6be69eb8cc99ee21a74dea6e3764362522121c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 4 Jan 2024 18:50:38 +0800 Subject: [PATCH 16/99] GPU (Linux): try detect GPU type --- src/detection/gpu/gpu_nvidia.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/detection/gpu/gpu_nvidia.c b/src/detection/gpu/gpu_nvidia.c index 717d6389b..b55cd3258 100644 --- a/src/detection/gpu/gpu_nvidia.c +++ b/src/detection/gpu/gpu_nvidia.c @@ -12,6 +12,7 @@ struct FFNvmlData { FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo_v2) FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores) FF_LIBRARY_SYMBOL(nvmlDeviceGetClockInfo) + FF_LIBRARY_SYMBOL(nvmlDeviceGetBrand) bool inited; } nvmlData; @@ -32,6 +33,7 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo_v2) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetClockInfo) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetBrand) if (ffnvmlInit_v2() != NVML_SUCCESS) { @@ -79,6 +81,24 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR if (!device) return "Device not found"; } + nvmlBrandType_t brand; + if (nvmlData.ffnvmlDeviceGetBrand(device, &brand) == NVML_SUCCESS) + { + switch (brand) + { + case NVML_BRAND_NVIDIA_RTX: + case NVML_BRAND_QUADRO_RTX: + case NVML_BRAND_GEFORCE: + case NVML_BRAND_TITAN: + case NVML_BRAND_TESLA: + case NVML_BRAND_QUADRO: + *result.type = FF_GPU_TYPE_DISCRETE; + break; + default: + break; + } + } + if (result.temp) { uint32_t value; From ea3ea196aa6e1e5b9fc17025f49d2e5d73f5a3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 10:56:45 +0800 Subject: [PATCH 17/99] Battery (Linux): simplify temp detection --- src/detection/battery/battery_linux.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index d37f174d5..fb6967dce 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -86,16 +86,10 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option result->temperature = FF_BATTERY_TEMP_UNSET; if (options->temp) { - const FFlist* tempsResult = ffDetectTemps(); - - FF_LIST_FOR_EACH(FFTempValue, value, *tempsResult) - { - if (ffStrbufEqualS(&value->deviceName, id)) - { - result->temperature = value->value; - break; - } - } + ffStrbufAppendS(dir, "/temp"); + if (ffReadFileBuffer(dir->chars, &tmpBuffer)) + options->temp = ffStrbufToDouble(&tmpBuffer) / 10; + ffStrbufSubstrBefore(dir, dirLength); } } From 5eacd0bb8e6f0bd5cbc1c3b58e91b593e73642e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 10:57:12 +0800 Subject: [PATCH 18/99] Battery (Apple): use less hard coded strings --- src/detection/battery/battery_apple.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index 2c9db57e2..63c5654be 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -4,6 +4,7 @@ #include "detection/temps/temps_apple.h" #include +#include const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) { @@ -35,20 +36,20 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) int currentCapacity, maxCapacity; - if ((error = ffCfDictGetInt(properties, CFSTR("MaxCapacity"), &maxCapacity))) + if ((error = ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity))) return error; if (maxCapacity <= 0) return "Querying MaxCapacity failed"; - if ((error = ffCfDictGetInt(properties, CFSTR("CurrentCapacity"), ¤tCapacity))) + if ((error = ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity))) return error; if(currentCapacity <= 0) return "Querying CurrentCapacity failed"; battery->capacity = currentCapacity * 100.0 / maxCapacity; - ffCfDictGetString(properties, CFSTR("DeviceName"), &battery->modelName); - ffCfDictGetString(properties, CFSTR("Serial"), &battery->serial); + ffCfDictGetString(properties, CFSTR(kIOPMDeviceNameKey), &battery->modelName); + ffCfDictGetString(properties, CFSTR(kIOPMPSSerialKey), &battery->serial); if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue) { @@ -59,16 +60,16 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) } int32_t cycleCount = 0; - ffCfDictGetInt(properties, CFSTR("CycleCount"), &cycleCount); + ffCfDictGetInt(properties, CFSTR(kIOPMPSCycleCountKey), &cycleCount); battery->cycleCount = cycleCount < 0 ? 0 : (uint32_t) cycleCount; - if (!ffCfDictGetBool(properties, CFSTR("ExternalConnected"), &boolValue) && boolValue) + if (!ffCfDictGetBool(properties, CFSTR(kIOPMPSExternalConnectedKey), &boolValue) && boolValue) ffStrbufAppendS(&battery->status, "AC connected, "); else ffStrbufAppendS(&battery->status, "Discharging, "); - if (!ffCfDictGetBool(properties, CFSTR("IsCharging"), &boolValue) && boolValue) + if (!ffCfDictGetBool(properties, CFSTR(kIOPMPSIsChargingKey), &boolValue) && boolValue) ffStrbufAppendS(&battery->status, "Charging, "); - if (!ffCfDictGetBool(properties, CFSTR("AtCriticalLevel"), &boolValue) && boolValue) + if (!ffCfDictGetBool(properties, CFSTR(kIOPMPSAtCriticalLevelKey), &boolValue) && boolValue) ffStrbufAppendS(&battery->status, "Critical, "); ffStrbufTrimRight(&battery->status, ' '); ffStrbufTrimRight(&battery->status, ','); @@ -76,7 +77,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) if (options->temp) { int64_t temp; - if (!ffCfDictGetInt64(properties, CFSTR("Temperature"), &temp)) + if (!ffCfDictGetInt64(properties, CFSTR(kIOPMPSBatteryTemperatureKey), &temp)) battery->temperature = (double) temp / 10 - 273.15; else ffDetectSmcTemps(FF_TEMP_BATTERY, &battery->temperature); From 396112e8eaaf3ed9dddb68753023f83803feef49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 11:01:16 +0800 Subject: [PATCH 19/99] PowerAdapter: simplify implementation and support serial number detection --- src/detection/poweradapter/poweradapter.h | 2 +- .../poweradapter/poweradapter_apple.c | 57 ++++++------------- .../poweradapter/poweradapter_linux.c | 6 ++ src/modules/poweradapter/poweradapter.c | 43 +++++++------- 4 files changed, 47 insertions(+), 61 deletions(-) diff --git a/src/detection/poweradapter/poweradapter.h b/src/detection/poweradapter/poweradapter.h index 405480690..8af98a6fa 100644 --- a/src/detection/poweradapter/poweradapter.h +++ b/src/detection/poweradapter/poweradapter.h @@ -8,10 +8,10 @@ typedef struct FFPowerAdapterResult FFstrbuf name; FFstrbuf modelName; FFstrbuf manufacturer; + FFstrbuf serial; int watts; } FFPowerAdapterResult; const char* ffDetectPowerAdapter(FFlist* results); -#define FF_POWERADAPTER_UNSET -2 #define FF_POWERADAPTER_NOT_CONNECTED -1 diff --git a/src/detection/poweradapter/poweradapter_apple.c b/src/detection/poweradapter/poweradapter_apple.c index 7c17a4f0b..794fccd45 100644 --- a/src/detection/poweradapter/poweradapter_apple.c +++ b/src/detection/poweradapter/poweradapter_apple.c @@ -2,51 +2,30 @@ #include "poweradapter.h" #include "util/apple/cf_helpers.h" -#include +#include +#include const char* ffDetectPowerAdapter(FFlist* results) { - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess) - return "IOServiceGetMatchingServices() failed"; + FF_CFTYPE_AUTO_RELEASE CFDictionaryRef details = IOPSCopyExternalPowerAdapterDetails(); + FFPowerAdapterResult* adapter = ffListAdd(results); - io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + ffStrbufInit(&adapter->name); + ffStrbufInit(&adapter->description); + ffStrbufInit(&adapter->manufacturer); + ffStrbufInit(&adapter->modelName); + ffStrbufInit(&adapter->serial); + adapter->watts = FF_POWERADAPTER_NOT_CONNECTED; + + if (details) { - CFMutableDictionaryRef properties; - if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) - { - IOObjectRelease(registryEntry); - continue; - } - - FFPowerAdapterResult* adapter = ffListAdd(results); - - ffStrbufInit(&adapter->name); - ffStrbufInit(&adapter->description); - ffStrbufInit(&adapter->manufacturer); - ffStrbufInit(&adapter->modelName); - adapter->watts = FF_POWERADAPTER_UNSET; - - CFDictionaryRef adapterDict; - if(!ffCfDictGetDict(properties, CFSTR("AdapterDetails"), &adapterDict)) - { - if (ffCfDictGetInt(adapterDict, CFSTR("Watts"), &adapter->watts)) - { - adapter->watts = FF_POWERADAPTER_NOT_CONNECTED; - continue; - } - ffCfDictGetString(adapterDict, CFSTR("Name"), &adapter->name); - ffCfDictGetString(adapterDict, CFSTR("Description"), &adapter->description); - ffCfDictGetString(adapterDict, CFSTR("Manufacturer"), &adapter->manufacturer); - ffCfDictGetString(adapterDict, CFSTR("Model"), &adapter->modelName); - } - - CFRelease(properties); - IOObjectRelease(registryEntry); + ffCfDictGetString(details, CFSTR(kIOPSNameKey), &adapter->name); + ffCfDictGetString(details, CFSTR("Model"), &adapter->modelName); + ffCfDictGetString(details, CFSTR("Manufacturer"), &adapter->manufacturer); + ffCfDictGetString(details, CFSTR("Description"), &adapter->description); + ffCfDictGetString(details, CFSTR("SerialString"), &adapter->serial); + ffCfDictGetInt(details, CFSTR(kIOPSPowerAdapterWattsKey), &adapter->watts); } - IOObjectRelease(iterator); - return NULL; } diff --git a/src/detection/poweradapter/poweradapter_linux.c b/src/detection/poweradapter/poweradapter_linux.c index b514c2590..8058ad7c6 100644 --- a/src/detection/poweradapter/poweradapter_linux.c +++ b/src/detection/poweradapter/poweradapter_linux.c @@ -65,6 +65,12 @@ static void parsePowerAdapter(FFstrbuf* dir, FF_MAYBE_UNUSED const char* id, FFl if (ffReadFileBuffer(dir->chars, &result->modelName)) ffStrbufTrimRightSpace(&result->modelName); ffStrbufSubstrBefore(dir, dirLength); + + ffStrbufInit(&result->serial); + ffStrbufAppendS(dir, "/serial_number"); + if (ffReadFileBuffer(dir->chars, &result->serial)) + ffStrbufTrimRightSpace(&result->serial); + ffStrbufSubstrBefore(dir, dirLength); } const char* ffDetectPowerAdapter(FFlist* results) diff --git a/src/modules/poweradapter/poweradapter.c b/src/modules/poweradapter/poweradapter.c index a4f599d4b..23cd10732 100644 --- a/src/modules/poweradapter/poweradapter.c +++ b/src/modules/poweradapter/poweradapter.c @@ -5,7 +5,7 @@ #include "util/stringUtils.h" #define FF_POWERADAPTER_DISPLAY_NAME "Power Adapter" -#define FF_POWERADAPTER_NUM_FORMAT_ARGS 5 +#define FF_POWERADAPTER_NUM_FORMAT_ARGS 6 void ffPrintPowerAdapter(FFPowerAdapterOptions* options) { @@ -27,35 +27,34 @@ void ffPrintPowerAdapter(FFPowerAdapterOptions* options) { FFPowerAdapterResult* result = ffListGet(&results, i); - if(result->watts != FF_POWERADAPTER_UNSET) + if(options->moduleArgs.outputFormat.length == 0) { - if(options->moduleArgs.outputFormat.length == 0) - { - ffPrintLogoAndKey(FF_POWERADAPTER_DISPLAY_NAME, i, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + ffPrintLogoAndKey(FF_POWERADAPTER_DISPLAY_NAME, i, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - if(result->name.length > 0) - puts(result->name.chars); - else if(result->watts == FF_POWERADAPTER_NOT_CONNECTED) - puts("not connected"); - else - printf("%dW\n", result->watts); - } + if(result->name.length > 0) + puts(result->name.chars); + else if(result->watts == FF_POWERADAPTER_NOT_CONNECTED) + puts("not connected"); else - { - ffPrintFormat(FF_POWERADAPTER_DISPLAY_NAME, i, &options->moduleArgs, FF_POWERADAPTER_NUM_FORMAT_ARGS, (FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_INT, &result->watts}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->name}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->description}, - }); - } + printf("%dW\n", result->watts); + } + else + { + ffPrintFormat(FF_POWERADAPTER_DISPLAY_NAME, i, &options->moduleArgs, FF_POWERADAPTER_NUM_FORMAT_ARGS, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_INT, &result->watts}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->name}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->description}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->serial}, + }); } ffStrbufDestroy(&result->manufacturer); ffStrbufDestroy(&result->description); ffStrbufDestroy(&result->modelName); ffStrbufDestroy(&result->name); + ffStrbufDestroy(&result->serial); } } } @@ -119,6 +118,7 @@ void ffGeneratePowerAdapterJsonResult(FF_MAYBE_UNUSED FFPowerAdapterOptions* opt yyjson_mut_obj_add_strbuf(doc, obj, "manufacturer", &item->manufacturer); yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &item->modelName); yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &item->serial); yyjson_mut_obj_add_int(doc, obj, "watts", item->watts); } } @@ -132,6 +132,7 @@ void ffPrintPowerAdapterHelpFormat(void) "PowerAdapter manufacturer", "PowerAdapter model", "PowerAdapter description" + "PowerAdapter serial number" }); } From 92a6b0113363fc8fc936bdf9f23c171b9bdae862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 13:20:47 +0800 Subject: [PATCH 20/99] Brightness (Apple): code optimise and fix mem leaks --- src/detection/brightness/brightness_apple.c | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/detection/brightness/brightness_apple.c b/src/detection/brightness/brightness_apple.c index 4c58b5e6a..52b0cee32 100644 --- a/src/detection/brightness/brightness_apple.c +++ b/src/detection/brightness/brightness_apple.c @@ -61,24 +61,27 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult* if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess) return "IOServiceGetMatchingServices() failed"; - FF_STRBUF_AUTO_DESTROY location = ffStrbufCreate(); - io_registry_entry_t registryEntry; while((registryEntry = IOIteratorNext(iterator)) != 0) { - CFMutableDictionaryRef properties; - if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) { - IOObjectRelease(registryEntry); - continue; + FF_CFTYPE_AUTO_RELEASE CFBooleanRef IOAVServiceUserInterfaceSupported = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("IOAVServiceUserInterfaceSupported"), kCFAllocatorDefault, kNilOptions); + if (IOAVServiceUserInterfaceSupported && !CFBooleanGetValue(IOAVServiceUserInterfaceSupported)) + { + // IOAVServiceCreateWithService won't work + IOObjectRelease(registryEntry); + continue; + } } - ffStrbufClear(&location); - if(ffCfDictGetString(properties, CFSTR("Location"), &location) || ffStrbufEqualS(&location, "Embedded")) { - // Builtin display should be handled by DisplayServices - IOObjectRelease(registryEntry); - continue; + FF_CFTYPE_AUTO_RELEASE CFStringRef location = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("Location"), kCFAllocatorDefault, kNilOptions); + if (location && CFStringCompare(location, CFSTR("Embedded"), 0) == 0) + { + // Builtin display should be handled by DisplayServices + IOObjectRelease(registryEntry); + continue; + } } FF_CFTYPE_AUTO_RELEASE IOAVServiceRef service = IOAVServiceCreateWithService(kCFAllocatorDefault, (io_service_t) registryEntry); From b6c8649cbf562985478177de6cae56d80701e203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 14:47:30 +0800 Subject: [PATCH 21/99] macOS: improve IO service related code generally --- src/detection/battery/battery_apple.c | 29 +++------- src/detection/brightness/brightness_apple.c | 25 ++++---- src/detection/cpu/cpu_apple.c | 56 ++++++++---------- src/detection/diskio/diskio_apple.c | 12 +--- src/detection/gpu/gpu_apple.c | 8 +-- src/detection/host/host_apple.c | 25 +++----- .../physicaldisk/physicaldisk_apple.c | 12 +--- src/detection/temps/temps_apple.c | 28 ++++----- src/util/apple/cf_helpers.c | 57 ++++++++++--------- src/util/apple/cf_helpers.h | 11 +++- 10 files changed, 108 insertions(+), 155 deletions(-) diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index 63c5654be..c0d0ec8a6 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -8,22 +8,19 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) { - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess) + FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL; + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryBattery = registryEntry; FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL; - if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) - { - IOObjectRelease(registryEntry); + if (IORegistryEntryCreateCFProperties(entryBattery, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) continue; - } bool boolValue; - const char* error; FFBatteryResult* battery = ffListAdd(results); battery->temperature = FF_BATTERY_TEMP_UNSET; @@ -36,15 +33,11 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) int currentCapacity, maxCapacity; - if ((error = ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity))) - return error; - if (maxCapacity <= 0) - return "Querying MaxCapacity failed"; + if (ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity) != NULL || maxCapacity <= 0) + continue; - if ((error = ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity))) - return error; - if(currentCapacity <= 0) - return "Querying CurrentCapacity failed"; + if (ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity) != NULL || currentCapacity <= 0) + continue; battery->capacity = currentCapacity * 100.0 / maxCapacity; @@ -82,11 +75,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) else ffDetectSmcTemps(FF_TEMP_BATTERY, &battery->temperature); } - - IOObjectRelease(registryEntry); } - IOObjectRelease(iterator); - return NULL; } diff --git a/src/detection/brightness/brightness_apple.c b/src/detection/brightness/brightness_apple.c index 52b0cee32..a9f8daf0c 100644 --- a/src/detection/brightness/brightness_apple.c +++ b/src/detection/brightness/brightness_apple.c @@ -57,38 +57,35 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult* if (!IOAVServiceCreate || !IOAVServiceReadI2C) return "IOAVService is not available"; - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess) + FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL; + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { + FF_CFTYPE_AUTO_RELEASE IOAVServiceRef service = NULL; { - FF_CFTYPE_AUTO_RELEASE CFBooleanRef IOAVServiceUserInterfaceSupported = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("IOAVServiceUserInterfaceSupported"), kCFAllocatorDefault, kNilOptions); + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryAv = registryEntry; + + FF_CFTYPE_AUTO_RELEASE CFBooleanRef IOAVServiceUserInterfaceSupported = IORegistryEntryCreateCFProperty(entryAv, CFSTR("IOAVServiceUserInterfaceSupported"), kCFAllocatorDefault, kNilOptions); if (IOAVServiceUserInterfaceSupported && !CFBooleanGetValue(IOAVServiceUserInterfaceSupported)) { // IOAVServiceCreateWithService won't work - IOObjectRelease(registryEntry); continue; } - } - { - FF_CFTYPE_AUTO_RELEASE CFStringRef location = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("Location"), kCFAllocatorDefault, kNilOptions); + FF_CFTYPE_AUTO_RELEASE CFStringRef location = IORegistryEntryCreateCFProperty(entryAv, CFSTR("Location"), kCFAllocatorDefault, kNilOptions); if (location && CFStringCompare(location, CFSTR("Embedded"), 0) == 0) { // Builtin display should be handled by DisplayServices - IOObjectRelease(registryEntry); continue; } + + service = IOAVServiceCreateWithService(kCFAllocatorDefault, (io_service_t) registryEntry); + if (!service) continue; } - FF_CFTYPE_AUTO_RELEASE IOAVServiceRef service = IOAVServiceCreateWithService(kCFAllocatorDefault, (io_service_t) registryEntry); - IOObjectRelease(registryEntry); - - if (!service) continue; - { uint8_t i2cIn[4] = { 0x82, 0x01, 0x10 /* luminance */ }; i2cIn[3] = 0x6e ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2]; diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c index a0afaa697..2f3ec2de7 100644 --- a/src/detection/cpu/cpu_apple.c +++ b/src/detection/cpu/cpu_apple.c @@ -1,6 +1,7 @@ #include "cpu.h" #include "common/sysctl.h" #include "detection/temps/temps_apple.h" +#include "util/stringUtils.h" static double detectCpuTemp(const FFstrbuf* cpuName) { @@ -35,44 +36,33 @@ static const char* detectFrequency(FFCPUResult* cpu) { // https://github.com/giampaolo/psutil/pull/2222/files - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleARMIODevice"), &iterator) != kIOReturnSuccess) + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("pmgr")); + if (!entryDevice) return "IOServiceGetMatchingServices() failed"; - io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice")) + return "\"pmgr\" should conform to \"AppleARMIODevice\""; + + FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL; + if (IORegistryEntryCreateCFProperties(entryDevice, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) + return "IORegistryEntryCreateCFProperties() failed"; + + uint32_t pMin, eMin, aMax, pCoreLength; + if (ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), 0, 4, (uint8_t*) &pMin, &pCoreLength) != NULL) // pCore + return "\"voltage-states5-sram\" in \"pmgr\" is not found"; + if (ffCfDictGetData(properties, CFSTR("voltage-states1-sram"), 0, 4, (uint8_t*) &eMin, NULL) != NULL) // eCore + return "\"voltage-states1-sram\" in \"pmgr\" is not found"; + + cpu->frequencyMin = (pMin < eMin ? pMin : eMin) / (1000.0 * 1000 * 1000); + + if (pCoreLength >= 8) { - CFMutableDictionaryRef properties; - if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) - { - IOObjectRelease(registryEntry); - continue; - } - - io_name_t name; - if (IORegistryEntryGetName(registryEntry, name) != KERN_SUCCESS) - continue; - if (strcmp(name, "pmgr") != 0) - continue; - - uint32_t pMin, eMin, aMax, pCoreLength; - ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), 0, 4, (uint8_t*) &pMin, &pCoreLength); // pCore - ffCfDictGetData(properties, CFSTR("voltage-states1-sram"), 0, 4, (uint8_t*) &eMin, NULL); // eCore - cpu->frequencyMin = (pMin < eMin ? pMin : eMin) / (1000.0 * 1000 * 1000); - - if (pCoreLength >= 8) - { - ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), pCoreLength - 8, 4, (uint8_t*) &aMax, NULL); - cpu->frequencyMax = aMax / (1000.0 * 1000 * 1000); - } - else - cpu->frequencyMax = 0.0; - - CFRelease(properties); - IOObjectRelease(registryEntry); + ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), pCoreLength - 8, 4, (uint8_t*) &aMax, NULL); + cpu->frequencyMax = aMax / (1000.0 * 1000 * 1000); } + else + cpu->frequencyMax = 0.0; - IOObjectRelease(iterator); return NULL; } #else diff --git a/src/detection/diskio/diskio_apple.c b/src/detection/diskio/diskio_apple.c index bc5d57f25..2e202f3d9 100644 --- a/src/detection/diskio/diskio_apple.c +++ b/src/detection/diskio/diskio_apple.c @@ -8,22 +8,14 @@ #include #include -static inline void wrapIoObjectRelease(io_service_t* service) -{ - assert(service); - if (*service) - IOObjectRelease(*service); -} -#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease))) - const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) { FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryPartition = registryEntry; diff --git a/src/detection/gpu/gpu_apple.c b/src/detection/gpu/gpu_apple.c index b7db8c562..6113dfce6 100644 --- a/src/detection/gpu/gpu_apple.c +++ b/src/detection/gpu/gpu_apple.c @@ -38,12 +38,12 @@ static double detectGpuTemp(const FFstrbuf* gpuName) const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) { - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOAcceleratorClassName), &iterator) != kIOReturnSuccess) + FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL; + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOAcceleratorClassName), &iterator) != kIOReturnSuccess) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { CFMutableDictionaryRef properties; if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) @@ -106,8 +106,6 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) IOObjectRelease(registryEntry); } - IOObjectRelease(iterator); - ffGpuDetectMetal(gpus); return NULL; } diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 6f5184e50..07f1cd102 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -169,26 +169,15 @@ static const char* getProductNameWithHwModel(const FFstrbuf* hwModel) const char* getProductNameWithIokit(FFstrbuf* result) { - io_iterator_t iterator; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceNameMatching("product"), &iterator) != kIOReturnSuccess) - return "IOServiceGetMatchingServices() failed"; + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("product")); + if (!registryEntry) + return "IOServiceGetMatchingService() failed"; - io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) - { - FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL; - if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) - { - IOObjectRelease(registryEntry); - continue; - } + FF_CFTYPE_AUTO_RELEASE CFStringRef productName = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("product-name"), kCFAllocatorDefault, kNilOptions); + if (!productName) + return "IORegistryEntryCreateCFProperty() failed"; - if (ffCfDictGetString(properties, CFSTR("product-name"), result)) - break; - } - - IOObjectRelease(registryEntry); - return NULL; + return ffCfStrGetString(productName, result); } const char* ffDetectHost(FFHostResult* host) diff --git a/src/detection/physicaldisk/physicaldisk_apple.c b/src/detection/physicaldisk/physicaldisk_apple.c index 4fbc84951..8f4a11420 100644 --- a/src/detection/physicaldisk/physicaldisk_apple.c +++ b/src/detection/physicaldisk/physicaldisk_apple.c @@ -9,14 +9,6 @@ #include #include -static inline void wrapIoObjectRelease(io_service_t* service) -{ - assert(service); - if (*service) - IOObjectRelease(*service); -} -#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease))) - static inline void wrapIoDestroyPlugInInterface(IOCFPlugInInterface*** pluginInf) { assert(pluginInf); @@ -49,11 +41,11 @@ static const char* detectSsdTemp(io_service_t entryPhysical, double* temp) const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) { FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0; - if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) + if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) return "IOServiceGetMatchingServices() failed"; io_registry_entry_t registryEntry; - while((registryEntry = IOIteratorNext(iterator)) != 0) + while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryPartition = registryEntry; diff --git a/src/detection/temps/temps_apple.c b/src/detection/temps/temps_apple.c index 2fbc2ae09..c4cef7827 100644 --- a/src/detection/temps/temps_apple.c +++ b/src/detection/temps/temps_apple.c @@ -85,12 +85,9 @@ static void smcUltostr(char *str, uint32_t val) static const char *smcCall(io_connect_t conn, uint32_t selector, SmcKeyData_t *inputStructure, SmcKeyData_t *outputStructure) { - size_t structureInputSize; - size_t structureOutputSize; - structureInputSize = sizeof(SmcKeyData_t); - structureOutputSize = sizeof(SmcKeyData_t); + size_t size = sizeof(SmcKeyData_t); - if (IOConnectCallStructMethod(conn, selector, inputStructure, structureInputSize, outputStructure, &structureOutputSize) != kIOReturnSuccess) + if (IOConnectCallStructMethod(conn, selector, inputStructure, size, outputStructure, &size) != kIOReturnSuccess) return "IOConnectCallStructMethod(conn) failed"; return NULL; } @@ -140,17 +137,13 @@ static const char *smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcV static const char *smcOpen(io_connect_t *conn) { - io_iterator_t iterator; - if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSMC"), &iterator) != kIOReturnSuccess) - return "IOServiceGetMatchingServices() failed"; - - io_object_t device = IOIteratorNext(iterator); - IOObjectRelease(iterator); - if (device == 0) + io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC")); + if (!device) return "No SMC device found"; kern_return_t result = IOServiceOpen(device, mach_task_self(), 0, conn); IOObjectRelease(device); + if (result != kIOReturnSuccess) return "IOServiceOpen() failed"; @@ -290,10 +283,13 @@ static bool detectTemp(io_connect_t conn, const char *sensor, double* sum) const char *ffDetectSmcTemps(enum FFTempType type, double *result) { static io_connect_t conn; - static dispatch_once_t once_control; - dispatch_once_f(&once_control, &conn, (dispatch_function_t) smcOpen); - if(!conn) - return "smcOpen() failed"; + if (!conn) + { + if (smcOpen(&conn) != NULL) + conn = (io_connect_t) -1; + } + else if (conn == (io_connect_t) -1) + return "Could not open SMC connection"; uint32_t count = 0; *result = 0; diff --git a/src/util/apple/cf_helpers.c b/src/util/apple/cf_helpers.c index 962334ed5..7b501af71 100644 --- a/src/util/apple/cf_helpers.c +++ b/src/util/apple/cf_helpers.c @@ -19,26 +19,42 @@ const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result) return "TypeID is neither 'CFNumber' nor 'CFData'"; } -const char* ffCfStrGetString(CFStringRef str, FFstrbuf* result) +const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) { - if (!str) + if (!cf) { ffStrbufClear(result); return NULL; } - uint32_t length = (uint32_t)CFStringGetLength(str); - //CFString stores UTF16 characters, therefore may require larger buffer to convert to UTF8 string - ffStrbufEnsureFree(result, length * 2); - if(!CFStringGetCString(str, result->chars, result->allocated, kCFStringEncodingUTF8)) + if (CFGetTypeID(cf) == CFStringGetTypeID()) { - ffStrbufEnsureFree(result, length * 4); - if(!CFStringGetCString(str, result->chars, result->allocated, kCFStringEncodingUTF8)) - return "CFStringGetCString() failed"; + CFStringRef cfStr = (CFStringRef)cf; + uint32_t length = (uint32_t)CFStringGetLength(cfStr); + //CFString stores UTF16 characters, therefore may require larger buffer to convert to UTF8 string + ffStrbufEnsureFree(result, length * 2); + if (!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) + { + ffStrbufEnsureFree(result, length * 4); + if(!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) + return "CFStringGetCString() failed"; + } + // CFStringGetCString ensures the buffer is NUL terminated + // https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring + result->length = (uint32_t) strnlen(result->chars, (uint32_t)result->allocated); } - // CFStringGetCString ensures the buffer is NUL terminated - // https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring - result->length = (uint32_t) strnlen(result->chars, (uint32_t)result->allocated); + else if (CFGetTypeID(cf) == CFDataGetTypeID()) + { + CFDataRef cfData = (CFDataRef)cf; + uint32_t length = (uint32_t)CFDataGetLength(cfData); + ffStrbufEnsureFree(result, length + 1); + CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars); + result->length = (uint32_t)strnlen(result->chars, length); + result->chars[result->length] = '\0'; + } + else + return "TypeID is neither 'CFString' nor 'CFData'"; + return NULL; } @@ -48,22 +64,7 @@ const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* r if(cf == NULL) return "CFDictionaryGetValue() failed"; - if(CFGetTypeID(cf) == CFStringGetTypeID()) - { - return ffCfStrGetString((CFStringRef)cf, result); - } - else if(CFGetTypeID(cf) == CFDataGetTypeID()) - { - CFDataRef cfData = (CFDataRef)cf; - uint32_t length = (uint32_t)CFDataGetLength(cfData); - ffStrbufEnsureFree(result, length + 1); - CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars); - result->length = (uint32_t)strnlen(result->chars, length); - result->chars[result->length] = '\0'; - return NULL; - } - - return "TypeID is neither 'CFString' nor 'CFData'"; + return ffCfStrGetString(cf, result); } const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) diff --git a/src/util/apple/cf_helpers.h b/src/util/apple/cf_helpers.h index eba56c127..a0e494710 100644 --- a/src/util/apple/cf_helpers.h +++ b/src/util/apple/cf_helpers.h @@ -5,9 +5,10 @@ #include "fastfetch.h" #include +#include //Return error info if failed, NULL otherwise -const char* ffCfStrGetString(CFStringRef str, FFstrbuf* result); +const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result); const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result); const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result); const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result); @@ -29,4 +30,12 @@ static inline void cfReleaseWrapper(void* type) #define FF_CFTYPE_AUTO_RELEASE __attribute__((__cleanup__(cfReleaseWrapper))) +static inline void wrapIoObjectRelease(io_service_t* service) +{ + assert(service); + if (*service) + IOObjectRelease(*service); +} +#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease))) + #endif From 2340c2afd726877f93d44f89d431940c90a9ef67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 16:15:53 +0800 Subject: [PATCH 22/99] Board (macOS): print internal name instead of model indentifier and actually detect the vendor --- src/detection/board/board_apple.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/detection/board/board_apple.c b/src/detection/board/board_apple.c index 56f582215..6381590d8 100644 --- a/src/detection/board/board_apple.c +++ b/src/detection/board/board_apple.c @@ -1,13 +1,21 @@ #include "board.h" #include "common/sysctl.h" +#include "util/apple/cf_helpers.h" const char* ffDetectBoard(FFBoardResult* result) { - const char* error = ffSysctlGetString("hw.model", &result->name); - if (error) - return error; + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t service = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("IOPlatformExpertDevice")); + if (!service) + return "No IOPlatformExpertDevice found"; + + io_name_t name; + if (IORegistryEntryGetName(service, name) == kIOReturnSuccess) + ffStrbufSetS(&result->name, name); + + FF_CFTYPE_AUTO_RELEASE CFTypeRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions); + if (manufacturer) + ffCfStrGetString(manufacturer, &result->vendor); - ffStrbufSetStatic(&result->vendor, "Apple"); return NULL; } From 810112cb265f50d278d05b5615972ad128c78687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 16:29:38 +0800 Subject: [PATCH 23/99] Host (macOS): detect serial number and uuid --- src/detection/host/host.h | 2 ++ src/detection/host/host_apple.c | 25 ++++++++++++++++++++++--- src/modules/host/host.c | 18 ++++++++++++++++-- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/detection/host/host.h b/src/detection/host/host.h index 1957e9c6b..23462f824 100644 --- a/src/detection/host/host.h +++ b/src/detection/host/host.h @@ -8,6 +8,8 @@ typedef struct FFHostResult FFstrbuf productName; FFstrbuf productVersion; FFstrbuf productSku; + FFstrbuf productSerial; + FFstrbuf productUuid; FFstrbuf sysVendor; } FFHostResult; diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 07f1cd102..74d4cbe74 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -180,10 +180,29 @@ const char* getProductNameWithIokit(FFstrbuf* result) return ffCfStrGetString(productName, result); } +const char* getOthersByIokit(FFHostResult* host) +{ + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("IOPlatformExpertDevice")); + if (!registryEntry) + return "IOServiceGetMatchingService() failed"; + + FF_CFTYPE_AUTO_RELEASE CFStringRef serialNumber = IORegistryEntryCreateCFProperty(registryEntry, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, kNilOptions); + if (serialNumber) + ffCfStrGetString(serialNumber, &host->productSerial); + + FF_CFTYPE_AUTO_RELEASE CFStringRef uuid = IORegistryEntryCreateCFProperty(registryEntry, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, kNilOptions); + if (uuid) + ffCfStrGetString(uuid, &host->productUuid); + + FF_CFTYPE_AUTO_RELEASE CFStringRef manufacturer = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions); + if (manufacturer) + ffCfStrGetString(manufacturer, &host->sysVendor); + + return NULL; +} + const char* ffDetectHost(FFHostResult* host) { - ffStrbufSetStatic(&host->sysVendor, "Apple"); - const char* error = ffSysctlGetString("hw.model", &host->productFamily); if (error) return error; @@ -192,6 +211,6 @@ const char* ffDetectHost(FFHostResult* host) getProductNameWithIokit(&host->productName); if (host->productName.length == 0) ffStrbufSet(&host->productName, &host->productFamily); - + getOthersByIokit(host); return NULL; } diff --git a/src/modules/host/host.c b/src/modules/host/host.c index aeafd7118..b6e5151ad 100644 --- a/src/modules/host/host.c +++ b/src/modules/host/host.c @@ -4,7 +4,7 @@ #include "modules/host/host.h" #include "util/stringUtils.h" -#define FF_HOST_NUM_FORMAT_ARGS 5 +#define FF_HOST_NUM_FORMAT_ARGS 7 void ffPrintHost(FFHostOptions* options) { @@ -13,6 +13,8 @@ void ffPrintHost(FFHostOptions* options) ffStrbufInit(&host.productName); ffStrbufInit(&host.productVersion); ffStrbufInit(&host.productSku); + ffStrbufInit(&host.productSerial); + ffStrbufInit(&host.productUuid); ffStrbufInit(&host.sysVendor); const char* error = ffDetectHost(&host); @@ -51,7 +53,9 @@ void ffPrintHost(FFHostOptions* options) {FF_FORMAT_ARG_TYPE_STRBUF, &host.productName}, {FF_FORMAT_ARG_TYPE_STRBUF, &host.productVersion}, {FF_FORMAT_ARG_TYPE_STRBUF, &host.productSku}, - {FF_FORMAT_ARG_TYPE_STRBUF, &host.sysVendor} + {FF_FORMAT_ARG_TYPE_STRBUF, &host.sysVendor}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.productSerial}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.productUuid}, }); } @@ -60,6 +64,8 @@ exit: ffStrbufDestroy(&host.productName); ffStrbufDestroy(&host.productVersion); ffStrbufDestroy(&host.productSku); + ffStrbufDestroy(&host.productSerial); + ffStrbufDestroy(&host.productUuid); ffStrbufDestroy(&host.sysVendor); } @@ -105,6 +111,8 @@ void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut ffStrbufInit(&host.productName); ffStrbufInit(&host.productVersion); ffStrbufInit(&host.productSku); + ffStrbufInit(&host.productSerial); + ffStrbufInit(&host.productUuid); ffStrbufInit(&host.sysVendor); const char* error = ffDetectHost(&host); @@ -125,6 +133,8 @@ void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut yyjson_mut_obj_add_strbuf(doc, obj, "name", &host.productName); yyjson_mut_obj_add_strbuf(doc, obj, "version", &host.productVersion); yyjson_mut_obj_add_strbuf(doc, obj, "sku", &host.productSku); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &host.productSerial); + yyjson_mut_obj_add_strbuf(doc, obj, "uuid", &host.productUuid); yyjson_mut_obj_add_strbuf(doc, obj, "sysVender", &host.sysVendor); exit: @@ -132,6 +142,8 @@ exit: ffStrbufDestroy(&host.productName); ffStrbufDestroy(&host.productVersion); ffStrbufDestroy(&host.productSku); + ffStrbufDestroy(&host.productSerial); + ffStrbufDestroy(&host.productUuid); ffStrbufDestroy(&host.sysVendor); } @@ -142,6 +154,8 @@ void ffPrintHostHelpFormat(void) "product name", "product version", "product sku", + "product serial number", + "product uuid", "sys vendor" }); } From f8ac56691f0fbe5f4bcd30e070e18483a2fdb7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 16:32:34 +0800 Subject: [PATCH 24/99] Host (FreeBSD): detect serial number and uuid --- src/detection/host/host_bsd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/detection/host/host_bsd.c b/src/detection/host/host_bsd.c index 9a7dcbd71..46dd0b9af 100644 --- a/src/detection/host/host_bsd.c +++ b/src/detection/host/host_bsd.c @@ -12,6 +12,10 @@ const char* ffDetectHost(FFHostResult* host) ffCleanUpSmbiosValue(&host->productVersion); ffSettingsGetFreeBSDKenv("smbios.system.sku", &host->productSku); ffCleanUpSmbiosValue(&host->productSku); + ffSettingsGetFreeBSDKenv("smbios.system.serial", &host->productSerial); + ffCleanUpSmbiosValue(&host->productSerial); + ffSettingsGetFreeBSDKenv("smbios.system.uuid", &host->productUuid); + ffCleanUpSmbiosValue(&host->productUuid); ffSettingsGetFreeBSDKenv("smbios.system.maker", &host->sysVendor); ffCleanUpSmbiosValue(&host->sysVendor); From 24cec76251484590f3ac453df4f97ab69ecc5694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 16:33:52 +0800 Subject: [PATCH 25/99] Host (Linux): detect serial number and uuid --- src/detection/host/host_linux.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detection/host/host_linux.c b/src/detection/host/host_linux.c index 8b11628d6..28697ad81 100644 --- a/src/detection/host/host_linux.c +++ b/src/detection/host/host_linux.c @@ -33,6 +33,8 @@ const char* ffDetectHost(FFHostResult* host) getHostProductName(&host->productName); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->productVersion); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->productSku); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->productSerial); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_uuid", "/sys/class/dmi/id/product_uuid", &host->productUuid); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->sysVendor); //KVM/Qemu virtual machine From 6bcd75835ee2205628bd50a004d5afa63560a9e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 20:38:29 +0800 Subject: [PATCH 26/99] Host: rename properties --- src/detection/host/host.h | 14 ++--- src/detection/host/host_android.c | 34 +++++------ src/detection/host/host_apple.c | 20 +++---- src/detection/host/host_bsd.c | 28 ++++----- src/detection/host/host_linux.c | 28 ++++----- src/detection/host/host_windows.c | 20 +++---- src/modules/host/host.c | 98 +++++++++++++++---------------- 7 files changed, 121 insertions(+), 121 deletions(-) diff --git a/src/detection/host/host.h b/src/detection/host/host.h index 23462f824..1b0c61187 100644 --- a/src/detection/host/host.h +++ b/src/detection/host/host.h @@ -4,13 +4,13 @@ typedef struct FFHostResult { - FFstrbuf productFamily; - FFstrbuf productName; - FFstrbuf productVersion; - FFstrbuf productSku; - FFstrbuf productSerial; - FFstrbuf productUuid; - FFstrbuf sysVendor; + FFstrbuf family; + FFstrbuf name; + FFstrbuf version; + FFstrbuf sku; + FFstrbuf serial; + FFstrbuf uuid; + FFstrbuf vendor; } FFHostResult; const char* ffDetectHost(FFHostResult* host); diff --git a/src/detection/host/host_android.c b/src/detection/host/host_android.c index 4b7c095a9..b496029a8 100644 --- a/src/detection/host/host_android.c +++ b/src/detection/host/host_android.c @@ -5,32 +5,32 @@ const char* ffDetectHost(FFHostResult* host) { // http://newandroidbook.com/ddb/ - ffSettingsGetAndroidProperty("ro.product.device", &host->productFamily); + ffSettingsGetAndroidProperty("ro.product.device", &host->family); - ffSettingsGetAndroidProperty("ro.product.marketname", &host->productName) - || ffSettingsGetAndroidProperty("ro.vendor.product.display", &host->productName) - || ffSettingsGetAndroidProperty("ro.config.devicename", &host->productName) - || ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->productName) - || ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->productName) - || ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->productName) - || ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->productName) - || ffSettingsGetAndroidProperty("ro.product.brand", &host->productName); + ffSettingsGetAndroidProperty("ro.product.marketname", &host->name) + || ffSettingsGetAndroidProperty("ro.vendor.product.display", &host->name) + || ffSettingsGetAndroidProperty("ro.config.devicename", &host->name) + || ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->name) + || ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->name) + || ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->name) + || ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->name) + || ffSettingsGetAndroidProperty("ro.product.brand", &host->name); - if (ffSettingsGetAndroidProperty("ro.product.model", &host->productVersion)) + if (ffSettingsGetAndroidProperty("ro.product.model", &host->version)) { - if (ffStrbufStartsWithIgnCase(&host->productVersion, &host->productName)) + if (ffStrbufStartsWithIgnCase(&host->version, &host->name)) { - ffStrbufSubstrAfter(&host->productVersion, host->productName.length); - ffStrbufTrimLeft(&host->productVersion, ' '); + ffStrbufSubstrAfter(&host->version, host->name.length); + ffStrbufTrimLeft(&host->version, ' '); } } - ffSettingsGetAndroidProperty("ro.product.manufacturer", &host->sysVendor); + ffSettingsGetAndroidProperty("ro.product.manufacturer", &host->vendor); - if(host->sysVendor.length && !ffStrbufStartsWithIgnCase(&host->productName, &host->sysVendor)) + if(host->vendor.length && !ffStrbufStartsWithIgnCase(&host->name, &host->vendor)) { - ffStrbufPrependS(&host->productName, " "); - ffStrbufPrepend(&host->productName, &host->sysVendor); + ffStrbufPrependS(&host->name, " "); + ffStrbufPrepend(&host->name, &host->vendor); } return NULL; diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 74d4cbe74..98910e5e8 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -177,7 +177,7 @@ const char* getProductNameWithIokit(FFstrbuf* result) if (!productName) return "IORegistryEntryCreateCFProperty() failed"; - return ffCfStrGetString(productName, result); + return ffCfStrGetString(name, result); } const char* getOthersByIokit(FFHostResult* host) @@ -188,29 +188,29 @@ const char* getOthersByIokit(FFHostResult* host) FF_CFTYPE_AUTO_RELEASE CFStringRef serialNumber = IORegistryEntryCreateCFProperty(registryEntry, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, kNilOptions); if (serialNumber) - ffCfStrGetString(serialNumber, &host->productSerial); + ffCfStrGetString(serialNumber, &host->serial); FF_CFTYPE_AUTO_RELEASE CFStringRef uuid = IORegistryEntryCreateCFProperty(registryEntry, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, kNilOptions); if (uuid) - ffCfStrGetString(uuid, &host->productUuid); + ffCfStrGetString(uuid, &host->uuid); FF_CFTYPE_AUTO_RELEASE CFStringRef manufacturer = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions); if (manufacturer) - ffCfStrGetString(manufacturer, &host->sysVendor); + ffCfStrGetString(manufacturer, &host->vendor); return NULL; } const char* ffDetectHost(FFHostResult* host) { - const char* error = ffSysctlGetString("hw.model", &host->productFamily); + const char* error = ffSysctlGetString("hw.model", &host->family); if (error) return error; - ffStrbufSetStatic(&host->productName, getProductNameWithHwModel(&host->productFamily)); - if (host->productName.length == 0) - getProductNameWithIokit(&host->productName); - if (host->productName.length == 0) - ffStrbufSet(&host->productName, &host->productFamily); + ffStrbufSetStatic(&host->name, getProductNameWithHwModel(&host->family)); + if (host->name.length == 0) + getProductNameWithIokit(&host->name); + if (host->name.length == 0) + ffStrbufSet(&host->name, &host->family); getOthersByIokit(host); return NULL; } diff --git a/src/detection/host/host_bsd.c b/src/detection/host/host_bsd.c index 46dd0b9af..334b04cab 100644 --- a/src/detection/host/host_bsd.c +++ b/src/detection/host/host_bsd.c @@ -4,20 +4,20 @@ const char* ffDetectHost(FFHostResult* host) { - ffSettingsGetFreeBSDKenv("smbios.system.product", &host->productName); - ffCleanUpSmbiosValue(&host->productName); - ffSettingsGetFreeBSDKenv("smbios.system.family", &host->productFamily); - ffCleanUpSmbiosValue(&host->productFamily); - ffSettingsGetFreeBSDKenv("smbios.system.version", &host->productVersion); - ffCleanUpSmbiosValue(&host->productVersion); - ffSettingsGetFreeBSDKenv("smbios.system.sku", &host->productSku); - ffCleanUpSmbiosValue(&host->productSku); - ffSettingsGetFreeBSDKenv("smbios.system.serial", &host->productSerial); - ffCleanUpSmbiosValue(&host->productSerial); - ffSettingsGetFreeBSDKenv("smbios.system.uuid", &host->productUuid); - ffCleanUpSmbiosValue(&host->productUuid); - ffSettingsGetFreeBSDKenv("smbios.system.maker", &host->sysVendor); - ffCleanUpSmbiosValue(&host->sysVendor); + ffSettingsGetFreeBSDKenv("smbios.system.product", &host->name); + ffCleanUpSmbiosValue(&host->name); + ffSettingsGetFreeBSDKenv("smbios.system.family", &host->family); + ffCleanUpSmbiosValue(&host->family); + ffSettingsGetFreeBSDKenv("smbios.system.version", &host->version); + ffCleanUpSmbiosValue(&host->version); + ffSettingsGetFreeBSDKenv("smbios.system.sku", &host->sku); + ffCleanUpSmbiosValue(&host->sku); + ffSettingsGetFreeBSDKenv("smbios.system.serial", &host->serial); + ffCleanUpSmbiosValue(&host->serial); + ffSettingsGetFreeBSDKenv("smbios.system.uuid", &host->uuid); + ffCleanUpSmbiosValue(&host->uuid); + ffSettingsGetFreeBSDKenv("smbios.system.maker", &host->vendor); + ffCleanUpSmbiosValue(&host->vendor); return NULL; } diff --git a/src/detection/host/host_linux.c b/src/detection/host/host_linux.c index 28697ad81..372557a88 100644 --- a/src/detection/host/host_linux.c +++ b/src/detection/host/host_linux.c @@ -29,28 +29,28 @@ static void getHostProductName(FFstrbuf* name) const char* ffDetectHost(FFHostResult* host) { - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->productFamily); - getHostProductName(&host->productName); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->productVersion); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->productSku); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->productSerial); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_uuid", "/sys/class/dmi/id/product_uuid", &host->productUuid); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->sysVendor); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family); + getHostProductName(&host->name); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->version); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->sku); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->serial); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_uuid", "/sys/class/dmi/id/product_uuid", &host->uuid); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->vendor); //KVM/Qemu virtual machine - if(ffStrbufStartsWithS(&host->productName, "Standard PC")) - ffStrbufPrependS(&host->productName, "KVM/QEMU "); + if(ffStrbufStartsWithS(&host->name, "Standard PC")) + ffStrbufPrependS(&host->name, "KVM/QEMU "); - if(host->productFamily.length == 0 && host->productName.length == 0) + if(host->family.length == 0 && host->name.length == 0) { const char* wslDistroName = getenv("WSL_DISTRO_NAME"); //On WSL, the real host can't be detected. Instead use WSL as host. if(wslDistroName != NULL || getenv("WSL_DISTRO") != NULL || getenv("WSL_INTEROP") != NULL) { - ffStrbufAppendS(&host->productName, "Windows Subsystem for Linux"); + ffStrbufAppendS(&host->name, "Windows Subsystem for Linux"); if (wslDistroName) - ffStrbufAppendF(&host->productName, " - %s", wslDistroName); - ffStrbufAppendS(&host->productFamily, "WSL"); + ffStrbufAppendF(&host->name, " - %s", wslDistroName); + ffStrbufAppendS(&host->family, "WSL"); FF_STRBUF_AUTO_DESTROY wslVer = ffStrbufCreate(); //Wide characters if(!ffProcessAppendStdOut(&wslVer, (char* const[]){ @@ -63,7 +63,7 @@ const char* ffDetectHost(FFHostResult* host) ffStrbufSubstrAfterLastC(&wslVer, ' '); for(uint32_t i = 0; i < wslVer.length; ++i) { if(wslVer.chars[i]) //don't append \0 - ffStrbufAppendC(&host->productVersion, wslVer.chars[i]); + ffStrbufAppendC(&host->version, wslVer.chars[i]); } } } diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.c index afc2b242c..8ff2c70a0 100644 --- a/src/detection/host/host_windows.c +++ b/src/detection/host/host_windows.c @@ -9,16 +9,16 @@ const char* ffDetectHost(FFHostResult* host) if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL)) return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed"; - ffRegReadStrbuf(hKey, L"SystemProductName", &host->productName, NULL); - ffCleanUpSmbiosValue(&host->productName); - ffRegReadStrbuf(hKey, L"SystemFamily", &host->productFamily, NULL); - ffCleanUpSmbiosValue(&host->productFamily); - ffRegReadStrbuf(hKey, L"SystemVersion", &host->productVersion, NULL); - ffCleanUpSmbiosValue(&host->productVersion); - ffRegReadStrbuf(hKey, L"SystemSKU", &host->productSku, NULL); - ffCleanUpSmbiosValue(&host->productSku); - ffRegReadStrbuf(hKey, L"SystemManufacturer", &host->sysVendor, NULL); - ffCleanUpSmbiosValue(&host->sysVendor); + ffRegReadStrbuf(hKey, L"SystemProductName", &host->name, NULL); + ffCleanUpSmbiosValue(&host->name); + ffRegReadStrbuf(hKey, L"SystemFamily", &host->family, NULL); + ffCleanUpSmbiosValue(&host->family); + ffRegReadStrbuf(hKey, L"SystemVersion", &host->version, NULL); + ffCleanUpSmbiosValue(&host->version); + ffRegReadStrbuf(hKey, L"SystemSKU", &host->sku, NULL); + ffCleanUpSmbiosValue(&host->sku); + ffRegReadStrbuf(hKey, L"SystemManufacturer", &host->vendor, NULL); + ffCleanUpSmbiosValue(&host->vendor); return NULL; } diff --git a/src/modules/host/host.c b/src/modules/host/host.c index b6e5151ad..5c80baef0 100644 --- a/src/modules/host/host.c +++ b/src/modules/host/host.c @@ -9,13 +9,13 @@ void ffPrintHost(FFHostOptions* options) { FFHostResult host; - ffStrbufInit(&host.productFamily); - ffStrbufInit(&host.productName); - ffStrbufInit(&host.productVersion); - ffStrbufInit(&host.productSku); - ffStrbufInit(&host.productSerial); - ffStrbufInit(&host.productUuid); - ffStrbufInit(&host.sysVendor); + ffStrbufInit(&host.family); + ffStrbufInit(&host.name); + ffStrbufInit(&host.version); + ffStrbufInit(&host.sku); + ffStrbufInit(&host.serial); + ffStrbufInit(&host.uuid); + ffStrbufInit(&host.vendor); const char* error = ffDetectHost(&host); if(error) @@ -24,7 +24,7 @@ void ffPrintHost(FFHostOptions* options) goto exit; } - if(host.productFamily.length == 0 && host.productName.length == 0) + if(host.family.length == 0 && host.name.length == 0) { ffPrintError(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, "neither product_family nor product_name is set by O.E.M."); goto exit; @@ -36,37 +36,37 @@ void ffPrintHost(FFHostOptions* options) FF_STRBUF_AUTO_DESTROY output = ffStrbufCreate(); - if(host.productName.length > 0) - ffStrbufAppend(&output, &host.productName); + if(host.name.length > 0) + ffStrbufAppend(&output, &host.name); else - ffStrbufAppend(&output, &host.productFamily); + ffStrbufAppend(&output, &host.family); - if(host.productVersion.length > 0) - ffStrbufAppendF(&output, " (%s)", host.productVersion.chars); + if(host.version.length > 0) + ffStrbufAppendF(&output, " (%s)", host.version.chars); ffStrbufPutTo(&output, stdout); } else { ffPrintFormat(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, FF_HOST_NUM_FORMAT_ARGS, (FFformatarg[]) { - {FF_FORMAT_ARG_TYPE_STRBUF, &host.productFamily}, - {FF_FORMAT_ARG_TYPE_STRBUF, &host.productName}, - {FF_FORMAT_ARG_TYPE_STRBUF, &host.productVersion}, - {FF_FORMAT_ARG_TYPE_STRBUF, &host.productSku}, - {FF_FORMAT_ARG_TYPE_STRBUF, &host.sysVendor}, - {FF_FORMAT_ARG_TYPE_STRBUF, &host.productSerial}, - {FF_FORMAT_ARG_TYPE_STRBUF, &host.productUuid}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.family}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.name}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.version}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.sku}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.vendor}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.serial}, + {FF_FORMAT_ARG_TYPE_STRBUF, &host.uuid}, }); } exit: - ffStrbufDestroy(&host.productFamily); - ffStrbufDestroy(&host.productName); - ffStrbufDestroy(&host.productVersion); - ffStrbufDestroy(&host.productSku); - ffStrbufDestroy(&host.productSerial); - ffStrbufDestroy(&host.productUuid); - ffStrbufDestroy(&host.sysVendor); + ffStrbufDestroy(&host.family); + ffStrbufDestroy(&host.name); + ffStrbufDestroy(&host.version); + ffStrbufDestroy(&host.sku); + ffStrbufDestroy(&host.serial); + ffStrbufDestroy(&host.uuid); + ffStrbufDestroy(&host.vendor); } bool ffParseHostCommandOptions(FFHostOptions* options, const char* key, const char* value) @@ -107,13 +107,13 @@ void ffGenerateHostJsonConfig(FFHostOptions* options, yyjson_mut_doc* doc, yyjso void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { FFHostResult host; - ffStrbufInit(&host.productFamily); - ffStrbufInit(&host.productName); - ffStrbufInit(&host.productVersion); - ffStrbufInit(&host.productSku); - ffStrbufInit(&host.productSerial); - ffStrbufInit(&host.productUuid); - ffStrbufInit(&host.sysVendor); + ffStrbufInit(&host.family); + ffStrbufInit(&host.name); + ffStrbufInit(&host.version); + ffStrbufInit(&host.sku); + ffStrbufInit(&host.serial); + ffStrbufInit(&host.uuid); + ffStrbufInit(&host.vendor); const char* error = ffDetectHost(&host); if (error) @@ -122,29 +122,29 @@ void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut goto exit; } - if (host.productFamily.length == 0 && host.productName.length == 0) + if (host.family.length == 0 && host.name.length == 0) { yyjson_mut_obj_add_str(doc, module, "error", "neither product_family nor product_name is set by O.E.M."); goto exit; } yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); - yyjson_mut_obj_add_strbuf(doc, obj, "family", &host.productFamily); - yyjson_mut_obj_add_strbuf(doc, obj, "name", &host.productName); - yyjson_mut_obj_add_strbuf(doc, obj, "version", &host.productVersion); - yyjson_mut_obj_add_strbuf(doc, obj, "sku", &host.productSku); - yyjson_mut_obj_add_strbuf(doc, obj, "serial", &host.productSerial); - yyjson_mut_obj_add_strbuf(doc, obj, "uuid", &host.productUuid); - yyjson_mut_obj_add_strbuf(doc, obj, "sysVender", &host.sysVendor); + yyjson_mut_obj_add_strbuf(doc, obj, "family", &host.family); + yyjson_mut_obj_add_strbuf(doc, obj, "name", &host.name); + yyjson_mut_obj_add_strbuf(doc, obj, "version", &host.version); + yyjson_mut_obj_add_strbuf(doc, obj, "sku", &host.sku); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &host.serial); + yyjson_mut_obj_add_strbuf(doc, obj, "uuid", &host.uuid); + yyjson_mut_obj_add_strbuf(doc, obj, "sysVender", &host.vendor); exit: - ffStrbufDestroy(&host.productFamily); - ffStrbufDestroy(&host.productName); - ffStrbufDestroy(&host.productVersion); - ffStrbufDestroy(&host.productSku); - ffStrbufDestroy(&host.productSerial); - ffStrbufDestroy(&host.productUuid); - ffStrbufDestroy(&host.sysVendor); + ffStrbufDestroy(&host.family); + ffStrbufDestroy(&host.name); + ffStrbufDestroy(&host.version); + ffStrbufDestroy(&host.sku); + ffStrbufDestroy(&host.serial); + ffStrbufDestroy(&host.uuid); + ffStrbufDestroy(&host.vendor); } void ffPrintHostHelpFormat(void) From 21f3875c4f1458e859093d3c10eceed4f68dda4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 5 Jan 2024 22:44:40 +0800 Subject: [PATCH 27/99] Host (Windows): detect serial number and UUID --- CMakeLists.txt | 2 +- doc/json_schema.json | 31 ++++++++++++++--- src/data/help.json | 14 ++++++-- src/detection/host/host.h | 2 +- src/detection/host/host_android.c | 2 +- src/detection/host/host_apple.c | 2 +- src/detection/host/host_bsd.c | 2 +- src/detection/host/host_linux.c | 2 +- .../host/{host_windows.c => host_windows.cpp} | 27 ++++++++++++++- src/modules/host/host.c | 33 ++++++++++++++++--- src/modules/host/option.h | 4 +++ 11 files changed, 104 insertions(+), 17 deletions(-) rename src/detection/host/{host_windows.c => host_windows.cpp} (52%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e0624a46..2a0babff5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -631,7 +631,7 @@ elseif(WIN32) src/detection/displayserver/displayserver_windows.c src/detection/font/font_windows.c src/detection/gpu/gpu_windows.c - src/detection/host/host_windows.c + src/detection/host/host_windows.cpp src/detection/icons/icons_windows.c src/detection/libc/libc_windows.cpp src/detection/lm/lm_nosupport.c diff --git a/doc/json_schema.json b/doc/json_schema.json index 78a4116b0..e86fbc74d 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -676,10 +676,6 @@ "const": "gamepad", "description": "List connected gamepads" }, - { - "const": "host", - "description": "Print product name of your computer" - }, { "const": "icons", "description": "Print icon style name" @@ -1221,6 +1217,33 @@ }, "additionalProperties": false }, + { + "title": "Host", + "properties": { + "type": { + "const": "host", + "description": "Print product name of your computer", + }, + "useWmi": { + "description": "Set if WMI query should be used on Windows, which detects more information but slower", + "type": "boolean", + "default": false + }, + "key": { + "$ref": "#/$defs/key" + }, + "keyColor": { + "$ref": "#/$defs/keyColor" + }, + "keyWidth": { + "$ref": "#/$defs/keyWidth" + }, + "format": { + "$ref": "#/$defs/format" + } + }, + "additionalProperties": false + }, { "title": "Local IP", "properties": { diff --git a/src/data/help.json b/src/data/help.json index 3af8895cc..2302f6c10 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -842,10 +842,20 @@ "default": "default" } }, + { + "long": "host-use-wmi", + "desc": "Set if WMI query should be used on Windows when detecting host", + "remark": "WMI query detects more information (UUID and serial number) but is slower. Windows only", + "arg": { + "type": "bool", + "optional": true, + "default": false + } + }, { "long": "chassis-use-wmi", - "desc": "Set if WMI query should be used on Windows", - "remark": "WMI query detects more information but is slower. Windows only", + "desc": "Set if WMI query should be used on Windows when detecting chassis", + "remark": "WMI query detects more information (vendor and version) but is slower. Windows only", "arg": { "type": "bool", "optional": true, diff --git a/src/detection/host/host.h b/src/detection/host/host.h index 1b0c61187..eb236ccf8 100644 --- a/src/detection/host/host.h +++ b/src/detection/host/host.h @@ -13,4 +13,4 @@ typedef struct FFHostResult FFstrbuf vendor; } FFHostResult; -const char* ffDetectHost(FFHostResult* host); +const char* ffDetectHost(FFHostResult* host, FFHostOptions* options); diff --git a/src/detection/host/host_android.c b/src/detection/host/host_android.c index b496029a8..e37202cb8 100644 --- a/src/detection/host/host_android.c +++ b/src/detection/host/host_android.c @@ -2,7 +2,7 @@ #include "common/settings.h" #include -const char* ffDetectHost(FFHostResult* host) +const char* ffDetectHost(FFHostResult* host, FF_MAYBE_UNUSED FFHostOptions* options) { // http://newandroidbook.com/ddb/ ffSettingsGetAndroidProperty("ro.product.device", &host->family); diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 98910e5e8..89f47f626 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -201,7 +201,7 @@ const char* getOthersByIokit(FFHostResult* host) return NULL; } -const char* ffDetectHost(FFHostResult* host) +const char* ffDetectHost(FFHostResult* host, FF_MAYBE_UNUSED FFHostOptions* options) { const char* error = ffSysctlGetString("hw.model", &host->family); if (error) return error; diff --git a/src/detection/host/host_bsd.c b/src/detection/host/host_bsd.c index 334b04cab..f662a9f28 100644 --- a/src/detection/host/host_bsd.c +++ b/src/detection/host/host_bsd.c @@ -2,7 +2,7 @@ #include "common/settings.h" #include "util/smbiosHelper.h" -const char* ffDetectHost(FFHostResult* host) +const char* ffDetectHost(FFHostResult* host, FF_MAYBE_UNUSED FFHostOptions* options) { ffSettingsGetFreeBSDKenv("smbios.system.product", &host->name); ffCleanUpSmbiosValue(&host->name); diff --git a/src/detection/host/host_linux.c b/src/detection/host/host_linux.c index 372557a88..4c542f6b9 100644 --- a/src/detection/host/host_linux.c +++ b/src/detection/host/host_linux.c @@ -27,7 +27,7 @@ static void getHostProductName(FFstrbuf* name) ffStrbufClear(name); } -const char* ffDetectHost(FFHostResult* host) +const char* ffDetectHost(FFHostResult* host, FF_MAYBE_UNUSED FFHostOptions* options) { ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family); getHostProductName(&host->name); diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.cpp similarity index 52% rename from src/detection/host/host_windows.c rename to src/detection/host/host_windows.cpp index 8ff2c70a0..2d3ab2040 100644 --- a/src/detection/host/host_windows.c +++ b/src/detection/host/host_windows.cpp @@ -1,8 +1,30 @@ +extern "C" +{ #include "host.h" #include "util/windows/registry.h" #include "util/smbiosHelper.h" +} +#include "util/windows/wmi.hpp" +#include "util/windows/unicode.hpp" -const char* ffDetectHost(FFHostResult* host) +const char* detectWithWmi(FFHostResult* host) +{ + FFWmiQuery query(L"SELECT IdentifyingNumber, UUID FROM Win32_ComputerSystemProduct", nullptr, FFWmiNamespace::CIMV2); + if(!query) + return "Query WMI service failed"; + + if (FFWmiRecord record = query.next()) + { + if (auto identifyingNumber = record.get(L"IdentifyingNumber")) + ffStrbufSetWSV(&host->serial, identifyingNumber.get()); + if (auto uuid = record.get(L"UUID")) + ffStrbufSetWSV(&host->uuid, uuid.get()); + return NULL; + } + return "No WMI result returned"; +} + +const char* ffDetectHost(FFHostResult* host, FFHostOptions* options) { FF_HKEY_AUTO_DESTROY hKey = NULL; @@ -20,5 +42,8 @@ const char* ffDetectHost(FFHostResult* host) ffRegReadStrbuf(hKey, L"SystemManufacturer", &host->vendor, NULL); ffCleanUpSmbiosValue(&host->vendor); + if (options->useWmi) + detectWithWmi(host); + return NULL; } diff --git a/src/modules/host/host.c b/src/modules/host/host.c index 5c80baef0..18a146378 100644 --- a/src/modules/host/host.c +++ b/src/modules/host/host.c @@ -16,8 +16,8 @@ void ffPrintHost(FFHostOptions* options) ffStrbufInit(&host.serial); ffStrbufInit(&host.uuid); ffStrbufInit(&host.vendor); - const char* error = ffDetectHost(&host); + const char* error = ffDetectHost(&host, options); if(error) { ffPrintError(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, "%s", error); @@ -76,6 +76,14 @@ bool ffParseHostCommandOptions(FFHostOptions* options, const char* key, const ch if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; + #ifdef _WIN32 + if (ffStrEqualsIgnCase(subKey, "use-wmi")) + { + options->useWmi = ffOptionParseBoolean(value); + return true; + } + #endif + return false; } @@ -92,6 +100,14 @@ void ffParseHostJsonObject(FFHostOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; + #ifdef _WIN32 + if (ffStrEqualsIgnCase(key, "useWmi")) + { + options->useWmi = yyjson_get_bool(val); + continue; + } + #endif + ffPrintError(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -102,6 +118,11 @@ void ffGenerateHostJsonConfig(FFHostOptions* options, yyjson_mut_doc* doc, yyjso ffInitHostOptions(&defaultOptions); ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); + + #ifdef _WIN32 + if (options->useWmi != defaultOptions.useWmi) + yyjson_mut_obj_add_bool(doc, module, "useWmi", options->useWmi); + #endif } void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -114,8 +135,8 @@ void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut ffStrbufInit(&host.serial); ffStrbufInit(&host.uuid); ffStrbufInit(&host.vendor); - const char* error = ffDetectHost(&host); + const char* error = ffDetectHost(&host, options); if (error) { yyjson_mut_obj_add_str(doc, module, "error", error); @@ -133,9 +154,9 @@ void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut yyjson_mut_obj_add_strbuf(doc, obj, "name", &host.name); yyjson_mut_obj_add_strbuf(doc, obj, "version", &host.version); yyjson_mut_obj_add_strbuf(doc, obj, "sku", &host.sku); + yyjson_mut_obj_add_strbuf(doc, obj, "vender", &host.vendor); yyjson_mut_obj_add_strbuf(doc, obj, "serial", &host.serial); yyjson_mut_obj_add_strbuf(doc, obj, "uuid", &host.uuid); - yyjson_mut_obj_add_strbuf(doc, obj, "sysVender", &host.vendor); exit: ffStrbufDestroy(&host.family); @@ -154,9 +175,9 @@ void ffPrintHostHelpFormat(void) "product name", "product version", "product sku", + "product vendor", "product serial number", "product uuid", - "sys vendor" }); } @@ -174,6 +195,10 @@ void ffInitHostOptions(FFHostOptions* options) ffGenerateHostJsonConfig ); ffOptionInitModuleArg(&options->moduleArgs); + + #ifdef _WIN32 + options->useWmi = false; + #endif } void ffDestroyHostOptions(FFHostOptions* options) diff --git a/src/modules/host/option.h b/src/modules/host/option.h index 1c6bf26f3..b305f2a92 100644 --- a/src/modules/host/option.h +++ b/src/modules/host/option.h @@ -8,4 +8,8 @@ typedef struct FFHostOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; + + #ifdef _WIN32 + bool useWmi; + #endif } FFHostOptions; From 33f319938387aba9a9414ea8740479032ea79452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 00:41:02 +0800 Subject: [PATCH 28/99] Host / Chassis (Windows): parse SMBIOS data directly --- CMakeLists.txt | 4 +- src/detection/chassis/chassis.c | 4 +- src/detection/chassis/chassis_windows.c | 47 +++++++++++++++ src/detection/chassis/chassis_windows.cpp | 73 ----------------------- src/detection/host/host_windows.c | 68 +++++++++++++++++++++ src/detection/host/host_windows.cpp | 49 --------------- src/util/smbiosHelper.c | 18 ++++++ src/util/smbiosHelper.h | 60 +++++++++++++++++++ 8 files changed, 197 insertions(+), 126 deletions(-) create mode 100644 src/detection/chassis/chassis_windows.c delete mode 100644 src/detection/chassis/chassis_windows.cpp create mode 100644 src/detection/host/host_windows.c delete mode 100644 src/detection/host/host_windows.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a0babff5..357faaaf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -621,7 +621,7 @@ elseif(WIN32) src/detection/bluetooth/bluetooth_windows.c src/detection/board/board_windows.c src/detection/brightness/brightness_windows.cpp - src/detection/chassis/chassis_windows.cpp + src/detection/chassis/chassis_windows.c src/detection/cpu/cpu_windows.c src/detection/cpuusage/cpuusage_windows.c src/detection/cursor/cursor_windows.c @@ -631,7 +631,7 @@ elseif(WIN32) src/detection/displayserver/displayserver_windows.c src/detection/font/font_windows.c src/detection/gpu/gpu_windows.c - src/detection/host/host_windows.cpp + src/detection/host/host_windows.c src/detection/icons/icons_windows.c src/detection/libc/libc_windows.cpp src/detection/lm/lm_nosupport.c diff --git a/src/detection/chassis/chassis.c b/src/detection/chassis/chassis.c index f2ebc2da1..9e76bcfc8 100644 --- a/src/detection/chassis/chassis.c +++ b/src/detection/chassis/chassis.c @@ -2,9 +2,9 @@ const char* ffChassisTypeToString(uint32_t type) { - // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.pdf + // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf // 7.4.1 System Enclosure or Chassis Types - switch (type) + switch (type & 0b01111111) { case 0x01: return "Other"; case 0x02: return "Unknown"; diff --git a/src/detection/chassis/chassis_windows.c b/src/detection/chassis/chassis_windows.c new file mode 100644 index 000000000..54dbad81f --- /dev/null +++ b/src/detection/chassis/chassis_windows.c @@ -0,0 +1,47 @@ +#include "chassis.h" +#include "util/smbiosHelper.h" + +// 7.4 +typedef struct FFSmbiosSystemEnclosure +{ + uint8_t Manufacturer; + uint8_t Type; + uint8_t Version; + uint8_t SerialNumber; + uint8_t AssetTagNumber; + uint8_t BootupState; + uint8_t PowerSupplyState; + uint8_t ThermalState; + uint8_t SecurityStatus; + uint32_t OEMDefined; + uint8_t Height; + uint8_t NumberOfPowerCords; +} FFSmbiosSystemEnclosure; + +const char* ffDetectChassis(FFChassisResult* result, FFChassisOptions* options) +{ + const FFRawSmbiosData* data = ffGetSmbiosData(); + + for ( + const FFSmbiosHeader* header = (const FFSmbiosHeader*) data->SMBIOSTableData; + (const uint8_t*) header < data->SMBIOSTableData + data->Length && header->Type < FF_SMBIOS_TYPE_LAST; + header = ffSmbiosSkipLastStr(header) + ) + { + if (header->Type != FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE) + continue; + + const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) header->Data; + const char* strings = (const char*) header + header->Length; + + ffStrbufSetStatic(&result->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&result->vendor); + ffStrbufSetStatic(&result->version, ffSmbiosLocateString(strings, data->Version)); + ffCleanUpSmbiosValue(&result->version); + ffStrbufSetStatic(&result->type, ffChassisTypeToString(data->Type)); + + return NULL; + } + + return "System enclosure is not found in SMBIOS data"; +} diff --git a/src/detection/chassis/chassis_windows.cpp b/src/detection/chassis/chassis_windows.cpp deleted file mode 100644 index 9a3d37fcc..000000000 --- a/src/detection/chassis/chassis_windows.cpp +++ /dev/null @@ -1,73 +0,0 @@ -extern "C" { -#include "chassis.h" -#include "util/windows/registry.h" -#include "util/smbiosHelper.h" -} -#include "util/windows/unicode.hpp" -#include "util/windows/wmi.hpp" - -static const char* detectWithRegistry(FFChassisResult* result) -{ - FF_HKEY_AUTO_DESTROY hKey = NULL; - if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL)) // SMBIOS - return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed"; - - uint32_t type = 0; - if(!ffRegReadUint(hKey, L"EnclosureType", &type, NULL)) - return "\"HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\EnclosureType\" doesn't exist"; - - const char* typeStr = ffChassisTypeToString(type); - if(!typeStr) - return "Unknown chassis type"; - - ffStrbufAppendS(&result->type, typeStr); - return NULL; -} - -FF_MAYBE_UNUSED static const char* detectWithWmi(FFChassisResult* result) -{ - FFWmiQuery query(L"SELECT Version, ChassisTypes, Manufacturer FROM Win32_SystemEnclosure"); - if (!query) - return "Query WMI service failed"; - - if (FFWmiRecord record = query.next()) - { - if (auto vtProp = record.get(L"ChassisTypes")) - { - auto [arr, len] = vtProp.get>(); - if(len == 0) - return "ChassisTypes contain no data"; - for (uint32_t i = 0; i < len; ++i) - { - if (i > 0) - ffStrbufAppendS(&result->type, ", "); - ffStrbufAppendS(&result->type, ffChassisTypeToString((uint32_t) arr[i])); - } - } - else - return "Get ChassisTypes failed"; - - if (auto vtProp = record.get(L"Version")) - { - ffStrbufSetWSV(&result->version, vtProp.get()); - ffCleanUpSmbiosValue(&result->version); - } - - if (auto vtProp = record.get(L"Manufacturer")) - { - ffStrbufSetWSV(&result->vendor, vtProp.get()); - ffCleanUpSmbiosValue(&result->vendor); - } - - return NULL; - } - return "No WMI result returned"; -} - -extern "C" -const char* ffDetectChassis(FFChassisResult* result, FFChassisOptions* options) -{ - if (options->useWmi) - return detectWithWmi(result); - return detectWithRegistry(result); -} diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.c new file mode 100644 index 000000000..6b217fa99 --- /dev/null +++ b/src/detection/host/host_windows.c @@ -0,0 +1,68 @@ +#include "host.h" +#include "util/smbiosHelper.h" + +typedef struct FFSmbiosSystemInfo +{ + uint8_t Manufacturer; + uint8_t ProductName; + uint8_t Version; + uint8_t SerialNumber; + struct { + uint32_t TimeLow; + uint16_t TimeMid; + uint16_t TimeHighAndVersion; + uint8_t ClockSeqHiAndReserved; + uint8_t ClockSeqLow; + uint8_t Node[6]; + } UUID; + uint8_t WakeUpType; + uint8_t SKUNumber; + uint8_t Family; +} FFSmbiosSystemInfo; + +const char* ffDetectHost(FFHostResult* host, FFHostOptions* options) +{ + const FFRawSmbiosData* fullData = ffGetSmbiosData(); + + for ( + const FFSmbiosHeader* header = (const FFSmbiosHeader*) fullData->SMBIOSTableData; + (const uint8_t*) header < fullData->SMBIOSTableData + fullData->Length && header->Type < FF_SMBIOS_TYPE_LAST; + header = ffSmbiosSkipLastStr(header) + ) + { + if (header->Type != FF_SMBIOS_TYPE_SYSTEM_INFO) + continue; + + const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) header->Data; + const char* strings = (const char*) header + header->Length; + + ffStrbufSetStatic(&host->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&host->vendor); + ffStrbufSetStatic(&host->name, ffSmbiosLocateString(strings, data->ProductName)); + ffCleanUpSmbiosValue(&host->name); + ffStrbufSetStatic(&host->version, ffSmbiosLocateString(strings, data->Version)); + ffCleanUpSmbiosValue(&host->version); + ffStrbufSetStatic(&host->serial, ffSmbiosLocateString(strings, data->SerialNumber)); + ffCleanUpSmbiosValue(&host->serial); + + if (header->Length > 0x08) + { + // Order? + ffStrbufSetF(&host->uuid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + data->UUID.TimeLow, data->UUID.TimeMid, data->UUID.TimeHighAndVersion, + data->UUID.ClockSeqHiAndReserved, data->UUID.ClockSeqLow, + data->UUID.Node[0], data->UUID.Node[1], data->UUID.Node[2], data->UUID.Node[3], data->UUID.Node[4], data->UUID.Node[5]); + } + if (header->Length > 0x19) + { + ffStrbufSetStatic(&host->family, ffSmbiosLocateString(strings, data->Family)); + ffCleanUpSmbiosValue(&host->family); + ffStrbufSetStatic(&host->sku, ffSmbiosLocateString(strings, data->SKUNumber)); + ffCleanUpSmbiosValue(&host->sku); + } + + return NULL; + } + + return "System information is not found in SMBIOS data"; +} diff --git a/src/detection/host/host_windows.cpp b/src/detection/host/host_windows.cpp deleted file mode 100644 index 2d3ab2040..000000000 --- a/src/detection/host/host_windows.cpp +++ /dev/null @@ -1,49 +0,0 @@ -extern "C" -{ -#include "host.h" -#include "util/windows/registry.h" -#include "util/smbiosHelper.h" -} -#include "util/windows/wmi.hpp" -#include "util/windows/unicode.hpp" - -const char* detectWithWmi(FFHostResult* host) -{ - FFWmiQuery query(L"SELECT IdentifyingNumber, UUID FROM Win32_ComputerSystemProduct", nullptr, FFWmiNamespace::CIMV2); - if(!query) - return "Query WMI service failed"; - - if (FFWmiRecord record = query.next()) - { - if (auto identifyingNumber = record.get(L"IdentifyingNumber")) - ffStrbufSetWSV(&host->serial, identifyingNumber.get()); - if (auto uuid = record.get(L"UUID")) - ffStrbufSetWSV(&host->uuid, uuid.get()); - return NULL; - } - return "No WMI result returned"; -} - -const char* ffDetectHost(FFHostResult* host, FFHostOptions* options) -{ - FF_HKEY_AUTO_DESTROY hKey = NULL; - - if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL)) - return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed"; - - ffRegReadStrbuf(hKey, L"SystemProductName", &host->name, NULL); - ffCleanUpSmbiosValue(&host->name); - ffRegReadStrbuf(hKey, L"SystemFamily", &host->family, NULL); - ffCleanUpSmbiosValue(&host->family); - ffRegReadStrbuf(hKey, L"SystemVersion", &host->version, NULL); - ffCleanUpSmbiosValue(&host->version); - ffRegReadStrbuf(hKey, L"SystemSKU", &host->sku, NULL); - ffCleanUpSmbiosValue(&host->sku); - ffRegReadStrbuf(hKey, L"SystemManufacturer", &host->vendor, NULL); - ffCleanUpSmbiosValue(&host->vendor); - - if (options->useWmi) - detectWithWmi(host); - - return NULL; -} diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 5f958fc27..718d56cfc 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -47,4 +47,22 @@ void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* ffStrbufClear(buffer); } +#elif defined(_WIN32) +#include + +#pragma GCC diagnostic ignored "-Wmultichar" + +const FFRawSmbiosData* ffGetSmbiosData() +{ + static FFRawSmbiosData* buffer; + if (!buffer) + { + const DWORD signature = 'RSMB'; + uint32_t bufSize = GetSystemFirmwareTable(signature, 0, NULL, 0); + assert(bufSize > sizeof(FFRawSmbiosData)); + buffer = (FFRawSmbiosData*) malloc(bufSize); + GetSystemFirmwareTable(signature, 0, buffer, bufSize); + } + return buffer; +} #endif diff --git a/src/util/smbiosHelper.h b/src/util/smbiosHelper.h index f129af5ac..bfb7c97af 100644 --- a/src/util/smbiosHelper.h +++ b/src/util/smbiosHelper.h @@ -14,6 +14,66 @@ static inline void ffCleanUpSmbiosValue(FFstrbuf* value) #ifdef __linux__ void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer); +#elif defined(_WIN32) +// https://github.com/KunYi/DumpSMBIOS +// https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf + +typedef enum __attribute__((__packed__)) FFSmbiosType // : uint8_t +{ + FF_SMBIOS_TYPE_BIOS = 0, + FF_SMBIOS_TYPE_SYSTEM_INFO = 1, + FF_SMBIOS_TYPE_BASEBOARD_INFO = 2, + FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE = 3, + FF_SMBIOS_TYPE_PROCESSOR_INFO = 4, + FF_SMBIOS_TYPE_MEMORY_MODULE_INFO = 6, + FF_SMBIOS_TYPE_CACHE_INFO = 7, + FF_SMBIOS_TYPE_OEM_STRING = 11, + FF_SMBIOS_TYPE_MEMORY_DEVICE = 17, + FF_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS = 19, + FF_SMBIOS_TYPE_BUILTIN_POINT_DEVICE = 21, + FF_SMBIOS_TYPE_PORTABLE_BATTERY = 22, + FF_SMBIOS_TYPE_LAST = 127, +} FFSmbiosType; +static_assert(sizeof(FFSmbiosType) == 1, "FFSmbiosType should be 1 byte"); + +typedef struct FFSmbiosHeader +{ + FFSmbiosType Type; + uint8_t Length; + uint16_t Handle; + uint8_t Data[]; +} FFSmbiosHeader; +static_assert(sizeof(FFSmbiosHeader) == 4, "FFSmbiosHeader should be 4 bytes"); + +typedef struct FFRawSmbiosData +{ + uint8_t Used20CallingMethod; + uint8_t SMBIOSMajorVersion; + uint8_t SMBIOSMinorVersion; + uint8_t DmiRevision; + uint32_t Length; + uint8_t SMBIOSTableData[]; +} FFRawSmbiosData; + +static inline const char* ffSmbiosLocateString(const char* start, uint8_t index /* start from 1 */) +{ + if (index == 0 || *start == '\0') + return NULL; + while (--index) + start += strlen(start) + 1; + return start; +} + +static inline const FFSmbiosHeader* ffSmbiosSkipLastStr(const FFSmbiosHeader* header) +{ + const char* p = ((const char*) header) + header->Length; + while (*p) + p += strlen(p) + 1; + + return (const FFSmbiosHeader*) (p + 1); +} + +const FFRawSmbiosData* ffGetSmbiosData(); #endif #endif From d578f1006c1d1d122ace0e5d3f7ba964f0c49c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 10:43:51 +0800 Subject: [PATCH 29/99] Host / Chassis (Windows): remove options `--*-use-wmi` --- CHANGELOG.md | 2 ++ doc/json_schema.json | 10 -------- src/data/help.json | 20 ---------------- src/detection/chassis/chassis.h | 2 +- src/detection/chassis/chassis_bsd.c | 2 +- src/detection/chassis/chassis_linux.c | 2 +- src/detection/chassis/chassis_nosupport.c | 2 +- src/detection/chassis/chassis_windows.c | 2 +- src/detection/host/host.h | 2 +- src/detection/host/host_android.c | 2 +- src/detection/host/host_apple.c | 2 +- src/detection/host/host_bsd.c | 2 +- src/detection/host/host_linux.c | 2 +- src/detection/host/host_windows.c | 2 +- src/modules/chassis/chassis.c | 29 ++--------------------- src/modules/chassis/option.h | 4 ---- src/modules/host/host.c | 29 ++--------------------- src/modules/host/option.h | 4 ---- 18 files changed, 17 insertions(+), 103 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a0ce1b9e..4a1153a63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,13 @@ Changes: * Remove support of option `--battery-dir`. We detect a lot of things in `/sys/class/*` and only module `Battery` supports specifying a custom directory for some reason, which is weird. +* Remove `--chassis-use-wmi` which is no longer used. Features: * Add `ENABLE_PROPRIETARY_GPU_DRIVER_API` cmake option to disable using of proprietary GPU driver APIs (GPU) * Add power adapter detection support for Asahi Linux (PowerAdapter, Linux) * Add battery serial number detection (Battery) +* Add host serial number and UUID detection (Host) Bugfixes: * Fix support of macOS Sonoma (Wallpaper, macOS) diff --git a/doc/json_schema.json b/doc/json_schema.json index e86fbc74d..cb48c7e66 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -875,11 +875,6 @@ "const": "chassis", "description": "Print chassis type (desktop, laptop, etc)" }, - "useWmi": { - "description": "Set if WMI query should be used on Windows, which detects more information but slower", - "type": "boolean", - "default": false - }, "key": { "$ref": "#/$defs/key" }, @@ -1224,11 +1219,6 @@ "const": "host", "description": "Print product name of your computer", }, - "useWmi": { - "description": "Set if WMI query should be used on Windows, which detects more information but slower", - "type": "boolean", - "default": false - }, "key": { "$ref": "#/$defs/key" }, diff --git a/src/data/help.json b/src/data/help.json index 2302f6c10..d3da78a82 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -842,26 +842,6 @@ "default": "default" } }, - { - "long": "host-use-wmi", - "desc": "Set if WMI query should be used on Windows when detecting host", - "remark": "WMI query detects more information (UUID and serial number) but is slower. Windows only", - "arg": { - "type": "bool", - "optional": true, - "default": false - } - }, - { - "long": "chassis-use-wmi", - "desc": "Set if WMI query should be used on Windows when detecting chassis", - "remark": "WMI query detects more information (vendor and version) but is slower. Windows only", - "arg": { - "type": "bool", - "optional": true, - "default": false - } - }, { "long": "separator-string", "desc": "Set the string printed by the separator module", diff --git a/src/detection/chassis/chassis.h b/src/detection/chassis/chassis.h index 60befc83e..6990a09e4 100644 --- a/src/detection/chassis/chassis.h +++ b/src/detection/chassis/chassis.h @@ -9,5 +9,5 @@ typedef struct FFChassisResult FFstrbuf version; } FFChassisResult; -const char* ffDetectChassis(FFChassisResult* result, FFChassisOptions* options); +const char* ffDetectChassis(FFChassisResult* result); const char* ffChassisTypeToString(uint32_t type); diff --git a/src/detection/chassis/chassis_bsd.c b/src/detection/chassis/chassis_bsd.c index 54a84c7e9..c38b562c2 100644 --- a/src/detection/chassis/chassis_bsd.c +++ b/src/detection/chassis/chassis_bsd.c @@ -2,7 +2,7 @@ #include "common/settings.h" #include "util/smbiosHelper.h" -const char* ffDetectChassis(FFChassisResult* result, FF_MAYBE_UNUSED FFChassisOptions* options) +const char* ffDetectChassis(FFChassisResult* result) { // Unlike other platforms, `smbios.chassis.type` return display string directly on my machine ffSettingsGetFreeBSDKenv("smbios.chassis.type", &result->type); diff --git a/src/detection/chassis/chassis_linux.c b/src/detection/chassis/chassis_linux.c index 8c050b859..9390169cf 100644 --- a/src/detection/chassis/chassis_linux.c +++ b/src/detection/chassis/chassis_linux.c @@ -4,7 +4,7 @@ #include -const char* ffDetectChassis(FFChassisResult* result, FF_MAYBE_UNUSED FFChassisOptions* options) +const char* ffDetectChassis(FFChassisResult* result) { ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor); diff --git a/src/detection/chassis/chassis_nosupport.c b/src/detection/chassis/chassis_nosupport.c index 6d83b90d1..c2acd7579 100644 --- a/src/detection/chassis/chassis_nosupport.c +++ b/src/detection/chassis/chassis_nosupport.c @@ -1,6 +1,6 @@ #include "chassis.h" -const char* ffDetectChassis(FF_MAYBE_UNUSED FFChassisResult* result, FF_MAYBE_UNUSED FFChassisOptions* options) +const char* ffDetectChassis(FF_MAYBE_UNUSED FFChassisResult* result) { return "Not supported on this platform"; } diff --git a/src/detection/chassis/chassis_windows.c b/src/detection/chassis/chassis_windows.c index 54dbad81f..707f4c3a9 100644 --- a/src/detection/chassis/chassis_windows.c +++ b/src/detection/chassis/chassis_windows.c @@ -18,7 +18,7 @@ typedef struct FFSmbiosSystemEnclosure uint8_t NumberOfPowerCords; } FFSmbiosSystemEnclosure; -const char* ffDetectChassis(FFChassisResult* result, FFChassisOptions* options) +const char* ffDetectChassis(FFChassisResult* result) { const FFRawSmbiosData* data = ffGetSmbiosData(); diff --git a/src/detection/host/host.h b/src/detection/host/host.h index eb236ccf8..1b0c61187 100644 --- a/src/detection/host/host.h +++ b/src/detection/host/host.h @@ -13,4 +13,4 @@ typedef struct FFHostResult FFstrbuf vendor; } FFHostResult; -const char* ffDetectHost(FFHostResult* host, FFHostOptions* options); +const char* ffDetectHost(FFHostResult* host); diff --git a/src/detection/host/host_android.c b/src/detection/host/host_android.c index e37202cb8..b496029a8 100644 --- a/src/detection/host/host_android.c +++ b/src/detection/host/host_android.c @@ -2,7 +2,7 @@ #include "common/settings.h" #include -const char* ffDetectHost(FFHostResult* host, FF_MAYBE_UNUSED FFHostOptions* options) +const char* ffDetectHost(FFHostResult* host) { // http://newandroidbook.com/ddb/ ffSettingsGetAndroidProperty("ro.product.device", &host->family); diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 89f47f626..98910e5e8 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -201,7 +201,7 @@ const char* getOthersByIokit(FFHostResult* host) return NULL; } -const char* ffDetectHost(FFHostResult* host, FF_MAYBE_UNUSED FFHostOptions* options) +const char* ffDetectHost(FFHostResult* host) { const char* error = ffSysctlGetString("hw.model", &host->family); if (error) return error; diff --git a/src/detection/host/host_bsd.c b/src/detection/host/host_bsd.c index f662a9f28..334b04cab 100644 --- a/src/detection/host/host_bsd.c +++ b/src/detection/host/host_bsd.c @@ -2,7 +2,7 @@ #include "common/settings.h" #include "util/smbiosHelper.h" -const char* ffDetectHost(FFHostResult* host, FF_MAYBE_UNUSED FFHostOptions* options) +const char* ffDetectHost(FFHostResult* host) { ffSettingsGetFreeBSDKenv("smbios.system.product", &host->name); ffCleanUpSmbiosValue(&host->name); diff --git a/src/detection/host/host_linux.c b/src/detection/host/host_linux.c index 4c542f6b9..372557a88 100644 --- a/src/detection/host/host_linux.c +++ b/src/detection/host/host_linux.c @@ -27,7 +27,7 @@ static void getHostProductName(FFstrbuf* name) ffStrbufClear(name); } -const char* ffDetectHost(FFHostResult* host, FF_MAYBE_UNUSED FFHostOptions* options) +const char* ffDetectHost(FFHostResult* host) { ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family); getHostProductName(&host->name); diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.c index 6b217fa99..6d382330d 100644 --- a/src/detection/host/host_windows.c +++ b/src/detection/host/host_windows.c @@ -20,7 +20,7 @@ typedef struct FFSmbiosSystemInfo uint8_t Family; } FFSmbiosSystemInfo; -const char* ffDetectHost(FFHostResult* host, FFHostOptions* options) +const char* ffDetectHost(FFHostResult* host) { const FFRawSmbiosData* fullData = ffGetSmbiosData(); diff --git a/src/modules/chassis/chassis.c b/src/modules/chassis/chassis.c index ad0b19570..1cb414f58 100644 --- a/src/modules/chassis/chassis.c +++ b/src/modules/chassis/chassis.c @@ -13,7 +13,7 @@ void ffPrintChassis(FFChassisOptions* options) ffStrbufInit(&result.vendor); ffStrbufInit(&result.version); - const char* error = ffDetectChassis(&result, options); + const char* error = ffDetectChassis(&result); if(error) { @@ -57,14 +57,6 @@ bool ffParseChassisCommandOptions(FFChassisOptions* options, const char* key, co if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; - #ifdef _WIN32 - if (ffStrEqualsIgnCase(subKey, "use-wmi")) - { - options->useWmi = ffOptionParseBoolean(value); - return true; - } - #endif - return false; } @@ -81,14 +73,6 @@ void ffParseChassisJsonObject(FFChassisOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; - #ifdef _WIN32 - if (ffStrEqualsIgnCase(key, "useWmi")) - { - options->useWmi = yyjson_get_bool(val); - continue; - } - #endif - ffPrintError(FF_CHASSIS_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -99,11 +83,6 @@ void ffGenerateChassisJsonConfig(FFChassisOptions* options, yyjson_mut_doc* doc, ffInitChassisOptions(&defaultOptions); ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); - - #ifdef _WIN32 - if (options->useWmi != defaultOptions.useWmi) - yyjson_mut_obj_add_bool(doc, module, "useWmi", options->useWmi); - #endif } void ffGenerateChassisJsonResult(FF_MAYBE_UNUSED FFChassisOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -113,7 +92,7 @@ void ffGenerateChassisJsonResult(FF_MAYBE_UNUSED FFChassisOptions* options, yyjs ffStrbufInit(&result.vendor); ffStrbufInit(&result.version); - const char* error = ffDetectChassis(&result, options); + const char* error = ffDetectChassis(&result); if (error) { @@ -161,10 +140,6 @@ void ffInitChassisOptions(FFChassisOptions* options) ffGenerateChassisJsonConfig ); ffOptionInitModuleArg(&options->moduleArgs); - - #ifdef _WIN32 - options->useWmi = false; - #endif } void ffDestroyChassisOptions(FFChassisOptions* options) diff --git a/src/modules/chassis/option.h b/src/modules/chassis/option.h index 25d7cee65..de6338cd5 100644 --- a/src/modules/chassis/option.h +++ b/src/modules/chassis/option.h @@ -8,8 +8,4 @@ typedef struct FFChassisOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; - - #ifdef _WIN32 - bool useWmi; - #endif } FFChassisOptions; diff --git a/src/modules/host/host.c b/src/modules/host/host.c index 18a146378..5590b5c38 100644 --- a/src/modules/host/host.c +++ b/src/modules/host/host.c @@ -17,7 +17,7 @@ void ffPrintHost(FFHostOptions* options) ffStrbufInit(&host.uuid); ffStrbufInit(&host.vendor); - const char* error = ffDetectHost(&host, options); + const char* error = ffDetectHost(&host); if(error) { ffPrintError(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, "%s", error); @@ -76,14 +76,6 @@ bool ffParseHostCommandOptions(FFHostOptions* options, const char* key, const ch if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; - #ifdef _WIN32 - if (ffStrEqualsIgnCase(subKey, "use-wmi")) - { - options->useWmi = ffOptionParseBoolean(value); - return true; - } - #endif - return false; } @@ -100,14 +92,6 @@ void ffParseHostJsonObject(FFHostOptions* options, yyjson_val* module) if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; - #ifdef _WIN32 - if (ffStrEqualsIgnCase(key, "useWmi")) - { - options->useWmi = yyjson_get_bool(val); - continue; - } - #endif - ffPrintError(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } } @@ -118,11 +102,6 @@ void ffGenerateHostJsonConfig(FFHostOptions* options, yyjson_mut_doc* doc, yyjso ffInitHostOptions(&defaultOptions); ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); - - #ifdef _WIN32 - if (options->useWmi != defaultOptions.useWmi) - yyjson_mut_obj_add_bool(doc, module, "useWmi", options->useWmi); - #endif } void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -136,7 +115,7 @@ void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut ffStrbufInit(&host.uuid); ffStrbufInit(&host.vendor); - const char* error = ffDetectHost(&host, options); + const char* error = ffDetectHost(&host); if (error) { yyjson_mut_obj_add_str(doc, module, "error", error); @@ -195,10 +174,6 @@ void ffInitHostOptions(FFHostOptions* options) ffGenerateHostJsonConfig ); ffOptionInitModuleArg(&options->moduleArgs); - - #ifdef _WIN32 - options->useWmi = false; - #endif } void ffDestroyHostOptions(FFHostOptions* options) diff --git a/src/modules/host/option.h b/src/modules/host/option.h index b305f2a92..1c6bf26f3 100644 --- a/src/modules/host/option.h +++ b/src/modules/host/option.h @@ -8,8 +8,4 @@ typedef struct FFHostOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; - - #ifdef _WIN32 - bool useWmi; - #endif } FFHostOptions; From 446fe907d2496dd9eb6d0954cc626873bbf1896c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 11:28:00 +0800 Subject: [PATCH 30/99] Smbios: add comments, tidy --- src/detection/chassis/chassis_windows.c | 37 ++++++++++------- src/detection/host/host_windows.c | 34 ++++++++++------ src/util/smbiosHelper.h | 54 ++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/detection/chassis/chassis_windows.c b/src/detection/chassis/chassis_windows.c index 707f4c3a9..5a3698928 100644 --- a/src/detection/chassis/chassis_windows.c +++ b/src/detection/chassis/chassis_windows.c @@ -4,18 +4,27 @@ // 7.4 typedef struct FFSmbiosSystemEnclosure { - uint8_t Manufacturer; - uint8_t Type; - uint8_t Version; - uint8_t SerialNumber; - uint8_t AssetTagNumber; - uint8_t BootupState; - uint8_t PowerSupplyState; - uint8_t ThermalState; - uint8_t SecurityStatus; - uint32_t OEMDefined; - uint8_t Height; - uint8_t NumberOfPowerCords; + FFSmbiosHeader Header; + + uint8_t Manufacturer; // string + uint8_t Type; // varies + uint8_t Version; // string + uint8_t SerialNumber; // string + uint8_t AssetTagNumber; // string + + // 2.1+ + uint8_t BootupState; // enum + uint8_t PowerSupplyState; // enum + uint8_t ThermalState; // enum + uint8_t SecurityStatus; // enum + + // 2.3+ + uint32_t OEMDefined; // varies + uint8_t Height; // varies + uint8_t NumberOfPowerCords; // varies + uint8_t ContainedElementCount; // varies + uint8_t ContainedRecordLength; // varies + uint8_t ContainedElements[]; // varies } FFSmbiosSystemEnclosure; const char* ffDetectChassis(FFChassisResult* result) @@ -24,14 +33,14 @@ const char* ffDetectChassis(FFChassisResult* result) for ( const FFSmbiosHeader* header = (const FFSmbiosHeader*) data->SMBIOSTableData; - (const uint8_t*) header < data->SMBIOSTableData + data->Length && header->Type < FF_SMBIOS_TYPE_LAST; + (const uint8_t*) header < data->SMBIOSTableData + data->Length && header->Type != FF_SMBIOS_TYPE_END_OF_TABLE; header = ffSmbiosSkipLastStr(header) ) { if (header->Type != FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE) continue; - const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) header->Data; + const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) header; const char* strings = (const char*) header + header->Length; ffStrbufSetStatic(&result->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.c index 6d382330d..26969173b 100644 --- a/src/detection/host/host_windows.c +++ b/src/detection/host/host_windows.c @@ -3,10 +3,14 @@ typedef struct FFSmbiosSystemInfo { - uint8_t Manufacturer; - uint8_t ProductName; - uint8_t Version; - uint8_t SerialNumber; + FFSmbiosHeader Header; + + uint8_t Manufacturer; // string + uint8_t ProductName; // string + uint8_t Version; // string + uint8_t SerialNumber; // string + + // 2.1+ struct { uint32_t TimeLow; uint16_t TimeMid; @@ -14,10 +18,12 @@ typedef struct FFSmbiosSystemInfo uint8_t ClockSeqHiAndReserved; uint8_t ClockSeqLow; uint8_t Node[6]; - } UUID; - uint8_t WakeUpType; - uint8_t SKUNumber; - uint8_t Family; + } UUID; // varies + uint8_t WakeUpType; // enum + + // 2.4+ + uint8_t SKUNumber; // string + uint8_t Family; // string } FFSmbiosSystemInfo; const char* ffDetectHost(FFHostResult* host) @@ -26,14 +32,14 @@ const char* ffDetectHost(FFHostResult* host) for ( const FFSmbiosHeader* header = (const FFSmbiosHeader*) fullData->SMBIOSTableData; - (const uint8_t*) header < fullData->SMBIOSTableData + fullData->Length && header->Type < FF_SMBIOS_TYPE_LAST; + (const uint8_t*) header < fullData->SMBIOSTableData + fullData->Length && header->Type != FF_SMBIOS_TYPE_END_OF_TABLE; header = ffSmbiosSkipLastStr(header) ) { if (header->Type != FF_SMBIOS_TYPE_SYSTEM_INFO) continue; - const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) header->Data; + const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) header; const char* strings = (const char*) header + header->Length; ffStrbufSetStatic(&host->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); @@ -45,15 +51,17 @@ const char* ffDetectHost(FFHostResult* host) ffStrbufSetStatic(&host->serial, ffSmbiosLocateString(strings, data->SerialNumber)); ffCleanUpSmbiosValue(&host->serial); - if (header->Length > 0x08) + static_assert(offsetof(FFSmbiosSystemInfo, UUID) == 0x08, "FFSmbiosSystemInfo.UUID offset is wrong"); + if (header->Length > offsetof(FFSmbiosSystemInfo, UUID)) { - // Order? ffStrbufSetF(&host->uuid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", data->UUID.TimeLow, data->UUID.TimeMid, data->UUID.TimeHighAndVersion, data->UUID.ClockSeqHiAndReserved, data->UUID.ClockSeqLow, data->UUID.Node[0], data->UUID.Node[1], data->UUID.Node[2], data->UUID.Node[3], data->UUID.Node[4], data->UUID.Node[5]); } - if (header->Length > 0x19) + + static_assert(offsetof(FFSmbiosSystemInfo, SKUNumber) == 0x19, "FFSmbiosSystemInfo.SKUNumber offset is wrong"); + if (header->Length > offsetof(FFSmbiosSystemInfo, SKUNumber)) { ffStrbufSetStatic(&host->family, ffSmbiosLocateString(strings, data->Family)); ffCleanUpSmbiosValue(&host->family); diff --git a/src/util/smbiosHelper.h b/src/util/smbiosHelper.h index bfb7c97af..c09655ab0 100644 --- a/src/util/smbiosHelper.h +++ b/src/util/smbiosHelper.h @@ -25,14 +25,51 @@ typedef enum __attribute__((__packed__)) FFSmbiosType // : uint8_t FF_SMBIOS_TYPE_BASEBOARD_INFO = 2, FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE = 3, FF_SMBIOS_TYPE_PROCESSOR_INFO = 4, - FF_SMBIOS_TYPE_MEMORY_MODULE_INFO = 6, + FF_SMBIOS_TYPE_MEMORY_CONTROLLER_INFO = 5, // obsolete + FF_SMBIOS_TYPE_MEMORY_MODULE_INFO = 6, // obsolete FF_SMBIOS_TYPE_CACHE_INFO = 7, + FF_SMBIOS_TYPE_PORT_CONNECTOR_INFO = 8, + FF_SMBIOS_TYPE_SYSTEM_SLOTS = 9, + FF_SMBIOS_TYPE_ON_BOARD_DEVICES_INFO = 10, // obsolete FF_SMBIOS_TYPE_OEM_STRING = 11, + FF_SMBIOS_TYPE_SYSTEM_CONFIGURATION_OPTIONS = 12, + FF_SMBIOS_TYPE_BIOS_LANGUAGE_INFO = 13, + FF_SMBIOS_TYPE_GROUP_ASSOCIATIONS = 14, + FF_SMBIOS_TYPE_SYSTEM_EVENT_LOG = 15, + FF_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY = 16, FF_SMBIOS_TYPE_MEMORY_DEVICE = 17, + FF_SMBIOS_TYPE_32BIT_MEMORY_ERROR_INFO = 18, FF_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS = 19, - FF_SMBIOS_TYPE_BUILTIN_POINT_DEVICE = 21, + FF_SMBIOS_TYPE_MEMORY_DEVICE_MAPPED_ADDRESS = 20, + FF_SMBIOS_TYPE_BUILTIN_POINTING_DEVICE = 21, FF_SMBIOS_TYPE_PORTABLE_BATTERY = 22, - FF_SMBIOS_TYPE_LAST = 127, + FF_SMBIOS_TYPE_SYSTEM_RESET = 23, + FF_SMBIOS_TYPE_HARDWARE_SECURITY = 24, + FF_SMBIOS_TYPE_SYSTEM_POWER_CONTROLS = 25, + FF_SMBIOS_TYPE_VOLTAGE_PROBE = 26, + FF_SMBIOS_TYPE_COOLING_DEVICE = 27, + FF_SMBIOS_TYPE_TEMPERATURE_PROBE = 28, + FF_SMBIOS_TYPE_ELECTRICAL_CURRENT_PROBE = 29, + FF_SMBIOS_TYPE_OUT_OF_BAND_REMOTE_ACCESS = 30, + FF_SMBIOS_TYPE_BOOT_INTEGRITY_SERVICES_ENTRY_POINT = 31, // reserved + FF_SMBIOS_TYPE_SYSTEM_BOOT_INFO = 32, + FF_SMBIOS_TYPE_64BIT_MEMORY_ERROR_INFO = 33, + FF_SMBIOS_TYPE_MANAGEMENT_DEVICE = 34, + FF_SMBIOS_TYPE_MANAGEMENT_DEVICE_COMPONENT = 35, + FF_SMBIOS_TYPE_MANAGEMENT_DEVICE_THRESHOLD_DATA = 36, + FF_SMBIOS_TYPE_MEMORY_CHANNEL = 37, + FF_SMBIOS_TYPE_IPMI_DEVICE_INFO = 38, + FF_SMBIOS_TYPE_SYSTEM_POWER_SUPPLY = 39, + FF_SMBIOS_TYPE_ADDITIONAL_INFO = 40, + FF_SMBIOS_TYPE_ONBOARD_DEVICE_EXTENDED_INFO = 41, + FF_SMBIOS_TYPE_MANAGEMENT_CONTROLLER_HOST_INTERFACE = 42, + FF_SMBIOS_TYPE_TPM_DEVICE = 43, + FF_SMBIOS_TYPE_PROCESSOR_ADDITIONAL_INFO = 44, + FF_SMBIOS_TYPE_FIRMWARE_INVENTORY_INFO = 45, + FF_SMBIOS_TYPE_STRING_PROPERTY = 46, + FF_SMBIOS_TYPE_INACTIVE = 126, + FF_SMBIOS_TYPE_END_OF_TABLE = 127, + // system- and OEM-specific information 128~256 } FFSmbiosType; static_assert(sizeof(FFSmbiosType) == 1, "FFSmbiosType should be 1 byte"); @@ -41,7 +78,6 @@ typedef struct FFSmbiosHeader FFSmbiosType Type; uint8_t Length; uint16_t Handle; - uint8_t Data[]; } FFSmbiosHeader; static_assert(sizeof(FFSmbiosHeader) == 4, "FFSmbiosHeader should be 4 bytes"); @@ -67,8 +103,14 @@ static inline const char* ffSmbiosLocateString(const char* start, uint8_t index static inline const FFSmbiosHeader* ffSmbiosSkipLastStr(const FFSmbiosHeader* header) { const char* p = ((const char*) header) + header->Length; - while (*p) - p += strlen(p) + 1; + if (*p) + { + do + p += strlen(p) + 1; + while (*p); + } + else // The terminator is always double 0 even if there is no string + p ++; return (const FFSmbiosHeader*) (p + 1); } From fe0b43d92dd6a5b581b7b26c0c33ce85b8df49ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 14:00:53 +0800 Subject: [PATCH 31/99] CPU (Windows): detect the actual maximum frequency --- src/detection/cpu/cpu_windows.c | 121 +++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 59f07ab7a..0be410064 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -2,8 +2,118 @@ #include "detection/temps/temps_windows.h" #include "util/windows/registry.h" #include "util/mallocHelper.h" +#include "util/smbiosHelper.h" -const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) +// 7.5 +typedef struct FFSmbiosProcessorInfo +{ + FFSmbiosHeader Header; + + uint8_t SocketDesignation; // string + uint8_t ProcessorType; // enum + uint8_t ProcessorFamily; // enum + uint8_t ProcessorManufacturer; // string + uint64_t ProcessorID; // varies + uint8_t ProcessorVersion; // string + uint8_t Voltage; // varies + uint16_t ExternalClock; // varies + uint16_t MaxSpeed; // varies + uint16_t CurrentSpeed; // varies + uint8_t Status; // varies + uint8_t ProcessorUpgrade; // enum + + // 2.1+ + uint16_t L1CacheHandle; // varies + uint16_t L2CacheHandle; // varies + uint16_t L3CacheHandle; // varies + + // 2.3+ + uint8_t SerialNumber; // string + uint8_t AssertTag; // string + uint8_t PartNumber; // string + + // 2.5+ + uint8_t CoreCount; // varies + uint8_t CoreEnabled; // varies + uint8_t ThreadCount; // varies + uint16_t ProcessorCharacteristics; // bit field + + // 2.6+ + uint16_t ProcessorFamily2; // enum + + // 3.0+ + uint16_t CoreCount2; // varies + uint16_t CoreEnabled2; // varies + uint16_t ThreadCount2; // varies + + // 3.6+ + uint16_t ThreadEnabled; // varies +} FFSmbiosProcessorInfo; + +static const char* detectBySmbios(FFCPUResult* cpu) +{ + const FFRawSmbiosData* data = ffGetSmbiosData(); + + for ( + const FFSmbiosHeader* header = (const FFSmbiosHeader*) data->SMBIOSTableData; + (const uint8_t*) header < data->SMBIOSTableData + data->Length && header->Type != FF_SMBIOS_TYPE_END_OF_TABLE; + header = ffSmbiosSkipLastStr(header) + ) + { + if (header->Type != FF_SMBIOS_TYPE_PROCESSOR_INFO) + continue; + + const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) header; + + if (data->ProcessorType != 0x03 /*Central Processor*/ || (data->Status & 0b00000111) != 1 /*Enabled*/) + continue; + + const char* strings = (const char*) header + header->Length; + + cpu->frequencyMax = (data->MaxSpeed > 0 ? data->MaxSpeed : data->CurrentSpeed) / 1000.0; + cpu->frequencyMin = data->ExternalClock / 1000.0; + ffStrbufSetStatic(&cpu->name, ffSmbiosLocateString(strings, data->ProcessorVersion)); + ffStrbufSetStatic(&cpu->vendor, ffSmbiosLocateString(strings, data->ProcessorManufacturer)); + + if (header->Length > offsetof(FFSmbiosProcessorInfo, CoreEnabled2)) + cpu->coresPhysical = data->CoreEnabled2; + else + cpu->coresPhysical = data->CoreEnabled; + + if (header->Length > offsetof(FFSmbiosProcessorInfo, ThreadEnabled)) + cpu->coresLogical = cpu->coresOnline = data->ThreadEnabled; + else + { + DWORD length = 0; + GetLogicalProcessorInformationEx(RelationGroup, NULL, &length); + if (length == 0) + return "GetLogicalProcessorInformationEx(RelationGroup, NULL, &length) failed"; + + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE + pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); + + if (pProcessorInfo && GetLogicalProcessorInformationEx(RelationGroup, pProcessorInfo, &length)) + { + for( + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo; + (uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length; + ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) + ) + { + assert(ptr->Relationship == RelationGroup); + cpu->coresOnline += ptr->Group.GroupInfo->ActiveProcessorCount; + cpu->coresLogical += ptr->Group.GroupInfo->MaximumProcessorCount; + } + } + } + + return NULL; + } + + return "System enclosure is not found in SMBIOS data"; +} + +static const char* detectByOS(FFCPUResult* cpu) { { DWORD length = 0; @@ -48,8 +158,15 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL); ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL); + return NULL; +} + +const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) +{ if(options->temp) ffDetectSmbiosTemp(&cpu->temperature, NULL); - return NULL; + if (detectBySmbios(cpu) == NULL) + return NULL; + return detectByOS(cpu); } From 1d3581125349a52e0bd67f9916601b72ae6e9f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 14:46:54 +0800 Subject: [PATCH 32/99] Windows: make SMBIOS data a singleton --- src/detection/chassis/chassis_windows.c | 31 +++---- src/detection/cpu/cpu_windows.c | 103 +++++++++++------------- src/detection/host/host_windows.c | 75 ++++++++--------- src/util/smbiosHelper.c | 41 +++++++++- src/util/smbiosHelper.h | 18 +---- 5 files changed, 133 insertions(+), 135 deletions(-) diff --git a/src/detection/chassis/chassis_windows.c b/src/detection/chassis/chassis_windows.c index 5a3698928..3279840c5 100644 --- a/src/detection/chassis/chassis_windows.c +++ b/src/detection/chassis/chassis_windows.c @@ -29,28 +29,17 @@ typedef struct FFSmbiosSystemEnclosure const char* ffDetectChassis(FFChassisResult* result) { - const FFRawSmbiosData* data = ffGetSmbiosData(); + const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE]; + if (!data) + return "System enclosure is not found in SMBIOS data"; - for ( - const FFSmbiosHeader* header = (const FFSmbiosHeader*) data->SMBIOSTableData; - (const uint8_t*) header < data->SMBIOSTableData + data->Length && header->Type != FF_SMBIOS_TYPE_END_OF_TABLE; - header = ffSmbiosSkipLastStr(header) - ) - { - if (header->Type != FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE) - continue; + const char* strings = (const char*) data + data->Header.Length; - const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) header; - const char* strings = (const char*) header + header->Length; + ffStrbufSetStatic(&result->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&result->vendor); + ffStrbufSetStatic(&result->version, ffSmbiosLocateString(strings, data->Version)); + ffCleanUpSmbiosValue(&result->version); + ffStrbufSetStatic(&result->type, ffChassisTypeToString(data->Type)); - ffStrbufSetStatic(&result->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); - ffCleanUpSmbiosValue(&result->vendor); - ffStrbufSetStatic(&result->version, ffSmbiosLocateString(strings, data->Version)); - ffCleanUpSmbiosValue(&result->version); - ffStrbufSetStatic(&result->type, ffChassisTypeToString(data->Type)); - - return NULL; - } - - return "System enclosure is not found in SMBIOS data"; + return NULL; } diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 0be410064..9551b8ece 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -52,65 +52,58 @@ typedef struct FFSmbiosProcessorInfo static const char* detectBySmbios(FFCPUResult* cpu) { - const FFRawSmbiosData* data = ffGetSmbiosData(); + const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PROCESSOR_INFO]; - for ( - const FFSmbiosHeader* header = (const FFSmbiosHeader*) data->SMBIOSTableData; - (const uint8_t*) header < data->SMBIOSTableData + data->Length && header->Type != FF_SMBIOS_TYPE_END_OF_TABLE; - header = ffSmbiosSkipLastStr(header) - ) + if (!data) + return "Processor information is not found in SMBIOS data"; + + while (data->ProcessorType != 0x03 /*Central Processor*/ || (data->Status & 0b00000111) != 1 /*Enabled*/) { - if (header->Type != FF_SMBIOS_TYPE_PROCESSOR_INFO) - continue; - - const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) header; - - if (data->ProcessorType != 0x03 /*Central Processor*/ || (data->Status & 0b00000111) != 1 /*Enabled*/) - continue; - - const char* strings = (const char*) header + header->Length; - - cpu->frequencyMax = (data->MaxSpeed > 0 ? data->MaxSpeed : data->CurrentSpeed) / 1000.0; - cpu->frequencyMin = data->ExternalClock / 1000.0; - ffStrbufSetStatic(&cpu->name, ffSmbiosLocateString(strings, data->ProcessorVersion)); - ffStrbufSetStatic(&cpu->vendor, ffSmbiosLocateString(strings, data->ProcessorManufacturer)); - - if (header->Length > offsetof(FFSmbiosProcessorInfo, CoreEnabled2)) - cpu->coresPhysical = data->CoreEnabled2; - else - cpu->coresPhysical = data->CoreEnabled; - - if (header->Length > offsetof(FFSmbiosProcessorInfo, ThreadEnabled)) - cpu->coresLogical = cpu->coresOnline = data->ThreadEnabled; - else - { - DWORD length = 0; - GetLogicalProcessorInformationEx(RelationGroup, NULL, &length); - if (length == 0) - return "GetLogicalProcessorInformationEx(RelationGroup, NULL, &length) failed"; - - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE - pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); - - if (pProcessorInfo && GetLogicalProcessorInformationEx(RelationGroup, pProcessorInfo, &length)) - { - for( - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo; - (uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length; - ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) - ) - { - assert(ptr->Relationship == RelationGroup); - cpu->coresOnline += ptr->Group.GroupInfo->ActiveProcessorCount; - cpu->coresLogical += ptr->Group.GroupInfo->MaximumProcessorCount; - } - } - } - - return NULL; + data = (const FFSmbiosProcessorInfo*) ffSmbiosNextEntry(&data->Header); + if (data->Header.Type != FF_SMBIOS_TYPE_PROCESSOR_INFO) + return "No active CPU is not found in SMBIOS data"; } - return "System enclosure is not found in SMBIOS data"; + const char* strings = (const char*) data + data->Header.Length; + + cpu->frequencyMax = (data->MaxSpeed > 0 ? data->MaxSpeed : data->CurrentSpeed) / 1000.0; + cpu->frequencyMin = data->ExternalClock / 1000.0; + ffStrbufSetStatic(&cpu->name, ffSmbiosLocateString(strings, data->ProcessorVersion)); + ffStrbufSetStatic(&cpu->vendor, ffSmbiosLocateString(strings, data->ProcessorManufacturer)); + + if (data->Header.Length > offsetof(FFSmbiosProcessorInfo, CoreEnabled2)) + cpu->coresPhysical = data->CoreEnabled2; + else + cpu->coresPhysical = data->CoreEnabled; + + if (data->Header.Length > offsetof(FFSmbiosProcessorInfo, ThreadEnabled)) + cpu->coresLogical = cpu->coresOnline = data->ThreadEnabled; + else + { + DWORD length = 0; + GetLogicalProcessorInformationEx(RelationGroup, NULL, &length); + if (length == 0) + return "GetLogicalProcessorInformationEx(RelationGroup, NULL, &length) failed"; + + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE + pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); + + if (pProcessorInfo && GetLogicalProcessorInformationEx(RelationGroup, pProcessorInfo, &length)) + { + for( + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo; + (uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length; + ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) + ) + { + assert(ptr->Relationship == RelationGroup); + cpu->coresOnline += ptr->Group.GroupInfo->ActiveProcessorCount; + cpu->coresLogical += ptr->Group.GroupInfo->MaximumProcessorCount; + } + } + } + + return NULL; } static const char* detectByOS(FFCPUResult* cpu) diff --git a/src/detection/host/host_windows.c b/src/detection/host/host_windows.c index 26969173b..8efe70a2f 100644 --- a/src/detection/host/host_windows.c +++ b/src/detection/host/host_windows.c @@ -28,49 +28,42 @@ typedef struct FFSmbiosSystemInfo const char* ffDetectHost(FFHostResult* host) { - const FFRawSmbiosData* fullData = ffGetSmbiosData(); + const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_SYSTEM_INFO]; + if (!data) + return "System information is not found in SMBIOS data"; - for ( - const FFSmbiosHeader* header = (const FFSmbiosHeader*) fullData->SMBIOSTableData; - (const uint8_t*) header < fullData->SMBIOSTableData + fullData->Length && header->Type != FF_SMBIOS_TYPE_END_OF_TABLE; - header = ffSmbiosSkipLastStr(header) - ) + const char* strings = (const char*) data + data->Header.Length; + + ffStrbufSetStatic(&host->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&host->vendor); + ffStrbufSetStatic(&host->name, ffSmbiosLocateString(strings, data->ProductName)); + ffCleanUpSmbiosValue(&host->name); + ffStrbufSetStatic(&host->version, ffSmbiosLocateString(strings, data->Version)); + ffCleanUpSmbiosValue(&host->version); + ffStrbufSetStatic(&host->serial, ffSmbiosLocateString(strings, data->SerialNumber)); + ffCleanUpSmbiosValue(&host->serial); + + static_assert(offsetof(FFSmbiosSystemInfo, UUID) == 0x08, "FFSmbiosSystemInfo.UUID offset is wrong"); + if (data->Header.Length > offsetof(FFSmbiosSystemInfo, UUID)) { - if (header->Type != FF_SMBIOS_TYPE_SYSTEM_INFO) - continue; - - const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) header; - const char* strings = (const char*) header + header->Length; - - ffStrbufSetStatic(&host->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); - ffCleanUpSmbiosValue(&host->vendor); - ffStrbufSetStatic(&host->name, ffSmbiosLocateString(strings, data->ProductName)); - ffCleanUpSmbiosValue(&host->name); - ffStrbufSetStatic(&host->version, ffSmbiosLocateString(strings, data->Version)); - ffCleanUpSmbiosValue(&host->version); - ffStrbufSetStatic(&host->serial, ffSmbiosLocateString(strings, data->SerialNumber)); - ffCleanUpSmbiosValue(&host->serial); - - static_assert(offsetof(FFSmbiosSystemInfo, UUID) == 0x08, "FFSmbiosSystemInfo.UUID offset is wrong"); - if (header->Length > offsetof(FFSmbiosSystemInfo, UUID)) - { - ffStrbufSetF(&host->uuid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - data->UUID.TimeLow, data->UUID.TimeMid, data->UUID.TimeHighAndVersion, - data->UUID.ClockSeqHiAndReserved, data->UUID.ClockSeqLow, - data->UUID.Node[0], data->UUID.Node[1], data->UUID.Node[2], data->UUID.Node[3], data->UUID.Node[4], data->UUID.Node[5]); - } - - static_assert(offsetof(FFSmbiosSystemInfo, SKUNumber) == 0x19, "FFSmbiosSystemInfo.SKUNumber offset is wrong"); - if (header->Length > offsetof(FFSmbiosSystemInfo, SKUNumber)) - { - ffStrbufSetStatic(&host->family, ffSmbiosLocateString(strings, data->Family)); - ffCleanUpSmbiosValue(&host->family); - ffStrbufSetStatic(&host->sku, ffSmbiosLocateString(strings, data->SKUNumber)); - ffCleanUpSmbiosValue(&host->sku); - } - - return NULL; + ffStrbufSetF(&host->uuid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + data->UUID.TimeLow, data->UUID.TimeMid, data->UUID.TimeHighAndVersion, + data->UUID.ClockSeqHiAndReserved, data->UUID.ClockSeqLow, + data->UUID.Node[0], data->UUID.Node[1], data->UUID.Node[2], data->UUID.Node[3], data->UUID.Node[4], data->UUID.Node[5]); } - return "System information is not found in SMBIOS data"; + static_assert(offsetof(FFSmbiosSystemInfo, SKUNumber) == 0x19, "FFSmbiosSystemInfo.SKUNumber offset is wrong"); + if (data->Header.Length > offsetof(FFSmbiosSystemInfo, SKUNumber)) + { + ffStrbufSetStatic(&host->sku, ffSmbiosLocateString(strings, data->SKUNumber)); + ffCleanUpSmbiosValue(&host->sku); + } + + if (data->Header.Length > offsetof(FFSmbiosSystemInfo, Family)) + { + ffStrbufSetStatic(&host->family, ffSmbiosLocateString(strings, data->Family)); + ffCleanUpSmbiosValue(&host->family); + } + + return NULL; } diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 718d56cfc..5118f6339 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -52,17 +52,52 @@ void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* #pragma GCC diagnostic ignored "-Wmultichar" -const FFRawSmbiosData* ffGetSmbiosData() +const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header) +{ + const char* p = ((const char*) header) + header->Length; + if (*p) + { + do + p += strlen(p) + 1; + while (*p); + } + else // The terminator is always double 0 even if there is no string + p ++; + + return (const FFSmbiosHeader*) (p + 1); +} + +const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() { static FFRawSmbiosData* buffer; + static FFSmbiosHeaderTable table; + if (!buffer) { const DWORD signature = 'RSMB'; uint32_t bufSize = GetSystemFirmwareTable(signature, 0, NULL, 0); assert(bufSize > sizeof(FFRawSmbiosData)); buffer = (FFRawSmbiosData*) malloc(bufSize); - GetSystemFirmwareTable(signature, 0, buffer, bufSize); + assert(buffer); + uint32_t resSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize); + assert(resSize == bufSize); + + for ( + const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer->SMBIOSTableData; + (const uint8_t*) header < buffer->SMBIOSTableData + buffer->Length; + header = ffSmbiosNextEntry(header) + ) + { + if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE) + { + if (!table[header->Type]) + table[header->Type] = header; + } + else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) + break; + } } - return buffer; + + return &table; } #endif diff --git a/src/util/smbiosHelper.h b/src/util/smbiosHelper.h index c09655ab0..e59211889 100644 --- a/src/util/smbiosHelper.h +++ b/src/util/smbiosHelper.h @@ -100,22 +100,10 @@ static inline const char* ffSmbiosLocateString(const char* start, uint8_t index return start; } -static inline const FFSmbiosHeader* ffSmbiosSkipLastStr(const FFSmbiosHeader* header) -{ - const char* p = ((const char*) header) + header->Length; - if (*p) - { - do - p += strlen(p) + 1; - while (*p); - } - else // The terminator is always double 0 even if there is no string - p ++; +typedef const FFSmbiosHeader* FFSmbiosHeaderTable[FF_SMBIOS_TYPE_END_OF_TABLE]; - return (const FFSmbiosHeader*) (p + 1); -} - -const FFRawSmbiosData* ffGetSmbiosData(); +const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header); +const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable(); #endif #endif From c1c7f7b93ffaf0845ff5eb4f705f32fb5b8451ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 15:59:53 +0800 Subject: [PATCH 33/99] Bios (Windows): use SMBIOS result --- src/detection/bios/bios_windows.c | 46 +++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/detection/bios/bios_windows.c b/src/detection/bios/bios_windows.c index 5adfbdd0d..23ff25275 100644 --- a/src/detection/bios/bios_windows.c +++ b/src/detection/bios/bios_windows.c @@ -1,5 +1,4 @@ #include "bios.h" -#include "util/windows/registry.h" #include "util/smbiosHelper.h" #include @@ -26,27 +25,46 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION }; } SYSTEM_BOOT_ENVIRONMENT_INFORMATION; + +typedef struct FFSmbiosBios +{ + FFSmbiosHeader Header; + + uint8_t Vendor; // string + uint8_t BiosVersion; // string + uint16_t BiosStartingAddressSegment; // varies + uint8_t BiosReleaseDate; // string + uint8_t BiosRomSize; // string + uint32_t BiosCharacteristics; // bit field + + // 2.4+ + uint8_t BiosCharacteristicsExtensionBytes[2]; // bit field + uint8_t SystemBiosMajorRelease; // varies + uint8_t SystemBiosMinorRelease; // varies + uint8_t EmbeddedControllerFirmwareMajorRelease; // varies + uint8_t EmbeddedControllerFirmwareMinorRelease; // varies + + // 3.1+ + uint16_t ExtendedBiosRomSize; // bit field +} FFSmbiosBios; + const char* ffDetectBios(FFBiosResult* bios) { - FF_HKEY_AUTO_DESTROY hKey = NULL; - if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL)) - return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed"; + const FFSmbiosBios* data = (const FFSmbiosBios*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_BIOS]; + if (!data) + return "BIOS section is not found in SMBIOS data"; - if(!ffRegReadStrbuf(hKey, L"BIOSVersion", &bios->version, NULL)) - return "\"HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\BIOSVersion\" doesn't exist"; + const char* strings = (const char*) data + data->Header.Length; + ffStrbufSetStatic(&bios->version, ffSmbiosLocateString(strings, data->BiosVersion)); ffCleanUpSmbiosValue(&bios->version); - ffRegReadStrbuf(hKey, L"BIOSVendor", &bios->vendor, NULL); + ffStrbufSetStatic(&bios->vendor, ffSmbiosLocateString(strings, data->Vendor)); ffCleanUpSmbiosValue(&bios->vendor); - ffRegReadStrbuf(hKey, L"BIOSReleaseDate", &bios->date, NULL); + ffStrbufSetStatic(&bios->date, ffSmbiosLocateString(strings, data->BiosReleaseDate)); ffCleanUpSmbiosValue(&bios->date); - uint32_t major, minor; - if( - ffRegReadUint(hKey, L"BiosMajorRelease", &major, NULL) && - ffRegReadUint(hKey, L"BiosMinorRelease", &minor, NULL) - ) - ffStrbufAppendF(&bios->release, "%u.%u", (unsigned)major, (unsigned)minor); + if (data->Header.Length > offsetof(FFSmbiosBios, SystemBiosMajorRelease)) + ffStrbufSetF(&bios->release, "%u.%u", data->SystemBiosMajorRelease, data->SystemBiosMinorRelease); // Same as GetFirmwareType, but support (?) Windows 7 // https://ntdoc.m417z.com/system_information_class From 48bb82c8fba9e8fe52bc82b807d98559f3cda5f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 16:08:49 +0800 Subject: [PATCH 34/99] Board (Windows): use SMBIOS result --- src/detection/board/board_windows.c | 33 +++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/detection/board/board_windows.c b/src/detection/board/board_windows.c index a2bfce4ff..612064950 100644 --- a/src/detection/board/board_windows.c +++ b/src/detection/board/board_windows.c @@ -1,21 +1,36 @@ #include "board.h" -#include "util/windows/registry.h" #include "util/smbiosHelper.h" +typedef struct FFSmbiosBaseboard +{ + FFSmbiosHeader Header; + + uint8_t Manufacturer; // string + uint8_t Product; // string + uint8_t Version; // string + uint8_t SerialNumber; // string + uint8_t AssetTag; // string + uint8_t FeatureFlags; // bit field + uint8_t LocationInChassis; // string + uint16_t ChassisHandle; // varies + uint8_t BoardType; // enum + uint8_t NumberOfContainedObjectHandle; // varies + uint16_t ContainedObjectHandle[]; // varies +} FFSmbiosBaseboard; + const char* ffDetectBoard(FFBoardResult* board) { - FF_HKEY_AUTO_DESTROY hKey = NULL; + const FFSmbiosBaseboard* data = (const FFSmbiosBaseboard*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_BASEBOARD_INFO]; + if (!data) + return "Baseboard information section is not found in SMBIOS data"; - if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL)) - return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\") failed"; - - if(!ffRegReadStrbuf(hKey, L"BaseBoardProduct", &board->name, NULL)) - return "ffRegReadStrbuf(hKey, L\"BaseBoardProduct\") failed"; + const char* strings = (const char*) data + data->Header.Length; + ffStrbufSetStatic(&board->name, ffSmbiosLocateString(strings, data->Product)); ffCleanUpSmbiosValue(&board->name); - ffRegReadStrbuf(hKey, L"BaseBoardManufacturer", &board->vendor, NULL); + ffStrbufSetStatic(&board->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); ffCleanUpSmbiosValue(&board->vendor); - ffRegReadStrbuf(hKey, L"BaseBoardVersion", &board->version, NULL); + ffStrbufSetStatic(&board->version, ffSmbiosLocateString(strings, data->Version)); ffCleanUpSmbiosValue(&board->version); return NULL; From d8297d296e8e15071605814a76b5265b9c69a4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 16:20:07 +0800 Subject: [PATCH 35/99] CPU (Windows): use ThreadCount if GetLogicalProcessorInformationEx() fails --- src/detection/cpu/cpu_windows.c | 37 ++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 9551b8ece..be4eb7d61 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -82,25 +82,32 @@ static const char* detectBySmbios(FFCPUResult* cpu) { DWORD length = 0; GetLogicalProcessorInformationEx(RelationGroup, NULL, &length); - if (length == 0) - return "GetLogicalProcessorInformationEx(RelationGroup, NULL, &length) failed"; - - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE - pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); - - if (pProcessorInfo && GetLogicalProcessorInformationEx(RelationGroup, pProcessorInfo, &length)) + if (length > 0) { - for( - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo; - (uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length; - ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) - ) + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE + pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); + + if (pProcessorInfo && GetLogicalProcessorInformationEx(RelationGroup, pProcessorInfo, &length)) { - assert(ptr->Relationship == RelationGroup); - cpu->coresOnline += ptr->Group.GroupInfo->ActiveProcessorCount; - cpu->coresLogical += ptr->Group.GroupInfo->MaximumProcessorCount; + for( + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo; + (uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length; + ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) + ) + { + assert(ptr->Relationship == RelationGroup); + cpu->coresOnline += ptr->Group.GroupInfo->ActiveProcessorCount; + cpu->coresLogical += ptr->Group.GroupInfo->MaximumProcessorCount; + } } } + if (cpu->coresOnline == 0 || cpu->coresLogical == 0) + { + if (data->Header.Length > offsetof(FFSmbiosProcessorInfo, ThreadCount2)) + cpu->coresOnline = cpu->coresLogical = data->ThreadCount2; + else + cpu->coresOnline = cpu->coresLogical = data->ThreadCount; + } } return NULL; From 1621484c96905335ca29c9395e7c86a6ce4d97b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 16:44:12 +0800 Subject: [PATCH 36/99] CPU (Windows): don't report 30GHz in VMware --- src/detection/cpu/cpu_windows.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index be4eb7d61..51a9a7213 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -66,7 +66,10 @@ static const char* detectBySmbios(FFCPUResult* cpu) const char* strings = (const char*) data + data->Header.Length; - cpu->frequencyMax = (data->MaxSpeed > 0 ? data->MaxSpeed : data->CurrentSpeed) / 1000.0; + if (data->MaxSpeed > 0 && data->MaxSpeed < 30000) // VMware reports weird values + cpu->frequencyMax = data->MaxSpeed / 1000.0; + else + cpu->frequencyMax = data->CurrentSpeed / 1000.0; cpu->frequencyMin = data->ExternalClock / 1000.0; ffStrbufSetStatic(&cpu->name, ffSmbiosLocateString(strings, data->ProcessorVersion)); ffStrbufSetStatic(&cpu->vendor, ffSmbiosLocateString(strings, data->ProcessorManufacturer)); From de91429e1a3001dc6227f97fdaee7c6b836830c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 17:07:36 +0800 Subject: [PATCH 37/99] CI: fix build --- src/detection/host/host_apple.c | 2 +- src/modules/host/host.c | 2 +- src/util/smbiosHelper.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 98910e5e8..402c2f07e 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -177,7 +177,7 @@ const char* getProductNameWithIokit(FFstrbuf* result) if (!productName) return "IORegistryEntryCreateCFProperty() failed"; - return ffCfStrGetString(name, result); + return ffCfStrGetString(productName, result); } const char* getOthersByIokit(FFHostResult* host) diff --git a/src/modules/host/host.c b/src/modules/host/host.c index 5590b5c38..08f11c8e7 100644 --- a/src/modules/host/host.c +++ b/src/modules/host/host.c @@ -133,7 +133,7 @@ void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut yyjson_mut_obj_add_strbuf(doc, obj, "name", &host.name); yyjson_mut_obj_add_strbuf(doc, obj, "version", &host.version); yyjson_mut_obj_add_strbuf(doc, obj, "sku", &host.sku); - yyjson_mut_obj_add_strbuf(doc, obj, "vender", &host.vendor); + yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &host.vendor); yyjson_mut_obj_add_strbuf(doc, obj, "serial", &host.serial); yyjson_mut_obj_add_strbuf(doc, obj, "uuid", &host.uuid); diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 5118f6339..191750fef 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -79,8 +79,8 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() assert(bufSize > sizeof(FFRawSmbiosData)); buffer = (FFRawSmbiosData*) malloc(bufSize); assert(buffer); - uint32_t resSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize); - assert(resSize == bufSize); + uint32_t resultSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize); + assert(resultSize == bufSize); for ( const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer->SMBIOSTableData; From 640fa146c17bef226dbd0a423be0d75f0d5ab2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 18:00:59 +0800 Subject: [PATCH 38/99] CPU (Windows): only use smbios to detect maximum speed Because some virtual machines report invalid information --- src/detection/cpu/cpu_windows.c | 65 +++++++-------------------------- 1 file changed, 14 insertions(+), 51 deletions(-) diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 51a9a7213..1bb169d74 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -50,7 +50,7 @@ typedef struct FFSmbiosProcessorInfo uint16_t ThreadEnabled; // varies } FFSmbiosProcessorInfo; -static const char* detectBySmbios(FFCPUResult* cpu) +static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu) { const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PROCESSOR_INFO]; @@ -61,57 +61,17 @@ static const char* detectBySmbios(FFCPUResult* cpu) { data = (const FFSmbiosProcessorInfo*) ffSmbiosNextEntry(&data->Header); if (data->Header.Type != FF_SMBIOS_TYPE_PROCESSOR_INFO) - return "No active CPU is not found in SMBIOS data"; + return "No active CPU is found in SMBIOS data"; } - const char* strings = (const char*) data + data->Header.Length; - + double speed; if (data->MaxSpeed > 0 && data->MaxSpeed < 30000) // VMware reports weird values - cpu->frequencyMax = data->MaxSpeed / 1000.0; + speed = data->MaxSpeed / 1000.0; else - cpu->frequencyMax = data->CurrentSpeed / 1000.0; - cpu->frequencyMin = data->ExternalClock / 1000.0; - ffStrbufSetStatic(&cpu->name, ffSmbiosLocateString(strings, data->ProcessorVersion)); - ffStrbufSetStatic(&cpu->vendor, ffSmbiosLocateString(strings, data->ProcessorManufacturer)); + speed = data->CurrentSpeed / 1000.0; - if (data->Header.Length > offsetof(FFSmbiosProcessorInfo, CoreEnabled2)) - cpu->coresPhysical = data->CoreEnabled2; - else - cpu->coresPhysical = data->CoreEnabled; - - if (data->Header.Length > offsetof(FFSmbiosProcessorInfo, ThreadEnabled)) - cpu->coresLogical = cpu->coresOnline = data->ThreadEnabled; - else - { - DWORD length = 0; - GetLogicalProcessorInformationEx(RelationGroup, NULL, &length); - if (length > 0) - { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE - pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); - - if (pProcessorInfo && GetLogicalProcessorInformationEx(RelationGroup, pProcessorInfo, &length)) - { - for( - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr = pProcessorInfo; - (uint8_t*)ptr < ((uint8_t*)pProcessorInfo) + length; - ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) - ) - { - assert(ptr->Relationship == RelationGroup); - cpu->coresOnline += ptr->Group.GroupInfo->ActiveProcessorCount; - cpu->coresLogical += ptr->Group.GroupInfo->MaximumProcessorCount; - } - } - } - if (cpu->coresOnline == 0 || cpu->coresLogical == 0) - { - if (data->Header.Length > offsetof(FFSmbiosProcessorInfo, ThreadCount2)) - cpu->coresOnline = cpu->coresLogical = data->ThreadCount2; - else - cpu->coresOnline = cpu->coresLogical = data->ThreadCount; - } - } + if (cpu->frequencyMax < speed) + cpu->frequencyMax = speed; return NULL; } @@ -155,7 +115,7 @@ static const char* detectByOS(FFCPUResult* cpu) { uint32_t mhz; if(ffRegReadUint(hKey, L"~MHz", &mhz, NULL)) - cpu->frequencyMax = mhz / 1000.0; + cpu->frequencyMin = cpu->frequencyMax = mhz / 1000.0; } ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL); @@ -166,10 +126,13 @@ static const char* detectByOS(FFCPUResult* cpu) const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) { + const char* error = detectByOS(cpu); + if (error) + return error; + if(options->temp) ffDetectSmbiosTemp(&cpu->temperature, NULL); - if (detectBySmbios(cpu) == NULL) - return NULL; - return detectByOS(cpu); + detectMaxSpeedBySmbios(cpu); + return NULL; } From c0c32456e857da75efc8d72bd2f3c25f661e8f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 18:12:51 +0800 Subject: [PATCH 39/99] Board: detect serial number --- src/detection/board/board.h | 1 + src/detection/board/board_bsd.c | 2 ++ src/detection/board/board_linux.c | 1 + src/detection/board/board_windows.c | 2 ++ src/modules/board/board.c | 11 +++++++++-- src/util/smbiosHelper.c | 1 + 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/detection/board/board.h b/src/detection/board/board.h index 44ba5c8ab..64a8dd3a7 100644 --- a/src/detection/board/board.h +++ b/src/detection/board/board.h @@ -7,6 +7,7 @@ typedef struct FFBoardResult FFstrbuf name; FFstrbuf vendor; FFstrbuf version; + FFstrbuf serial; } FFBoardResult; const char* ffDetectBoard(FFBoardResult* board); diff --git a/src/detection/board/board_bsd.c b/src/detection/board/board_bsd.c index 871cf87aa..3fc5f9637 100644 --- a/src/detection/board/board_bsd.c +++ b/src/detection/board/board_bsd.c @@ -6,6 +6,8 @@ const char* ffDetectBoard(FFBoardResult* result) { ffSettingsGetFreeBSDKenv("smbios.planar.product", &result->name); ffCleanUpSmbiosValue(&result->name); + ffSettingsGetFreeBSDKenv("smbios.planar.serial", &result->serial); + ffCleanUpSmbiosValue(&result->serial); ffSettingsGetFreeBSDKenv("smbios.planar.maker", &result->vendor); ffCleanUpSmbiosValue(&result->vendor); ffSettingsGetFreeBSDKenv("smbios.planar.version", &result->version); diff --git a/src/detection/board/board_linux.c b/src/detection/board/board_linux.c index 1092b54ee..380db6c14 100644 --- a/src/detection/board/board_linux.c +++ b/src/detection/board/board_linux.c @@ -7,6 +7,7 @@ const char* ffDetectBoard(FFBoardResult* board) { ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_serial", "/sys/class/dmi/id/board_serial", &board->serial); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_vendor", "/sys/class/dmi/id/board_vendor", &board->vendor); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_version", "/sys/class/dmi/id/board_version", &board->version); return NULL; diff --git a/src/detection/board/board_windows.c b/src/detection/board/board_windows.c index 612064950..d16d4a905 100644 --- a/src/detection/board/board_windows.c +++ b/src/detection/board/board_windows.c @@ -28,6 +28,8 @@ const char* ffDetectBoard(FFBoardResult* board) ffStrbufSetStatic(&board->name, ffSmbiosLocateString(strings, data->Product)); ffCleanUpSmbiosValue(&board->name); + ffStrbufSetStatic(&board->serial, ffSmbiosLocateString(strings, data->SerialNumber)); + ffCleanUpSmbiosValue(&board->serial); ffStrbufSetStatic(&board->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); ffCleanUpSmbiosValue(&board->vendor); ffStrbufSetStatic(&board->version, ffSmbiosLocateString(strings, data->Version)); diff --git a/src/modules/board/board.c b/src/modules/board/board.c index 0cb3bcfaa..81a663609 100644 --- a/src/modules/board/board.c +++ b/src/modules/board/board.c @@ -12,8 +12,9 @@ void ffPrintBoard(FFBoardOptions* options) ffStrbufInit(&result.name); ffStrbufInit(&result.vendor); ffStrbufInit(&result.version); - const char* error = ffDetectBoard(&result); + ffStrbufInit(&result.serial); + const char* error = ffDetectBoard(&result); if(error) { ffPrintError(FF_BOARD_MODULE_NAME, 0, &options->moduleArgs, "%s", error); @@ -40,6 +41,7 @@ void ffPrintBoard(FFBoardOptions* options) {FF_FORMAT_ARG_TYPE_STRBUF, &result.name}, {FF_FORMAT_ARG_TYPE_STRBUF, &result.vendor}, {FF_FORMAT_ARG_TYPE_STRBUF, &result.version}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result.serial}, }); } @@ -47,6 +49,7 @@ exit: ffStrbufDestroy(&result.name); ffStrbufDestroy(&result.vendor); ffStrbufDestroy(&result.version); + ffStrbufDestroy(&result.serial); } bool ffParseBoardCommandOptions(FFBoardOptions* options, const char* key, const char* value) @@ -90,6 +93,7 @@ void ffGenerateBoardJsonResult(FF_MAYBE_UNUSED FFBoardOptions* options, yyjson_m ffStrbufInit(&board.name); ffStrbufInit(&board.vendor); ffStrbufInit(&board.version); + ffStrbufInit(&board.serial); const char* error = ffDetectBoard(&board); @@ -109,11 +113,13 @@ void ffGenerateBoardJsonResult(FF_MAYBE_UNUSED FFBoardOptions* options, yyjson_m yyjson_mut_obj_add_strbuf(doc, obj, "name", &board.name); yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &board.vendor); yyjson_mut_obj_add_strbuf(doc, obj, "version", &board.version); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &board.serial); exit: ffStrbufDestroy(&board.name); ffStrbufDestroy(&board.vendor); ffStrbufDestroy(&board.version); + ffStrbufDestroy(&board.serial); } void ffPrintBoardHelpFormat(void) @@ -121,7 +127,8 @@ void ffPrintBoardHelpFormat(void) ffPrintModuleFormatHelp(FF_BOARD_MODULE_NAME, "{1} ({3})", FF_BOARD_NUM_FORMAT_ARGS, (const char* []) { "board name", "board vendor", - "board version" + "board version", + "board serial number", }); } diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 191750fef..6d505b49d 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -23,6 +23,7 @@ bool ffIsSmbiosValueSet(FFstrbuf* value) !ffStrbufIgnCaseEqualS(value, "Not Available") && !ffStrbufIgnCaseEqualS(value, "INVALID") && !ffStrbufIgnCaseEqualS(value, "Type1ProductConfigId") && + !ffStrbufIgnCaseEqualS(value, "No Enclosure") && !ffStrbufIgnCaseEqualS(value, "All Series") && !ffStrbufIgnCaseEqualS(value, "N/A") ; From 8801921d02a745fb38a3a46cf21d8aa6f143ea00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 18:33:57 +0800 Subject: [PATCH 40/99] Smbios: trim spaces --- src/util/FFstrbuf.c | 24 ++++++++++++++++-------- src/util/smbiosHelper.c | 1 + tests/strbuf.c | 9 +++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index 3637c6c44..d3c8bb8ec 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -249,13 +249,17 @@ void ffStrbufTrimLeft(FFstrbuf* strbuf, char c) void ffStrbufTrimRight(FFstrbuf* strbuf, char c) { - if(strbuf->length == 0) + if (strbuf->length == 0) return; - while(ffStrbufEndsWithC(strbuf, c)) - --strbuf->length; + if (!ffStrbufEndsWithC(strbuf, c)) + return; - if(strbuf->allocated == 0) + do + --strbuf->length; + while (ffStrbufEndsWithC(strbuf, c)); + + if (strbuf->allocated == 0) { //static string ffStrbufInitNS(strbuf, strbuf->length, strbuf->chars); @@ -267,13 +271,17 @@ void ffStrbufTrimRight(FFstrbuf* strbuf, char c) void ffStrbufTrimRightSpace(FFstrbuf* strbuf) { - if(strbuf->length == 0) + if (strbuf->length == 0) return; - while(ffStrbufEndsWithFn(strbuf, isspace)) - --strbuf->length; + if (!ffStrbufEndsWithFn(strbuf, isspace)) + return; - if(strbuf->allocated == 0) + do + --strbuf->length; + while (ffStrbufEndsWithFn(strbuf, isspace)); + + if (strbuf->allocated == 0) { //static string ffStrbufInitNS(strbuf, strbuf->length, strbuf->chars); diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 6d505b49d..4ba518079 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -3,6 +3,7 @@ bool ffIsSmbiosValueSet(FFstrbuf* value) { + ffStrbufTrimRightSpace(value); return value->length > 0 && !ffStrbufStartsWithIgnCaseS(value, "To be filled") && diff --git a/tests/strbuf.c b/tests/strbuf.c index e27bc6c2e..0a35012d2 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -181,6 +181,12 @@ int main(void) ffStrbufEnsureEndsWithC(&strbuf, '$'); VERIFY(ffStrbufEqualS(&strbuf, "AbCdEfG$")); + //trimRight + ffStrbufTrimRight(&strbuf, '$'); + VERIFY(ffStrbufEqualS(&strbuf, "AbCdEfG")); + ffStrbufTrimRight(&strbuf, '$'); + VERIFY(ffStrbufEqualS(&strbuf, "AbCdEfG")); + //clear ffStrbufClear(&strbuf); VERIFY(strbuf.allocated > 0); @@ -296,6 +302,9 @@ int main(void) //ffStrbufCreateStatic / TrimR ffStrbufInitStatic(&strbuf, "_TEST_"); + ffStrbufTrimRight(&strbuf, ' '); + VERIFY(strbuf.allocated == 0); + VERIFY(ffStrbufEqualS(&strbuf, "_TEST_")); ffStrbufTrimRight(&strbuf, '_'); VERIFY(ffStrbufEqualS(&strbuf, "_TEST")); VERIFY(strbuf.length == 5); From b9777bec77e92d05d7f74f8d6346bb8c4f5fc874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 18:35:10 +0800 Subject: [PATCH 41/99] Chassis: detect serial number --- src/detection/chassis/chassis.h | 1 + src/detection/chassis/chassis_bsd.c | 2 ++ src/detection/chassis/chassis_linux.c | 1 + src/detection/chassis/chassis_windows.c | 2 ++ src/modules/chassis/chassis.c | 9 ++++++++- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/detection/chassis/chassis.h b/src/detection/chassis/chassis.h index 6990a09e4..0c9c0380d 100644 --- a/src/detection/chassis/chassis.h +++ b/src/detection/chassis/chassis.h @@ -5,6 +5,7 @@ typedef struct FFChassisResult { FFstrbuf type; + FFstrbuf serial; FFstrbuf vendor; FFstrbuf version; } FFChassisResult; diff --git a/src/detection/chassis/chassis_bsd.c b/src/detection/chassis/chassis_bsd.c index c38b562c2..816a5dcad 100644 --- a/src/detection/chassis/chassis_bsd.c +++ b/src/detection/chassis/chassis_bsd.c @@ -9,6 +9,8 @@ const char* ffDetectChassis(FFChassisResult* result) ffCleanUpSmbiosValue(&result->type); ffSettingsGetFreeBSDKenv("smbios.chassis.maker", &result->vendor); ffCleanUpSmbiosValue(&result->vendor); + ffSettingsGetFreeBSDKenv("smbios.chassis.serial", &result->serial); + ffCleanUpSmbiosValue(&result->serial); ffSettingsGetFreeBSDKenv("smbios.chassis.version", &result->version); ffCleanUpSmbiosValue(&result->version); return NULL; diff --git a/src/detection/chassis/chassis_linux.c b/src/detection/chassis/chassis_linux.c index 9390169cf..8968a2093 100644 --- a/src/detection/chassis/chassis_linux.c +++ b/src/detection/chassis/chassis_linux.c @@ -7,6 +7,7 @@ const char* ffDetectChassis(FFChassisResult* result) { ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type); + ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_serial", "/sys/class/dmi/id/chassis_serial", &result->serial); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version); diff --git a/src/detection/chassis/chassis_windows.c b/src/detection/chassis/chassis_windows.c index 3279840c5..754b85a3d 100644 --- a/src/detection/chassis/chassis_windows.c +++ b/src/detection/chassis/chassis_windows.c @@ -37,6 +37,8 @@ const char* ffDetectChassis(FFChassisResult* result) ffStrbufSetStatic(&result->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); ffCleanUpSmbiosValue(&result->vendor); + ffStrbufSetStatic(&result->serial, ffSmbiosLocateString(strings, data->SerialNumber)); + ffCleanUpSmbiosValue(&result->serial); ffStrbufSetStatic(&result->version, ffSmbiosLocateString(strings, data->Version)); ffCleanUpSmbiosValue(&result->version); ffStrbufSetStatic(&result->type, ffChassisTypeToString(data->Type)); diff --git a/src/modules/chassis/chassis.c b/src/modules/chassis/chassis.c index 1cb414f58..4966053a1 100644 --- a/src/modules/chassis/chassis.c +++ b/src/modules/chassis/chassis.c @@ -12,6 +12,7 @@ void ffPrintChassis(FFChassisOptions* options) ffStrbufInit(&result.type); ffStrbufInit(&result.vendor); ffStrbufInit(&result.version); + ffStrbufInit(&result.serial); const char* error = ffDetectChassis(&result); @@ -41,6 +42,7 @@ void ffPrintChassis(FFChassisOptions* options) {FF_FORMAT_ARG_TYPE_STRBUF, &result.type}, {FF_FORMAT_ARG_TYPE_STRBUF, &result.vendor}, {FF_FORMAT_ARG_TYPE_STRBUF, &result.version}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result.serial}, }); } @@ -48,6 +50,7 @@ exit: ffStrbufDestroy(&result.type); ffStrbufDestroy(&result.vendor); ffStrbufDestroy(&result.version); + ffStrbufDestroy(&result.serial); } bool ffParseChassisCommandOptions(FFChassisOptions* options, const char* key, const char* value) @@ -91,6 +94,7 @@ void ffGenerateChassisJsonResult(FF_MAYBE_UNUSED FFChassisOptions* options, yyjs ffStrbufInit(&result.type); ffStrbufInit(&result.vendor); ffStrbufInit(&result.version); + ffStrbufInit(&result.serial); const char* error = ffDetectChassis(&result); @@ -110,11 +114,13 @@ void ffGenerateChassisJsonResult(FF_MAYBE_UNUSED FFChassisOptions* options, yyjs yyjson_mut_obj_add_strbuf(doc, obj, "type", &result.type); yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &result.vendor); yyjson_mut_obj_add_strbuf(doc, obj, "version", &result.version); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &result.serial); exit: ffStrbufDestroy(&result.type); ffStrbufDestroy(&result.vendor); ffStrbufDestroy(&result.version); + ffStrbufDestroy(&result.serial); } void ffPrintChassisHelpFormat(void) @@ -122,7 +128,8 @@ void ffPrintChassisHelpFormat(void) ffPrintModuleFormatHelp(FF_CHASSIS_MODULE_NAME, "{1}", FF_CHASSIS_NUM_FORMAT_ARGS, (const char* []) { "chassis type", "chassis vendor", - "chassis version" + "chassis version", + "chassis serial number", }); } From 0af40ab6a3da282497bd374c006eba79b1b8ef72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 18:45:02 +0800 Subject: [PATCH 42/99] Settings (FreeBSD): don't append trailing `\0` --- CHANGELOG.md | 1 + src/common/settings.c | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a1153a63..175bfc791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Features: Bugfixes: * Fix support of macOS Sonoma (Wallpaper, macOS) * Fix overall memory leaks (macOS) +* Remove trailing `\0` in JSON results (FreeBSD) # 2.5.0 diff --git a/src/common/settings.c b/src/common/settings.c index ae057a292..a01d4e706 100644 --- a/src/common/settings.c +++ b/src/common/settings.c @@ -411,9 +411,8 @@ bool ffSettingsGetFreeBSDKenv(const char* propName, FFstrbuf* result) //https://wiki.ghostbsd.org/index.php/Kenv ffStrbufEnsureFree(result, KENV_MVALLEN); int len = kenv(KENV_GET, propName, result->chars + result->length, KENV_MVALLEN); - if (len <= 0) return false; - result->length += (uint32_t) len; - result->chars[result->length] = '\0'; + if (len <= 1) return false; // number of bytes copied, including NUL terminator + result->length += (uint32_t) len - 1; return true; } #endif From 2ba878cbab13de5b08a1834c4c4d6aca0f16f5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 19:12:36 +0800 Subject: [PATCH 43/99] Monitor (Linux): fix detection with Nvidia drivers NVIDIA DRM driver reports `enabled` to be `disabled` --- CHANGELOG.md | 1 + src/detection/monitor/monitor_linux.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 175bfc791..e62674db2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Bugfixes: * Fix support of macOS Sonoma (Wallpaper, macOS) * Fix overall memory leaks (macOS) * Remove trailing `\0` in JSON results (FreeBSD) +* Fix physical monitor detection with Nvidia drivers (Monitor, Linux) # 2.5.0 diff --git a/src/detection/monitor/monitor_linux.c b/src/detection/monitor/monitor_linux.c index 507efdfa2..3b2ef1ea7 100644 --- a/src/detection/monitor/monitor_linux.c +++ b/src/detection/monitor/monitor_linux.c @@ -29,10 +29,10 @@ const char* ffDetectMonitor(FFlist* results) ffStrbufAppendS(&drmDir, entry->d_name); uint32_t drmDirWithDnameLength = drmDir.length; - ffStrbufAppendS(&drmDir, "/enabled"); - char enabled = 'd'; // disabled - ffReadFileData(drmDir.chars, sizeof(enabled), &enabled); - if (enabled != 'e') // enabled + ffStrbufAppendS(&drmDir, "/status"); + char status = 'd'; // disconnected + ffReadFileData(drmDir.chars, sizeof(status), &status); + if (status != 'c') // connected { ffStrbufSubstrBefore(&drmDir, drmDirLength); continue; From 5b4a26393d44d53ba65e1074f6c9318b1372f9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 20:40:20 +0800 Subject: [PATCH 44/99] Gamepad (Linux): detect battery capacity --- src/detection/gamepad/gamepad.h | 1 + src/detection/gamepad/gamepad_apple.c | 1 + src/detection/gamepad/gamepad_bsd.c | 1 + src/detection/gamepad/gamepad_linux.c | 59 +++++++++++++++++++------ src/detection/gamepad/gamepad_windows.c | 1 + src/modules/gamepad/gamepad.c | 13 +++++- 6 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/detection/gamepad/gamepad.h b/src/detection/gamepad/gamepad.h index be63e9dea..441b095dc 100644 --- a/src/detection/gamepad/gamepad.h +++ b/src/detection/gamepad/gamepad.h @@ -6,6 +6,7 @@ typedef struct FFGamepadDevice { FFstrbuf identifier; FFstrbuf name; + uint8_t battery; // 0-100% } FFGamepadDevice; const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */); diff --git a/src/detection/gamepad/gamepad_apple.c b/src/detection/gamepad/gamepad_apple.c index b1a8436ca..6927d6213 100644 --- a/src/detection/gamepad/gamepad_apple.c +++ b/src/detection/gamepad/gamepad_apple.c @@ -13,6 +13,7 @@ static void enumSet(const void* value, void *context) ffCfStrGetString(serialNumber, &device->identifier); ffStrbufInit(&device->name); ffCfStrGetString(product, &device->name); + device->battery = 0; } const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) diff --git a/src/detection/gamepad/gamepad_bsd.c b/src/detection/gamepad/gamepad_bsd.c index ade8fb996..019fec23c 100644 --- a/src/detection/gamepad/gamepad_bsd.c +++ b/src/detection/gamepad/gamepad_bsd.c @@ -44,6 +44,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); ffStrbufInitS(&device->identifier, di.udi_serial); ffStrbufInitF(&device->name, "%s %s", di.udi_vendor, di.udi_product); + device->battery = 0; } } } diff --git a/src/detection/gamepad/gamepad_linux.c b/src/detection/gamepad/gamepad_linux.c index a5273a0fa..ec584aad5 100644 --- a/src/detection/gamepad/gamepad_linux.c +++ b/src/detection/gamepad/gamepad_linux.c @@ -5,39 +5,72 @@ #include #include +static void detectGamepad(FFlist* devices, FFstrbuf* name, FFstrbuf* path) +{ + uint32_t baseLen = path->length; + FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); + ffStrbufInit(&device->identifier); + ffStrbufInitMove(&device->name, name); + device->battery = 0; + + ffStrbufAppendS(path, "uniq"); + if (ffAppendFileBuffer(path->chars, &device->identifier)) + ffStrbufTrimRightSpace(&device->identifier); + + ffStrbufSubstrBefore(path, baseLen); + ffStrbufAppendS(path, "device/power_supply/"); // /sys/class/input/jsX/device/device/power_supply + + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(path->chars); + if (dirp) + { + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) + { + if (entry->d_name[0] == '.' || (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN)) + continue; + ffStrbufAppendS(path, entry->d_name); + ffStrbufAppendS(path, "/capacity"); // /sys/class/input/jsX/device/device/power_supply/XXX/capacity + char capacity[32]; + ssize_t nRead = ffReadFileData(path->chars, sizeof(capacity) - 1, capacity); + if (nRead > 0) + { + capacity[nRead] = '\0'; + device->battery = (uint8_t) strtoul(capacity, NULL, 10); + } + } + } +} + const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) { - DIR* dirp = opendir("/sys/class/input/"); - if(dirp == NULL) + FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/input/"); + if (dirp == NULL) return "opendir(\"/sys/class/input/\") == NULL"; FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/class/input/"); uint32_t baseLen = path.length; struct dirent* entry; - while((entry = readdir(dirp)) != NULL) + while ((entry = readdir(dirp)) != NULL) { - if(!ffStrStartsWith(entry->d_name, "js")) + if (!ffStrStartsWith(entry->d_name, "js")) continue; - if(!isdigit(entry->d_name[2])) + if (!isdigit(entry->d_name[2])) continue; ffStrbufAppendS(&path, entry->d_name); ffStrbufAppendS(&path, "/device/name"); - if (ffPathExists(path.chars, FF_PATHTYPE_FILE)) + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); + if (ffAppendFileBuffer(path.chars, &name)) { - FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); - ffStrbufInitS(&device->identifier, entry->d_name); - ffStrbufInit(&device->name); - if (ffAppendFileBuffer(path.chars, &device->name)) - ffStrbufTrimRightSpace(&device->name); + ffStrbufTrimRightSpace(&name); + ffStrbufSubstrBefore(&path, path.length - 4); + detectGamepad(devices, &name, &path); } ffStrbufSubstrBefore(&path, baseLen); } - closedir(dirp); - return NULL; } diff --git a/src/detection/gamepad/gamepad_windows.c b/src/detection/gamepad/gamepad_windows.c index 8a5799717..a95f273c9 100644 --- a/src/detection/gamepad/gamepad_windows.c +++ b/src/detection/gamepad/gamepad_windows.c @@ -119,6 +119,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); ffStrbufInitWS(&device->identifier, devName); ffStrbufInit(&device->name); + device->battery = 0; const char* knownGamepad = detectKnownGamepad(rdi.hid.dwVendorId, rdi.hid.dwProductId); if (knownGamepad) diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index f48be7bf9..55a2aba00 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -1,3 +1,4 @@ +#include "common/bar.h" #include "common/printing.h" #include "common/jsonconfig.h" #include "detection/gamepad/gamepad.h" @@ -10,14 +11,21 @@ static void printDevice(FFGamepadOptions* options, const FFGamepadDevice* device { if(options->moduleArgs.outputFormat.length == 0) { + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateCopy(&device->name); ffPrintLogoAndKey(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - ffStrbufPutTo(&device->name, stdout); + if (device->battery > 0 && device->battery <= 100) + { + ffStrbufAppendC(&buffer, ' '); + ffAppendPercentNum(&buffer, device->battery, 51, 21, true); + } + ffStrbufPutTo(&buffer, stdout); } else { ffPrintFormat(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_GAMEPAD_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, {FF_FORMAT_ARG_TYPE_STRBUF, &device->identifier}, + {FF_FORMAT_ARG_TYPE_UINT8, &device->battery}, }); } } @@ -121,7 +129,8 @@ void ffPrintGamepadHelpFormat(void) { ffPrintModuleFormatHelp(FF_GAMEPAD_MODULE_NAME, "{1}", FF_GAMEPAD_NUM_FORMAT_ARGS, (const char* []) { "Name", - "Identifier" + "Identifier", + "Battery", }); } From cf096eb101dfcc162f1f31446a50244e92c16bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 6 Jan 2024 23:43:35 +0800 Subject: [PATCH 45/99] Gamepad (Windows): detect serial number and battery (PS4 controller) --- src/detection/gamepad/gamepad_windows.c | 76 ++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/src/detection/gamepad/gamepad_windows.c b/src/detection/gamepad/gamepad_windows.c index a95f273c9..47d8a3baf 100644 --- a/src/detection/gamepad/gamepad_windows.c +++ b/src/detection/gamepad/gamepad_windows.c @@ -3,6 +3,7 @@ #include "util/mallocHelper.h" #include "util/windows/unicode.h" +#include #include #include @@ -98,7 +99,8 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) if ((nDevices = GetRawInputDeviceList(pRawInputDeviceList, &nDevices, sizeof(RAWINPUTDEVICELIST))) == (UINT) -1) return "GetRawInputDeviceList(pRawInputDeviceList) failed"; - for (UINT i = 0; i < nDevices; ++i) { + for (UINT i = 0; i < nDevices; ++i) + { if (pRawInputDeviceList[i].dwType != 2) continue; HANDLE hDevice = pRawInputDeviceList[i].hDevice; @@ -117,21 +119,79 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) continue; FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); - ffStrbufInitWS(&device->identifier, devName); + ffStrbufInit(&device->identifier); ffStrbufInit(&device->name); device->battery = 0; const char* knownGamepad = detectKnownGamepad(rdi.hid.dwVendorId, rdi.hid.dwProductId); if (knownGamepad) ffStrbufSetS(&device->name, knownGamepad); - else + HANDLE FF_AUTO_CLOSE_FD hHidFile = CreateFileW(devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (!hHidFile) + { + if (!knownGamepad) + ffStrbufSetF(&device->name, "Unknown gamepad %04X-%04X", (unsigned) rdi.hid.dwVendorId, (unsigned) rdi.hid.dwProductId); + continue; + } + + if (!knownGamepad) { wchar_t displayName[126]; - HANDLE FF_AUTO_CLOSE_FD hHidFile = CreateFileW(devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (hHidFile && HidD_GetProductString(hHidFile, displayName, sizeof(wchar_t) * 126)) - ffStrbufSetWS(&device->name, displayName); - else - ffStrbufSetF(&device->name, "Unknown gamepad %4X-%4X", (unsigned) rdi.hid.dwVendorId, (unsigned) rdi.hid.dwProductId); + if (HidD_GetProductString(hHidFile, displayName, sizeof(displayName))) + { + wchar_t manufacturer[126]; + if (HidD_GetManufacturerString(hHidFile, manufacturer, sizeof(manufacturer))) + { + ffStrbufSetWS(&device->name, manufacturer); + FF_STRBUF_AUTO_DESTROY displayNameStr = ffStrbufCreateWS(displayName); + ffStrbufAppendC(&device->name, ' '); + ffStrbufAppend(&device->name, &displayNameStr); + } + else + { + ffStrbufSetWS(&device->name, displayName); + } + } + } + + PHIDP_PREPARSED_DATA preparsedData = NULL; + if (HidD_GetPreparsedData(hHidFile, &preparsedData)) + { + HIDP_CAPS caps; + NTSTATUS capsResult = HidP_GetCaps(preparsedData, &caps); + HidD_FreePreparsedData(preparsedData); + if (!NT_SUCCESS(capsResult)) + continue; + + wchar_t serialNumber[127] = L""; + if (HidD_GetSerialNumberString(hHidFile, serialNumber, sizeof(serialNumber))) + ffStrbufSetWS(&device->identifier, serialNumber); + else if (caps.FeatureReportByteLength >= 6) + { + uint8_t* featureBuffer = malloc(caps.FeatureReportByteLength); + featureBuffer[0] = 18; + if (HidD_GetFeature(hHidFile, featureBuffer, caps.FeatureReportByteLength)) + ffStrbufSetF(&device->identifier, "%02X:%02X:%02X:%02X:%02X:%02X", featureBuffer[0], featureBuffer[1], featureBuffer[2], featureBuffer[3], featureBuffer[4], featureBuffer[5]); + } + + + if (caps.InputReportByteLength < 31) + continue; + + if ( + (rdi.hid.dwVendorId == 0x054C && rdi.hid.dwProductId == 0x05C4) || // PS4 G1 + (rdi.hid.dwVendorId == 0x054C && rdi.hid.dwProductId == 0x09CC) // PS4 G2 + ) + { + FF_AUTO_FREE uint8_t* reportBuffer = malloc(caps.InputReportByteLength); + ssize_t nBytes = ffReadFDData(hHidFile, caps.InputReportByteLength, reportBuffer); + if (nBytes > 31) + { + uint8_t batteryInfo = reportBuffer[caps.InputReportByteLength == 64 /*USB?*/ ? 30 : 32]; + device->battery = (uint8_t) ((batteryInfo & 0x0f) * 100 / (batteryInfo & 0x10 /*charging?*/ ? 11 /*BATTERY_MAX_USB*/ : 8 /*BATTERY_MAX*/)); + if (device->battery > 100) device->battery = 100; + } + } } } From 2aa899d83c48bf6c2d62b148f7adb3022a867533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 7 Jan 2024 17:59:50 +0800 Subject: [PATCH 46/99] Gamepad (Linux): support battery level detection of NS Pro controller --- src/detection/gamepad/gamepad_linux.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/detection/gamepad/gamepad_linux.c b/src/detection/gamepad/gamepad_linux.c index ec584aad5..ac823e0fa 100644 --- a/src/detection/gamepad/gamepad_linux.c +++ b/src/detection/gamepad/gamepad_linux.c @@ -32,10 +32,26 @@ static void detectGamepad(FFlist* devices, FFstrbuf* name, FFstrbuf* path) ffStrbufAppendS(path, "/capacity"); // /sys/class/input/jsX/device/device/power_supply/XXX/capacity char capacity[32]; ssize_t nRead = ffReadFileData(path->chars, sizeof(capacity) - 1, capacity); - if (nRead > 0) + if (nRead > 0) // Tested with a PS4 controller { capacity[nRead] = '\0'; device->battery = (uint8_t) strtoul(capacity, NULL, 10); + break; + } + + ffStrbufAppendS(path, "_level"); + nRead = ffReadFileData(path->chars, sizeof(capacity) - 1, capacity); + if (nRead > 0) // Tested with a NS Pro controller + { + // https://github.com/torvalds/linux/blob/52b1853b080a082ec3749c3a9577f6c71b1d4a90/drivers/power/supply/power_supply_sysfs.c#L124 + switch (capacity[0]) + { + case 'C': device->battery = 1; break; // Critical + case 'L': device->battery = 25; break; // Low + case 'N': device->battery = 50; break; // Normal + case 'H': device->battery = 75; break; // High + case 'F': device->battery = 100; break; // Full + } } } } From 1215eb06ca3e2a4937f2e0594fcf1eba319173bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 7 Jan 2024 19:07:15 +0800 Subject: [PATCH 47/99] Gamepad (Windows): support battery detection of NS Pro --- src/detection/gamepad/gamepad_windows.c | 34 +++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/detection/gamepad/gamepad_windows.c b/src/detection/gamepad/gamepad_windows.c index 47d8a3baf..ef99cedb9 100644 --- a/src/detection/gamepad/gamepad_windows.c +++ b/src/detection/gamepad/gamepad_windows.c @@ -174,22 +174,36 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) ffStrbufSetF(&device->identifier, "%02X:%02X:%02X:%02X:%02X:%02X", featureBuffer[0], featureBuffer[1], featureBuffer[2], featureBuffer[3], featureBuffer[4], featureBuffer[5]); } - - if (caps.InputReportByteLength < 31) - continue; - if ( - (rdi.hid.dwVendorId == 0x054C && rdi.hid.dwProductId == 0x05C4) || // PS4 G1 - (rdi.hid.dwVendorId == 0x054C && rdi.hid.dwProductId == 0x09CC) // PS4 G2 + (rdi.hid.dwVendorId == 0x054C && ( + rdi.hid.dwProductId == 0x05C4 || // PS4 Gen1 + rdi.hid.dwProductId == 0x09CC // PS4 Gen2 + )) || + (rdi.hid.dwVendorId == 0x057E && ( + rdi.hid.dwProductId == 0x2009 // NS Pro + )) ) { FF_AUTO_FREE uint8_t* reportBuffer = malloc(caps.InputReportByteLength); ssize_t nBytes = ffReadFDData(hHidFile, caps.InputReportByteLength, reportBuffer); - if (nBytes > 31) + if (rdi.hid.dwVendorId == 0x054C) { - uint8_t batteryInfo = reportBuffer[caps.InputReportByteLength == 64 /*USB?*/ ? 30 : 32]; - device->battery = (uint8_t) ((batteryInfo & 0x0f) * 100 / (batteryInfo & 0x10 /*charging?*/ ? 11 /*BATTERY_MAX_USB*/ : 8 /*BATTERY_MAX*/)); - if (device->battery > 100) device->battery = 100; + if (nBytes > 31) + { + uint8_t batteryInfo = reportBuffer[caps.InputReportByteLength == 64 /*USB?*/ ? 30 : 32]; + device->battery = (uint8_t) ((batteryInfo & 0x0f) * 100 / (batteryInfo & 0x10 /*charging?*/ ? 11 /*BATTERY_MAX_USB*/ : 8 /*BATTERY_MAX*/)); + if (device->battery > 100) device->battery = 100; + } + } + else + { + if (nBytes > 3 && reportBuffer[0] == 0x30) // Controller must be connected by other programs + { + uint8_t batteryInfo = reportBuffer[2]; + device->battery = (uint8_t) (((batteryInfo & 0xE0) >> 4) * 100 / 8); + if (device->battery == 0) device->battery = 1; + else if (device->battery > 100) device->battery = 100; + } } } } From 8e78fadbeb8f771d3fc0b46d07297532fa621443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 8 Jan 2024 09:55:11 +0800 Subject: [PATCH 48/99] Gamepad: don't provide device names of XBox compatible controllers --- src/detection/gamepad/gamepad_apple.c | 16 ++++++----- src/detection/gamepad/gamepad_windows.c | 35 +++++-------------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/detection/gamepad/gamepad_apple.c b/src/detection/gamepad/gamepad_apple.c index 6927d6213..814e2c3b8 100644 --- a/src/detection/gamepad/gamepad_apple.c +++ b/src/detection/gamepad/gamepad_apple.c @@ -4,16 +4,18 @@ #include #include -static void enumSet(const void* value, void *context) +static void enumSet(IOHIDDeviceRef value, FFlist* results) { - CFStringRef product = IOHIDDeviceGetProperty((IOHIDDeviceRef) value, CFSTR(kIOHIDProductKey)); - CFStringRef serialNumber = IOHIDDeviceGetProperty((IOHIDDeviceRef) value, CFSTR(kIOHIDSerialNumberKey)); - FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd((FFlist*) context); + FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(results); ffStrbufInit(&device->identifier); - ffCfStrGetString(serialNumber, &device->identifier); ffStrbufInit(&device->name); - ffCfStrGetString(product, &device->name); device->battery = 0; + + CFStringRef serialNumber = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDSerialNumberKey)); + ffCfStrGetString(serialNumber, &device->identifier); + + CFStringRef product = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDProductKey)); + ffCfStrGetString(product, &device->name); } const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) @@ -35,7 +37,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) CFSetRef FF_CFTYPE_AUTO_RELEASE set = IOHIDManagerCopyDevices(manager); if (set) - CFSetApplyFunction(set, &enumSet, devices); + CFSetApplyFunction(set, (CFSetApplierFunction) &enumSet, devices); IOHIDManagerClose(manager, 0); return NULL; diff --git a/src/detection/gamepad/gamepad_windows.c b/src/detection/gamepad/gamepad_windows.c index ef99cedb9..7d533a616 100644 --- a/src/detection/gamepad/gamepad_windows.c +++ b/src/detection/gamepad/gamepad_windows.c @@ -7,7 +7,7 @@ #include #include -static const char* detectKnownGamepad(uint32_t vendorId, uint32_t productId) +static const char* detectKnownDeviceName(uint32_t vendorId, uint32_t productId) { switch (vendorId) { @@ -31,38 +31,14 @@ static const char* detectKnownGamepad(uint32_t vendorId, uint32_t productId) { switch (productId) { - case 0x0268: return "Sony Playstation 3 Controller"; + case 0x0268: return "Sony DualShock 3 / Six Axis"; case 0x05C4: return "Sony DualShock 4 Gen1"; case 0x09CC: return "Sony DualShock 4 Gen2"; - case 0x0BA0: return "Sony PS4 Controller USB receiver"; + case 0x0BA0: return "Sony DualShock 4 USB receiver"; case 0x0CE6: return "Sony DualSense"; - - default: return NULL; - } - } - - // Microsoft - case 0x045E: - { - switch (productId) - { - case 0x02E0: return "Microsoft X-Box One S pad (Wireless)"; - case 0x02FD: return "Microsoft X-Box One S pad (Wireless, 2016 FW)"; - case 0x0B05: return "Microsoft X-Box One Elite Series 2 pad (Wireless)"; - case 0x0B13: return "Microsoft X-Box Series X (Wireless)"; - - case 0x028E: return "Microsoft XBox 360"; - case 0x028F: return "Microsoft XBox 360 v2"; - case 0x02A1: return "Microsoft XBox 360"; - case 0x0291: return "Microsoft XBox 360 USB receiver"; - case 0x02A0: return "Microsoft XBox 360 Big Button IR"; - case 0x02DD: return "Microsoft XBox One"; - case 0xB326: return "Microsoft XBox One Firmware 2015"; - case 0x02E3: return "Microsoft XBox One Elite"; - case 0x02FF: return "Microsoft XBox One Elite"; - case 0x02EA: return "Microsoft XBox One S"; + case 0x0DF2: return "Sony DualSense Edge"; default: return NULL; } @@ -84,6 +60,7 @@ static const char* detectKnownGamepad(uint32_t vendorId, uint32_t productId) } } + case 0x045E: // Microsoft Xbox compatible controllers should be handled by Windows without problems default: return NULL; } } @@ -123,7 +100,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) ffStrbufInit(&device->name); device->battery = 0; - const char* knownGamepad = detectKnownGamepad(rdi.hid.dwVendorId, rdi.hid.dwProductId); + const char* knownGamepad = detectKnownDeviceName(rdi.hid.dwVendorId, rdi.hid.dwProductId); if (knownGamepad) ffStrbufSetS(&device->name, knownGamepad); HANDLE FF_AUTO_CLOSE_FD hHidFile = CreateFileW(devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); From 80cc4e3f4ad62510ba184606eb2173a59e7e73a0 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 8 Jan 2024 11:19:35 +0800 Subject: [PATCH 49/99] Host (Linux): detect serial number for Asahi Linux --- src/detection/host/host_linux.c | 60 +++++++++++++++++++++++---------- src/util/smbiosHelper.c | 7 ++-- src/util/smbiosHelper.h | 2 +- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/detection/host/host_linux.c b/src/detection/host/host_linux.c index 372557a88..92b1c49f9 100644 --- a/src/detection/host/host_linux.c +++ b/src/detection/host/host_linux.c @@ -7,35 +7,61 @@ static void getHostProductName(FFstrbuf* name) { - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", name); - if(name->length > 0) - return; + if (ffReadFileBuffer("/sys/firmware/devicetree/base/model", name)) + { + ffStrbufTrimRightSpace(name); + ffStrbufTrimRight(name, '\0'); + if(ffIsSmbiosValueSet(name)) + return; + } - ffReadFileBuffer("/sys/firmware/devicetree/base/model", name); - if(ffIsSmbiosValueSet(name)) - return; + if (ffReadFileBuffer("/sys/firmware/devicetree/base/banner-name", name)) + { + ffStrbufTrimRightSpace(name); + ffStrbufTrimRight(name, '\0'); + if(ffIsSmbiosValueSet(name)) + return; + } - ffReadFileBuffer("/sys/firmware/devicetree/base/banner-name", name); - if(ffIsSmbiosValueSet(name)) - return; - - //does a clear before the read - ffReadFileBuffer("/tmp/sysinfo/model", name); - if(ffIsSmbiosValueSet(name)) - return; + if (ffReadFileBuffer("/tmp/sysinfo/model", name)) + { + ffStrbufTrimRightSpace(name); + ffStrbufTrimRight(name, '\0'); + if(ffIsSmbiosValueSet(name)) + return; + } ffStrbufClear(name); } +static void getHostSerialNumber(FFstrbuf* serial) +{ + if (ffReadFileBuffer("/sys/firmware/devicetree/base/serial-number", serial)) + { + ffStrbufTrimRightSpace(serial); + ffStrbufTrimRight(serial, '\0'); + if(ffIsSmbiosValueSet(serial)) + return; + } + + ffStrbufClear(serial); +} + const char* ffDetectHost(FFHostResult* host) { ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family); - getHostProductName(&host->name); + if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", &host->name)) + getHostProductName(&host->name); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->version); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->sku); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->serial); + if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->serial)) + getHostSerialNumber(&host->serial); ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_uuid", "/sys/class/dmi/id/product_uuid", &host->uuid); - ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->vendor); + if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->vendor)) + { + if (ffStrbufStartsWithS(&host->name, "Apple ")) + ffStrbufSetStatic(&host->vendor, "Apple Inc."); + } //KVM/Qemu virtual machine if(ffStrbufStartsWithS(&host->name, "Standard PC")) diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 4ba518079..a9ab4e857 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -31,23 +31,24 @@ bool ffIsSmbiosValueSet(FFstrbuf* value) } #ifdef __linux__ -void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer) +bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer) { if (ffReadFileBuffer(devicesPath, buffer)) { ffStrbufTrimRightSpace(buffer); if(ffIsSmbiosValueSet(buffer)) - return; + return true; } if (ffReadFileBuffer(classPath, buffer)) { ffStrbufTrimRightSpace(buffer); if(ffIsSmbiosValueSet(buffer)) - return; + return true; } ffStrbufClear(buffer); + return false; } #elif defined(_WIN32) #include diff --git a/src/util/smbiosHelper.h b/src/util/smbiosHelper.h index e59211889..6a80b3ab5 100644 --- a/src/util/smbiosHelper.h +++ b/src/util/smbiosHelper.h @@ -13,7 +13,7 @@ static inline void ffCleanUpSmbiosValue(FFstrbuf* value) } #ifdef __linux__ -void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer); +bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer); #elif defined(_WIN32) // https://github.com/KunYi/DumpSMBIOS // https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf From e8c067ff3d8763104e5faa61d130d5af5a6624f0 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 8 Jan 2024 11:32:39 +0800 Subject: [PATCH 50/99] Wifi (Linux): don't print invalid information --- src/detection/wifi/wifi_linux.c | 36 +++++++++++++++++---------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index 5c500f50d..34af04fd4 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -87,43 +87,43 @@ static const char* detectWifiWithLibnm(FFlist* result) switch(state) { case NM_DEVICE_STATE_UNKNOWN: - ffStrbufAppendS(&item->inf.status, "Unknown"); + ffStrbufSetStatic(&item->inf.status, "Unknown"); break; case NM_DEVICE_STATE_UNMANAGED: - ffStrbufAppendS(&item->inf.status, "Unmanaged"); + ffStrbufSetStatic(&item->inf.status, "Unmanaged"); break; case NM_DEVICE_STATE_UNAVAILABLE: - ffStrbufAppendS(&item->inf.status, "Unavailable"); + ffStrbufSetStatic(&item->inf.status, "Unavailable"); break; case NM_DEVICE_STATE_DISCONNECTED: - ffStrbufAppendS(&item->inf.status, "Disconnected"); + ffStrbufSetStatic(&item->inf.status, "Disconnected"); break; case NM_DEVICE_STATE_PREPARE: - ffStrbufAppendS(&item->inf.status, "Prepare"); + ffStrbufSetStatic(&item->inf.status, "Prepare"); break; case NM_DEVICE_STATE_CONFIG: - ffStrbufAppendS(&item->inf.status, "Config"); + ffStrbufSetStatic(&item->inf.status, "Config"); break; case NM_DEVICE_STATE_NEED_AUTH: - ffStrbufAppendS(&item->inf.status, "Need auth"); + ffStrbufSetStatic(&item->inf.status, "Need auth"); break; case NM_DEVICE_STATE_IP_CONFIG: - ffStrbufAppendS(&item->inf.status, "IP config"); + ffStrbufSetStatic(&item->inf.status, "IP config"); break; case NM_DEVICE_STATE_IP_CHECK: - ffStrbufAppendS(&item->inf.status, "IP check"); + ffStrbufSetStatic(&item->inf.status, "IP check"); break; case NM_DEVICE_STATE_SECONDARIES: - ffStrbufAppendS(&item->inf.status, "Secondaries"); + ffStrbufSetStatic(&item->inf.status, "Secondaries"); break; case NM_DEVICE_STATE_ACTIVATED: - ffStrbufAppendS(&item->inf.status, "Activated"); + ffStrbufSetStatic(&item->inf.status, "Activated"); break; case NM_DEVICE_STATE_DEACTIVATING: - ffStrbufAppendS(&item->inf.status, "Deactivating"); + ffStrbufSetStatic(&item->inf.status, "Deactivating"); break; case NM_DEVICE_STATE_FAILED: - ffStrbufAppendS(&item->inf.status, "Failed"); + ffStrbufSetStatic(&item->inf.status, "Failed"); break; } if(state != NM_DEVICE_STATE_ACTIVATED) @@ -133,6 +133,8 @@ static const char* detectWifiWithLibnm(FFlist* result) if (!ap) continue; + ffStrbufSetStatic(&item->conn.status, "Connected"); + GBytes* activeSsid = ffnm_access_point_get_ssid(ap); if (activeSsid) { @@ -161,13 +163,13 @@ static const char* detectWifiWithLibnm(FFlist* result) if(ffParsePropLines(output.chars, "tx bitrate: ", &item->conn.protocol)) { if(ffStrbufContainS(&item->conn.protocol, " HE-MCS ")) - ffStrbufSetS(&item->conn.protocol, "802.11ax (Wi-Fi 6)"); + ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)"); else if(ffStrbufContainS(&item->conn.protocol, " VHT-MCS ")) - ffStrbufSetS(&item->conn.protocol, "802.11ac (Wi-Fi 5)"); + ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)"); else if(ffStrbufContainS(&item->conn.protocol, " MCS ")) - ffStrbufSetS(&item->conn.protocol, "802.11n (Wi-Fi 4)"); + ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)"); else - ffStrbufSetS(&item->conn.protocol, "802.11a/b/g"); + ffStrbufClear(&item->conn.protocol); sscanf(item->conn.protocol.chars, "%lf", &item->conn.txRate); } From 5693700c16a164081f9dad2a604f377bd1b82c78 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 8 Jan 2024 15:27:03 +0800 Subject: [PATCH 51/99] Bios (FreeBSD): fix boot type detection on some weird platforms --- src/common/io/io.h | 2 +- src/detection/bios/bios_bsd.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/common/io/io.h b/src/common/io/io.h index ec3375bd0..d188942ca 100644 --- a/src/common/io/io.h +++ b/src/common/io/io.h @@ -105,7 +105,7 @@ static inline bool ffPathExists(const char* path, FFPathType pathType) unsigned int mode = fileStat.st_mode & S_IFMT; - if(pathType & FF_PATHTYPE_FILE && mode == S_IFREG) + if(pathType & FF_PATHTYPE_FILE && mode != S_IFDIR) return true; if(pathType & FF_PATHTYPE_DIRECTORY && mode == S_IFDIR) diff --git a/src/detection/bios/bios_bsd.c b/src/detection/bios/bios_bsd.c index 6111b4315..aa115de21 100644 --- a/src/detection/bios/bios_bsd.c +++ b/src/detection/bios/bios_bsd.c @@ -2,6 +2,7 @@ #include "common/settings.h" #include "common/sysctl.h" +#include "common/io/io.h" #include "util/smbiosHelper.h" const char* ffDetectBios(FFBiosResult* result) @@ -15,5 +16,18 @@ const char* ffDetectBios(FFBiosResult* result) ffSettingsGetFreeBSDKenv("smbios.bios.version", &result->version); ffCleanUpSmbiosValue(&result->version); ffSysctlGetString("machdep.bootmethod", &result->type); + + if (result->type.length == 0) + { + if (ffSettingsGetFreeBSDKenv("loader.efi", &result->type)) + ffStrbufSetStatic(&result->type, ffStrbufEqualS(&result->type, "1") ? "UEFI" : "BIOS"); + else + { + ffStrbufSetStatic(&result->type, + ffPathExists("/dev/efi" /*efidev*/, FF_PATHTYPE_FILE) || + ffPathExists("/boot/efi/efi" /*efi partition*/, FF_PATHTYPE_DIRECTORY) + ? "UEFI" : "BIOS"); + } + } return NULL; } From cb599c6f2ae4ef587eedb769c4553e7066dba7e9 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 8 Jan 2024 15:54:08 +0800 Subject: [PATCH 52/99] Display (FreeBSD): support resolution detection in console --- .../displayserver/linux/displayserver_linux.c | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/detection/displayserver/linux/displayserver_linux.c b/src/detection/displayserver/linux/displayserver_linux.c index 60168b0dc..78483b7e4 100644 --- a/src/detection/displayserver/linux/displayserver_linux.c +++ b/src/detection/displayserver/linux/displayserver_linux.c @@ -1,5 +1,8 @@ #include "displayserver_linux.h" -#include "common/io/io.h" + +#ifdef __FreeBSD__ + #include "common/settings.h" +#endif void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) { @@ -31,6 +34,26 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) if(ds->displays.length == 0) ffdsConnectDrm(ds); + #ifdef __FreeBSD__ + if(ds->displays.length == 0) + { + FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate(); + if (ffSettingsGetFreeBSDKenv("screen.width", &buf)) + { + uint32_t width = (uint32_t) ffStrbufToUInt(&buf, 0); + if (width) + { + ffStrbufClear(&buf); + if (ffSettingsGetFreeBSDKenv("screen.height", &buf)) + { + uint32_t height = (uint32_t) ffStrbufToUInt(&buf, 0); + ffdsAppendDisplay(ds, width, height, 0, 0, 0, 0, NULL, FF_DISPLAY_TYPE_UNKNOWN, false, 0); + } + } + } + } + #endif + //This fills in missing information about WM / DE by using env vars and iterating processes ffdsDetectWMDE(ds); } From a160bc8de50a9ed7b612e84002539273c3bdca63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 9 Jan 2024 15:28:03 +0800 Subject: [PATCH 53/99] Gamepad (macOS): detect manufacturer --- src/detection/gamepad/gamepad_apple.c | 41 ++++++++++++++++++++------- src/util/apple/cf_helpers.c | 35 +++++++++++++---------- src/util/apple/cf_helpers.h | 1 + 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/detection/gamepad/gamepad_apple.c b/src/detection/gamepad/gamepad_apple.c index 814e2c3b8..de20ae5d8 100644 --- a/src/detection/gamepad/gamepad_apple.c +++ b/src/detection/gamepad/gamepad_apple.c @@ -1,5 +1,6 @@ #include "gamepad.h" #include "util/apple/cf_helpers.h" +#include "util/mallocHelper.h" #include #include @@ -11,11 +12,23 @@ static void enumSet(IOHIDDeviceRef value, FFlist* results) ffStrbufInit(&device->name); device->battery = 0; - CFStringRef serialNumber = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDSerialNumberKey)); - ffCfStrGetString(serialNumber, &device->identifier); + CFStringRef manufacturer = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDManufacturerKey)); + ffCfStrGetString(manufacturer, &device->name); CFStringRef product = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDProductKey)); - ffCfStrGetString(product, &device->name); + if (device->name.length) + { + ffCfStrGetString(product, &device->identifier); + ffStrbufAppendC(&device->name, ' '); + ffStrbufAppend(&device->name, &device->identifier); + } + else + { + ffCfStrGetString(product, &device->name); + } + + CFStringRef serialNumber = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDSerialNumberKey)); + ffCfStrGetString(serialNumber, &device->identifier); } const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) @@ -24,21 +37,29 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) if (IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone) != kIOReturnSuccess) return "IOHIDManagerOpen() failed"; - CFNumberRef FF_CFTYPE_AUTO_RELEASE genericDesktop = ffCfCreateInt(kHIDPage_GenericDesktop); - CFNumberRef FF_CFTYPE_AUTO_RELEASE gamePad = ffCfCreateInt(kHIDUsage_GD_GamePad); - CFDictionaryRef FF_CFTYPE_AUTO_RELEASE matching = CFDictionaryCreate(kCFAllocatorDefault, (const void **)(CFStringRef[]){ + CFDictionaryRef FF_CFTYPE_AUTO_RELEASE matching1 = CFDictionaryCreate(kCFAllocatorDefault, (const void **)(CFStringRef[]){ CFSTR(kIOHIDDeviceUsagePageKey), CFSTR(kIOHIDDeviceUsageKey) }, (const void **)(CFNumberRef[]){ - genericDesktop, - gamePad + ffCfCreateInt(kHIDPage_GenericDesktop), + ffCfCreateInt(kHIDUsage_GD_Joystick) }, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - IOHIDManagerSetDeviceMatching(manager, matching); + CFDictionaryRef FF_CFTYPE_AUTO_RELEASE matching2 = CFDictionaryCreate(kCFAllocatorDefault, (const void **)(CFStringRef[]){ + CFSTR(kIOHIDDeviceUsagePageKey), + CFSTR(kIOHIDDeviceUsageKey) + }, (const void **)(CFNumberRef[]){ + ffCfCreateInt(kHIDPage_GenericDesktop), + ffCfCreateInt(kHIDUsage_GD_GamePad) + }, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFArrayRef FF_CFTYPE_AUTO_RELEASE matchings = CFArrayCreate(kCFAllocatorDefault, (const void **)(CFTypeRef[]){ + matching1, matching2 + }, 2, &kCFTypeArrayCallBacks); + IOHIDManagerSetDeviceMatchingMultiple(manager, matchings); CFSetRef FF_CFTYPE_AUTO_RELEASE set = IOHIDManagerCopyDevices(manager); if (set) CFSetApplyFunction(set, (CFSetApplierFunction) &enumSet, devices); - IOHIDManagerClose(manager, 0); + IOHIDManagerClose(manager, kIOHIDOptionsTypeNone); return NULL; } diff --git a/src/util/apple/cf_helpers.c b/src/util/apple/cf_helpers.c index 7b501af71..a0bc534c7 100644 --- a/src/util/apple/cf_helpers.c +++ b/src/util/apple/cf_helpers.c @@ -19,6 +19,25 @@ const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result) return "TypeID is neither 'CFNumber' nor 'CFData'"; } +const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result) +{ + if(CFGetTypeID(cf) == CFNumberGetTypeID()) + { + if(!CFNumberGetValue((CFNumberRef)cf, kCFNumberSInt32Type, result)) + return "Number type is not SInt32"; + return NULL; + } + else if(CFGetTypeID(cf) == CFDataGetTypeID()) + { + if(CFDataGetLength((CFDataRef)cf) != sizeof(int)) + return "Data length is not sizeof(int)"; + CFDataGetBytes((CFDataRef)cf, CFRangeMake(0, sizeof(int)), (uint8_t*)result); + return NULL; + } + + return "TypeID is neither 'CFNumber' nor 'CFData'"; +} + const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) { if (!cf) @@ -86,21 +105,7 @@ const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result) if(cf == NULL) return "CFDictionaryGetValue() failed"; - if(CFGetTypeID(cf) == CFNumberGetTypeID()) - { - if(!CFNumberGetValue((CFNumberRef)cf, kCFNumberSInt32Type, result)) - return "Number type is not SInt32"; - return NULL; - } - else if(CFGetTypeID(cf) == CFDataGetTypeID()) - { - if(CFDataGetLength((CFDataRef)cf) != sizeof(int)) - return "Data length is not sizeof(int)"; - CFDataGetBytes((CFDataRef)cf, CFRangeMake(0, sizeof(int)), (uint8_t*)result); - return NULL; - } - - return "TypeID is neither 'CFNumber' nor 'CFData'"; + return ffCfNumGetInt(cf, result); } const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result) diff --git a/src/util/apple/cf_helpers.h b/src/util/apple/cf_helpers.h index a0e494710..fbfa47383 100644 --- a/src/util/apple/cf_helpers.h +++ b/src/util/apple/cf_helpers.h @@ -9,6 +9,7 @@ //Return error info if failed, NULL otherwise const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result); +const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result); const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result); const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result); const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result); From f84bb1ebe2b9b1cc8e4fc664031fe80a436152fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 9 Jan 2024 15:46:19 +0800 Subject: [PATCH 54/99] Smbios: silence compiler warnings --- src/util/smbiosHelper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index a9ab4e857..de33403eb 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -1,5 +1,6 @@ #include "smbiosHelper.h" #include "common/io/io.h" +#include "util/unused.h" bool ffIsSmbiosValueSet(FFstrbuf* value) { @@ -82,7 +83,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() assert(bufSize > sizeof(FFRawSmbiosData)); buffer = (FFRawSmbiosData*) malloc(bufSize); assert(buffer); - uint32_t resultSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize); + FF_MAYBE_UNUSED uint32_t resultSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize); assert(resultSize == bufSize); for ( From bc5261341001d53be07f165b5ef43fb72eae68c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 9 Jan 2024 15:53:42 +0800 Subject: [PATCH 55/99] Gamepad: rename identifier to serial number --- src/detection/gamepad/gamepad.h | 2 +- src/detection/gamepad/gamepad_apple.c | 8 ++++---- src/detection/gamepad/gamepad_bsd.c | 2 +- src/detection/gamepad/gamepad_linux.c | 6 +++--- src/detection/gamepad/gamepad_windows.c | 11 ++--------- src/modules/gamepad/gamepad.c | 10 +++++----- 6 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/detection/gamepad/gamepad.h b/src/detection/gamepad/gamepad.h index 441b095dc..3caed4cc7 100644 --- a/src/detection/gamepad/gamepad.h +++ b/src/detection/gamepad/gamepad.h @@ -4,7 +4,7 @@ typedef struct FFGamepadDevice { - FFstrbuf identifier; + FFstrbuf serial; FFstrbuf name; uint8_t battery; // 0-100% } FFGamepadDevice; diff --git a/src/detection/gamepad/gamepad_apple.c b/src/detection/gamepad/gamepad_apple.c index de20ae5d8..bfeb65ed0 100644 --- a/src/detection/gamepad/gamepad_apple.c +++ b/src/detection/gamepad/gamepad_apple.c @@ -8,7 +8,7 @@ static void enumSet(IOHIDDeviceRef value, FFlist* results) { FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(results); - ffStrbufInit(&device->identifier); + ffStrbufInit(&device->serial); ffStrbufInit(&device->name); device->battery = 0; @@ -18,9 +18,9 @@ static void enumSet(IOHIDDeviceRef value, FFlist* results) CFStringRef product = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDProductKey)); if (device->name.length) { - ffCfStrGetString(product, &device->identifier); + ffCfStrGetString(product, &device->serial); ffStrbufAppendC(&device->name, ' '); - ffStrbufAppend(&device->name, &device->identifier); + ffStrbufAppend(&device->name, &device->serial); } else { @@ -28,7 +28,7 @@ static void enumSet(IOHIDDeviceRef value, FFlist* results) } CFStringRef serialNumber = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDSerialNumberKey)); - ffCfStrGetString(serialNumber, &device->identifier); + ffCfStrGetString(serialNumber, &device->serial); } const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) diff --git a/src/detection/gamepad/gamepad_bsd.c b/src/detection/gamepad/gamepad_bsd.c index 019fec23c..340ff1165 100644 --- a/src/detection/gamepad/gamepad_bsd.c +++ b/src/detection/gamepad/gamepad_bsd.c @@ -42,7 +42,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) if (ioctl(fd, USB_GET_DEVICEINFO, &di) != -1) { FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); - ffStrbufInitS(&device->identifier, di.udi_serial); + ffStrbufInitS(&device->serial, di.udi_serial); ffStrbufInitF(&device->name, "%s %s", di.udi_vendor, di.udi_product); device->battery = 0; } diff --git a/src/detection/gamepad/gamepad_linux.c b/src/detection/gamepad/gamepad_linux.c index ac823e0fa..791412a70 100644 --- a/src/detection/gamepad/gamepad_linux.c +++ b/src/detection/gamepad/gamepad_linux.c @@ -9,13 +9,13 @@ static void detectGamepad(FFlist* devices, FFstrbuf* name, FFstrbuf* path) { uint32_t baseLen = path->length; FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); - ffStrbufInit(&device->identifier); + ffStrbufInit(&device->serial); ffStrbufInitMove(&device->name, name); device->battery = 0; ffStrbufAppendS(path, "uniq"); - if (ffAppendFileBuffer(path->chars, &device->identifier)) - ffStrbufTrimRightSpace(&device->identifier); + if (ffAppendFileBuffer(path->chars, &device->serial)) + ffStrbufTrimRightSpace(&device->serial); ffStrbufSubstrBefore(path, baseLen); ffStrbufAppendS(path, "device/power_supply/"); // /sys/class/input/jsX/device/device/power_supply diff --git a/src/detection/gamepad/gamepad_windows.c b/src/detection/gamepad/gamepad_windows.c index 7d533a616..65ee5c0f6 100644 --- a/src/detection/gamepad/gamepad_windows.c +++ b/src/detection/gamepad/gamepad_windows.c @@ -96,7 +96,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) continue; FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); - ffStrbufInit(&device->identifier); + ffStrbufInit(&device->serial); ffStrbufInit(&device->name); device->battery = 0; @@ -142,14 +142,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) wchar_t serialNumber[127] = L""; if (HidD_GetSerialNumberString(hHidFile, serialNumber, sizeof(serialNumber))) - ffStrbufSetWS(&device->identifier, serialNumber); - else if (caps.FeatureReportByteLength >= 6) - { - uint8_t* featureBuffer = malloc(caps.FeatureReportByteLength); - featureBuffer[0] = 18; - if (HidD_GetFeature(hHidFile, featureBuffer, caps.FeatureReportByteLength)) - ffStrbufSetF(&device->identifier, "%02X:%02X:%02X:%02X:%02X:%02X", featureBuffer[0], featureBuffer[1], featureBuffer[2], featureBuffer[3], featureBuffer[4], featureBuffer[5]); - } + ffStrbufSetWS(&device->serial, serialNumber); if ( (rdi.hid.dwVendorId == 0x054C && ( diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index 55a2aba00..a74d603cc 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -24,7 +24,7 @@ static void printDevice(FFGamepadOptions* options, const FFGamepadDevice* device { ffPrintFormat(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_GAMEPAD_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, - {FF_FORMAT_ARG_TYPE_STRBUF, &device->identifier}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->serial}, {FF_FORMAT_ARG_TYPE_UINT8, &device->battery}, }); } @@ -52,7 +52,7 @@ void ffPrintGamepad(FFGamepadOptions* options) FF_LIST_FOR_EACH(FFGamepadDevice, device, result) { printDevice(options, device, result.length > 1 ? ++index : 0); - ffStrbufDestroy(&device->identifier); + ffStrbufDestroy(&device->serial); ffStrbufDestroy(&device->name); } } @@ -114,13 +114,13 @@ void ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjs FF_LIST_FOR_EACH(FFGamepadDevice, device, result) { yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); - yyjson_mut_obj_add_strbuf(doc, obj, "identifier", &device->identifier); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial); yyjson_mut_obj_add_strbuf(doc, obj, "name", &device->name); } FF_LIST_FOR_EACH(FFGamepadDevice, device, result) { - ffStrbufDestroy(&device->identifier); + ffStrbufDestroy(&device->serial); ffStrbufDestroy(&device->name); } } @@ -129,7 +129,7 @@ void ffPrintGamepadHelpFormat(void) { ffPrintModuleFormatHelp(FF_GAMEPAD_MODULE_NAME, "{1}", FF_GAMEPAD_NUM_FORMAT_ARGS, (const char* []) { "Name", - "Identifier", + "Serial number", "Battery", }); } From 61af59fc0063c8b10a903e2822cd91c0ab208efb Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 9 Jan 2024 16:34:04 +0800 Subject: [PATCH 56/99] Battery (Linux): fix temperature detection --- src/detection/battery/battery_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index fb6967dce..e10484dcf 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -88,7 +88,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option { ffStrbufAppendS(dir, "/temp"); if (ffReadFileBuffer(dir->chars, &tmpBuffer)) - options->temp = ffStrbufToDouble(&tmpBuffer) / 10; + result->temperature = ffStrbufToDouble(&tmpBuffer) / 10; ffStrbufSubstrBefore(dir, dirLength); } } From 7926b749175c68368993bbfaeca90c0b4a53b4eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 9 Jan 2024 22:58:32 +0800 Subject: [PATCH 57/99] Battery: detect manufacturer date --- src/detection/battery/battery.h | 1 + src/detection/battery/battery_android.c | 1 + src/detection/battery/battery_apple.c | 1 + src/detection/battery/battery_bsd.c | 1 + src/detection/battery/battery_linux.c | 2 + src/detection/battery/battery_windows.c | 108 ++++++++++++++++++++++-- src/modules/battery/battery.c | 6 ++ 7 files changed, 111 insertions(+), 9 deletions(-) diff --git a/src/detection/battery/battery.h b/src/detection/battery/battery.h index 8165d1961..91ca8d37b 100644 --- a/src/detection/battery/battery.h +++ b/src/detection/battery/battery.h @@ -7,6 +7,7 @@ typedef struct FFBatteryResult { FFstrbuf manufacturer; + FFstrbuf manufacturerDate; FFstrbuf modelName; FFstrbuf technology; FFstrbuf status; diff --git a/src/detection/battery/battery_android.c b/src/detection/battery/battery_android.c index 6ddf3bbfe..b3b08dee1 100644 --- a/src/detection/battery/battery_android.c +++ b/src/detection/battery/battery_android.c @@ -40,6 +40,7 @@ static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results) ffStrbufInit(&battery->modelName); ffStrbufInit(&battery->status); ffStrbufInit(&battery->technology); + ffStrbufInit(&battery->manufacturerDate); battery->capacity = yyjson_get_num(yyjson_obj_get(root, "percentage")); ffStrbufAppendS(&battery->status, yyjson_get_str(yyjson_obj_get(root, "status"))); diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index c0d0ec8a6..4c5be2edf 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -29,6 +29,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) ffStrbufInit(&battery->serial); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->status); + ffStrbufInit(&battery->manufacturerDate); battery->capacity = 0.0/0.0; int currentCapacity, maxCapacity; diff --git a/src/detection/battery/battery_bsd.c b/src/detection/battery/battery_bsd.c index cb1e3090e..ff6367547 100644 --- a/src/detection/battery/battery_bsd.c +++ b/src/detection/battery/battery_bsd.c @@ -40,6 +40,7 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r ffStrbufInit(&battery->status); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->serial); + ffStrbufInit(&battery->manufacturerDate); battery->capacity = battio.battinfo.cap; if(battio.battinfo.state == ACPI_BATT_STAT_INVALID) diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index e10484dcf..536f1995d 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -83,6 +83,8 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount; } + ffStrbufInit(&result->manufacturerDate); + result->temperature = FF_BATTERY_TEMP_UNSET; if (options->temp) { diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index 81e78162e..4866f49cd 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -1,6 +1,7 @@ #include "battery.h" #include "util/windows/unicode.h" #include "util/mallocHelper.h" +#include "util/smbiosHelper.h" #undef WIN32_LEAN_AND_MEAN #include @@ -75,19 +76,19 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results); if(memcmp(bi.Chemistry, "PbAc", 4) == 0) - ffStrbufInitS(&battery->technology, "Lead Acid"); + ffStrbufInitStatic(&battery->technology, "Lead Acid"); else if(memcmp(bi.Chemistry, "LION", 4) == 0 || memcmp(bi.Chemistry, "Li-I", 4) == 0) - ffStrbufInitS(&battery->technology, "Lithium Ion"); + ffStrbufInitStatic(&battery->technology, "Lithium Ion"); else if(memcmp(bi.Chemistry, "NiCd", 4) == 0) - ffStrbufInitS(&battery->technology, "Nickel Cadmium"); + ffStrbufInitStatic(&battery->technology, "Nickel Cadmium"); else if(memcmp(bi.Chemistry, "NiMH", 4) == 0) - ffStrbufInitS(&battery->technology, "Nickel Metal Hydride"); + ffStrbufInitStatic(&battery->technology, "Nickel Metal Hydride"); else if(memcmp(bi.Chemistry, "NiZn", 4) == 0) - ffStrbufInitS(&battery->technology, "Nickel Zinc"); + ffStrbufInitStatic(&battery->technology, "Nickel Zinc"); else if(memcmp(bi.Chemistry, "RAM\0", 4) == 0) - ffStrbufInitS(&battery->technology, "Rechargeable Alkaline-Manganese"); + ffStrbufInitStatic(&battery->technology, "Rechargeable Alkaline-Manganese"); else - ffStrbufInitS(&battery->technology, "Unknown"); + ffStrbufInitStatic(&battery->technology, "Unknown"); { ffStrbufInit(&battery->modelName); @@ -105,6 +106,14 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results ffStrbufSetWS(&battery->manufacturer, name); } + { + ffStrbufInit(&battery->manufacturerDate); + bqi.InformationLevel = BatteryManufactureDate; + BATTERY_MANUFACTURE_DATE date; + if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL)) + ffStrbufSetF(&battery->manufacturerDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day); + } + { ffStrbufInit(&battery->serial); bqi.InformationLevel = BatterySerialNumber; @@ -121,7 +130,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results bqi.InformationLevel = BatteryTemperature; ULONG temp; if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &temp, sizeof(temp), &dwOut, NULL)) - battery->temperature = temp; + battery->temperature = temp / 10.0 - 273.15; } { @@ -148,6 +157,83 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results return NULL; } + + +typedef struct FFSmbiosPortableBattery +{ + FFSmbiosHeader Header; + + // 2.1+ + uint8_t Location; // string + uint8_t Manufacturer; // string + uint8_t ManufactureDate; // string + uint8_t SerialNumber; // string + uint8_t DeviceName; // string + uint8_t DeviceChemistry; // enum + uint16_t DesignCapacity; // varies + uint16_t DesignVoltage; // varies + uint8_t SbdsVersionNumber; // string + uint8_t MaximumErrorInBatteryData; // varies + + // 2.2+ + uint16_t SbdsSerialNumber; // varies + uint16_t SbdsManufactureDate; // varies + uint8_t SbdsDeviceChemistry; // string + uint8_t DesignCapacityMultiplier; // varies + uint16_t OEMSpecific; // varies +} FFSmbiosPortableBattery; + +const char* detectBySmbios(FFBatteryResult* battery) +{ + const FFSmbiosPortableBattery* data = (const FFSmbiosPortableBattery*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PORTABLE_BATTERY]; + if (!data) + return "Portable battery section is not found in SMBIOS data"; + + const char* strings = (const char*) data + data->Header.Length; + + ffStrbufSetStatic(&battery->modelName, ffSmbiosLocateString(strings, data->DeviceName)); + ffCleanUpSmbiosValue(&battery->modelName); + ffStrbufSetStatic(&battery->manufacturer, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&battery->manufacturer); + + if (data->ManufactureDate) + { + ffStrbufSetStatic(&battery->manufacturerDate, ffSmbiosLocateString(strings, data->ManufactureDate)); + ffCleanUpSmbiosValue(&battery->manufacturerDate); + } + else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsManufactureDate)) + { + uint16_t day = data->SbdsManufactureDate & 0b11111; + uint16_t month = (data->SbdsManufactureDate >> 5) & 0b1111; + uint16_t year = (data->SbdsManufactureDate >> 9) + 1800; + ffStrbufSetF(&battery->manufacturerDate, "%.4d-%.2d-%.2d", year, month, day); + } + + switch (data->DeviceChemistry) + { + case 0x01: ffStrbufSetStatic(&battery->technology, "Other"); break; + case 0x02: ffStrbufSetStatic(&battery->technology, "Unknown"); break; + case 0x03: ffStrbufSetStatic(&battery->technology, "Lead Acid"); break; + case 0x04: ffStrbufSetStatic(&battery->technology, "Nickel Cadmium"); break; + case 0x05: ffStrbufSetStatic(&battery->technology, "Nickel metal hydride"); break; + case 0x06: ffStrbufSetStatic(&battery->technology, "Lithium-ion"); break; + case 0x07: ffStrbufSetStatic(&battery->technology, "Zinc air"); break; + case 0x08: ffStrbufSetStatic(&battery->technology, "Lithium Polymer"); break; + } + + if (data->SerialNumber) + { + ffStrbufSetStatic(&battery->serial, ffSmbiosLocateString(strings, data->SerialNumber)); + ffCleanUpSmbiosValue(&battery->serial); + } + else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsSerialNumber)) + { + ffStrbufSetF(&battery->serial, "%4X", data->SbdsSerialNumber); + } + + return NULL; +} + static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results) { SYSTEM_BATTERY_STATE info; @@ -156,6 +242,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results); ffStrbufInit(&battery->modelName); ffStrbufInit(&battery->manufacturer); + ffStrbufInit(&battery->manufacturerDate); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->status); ffStrbufInit(&battery->serial); @@ -171,6 +258,9 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF } else if(info.Discharging) ffStrbufAppendS(&battery->status, "Discharging"); + + detectBySmbios(battery); + return NULL; } return "NtPowerInformation(SystemBatteryState) failed"; @@ -178,7 +268,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) { - return true + return options->useSetupApi ? detectWithSetupApi(options, results) : detectWithNtApi(options, results); } diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 733983d20..3fad65c54 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -72,6 +72,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin {FF_FORMAT_ARG_TYPE_DOUBLE, &result->temperature}, {FF_FORMAT_ARG_TYPE_UINT, &result->cycleCount}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->serial}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturerDate}, }); } } @@ -97,6 +98,8 @@ void ffPrintBattery(FFBatteryOptions* options) ffStrbufDestroy(&result->modelName); ffStrbufDestroy(&result->technology); ffStrbufDestroy(&result->status); + ffStrbufDestroy(&result->serial); + ffStrbufDestroy(&result->manufacturerDate); } if(results.length == 0) ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, "No batteries found"); @@ -192,6 +195,7 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); yyjson_mut_obj_add_real(doc, obj, "capacity", battery->capacity); yyjson_mut_obj_add_strbuf(doc, obj, "manufacturer", &battery->manufacturer); + yyjson_mut_obj_add_strbuf(doc, obj, "manufacturerDate", &battery->manufacturerDate); yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &battery->modelName); yyjson_mut_obj_add_strbuf(doc, obj, "status", &battery->status); yyjson_mut_obj_add_strbuf(doc, obj, "technology", &battery->technology); @@ -203,6 +207,7 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, FF_LIST_FOR_EACH(FFBatteryResult, battery, results) { ffStrbufDestroy(&battery->manufacturer); + ffStrbufDestroy(&battery->manufacturerDate); ffStrbufDestroy(&battery->modelName); ffStrbufDestroy(&battery->technology); ffStrbufDestroy(&battery->status); @@ -221,6 +226,7 @@ void ffPrintBatteryHelpFormat(void) "Battery temperature", "Battery cycle count", "Battery serial number", + "Battery manufactorDate", }); } From 12155e029b1258565b6cec699f6308121b829423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 9 Jan 2024 23:08:19 +0800 Subject: [PATCH 58/99] Battery (Linux): support manufacture date detection --- src/detection/battery/battery_linux.c | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index 536f1995d..605ac2ad0 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -84,6 +84,37 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option } ffStrbufInit(&result->manufacturerDate); + ffStrbufAppendS(dir, "/manufacture_year"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) + { + int year = (int) ffStrbufToSInt(&tmpBuffer, 0); + if (year > 0) + { + ffStrbufAppendS(dir, "/manufacture_month"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) + { + int month = (int) ffStrbufToSInt(&tmpBuffer, 0); + if (month > 0) + { + ffStrbufAppendS(dir, "/manufacture_day"); + available = ffReadFileBuffer(dir->chars, &tmpBuffer); + ffStrbufSubstrBefore(dir, dirLength); + if (available) + { + int day = (int) ffStrbufToSInt(&tmpBuffer, 0); + if (day > 0) + { + ffStrbufSetF(&result->manufacturerDate, "%.4d-%.2d-%.2d", year, month, day); + } + } + } + } + } + } result->temperature = FF_BATTERY_TEMP_UNSET; if (options->temp) From fdb68669f49589a407a0da63b96a9c6d27d6d0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 10 Jan 2024 13:26:54 +0800 Subject: [PATCH 59/99] Battery (macOS): support manufacture date detection --- src/detection/battery/battery_apple.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index 4c5be2edf..c237389db 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -68,6 +68,20 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) ffStrbufTrimRight(&battery->status, ' '); ffStrbufTrimRight(&battery->status, ','); + CFDictionaryRef batteryData; + if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL) + { + char manufactureDate[sizeof(uint64_t)]; + if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL) + { + // https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419 + int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8; + int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0'); + int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '5'); + ffStrbufSetF(&battery->manufacturerDate, "%.4d-%.2d-%.2d", year, month, day); + } + } + if (options->temp) { int64_t temp; From 8ba031b761995c2c7565ff74d5b38a635b0b6480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 10 Jan 2024 14:22:56 +0800 Subject: [PATCH 60/99] Brightness (FreeBSD): don't print empty `()` --- src/detection/brightness/brightness_bsd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/detection/brightness/brightness_bsd.c b/src/detection/brightness/brightness_bsd.c index 34b91ab5c..22b3772fb 100644 --- a/src/detection/brightness/brightness_bsd.c +++ b/src/detection/brightness/brightness_bsd.c @@ -36,6 +36,8 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl struct backlight_info info; if(ioctl(blfd, BACKLIGHTGETINFO, &info) < 0) ffStrbufAppendS(&brightness->name, info.name); + else + ffStrbufAppendS(&brightness->name, path + strlen("/dev/backlight/")); } return NULL; } From 92e05f7e38b2e5b3c227582e3f51d2fb6d6dead5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 10 Jan 2024 14:44:14 +0800 Subject: [PATCH 61/99] Chassis: don't print useless version --- src/util/smbiosHelper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index de33403eb..b9418cab9 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -26,6 +26,7 @@ bool ffIsSmbiosValueSet(FFstrbuf* value) !ffStrbufIgnCaseEqualS(value, "INVALID") && !ffStrbufIgnCaseEqualS(value, "Type1ProductConfigId") && !ffStrbufIgnCaseEqualS(value, "No Enclosure") && + !ffStrbufIgnCaseEqualS(value, "Chassis Version") && !ffStrbufIgnCaseEqualS(value, "All Series") && !ffStrbufIgnCaseEqualS(value, "N/A") ; From f5a57ab74727248647d47964f49165fe4276574c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 10 Jan 2024 14:48:47 +0800 Subject: [PATCH 62/99] Doc: update changelog --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e62674db2..5a0ae91a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,11 @@ Changes: Features: * Add `ENABLE_PROPRIETARY_GPU_DRIVER_API` cmake option to disable using of proprietary GPU driver APIs (GPU) -* Add power adapter detection support for Asahi Linux (PowerAdapter, Linux) -* Add battery serial number detection (Battery) -* Add host serial number and UUID detection (Host) +* Support power adapter detection for Asahi Linux (PowerAdapter, Linux) +* Support battery serial number and manufacturer date detection (Battery) +* Support host serial number and UUID detection (Host) +* Support battery level detection for gamepads where possible (Gamepad) +* Support maximum CPU clock detection. Previously base clock was printed (CPU, Windows) Bugfixes: * Fix support of macOS Sonoma (Wallpaper, macOS) From 0645f559afa683a99e7ccca687022bbb1f5750be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 10 Jan 2024 16:34:14 +0800 Subject: [PATCH 63/99] Monitor: detect serial number and manufacture date --- src/detection/monitor/monitor.h | 3 ++ src/detection/monitor/monitor_apple.m | 14 +++++++- src/detection/monitor/monitor_linux.c | 1 + src/detection/monitor/monitor_windows.c | 1 + src/modules/monitor/monitor.c | 44 ++++++++++++++++++++++--- src/util/edidHelper.c | 14 ++++++++ src/util/edidHelper.h | 1 + 7 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/detection/monitor/monitor.h b/src/detection/monitor/monitor.h index 8314c4cf4..a6150e5d3 100644 --- a/src/detection/monitor/monitor.h +++ b/src/detection/monitor/monitor.h @@ -8,6 +8,9 @@ typedef struct FFMonitorResult uint32_t physicalWidth; // in mm uint32_t physicalHeight; // in mm bool hdrCompatible; + uint16_t manufactureYear; + uint16_t manufactureWeek; + uint32_t serial; } FFMonitorResult; const char* ffDetectMonitor(FFlist* results); diff --git a/src/detection/monitor/monitor_apple.m b/src/detection/monitor/monitor_apple.m index be3b51a46..348a1ad33 100644 --- a/src/detection/monitor/monitor_apple.m +++ b/src/detection/monitor/monitor_apple.m @@ -40,9 +40,13 @@ const char* ffDetectMonitor(FFlist* results) CFDictionaryRef FF_CFTYPE_AUTO_RELEASE displayInfo = CoreDisplay_DisplayCreateInfoDictionary((CGDirectDisplayID) display->id); if(!displayInfo) continue; + bool isVirtual = false; + if (ffCfDictGetBool(displayInfo, CFSTR("kCGDisplayIsVirtualDevice"), &isVirtual) == NULL && isVirtual) + continue; + uint8_t edidData[128] = {}; uint32_t edidLength = 0; - if (false || !ffCfDictGetData(displayInfo, CFSTR("IODisplayEDID"), 0, sizeof(edidData), edidData, &edidLength)) + if (ffCfDictGetData(displayInfo, CFSTR("IODisplayEDID"), 0, sizeof(edidData), edidData, &edidLength) == NULL) { uint32_t width, height; ffEdidGetPhysicalResolution(edidData, &width, &height); @@ -75,6 +79,14 @@ const char* ffDetectMonitor(FFlist* results) monitor->physicalHeight = (uint32_t) (size.height + 0.5); monitor->hdrCompatible = CFDictionaryContainsKey(displayInfo, CFSTR("ReferencePeakHDRLuminance")) || detectHdrSupportWithNSScreen(display); + + int64_t serial, year, week; + if (ffCfDictGetInt64(displayInfo, CFSTR("DisplaySerialNumber"), &serial) == NULL) + monitor->serial = (uint32_t) (uint64_t) serial; + if (ffCfDictGetInt64(displayInfo, CFSTR("DisplayYearManufacture"), &year) == NULL) + monitor->manufactureYear = (uint16_t) year; + if (ffCfDictGetInt64(displayInfo, CFSTR("DisplayWeekManufacture"), &week) == NULL) + monitor->manufactureWeek = (uint16_t) week; } return NULL; diff --git a/src/detection/monitor/monitor_linux.c b/src/detection/monitor/monitor_linux.c index 3b2ef1ea7..8d0f5ec11 100644 --- a/src/detection/monitor/monitor_linux.c +++ b/src/detection/monitor/monitor_linux.c @@ -59,6 +59,7 @@ const char* ffDetectMonitor(FFlist* results) ffStrbufInit(&display->name); ffEdidGetName(edidData, &display->name); ffEdidGetPhysicalSize(edidData, &display->physicalWidth, &display->physicalHeight); + ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek); display->hdrCompatible = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength); } diff --git a/src/detection/monitor/monitor_windows.c b/src/detection/monitor/monitor_windows.c index f56c5a188..b695cf67a 100644 --- a/src/detection/monitor/monitor_windows.c +++ b/src/detection/monitor/monitor_windows.c @@ -44,6 +44,7 @@ const char* ffDetectMonitor(FFlist* results) FFMonitorResult* display = (FFMonitorResult*) ffListAdd(results); display->width = width; display->height = height; + ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek); display->hdrCompatible = ffEdidGetHdrCompatible(edidData, edidLength); // Doesn't work. edidLength is always 128 ffStrbufInit(&display->name); ffEdidGetName(edidData, &display->name); diff --git a/src/modules/monitor/monitor.c b/src/modules/monitor/monitor.c index 35ad8a6c4..776d4fd18 100644 --- a/src/modules/monitor/monitor.c +++ b/src/modules/monitor/monitor.c @@ -59,6 +59,15 @@ void ffPrintMonitor(FFMonitorOptions* options) } else { + char buf[32]; + if (display->serial) + { + const uint8_t* nums = (uint8_t*) &display->serial; + snprintf(buf, sizeof(buf), "%2X-%2X-%2X-%2X", nums[0], nums[1], nums[2], nums[3]); + } + else + buf[0] = '\0'; + ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_MONITOR_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_STRBUF, &display->name}, {FF_FORMAT_ARG_TYPE_UINT, &display->width}, @@ -67,6 +76,9 @@ void ffPrintMonitor(FFMonitorOptions* options) {FF_FORMAT_ARG_TYPE_UINT, &display->physicalHeight}, {FF_FORMAT_ARG_TYPE_DOUBLE, &inch}, {FF_FORMAT_ARG_TYPE_DOUBLE, &ppi}, + {FF_FORMAT_ARG_TYPE_UINT16, &display->manufactureYear}, + {FF_FORMAT_ARG_TYPE_UINT16, &display->manufactureWeek}, + {FF_FORMAT_ARG_TYPE_STRING, buf}, }); } @@ -131,11 +143,31 @@ void ffGenerateMonitorJsonResult(FF_MAYBE_UNUSED FFMonitorOptions* options, yyjs { yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); yyjson_mut_obj_add_bool(doc, obj, "hdrCompatible", item->hdrCompatible); - yyjson_mut_obj_add_uint(doc, obj, "width", item->width); - yyjson_mut_obj_add_uint(doc, obj, "height", item->height); yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name); - yyjson_mut_obj_add_uint(doc, obj, "physicalHeight", item->physicalHeight); - yyjson_mut_obj_add_uint(doc, obj, "physicalWidth", item->physicalWidth); + + yyjson_mut_val* resolution = yyjson_mut_obj_add_obj(doc, obj, "resolution"); + yyjson_mut_obj_add_uint(doc, resolution, "width", item->width); + yyjson_mut_obj_add_uint(doc, resolution, "height", item->height); + + yyjson_mut_val* physical = yyjson_mut_obj_add_obj(doc, obj, "physical"); + yyjson_mut_obj_add_uint(doc, physical, "height", item->physicalHeight); + yyjson_mut_obj_add_uint(doc, physical, "width", item->physicalWidth); + + if (item->manufactureYear) + { + yyjson_mut_val* manufactureDate = yyjson_mut_obj_add_obj(doc, obj, "manufactureDate"); + yyjson_mut_obj_add_uint(doc, manufactureDate, "year", item->manufactureYear); + yyjson_mut_obj_add_uint(doc, manufactureDate, "week", item->manufactureWeek); + } + else + { + yyjson_mut_obj_add_null(doc, obj, "manufactureDate"); + } + + if (item->serial) + yyjson_mut_obj_add_uint(doc, obj, "serial", item->serial); + else + yyjson_mut_obj_add_null(doc, obj, "serial"); } } @@ -154,7 +186,9 @@ void ffPrintMonitorHelpFormat(void) "Display physical width in millimeters", "Display physical height in millimeters", "Display physical diagonal length in inches", - "Display physical pixels per inch (PPI)" + "Year of manufacturing", + "Nth week of manufacturing in the year", + "Serial number", }); } diff --git a/src/util/edidHelper.c b/src/util/edidHelper.c index 5a375dfcf..5fa2c662b 100644 --- a/src/util/edidHelper.c +++ b/src/util/edidHelper.c @@ -50,6 +50,20 @@ void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* h *height = (((uint32_t) edid[68] & 0x0F) << 8) + edid[67]; } +void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week) +{ + if (edid[17] > 0 && edid[17] < 0xFF) + { + *year = edid[17] + 1990; + *week = edid[16]; + if (*week == 0xFF) *week = 0; + } + else + *year = *week = 0; + + *serial = *(uint32_t*) &edid[12]; +} + bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length) { if (length <= 128) return false; diff --git a/src/util/edidHelper.h b/src/util/edidHelper.h index 2fc8d591d..6e768ddf9 100644 --- a/src/util/edidHelper.h +++ b/src/util/edidHelper.h @@ -7,4 +7,5 @@ void ffEdidGetVendorAndModel(const uint8_t edid[128], FFstrbuf* result); bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name); void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height); void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm +void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week); bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length); From 5f638a67eda2e235ddad6e36a7611e8c1260b10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 10 Jan 2024 19:03:58 +0800 Subject: [PATCH 64/99] Battery: rename manufacturerDate to manufactureDate --- src/detection/battery/battery.h | 2 +- src/detection/battery/battery_android.c | 2 +- src/detection/battery/battery_apple.c | 4 ++-- src/detection/battery/battery_bsd.c | 2 +- src/detection/battery/battery_linux.c | 4 ++-- src/detection/battery/battery_windows.c | 12 ++++++------ src/modules/battery/battery.c | 8 ++++---- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/detection/battery/battery.h b/src/detection/battery/battery.h index 91ca8d37b..2f4c8e3f1 100644 --- a/src/detection/battery/battery.h +++ b/src/detection/battery/battery.h @@ -7,7 +7,7 @@ typedef struct FFBatteryResult { FFstrbuf manufacturer; - FFstrbuf manufacturerDate; + FFstrbuf manufactureDate; FFstrbuf modelName; FFstrbuf technology; FFstrbuf status; diff --git a/src/detection/battery/battery_android.c b/src/detection/battery/battery_android.c index b3b08dee1..8939625cf 100644 --- a/src/detection/battery/battery_android.c +++ b/src/detection/battery/battery_android.c @@ -40,7 +40,7 @@ static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results) ffStrbufInit(&battery->modelName); ffStrbufInit(&battery->status); ffStrbufInit(&battery->technology); - ffStrbufInit(&battery->manufacturerDate); + ffStrbufInit(&battery->manufactureDate); battery->capacity = yyjson_get_num(yyjson_obj_get(root, "percentage")); ffStrbufAppendS(&battery->status, yyjson_get_str(yyjson_obj_get(root, "status"))); diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index c237389db..8aafed206 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -29,7 +29,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) ffStrbufInit(&battery->serial); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->status); - ffStrbufInit(&battery->manufacturerDate); + ffStrbufInit(&battery->manufactureDate); battery->capacity = 0.0/0.0; int currentCapacity, maxCapacity; @@ -78,7 +78,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8; int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0'); int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '5'); - ffStrbufSetF(&battery->manufacturerDate, "%.4d-%.2d-%.2d", year, month, day); + ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day); } } diff --git a/src/detection/battery/battery_bsd.c b/src/detection/battery/battery_bsd.c index ff6367547..4376e6e75 100644 --- a/src/detection/battery/battery_bsd.c +++ b/src/detection/battery/battery_bsd.c @@ -40,7 +40,7 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r ffStrbufInit(&battery->status); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->serial); - ffStrbufInit(&battery->manufacturerDate); + ffStrbufInit(&battery->manufactureDate); battery->capacity = battio.battinfo.cap; if(battio.battinfo.state == ACPI_BATT_STAT_INVALID) diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index 605ac2ad0..085e4a892 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -83,7 +83,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount; } - ffStrbufInit(&result->manufacturerDate); + ffStrbufInit(&result->manufactureDate); ffStrbufAppendS(dir, "/manufacture_year"); available = ffReadFileBuffer(dir->chars, &tmpBuffer); ffStrbufSubstrBefore(dir, dirLength); @@ -108,7 +108,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option int day = (int) ffStrbufToSInt(&tmpBuffer, 0); if (day > 0) { - ffStrbufSetF(&result->manufacturerDate, "%.4d-%.2d-%.2d", year, month, day); + ffStrbufSetF(&result->manufactureDate, "%.4d-%.2d-%.2d", year, month, day); } } } diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index 4866f49cd..4e1a44db4 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -107,11 +107,11 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results } { - ffStrbufInit(&battery->manufacturerDate); + ffStrbufInit(&battery->manufactureDate); bqi.InformationLevel = BatteryManufactureDate; BATTERY_MANUFACTURE_DATE date; if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL)) - ffStrbufSetF(&battery->manufacturerDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day); + ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day); } { @@ -198,15 +198,15 @@ const char* detectBySmbios(FFBatteryResult* battery) if (data->ManufactureDate) { - ffStrbufSetStatic(&battery->manufacturerDate, ffSmbiosLocateString(strings, data->ManufactureDate)); - ffCleanUpSmbiosValue(&battery->manufacturerDate); + ffStrbufSetStatic(&battery->manufactureDate, ffSmbiosLocateString(strings, data->ManufactureDate)); + ffCleanUpSmbiosValue(&battery->manufactureDate); } else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsManufactureDate)) { uint16_t day = data->SbdsManufactureDate & 0b11111; uint16_t month = (data->SbdsManufactureDate >> 5) & 0b1111; uint16_t year = (data->SbdsManufactureDate >> 9) + 1800; - ffStrbufSetF(&battery->manufacturerDate, "%.4d-%.2d-%.2d", year, month, day); + ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day); } switch (data->DeviceChemistry) @@ -242,7 +242,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results); ffStrbufInit(&battery->modelName); ffStrbufInit(&battery->manufacturer); - ffStrbufInit(&battery->manufacturerDate); + ffStrbufInit(&battery->manufactureDate); ffStrbufInit(&battery->technology); ffStrbufInit(&battery->status); ffStrbufInit(&battery->serial); diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index 3fad65c54..cefe6166a 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -72,7 +72,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin {FF_FORMAT_ARG_TYPE_DOUBLE, &result->temperature}, {FF_FORMAT_ARG_TYPE_UINT, &result->cycleCount}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->serial}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturerDate}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->manufactureDate}, }); } } @@ -99,7 +99,7 @@ void ffPrintBattery(FFBatteryOptions* options) ffStrbufDestroy(&result->technology); ffStrbufDestroy(&result->status); ffStrbufDestroy(&result->serial); - ffStrbufDestroy(&result->manufacturerDate); + ffStrbufDestroy(&result->manufactureDate); } if(results.length == 0) ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, "No batteries found"); @@ -195,7 +195,7 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); yyjson_mut_obj_add_real(doc, obj, "capacity", battery->capacity); yyjson_mut_obj_add_strbuf(doc, obj, "manufacturer", &battery->manufacturer); - yyjson_mut_obj_add_strbuf(doc, obj, "manufacturerDate", &battery->manufacturerDate); + yyjson_mut_obj_add_strbuf(doc, obj, "manufactureDate", &battery->manufactureDate); yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &battery->modelName); yyjson_mut_obj_add_strbuf(doc, obj, "status", &battery->status); yyjson_mut_obj_add_strbuf(doc, obj, "technology", &battery->technology); @@ -207,7 +207,7 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, FF_LIST_FOR_EACH(FFBatteryResult, battery, results) { ffStrbufDestroy(&battery->manufacturer); - ffStrbufDestroy(&battery->manufacturerDate); + ffStrbufDestroy(&battery->manufactureDate); ffStrbufDestroy(&battery->modelName); ffStrbufDestroy(&battery->technology); ffStrbufDestroy(&battery->status); From a8aaf605b1a8cf8890aa0c9ef2978fd6b9aaef33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 10 Jan 2024 19:04:47 +0800 Subject: [PATCH 65/99] Doc: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a0ae91a1..ea9da6b13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Features: * Support host serial number and UUID detection (Host) * Support battery level detection for gamepads where possible (Gamepad) * Support maximum CPU clock detection. Previously base clock was printed (CPU, Windows) +* Support manufacture date and serial number detection for physical monitors (Monitor) Bugfixes: * Fix support of macOS Sonoma (Wallpaper, macOS) From 653e689f18678c8ff379b2212f839f02b42c8fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 11 Jan 2024 09:53:20 +0800 Subject: [PATCH 66/99] GPU (macOS): tidy --- src/detection/gpu/gpu_apple.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detection/gpu/gpu_apple.m b/src/detection/gpu/gpu_apple.m index 1079ff1e0..951d25469 100644 --- a/src/detection/gpu/gpu_apple.m +++ b/src/detection/gpu/gpu_apple.m @@ -15,7 +15,7 @@ const char* ffGpuDetectMetal(FFlist* gpus) FFGPUResult* gpu = NULL; FF_LIST_FOR_EACH(FFGPUResult, x, *gpus) { - if (x->deviceId == device.registryID || ffStrbufEqualS(&x->name, device.name.UTF8String)) + if (x->deviceId == device.registryID) { gpu = x; break; @@ -34,7 +34,7 @@ const char* ffGpuDetectMetal(FFlist* gpus) gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; } + return NULL; } - - return NULL; + return "Metal API is not supported by this macOS version"; } From 0c65cdc1f5d8068df969d70145d5dc89f40eeea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 11 Jan 2024 10:11:50 +0800 Subject: [PATCH 67/99] GPU (macOS): detect memory usage --- src/detection/gpu/gpu_apple.m | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/detection/gpu/gpu_apple.m b/src/detection/gpu/gpu_apple.m index 951d25469..0323fdaff 100644 --- a/src/detection/gpu/gpu_apple.m +++ b/src/detection/gpu/gpu_apple.m @@ -32,7 +32,18 @@ const char* ffGpuDetectMetal(FFlist* gpus) else if ([device supportsFamily:MTLGPUFamilyCommon1]) ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1"); - gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; + if (gpu->type == device.hasUnifiedMemory) + { + gpu->type = FF_GPU_TYPE_INTEGRATED; + gpu->shared.total = device.recommendedMaxWorkingSetSize; + gpu->shared.used = device.currentAllocatedSize; + } + else + { + gpu->type = FF_GPU_TYPE_DISCRETE; + gpu->dedicated.total = device.recommendedMaxWorkingSetSize; + gpu->dedicated.used = device.currentAllocatedSize; + } } return NULL; } From 37e0a7b03f3c248911c192f16a7f7ff1b3f4dc6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 11 Jan 2024 16:27:53 +0800 Subject: [PATCH 68/99] stringUtils: tidy --- CMakeLists.txt | 1 - src/util/stringUtils.c | 28 ---------------------------- src/util/stringUtils.h | 14 ++++++++++++-- 3 files changed, 12 insertions(+), 31 deletions(-) delete mode 100644 src/util/stringUtils.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 357faaaf9..6e7594c85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -377,7 +377,6 @@ set(LIBFASTFETCH_SRC src/util/FFlist.c src/util/FFstrbuf.c src/util/platform/FFPlatform.c - src/util/stringUtils.c src/util/smbiosHelper.c ) diff --git a/src/util/stringUtils.c b/src/util/stringUtils.c deleted file mode 100644 index 07a3bd101..000000000 --- a/src/util/stringUtils.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "stringUtils.h" - -#include - -bool ffStrSet(const char* str) -{ - if(str == NULL) - return false; - - while(isspace(*str)) - str++; - - return *str != '\0'; -} - -bool ffStrHasNChars(const char* str, char c, uint32_t n) -{ - for(uint32_t i = 0; i < n; i++) - { - char* current = strchr(str, c); - if(current == NULL) - return false; - - str = current + 1; - } - - return true; -} diff --git a/src/util/stringUtils.h b/src/util/stringUtils.h index e67298224..e5fe80e12 100644 --- a/src/util/stringUtils.h +++ b/src/util/stringUtils.h @@ -3,9 +3,19 @@ #include #include #include +#include + +static inline bool ffStrSet(const char* str) +{ + if(str == NULL) + return false; + + while(isspace(*str)) + str++; + + return *str != '\0'; +} -bool ffStrSet(const char* str); -bool ffStrHasNChars(const char* str, char c, uint32_t n); static inline bool ffStrStartsWithIgnCase(const char* str, const char* compareTo) { From 6da57d64c3875465c26999cf31ea07258a1f1561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 12 Jan 2024 16:40:21 +0800 Subject: [PATCH 69/99] TerminalShell: split terminal detection and shell detection --- .../terminalshell/terminalshell_linux.c | 192 ++++++++++-------- .../terminalshell/terminalshell_windows.c | 36 +++- 2 files changed, 130 insertions(+), 98 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 327ba9772..cea214ca7 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -118,7 +118,7 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) return NULL; } -static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) +static pid_t getShellInfo(FFTerminalShellResult* result, pid_t pid) { char name[256]; name[0] = '\0'; @@ -126,7 +126,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) pid_t ppid = 0; if(getProcessNameAndPpid(pid, name, &ppid)) - return; + return 0; //Common programs that are between terminal and own process, but are not the shell if( @@ -137,6 +137,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) strcasecmp(name, "sshd") == 0 || strcasecmp(name, "gdb") == 0 || strcasecmp(name, "lldb") == 0 || + strcasecmp(name, "lldb-mi") == 0 || strcasecmp(name, "login") == 0 || strcasecmp(name, "ltrace") == 0 || strcasecmp(name, "perf") == 0 || @@ -144,10 +145,24 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) strcasestr(name, "debug") != NULL || strcasestr(name, "command-not-found") != NULL || ffStrEndsWith(name, ".sh") - ) { - getTerminalShell(result, ppid); - return; - } + ) + return getShellInfo(result, ppid); + + result->shellPid = (uint32_t) pid; + ffStrbufSetS(&result->shellProcessName, name); + getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName); + return ppid; +} + +static pid_t getTerminalInfo(FFTerminalShellResult* result, pid_t pid) +{ + char name[256]; + name[0] = '\0'; + + pid_t ppid = 0; + + if(getProcessNameAndPpid(pid, name, &ppid)) + return 0; //Known shells if ( @@ -167,17 +182,8 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) strcasecmp(name, "elvish") == 0 || strcasecmp(name, "oil.ovm") == 0 || (strcasecmp(name, "python") == 0 && getenv("XONSH_VERSION")) - ) { - if (result->shellProcessName.length == 0) - { - result->shellPid = (uint32_t) pid; - ffStrbufSetS(&result->shellProcessName, name); - getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName); - } - - getTerminalShell(result, ppid); - return; - } + ) + return getTerminalInfo(result, ppid); #ifdef __APPLE__ // https://github.com/fastfetch-cli/fastfetch/discussions/501 @@ -188,6 +194,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) result->terminalPid = (uint32_t) pid; ffStrbufSetS(&result->terminalProcessName, name); getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName); + return ppid; } static void getTerminalFromEnv(FFTerminalShellResult* result) @@ -288,6 +295,80 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version); +static void setShellInfoDetails(FFTerminalShellResult* result) +{ + ffStrbufClear(&result->shellVersion); + fftsGetShellVersion(&result->shellExe, result->shellExeName, &result->shellVersion); + + if(ffStrbufEqualS(&result->shellProcessName, "pwsh")) + ffStrbufInitStatic(&result->shellPrettyName, "PowerShell"); + else if(ffStrbufEqualS(&result->shellProcessName, "nu")) + ffStrbufInitStatic(&result->shellPrettyName, "nushell"); + else if(ffStrbufIgnCaseEqualS(&result->shellProcessName, "python") && getenv("XONSH_VERSION")) + ffStrbufInitStatic(&result->shellPrettyName, "xonsh"); + else if(ffStrbufIgnCaseEqualS(&result->shellProcessName, "oil.ovm")) + ffStrbufInitStatic(&result->shellPrettyName, "Oils"); + else + { + // https://github.com/fastfetch-cli/fastfetch/discussions/280#discussioncomment-3831734 + ffStrbufInitS(&result->shellPrettyName, result->shellExeName); + } +} + +static void setTerminalInfoDetails(FFTerminalShellResult* result) +{ + if(result->terminalExeName[0] == '.' && ffStrEndsWith(result->terminalExeName, "-wrapped")) + { + // For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428 + // We use terminalProcessName when detecting version and font, overriding it for simplification + ffStrbufSetNS( + &result->terminalProcessName, + (uint32_t) (strlen(result->terminalExeName) - strlen(".-wrapped")), + result->terminalExeName + 1); + } + + if(ffStrbufEqualS(&result->terminalProcessName, "wezterm-gui")) + ffStrbufInitStatic(&result->terminalPrettyName, "WezTerm"); + if(ffStrbufStartsWithS(&result->terminalProcessName, "tmux:")) + ffStrbufInitStatic(&result->terminalPrettyName, "tmux"); + + #if defined(__ANDROID__) + + else if(ffStrbufEqualS(&result->terminalProcessName, "com.termux")) + ffStrbufInitStatic(&result->terminalPrettyName, "Termux"); + + #elif defined(__linux__) || defined(__FreeBSD__) + + else if(ffStrbufStartsWithS(&result->terminalProcessName, "gnome-terminal-")) + ffStrbufInitStatic(&result->terminalPrettyName, "GNOME Terminal"); + else if(ffStrbufStartsWithS(&result->terminalProcessName, "kgx")) + ffStrbufInitStatic(&result->terminalPrettyName, "GNOME Console"); + else if(ffStrbufEqualS(&result->terminalProcessName, "urxvt") || + ffStrbufEqualS(&result->terminalProcessName, "urxvtd") || + ffStrbufEqualS(&result->terminalProcessName, "rxvt") + ) + ffStrbufInitStatic(&result->terminalPrettyName, "rxvt-unicode"); + + #elif defined(__APPLE__) + + else if(ffStrbufEqualS(&result->terminalProcessName, "iTerm.app") || ffStrbufStartsWithS(&result->terminalProcessName, "iTermServer-")) + ffStrbufInitStatic(&result->terminalPrettyName, "iTerm"); + else if(ffStrbufEqualS(&result->terminalProcessName, "Apple_Terminal")) + ffStrbufInitStatic(&result->terminalPrettyName, "Apple Terminal"); + else if(ffStrbufEqualS(&result->terminalProcessName, "WarpTerminal")) + ffStrbufInitStatic(&result->terminalPrettyName, "Warp"); + + #endif + + else if(strncmp(result->terminalExeName, result->terminalProcessName.chars, result->terminalProcessName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName + ffStrbufInitS(&result->terminalPrettyName, result->terminalExeName); + else + ffStrbufInitCopy(&result->terminalPrettyName, &result->terminalProcessName); + + ffStrbufInit(&result->terminalVersion); + fftsGetTerminalVersion(&result->terminalProcessName, &result->terminalExe, &result->terminalVersion); +} + const FFTerminalShellResult* ffDetectTerminalShell() { static FFTerminalShellResult result; @@ -317,78 +398,15 @@ const FFTerminalShellResult* ffDetectTerminalShell() result.terminalExeName = result.terminalExe.chars; result.terminalPid = 0; - getTerminalShell(&result, getppid()); - - getTerminalFromEnv(&result); + pid_t ppid = getppid(); + ppid = getShellInfo(&result, ppid); getUserShellFromEnv(&result); + setShellInfoDetails(&result); - ffStrbufClear(&result.shellVersion); - fftsGetShellVersion(&result.shellExe, result.shellExeName, &result.shellVersion); - - if(ffStrbufEqualS(&result.shellProcessName, "pwsh")) - ffStrbufInitStatic(&result.shellPrettyName, "PowerShell"); - else if(ffStrbufEqualS(&result.shellProcessName, "nu")) - ffStrbufInitStatic(&result.shellPrettyName, "nushell"); - else if(ffStrbufIgnCaseEqualS(&result.shellProcessName, "python") && getenv("XONSH_VERSION")) - ffStrbufInitStatic(&result.shellPrettyName, "xonsh"); - else if(ffStrbufIgnCaseEqualS(&result.shellProcessName, "oil.ovm")) - ffStrbufInitStatic(&result.shellPrettyName, "Oils"); - else - { - // https://github.com/fastfetch-cli/fastfetch/discussions/280#discussioncomment-3831734 - ffStrbufInitS(&result.shellPrettyName, result.shellExeName); - } - - if(result.terminalExeName[0] == '.' && ffStrEndsWith(result.terminalExeName, "-wrapped")) - { - // For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428 - // We use terminalProcessName when detecting version and font, overriding it for simplification - ffStrbufSetNS( - &result.terminalProcessName, - (uint32_t) (strlen(result.terminalExeName) - strlen(".-wrapped")), - result.terminalExeName + 1); - } - - if(ffStrbufEqualS(&result.terminalProcessName, "wezterm-gui")) - ffStrbufInitStatic(&result.terminalPrettyName, "WezTerm"); - if(ffStrbufStartsWithS(&result.terminalProcessName, "tmux:")) - ffStrbufInitStatic(&result.terminalPrettyName, "tmux"); - - #if defined(__ANDROID__) - - else if(ffStrbufEqualS(&result.terminalProcessName, "com.termux")) - ffStrbufInitStatic(&result.terminalPrettyName, "Termux"); - - #elif defined(__linux__) || defined(__FreeBSD__) - - else if(ffStrbufStartsWithS(&result.terminalProcessName, "gnome-terminal-")) - ffStrbufInitStatic(&result.terminalPrettyName, "GNOME Terminal"); - else if(ffStrbufStartsWithS(&result.terminalProcessName, "kgx")) - ffStrbufInitStatic(&result.terminalPrettyName, "GNOME Console"); - else if(ffStrbufEqualS(&result.terminalProcessName, "urxvt") || - ffStrbufEqualS(&result.terminalProcessName, "urxvtd") || - ffStrbufEqualS(&result.terminalProcessName, "rxvt") - ) - ffStrbufInitStatic(&result.terminalPrettyName, "rxvt-unicode"); - - #elif defined(__APPLE__) - - else if(ffStrbufEqualS(&result.terminalProcessName, "iTerm.app") || ffStrbufStartsWithS(&result.terminalProcessName, "iTermServer-")) - ffStrbufInitStatic(&result.terminalPrettyName, "iTerm"); - else if(ffStrbufEqualS(&result.terminalProcessName, "Apple_Terminal")) - ffStrbufInitStatic(&result.terminalPrettyName, "Apple Terminal"); - else if(ffStrbufEqualS(&result.terminalProcessName, "WarpTerminal")) - ffStrbufInitStatic(&result.terminalPrettyName, "Warp"); - - #endif - - else if(strncmp(result.terminalExeName, result.terminalProcessName.chars, result.terminalProcessName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName - ffStrbufInitS(&result.terminalPrettyName, result.terminalExeName); - else - ffStrbufInitCopy(&result.terminalPrettyName, &result.terminalProcessName); - - ffStrbufInit(&result.terminalVersion); - fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion); + if (ppid) + ppid = getTerminalInfo(&result, ppid); + getTerminalFromEnv(&result); + setTerminalInfoDetails(&result); return &result; } diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index 0f2f23c81..ac5ad1872 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -120,6 +120,19 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion); result->shellPid = pid; + + if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer")) + { + ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell + // In this case, terminal process will be created by fastfetch itself. + ppid = 0; + } + + return ppid; +} + +static void setShellInfoDetails(FFTerminalShellResult* result) +{ if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh")) ffStrbufSetS(&result->shellPrettyName, "PowerShell"); else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell")) @@ -131,7 +144,7 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) ffStrbufClear(&result->shellPrettyName); FF_AUTO_CLOSE_FD HANDLE snapshot = NULL; - while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid)) && GetLastError() == ERROR_BAD_LENGTH) {} + while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, result->shellPid)) && GetLastError() == ERROR_BAD_LENGTH) {} if(snapshot) { @@ -154,13 +167,7 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "nu")) ffStrbufSetS(&result->shellPrettyName, "nushell"); else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer")) - { - ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell - // In this case, terminal process will be created by fastfetch itself. - return 0; - } - - return ppid; + ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); } static bool getTerminalFromEnv(FFTerminalShellResult* result) @@ -198,7 +205,7 @@ static bool getTerminalFromEnv(FFTerminalShellResult* result) if(!term && ( getenv("WT_SESSION") != NULL || getenv("WT_PROFILE_ID") != NULL - )) term = "Windows Terminal"; + )) term = "WindowsTerminal"; //Alacritty if(!term && ( @@ -334,6 +341,11 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) else result->terminalPid = pid; + return ppid; +} + +static void setTerminalInfoDetails(FFTerminalShellResult* result) +{ if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal")) ffStrbufSetStatic(&result->terminalPrettyName, ffStrbufContainIgnCaseS(&result->terminalExe, ".WindowsTerminalPreview_") ? "Windows Terminal Preview" @@ -347,8 +359,6 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) ffStrbufSetStatic(&result->terminalPrettyName, "Windows Explorer"); else if(ffStrbufEqualS(&result->terminalPrettyName, "wezterm-gui")) ffStrbufSetStatic(&result->terminalPrettyName, "WezTerm"); - - return ppid; } bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version); @@ -379,12 +389,16 @@ const FFTerminalShellResult* ffDetectTerminalShell(void) return &result; ppid = getShellInfo(&result, ppid); + setShellInfoDetails(&result); + if(ppid) getTerminalInfo(&result, ppid); if(result.terminalProcessName.length == 0) getTerminalFromEnv(&result); + setTerminalInfoDetails(&result); + ffStrbufInit(&result.terminalVersion); fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion); From 905ed76ddddb424f74c35da5749103798516a54e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 12 Jan 2024 20:42:33 +0800 Subject: [PATCH 70/99] TerminalShell: split terminal and shell detection code further --- src/detection/terminalfont/terminalfont.c | 40 +-- .../terminalfont/terminalfont_android.c | 4 +- .../terminalfont/terminalfont_apple.m | 10 +- .../terminalfont/terminalfont_linux.c | 30 +- .../terminalfont/terminalfont_windows.c | 8 +- src/detection/terminalshell/terminalshell.h | 37 ++- .../terminalshell/terminalshell_linux.c | 198 +++++++------ .../terminalshell/terminalshell_windows.c | 272 ++++++++++-------- src/detection/wm/wm_windows.cpp | 2 +- src/logo/logo.c | 10 +- src/modules/shell/shell.c | 37 +-- src/modules/terminal/terminal.c | 39 +-- 12 files changed, 365 insertions(+), 322 deletions(-) diff --git a/src/detection/terminalfont/terminalfont.c b/src/detection/terminalfont/terminalfont.c index 23932ef81..532296af9 100644 --- a/src/detection/terminalfont/terminalfont.c +++ b/src/detection/terminalfont/terminalfont.c @@ -394,35 +394,35 @@ static bool detectContour(const FFstrbuf* exe, FFTerminalFontResult* result) return true; } -void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont); +void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont); -static bool detectTerminalFontCommon(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont) +static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { - if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "alacritty")) + if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "alacritty")) detectAlacritty(terminalFont); - else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "terminator")) + else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "terminator")) detectTerminator(terminalFont); - else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "wezterm-gui")) + else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "wezterm-gui")) detectWezterm(terminalFont); - else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "tabby")) + else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "tabby")) detectTabby(terminalFont); - else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "contour")) - detectContour(&terminalShell->terminalExe, terminalFont); + else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "contour")) + detectContour(&terminal->exe, terminalFont); #ifndef _WIN32 - else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalExe, "/dev/pts/")) + else if(ffStrbufStartsWithIgnCaseS(&terminal->exe, "/dev/pts/")) ffStrbufAppendS(&terminalFont->error, "Terminal font detection is not supported on PTS"); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "kitty")) - detectKitty(&terminalShell->terminalExe, terminalFont); - else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalExe, "/dev/tty")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "kitty")) + detectKitty(&terminal->exe, terminalFont); + else if(ffStrbufStartsWithIgnCaseS(&terminal->exe, "/dev/tty")) detectTTY(terminalFont); #endif #if defined(_WIN32) || defined(__linux__) //Used by both Linux (WSL) and Windows - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "Windows Terminal") || - ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "WindowsTerminal.exe")) - detectFromWindowsTeriminal(&terminalShell->terminalExe, terminalFont); + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "Windows Terminal") || + ffStrbufIgnCaseEqualS(&terminal->processName, "WindowsTerminal.exe")) + detectFromWindowsTeriminal(&terminal->exe, terminalFont); #endif else @@ -433,16 +433,16 @@ static bool detectTerminalFontCommon(const FFTerminalShellResult* terminalShell, bool ffDetectTerminalFont(FFTerminalFontResult* result) { - const FFTerminalShellResult* terminalShell = ffDetectTerminalShell(); + const FFTerminalResult* terminal = ffDetectTerminal(); - if(terminalShell->terminalProcessName.length == 0) + if(terminal->processName.length == 0) ffStrbufAppendS(&result->error, "Terminal font needs successful terminal detection"); - else if(!detectTerminalFontCommon(terminalShell, result)) - ffDetectTerminalFontPlatform(terminalShell, result); + else if(!detectTerminalFontCommon(terminal, result)) + ffDetectTerminalFontPlatform(terminal, result); if(result->error.length == 0 && result->font.pretty.length == 0) - ffStrbufAppendF(&result->error, "Unknown terminal: %s", terminalShell->terminalProcessName.chars); + ffStrbufAppendF(&result->error, "Unknown terminal: %s", terminal->processName.chars); return result->error.length == 0; } diff --git a/src/detection/terminalfont/terminalfont_android.c b/src/detection/terminalfont/terminalfont_android.c index 72a67fb0a..fef9ad24a 100644 --- a/src/detection/terminalfont/terminalfont_android.c +++ b/src/detection/terminalfont/terminalfont_android.c @@ -53,9 +53,9 @@ exit: #endif } -void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont) +void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { - if(ffStrbufCompS(&terminalShell->terminalProcessName, "com.termux") != 0) + if(ffStrbufCompS(&terminal->processName, "com.termux") != 0) { ffStrbufSetS(&terminalFont->error, "Unsupported terminal"); return; diff --git a/src/detection/terminalfont/terminalfont_apple.m b/src/detection/terminalfont/terminalfont_apple.m index 871462109..65c148710 100644 --- a/src/detection/terminalfont/terminalfont_apple.m +++ b/src/detection/terminalfont/terminalfont_apple.m @@ -91,13 +91,13 @@ static void detectWarpTerminal(FFTerminalFontResult* terminalFont) ffFontInitValues(&terminalFont->font, fontName.UTF8String, fontSize.UTF8String); } -void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont) +void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { - if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "iterm.app") == 0 || - ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "iTermServer-")) + if(ffStrbufIgnCaseCompS(&terminal->processName, "iterm.app") == 0 || + ffStrbufStartsWithIgnCaseS(&terminal->processName, "iTermServer-")) detectIterm2(terminalFont); - else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "Apple_Terminal") == 0) + else if(ffStrbufIgnCaseCompS(&terminal->processName, "Apple_Terminal") == 0) detectAppleTerminal(terminalFont); - else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "WarpTerminal") == 0) + else if(ffStrbufIgnCaseCompS(&terminal->processName, "WarpTerminal") == 0) detectWarpTerminal(terminalFont); } diff --git a/src/detection/terminalfont/terminalfont_linux.c b/src/detection/terminalfont/terminalfont_linux.c index a8fc901bb..8f163418e 100644 --- a/src/detection/terminalfont/terminalfont_linux.c +++ b/src/detection/terminalfont/terminalfont_linux.c @@ -303,32 +303,32 @@ static void detectSt(FFTerminalFontResult* terminalFont, uint32_t pid) ffFontInitValues(&terminalFont->font, font.chars, size.chars); } -void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont) +void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { - if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "konsole")) + if(ffStrbufIgnCaseEqualS(&terminal->processName, "konsole")) detectKonsole(terminalFont, "konsolerc"); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "yakuake")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "yakuake")) detectKonsole(terminalFont, "yakuakerc"); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "xfce4-terminal")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "xfce4-terminal")) detectXFCETerminal(terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "lxterminal")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "lxterminal")) detectFromConfigFile("lxterminal/lxterminal.conf", "fontname =", terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "tilix")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "tilix")) detectFromGSettings("/com/gexperts/Tilix/profiles/", "com.gexperts.Tilix.ProfilesList", "com.gexperts.Tilix.Profile", "default", terminalFont); - else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "gnome-terminal-")) + else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "gnome-terminal-")) detectFromGSettings("/org/gnome/terminal/legacy/profiles:/:", "org.gnome.Terminal.ProfilesList", "org.gnome.Terminal.Legacy.Profile", "default", terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "kgx")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "kgx")) detectKgx(terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "mate-terminal")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "mate-terminal")) detectFromGSettings("/org/mate/terminal/profiles/", "org.mate.terminal.global", "org.mate.terminal.profile", "default-profile", terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "deepin-terminal")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "deepin-terminal")) detectDeepinTerminal(terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "foot")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "foot")) detectFootTerminal(terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "qterminal")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "qterminal")) detectQTerminal(terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "xterm")) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "xterm")) detectXterm(terminalFont); - else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "st")) - detectSt(terminalFont, terminalShell->terminalPid); + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "st")) + detectSt(terminalFont, terminal->pid); } diff --git a/src/detection/terminalfont/terminalfont_windows.c b/src/detection/terminalfont/terminalfont_windows.c index e461986dd..7e9e526cc 100644 --- a/src/detection/terminalfont/terminalfont_windows.c +++ b/src/detection/terminalfont/terminalfont_windows.c @@ -85,12 +85,12 @@ static void detectConEmu(FFTerminalFontResult* terminalFont) ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars); } -void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont) +void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { - if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "mintty") == 0) + if(ffStrbufIgnCaseCompS(&terminal->processName, "mintty") == 0) detectMintty(terminalFont); - else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "conhost.exe") == 0) + else if(ffStrbufIgnCaseCompS(&terminal->processName, "conhost.exe") == 0) detectConhost(terminalFont); - else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "ConEmu")) + else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "ConEmu")) detectConEmu(terminalFont); } diff --git a/src/detection/terminalshell/terminalshell.h b/src/detection/terminalshell/terminalshell.h index 3dbb0633f..6f050d01a 100644 --- a/src/detection/terminalshell/terminalshell.h +++ b/src/detection/terminalshell/terminalshell.h @@ -2,21 +2,28 @@ #include "fastfetch.h" -typedef struct FFTerminalShellResult +typedef struct FFShellResult { - FFstrbuf shellProcessName; - FFstrbuf shellExe; - const char* shellExeName; //pointer to a char in shellExe - FFstrbuf shellPrettyName; - FFstrbuf shellVersion; - uint32_t shellPid; + FFstrbuf processName; + FFstrbuf exe; + const char* exeName; //pointer to a char in exe + FFstrbuf prettyName; + FFstrbuf version; + uint32_t pid; + uint32_t ppid; +} FFShellResult; - FFstrbuf terminalProcessName; - FFstrbuf terminalExe; - FFstrbuf terminalPrettyName; - const char* terminalExeName; //pointer to a char in terminalExe - FFstrbuf terminalVersion; - uint32_t terminalPid; -} FFTerminalShellResult; +typedef struct FFTerminalResult +{ -const FFTerminalShellResult* ffDetectTerminalShell(); + FFstrbuf processName; + FFstrbuf exe; + FFstrbuf prettyName; + const char* exeName; //pointer to a char in exe + FFstrbuf version; + uint32_t pid; + uint32_t ppid; +} FFTerminalResult; + +const FFShellResult* ffDetectShell(); +const FFTerminalResult* ffDetectTerminal(); diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index cea214ca7..dc4d2de82 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -118,7 +118,7 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) return NULL; } -static pid_t getShellInfo(FFTerminalShellResult* result, pid_t pid) +static pid_t getShellInfo(FFShellResult* result, pid_t pid) { char name[256]; name[0] = '\0'; @@ -148,13 +148,14 @@ static pid_t getShellInfo(FFTerminalShellResult* result, pid_t pid) ) return getShellInfo(result, ppid); - result->shellPid = (uint32_t) pid; - ffStrbufSetS(&result->shellProcessName, name); - getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName); + result->pid = (uint32_t) pid; + result->ppid = (uint32_t) ppid; + ffStrbufSetS(&result->processName, name); + getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); return ppid; } -static pid_t getTerminalInfo(FFTerminalShellResult* result, pid_t pid) +static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) { char name[256]; name[0] = '\0'; @@ -191,29 +192,29 @@ static pid_t getTerminalInfo(FFTerminalShellResult* result, pid_t pid) getProcessNameAndPpid(ppid, name, &ppid); #endif - result->terminalPid = (uint32_t) pid; - ffStrbufSetS(&result->terminalProcessName, name); - getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName); + result->pid = (uint32_t) pid; + ffStrbufSetS(&result->processName, name); + getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); return ppid; } -static void getTerminalFromEnv(FFTerminalShellResult* result) +static void getTerminalFromEnv(FFTerminalResult* result) { if( - result->terminalProcessName.length > 0 && - !ffStrbufStartsWithIgnCaseS(&result->terminalProcessName, "login") && - !ffStrbufIgnCaseEqualS(&result->terminalProcessName, "(login)") && + result->processName.length > 0 && + !ffStrbufStartsWithIgnCaseS(&result->processName, "login") && + !ffStrbufIgnCaseEqualS(&result->processName, "(login)") && #ifdef __APPLE__ - !ffStrbufIgnCaseEqualS(&result->terminalProcessName, "launchd") && - !ffStrbufIgnCaseEqualS(&result->terminalProcessName, "stable") && //for WarpTerminal + !ffStrbufIgnCaseEqualS(&result->processName, "launchd") && + !ffStrbufIgnCaseEqualS(&result->processName, "stable") && //for WarpTerminal #else - !ffStrbufIgnCaseEqualS(&result->terminalProcessName, "systemd") && - !ffStrbufIgnCaseEqualS(&result->terminalProcessName, "init") && - !ffStrbufIgnCaseEqualS(&result->terminalProcessName, "(init)") && + !ffStrbufIgnCaseEqualS(&result->processName, "systemd") && + !ffStrbufIgnCaseEqualS(&result->processName, "init") && + !ffStrbufIgnCaseEqualS(&result->processName, "(init)") && #endif - ffStrbufIgnCaseCompS(&result->terminalProcessName, "0") != 0 + ffStrbufIgnCaseCompS(&result->processName, "0") != 0 ) return; const char* term = NULL; @@ -274,20 +275,20 @@ static void getTerminalFromEnv(FFTerminalShellResult* result) if(ffStrSet(term)) { - ffStrbufSetS(&result->terminalProcessName, term); - ffStrbufSetS(&result->terminalExe, term); - setExeName(&result->terminalExe, &result->terminalExeName); + ffStrbufSetS(&result->processName, term); + ffStrbufSetS(&result->exe, term); + setExeName(&result->exe, &result->exeName); } } -static void getUserShellFromEnv(FFTerminalShellResult* result) +static void getUserShellFromEnv(FFShellResult* result) { //If shell detection via processes failed - if(result->shellProcessName.length == 0 && instance.state.platform.userShell.length > 0) + if(result->processName.length == 0 && instance.state.platform.userShell.length > 0) { - ffStrbufSet(&result->shellExe, &instance.state.platform.userShell); - setExeName(&result->shellExe, &result->shellExeName); - ffStrbufAppendS(&result->shellProcessName, result->shellExeName); + ffStrbufSet(&result->exe, &instance.state.platform.userShell); + setExeName(&result->exe, &result->exeName); + ffStrbufAppendS(&result->processName, result->exeName); } } @@ -295,114 +296,129 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version); -static void setShellInfoDetails(FFTerminalShellResult* result) +static void setShellInfoDetails(FFShellResult* result) { - ffStrbufClear(&result->shellVersion); - fftsGetShellVersion(&result->shellExe, result->shellExeName, &result->shellVersion); + ffStrbufClear(&result->version); + fftsGetShellVersion(&result->exe, result->exeName, &result->version); - if(ffStrbufEqualS(&result->shellProcessName, "pwsh")) - ffStrbufInitStatic(&result->shellPrettyName, "PowerShell"); - else if(ffStrbufEqualS(&result->shellProcessName, "nu")) - ffStrbufInitStatic(&result->shellPrettyName, "nushell"); - else if(ffStrbufIgnCaseEqualS(&result->shellProcessName, "python") && getenv("XONSH_VERSION")) - ffStrbufInitStatic(&result->shellPrettyName, "xonsh"); - else if(ffStrbufIgnCaseEqualS(&result->shellProcessName, "oil.ovm")) - ffStrbufInitStatic(&result->shellPrettyName, "Oils"); + if(ffStrbufEqualS(&result->processName, "pwsh")) + ffStrbufInitStatic(&result->prettyName, "PowerShell"); + else if(ffStrbufEqualS(&result->processName, "nu")) + ffStrbufInitStatic(&result->prettyName, "nushell"); + else if(ffStrbufIgnCaseEqualS(&result->processName, "python") && getenv("XONSH_VERSION")) + ffStrbufInitStatic(&result->prettyName, "xonsh"); + else if(ffStrbufIgnCaseEqualS(&result->processName, "oil.ovm")) + ffStrbufInitStatic(&result->prettyName, "Oils"); else { // https://github.com/fastfetch-cli/fastfetch/discussions/280#discussioncomment-3831734 - ffStrbufInitS(&result->shellPrettyName, result->shellExeName); + ffStrbufInitS(&result->prettyName, result->exeName); } } -static void setTerminalInfoDetails(FFTerminalShellResult* result) +static void setTerminalInfoDetails(FFTerminalResult* result) { - if(result->terminalExeName[0] == '.' && ffStrEndsWith(result->terminalExeName, "-wrapped")) + if(result->exeName[0] == '.' && ffStrEndsWith(result->exeName, "-wrapped")) { // For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428 - // We use terminalProcessName when detecting version and font, overriding it for simplification + // We use processName when detecting version and font, overriding it for simplification ffStrbufSetNS( - &result->terminalProcessName, - (uint32_t) (strlen(result->terminalExeName) - strlen(".-wrapped")), - result->terminalExeName + 1); + &result->processName, + (uint32_t) (strlen(result->exeName) - strlen(".-wrapped")), + result->exeName + 1); } - if(ffStrbufEqualS(&result->terminalProcessName, "wezterm-gui")) - ffStrbufInitStatic(&result->terminalPrettyName, "WezTerm"); - if(ffStrbufStartsWithS(&result->terminalProcessName, "tmux:")) - ffStrbufInitStatic(&result->terminalPrettyName, "tmux"); + if(ffStrbufEqualS(&result->processName, "wezterm-gui")) + ffStrbufInitStatic(&result->prettyName, "WezTerm"); + if(ffStrbufStartsWithS(&result->processName, "tmux:")) + ffStrbufInitStatic(&result->prettyName, "tmux"); #if defined(__ANDROID__) - else if(ffStrbufEqualS(&result->terminalProcessName, "com.termux")) - ffStrbufInitStatic(&result->terminalPrettyName, "Termux"); + else if(ffStrbufEqualS(&result->processName, "com.termux")) + ffStrbufInitStatic(&result->prettyName, "Termux"); #elif defined(__linux__) || defined(__FreeBSD__) - else if(ffStrbufStartsWithS(&result->terminalProcessName, "gnome-terminal-")) - ffStrbufInitStatic(&result->terminalPrettyName, "GNOME Terminal"); - else if(ffStrbufStartsWithS(&result->terminalProcessName, "kgx")) - ffStrbufInitStatic(&result->terminalPrettyName, "GNOME Console"); - else if(ffStrbufEqualS(&result->terminalProcessName, "urxvt") || - ffStrbufEqualS(&result->terminalProcessName, "urxvtd") || - ffStrbufEqualS(&result->terminalProcessName, "rxvt") + else if(ffStrbufStartsWithS(&result->processName, "gnome-terminal-")) + ffStrbufInitStatic(&result->prettyName, "GNOME Terminal"); + else if(ffStrbufStartsWithS(&result->processName, "kgx")) + ffStrbufInitStatic(&result->prettyName, "GNOME Console"); + else if(ffStrbufEqualS(&result->processName, "urxvt") || + ffStrbufEqualS(&result->processName, "urxvtd") || + ffStrbufEqualS(&result->processName, "rxvt") ) - ffStrbufInitStatic(&result->terminalPrettyName, "rxvt-unicode"); + ffStrbufInitStatic(&result->prettyName, "rxvt-unicode"); #elif defined(__APPLE__) - else if(ffStrbufEqualS(&result->terminalProcessName, "iTerm.app") || ffStrbufStartsWithS(&result->terminalProcessName, "iTermServer-")) - ffStrbufInitStatic(&result->terminalPrettyName, "iTerm"); - else if(ffStrbufEqualS(&result->terminalProcessName, "Apple_Terminal")) - ffStrbufInitStatic(&result->terminalPrettyName, "Apple Terminal"); - else if(ffStrbufEqualS(&result->terminalProcessName, "WarpTerminal")) - ffStrbufInitStatic(&result->terminalPrettyName, "Warp"); + else if(ffStrbufEqualS(&result->processName, "iTerm.app") || ffStrbufStartsWithS(&result->processName, "iTermServer-")) + ffStrbufInitStatic(&result->prettyName, "iTerm"); + else if(ffStrbufEqualS(&result->processName, "Apple_Terminal")) + ffStrbufInitStatic(&result->prettyName, "Apple Terminal"); + else if(ffStrbufEqualS(&result->processName, "WarpTerminal")) + ffStrbufInitStatic(&result->prettyName, "Warp"); #endif - else if(strncmp(result->terminalExeName, result->terminalProcessName.chars, result->terminalProcessName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName - ffStrbufInitS(&result->terminalPrettyName, result->terminalExeName); + else if(strncmp(result->exeName, result->processName.chars, result->processName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName + ffStrbufInitS(&result->prettyName, result->exeName); else - ffStrbufInitCopy(&result->terminalPrettyName, &result->terminalProcessName); + ffStrbufInitCopy(&result->prettyName, &result->processName); - ffStrbufInit(&result->terminalVersion); - fftsGetTerminalVersion(&result->terminalProcessName, &result->terminalExe, &result->terminalVersion); + ffStrbufInit(&result->version); + fftsGetTerminalVersion(&result->processName, &result->exe, &result->version); } -const FFTerminalShellResult* ffDetectTerminalShell() +#ifdef __APPLE__ +#define FF_EXE_PATH_LEN PROC_PIDPATHINFO_MAXSIZE +#elif defined(MAXPATH) +#define FF_EXE_PATH_LEN MAXPATH +#elif defined(PATH_MAX) +#define FF_EXE_PATH_LEN PATH_MAX +#else +#define FF_EXE_PATH_LEN 260 +#endif + +const FFShellResult* ffDetectShell() { - static FFTerminalShellResult result; + static FFShellResult result; static bool init = false; if(init) return &result; init = true; - #ifdef __APPLE__ - const uint32_t exePathLen = PROC_PIDPATHINFO_MAXSIZE; - #elif defined(MAXPATH) - const uint32_t exePathLen = MAXPATH; - #elif defined(PATH_MAX) - const uint32_t exePathLen = PATH_MAX; - #else - const uint32_t exePathLen = 260; - #endif - - ffStrbufInit(&result.shellProcessName); - ffStrbufInitA(&result.shellExe, exePathLen); - result.shellExeName = result.shellExe.chars; - ffStrbufInit(&result.shellVersion); - result.shellPid = 0; - - ffStrbufInit(&result.terminalProcessName); - ffStrbufInitA(&result.terminalExe, exePathLen); - result.terminalExeName = result.terminalExe.chars; - result.terminalPid = 0; + ffStrbufInit(&result.processName); + ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN); + result.exeName = result.exe.chars; + ffStrbufInit(&result.version); + result.pid = 0; + result.ppid = 0; pid_t ppid = getppid(); ppid = getShellInfo(&result, ppid); getUserShellFromEnv(&result); setShellInfoDetails(&result); + return &result; +} + +const FFTerminalResult* ffDetectTerminal() +{ + static FFTerminalResult result; + static bool init = false; + if(init) + return &result; + init = true; + + ffStrbufInit(&result.processName); + ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN); + result.exeName = result.exe.chars; + result.pid = 0; + result.ppid = 0; + + pid_t ppid = (pid_t) ffDetectShell()->ppid; + if (ppid) ppid = getTerminalInfo(&result, ppid); getTerminalFromEnv(&result); diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index ac5ad1872..29ff9b5cc 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -83,47 +83,48 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); -static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) +static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) { uint32_t ppid; - if(pid == 0 || !getProcessInfo(pid, &ppid, &result->shellProcessName, &result->shellExe, &result->shellExeName)) + if(pid == 0 || !getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName)) return 0; - ffStrbufSet(&result->shellPrettyName, &result->shellProcessName); - if(ffStrbufEndsWithIgnCaseS(&result->shellPrettyName, ".exe")) - ffStrbufSubstrBefore(&result->shellPrettyName, result->shellPrettyName.length - 4); + ffStrbufSet(&result->prettyName, &result->processName); + if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) + ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); //Common programs that are between terminal and own process, but are not the shell if( - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "sudo") || - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "su") || - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "doas") || - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "strace") || - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "sshd") || - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "gdb") || - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "lldb") || - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "guake-wrapped") || - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "fastfetch") || //scoop warps the real binaries with a "shim" exe - ffStrbufIgnCaseEqualS(&result->shellPrettyName, "flashfetch") || - ffStrbufContainIgnCaseS(&result->shellPrettyName, "debug") || - ffStrbufStartsWithIgnCaseS(&result->shellPrettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014 + ffStrbufIgnCaseEqualS(&result->prettyName, "sudo") || + ffStrbufIgnCaseEqualS(&result->prettyName, "su") || + ffStrbufIgnCaseEqualS(&result->prettyName, "doas") || + ffStrbufIgnCaseEqualS(&result->prettyName, "strace") || + ffStrbufIgnCaseEqualS(&result->prettyName, "sshd") || + ffStrbufIgnCaseEqualS(&result->prettyName, "gdb") || + ffStrbufIgnCaseEqualS(&result->prettyName, "lldb") || + ffStrbufIgnCaseEqualS(&result->prettyName, "guake-wrapped") || + ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || //scoop warps the real binaries with a "shim" exe + ffStrbufIgnCaseEqualS(&result->prettyName, "flashfetch") || + ffStrbufContainIgnCaseS(&result->prettyName, "debug") || + ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014 ) { - ffStrbufClear(&result->shellProcessName); - ffStrbufClear(&result->shellPrettyName); - ffStrbufClear(&result->shellExe); - result->shellExeName = NULL; + ffStrbufClear(&result->processName); + ffStrbufClear(&result->prettyName); + ffStrbufClear(&result->exe); + result->exeName = NULL; return getShellInfo(result, ppid); } - ffStrbufClear(&result->shellVersion); - fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion); + ffStrbufClear(&result->version); + fftsGetShellVersion(&result->exe, result->prettyName.chars, &result->version); - result->shellPid = pid; + result->pid = pid; + result->ppid = ppid; - if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer")) + if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")) { - ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell + ffStrbufSetS(&result->prettyName, "Windows Explorer"); // Started without shell // In this case, terminal process will be created by fastfetch itself. ppid = 0; } @@ -131,20 +132,20 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) return ppid; } -static void setShellInfoDetails(FFTerminalShellResult* result) +static void setShellInfoDetails(FFShellResult* result) { - if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh")) - ffStrbufSetS(&result->shellPrettyName, "PowerShell"); - else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell")) - ffStrbufSetS(&result->shellPrettyName, "Windows PowerShell"); - else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell_ise")) - ffStrbufSetS(&result->shellPrettyName, "Windows PowerShell ISE"); - else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "cmd")) + if(ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh")) + ffStrbufSetS(&result->prettyName, "PowerShell"); + else if(ffStrbufIgnCaseEqualS(&result->prettyName, "powershell")) + ffStrbufSetS(&result->prettyName, "Windows PowerShell"); + else if(ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise")) + ffStrbufSetS(&result->prettyName, "Windows PowerShell ISE"); + else if(ffStrbufIgnCaseEqualS(&result->prettyName, "cmd")) { - ffStrbufClear(&result->shellPrettyName); + ffStrbufClear(&result->prettyName); FF_AUTO_CLOSE_FD HANDLE snapshot = NULL; - while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, result->shellPid)) && GetLastError() == ERROR_BAD_LENGTH) {} + while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, result->pid)) && GetLastError() == ERROR_BAD_LENGTH) {} if(snapshot) { @@ -154,27 +155,27 @@ static void setShellInfoDetails(FFTerminalShellResult* result) { if(wcsncmp(module.szModule, L"clink_dll_", strlen("clink_dll_")) == 0) { - ffStrbufAppendS(&result->shellPrettyName, "CMD (with Clink "); - getProductVersion(module.szExePath, &result->shellPrettyName); - ffStrbufAppendC(&result->shellPrettyName, ')'); + ffStrbufAppendS(&result->prettyName, "CMD (with Clink "); + getProductVersion(module.szExePath, &result->prettyName); + ffStrbufAppendC(&result->prettyName, ')'); break; } } } - if(result->shellPrettyName.length == 0) - ffStrbufAppendS(&result->shellPrettyName, "Command Prompt"); + if(result->prettyName.length == 0) + ffStrbufAppendS(&result->prettyName, "Command Prompt"); } - else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "nu")) - ffStrbufSetS(&result->shellPrettyName, "nushell"); - else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer")) - ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); + else if(ffStrbufIgnCaseEqualS(&result->prettyName, "nu")) + ffStrbufSetS(&result->prettyName, "nushell"); + else if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")) + ffStrbufSetS(&result->prettyName, "Windows Explorer"); } -static bool getTerminalFromEnv(FFTerminalShellResult* result) +static bool getTerminalFromEnv(FFTerminalResult* result) { if( - result->terminalProcessName.length > 0 && - ffStrbufIgnCaseCompS(&result->terminalProcessName, "explorer") != 0 + result->processName.length > 0 && + ffStrbufIgnCaseCompS(&result->processName, "explorer") != 0 ) return false; const char* term = getenv("ConEmuPID"); @@ -183,12 +184,12 @@ static bool getTerminalFromEnv(FFTerminalShellResult* result) { //ConEmu uint32_t pid = (uint32_t) strtoul(term, NULL, 10); - result->terminalPid = pid; - if(getProcessInfo(pid, NULL, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName)) + result->pid = pid; + if(getProcessInfo(pid, NULL, &result->processName, &result->exe, &result->exeName)) { - ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName); - if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe")) - ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4); + ffStrbufSet(&result->prettyName, &result->processName); + if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) + ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); return true; } else @@ -223,17 +224,17 @@ static bool getTerminalFromEnv(FFTerminalShellResult* result) if(term) { - ffStrbufSetS(&result->terminalProcessName, term); - ffStrbufSetS(&result->terminalPrettyName, term); - ffStrbufSetS(&result->terminalExe, term); - result->terminalExeName = ""; + ffStrbufSetS(&result->processName, term); + ffStrbufSetS(&result->prettyName, term); + ffStrbufSetS(&result->exe, term); + result->exeName = ""; return true; } return false; } -static bool detectDefaultTerminal(FFTerminalShellResult* result) +static bool detectDefaultTerminal(FFTerminalResult* result) { wchar_t regPath[128] = L"SOFTWARE\\Classes\\PackagedCom\\ClassIndex\\"; wchar_t* uuid = regPath + strlen("SOFTWARE\\Classes\\PackagedCom\\ClassIndex\\"); @@ -258,18 +259,18 @@ static bool detectDefaultTerminal(FFTerminalShellResult* result) { if (ffStrbufStartsWithS(&path, "Microsoft.WindowsTerminal")) { - ffStrbufSetS(&result->terminalProcessName, "WindowsTerminal.exe"); - ffStrbufSetS(&result->terminalPrettyName, "WindowsTerminal"); - ffStrbufSetF(&result->terminalExe, "%s\\WindowsApps\\%s\\WindowsTerminal.exe", getenv("ProgramFiles"), path.chars); - if(ffPathExists(result->terminalExe.chars, FF_PATHTYPE_FILE)) + ffStrbufSetS(&result->processName, "WindowsTerminal.exe"); + ffStrbufSetS(&result->prettyName, "WindowsTerminal"); + ffStrbufSetF(&result->exe, "%s\\WindowsApps\\%s\\WindowsTerminal.exe", getenv("ProgramFiles"), path.chars); + if(ffPathExists(result->exe.chars, FF_PATHTYPE_FILE)) { - result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\') + 1; + result->exeName = result->exe.chars + ffStrbufLastIndexC(&result->exe, '\\') + 1; } else { - ffStrbufDestroy(&result->terminalExe); - ffStrbufInitMove(&result->terminalExe, &path); - result->terminalExeName = ""; + ffStrbufDestroy(&result->exe); + ffStrbufInitMove(&result->exe, &path); + result->exeName = ""; } return true; } @@ -278,111 +279,109 @@ static bool detectDefaultTerminal(FFTerminalShellResult* result) } conhost: - ffStrbufSetF(&result->terminalExe, "%s\\System32\\conhost.exe", getenv("SystemRoot")); - if(ffPathExists(result->terminalExe.chars, FF_PATHTYPE_FILE)) + ffStrbufSetF(&result->exe, "%s\\System32\\conhost.exe", getenv("SystemRoot")); + if(ffPathExists(result->exe.chars, FF_PATHTYPE_FILE)) { - ffStrbufSetS(&result->terminalProcessName, "conhost.exe"); - ffStrbufSetS(&result->terminalPrettyName, "conhost"); - result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\') + 1; + ffStrbufSetS(&result->processName, "conhost.exe"); + ffStrbufSetS(&result->prettyName, "conhost"); + result->exeName = result->exe.chars + ffStrbufLastIndexC(&result->exe, '\\') + 1; return true; } - ffStrbufClear(&result->terminalExe); + ffStrbufClear(&result->exe); return false; } -static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) +static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid) { uint32_t ppid; - if(pid == 0 || !getProcessInfo(pid, &ppid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName)) + if(pid == 0 || !getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName)) return 0; - ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName); - if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe")) - ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4); + ffStrbufSet(&result->prettyName, &result->processName); + if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) + ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); if( - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "pwsh") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "cmd") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "bash") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "zsh") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "fish") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "nu") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "powershell") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "powershell_ise") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "wsl") || // running inside wsl - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "servercoreshell") || // ServerCore Shell Launcher - ffStrbufStartsWithIgnCaseS(&result->terminalPrettyName, "ConEmuC") // wrapper process of ConEmu + ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh") || + ffStrbufIgnCaseEqualS(&result->prettyName, "cmd") || + ffStrbufIgnCaseEqualS(&result->prettyName, "bash") || + ffStrbufIgnCaseEqualS(&result->prettyName, "zsh") || + ffStrbufIgnCaseEqualS(&result->prettyName, "fish") || + ffStrbufIgnCaseEqualS(&result->prettyName, "nu") || + ffStrbufIgnCaseEqualS(&result->prettyName, "powershell") || + ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise") || + ffStrbufIgnCaseEqualS(&result->prettyName, "wsl") || // running inside wsl + ffStrbufIgnCaseEqualS(&result->prettyName, "servercoreshell") || // ServerCore Shell Launcher + ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmuC") // wrapper process of ConEmu ) { //We are nested shell - ffStrbufClear(&result->terminalProcessName); - ffStrbufClear(&result->terminalPrettyName); - ffStrbufClear(&result->terminalExe); - result->terminalExeName = ""; + ffStrbufClear(&result->processName); + ffStrbufClear(&result->prettyName); + ffStrbufClear(&result->exe); + result->exeName = ""; return getTerminalInfo(result, ppid); } - if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "sihost") || - ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer") + if(ffStrbufIgnCaseEqualS(&result->prettyName, "sihost") || + ffStrbufIgnCaseEqualS(&result->prettyName, "explorer") ) { // A CUI program created by Windows Explorer will spawn a conhost as its child. // However the conhost process is just a placeholder; // The true terminal can be Windows Terminal or others. if (!getTerminalFromEnv(result) && !detectDefaultTerminal(result)) { - ffStrbufClear(&result->terminalProcessName); - ffStrbufClear(&result->terminalPrettyName); - ffStrbufClear(&result->terminalExe); - result->terminalExeName = ""; + ffStrbufClear(&result->processName); + ffStrbufClear(&result->prettyName); + ffStrbufClear(&result->exe); + result->exeName = ""; return 0; } } else - result->terminalPid = pid; + { + result->pid = pid; + result->ppid = ppid; + } return ppid; } -static void setTerminalInfoDetails(FFTerminalShellResult* result) +static void setTerminalInfoDetails(FFTerminalResult* result) { - if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal")) - ffStrbufSetStatic(&result->terminalPrettyName, ffStrbufContainIgnCaseS(&result->terminalExe, ".WindowsTerminalPreview_") + if(ffStrbufIgnCaseEqualS(&result->prettyName, "WindowsTerminal")) + ffStrbufSetStatic(&result->prettyName, ffStrbufContainIgnCaseS(&result->exe, ".WindowsTerminalPreview_") ? "Windows Terminal Preview" : "Windows Terminal" ); - else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "conhost")) - ffStrbufSetStatic(&result->terminalPrettyName, "Console Window Host"); - else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "Code")) - ffStrbufSetStatic(&result->terminalPrettyName, "Visual Studio Code"); - else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer")) - ffStrbufSetStatic(&result->terminalPrettyName, "Windows Explorer"); - else if(ffStrbufEqualS(&result->terminalPrettyName, "wezterm-gui")) - ffStrbufSetStatic(&result->terminalPrettyName, "WezTerm"); + else if(ffStrbufIgnCaseEqualS(&result->prettyName, "conhost")) + ffStrbufSetStatic(&result->prettyName, "Console Window Host"); + else if(ffStrbufIgnCaseEqualS(&result->prettyName, "Code")) + ffStrbufSetStatic(&result->prettyName, "Visual Studio Code"); + else if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")) + ffStrbufSetStatic(&result->prettyName, "Windows Explorer"); + else if(ffStrbufEqualS(&result->prettyName, "wezterm-gui")) + ffStrbufSetStatic(&result->prettyName, "WezTerm"); } bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version); -const FFTerminalShellResult* ffDetectTerminalShell(void) +const FFShellResult* ffDetectShell(void) { - static FFTerminalShellResult result; + static FFShellResult result; static bool init = false; if(init) return &result; init = true; - ffStrbufInit(&result.shellProcessName); - ffStrbufInitA(&result.shellExe, 128); - result.shellExeName = ""; - ffStrbufInit(&result.shellPrettyName); - ffStrbufInit(&result.shellVersion); - result.shellPid = 0; - - ffStrbufInit(&result.terminalProcessName); - ffStrbufInitA(&result.terminalExe, 128); - result.terminalExeName = ""; - ffStrbufInit(&result.terminalPrettyName); - result.terminalPid = 0; + ffStrbufInit(&result.processName); + ffStrbufInitA(&result.exe, 128); + result.exeName = ""; + ffStrbufInit(&result.prettyName); + ffStrbufInit(&result.version); + result.pid = 0; + result.ppid = 0; uint32_t ppid; if(!getProcessInfo(0, &ppid, NULL, NULL, NULL)) @@ -391,16 +390,35 @@ const FFTerminalShellResult* ffDetectTerminalShell(void) ppid = getShellInfo(&result, ppid); setShellInfoDetails(&result); + return &result; +} + +const FFTerminalResult* ffDetectTerminal(void) +{ + static FFTerminalResult result; + static bool init = false; + if(init) + return &result; + init = true; + + ffStrbufInit(&result.processName); + ffStrbufInitA(&result.exe, 128); + result.exeName = ""; + ffStrbufInit(&result.prettyName); + ffStrbufInit(&result.version); + result.pid = 0; + result.ppid = 0; + + uint32_t ppid = ffDetectShell()->ppid; if(ppid) getTerminalInfo(&result, ppid); - if(result.terminalProcessName.length == 0) + if(result.processName.length == 0) getTerminalFromEnv(&result); setTerminalInfoDetails(&result); - ffStrbufInit(&result.terminalVersion); - fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion); + fftsGetTerminalVersion(&result.processName, &result.exe, &result.version); return &result; } diff --git a/src/detection/wm/wm_windows.cpp b/src/detection/wm/wm_windows.cpp index 941052830..583cf2149 100644 --- a/src/detection/wm/wm_windows.cpp +++ b/src/detection/wm/wm_windows.cpp @@ -25,7 +25,7 @@ private: extern "C" const char* ffDetectWMPlugin(FFstrbuf* pluginName) { - DWORD pid = ffDetectTerminalShell()->terminalPid; // Whatever GUI program + DWORD pid = ffDetectTerminal()->pid; // Whatever GUI program if (pid == 0) return "Unable to find a GUI program"; FF_AUTO_CLOSE_FD HANDLE snapshot = NULL; diff --git a/src/logo/logo.c b/src/logo/logo.c index 6fa0610a8..4aa78bd06 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -498,14 +498,14 @@ void ffLogoPrint(void) //Make sure the logo path is set correctly. updateLogoPath(); - const FFTerminalShellResult* terminalShell = ffDetectTerminalShell(); + const FFTerminalResult* terminal = ffDetectTerminal(); //Terminal emulators that support kitty graphics protocol. bool supportsKitty = - ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "kitty") == 0 || - ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "konsole") == 0 || - ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wezterm") == 0 || - ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wayst") == 0; + ffStrbufIgnCaseCompS(&terminal->processName, "kitty") == 0 || + ffStrbufIgnCaseCompS(&terminal->processName, "konsole") == 0 || + ffStrbufIgnCaseCompS(&terminal->processName, "wezterm") == 0 || + ffStrbufIgnCaseCompS(&terminal->processName, "wayst") == 0; //Try to load the logo as an image. If it succeeds, print it and return. if(logoPrintImageIfExists(supportsKitty ? FF_LOGO_TYPE_IMAGE_KITTY : FF_LOGO_TYPE_IMAGE_CHAFA, false)) diff --git a/src/modules/shell/shell.c b/src/modules/shell/shell.c index cc8cb6170..9bb590eea 100644 --- a/src/modules/shell/shell.c +++ b/src/modules/shell/shell.c @@ -8,9 +8,9 @@ void ffPrintShell(FFShellOptions* options) { - const FFTerminalShellResult* result = ffDetectTerminalShell(); + const FFShellResult* result = ffDetectShell(); - if(result->shellProcessName.length == 0) + if(result->processName.length == 0) { ffPrintError(FF_SHELL_MODULE_NAME, 0, &options->moduleArgs, "Couldn't detect shell"); return; @@ -19,12 +19,12 @@ void ffPrintShell(FFShellOptions* options) if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_SHELL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - ffStrbufWriteTo(&result->shellPrettyName, stdout); + ffStrbufWriteTo(&result->prettyName, stdout); - if(result->shellVersion.length > 0) + if(result->version.length > 0) { putchar(' '); - ffStrbufWriteTo(&result->shellVersion, stdout); + ffStrbufWriteTo(&result->version, stdout); } putchar('\n'); @@ -32,12 +32,12 @@ void ffPrintShell(FFShellOptions* options) else { ffPrintFormat(FF_SHELL_MODULE_NAME, 0, &options->moduleArgs, FF_SHELL_NUM_FORMAT_ARGS, (FFformatarg[]) { - {FF_FORMAT_ARG_TYPE_STRBUF, &result->shellProcessName}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->shellExe}, - {FF_FORMAT_ARG_TYPE_STRING, result->shellExeName}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->shellVersion}, - {FF_FORMAT_ARG_TYPE_UINT, &result->shellPid}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->shellPrettyName}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->processName}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->exe}, + {FF_FORMAT_ARG_TYPE_STRING, result->exeName}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->version}, + {FF_FORMAT_ARG_TYPE_UINT, &result->pid}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName}, }); } } @@ -79,20 +79,21 @@ void ffGenerateShellJsonConfig(FFShellOptions* options, yyjson_mut_doc* doc, yyj void ffGenerateShellJsonResult(FF_MAYBE_UNUSED FFShellOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { - const FFTerminalShellResult* result = ffDetectTerminalShell(); + const FFShellResult* result = ffDetectShell(); - if(result->shellProcessName.length == 0) + if(result->processName.length == 0) { yyjson_mut_obj_add_str(doc, module, "error", "Couldn't detect shell"); return; } yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); - yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->shellExe); - yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->shellExeName); - yyjson_mut_obj_add_uint(doc, obj, "pid", result->shellPid); - yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->shellProcessName); - yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->shellVersion); + yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->exe); + yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->exeName); + yyjson_mut_obj_add_uint(doc, obj, "pid", result->pid); + yyjson_mut_obj_add_uint(doc, obj, "ppid", result->ppid); + yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->processName); + yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->version); } void ffPrintShellHelpFormat(void) diff --git a/src/modules/terminal/terminal.c b/src/modules/terminal/terminal.c index 02347593f..d456ea771 100644 --- a/src/modules/terminal/terminal.c +++ b/src/modules/terminal/terminal.c @@ -10,9 +10,9 @@ void ffPrintTerminal(FFTerminalOptions* options) { - const FFTerminalShellResult* result = ffDetectTerminalShell(); + const FFTerminalResult* result = ffDetectTerminal(); - if(result->terminalProcessName.length == 0) + if(result->processName.length == 0) { ffPrintError(FF_TERMINAL_MODULE_NAME, 0, &options->moduleArgs, "Couldn't detect terminal"); return; @@ -22,20 +22,20 @@ void ffPrintTerminal(FFTerminalOptions* options) { ffPrintLogoAndKey(FF_TERMINAL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); - if(result->terminalVersion.length) - printf("%s %s\n", result->terminalPrettyName.chars, result->terminalVersion.chars); + if(result->version.length) + printf("%s %s\n", result->prettyName.chars, result->version.chars); else - ffStrbufPutTo(&result->terminalPrettyName, stdout); + ffStrbufPutTo(&result->prettyName, stdout); } else { ffPrintFormat(FF_TERMINAL_MODULE_NAME, 0, &options->moduleArgs, FF_TERMINAL_NUM_FORMAT_ARGS, (FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_STRBUF, &result->terminalProcessName}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->terminalExe}, - {FF_FORMAT_ARG_TYPE_STRING, result->terminalExeName}, - {FF_FORMAT_ARG_TYPE_UINT, &result->terminalPid}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->terminalPrettyName}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->terminalVersion}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->processName}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->exe}, + {FF_FORMAT_ARG_TYPE_STRING, result->exeName}, + {FF_FORMAT_ARG_TYPE_UINT, &result->pid}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName}, + {FF_FORMAT_ARG_TYPE_STRBUF, &result->version}, }); } } @@ -77,21 +77,22 @@ void ffGenerateTerminalJsonConfig(FFTerminalOptions* options, yyjson_mut_doc* do void ffGenerateTerminalJsonResult(FF_MAYBE_UNUSED FFTerminalOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { - const FFTerminalShellResult* result = ffDetectTerminalShell(); + const FFTerminalResult* result = ffDetectTerminal(); - if(result->terminalProcessName.length == 0) + if(result->processName.length == 0) { yyjson_mut_obj_add_str(doc, module, "error", "Couldn't detect terminal"); return; } yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); - yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->terminalProcessName); - yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->terminalExe); - yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->terminalExeName); - yyjson_mut_obj_add_uint(doc, obj, "pid", result->terminalPid); - yyjson_mut_obj_add_strbuf(doc, obj, "prettyName", &result->terminalPrettyName); - yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->terminalVersion); + yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->processName); + yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->exe); + yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->exeName); + yyjson_mut_obj_add_uint(doc, obj, "pid", result->pid); + yyjson_mut_obj_add_uint(doc, obj, "ppid", result->ppid); + yyjson_mut_obj_add_strbuf(doc, obj, "prettyName", &result->prettyName); + yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->version); } void ffPrintTerminalHelpFormat(void) From 22cdb1247f887383672bd9ce069e5a7babf9082b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 12 Jan 2024 21:13:59 +0800 Subject: [PATCH 71/99] TerminalShell: tidy; use case senstive string comparation where meaningful --- .../terminalshell/terminalshell_linux.c | 84 +++++++++---------- src/util/stringUtils.h | 10 +++ 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index dc4d2de82..2ec21dc43 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -75,7 +75,7 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) char buf[PROC_FILE_BUFFSIZ]; ssize_t nRead = ffReadFileData(statFilePath, sizeof(buf) - 1, buf); if(nRead < 0) - return "ffReadFileData(statFilePath, sizeof(buf)-1, buf)"; + return "ffReadFileData(statFilePath, sizeof(buf)-1, buf) failed"; buf[nRead] = '\0'; *ppid = 0; @@ -130,20 +130,20 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid) //Common programs that are between terminal and own process, but are not the shell if( - strcasecmp(name, "sh") == 0 || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell - strcasecmp(name, "sudo") == 0 || - strcasecmp(name, "su") == 0 || - strcasecmp(name, "strace") == 0 || - strcasecmp(name, "sshd") == 0 || - strcasecmp(name, "gdb") == 0 || - strcasecmp(name, "lldb") == 0 || - strcasecmp(name, "lldb-mi") == 0 || - strcasecmp(name, "login") == 0 || - strcasecmp(name, "ltrace") == 0 || - strcasecmp(name, "perf") == 0 || - strcasecmp(name, "guake-wrapped") == 0 || - strcasestr(name, "debug") != NULL || - strcasestr(name, "command-not-found") != NULL || + ffStrEquals(name, "sh") || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell + ffStrEquals(name, "sudo") || + ffStrEquals(name, "su") || + ffStrEquals(name, "strace") || + ffStrEquals(name, "sshd") || + ffStrEquals(name, "gdb") || + ffStrEquals(name, "lldb") || + ffStrEquals(name, "lldb-mi") || + ffStrEquals(name, "login") || + ffStrEquals(name, "ltrace") || + ffStrEquals(name, "perf") || + ffStrEquals(name, "guake-wrapped") || + ffStrContainsIgnCase(name, "debug") || + ffStrContainsIgnCase(name, "not-found") || ffStrEndsWith(name, ".sh") ) return getShellInfo(result, ppid); @@ -167,22 +167,22 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) //Known shells if ( - strcasecmp(name, "ash") == 0 || - strcasecmp(name, "bash") == 0 || - strcasecmp(name, "zsh") == 0 || - strcasecmp(name, "ksh") == 0 || - strcasecmp(name, "mksh") == 0 || - strcasecmp(name, "oksh") == 0 || - strcasecmp(name, "csh") == 0 || - strcasecmp(name, "tcsh") == 0 || - strcasecmp(name, "fish") == 0 || - strcasecmp(name, "dash") == 0 || - strcasecmp(name, "pwsh") == 0 || - strcasecmp(name, "nu") == 0 || - strcasecmp(name, "git-shell") == 0 || - strcasecmp(name, "elvish") == 0 || - strcasecmp(name, "oil.ovm") == 0 || - (strcasecmp(name, "python") == 0 && getenv("XONSH_VERSION")) + ffStrEquals(name, "ash") || + ffStrEquals(name, "bash") || + ffStrEquals(name, "zsh") || + ffStrEquals(name, "ksh") || + ffStrEquals(name, "mksh") || + ffStrEquals(name, "oksh") || + ffStrEquals(name, "csh") || + ffStrEquals(name, "tcsh") || + ffStrEquals(name, "fish") || + ffStrEquals(name, "dash") || + ffStrEquals(name, "pwsh") || + ffStrEquals(name, "nu") || + ffStrEquals(name, "git-shell") || + ffStrEquals(name, "elvish") || + ffStrEquals(name, "oil.ovm") || + (ffStrEquals(name, "python") && getenv("XONSH_VERSION")) ) return getTerminalInfo(result, ppid); @@ -202,19 +202,19 @@ static void getTerminalFromEnv(FFTerminalResult* result) { if( result->processName.length > 0 && - !ffStrbufStartsWithIgnCaseS(&result->processName, "login") && - !ffStrbufIgnCaseEqualS(&result->processName, "(login)") && + !ffStrbufStartsWithS(&result->processName, "login") && + !ffStrbufEqualS(&result->processName, "(login)") && #ifdef __APPLE__ - !ffStrbufIgnCaseEqualS(&result->processName, "launchd") && - !ffStrbufIgnCaseEqualS(&result->processName, "stable") && //for WarpTerminal + !ffStrbufEqualS(&result->processName, "launchd") && + !ffStrbufEqualS(&result->processName, "stable") && //for WarpTerminal #else - !ffStrbufIgnCaseEqualS(&result->processName, "systemd") && - !ffStrbufIgnCaseEqualS(&result->processName, "init") && - !ffStrbufIgnCaseEqualS(&result->processName, "(init)") && + !ffStrbufEqualS(&result->processName, "systemd") && + !ffStrbufEqualS(&result->processName, "init") && + !ffStrbufEqualS(&result->processName, "(init)") && #endif - ffStrbufIgnCaseCompS(&result->processName, "0") != 0 + ffStrbufEqualS(&result->processName, "0") ) return; const char* term = NULL; @@ -270,7 +270,7 @@ static void getTerminalFromEnv(FFTerminalResult* result) term = getenv("TERM"); //TTY - if(!ffStrSet(term) || strcasecmp(term, "linux") == 0) + if(!ffStrSet(term) || ffStrEquals(term, "linux")) term = ttyname(STDIN_FILENO); if(ffStrSet(term)) @@ -305,9 +305,9 @@ static void setShellInfoDetails(FFShellResult* result) ffStrbufInitStatic(&result->prettyName, "PowerShell"); else if(ffStrbufEqualS(&result->processName, "nu")) ffStrbufInitStatic(&result->prettyName, "nushell"); - else if(ffStrbufIgnCaseEqualS(&result->processName, "python") && getenv("XONSH_VERSION")) + else if(ffStrbufEqualS(&result->processName, "python") && getenv("XONSH_VERSION")) ffStrbufInitStatic(&result->prettyName, "xonsh"); - else if(ffStrbufIgnCaseEqualS(&result->processName, "oil.ovm")) + else if(ffStrbufEqualS(&result->processName, "oil.ovm")) ffStrbufInitStatic(&result->prettyName, "Oils"); else { diff --git a/src/util/stringUtils.h b/src/util/stringUtils.h index e5fe80e12..4de957841 100644 --- a/src/util/stringUtils.h +++ b/src/util/stringUtils.h @@ -54,3 +54,13 @@ static inline bool ffStrEquals(const char* str, const char* compareTo) { return strcmp(str, compareTo) == 0; } + +static inline bool ffStrContains(const char* str, const char* compareTo) +{ + return strstr(str, compareTo) != NULL; +} + +static inline bool ffStrContainsIgnCase(const char* str, const char* compareTo) +{ + return strcasestr(str, compareTo) != NULL; +} From 269ad36df5807e49b8cdee1b8951ebdad78120f9 Mon Sep 17 00:00:00 2001 From: apocelipes Date: Fri, 12 Jan 2024 23:57:56 +0900 Subject: [PATCH 72/99] refactor(TerminalShell): changing recursion into loops --- .../terminalshell/terminalshell_linux.c | 125 +++++++------ .../terminalshell/terminalshell_windows.c | 168 +++++++++--------- 2 files changed, 154 insertions(+), 139 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 2ec21dc43..06f8307b6 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -125,33 +125,37 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid) pid_t ppid = 0; - if(getProcessNameAndPpid(pid, name, &ppid)) - return 0; + while (getProcessNameAndPpid(pid, name, &ppid) == NULL) + { + //Common programs that are between terminal and own process, but are not the shell + if( + ffStrEquals(name, "sh") || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell + ffStrEquals(name, "sudo") || + ffStrEquals(name, "su") || + ffStrEquals(name, "strace") || + ffStrEquals(name, "sshd") || + ffStrEquals(name, "gdb") || + ffStrEquals(name, "lldb") || + ffStrEquals(name, "lldb-mi") || + ffStrEquals(name, "login") || + ffStrEquals(name, "ltrace") || + ffStrEquals(name, "perf") || + ffStrEquals(name, "guake-wrapped") || + ffStrContainsIgnCase(name, "debug") || + ffStrContainsIgnCase(name, "not-found") || + ffStrEndsWith(name, ".sh") + ) + { + pid = ppid; + continue; + } - //Common programs that are between terminal and own process, but are not the shell - if( - ffStrEquals(name, "sh") || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell - ffStrEquals(name, "sudo") || - ffStrEquals(name, "su") || - ffStrEquals(name, "strace") || - ffStrEquals(name, "sshd") || - ffStrEquals(name, "gdb") || - ffStrEquals(name, "lldb") || - ffStrEquals(name, "lldb-mi") || - ffStrEquals(name, "login") || - ffStrEquals(name, "ltrace") || - ffStrEquals(name, "perf") || - ffStrEquals(name, "guake-wrapped") || - ffStrContainsIgnCase(name, "debug") || - ffStrContainsIgnCase(name, "not-found") || - ffStrEndsWith(name, ".sh") - ) - return getShellInfo(result, ppid); - - result->pid = (uint32_t) pid; - result->ppid = (uint32_t) ppid; - ffStrbufSetS(&result->processName, name); - getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); + result->pid = (uint32_t) pid; + result->ppid = (uint32_t) ppid; + ffStrbufSetS(&result->processName, name); + getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); + break; + } return ppid; } @@ -162,39 +166,46 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) pid_t ppid = 0; - if(getProcessNameAndPpid(pid, name, &ppid)) - return 0; + while (getProcessNameAndPpid(pid, name, &ppid) == NULL) + { + //Known shells + if ( + ffStrEquals(name, "ash") || + ffStrEquals(name, "bash") || + ffStrEquals(name, "zsh") || + ffStrEquals(name, "ksh") || + ffStrEquals(name, "mksh") || + ffStrEquals(name, "oksh") || + ffStrEquals(name, "csh") || + ffStrEquals(name, "tcsh") || + ffStrEquals(name, "fish") || + ffStrEquals(name, "dash") || + ffStrEquals(name, "pwsh") || + ffStrEquals(name, "nu") || + ffStrEquals(name, "git-shell") || + ffStrEquals(name, "elvish") || + ffStrEquals(name, "oil.ovm") || + (ffStrEquals(name, "python") && getenv("XONSH_VERSION")) + ) + { + pid = ppid; + continue; + } - //Known shells - if ( - ffStrEquals(name, "ash") || - ffStrEquals(name, "bash") || - ffStrEquals(name, "zsh") || - ffStrEquals(name, "ksh") || - ffStrEquals(name, "mksh") || - ffStrEquals(name, "oksh") || - ffStrEquals(name, "csh") || - ffStrEquals(name, "tcsh") || - ffStrEquals(name, "fish") || - ffStrEquals(name, "dash") || - ffStrEquals(name, "pwsh") || - ffStrEquals(name, "nu") || - ffStrEquals(name, "git-shell") || - ffStrEquals(name, "elvish") || - ffStrEquals(name, "oil.ovm") || - (ffStrEquals(name, "python") && getenv("XONSH_VERSION")) - ) - return getTerminalInfo(result, ppid); + #ifdef __APPLE__ + // https://github.com/fastfetch-cli/fastfetch/discussions/501 + if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)")) + { + if (__builtin_expect(getProcessNameAndPpid(ppid, name, &ppid) != NULL, false)) + return 0; + } + #endif - #ifdef __APPLE__ - // https://github.com/fastfetch-cli/fastfetch/discussions/501 - if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)")) - getProcessNameAndPpid(ppid, name, &ppid); - #endif - - result->pid = (uint32_t) pid; - ffStrbufSetS(&result->processName, name); - getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); + result->pid = (uint32_t) pid; + ffStrbufSetS(&result->processName, name); + getProcessInformation(pid, &result->processName, &result->exe, &result->exeName); + break; + } return ppid; } diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index 29ff9b5cc..a462ab566 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -87,48 +87,50 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) { uint32_t ppid; - if(pid == 0 || !getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName)) - return 0; - - ffStrbufSet(&result->prettyName, &result->processName); - if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) - ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); - - //Common programs that are between terminal and own process, but are not the shell - if( - ffStrbufIgnCaseEqualS(&result->prettyName, "sudo") || - ffStrbufIgnCaseEqualS(&result->prettyName, "su") || - ffStrbufIgnCaseEqualS(&result->prettyName, "doas") || - ffStrbufIgnCaseEqualS(&result->prettyName, "strace") || - ffStrbufIgnCaseEqualS(&result->prettyName, "sshd") || - ffStrbufIgnCaseEqualS(&result->prettyName, "gdb") || - ffStrbufIgnCaseEqualS(&result->prettyName, "lldb") || - ffStrbufIgnCaseEqualS(&result->prettyName, "guake-wrapped") || - ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || //scoop warps the real binaries with a "shim" exe - ffStrbufIgnCaseEqualS(&result->prettyName, "flashfetch") || - ffStrbufContainIgnCaseS(&result->prettyName, "debug") || - ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014 - ) { - ffStrbufClear(&result->processName); - ffStrbufClear(&result->prettyName); - ffStrbufClear(&result->exe); - result->exeName = NULL; - return getShellInfo(result, ppid); - } - - ffStrbufClear(&result->version); - fftsGetShellVersion(&result->exe, result->prettyName.chars, &result->version); - - result->pid = pid; - result->ppid = ppid; - - if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")) + while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName)) { - ffStrbufSetS(&result->prettyName, "Windows Explorer"); // Started without shell - // In this case, terminal process will be created by fastfetch itself. - ppid = 0; - } + ffStrbufSet(&result->prettyName, &result->processName); + if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) + ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); + //Common programs that are between terminal and own process, but are not the shell + if( + ffStrbufIgnCaseEqualS(&result->prettyName, "sudo") || + ffStrbufIgnCaseEqualS(&result->prettyName, "su") || + ffStrbufIgnCaseEqualS(&result->prettyName, "doas") || + ffStrbufIgnCaseEqualS(&result->prettyName, "strace") || + ffStrbufIgnCaseEqualS(&result->prettyName, "sshd") || + ffStrbufIgnCaseEqualS(&result->prettyName, "gdb") || + ffStrbufIgnCaseEqualS(&result->prettyName, "lldb") || + ffStrbufIgnCaseEqualS(&result->prettyName, "guake-wrapped") || + ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || //scoop warps the real binaries with a "shim" exe + ffStrbufIgnCaseEqualS(&result->prettyName, "flashfetch") || + ffStrbufContainIgnCaseS(&result->prettyName, "debug") || + ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014 + ) { + ffStrbufClear(&result->processName); + ffStrbufClear(&result->prettyName); + ffStrbufClear(&result->exe); + result->exeName = NULL; + pid = ppid; + continue; + } + + ffStrbufClear(&result->version); + fftsGetShellVersion(&result->exe, result->prettyName.chars, &result->version); + + result->pid = pid; + result->ppid = ppid; + + if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")) + { + ffStrbufSetS(&result->prettyName, "Windows Explorer"); // Started without shell + // In this case, terminal process will be created by fastfetch itself. + ppid = 0; + } + + break; + } return ppid; } @@ -296,55 +298,57 @@ static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid) { uint32_t ppid; - if(pid == 0 || !getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName)) - return 0; + while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName)) + { + ffStrbufSet(&result->prettyName, &result->processName); + if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) + ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); - ffStrbufSet(&result->prettyName, &result->processName); - if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) - ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); - - if( - ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh") || - ffStrbufIgnCaseEqualS(&result->prettyName, "cmd") || - ffStrbufIgnCaseEqualS(&result->prettyName, "bash") || - ffStrbufIgnCaseEqualS(&result->prettyName, "zsh") || - ffStrbufIgnCaseEqualS(&result->prettyName, "fish") || - ffStrbufIgnCaseEqualS(&result->prettyName, "nu") || - ffStrbufIgnCaseEqualS(&result->prettyName, "powershell") || - ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise") || - ffStrbufIgnCaseEqualS(&result->prettyName, "wsl") || // running inside wsl - ffStrbufIgnCaseEqualS(&result->prettyName, "servercoreshell") || // ServerCore Shell Launcher - ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmuC") // wrapper process of ConEmu - ) { - //We are nested shell - ffStrbufClear(&result->processName); - ffStrbufClear(&result->prettyName); - ffStrbufClear(&result->exe); - result->exeName = ""; - return getTerminalInfo(result, ppid); - } - - if(ffStrbufIgnCaseEqualS(&result->prettyName, "sihost") || - ffStrbufIgnCaseEqualS(&result->prettyName, "explorer") - ) { - // A CUI program created by Windows Explorer will spawn a conhost as its child. - // However the conhost process is just a placeholder; - // The true terminal can be Windows Terminal or others. - if (!getTerminalFromEnv(result) && !detectDefaultTerminal(result)) - { + if( + ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh") || + ffStrbufIgnCaseEqualS(&result->prettyName, "cmd") || + ffStrbufIgnCaseEqualS(&result->prettyName, "bash") || + ffStrbufIgnCaseEqualS(&result->prettyName, "zsh") || + ffStrbufIgnCaseEqualS(&result->prettyName, "fish") || + ffStrbufIgnCaseEqualS(&result->prettyName, "nu") || + ffStrbufIgnCaseEqualS(&result->prettyName, "powershell") || + ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise") || + ffStrbufIgnCaseEqualS(&result->prettyName, "wsl") || // running inside wsl + ffStrbufIgnCaseEqualS(&result->prettyName, "servercoreshell") || // ServerCore Shell Launcher + ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmuC") // wrapper process of ConEmu + ) { + //We are nested shell ffStrbufClear(&result->processName); ffStrbufClear(&result->prettyName); ffStrbufClear(&result->exe); result->exeName = ""; - return 0; + pid = ppid; + continue; } - } - else - { - result->pid = pid; - result->ppid = ppid; - } + if(ffStrbufIgnCaseEqualS(&result->prettyName, "sihost") || + ffStrbufIgnCaseEqualS(&result->prettyName, "explorer") + ) { + // A CUI program created by Windows Explorer will spawn a conhost as its child. + // However the conhost process is just a placeholder; + // The true terminal can be Windows Terminal or others. + if (!getTerminalFromEnv(result) && !detectDefaultTerminal(result)) + { + ffStrbufClear(&result->processName); + ffStrbufClear(&result->prettyName); + ffStrbufClear(&result->exe); + result->exeName = ""; + return 0; + } + } + else + { + result->pid = pid; + result->ppid = ppid; + } + + break; + } return ppid; } From 89db425a033355b6a27c13b009ed6093189542c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 13 Jan 2024 13:32:41 +0800 Subject: [PATCH 73/99] Gamepad (Windows): use nonblocking read to get battery information --- src/detection/gamepad/gamepad_windows.c | 40 +++++++++++++++---------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/detection/gamepad/gamepad_windows.c b/src/detection/gamepad/gamepad_windows.c index 65ee5c0f6..ab4540af0 100644 --- a/src/detection/gamepad/gamepad_windows.c +++ b/src/detection/gamepad/gamepad_windows.c @@ -103,7 +103,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) const char* knownGamepad = detectKnownDeviceName(rdi.hid.dwVendorId, rdi.hid.dwProductId); if (knownGamepad) ffStrbufSetS(&device->name, knownGamepad); - HANDLE FF_AUTO_CLOSE_FD hHidFile = CreateFileW(devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + HANDLE FF_AUTO_CLOSE_FD hHidFile = CreateFileW(devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (!hHidFile) { if (!knownGamepad) @@ -154,27 +154,35 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */) )) ) { + // Controller must be connected by other programs FF_AUTO_FREE uint8_t* reportBuffer = malloc(caps.InputReportByteLength); - ssize_t nBytes = ffReadFDData(hHidFile, caps.InputReportByteLength, reportBuffer); - if (rdi.hid.dwVendorId == 0x054C) + OVERLAPPED overlapped = { }; + DWORD nBytes; + if (ReadFile(hHidFile, reportBuffer, caps.InputReportByteLength, &nBytes, &overlapped) || + (WaitForSingleObject(hHidFile, FF_IO_TERM_RESP_WAIT_MS) == WAIT_OBJECT_0 && GetOverlappedResult(hHidFile, &overlapped, &nBytes, FALSE))) { - if (nBytes > 31) + if (rdi.hid.dwVendorId == 0x054C) { - uint8_t batteryInfo = reportBuffer[caps.InputReportByteLength == 64 /*USB?*/ ? 30 : 32]; - device->battery = (uint8_t) ((batteryInfo & 0x0f) * 100 / (batteryInfo & 0x10 /*charging?*/ ? 11 /*BATTERY_MAX_USB*/ : 8 /*BATTERY_MAX*/)); - if (device->battery > 100) device->battery = 100; + if (nBytes > 31) + { + uint8_t batteryInfo = reportBuffer[caps.InputReportByteLength == 64 /*USB?*/ ? 30 : 32]; + device->battery = (uint8_t) ((batteryInfo & 0x0f) * 100 / (batteryInfo & 0x10 /*charging?*/ ? 11 /*BATTERY_MAX_USB*/ : 8 /*BATTERY_MAX*/)); + if (device->battery > 100) device->battery = 100; + } + } + else + { + if (nBytes > 3 && reportBuffer[0] == 0x30) + { + uint8_t batteryInfo = reportBuffer[2]; + device->battery = (uint8_t) (((batteryInfo & 0xE0) >> 4) * 100 / 8); + if (device->battery == 0) device->battery = 1; + else if (device->battery > 100) device->battery = 100; + } } } else - { - if (nBytes > 3 && reportBuffer[0] == 0x30) // Controller must be connected by other programs - { - uint8_t batteryInfo = reportBuffer[2]; - device->battery = (uint8_t) (((batteryInfo & 0xE0) >> 4) * 100 / 8); - if (device->battery == 0) device->battery = 1; - else if (device->battery > 100) device->battery = 100; - } - } + CancelIo(hHidFile); } } } From d3c7529c45483d13ebc1f97d5973386da40481d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 13 Jan 2024 13:38:53 +0800 Subject: [PATCH 74/99] Processing (Windows): don't use CreateEventW --- src/common/processing_windows.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/common/processing_windows.c b/src/common/processing_windows.c index 398194b34..c93e5a9e4 100644 --- a/src/common/processing_windows.c +++ b/src/common/processing_windows.c @@ -83,8 +83,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use char str[FF_PIPE_BUFSIZ]; DWORD nRead = 0; - FF_AUTO_CLOSE_FD HANDLE hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - OVERLAPPED overlapped = { .hEvent = hEvent }; + OVERLAPPED overlapped = { }; // ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED do { @@ -93,11 +92,11 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use switch (GetLastError()) { case ERROR_IO_PENDING: - if (!timeout || WaitForSingleObject(hEvent, (DWORD) timeout) != WAIT_OBJECT_0) + if (!timeout || WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0) { CancelIo(hChildPipeRead); TerminateProcess(hProcess, 1); - return "WaitForSingleObject(hEvent) failed or timeout"; + return "WaitForSingleObject(hChildPipeRead) failed or timeout"; } if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE)) From 95b64622c4f444f49b1115ac483cb0fdca9d93ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 13 Jan 2024 23:36:58 +0800 Subject: [PATCH 75/99] Terminal (Linux): fix detection --- src/detection/terminalshell/terminalshell_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 06f8307b6..29d457504 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -225,7 +225,7 @@ static void getTerminalFromEnv(FFTerminalResult* result) !ffStrbufEqualS(&result->processName, "(init)") && #endif - ffStrbufEqualS(&result->processName, "0") + !ffStrbufEqualS(&result->processName, "0") ) return; const char* term = NULL; From ab1e3db665f853cac3284f228601f63ea502d3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 13 Jan 2024 23:15:47 +0800 Subject: [PATCH 76/99] Shell (Linux): detect ash version --- src/detection/terminalshell/terminalshell.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index 68b963e07..118b4c70f 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -152,6 +152,22 @@ static bool getShellVersionNushell(FFstrbuf* exe, FFstrbuf* version) return getExeVersionRaw(exe, version); //0.73.0 } +static bool getShellVersionAsh(FFstrbuf* exe, FFstrbuf* version) +{ + if(ffProcessAppendStdErr(version, (char* const[]) { + exe->chars, + "--help", + NULL + }) != NULL) + return false; + + // BusyBox v1.36.1 (2023-11-07 18:53:09 UTC) multi-call binary... + ffStrbufSubstrAfterFirstC(version, ' '); + ffStrbufSubstrBeforeFirstC(version, ' '); + ffStrbufTrimLeft(version, 'v'); + return true; +} + #ifdef _WIN32 static bool getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version) { @@ -210,6 +226,8 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version) return getShellVersionOils(exe, version); if(strcasecmp(exeName, "elvish") == 0) return getExeVersionRaw(exe, version); + if(strcasecmp(exeName, "ash") == 0) + return getShellVersionAsh(exe, version); if(strcasecmp(exeName, "python") == 0 && getenv("XONSH_VERSION")) { ffStrbufSetS(version, getenv("XONSH_VERSION")); From 974ee2ab0d6795d421b763c819e747f637714b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 14 Jan 2024 17:26:54 +0800 Subject: [PATCH 77/99] TerminalShell: fix wezterm name pretty printing --- src/detection/terminalshell/terminalshell_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 29d457504..6bbbec717 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -341,7 +341,7 @@ static void setTerminalInfoDetails(FFTerminalResult* result) if(ffStrbufEqualS(&result->processName, "wezterm-gui")) ffStrbufInitStatic(&result->prettyName, "WezTerm"); - if(ffStrbufStartsWithS(&result->processName, "tmux:")) + else if(ffStrbufStartsWithS(&result->processName, "tmux:")) ffStrbufInitStatic(&result->prettyName, "tmux"); #if defined(__ANDROID__) From afa0a7dac8bd3fcdd5ae29baf7966536ba64daed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 09:13:14 +0800 Subject: [PATCH 78/99] Image: silence compiler warnings --- src/logo/image/im6.c | 3 +-- src/logo/image/im7.c | 3 +-- src/logo/image/image.c | 6 +----- src/logo/image/magickcore_wrapper.h | 13 +++++++++++++ 4 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 src/logo/image/magickcore_wrapper.h diff --git a/src/logo/image/im6.c b/src/logo/image/im6.c index 9694a797b..6394fcde8 100644 --- a/src/logo/image/im6.c +++ b/src/logo/image/im6.c @@ -1,10 +1,9 @@ #ifdef FF_HAVE_IMAGEMAGICK6 #include "image.h" +#include "magickcore_wrapper.h" #include "common/library.h" -#include - static FF_LIBRARY_SYMBOL(ResizeImage) static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo) diff --git a/src/logo/image/im7.c b/src/logo/image/im7.c index b0eeed2dc..74c5a8d33 100644 --- a/src/logo/image/im7.c +++ b/src/logo/image/im7.c @@ -1,10 +1,9 @@ #ifdef FF_HAVE_IMAGEMAGICK7 #include "image.h" +#include "magickcore_wrapper.h" #include "common/library.h" -#include - static FF_LIBRARY_SYMBOL(ResizeImage) static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo) diff --git a/src/logo/image/image.c b/src/logo/image/image.c index 460ea3db0..bcd3d0d22 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -265,11 +265,7 @@ static bool compressBlob(void** blob, size_t* length) #endif // FF_HAVE_ZLIB //We use only the defines from here, that are exactly the same in both versions -#ifdef FF_HAVE_IMAGEMAGICK7 - #include -#else - #include -#endif +#include "magickcore_wrapper.h" typedef struct ImageData { diff --git a/src/logo/image/magickcore_wrapper.h b/src/logo/image/magickcore_wrapper.h new file mode 100644 index 000000000..6f4314c71 --- /dev/null +++ b/src/logo/image/magickcore_wrapper.h @@ -0,0 +1,13 @@ +#pragma once + +// ImageMagick-7/MagickCore/pixel-accessor.h:518:46: warning: implicit conversion from 'QuantumAny' (aka 'unsigned long long') to 'double' may lose precision +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-int-float-conversion" + +#ifdef FF_HAVE_IMAGEMAGICK7 + #include +#elif defined(FF_HAVE_IMAGEMAGICK6) + #include +#endif + +#pragma GCC diagnostic pop From 5a34b8d01f8883e09239000b278afb5368268207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 09:39:03 +0800 Subject: [PATCH 79/99] Vulkan: error out if no results detected --- src/modules/vulkan/vulkan.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/vulkan/vulkan.c b/src/modules/vulkan/vulkan.c index 94a0c32dd..de38f8599 100644 --- a/src/modules/vulkan/vulkan.c +++ b/src/modules/vulkan/vulkan.c @@ -17,6 +17,12 @@ void ffPrintVulkan(FFVulkanOptions* options) return; } + if (vulkan->apiVersion.length == 0 && vulkan->driver.length == 0) + { + ffPrintError(FF_VULKAN_MODULE_NAME, 0, &options->moduleArgs, "No Vulkan drivers found"); + return; + } + if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_VULKAN_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); From 01de158bba6383bb0e988c4bfec48c34f566784f Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 15 Jan 2024 10:32:03 +0800 Subject: [PATCH 80/99] Vulkan: print instance version if no vulkan drivers found --- src/detection/vulkan/vulkan.c | 14 ++++---------- src/detection/vulkan/vulkan.h | 1 + src/modules/vulkan/vulkan.c | 16 +++++++++------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/detection/vulkan/vulkan.c b/src/detection/vulkan/vulkan.c index 70d6c5590..5492882c7 100644 --- a/src/detection/vulkan/vulkan.c +++ b/src/detection/vulkan/vulkan.c @@ -1,5 +1,4 @@ #include "fastfetch.h" -#include "common/thread.h" #include "detection/gpu/gpu.h" #include "detection/vulkan/vulkan.h" @@ -8,7 +7,7 @@ #include "common/io/io.h" #include "common/parsing.h" #include "util/stringUtils.h" -#include "util/mallocHelper.h" + #include #include @@ -211,14 +210,8 @@ static const char* detectVulkan(FFVulkanResult* result) continue; } - //If the highest device version is lower than the instance version, use it as our vulkan version - //otherwise the instance version is the vulkan version - if(ffVersionCompare(&instanceVersion, &maxDeviceApiVersion) > 0) - ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion); - else - ffVersionToPretty(&instanceVersion, &result->apiVersion); - - //Use the highest device conformace version as our conformance version + ffVersionToPretty(&instanceVersion, &result->instanceVersion); + ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion); ffVersionToPretty(&maxDeviceConformanceVersion, &result->conformanceVersion); ffvkDestroyInstance(vkInstance, NULL); @@ -236,6 +229,7 @@ FFVulkanResult* ffDetectVulkan(void) ffStrbufInit(&result.driver); ffStrbufInit(&result.apiVersion); ffStrbufInit(&result.conformanceVersion); + ffStrbufInit(&result.instanceVersion); ffListInit(&result.gpus, sizeof(FFGPUResult)); #ifdef FF_HAVE_VULKAN diff --git a/src/detection/vulkan/vulkan.h b/src/detection/vulkan/vulkan.h index 9ac051cbc..5b6d7832e 100644 --- a/src/detection/vulkan/vulkan.h +++ b/src/detection/vulkan/vulkan.h @@ -7,6 +7,7 @@ typedef struct FFVulkanResult FFstrbuf driver; FFstrbuf apiVersion; FFstrbuf conformanceVersion; + FFstrbuf instanceVersion; FFlist gpus; //List of FFGPUResult, see detection/gpu/gpu.h const char* error; } FFVulkanResult; diff --git a/src/modules/vulkan/vulkan.c b/src/modules/vulkan/vulkan.c index de38f8599..8c03668f9 100644 --- a/src/modules/vulkan/vulkan.c +++ b/src/modules/vulkan/vulkan.c @@ -17,16 +17,17 @@ void ffPrintVulkan(FFVulkanOptions* options) return; } - if (vulkan->apiVersion.length == 0 && vulkan->driver.length == 0) - { - ffPrintError(FF_VULKAN_MODULE_NAME, 0, &options->moduleArgs, "No Vulkan drivers found"); - return; - } - if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_VULKAN_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + if (vulkan->apiVersion.length == 0 && vulkan->driver.length == 0) + { + ffStrbufWriteTo(&vulkan->instanceVersion, stdout); + puts(" [Software only]"); + return; + } + if(vulkan->apiVersion.length > 0) { ffStrbufWriteTo(&vulkan->apiVersion, stdout); @@ -145,7 +146,8 @@ void ffPrintVulkanHelpFormat(void) ffPrintModuleFormatHelp(FF_VULKAN_MODULE_NAME, "{2} - {1}", FF_VULKAN_NUM_FORMAT_ARGS, (const char* []) { "Driver name", "API version", - "Conformance version" + "Conformance version", + "Instance version", }); } From 38f216291ee501755acb0c4a763ae283e463da61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 11:22:42 +0800 Subject: [PATCH 81/99] CMake: use system `` in `fastfetch.c` and `flashfetch.c` too Fix #684 --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e7594c85..4449034b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1005,6 +1005,11 @@ set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "") set_target_properties(fastfetch PROPERTIES LINKER_LANGUAGE C) set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C) +if(yyjson_FOUND) + target_compile_definitions(fastfetch PRIVATE FF_USE_SYSTEM_YYJSON) + target_compile_definitions(flashfetch PRIVATE FF_USE_SYSTEM_YYJSON) +endif() + if(WIN32) set(TARGET_NAME fastfetch) target_sources(fastfetch From 43657e8fd624e8ef13c82b47096f8d7b0aad2898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 11:29:29 +0800 Subject: [PATCH 82/99] Doc: update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea9da6b13..d7fc17afd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,15 @@ Features: * Support battery level detection for gamepads where possible (Gamepad) * Support maximum CPU clock detection. Previously base clock was printed (CPU, Windows) * Support manufacture date and serial number detection for physical monitors (Monitor) +* Support ash shell version detection (Shell, Linux) Bugfixes: * Fix support of macOS Sonoma (Wallpaper, macOS) * Fix overall memory leaks (macOS) * Remove trailing `\0` in JSON results (FreeBSD) * Fix physical monitor detection with Nvidia drivers (Monitor, Linux) +* Don't print llvmpipe in vulkan module (Vulkan) +* Fix system yyjson usage in `fastfetch.c`. Previously embeded `3rdparty/yyjson/yyjson.h` was used in `fastfetch.c` even if `ENABLE_SYSTEM_YYJSON` was set (CMake) # 2.5.0 From 6655c446bafb41cfd4743bf4288e6b871f1dfbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 13:15:43 +0800 Subject: [PATCH 83/99] Revert "Image: silence compiler warnings" This reverts commit afa0a7dac8bd3fcdd5ae29baf7966536ba64daed. --- src/logo/image/im6.c | 3 ++- src/logo/image/im7.c | 3 ++- src/logo/image/image.c | 6 +++++- src/logo/image/magickcore_wrapper.h | 13 ------------- 4 files changed, 9 insertions(+), 16 deletions(-) delete mode 100644 src/logo/image/magickcore_wrapper.h diff --git a/src/logo/image/im6.c b/src/logo/image/im6.c index 6394fcde8..9694a797b 100644 --- a/src/logo/image/im6.c +++ b/src/logo/image/im6.c @@ -1,9 +1,10 @@ #ifdef FF_HAVE_IMAGEMAGICK6 #include "image.h" -#include "magickcore_wrapper.h" #include "common/library.h" +#include + static FF_LIBRARY_SYMBOL(ResizeImage) static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo) diff --git a/src/logo/image/im7.c b/src/logo/image/im7.c index 74c5a8d33..b0eeed2dc 100644 --- a/src/logo/image/im7.c +++ b/src/logo/image/im7.c @@ -1,9 +1,10 @@ #ifdef FF_HAVE_IMAGEMAGICK7 #include "image.h" -#include "magickcore_wrapper.h" #include "common/library.h" +#include + static FF_LIBRARY_SYMBOL(ResizeImage) static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo) diff --git a/src/logo/image/image.c b/src/logo/image/image.c index bcd3d0d22..460ea3db0 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -265,7 +265,11 @@ static bool compressBlob(void** blob, size_t* length) #endif // FF_HAVE_ZLIB //We use only the defines from here, that are exactly the same in both versions -#include "magickcore_wrapper.h" +#ifdef FF_HAVE_IMAGEMAGICK7 + #include +#else + #include +#endif typedef struct ImageData { diff --git a/src/logo/image/magickcore_wrapper.h b/src/logo/image/magickcore_wrapper.h deleted file mode 100644 index 6f4314c71..000000000 --- a/src/logo/image/magickcore_wrapper.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -// ImageMagick-7/MagickCore/pixel-accessor.h:518:46: warning: implicit conversion from 'QuantumAny' (aka 'unsigned long long') to 'double' may lose precision -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wimplicit-int-float-conversion" - -#ifdef FF_HAVE_IMAGEMAGICK7 - #include -#elif defined(FF_HAVE_IMAGEMAGICK6) - #include -#endif - -#pragma GCC diagnostic pop From 958bde228b86fca25ae48269e84baf330fa44134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 13:30:18 +0800 Subject: [PATCH 84/99] Doc: fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7fc17afd..6b4639379 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ Bugfixes: * Remove trailing `\0` in JSON results (FreeBSD) * Fix physical monitor detection with Nvidia drivers (Monitor, Linux) * Don't print llvmpipe in vulkan module (Vulkan) -* Fix system yyjson usage in `fastfetch.c`. Previously embeded `3rdparty/yyjson/yyjson.h` was used in `fastfetch.c` even if `ENABLE_SYSTEM_YYJSON` was set (CMake) +* Fix system yyjson usage in `fastfetch.c`. Previously embedded `3rdparty/yyjson/yyjson.h` was used in `fastfetch.c` even if `ENABLE_SYSTEM_YYJSON` was set (CMake) # 2.5.0 From c1d41a36bb28136e2ea54f2f10e6ad0e79e0928a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 14:04:56 +0800 Subject: [PATCH 85/99] CMake: fix build in macOS with -DENABLE_SYSTEM_YYJSON --- CMakeLists.txt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4449034b6..6e17bfd66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,12 +114,6 @@ elseif(APPLE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-arc") endif() -# Used for dlopen finding dylibs installed by homebrew -# `/opt/homebrew/lib` is not on in dlopen search path by default -if(APPLE AND DEFINED ENV{HOMEBREW_PREFIX}) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,$ENV{HOMEBREW_PREFIX}/lib") -endif() - set(FASTFETCH_FLAGS_DEBUG "-fno-omit-frame-pointer") if(ENABLE_ASAN) message(STATUS "Address sanitizer enabled (DEBUG only)") @@ -713,7 +707,14 @@ endif() if(yyjson_FOUND) target_compile_definitions(libfastfetch PRIVATE FF_USE_SYSTEM_YYJSON) - target_link_libraries(libfastfetch PRIVATE yyjson) + target_link_libraries(libfastfetch PRIVATE yyjson::yyjson) + # `target_link_libraries(yyjson::yyjson)` sets rpath implicitly +else() + # Used for dlopen finding dylibs installed by homebrew + # `/opt/homebrew/lib` is not on in dlopen search path by default + if(APPLE AND DEFINED ENV{HOMEBREW_PREFIX}) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,$ENV{HOMEBREW_PREFIX}/lib") + endif() endif() if(LINUX AND EXISTS "/lib/ld-musl-${CMAKE_HOST_SYSTEM_PROCESSOR}.so.1") @@ -1007,7 +1008,9 @@ set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C) if(yyjson_FOUND) target_compile_definitions(fastfetch PRIVATE FF_USE_SYSTEM_YYJSON) + target_link_libraries(fastfetch PRIVATE yyjson::yyjson) target_compile_definitions(flashfetch PRIVATE FF_USE_SYSTEM_YYJSON) + target_link_libraries(flashfetch PRIVATE yyjson::yyjson) endif() if(WIN32) From e1af6fc0fe34dc9c06251bda27897de3c42d5f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 14:27:29 +0800 Subject: [PATCH 86/99] Locale: display only `LC_MESSAGES` if available, which is used by `gettext` --- src/detection/locale/locale.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/detection/locale/locale.c b/src/detection/locale/locale.c index e2f27a214..99edccec0 100644 --- a/src/detection/locale/locale.c +++ b/src/detection/locale/locale.c @@ -21,14 +21,14 @@ static void getLocaleFromEnv(FFstrbuf* locale) static void getLocaleFromStdFn(FFstrbuf* locale) { - ffStrbufAppendS(locale, setlocale(LC_ALL, NULL)); - #ifdef LC_MESSAGES + ffStrbufAppendS(locale, setlocale(LC_MESSAGES, NULL)); + if(locale->length > 0) return; - - ffStrbufAppendS(locale, setlocale(LC_MESSAGES, NULL)); #endif + + ffStrbufAppendS(locale, setlocale(LC_ALL, NULL)); } void ffDetectLocale(FFstrbuf* result) From c1ed0a4e91b0ba2a78de1825682501205d82a6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 14:50:47 +0800 Subject: [PATCH 87/99] Locale (Windows): print standard format --- CMakeLists.txt | 6 +++++- .../locale/{locale.c => locale_linux.c} | 0 src/detection/locale/locale_windows.c | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) rename src/detection/locale/{locale.c => locale_linux.c} (100%) create mode 100644 src/detection/locale/locale_windows.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e17bfd66..3d34761b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,7 +287,6 @@ set(LIBFASTFETCH_SRC src/detection/displayserver/displayserver.c src/detection/font/font.c src/detection/gpu/gpu.c - src/detection/locale/locale.c src/detection/media/media.c src/detection/netio/netio.c src/detection/opencl/opencl.c @@ -406,6 +405,7 @@ if(LINUX) src/detection/icons/icons_linux.c src/detection/libc/libc_linux.c src/detection/lm/lm_linux.c + src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_linux.c src/detection/media/media_linux.c @@ -459,6 +459,7 @@ elseif(ANDROID) src/detection/icons/icons_nosupport.c src/detection/libc/libc_android.c src/detection/lm/lm_nosupport.c + src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_nosupport.c src/detection/media/media_nosupport.c @@ -519,6 +520,7 @@ elseif(BSD) src/detection/lm/lm_linux.c src/detection/icons/icons_linux.c src/detection/libc/libc_bsd.c + src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_bsd.c src/detection/media/media_linux.c @@ -574,6 +576,7 @@ elseif(APPLE) src/detection/lm/lm_nosupport.c src/detection/icons/icons_nosupport.c src/detection/libc/libc_apple.c + src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_apple.c src/detection/media/media_apple.m @@ -628,6 +631,7 @@ elseif(WIN32) src/detection/icons/icons_windows.c src/detection/libc/libc_windows.cpp src/detection/lm/lm_nosupport.c + src/detection/locale/locale_windows.c src/detection/localip/localip_windows.c src/detection/gamepad/gamepad_windows.c src/detection/media/media_nosupport.c diff --git a/src/detection/locale/locale.c b/src/detection/locale/locale_linux.c similarity index 100% rename from src/detection/locale/locale.c rename to src/detection/locale/locale_linux.c diff --git a/src/detection/locale/locale_windows.c b/src/detection/locale/locale_windows.c new file mode 100644 index 000000000..8cdfaf15f --- /dev/null +++ b/src/detection/locale/locale_windows.c @@ -0,0 +1,18 @@ +#include "detection/locale/locale.h" +#include "util/windows/unicode.h" + +#include +#include + +void ffDetectLocale(FFstrbuf* result) +{ + wchar_t name[LOCALE_NAME_MAX_LENGTH]; + int size = GetUserDefaultLocaleName(name, LOCALE_NAME_MAX_LENGTH); + if (size > 1) // including '\0' + { + ffStrbufSetNWS(result, (uint32_t)size - 1, name); + ffStrbufAppendS(result, ".UTF-8"); // set explictly in `ffInitInstance` + } + else + ffStrbufSetS(result, setlocale(LC_ALL, NULL)); +} From 0c844fc342ec81351128a5402cc7cdc598baa254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 15:11:04 +0800 Subject: [PATCH 88/99] FFstrbuf: don't crash with `ffStrbufInitStatic(&buf, NULL)` --- src/util/FFstrbuf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 7f67126af..1eb6a3edd 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -223,6 +223,8 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreate() static inline void ffStrbufInitStatic(FFstrbuf* strbuf, const char* str) { ffStrbufInit(strbuf); + if (!str) return; + strbuf->allocated = 0; strbuf->length = (uint32_t) strlen(str); strbuf->chars = (char*) str; From 5d35dade606781b944250ce0f33766354e225a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 15:22:08 +0800 Subject: [PATCH 89/99] DisplayServer (Windows): don't detect unknown display type as external --- src/detection/displayserver/displayserver_windows.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/detection/displayserver/displayserver_windows.c b/src/detection/displayserver/displayserver_windows.c index 684f29928..c57c03992 100644 --- a/src/detection/displayserver/displayserver_windows.c +++ b/src/detection/displayserver/displayserver_windows.c @@ -129,8 +129,9 @@ static void detectDisplays(FFDisplayServerResult* ds) (uint32_t) (monitorInfo->info.rcMonitor.bottom - monitorInfo->info.rcMonitor.top), rotation, &name, - path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL || - path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED || + path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER ? FF_DISPLAY_TYPE_UNKNOWN : + path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL || + path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED || path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED ? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL, !!(monitorInfo->info.dwFlags & MONITORINFOF_PRIMARY), From ea3734f0049e7d3fabb27ce9c27445616d311db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 15:48:32 +0800 Subject: [PATCH 90/99] Locale (Windows): fix typo --- src/detection/locale/locale_windows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/locale/locale_windows.c b/src/detection/locale/locale_windows.c index 8cdfaf15f..128913129 100644 --- a/src/detection/locale/locale_windows.c +++ b/src/detection/locale/locale_windows.c @@ -11,7 +11,7 @@ void ffDetectLocale(FFstrbuf* result) if (size > 1) // including '\0' { ffStrbufSetNWS(result, (uint32_t)size - 1, name); - ffStrbufAppendS(result, ".UTF-8"); // set explictly in `ffInitInstance` + ffStrbufAppendS(result, ".UTF-8"); // set explicitly in `ffInitInstance` } else ffStrbufSetS(result, setlocale(LC_ALL, NULL)); From 35d149705386a0d00bddbd2f5b57d3590dd2ead6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 15:48:39 +0800 Subject: [PATCH 91/99] Doc: update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b4639379..6d06b9424 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 2.5.1 +# 2.6.0 Changes: * Remove support of option `--battery-dir`. We detect a lot of things in `/sys/class/*` and only module `Battery` supports specifying a custom directory for some reason, which is weird. @@ -21,6 +21,7 @@ Bugfixes: * Fix physical monitor detection with Nvidia drivers (Monitor, Linux) * Don't print llvmpipe in vulkan module (Vulkan) * Fix system yyjson usage in `fastfetch.c`. Previously embedded `3rdparty/yyjson/yyjson.h` was used in `fastfetch.c` even if `ENABLE_SYSTEM_YYJSON` was set (CMake) +* Fix locale module printing unexpected results in specific environments (Locale) # 2.5.0 From 1227799a38b78acd3daa4d9d977c1c1436e58a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 15 Jan 2024 18:14:40 +0800 Subject: [PATCH 92/99] Vulkan: print `platformApi` in JSON format --- src/modules/vulkan/vulkan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/vulkan/vulkan.c b/src/modules/vulkan/vulkan.c index 8c03668f9..24b5497da 100644 --- a/src/modules/vulkan/vulkan.c +++ b/src/modules/vulkan/vulkan.c @@ -108,6 +108,7 @@ void ffGenerateVulkanJsonResult(FF_MAYBE_UNUSED FFVulkanOptions* options, yyjson yyjson_mut_obj_add_strbuf(doc, gpuObj, "vendor", &vulkanGpu->vendor); yyjson_mut_obj_add_strbuf(doc, gpuObj, "name", &vulkanGpu->name); yyjson_mut_obj_add_strbuf(doc, gpuObj, "driver", &vulkanGpu->driver); + yyjson_mut_obj_add_strbuf(doc, gpuObj, "platformApi", &vulkanGpu->platformApi); yyjson_mut_val* memoryObj = yyjson_mut_obj_add_obj(doc, gpuObj, "memory"); From 861eea5899eb0c484a6e9c964f411c1eef426dfe Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 16 Jan 2024 11:06:07 +0800 Subject: [PATCH 93/99] Sound (FreeBSD): new impl; drop pulseaudio dep --- CMakeLists.txt | 5 +++-- src/detection/sound/sound_bsd.c | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/detection/sound/sound_bsd.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d34761b2..3b080fa15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,7 @@ cmake_dependent_option(ENABLE_OSMESA "Enable osmesa" ON "LINUX OR BSD" OFF) cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD OR WIN32" OFF) cmake_dependent_option(ENABLE_LIBNM "Enable libnm" ON "LINUX" OFF) cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF) -cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR BSD" OFF) +cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX" OFF) cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF) cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF) cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF) @@ -533,7 +533,7 @@ elseif(BSD) src/detection/poweradapter/poweradapter_nosupport.c src/detection/processes/processes_bsd.c src/detection/gtk_qt/qt.c - src/detection/sound/sound_linux.c + src/detection/sound/sound_bsd.c src/detection/swap/swap_bsd.c src/detection/temps/temps_bsd.c src/detection/terminalfont/terminalfont_linux.c @@ -954,6 +954,7 @@ elseif(BSD) PRIVATE "m" PRIVATE "usbhid" PRIVATE "geom" + PRIVATE "mixer" ) elseif(ANDROID) CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC) diff --git a/src/detection/sound/sound_bsd.c b/src/detection/sound/sound_bsd.c new file mode 100644 index 000000000..f6077818e --- /dev/null +++ b/src/detection/sound/sound_bsd.c @@ -0,0 +1,38 @@ +#include "sound.h" + +#include + +const char* ffDetectSound(FFlist* devices) +{ + int nmixers = mixer_get_nmixers(); + if (nmixers == 0) return "No mixers found"; + + if (__builtin_expect(nmixers > 9, false)) nmixers = 9; + + char path[] = "/dev/mixer0"; + + for (int idev = 0; idev < nmixers; ++idev) + { + path[strlen("/dev/mixer")] = (char) ('0' + idev); + struct mixer* m = mixer_open(path); + if (!m) continue; + + if (m->mode & MIX_MODE_PLAY) + { + struct mix_dev* dev = mixer_get_dev_byname(m, "vol"); + if (dev) + { + FFSoundDevice* device = ffListAdd(devices); + ffStrbufInitS(&device->identifier, path); + ffStrbufInitF(&device->name, "%s %s", m->ci.longname, m->ci.hw_info); + device->volume = MIX_ISMUTE(m, dev->devno) ? 0 : (uint8_t) MIX_VOLDENORM((dev->vol.left + dev->vol.right) / 2); + device->active = true; + device->main = !!m->f_default; + } + } + + mixer_close(m); + } + + return NULL; +} From c8f28e4c79afa46339c85f36464900479a3ae046 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 17 Jan 2024 10:11:07 +0800 Subject: [PATCH 94/99] Sound (FreeBSD): don't use mixer.h It's only supported in FreeBSD 14 and later --- CMakeLists.txt | 1 - src/detection/sound/sound_bsd.c | 56 +++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b080fa15..ae3d94b7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -954,7 +954,6 @@ elseif(BSD) PRIVATE "m" PRIVATE "usbhid" PRIVATE "geom" - PRIVATE "mixer" ) elseif(ANDROID) CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC) diff --git a/src/detection/sound/sound_bsd.c b/src/detection/sound/sound_bsd.c index f6077818e..49575d355 100644 --- a/src/detection/sound/sound_bsd.c +++ b/src/detection/sound/sound_bsd.c @@ -1,37 +1,47 @@ #include "sound.h" +#include "common/io/io.h" +#include "common/sysctl.h" -#include +#include +#include const char* ffDetectSound(FFlist* devices) { - int nmixers = mixer_get_nmixers(); - if (nmixers == 0) return "No mixers found"; - - if (__builtin_expect(nmixers > 9, false)) nmixers = 9; - char path[] = "/dev/mixer0"; + int defaultDev = ffSysctlGetInt("hw.snd.default_unit", -1); - for (int idev = 0; idev < nmixers; ++idev) + for (int idev = 0; idev <= 9; ++idev) { path[strlen("/dev/mixer")] = (char) ('0' + idev); - struct mixer* m = mixer_open(path); - if (!m) continue; + FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR); + if (fd < 0) break; - if (m->mode & MIX_MODE_PLAY) - { - struct mix_dev* dev = mixer_get_dev_byname(m, "vol"); - if (dev) - { - FFSoundDevice* device = ffListAdd(devices); - ffStrbufInitS(&device->identifier, path); - ffStrbufInitF(&device->name, "%s %s", m->ci.longname, m->ci.hw_info); - device->volume = MIX_ISMUTE(m, dev->devno) ? 0 : (uint8_t) MIX_VOLDENORM((dev->vol.left + dev->vol.right) / 2); - device->active = true; - device->main = !!m->f_default; - } - } + uint32_t devmask = 0; + if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) + continue; + if (!((1 << SOUND_MIXER_VOLUME) & devmask)) + continue; - mixer_close(m); + uint32_t mutemask = 0; + if (ioctl(fd, SOUND_MIXER_READ_MUTE, &mutemask) < 0) + continue; + + struct oss_card_info ci = { .card = idev }; + if (ioctl(fd, SNDCTL_CARDINFO, &ci) < 0) + continue; + + uint32_t volume; + if (ioctl(fd, MIXER_READ(SOUND_MIXER_VOLUME), &volume) < 0) + continue; + + FFSoundDevice* device = ffListAdd(devices); + ffStrbufInitS(&device->identifier, path); + ffStrbufInitF(&device->name, "%s %s", ci.longname, ci.hw_info); + device->volume = (1 << SOUND_MIXER_VOLUME) & mutemask + ? 0 + : ((uint8_t) volume /*left*/ + (uint8_t) (volume >> 8) /*right*/) / 2; + device->active = true; + device->main = defaultDev == idev; } return NULL; From a3c0085e2bd44af9c713cbefd78673c1e37b8b09 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 17 Jan 2024 13:31:34 +0800 Subject: [PATCH 95/99] Sound: tidy --- src/detection/media/media_linux.c | 2 -- src/detection/sound/sound_bsd.c | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/detection/media/media_linux.c b/src/detection/media/media_linux.c index 35830f1b9..5dd673338 100644 --- a/src/detection/media/media_linux.c +++ b/src/detection/media/media_linux.c @@ -1,6 +1,5 @@ #include "fastfetch.h" #include "detection/media/media.h" -#include "common/thread.h" #include "util/stringUtils.h" #include @@ -11,7 +10,6 @@ #ifdef FF_HAVE_DBUS #include "common/dbus.h" #include "common/library.h" -#include "common/parsing.h" static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResult* result) { diff --git a/src/detection/sound/sound_bsd.c b/src/detection/sound/sound_bsd.c index 49575d355..3053c14d5 100644 --- a/src/detection/sound/sound_bsd.c +++ b/src/detection/sound/sound_bsd.c @@ -19,7 +19,7 @@ const char* ffDetectSound(FFlist* devices) uint32_t devmask = 0; if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) continue; - if (!((1 << SOUND_MIXER_VOLUME) & devmask)) + if (!(devmask & SOUND_MASK_VOLUME)) continue; uint32_t mutemask = 0; @@ -31,13 +31,13 @@ const char* ffDetectSound(FFlist* devices) continue; uint32_t volume; - if (ioctl(fd, MIXER_READ(SOUND_MIXER_VOLUME), &volume) < 0) + if (ioctl(fd, SOUND_MIXER_READ_VOLUME, &volume) < 0) continue; FFSoundDevice* device = ffListAdd(devices); ffStrbufInitS(&device->identifier, path); ffStrbufInitF(&device->name, "%s %s", ci.longname, ci.hw_info); - device->volume = (1 << SOUND_MIXER_VOLUME) & mutemask + device->volume = mutemask & SOUND_MASK_VOLUME ? 0 : ((uint8_t) volume /*left*/ + (uint8_t) (volume >> 8) /*right*/) / 2; device->active = true; From 07dfe57386191fa755633c71011779ecba0d77b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 17 Jan 2024 14:00:55 +0800 Subject: [PATCH 96/99] Doc: update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d06b9424..58e0e5e38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ Features: * Support maximum CPU clock detection. Previously base clock was printed (CPU, Windows) * Support manufacture date and serial number detection for physical monitors (Monitor) * Support ash shell version detection (Shell, Linux) +* Sound module in FreeBSD now uses native `ioctl`s. Pulseaudio dependency is no longer used. +* Locale module in Windows now prints the same format as in Linux and other posix systems. Bugfixes: * Fix support of macOS Sonoma (Wallpaper, macOS) From 963eaa539520966d2cb32d450602086c8d47b680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 17 Jan 2024 14:02:07 +0800 Subject: [PATCH 97/99] Release: v2.6.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae3d94b7c..b1247d7f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.5.0 + VERSION 2.6.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" From 9f77851176b0ca77fe63368200a22d2a6278ad5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 17 Jan 2024 14:08:31 +0800 Subject: [PATCH 98/99] JsonSchema: make it a valid json document --- doc/json_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/json_schema.json b/doc/json_schema.json index cb48c7e66..1aa42ecea 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1217,7 +1217,7 @@ "properties": { "type": { "const": "host", - "description": "Print product name of your computer", + "description": "Print product name of your computer" }, "key": { "$ref": "#/$defs/key" From b3945e277c56f2c72ac7d52f600445e5d67c650a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 17 Jan 2024 15:06:52 +0800 Subject: [PATCH 99/99] Global: review code --- CHANGELOG.md | 6 +++-- doc/json_schema.json | 26 +++---------------- presets/examples/9.jsonc | 5 +--- .../terminalfont/terminalfont_apple.m | 6 ++--- .../terminalfont/terminalfont_windows.c | 4 +-- src/detection/terminalshell/terminalshell.h | 1 - src/logo/logo.c | 8 +++--- src/modules/battery/battery.c | 2 +- 8 files changed, 19 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e0e5e38..0683c6727 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,24 +6,26 @@ Changes: Features: * Add `ENABLE_PROPRIETARY_GPU_DRIVER_API` cmake option to disable using of proprietary GPU driver APIs (GPU) +* Support wallpaper detection for macOS Sonoma (Wallpaper, macOS) * Support power adapter detection for Asahi Linux (PowerAdapter, Linux) * Support battery serial number and manufacturer date detection (Battery) * Support host serial number and UUID detection (Host) * Support battery level detection for gamepads where possible (Gamepad) * Support maximum CPU clock detection. Previously base clock was printed (CPU, Windows) * Support manufacture date and serial number detection for physical monitors (Monitor) -* Support ash shell version detection (Shell, Linux) +* Support ash (default shell of BusyBox) version detection (Shell, Linux) * Sound module in FreeBSD now uses native `ioctl`s. Pulseaudio dependency is no longer used. * Locale module in Windows now prints the same format as in Linux and other posix systems. Bugfixes: -* Fix support of macOS Sonoma (Wallpaper, macOS) * Fix overall memory leaks (macOS) * Remove trailing `\0` in JSON results (FreeBSD) * Fix physical monitor detection with Nvidia drivers (Monitor, Linux) * Don't print llvmpipe in vulkan module (Vulkan) * Fix system yyjson usage in `fastfetch.c`. Previously embedded `3rdparty/yyjson/yyjson.h` was used in `fastfetch.c` even if `ENABLE_SYSTEM_YYJSON` was set (CMake) * Fix locale module printing unexpected results in specific environments (Locale) +* Fix battery temperature detection in Windows. Note only smart batteries report temperatures but few laptops uses smart battery (Battery, Windows) +* Print device name if no backlight name is available, so we don't print empty parentheses (Brightness, FreeBSD) # 2.5.0 diff --git a/doc/json_schema.json b/doc/json_schema.json index 1aa42ecea..ce00756da 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -676,6 +676,10 @@ "const": "gamepad", "description": "List connected gamepads" }, + { + "const": "host", + "description": "Print product name of your computer" + }, { "const": "icons", "description": "Print icon style name" @@ -1212,28 +1216,6 @@ }, "additionalProperties": false }, - { - "title": "Host", - "properties": { - "type": { - "const": "host", - "description": "Print product name of your computer" - }, - "key": { - "$ref": "#/$defs/key" - }, - "keyColor": { - "$ref": "#/$defs/keyColor" - }, - "keyWidth": { - "$ref": "#/$defs/keyWidth" - }, - "format": { - "$ref": "#/$defs/format" - } - }, - "additionalProperties": false - }, { "title": "Local IP", "properties": { diff --git a/presets/examples/9.jsonc b/presets/examples/9.jsonc index 7c2db86bd..e2801c248 100644 --- a/presets/examples/9.jsonc +++ b/presets/examples/9.jsonc @@ -16,10 +16,7 @@ "separator", "memory", "swap", - { - "type": "disk", - "folders": "/" - }, + "disk", "battery", { "type": "colors", diff --git a/src/detection/terminalfont/terminalfont_apple.m b/src/detection/terminalfont/terminalfont_apple.m index 65c148710..7d6aca282 100644 --- a/src/detection/terminalfont/terminalfont_apple.m +++ b/src/detection/terminalfont/terminalfont_apple.m @@ -93,11 +93,11 @@ static void detectWarpTerminal(FFTerminalFontResult* terminalFont) void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { - if(ffStrbufIgnCaseCompS(&terminal->processName, "iterm.app") == 0 || + if(ffStrbufIgnCaseEqualS(&terminal->processName, "iterm.app") || ffStrbufStartsWithIgnCaseS(&terminal->processName, "iTermServer-")) detectIterm2(terminalFont); - else if(ffStrbufIgnCaseCompS(&terminal->processName, "Apple_Terminal") == 0) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "Apple_Terminal")) detectAppleTerminal(terminalFont); - else if(ffStrbufIgnCaseCompS(&terminal->processName, "WarpTerminal") == 0) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal")) detectWarpTerminal(terminalFont); } diff --git a/src/detection/terminalfont/terminalfont_windows.c b/src/detection/terminalfont/terminalfont_windows.c index 7e9e526cc..633781ad7 100644 --- a/src/detection/terminalfont/terminalfont_windows.c +++ b/src/detection/terminalfont/terminalfont_windows.c @@ -87,9 +87,9 @@ static void detectConEmu(FFTerminalFontResult* terminalFont) void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { - if(ffStrbufIgnCaseCompS(&terminal->processName, "mintty") == 0) + if(ffStrbufIgnCaseEqualS(&terminal->processName, "mintty")) detectMintty(terminalFont); - else if(ffStrbufIgnCaseCompS(&terminal->processName, "conhost.exe") == 0) + else if(ffStrbufIgnCaseEqualS(&terminal->processName, "conhost.exe")) detectConhost(terminalFont); else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "ConEmu")) detectConEmu(terminalFont); diff --git a/src/detection/terminalshell/terminalshell.h b/src/detection/terminalshell/terminalshell.h index 6f050d01a..921fb7098 100644 --- a/src/detection/terminalshell/terminalshell.h +++ b/src/detection/terminalshell/terminalshell.h @@ -15,7 +15,6 @@ typedef struct FFShellResult typedef struct FFTerminalResult { - FFstrbuf processName; FFstrbuf exe; FFstrbuf prettyName; diff --git a/src/logo/logo.c b/src/logo/logo.c index 4aa78bd06..708bc6c7f 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -502,10 +502,10 @@ void ffLogoPrint(void) //Terminal emulators that support kitty graphics protocol. bool supportsKitty = - ffStrbufIgnCaseCompS(&terminal->processName, "kitty") == 0 || - ffStrbufIgnCaseCompS(&terminal->processName, "konsole") == 0 || - ffStrbufIgnCaseCompS(&terminal->processName, "wezterm") == 0 || - ffStrbufIgnCaseCompS(&terminal->processName, "wayst") == 0; + ffStrbufIgnCaseEqualS(&terminal->processName, "kitty") || + ffStrbufIgnCaseEqualS(&terminal->processName, "konsole") || + ffStrbufIgnCaseEqualS(&terminal->processName, "wezterm") || + ffStrbufIgnCaseEqualS(&terminal->processName, "wayst"); //Try to load the logo as an image. If it succeeds, print it and return. if(logoPrintImageIfExists(supportsKitty ? FF_LOGO_TYPE_IMAGE_KITTY : FF_LOGO_TYPE_IMAGE_CHAFA, false)) diff --git a/src/modules/battery/battery.c b/src/modules/battery/battery.c index cefe6166a..0a2bd8afd 100644 --- a/src/modules/battery/battery.c +++ b/src/modules/battery/battery.c @@ -226,7 +226,7 @@ void ffPrintBatteryHelpFormat(void) "Battery temperature", "Battery cycle count", "Battery serial number", - "Battery manufactorDate", + "Battery manufactor date", }); }