diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5414375470..25be05ee0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -408,8 +408,55 @@ jobs: name: fastfetch-musl-amd64 path: ./fastfetch-*.* - macos-universal: - name: macOS-universal + macos-amd64: + name: macOS-amd64 + runs-on: macos-13 + permissions: + security-events: write + contents: read + steps: + - name: checkout repository + uses: actions/checkout@v4 + + - name: uname -a + run: uname -a + + - name: install required packages + run: | + HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa + + - name: configure project + run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On . + + - name: build project + run: cmake --build . --target package --verbose -j4 + + - name: list features + run: ./fastfetch --list-features + + - name: run fastfetch + run: time ./fastfetch -c presets/ci.jsonc --stat false + + - name: run fastfetch --format json + run: time ./fastfetch -c presets/ci.jsonc --format json + + - name: run flashfetch + run: time ./flashfetch + + - name: print dependencies + run: otool -L fastfetch + + - name: run tests + run: ctest --output-on-failure + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: fastfetch-macos-amd64 + path: ./fastfetch-*.* + + macos-aarch64: + name: macOS-aarch64 runs-on: macos-latest permissions: security-events: write @@ -426,7 +473,7 @@ jobs: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa - name: configure project - run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' . + run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On . - name: build project run: cmake --build . --target package --verbose -j4 @@ -452,7 +499,7 @@ jobs: - name: upload artifacts uses: actions/upload-artifact@v4 with: - name: fastfetch-macos-universal + name: fastfetch-macos-aarch64 path: ./fastfetch-*.* sunos-amd64: @@ -542,7 +589,7 @@ jobs: architecture: x86-64 cpu_count: 4 shell: bash - version: '7.6' + version: '7.7' run: | uname -a sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa @@ -808,7 +855,8 @@ jobs: - linux-ppc64le - linux-s390x - musl-amd64 - - macos-universal + - macos-amd64 + - macos-aarch64 - freebsd-amd64 - openbsd-amd64 - netbsd-amd64 diff --git a/CHANGELOG.md b/CHANGELOG.md index 46c61d5523..a9bcf47762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,41 @@ +# 2.46.0 + +Features: +* Support Rio terminal font detection (#1789, TerminalFont, Linux) +* Support GPU detection by DRM on FreeBSD (GPU, FreeBSD) + * Enable by `--gpu-detection-method auto` + * Require proper DRM drivers installed and loaded +* Support PowerPC CPU detection on NetBSD (#1802, CPU, NetBSD) +* Support Aerospace WM detection (#1796, WM, macOS) +* Improve Raspberry Pi OS for RPI5 detection (#1773, OS, Linux) +* Support Linux Binary Compatibility detection on FreeBSD (#1786, Host, Linux) +* Use `board-id` as board name if available (Board, macOS) + * Intel only +* Support shared VRAM usage detection for AMD GPUs (GPU, Linux) +* Use `perflib.h` instead of `pdh.h` for CPU temperature querying to get rid of pdh.dll (#1787, CPU, Windows) +* Support GPU info detection for old ATI radeon driver (#1810, GPU, Linux) +* Add macOS 26 Tahoe support (macOS) + * Report macOS 26 code name (OS) + * Report Liquid Glass DE on macOS 26+ (DE) + * Detect Metal 4 support (GPU) + +Bugfixes: +* Fix packages counting by ignoring hidden folders (Packages, OpenBSD) +* Fix Hyprland version detection (WM, FreeBSD) +* Don't show `Please insert a disk into drive D:` error dialogs (#1805, Disk, Windows) +* Hide `/boot/firmware` by default (Disk, Linux) + +Logos: +* Rename Hydra Framework to HydraPwk (#1812) +* Add AnushOS (#1806) +* Add HarmonyOS (#1804) +* Add GhostFreak (#1801) +* Add TrueNAS Scale (#1795) +* Add Fedora2_small (#1785) +* Add xenia_old; update colors of xenia (#1797) +* Improve colors of bedrock_small (#1790) +* Add Kalpa Desktop (#1807) + # 2.45.0 Features: diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f3359d949..27b8957b81 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.45.0 + VERSION 2.46.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" @@ -61,7 +61,7 @@ cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeB cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) -cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX" OFF) +cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD" OFF) cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" OFF) @@ -529,6 +529,7 @@ if(LINUX) src/detection/displayserver/linux/xlib.c src/detection/font/font_linux.c src/detection/gpu/gpu_linux.c + src/detection/gpu/gpu_drm.c src/detection/gpu/gpu_pci.c src/detection/gtk_qt/gtk.c src/detection/host/host_linux.c @@ -676,6 +677,7 @@ elseif(FreeBSD) src/detection/displayserver/linux/xlib.c src/detection/font/font_linux.c src/detection/gpu/gpu_bsd.c + src/detection/gpu/gpu_drm.c src/detection/gpu/gpu_pci.c src/detection/gtk_qt/gtk.c src/detection/host/host_bsd.c @@ -1593,7 +1595,6 @@ elseif(WIN32) PRIVATE "winbrand" PRIVATE "propsys" PRIVATE "secur32" - PRIVATE "pdh" ) if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64") # WoA only works on Windows 10 or higher @@ -1925,17 +1926,17 @@ install( ################## set(CPACK_GENERATOR "TGZ;ZIP") +if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(CMAKE_SYSTEM_PROCESSOR "amd64") +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") + set(CMAKE_SYSTEM_PROCESSOR "aarch64") +endif() if(APPLE) - string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-universal" CPACK_PACKAGE_FILE_NAME) -else() # We don't use this in Windows - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(CMAKE_SYSTEM_PROCESSOR "amd64") - endif() - if(IS_MUSL) - string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) - else() - string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) - endif() + string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) # use macos instead of darwin +elseif(IS_MUSL) + string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) +else() + string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) endif() if(LINUX) diff --git a/debian/changelog b/debian/changelog index d3df85c445..6e1e23fe68 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +fastfetch (2.45.0) jammy; urgency=medium + + * Update to 2.45.0 + + -- Carter Li Thu, 05 Jun 2025 10:56:38 +0800 + fastfetch (2.44.0) jammy; urgency=medium * Update to 2.44.0 diff --git a/debian/files b/debian/files index 4ce3a4475f..806f0dbe1f 100644 --- a/debian/files +++ b/debian/files @@ -1 +1 @@ -fastfetch_2.44.0_source.buildinfo universe/utils optional +fastfetch_2.45.0_source.buildinfo universe/utils optional diff --git a/doc/json_schema.json b/doc/json_schema.json index 66e4715926..d2c4ff4173 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -3002,6 +3002,11 @@ "const": "swap", "description": "Print swap (paging file) space usage" }, + "separate": { + "type": "boolean", + "description": "Set if detailed swap devices should be reported on separate lines instead of a summary", + "default": false + }, "percent": { "$ref": "#/$defs/percent" }, diff --git a/presets/all.jsonc b/presets/all.jsonc index d1e30ef4c5..74bea1f352 100644 --- a/presets/all.jsonc +++ b/presets/all.jsonc @@ -52,7 +52,10 @@ }, "memory", "physicalmemory", - "swap", + { + "type": "swap", + "separate": true + }, "disk", "btrfs", "zpool", diff --git a/presets/ci.jsonc b/presets/ci.jsonc index a1e9da42bb..4203ff7c59 100644 --- a/presets/ci.jsonc +++ b/presets/ci.jsonc @@ -54,7 +54,10 @@ }, "memory", "physicalmemory", - "swap", + { + "type": "swap", + "separate": true + }, "disk", "btrfs", "zpool", diff --git a/src/common/init.c b/src/common/init.c index 561e856cfd..8b6032c03e 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -105,6 +105,7 @@ void ffStart(void) ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc; #ifdef _WIN32 + SetErrorMode(SEM_FAILCRITICALERRORS); if (instance.config.display.noBuffer) setvbuf(stdout, NULL, _IONBF, 0); else diff --git a/src/common/io/io_unix.c b/src/common/io/io_unix.c index 7875c75870..8e354cd792 100644 --- a/src/common/io/io_unix.c +++ b/src/common/io/io_unix.c @@ -290,7 +290,7 @@ bool ffSuppressIO(bool suppress) void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty) { - FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY); + FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC); if (dfd < 0) return; diff --git a/src/data/help.json b/src/data/help.json index 68f67d17f6..4244fad56d 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1144,11 +1144,11 @@ "arg": { "type": "enum", "enum": { - "auto": "Query platform-specific graphics APIs. Requires proper GPU drivers to be installed. Not supported on BSDs", + "auto": "Query platform-specific graphics APIs. Requires proper GPU drivers to be installed. Supported on Linux, FreeBSD, Windows and macOS", "pci": "Search PCI devices, which does not require GPU drivers to be installed. Not supported on Windows and macOS", "vulkan": "Use Vulkan API. Slow and requires proper Vulkan drivers to be installed. Used for Android", "opencl": "Use OpenCL API. Slow and requires proper OpenCL drivers to be installed", - "opengl": "Use OpenGL API. Slow and only detects one GPU" + "opengl": "Use OpenGL API. Slow and only detects one GPU. Used for OpenBSD" }, "default": "auto" } diff --git a/src/detection/battery/battery_nbsd.c b/src/detection/battery/battery_nbsd.c index bcff9a875c..671fae3603 100644 --- a/src/detection/battery/battery_nbsd.c +++ b/src/detection/battery/battery_nbsd.c @@ -16,8 +16,8 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results) { - FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY); - if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed"; + FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC); + if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed"; prop_dictionary_t root = NULL; if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0) diff --git a/src/detection/battery/battery_obsd.c b/src/detection/battery/battery_obsd.c index ea4f731489..c9ef03c874 100644 --- a/src/detection/battery/battery_obsd.c +++ b/src/detection/battery/battery_obsd.c @@ -8,9 +8,9 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* result) { - FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY); + FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY | O_CLOEXEC); - if (devfd < 0) return "open(dev/apm, O_RDONLY) failed"; + if (devfd < 0) return "open(dev/apm, O_RDONLY | O_CLOEXEC) failed"; struct apm_power_info info = {}; diff --git a/src/detection/board/board_apple.c b/src/detection/board/board_apple.c index 6381590d85..dca906bc37 100644 --- a/src/detection/board/board_apple.c +++ b/src/detection/board/board_apple.c @@ -9,9 +9,19 @@ const char* ffDetectBoard(FFBoardResult* result) if (!service) return "No IOPlatformExpertDevice found"; - io_name_t name; - if (IORegistryEntryGetName(service, name) == kIOReturnSuccess) - ffStrbufSetS(&result->name, name); + FF_CFTYPE_AUTO_RELEASE CFTypeRef boardId = IORegistryEntryCreateCFProperty(service, CFSTR("board-id"), kCFAllocatorDefault, kNilOptions); + if (boardId) + ffCfStrGetString(boardId, &result->name); + else + { + io_name_t name; + if (IORegistryEntryGetName(service, name) == kIOReturnSuccess) + ffStrbufSetS(&result->name, name); + } + + FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(service, CFSTR("version"), kCFAllocatorDefault, kNilOptions); + if (version) + ffCfStrGetString(version, &result->version); FF_CFTYPE_AUTO_RELEASE CFTypeRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions); if (manufacturer) diff --git a/src/detection/bootmgr/bootmgr_bsd.c b/src/detection/bootmgr/bootmgr_bsd.c index c2924fcf6e..989ac348e4 100644 --- a/src/detection/bootmgr/bootmgr_bsd.c +++ b/src/detection/bootmgr/bootmgr_bsd.c @@ -20,7 +20,7 @@ const char* ffDetectBootmgr(FFBootmgrResult* result) { - FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR); + FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR | O_CLOEXEC); if (efifd < 0) return "open(/dev/efi) failed"; uint8_t buffer[2048]; diff --git a/src/detection/brightness/brightness_obsd.c b/src/detection/brightness/brightness_obsd.c index eb411129d9..e5b944a42a 100644 --- a/src/detection/brightness/brightness_obsd.c +++ b/src/detection/brightness/brightness_obsd.c @@ -12,7 +12,7 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl for (char i = '0'; i <= '9'; ++i) { path[strlen("/dev/ttyC")] = i; - FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY); + FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY | O_CLOEXEC); if (devfd < 0) { if (errno == EACCES && i == '0') diff --git a/src/detection/camera/camera_linux.c b/src/detection/camera/camera_linux.c index 8c1cfd0ab3..09a6fb06dd 100644 --- a/src/detection/camera/camera_linux.c +++ b/src/detection/camera/camera_linux.c @@ -20,7 +20,7 @@ const char* ffDetectCamera(FFlist* result) for (uint32_t i = 0; i <= 9; ++i) { path[ARRAY_SIZE(path) - 2] = (char) (i + '0'); - FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY); + FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { if (errno == ENOENT) diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 8a84422298..012af9202d 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -474,7 +474,7 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC static const char* detectPhysicalCores(FFCPUResult* cpu) { - int dfd = open("/sys/devices/system/cpu/", O_RDONLY | O_DIRECTORY); + int dfd = open("/sys/devices/system/cpu/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); if (dfd < 0) return "open(\"/sys/devices/system/cpu/\") failed"; FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd); diff --git a/src/detection/cpu/cpu_nbsd.c b/src/detection/cpu/cpu_nbsd.c index 0486e213c0..16ad005054 100644 --- a/src/detection/cpu/cpu_nbsd.c +++ b/src/detection/cpu/cpu_nbsd.c @@ -18,8 +18,8 @@ static void freePropDict(prop_dictionary_t* pdict) static const char* detectCpuTemp(double* current) { - FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY); - if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed"; + FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC); + if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed"; __attribute__((__cleanup__(freePropDict))) prop_dictionary_t root = NULL; if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0) @@ -51,7 +51,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) { if (ffSysctlGetString("machdep.cpu_brand", &cpu->name) != NULL && ffSysctlGetString("machdep.dmi.processor-version", &cpu->name) != NULL && - ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL) + ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL && + ffSysctlGetString("hw.model", &cpu->name) != NULL) { ffStrbufSetS(&cpu->name, "Unknown CPU"); } diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 515262158e..2cb1eef347 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -4,42 +4,116 @@ #include "util/mallocHelper.h" #include "util/smbiosHelper.h" -#include +#include +#include "perflib_.h" +#include -static void ffPdhOpenCloseQuery(HQUERY* query) +static inline void ffPerfCloseQueryHandle(HANDLE* phQuery) { - assert(query); - if (*query) + if (*phQuery != NULL) { - PdhCloseQuery(*query); - *query = NULL; + PerfCloseQueryHandle(*phQuery); + *phQuery = NULL; } } -static const char* detectThermalTemp(double* result) +const char* detectThermalTemp(double* result) { - // typeperf.exe -sc 1 "\Thermal Zone Information(*)\Temperature" + struct FFPerfQuerySpec + { + PERF_COUNTER_IDENTIFIER Identifier; + WCHAR Name[16]; + } querySpec = { + .Identifier = { + // Thermal Zone Information + // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{52bc5412-dac2-449c-8bc2-96443888fe6b} + .CounterSetGuid = { 0x52bc5412, 0xdac2, 0x449c, {0x8b, 0xc2, 0x96, 0x44, 0x38, 0x88, 0xfe, 0x6b} }, + .Size = sizeof(querySpec), + .CounterId = PERF_WILDCARD_COUNTER, + .InstanceId = PERF_WILDCARD_COUNTER, + }, + .Name = L"\\_TZ.CPUZ", // The standard(?) instance name for CPU temperature in the thermal provider + }; + + DWORD dataSize = 0; + if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY) + return "PerfEnumerateCounterSetInstances() failed"; + + if (dataSize <= sizeof(PERF_INSTANCE_HEADER)) + return "No `Thermal Zone Information` instances found"; + + { + FF_AUTO_FREE PERF_INSTANCE_HEADER* const pHead = malloc(dataSize); + if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, pHead, dataSize, &dataSize) != ERROR_SUCCESS) + return "PerfEnumerateCounterSetInstances() failed to get instance headers"; + + PERF_INSTANCE_HEADER* pInstanceHeader = pHead; + while (1) + { + const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader)); + if (wcscmp(instanceName, querySpec.Name) == 0) + break; + + dataSize -= pInstanceHeader->Size; + if (dataSize == 0) + break; + pInstanceHeader = (PERF_INSTANCE_HEADER*)((BYTE*)pInstanceHeader + pInstanceHeader->Size); + } + + if (dataSize == 0) + { + const wchar_t* instanceName = (const wchar_t*)((BYTE*)pHead + sizeof(*pHead)); + wcscpy(querySpec.Name, instanceName); // Use the first instance name if the specific one is not found + } + } + + __attribute__((__cleanup__(ffPerfCloseQueryHandle))) + HANDLE hQuery = NULL; - __attribute__((__cleanup__(ffPdhOpenCloseQuery))) HQUERY query = NULL; + if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS) + return "PerfOpenQueryHandle() failed"; - if (PdhOpenQueryW(NULL, 0, &query) != ERROR_SUCCESS) - return "Failed to open PDH query"; + if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS) + return "PerfAddCounters() failed"; - HCOUNTER counter = NULL; - if (PdhAddEnglishCounterW(query, - L"\\Thermal Zone Information(*)\\Temperature", - 0, - &counter) != ERROR_SUCCESS) - return "Failed to add TZI temperature counter"; + if (querySpec.Identifier.Status != ERROR_SUCCESS) + return "PerfAddCounters() reports invalid identifier"; - if (PdhCollectQueryData(query) != ERROR_SUCCESS) - return "Failed to collect query data"; + if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY) + return "PerfQueryCounterData(NULL) failed"; - PDH_FMT_COUNTERVALUE value; - if (PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, NULL, &value) != ERROR_SUCCESS) - return "Failed to format counter value"; + if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER)) // PERF_ERROR_RETURN, should not happen + return "instance doesn't exist"; - *result = value.doubleValue - 273; + FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = malloc(dataSize); + + if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS) + return "PerfQueryCounterData(pDataHeader) failed"; + + PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1); + if (pCounterHeader->dwType != PERF_MULTIPLE_COUNTERS) + return "Invalid counter type"; + + PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1); + PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pMultiCounters + pMultiCounters->dwSize); + + for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++) + { + if (pCounterData->dwDataSize == sizeof(int32_t)) + { + DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1); + switch (pCounterIds[iCounter]) { + case 0: // Temperature + *result = *(int32_t*)(pCounterData + 1) - 273; + break; + case 3: // High Precision Temperature + *result = *(int32_t*)(pCounterData + 1) / 10.0 - 273; + break; + } + } + + pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize); + } return NULL; } diff --git a/src/detection/cpu/perflib_.h b/src/detection/cpu/perflib_.h new file mode 100644 index 0000000000..5c6a3febcb --- /dev/null +++ b/src/detection/cpu/perflib_.h @@ -0,0 +1,133 @@ +#pragma once + +#include +#include + +// Missing from of MinGW-w64 SDK + +#define PERF_WILDCARD_COUNTER 0xFFFFFFFF +#define PERF_WILDCARD_INSTANCE L"*" +#define PERF_AGGREGATE_INSTANCE L"_Total" +#define PERF_MAX_INSTANCE_NAME 1024 + +typedef struct _PERF_INSTANCE_HEADER { + ULONG Size; // = sizeof(PERF_INSTANCE_HEADER) + sizeof(InstanceName) + sizeof(Padding) + ULONG InstanceId; // Instance ID. + // Followed by: + // WCHAR InstanceName[]; // Nul-terminated. + // WCHAR Padding[]; // Pad to a multiple of 8 bytes +} PERF_INSTANCE_HEADER, *PPERF_INSTANCE_HEADER; + +typedef struct _PERF_COUNTER_IDENTIFIER { + GUID CounterSetGuid; // The GUID of the counterset. + ULONG Status; // Win32 error code indicating success/failure of the add/delete operation. + ULONG Size; // sizeof(PERF_COUNTER_IDENTIFIER) + sizeof(InstanceName) + sizeof(Padding) + ULONG CounterId; // CounterId, or PERF_WILDCARD_COUNTER for all counters. + ULONG InstanceId; // InstanceId, or 0xFFFFFFFF to not filter on instance ID. + ULONG Index; // Set by PerfQueryCounterInfo to the position in which the corresponding counter data is returned. + ULONG Reserved; // Reserved. + // Followed by: + // WCHAR InstanceName[]; + // WCHAR Padding[]; +} PERF_COUNTER_IDENTIFIER, * PPERF_COUNTER_IDENTIFIER; + +typedef struct _PERF_DATA_HEADER { + ULONG dwTotalSize; // = sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER blocks...) + ULONG dwNumCounters; // The number of PERF_COUNTER_HEADER blocks. + LONGLONG PerfTimeStamp; // Timestamp from a high-resolution clock. + LONGLONG PerfTime100NSec; // The number of 100 nanosecond intervals since January 1, 1601, in Coordinated Universal Time (UTC). + LONGLONG PerfFreq; // The frequency of a high-resolution clock. + SYSTEMTIME SystemTime; // The time at which data is collected on the provider side. + // Followed by: + // PERF_COUNTER_HEADER blocks...; +} PERF_DATA_HEADER, * PPERF_DATA_HEADER; + +typedef enum _PerfCounterDataType { + PERF_ERROR_RETURN = 0, /* An error occurred when the performance counter value was queried. */ + PERF_SINGLE_COUNTER = 1, /* Query returned a single counter from a single-instance. */ + PERF_MULTIPLE_COUNTERS = 2, /* Query returned multiple counters from a single instance. */ + PERF_MULTIPLE_INSTANCES = 4, /* Query returned a single counter from each of multiple instances. */ + PERF_COUNTERSET = 6 /* Query returned multiple counters from each of multiple instances. */ +} PerfCounterDataType; + +typedef struct _PERF_COUNTER_HEADER { + ULONG dwStatus; // Win32 error code indicating success/failure of the query operation. + PerfCounterDataType dwType; // Result type - error, single/single, multi/single, single/multi, multi/multi. + ULONG dwSize; // = sizeof(PERF_COUNTER_HEADER) + sizeof(Additional data) + ULONG Reserved; // Reserved. + // Followed by additional data: + // If dwType == PERF_ERROR_RETURN: nothing. + // If dwType == PERF_SINGLE_COUNTER: PERF_COUNTER_DATA block. + // If dwType == PERF_MULTIPLE_COUNTERS: PERF_MULTI_COUNTERS block + PERF_COUNTER_DATA blocks. + // If dwType == PERF_MULTIPLE_INSTANCES: PERF_MULTI_INSTANCES block. + // If dwType == PERF_COUNTERSET: PERF_MULTI_COUNTERS block + PERF_MULTI_INSTANCES block. +} PERF_COUNTER_HEADER, * PPERF_COUNTER_HEADER; + +typedef struct _PERF_MULTI_COUNTERS { + ULONG dwSize; // sizeof(PERF_MULTI_COUNTERS) + sizeof(CounterIds) + ULONG dwCounters; // Number of counter ids. + // Followed by: + // DWORD CounterIds[dwCounters]; +} PERF_MULTI_COUNTERS, * PPERF_MULTI_COUNTERS; + +typedef struct _PERF_COUNTER_DATA { + ULONG dwDataSize; // Size of the counter data, in bytes. + ULONG dwSize; // = sizeof(PERF_COUNTER_DATA) + sizeof(Data) + sizeof(Padding) + // Followed by: + // BYTE Data[dwDataSize]; + // BYTE Padding[]; +} PERF_COUNTER_DATA, * PPERF_COUNTER_DATA; + +_Success_(return == ERROR_SUCCESS) +ULONG +WINAPI +PerfEnumerateCounterSetInstances( + _In_opt_z_ LPCWSTR szMachine, + _In_ LPCGUID pCounterSetId, + _Out_opt_bytecap_post_bytecount_(cbInstances, *pcbInstancesActual) PPERF_INSTANCE_HEADER pInstances, + DWORD cbInstances, + _Out_ LPDWORD pcbInstancesActual + ); + +_Success_(return == ERROR_SUCCESS) +ULONG +WINAPI +PerfOpenQueryHandle( + _In_opt_z_ LPCWSTR szMachine, + _Out_ HANDLE * phQuery + ); + +_Success_(return == ERROR_SUCCESS) +ULONG +WINAPI +PerfCloseQueryHandle( + _In_ HANDLE hQuery + ); + +_Success_(return == ERROR_SUCCESS) +ULONG +WINAPI +PerfAddCounters( + _In_ HANDLE hQuery, + _Inout_bytecount_(cbCounters) PPERF_COUNTER_IDENTIFIER pCounters, + DWORD cbCounters + ); + +_Success_(return == ERROR_SUCCESS) +ULONG +WINAPI +PerfDeleteCounters( + _In_ HANDLE hQuery, + _Inout_bytecount_(cbCounters) PPERF_COUNTER_IDENTIFIER pCounters, + DWORD cbCounters + ); + +_Success_(return == ERROR_SUCCESS) +ULONG +WINAPI +PerfQueryCounterData( + _In_ HANDLE hQuery, + _Out_opt_bytecap_post_bytecount_(cbCounterBlock, *pcbCounterBlockActual) PPERF_DATA_HEADER pCounterBlock, + DWORD cbCounterBlock, + _Out_ LPDWORD pcbCounterBlockActual + ); diff --git a/src/detection/disk/disk_windows.c b/src/detection/disk/disk_windows.c index e8955908b8..092a247c36 100644 --- a/src/detection/disk/disk_windows.c +++ b/src/detection/disk/disk_windows.c @@ -99,9 +99,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) wchar_t diskName[MAX_PATH + 1], diskFileSystem[MAX_PATH + 1]; - //https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa#remarks - UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS); - DWORD diskFlags; BOOL result = GetVolumeInformationW(mountpoint, diskName, ARRAY_SIZE(diskName), //Volume name @@ -110,7 +107,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) &diskFlags, //File system flags diskFileSystem, ARRAY_SIZE(diskFileSystem) ); - SetErrorMode(errorMode); if(result) { diff --git a/src/detection/displayserver/displayserver_apple.c b/src/detection/displayserver/displayserver_apple.c index df6c7cf90c..4ef8d05209 100644 --- a/src/detection/displayserver/displayserver_apple.c +++ b/src/detection/displayserver/displayserver_apple.c @@ -2,6 +2,7 @@ #include "util/apple/cf_helpers.h" #include "util/stringUtils.h" #include "util/edidHelper.h" +#include "detection/os/os.h" #include #include @@ -194,7 +195,22 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) ffStrbufSetStatic(&ds->wmPrettyName, "Quartz Compositor"); } } - ffStrbufSetStatic(&ds->dePrettyName, "Aqua"); + + const FFOSResult* os = ffDetectOS(); + + char* str_end; + const char* version = os->version.chars; + unsigned long osNum = strtoul(version, &str_end, 10); + if (str_end != version) + { + if (osNum > 15) { // Tahoe + ffStrbufSetStatic(&ds->dePrettyName, "Liquid Glass"); + } else if (osNum < 10) { + ffStrbufSetStatic(&ds->dePrettyName, "Platinum"); + } else { + ffStrbufSetStatic(&ds->dePrettyName, "Aqua"); + } + } detectDisplays(ds); } diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index a81dd11f16..1ebee2de6c 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -49,7 +49,25 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus); const char* ffGPUGetVendorString(unsigned vendorId); +typedef struct FFGpuDriverPciBusId +{ + uint32_t domain; + uint32_t bus; + uint32_t device; + uint32_t func; +} FFGpuDriverPciBusId; + #if defined(__linux__) || defined(__FreeBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu); void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu); -#endif + +#if FF_HAVE_DRM +const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath); +const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath); +const char* ffDrmDetectI915(FFGPUResult* gpu, int fd); +const char* ffDrmDetectXe(FFGPUResult* gpu, int fd); +const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd); +#endif // FF_HAVE_DRM + +const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId); +#endif // defined(XXX) diff --git a/src/detection/gpu/gpu_apple.m b/src/detection/gpu/gpu_apple.m index 7adfde58ad..f3f9c98e7e 100644 --- a/src/detection/gpu/gpu_apple.m +++ b/src/detection/gpu/gpu_apple.m @@ -3,6 +3,9 @@ #import #import +#ifndef MAC_OS_VERSION_26_0 + #define MTLGPUFamilyMetal4 ((MTLGPUFamily) 5002) +#endif #ifndef MAC_OS_VERSION_13_0 #define MTLGPUFamilyMetal3 ((MTLGPUFamily) 5001) #endif @@ -57,7 +60,9 @@ else if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 1"); #else // MAC_OS_X_VERSION_10_15 - if ([device supportsFamily:MTLGPUFamilyMetal3]) + if ([device supportsFamily:MTLGPUFamilyMetal4]) + ffStrbufSetStatic(&gpu->platformApi, "Metal 4"); + else if ([device supportsFamily:MTLGPUFamilyMetal3]) ffStrbufSetStatic(&gpu->platformApi, "Metal 3"); else if ([device supportsFamily:MTLGPUFamilyCommon3]) ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3"); diff --git a/src/detection/gpu/gpu_bsd.c b/src/detection/gpu/gpu_bsd.c index 4dc142c5b4..20556b66f7 100644 --- a/src/detection/gpu/gpu_bsd.c +++ b/src/detection/gpu/gpu_bsd.c @@ -1,6 +1,7 @@ #include "gpu_driver_specific.h" #include "common/io/io.h" +#include "util/mallocHelper.h" #include #include @@ -10,11 +11,145 @@ #include // DragonFly #endif -const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) +static void fillGPUTypeGeneric(FFGPUResult* gpu) +{ + if (gpu->type == FF_GPU_TYPE_UNKNOWN) + { + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) + { + if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") || + ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") || + ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) + gpu->type = FF_GPU_TYPE_DISCRETE; + } + else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) + { + if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) + gpu->type = FF_GPU_TYPE_DISCRETE; + } + else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) + { + // 0000:00:02.0 is reserved for Intel integrated graphics + gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; + } + } +} + +#if FF_HAVE_DRM +#include "common/library.h" +#include "util/stringUtils.h" + +#include + +static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus) +{ + FF_LIBRARY_LOAD(libdrm, "dlopen libdrm" FF_LIBRARY_EXTENSION " failed", "libdrm" FF_LIBRARY_EXTENSION, 2) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices) + + drmDevicePtr devices[64]; + int nDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices)); + if (nDevices < 0) + return "drmGetDevices() failed"; + + for (int iDev = 0; iDev < nDevices; ++iDev) + { + drmDevice* dev = devices[iDev]; + + if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY))) + continue; + + const char* path = dev->nodes[DRM_NODE_PRIMARY]; + + FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus); + ffStrbufInit(&gpu->vendor); + ffStrbufInit(&gpu->name); + ffStrbufInit(&gpu->driver); + ffStrbufInitS(&gpu->platformApi, path); + ffStrbufInit(&gpu->memoryType); + gpu->index = FF_GPU_INDEX_UNSET; + gpu->temperature = FF_GPU_TEMP_UNSET; + gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; + gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; + gpu->type = FF_GPU_TYPE_UNKNOWN; + gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; + gpu->deviceId = 0; + gpu->frequency = FF_GPU_FREQUENCY_UNSET; + + switch (dev->bustype) + { + case DRM_BUS_PCI: + ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->deviceinfo.pci->vendor_id)); + gpu->deviceId = (dev->businfo.pci->domain * 100000ull) + (dev->businfo.pci->bus * 1000ull) + (dev->businfo.pci->dev * 10ull) + dev->businfo.pci->func; + break; + case DRM_BUS_HOST1X: + ffStrbufSetS(&gpu->name, dev->deviceinfo.host1x->compatible[0]); + gpu->type = FF_GPU_TYPE_INTEGRATED; + break; + case DRM_BUS_PLATFORM: + ffStrbufSetS(&gpu->name, dev->deviceinfo.platform->compatible[0]); + gpu->type = FF_GPU_TYPE_INTEGRATED; + break; + case DRM_BUS_USB: + ffStrbufSetF(&gpu->name, "USB Device (%u-%u)", dev->deviceinfo.usb->vendor, dev->deviceinfo.usb->product); + gpu->type = FF_GPU_TYPE_DISCRETE; + break; + } + + FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) continue; + + char driverName[64]; + driverName[0] = '\0'; + struct drm_version ver = { + .name = driverName, + .name_len = ARRAY_SIZE(driverName), + }; + if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0) + ffStrbufSetF(&gpu->driver, "%*s %d.%d.%d", (int) ver.name_len, ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel); + + if (ffStrStartsWith(driverName, "i915")) + ffDrmDetectI915(gpu, fd); + else if (ffStrStartsWith(driverName, "amdgpu")) + ffDrmDetectAmdgpu(options, gpu, dev->nodes[DRM_NODE_RENDER]); + else if (ffStrStartsWith(driverName, "radeon")) + ffDrmDetectRadeon(options, gpu, dev->nodes[DRM_NODE_RENDER]); + else if (ffStrStartsWith(driverName, "xe")) + ffDrmDetectXe(gpu, fd); + else if (ffStrStartsWith(driverName, "asahi")) + ffDrmDetectAsahi(gpu, fd); + else if (dev->bustype == DRM_BUS_PCI) + { + ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { + .domain = (uint32_t) dev->businfo.pci->domain, + .bus = dev->businfo.pci->bus, + .device = dev->businfo.pci->dev, + .func = dev->businfo.pci->func, + }); + } + + if (gpu->name.length == 0) + { + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) + ffGPUQueryAmdGpuName(dev->deviceinfo.pci->device_id, dev->deviceinfo.pci->revision_id, gpu); + if (gpu->name.length == 0) + ffGPUFillVendorAndName(0, dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id, gpu); + } + + fillGPUTypeGeneric(gpu); + } + + ffdrmFreeDevices(devices, nDevices); + + return NULL; +} +#endif + +static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) { - FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY, 0); + FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC); if (fd < 0) - return "open(\"/dev/pci\", O_RDONLY, 0) failed"; + return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed"; struct pci_conf confs[128]; struct pci_match_conf match = { @@ -54,27 +189,12 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) gpu->deviceId = (pc->pc_sel.pc_domain * 100000ull) + (pc->pc_sel.pc_bus * 1000ull) + (pc->pc_sel.pc_dev * 10ull) + pc->pc_sel.pc_func; gpu->frequency = FF_GPU_FREQUENCY_UNSET; - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific)) - { - ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) { - .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID, - .pciBusId = { - .domain = (uint32_t) pc->pc_sel.pc_domain, - .bus = pc->pc_sel.pc_bus, - .device = pc->pc_sel.pc_dev, - .func = pc->pc_sel.pc_func, - }, - }, (FFGpuDriverResult) { - .index = &gpu->index, - .temp = options->temp ? &gpu->temperature : NULL, - .memory = options->driverSpecific ? &gpu->dedicated : NULL, - .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, - .type = &gpu->type, - .frequency = &gpu->frequency, - .coreUsage = &gpu->coreUsage, - .name = &gpu->name, - }, "libnvidia-ml.so"); - } + ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { + .domain = (uint32_t) pc->pc_sel.pc_domain, + .bus = pc->pc_sel.pc_bus, + .device = pc->pc_sel.pc_dev, + .func = pc->pc_sel.pc_func, + }); if (gpu->name.length == 0) { @@ -84,27 +204,19 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu); } - if (gpu->type == FF_GPU_TYPE_UNKNOWN) - { - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) - { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) - gpu->type = FF_GPU_TYPE_DISCRETE; - } - else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) - { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) - gpu->type = FF_GPU_TYPE_DISCRETE; - } - else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) - { - // 0000:00:02.0 is reserved for Intel integrated graphics - gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; - } - } + fillGPUTypeGeneric(gpu); } return NULL; } + +const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) +{ + if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO) + { + detectByDrm(options, gpus); + if (gpus->length > 0) return NULL; + } + + return detectByPci(options, gpus); +} diff --git a/src/detection/gpu/gpu_driver_specific.h b/src/detection/gpu/gpu_driver_specific.h index 82db3f66b2..37b4a67282 100644 --- a/src/detection/gpu/gpu_driver_specific.h +++ b/src/detection/gpu/gpu_driver_specific.h @@ -10,14 +10,6 @@ typedef enum __attribute__((__packed__)) FFGpuDriverConditionType FF_GPU_DRIVER_CONDITION_TYPE_FORCE_UNSIGNED = UINT8_MAX, } FFGpuDriverConditionType; -typedef struct FFGpuDriverPciBusId -{ - uint32_t domain; - uint32_t bus; - uint32_t device; - uint32_t func; -} FFGpuDriverPciBusId; - typedef struct FFGpuDriverPciDeviceId { uint32_t deviceId; diff --git a/src/detection/gpu/gpu_drm.c b/src/detection/gpu/gpu_drm.c new file mode 100644 index 0000000000..192364568e --- /dev/null +++ b/src/detection/gpu/gpu_drm.c @@ -0,0 +1,372 @@ +#include "gpu.h" + +#if FF_HAVE_DRM +#include +#include +#include + +#include "common/io/io.h" +#include "common/library.h" +#include "util/mallocHelper.h" +#include "util/stringUtils.h" + +#include "intel_drm.h" +#include "asahi_drm.h" +#include + +const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath) +{ + FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC); + if (fd < 0) return "Failed to open DRM render device"; + + uint32_t value; + + // https://github.com/torvalds/linux/blob/fb4d33ab452ea254e2c319bac5703d1b56d895bf/drivers/gpu/drm/radeon/radeon_kms.c#L231 + + if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) { + .request = RADEON_INFO_ACTIVE_CU_COUNT, + .value = (uintptr_t) &value, + }) >= 0) + gpu->coreCount = (int32_t) value; + + if (options->temp) + { + if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) { + .request = RADEON_INFO_CURRENT_GPU_TEMP, // millidegrees C + .value = (uintptr_t) &value, + }) >= 0 && value != 0) // 0 means unavailable + gpu->temperature = (double) value / 1000.0; + } + + if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) { + .request = RADEON_INFO_MAX_SCLK, // MHz + .value = (uintptr_t) &value, + }) >= 0) + gpu->frequency = (uint32_t) (value / 1000u); + + if (options->driverSpecific) + { + struct drm_radeon_gem_info gemInfo; + if (ioctl(fd, DRM_IOCTL_RADEON_GEM_INFO, &gemInfo) >= 0) + { + // vram_usage can be bigger than vram_usage, so we use vram_size here + gpu->dedicated.total = gemInfo.vram_size; + gpu->shared.total = gemInfo.gart_size; + + uint64_t memSize; + if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) { + .request = RADEON_INFO_VRAM_USAGE, // uint64_t + .value = (uintptr_t) &memSize, + }) >= 0) + gpu->dedicated.used = memSize; + + if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) { + .request = RADEON_INFO_GTT_USAGE, // uint64_t + .value = (uintptr_t) &memSize, + }) >= 0) + gpu->shared.used = memSize; + } + } + + return NULL; +} + +#ifdef FF_HAVE_DRM_AMDGPU +#include +#include + +const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath) +{ +#if FF_HAVE_DRM_AMDGPU + FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize) + + FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC); + if (fd < 0) return "Failed to open DRM render device"; + + amdgpu_device_handle handle; + uint32_t majorVersion, minorVersion; + if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0) + return "Failed to initialize AMDGPU device"; + + uint32_t value; + + if (options->temp) + { + if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0) + gpu->temperature = value / 1000.; + } + + ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle)); + + struct amdgpu_gpu_info gpuInfo; + if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0) + { + gpu->coreCount = (int32_t) gpuInfo.cu_active_number; + gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u); + gpu->index = FF_GPU_INDEX_UNSET; + gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; +#define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break + switch (gpuInfo.vram_type) + { + FF_VRAM_CASE(UNKNOWN, 0); + FF_VRAM_CASE(GDDR1, 1); + FF_VRAM_CASE(DDR2, 2); + FF_VRAM_CASE(GDDR3, 3); + FF_VRAM_CASE(GDDR4, 4); + FF_VRAM_CASE(GDDR5, 5); + FF_VRAM_CASE(HBM, 6); + FF_VRAM_CASE(DDR3, 7); + FF_VRAM_CASE(DDR4, 8); + FF_VRAM_CASE(GDDR6, 9); + FF_VRAM_CASE(DDR5, 10); + FF_VRAM_CASE(LPDDR4, 11); + FF_VRAM_CASE(LPDDR5, 12); + default: + ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type); + break; + } + + struct amdgpu_heap_info heapInfo; + if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0) + { + gpu->dedicated.total = heapInfo.heap_size; + gpu->dedicated.used = heapInfo.heap_usage; + } + if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_GTT, 0, &heapInfo) >= 0) + { + gpu->shared.total = heapInfo.heap_size; + gpu->shared.used = heapInfo.heap_usage; + } + } + + if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0) + gpu->coreUsage = value; + + ffamdgpu_device_deinitialize(handle); + + return NULL; +#else + FF_UNUSED(gpu, renderPath); + return "Fastfetch is compiled without libdrm support"; +#endif +} +#endif + +const char* ffDrmDetectI915(FFGPUResult* gpu, int fd) +{ + { + int value; + drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value }; + if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0) + gpu->coreCount = value; + } + { + struct drm_i915_query_item queryItem = { + .query_id = DRM_I915_QUERY_MEMORY_REGIONS, + }; + struct drm_i915_query query = { + .items_ptr = (uintptr_t) &queryItem, + .num_items = 1, + }; + if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 ) + { + FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length); + queryItem.data_ptr = (uintptr_t) buffer; + if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0) + { + gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; + struct drm_i915_query_memory_regions* regionInfo = (void*) buffer; + for (uint32_t i = 0; i < regionInfo->num_regions; i++) + { + struct drm_i915_memory_region_info* region = regionInfo->regions + i; + switch (region->region.memory_class) + { + case I915_MEMORY_CLASS_SYSTEM: + gpu->shared.total += region->probed_size; + gpu->shared.used += region->probed_size - region->unallocated_size; + break; + case I915_MEMORY_CLASS_DEVICE: + gpu->dedicated.total += region->probed_size; + gpu->dedicated.used += region->probed_size - region->unallocated_size; + break; + } + } + } + } + } + return NULL; +} + +static inline int popcountBytes(uint8_t* bytes, uint32_t length) +{ + int count = 0; + while (length >= 8) + { + count += __builtin_popcountll(*(uint64_t*) bytes); + bytes += 8; + length -= 8; + } + if (length >= 4) + { + count += __builtin_popcountl(*(uint32_t*) bytes); + bytes += 4; + length -= 4; + } + if (length >= 2) + { + count += __builtin_popcountl(*(uint16_t*) bytes); + bytes += 2; + length -= 2; + } + if (length) + { + count += __builtin_popcountl(*(uint8_t*) bytes); + } + return count; +} + +const char* ffDrmDetectXe(FFGPUResult* gpu, int fd) +{ + bool flag = false; + { + struct drm_xe_device_query query = { + .query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY, + }; + if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) + { + FF_AUTO_FREE uint8_t* buffer = malloc(query.size); + query.data = (uintptr_t) buffer; + if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) + { + int dssCount = 0, euPerDssCount = 0; + for (struct drm_xe_query_topology_mask* topo = (void*) buffer; + (uint8_t*) topo < buffer + query.size; + topo = (void*) (topo->mask + topo->num_bytes) + ) { + switch (topo->type) + { + case DRM_XE_TOPO_DSS_COMPUTE: + case DRM_XE_TOPO_DSS_GEOMETRY: + dssCount += popcountBytes(topo->mask, topo->num_bytes); + break; + case DRM_XE_TOPO_EU_PER_DSS: + euPerDssCount += popcountBytes(topo->mask, topo->num_bytes); + break; + } + } + gpu->coreCount = dssCount * euPerDssCount; + flag = true; + } + } + } + + { + struct drm_xe_device_query query = { + .query = DRM_XE_DEVICE_QUERY_MEM_REGIONS, + }; + if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) + { + FF_AUTO_FREE uint8_t* buffer = malloc(query.size); + query.data = (uintptr_t) buffer; + if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) + { + gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; + struct drm_xe_query_mem_regions* regionInfo = (void*) buffer; + for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++) + { + struct drm_xe_mem_region* region = regionInfo->mem_regions + i; + switch (region->mem_class) + { + case DRM_XE_MEM_REGION_CLASS_SYSMEM: + gpu->shared.total += region->total_size; + gpu->shared.used += region->used; + break; + case DRM_XE_MEM_REGION_CLASS_VRAM: + gpu->dedicated.total += region->total_size; + gpu->dedicated.used += region->used; + break; + } + } + flag = true; + } + } + } + return flag ? NULL : "Failed to query Xe GPU information"; +} + +const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd) +{ + struct drm_asahi_params_global paramsGlobal = {}; + if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) { + .param_group = DRM_ASAHI_GET_PARAMS, + .pointer = (uint64_t) ¶msGlobal, + .size = sizeof(paramsGlobal), + }) >= 0) + { + // They removed `unstable_uabi_version` from the struct. Hopefully they won't introduce new ABI changes. + gpu->coreCount = (int32_t) (paramsGlobal.num_clusters_total * paramsGlobal.num_cores_per_cluster); + gpu->frequency = paramsGlobal.max_frequency_khz / 1000; + gpu->deviceId = paramsGlobal.chip_id; + + if (!gpu->name.length) + { + const char* variant = " Unknown"; + switch (paramsGlobal.gpu_variant) { + case 'G': + variant = ""; + break; + case 'S': + variant = " Pro"; + break; + case 'C': + variant = " Max"; + break; + case 'D': + variant = " Ultra"; + break; + } + ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)", + paramsGlobal.gpu_generation - 12, variant, + paramsGlobal.gpu_generation, paramsGlobal.gpu_variant, + paramsGlobal.gpu_revision + 0xA0); + } + + return NULL; + } + + return "Failed to query Asahi GPU information"; +} + +#endif // FF_HAVE_DRM + +#include "gpu_driver_specific.h" + +const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId) +{ + __typeof__(&ffDetectNvidiaGpuInfo) detectFn; + const char* soName; + if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific)) + { + return detectFn(&(FFGpuDriverCondition) { + .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID, + .pciBusId = pciBusId, + }, (FFGpuDriverResult) { + .index = &gpu->index, + .temp = options->temp ? &gpu->temperature : NULL, + .memory = options->driverSpecific ? &gpu->dedicated : NULL, + .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, + .coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL, + .type = &gpu->type, + .frequency = options->driverSpecific ? &gpu->frequency : NULL, + .name = &gpu->name, + }, soName); + } + + return "No driver-specific detection function found for the GPU vendor"; +} diff --git a/src/detection/gpu/gpu_haiku.c b/src/detection/gpu/gpu_haiku.c index ec1e566f8f..09c34e70f9 100644 --- a/src/detection/gpu/gpu_haiku.c +++ b/src/detection/gpu/gpu_haiku.c @@ -5,7 +5,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus) { - FF_AUTO_CLOSE_FD int pokefd = open(POKE_DEVICE_FULLNAME, O_RDWR); + FF_AUTO_CLOSE_FD int pokefd = open(POKE_DEVICE_FULLNAME, O_RDWR | O_CLOEXEC); if (pokefd < 0) return "open(POKE_DEVICE_FULLNAME) failed"; pci_info dev; diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index 681845f1f9..c37502e47a 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -105,93 +105,23 @@ FF_MAYBE_UNUSED static const char* drmFindRenderFromCard(const char* drmCardKey, static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) { - #if FF_HAVE_DRM_AMDGPU - - FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize) - - { - const char* error = drmFindRenderFromCard(drmKey, buffer); - if (error) return error; - } - FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY); - if (fd < 0) return "Failed to open DRM device"; - - amdgpu_device_handle handle; - uint32_t majorVersion, minorVersion; - if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0) - return "Failed to initialize AMDGPU device"; - - ffStrbufAppendF(&gpu->driver, " %u.%u", (unsigned) majorVersion, (unsigned) minorVersion); - - uint32_t value; - - if (options->temp) - { - if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0) - gpu->temperature = value / 1000.; - } - - ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle)); - - struct amdgpu_gpu_info gpuInfo; - if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0) + #if FF_HAVE_DRM + const char* error = drmFindRenderFromCard(drmKey, buffer); + if (error) return error; + if (ffStrbufEqualS(&gpu->driver, "radeon")) + return ffDrmDetectRadeon(options, gpu, buffer->chars); + else { - gpu->coreCount = (int32_t) gpuInfo.cu_active_number; - gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u); - gpu->index = FF_GPU_INDEX_UNSET; - gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; - #define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break - switch (gpuInfo.vram_type) - { - FF_VRAM_CASE(UNKNOWN, 0); - FF_VRAM_CASE(GDDR1, 1); - FF_VRAM_CASE(DDR2, 2); - FF_VRAM_CASE(GDDR3, 3); - FF_VRAM_CASE(GDDR4, 4); - FF_VRAM_CASE(GDDR5, 5); - FF_VRAM_CASE(HBM, 6); - FF_VRAM_CASE(DDR3, 7); - FF_VRAM_CASE(DDR4, 8); - FF_VRAM_CASE(GDDR6, 9); - FF_VRAM_CASE(DDR5, 10); - FF_VRAM_CASE(LPDDR4, 11); - FF_VRAM_CASE(LPDDR5, 12); - default: - ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type); - break; - } - - struct amdgpu_heap_info heapInfo; - if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0) - { - if (gpu->type == FF_GPU_TYPE_DISCRETE) - { - gpu->dedicated.total = heapInfo.heap_size; - gpu->dedicated.used = heapInfo.heap_usage; - } - else - { - gpu->shared.total = heapInfo.heap_size; - gpu->shared.used = heapInfo.heap_usage; - } - } + #if FF_HAVE_DRM_AMDGPU + return ffDrmDetectAmdgpu(options, gpu, buffer->chars); + #else + FF_UNUSED(options, gpu, drmKey, buffer); + return "Fastfetch is not compiled with libdrm_amdgpu support"; + #endif } - - if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0) - gpu->coreUsage = value; - - ffamdgpu_device_deinitialize(handle); - - return NULL; #else - FF_UNUSED(options, gpu, drmKey, buffer); - return "Fastfetch is compiled without libdrm support"; + FF_UNUSED(gpu, drmKey, buffer); + return "Fastfetch is not compiled with drm support"; #endif } @@ -215,47 +145,50 @@ static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, ffStrbufAppendC(pciDir, '/'); const uint32_t hwmonLen = pciDir->length; - ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only) - if (ffPathExists(pciDir->chars, FF_PATHTYPE_ANY)) - gpu->type = FF_GPU_TYPE_INTEGRATED; - else - gpu->type = FF_GPU_TYPE_DISCRETE; - uint64_t value = 0; if (options->temp) { - ffStrbufSubstrBefore(pciDir, hwmonLen); ffStrbufAppendS(pciDir, "temp1_input"); // The on die GPU temperature in millidegrees Celsius if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0))) gpu->temperature = (double) value / 1000; } - if (options->driverSpecific) + if (ffStrbufEqualS(&gpu->driver, "amdgpu")) // Ancient radeon drivers don't have these files { - ffStrbufSubstrBefore(pciDir, pciDirLen); - ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total"); - if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0))) - { - if (gpu->type == FF_GPU_TYPE_DISCRETE) - gpu->dedicated.total = value; - else - gpu->shared.total = value; + ffStrbufSubstrBefore(pciDir, hwmonLen); + ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only) + if (ffPathExists(pciDir->chars, FF_PATHTYPE_ANY)) + gpu->type = FF_GPU_TYPE_INTEGRATED; + else + gpu->type = FF_GPU_TYPE_DISCRETE; - ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total")); - ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used"); + if (options->driverSpecific) + { + ffStrbufSubstrBefore(pciDir, pciDirLen); + ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total"); if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0))) { if (gpu->type == FF_GPU_TYPE_DISCRETE) - gpu->dedicated.used = value; + gpu->dedicated.total = value; else - gpu->shared.used = value; + gpu->shared.total = value; + + ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total")); + ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used"); + if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0))) + { + if (gpu->type == FF_GPU_TYPE_DISCRETE) + gpu->dedicated.used = value; + else + gpu->shared.used = value; + } } - } - ffStrbufSubstrBefore(pciDir, pciDirLen); - ffStrbufAppendS(pciDir, "/gpu_busy_percent"); - if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0))) - gpu->coreUsage = (double) value; + ffStrbufSubstrBefore(pciDir, pciDirLen); + ffStrbufAppendS(pciDir, "/gpu_busy_percent"); + if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0))) + gpu->coreUsage = (double) value; + } } } @@ -311,150 +244,19 @@ static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu } } -static inline int popcountBytes(uint8_t* bytes, uint32_t length) -{ - int count = 0; - while (length >= 8) - { - count += __builtin_popcountll(*(uint64_t*) bytes); - bytes += 8; - length -= 8; - } - if (length >= 4) - { - count += __builtin_popcountl(*(uint32_t*) bytes); - bytes += 4; - length -= 4; - } - if (length >= 2) - { - count += __builtin_popcountl(*(uint16_t*) bytes); - bytes += 2; - length -= 2; - } - if (length) - { - count += __builtin_popcountl(*(uint8_t*) bytes); - } - return count; -} - static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) { #if FF_HAVE_DRM ffStrbufSetS(buffer, "/dev/dri/"); ffStrbufAppendS(buffer, drmKey); - FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY); + FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC); if (fd < 0) return "Failed to open drm device"; if (ffStrbufEqualS(&gpu->driver, "xe")) - { - { - struct drm_xe_device_query query = { - .query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY, - }; - if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) - { - FF_AUTO_FREE uint8_t* buffer = malloc(query.size); - query.data = (uintptr_t) buffer; - if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) - { - int dssCount = 0, euPerDssCount = 0; - for (struct drm_xe_query_topology_mask* topo = (void*) buffer; - (uint8_t*) topo < buffer + query.size; - topo = (void*) (topo->mask + topo->num_bytes) - ) { - switch (topo->type) - { - case DRM_XE_TOPO_DSS_COMPUTE: - case DRM_XE_TOPO_DSS_GEOMETRY: - dssCount += popcountBytes(topo->mask, topo->num_bytes); - break; - case DRM_XE_TOPO_EU_PER_DSS: - euPerDssCount += popcountBytes(topo->mask, topo->num_bytes); - break; - } - } - gpu->coreCount = dssCount * euPerDssCount; - } - } - } - - { - struct drm_xe_device_query query = { - .query = DRM_XE_DEVICE_QUERY_MEM_REGIONS, - }; - if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) - { - FF_AUTO_FREE uint8_t* buffer = malloc(query.size); - query.data = (uintptr_t) buffer; - if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0) - { - gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; - struct drm_xe_query_mem_regions* regionInfo = (void*) buffer; - for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++) - { - struct drm_xe_mem_region* region = regionInfo->mem_regions + i; - switch (region->mem_class) - { - case DRM_XE_MEM_REGION_CLASS_SYSMEM: - gpu->shared.total += region->total_size; - gpu->shared.used += region->used; - break; - case DRM_XE_MEM_REGION_CLASS_VRAM: - gpu->dedicated.total += region->total_size; - gpu->dedicated.used += region->used; - break; - } - } - } - } - } - } + return ffDrmDetectXe(gpu, fd); else if (ffStrbufEqualS(&gpu->driver, "i915")) - { - { - int value; - drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value }; - if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0) - gpu->coreCount = value; - } - { - struct drm_i915_query_item queryItem = { - .query_id = DRM_I915_QUERY_MEMORY_REGIONS, - }; - struct drm_i915_query query = { - .items_ptr = (uintptr_t) &queryItem, - .num_items = 1, - }; - if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 ) - { - FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length); - queryItem.data_ptr = (uintptr_t) buffer; - if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0) - { - gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0; - struct drm_i915_query_memory_regions* regionInfo = (void*) buffer; - for (uint32_t i = 0; i < regionInfo->num_regions; i++) - { - struct drm_i915_memory_region_info* region = regionInfo->regions + i; - switch (region->region.memory_class) - { - case I915_MEMORY_CLASS_SYSTEM: - gpu->shared.total += region->probed_size; - gpu->shared.used += region->probed_size - region->unallocated_size; - break; - case I915_MEMORY_CLASS_DEVICE: - gpu->dedicated.total += region->probed_size; - gpu->dedicated.used += region->probed_size - region->unallocated_size; - break; - } - } - } - } - } - } - return NULL; + return ffDrmDetectI915(gpu, fd); + return "Unknown Intel GPU driver"; #else FF_UNUSED(gpu, drmKey, buffer); return "Fastfetch is not compiled with drm support"; @@ -569,29 +371,12 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf } else { - __typeof__(&ffDetectNvidiaGpuInfo) detectFn; - const char* soName; - if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific)) - { - detectFn(&(FFGpuDriverCondition) { - .type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID, - .pciBusId = { - .domain = pciDomain, - .bus = pciBus, - .device = pciDevice, - .func = pciFunc, - }, - }, (FFGpuDriverResult) { - .index = &gpu->index, - .temp = options->temp ? &gpu->temperature : NULL, - .memory = options->driverSpecific ? &gpu->dedicated : NULL, - .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, - .coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL, - .type = &gpu->type, - .frequency = options->driverSpecific ? &gpu->frequency : NULL, - .name = &gpu->name, - }, soName); - } + ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { + .domain = pciDomain, + .bus = pciBus, + .device = pciDevice, + .func = pciFunc, + }); } if (gpu->name.length == 0) @@ -627,45 +412,9 @@ FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, cons #if FF_HAVE_DRM_ASAHI ffStrbufSetS(buffer, "/dev/dri/"); ffStrbufAppendS(buffer, drmKey); - FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY); + FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC); if (fd >= 0) - { - struct drm_asahi_params_global paramsGlobal = {}; - if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) { - .param_group = DRM_ASAHI_GET_PARAMS, - .pointer = (uint64_t) ¶msGlobal, - .size = sizeof(paramsGlobal), - }) >= 0) - { - // They removed `unstable_uabi_version` from the struct. Hopefully they won't introduce new ABI changes. - gpu->coreCount = (int32_t) (paramsGlobal.num_clusters_total * paramsGlobal.num_cores_per_cluster); - gpu->frequency = paramsGlobal.max_frequency_khz / 1000; - gpu->deviceId = paramsGlobal.chip_id; - - if (!gpu->name.length) - { - const char* variant = " Unknown"; - switch (paramsGlobal.gpu_variant) { - case 'G': - variant = ""; - break; - case 'S': - variant = " Pro"; - break; - case 'C': - variant = " Max"; - break; - case 'D': - variant = " Ultra"; - break; - } - ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)", - paramsGlobal.gpu_generation - 12, variant, - paramsGlobal.gpu_generation, paramsGlobal.gpu_variant, - paramsGlobal.gpu_revision + 0xA0); - } - } - } + return ffDrmDetectAsahi(gpu, fd); #endif return NULL; diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index c83b096848..2477ea7e94 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -36,6 +36,10 @@ const char* getOthersByIokit(FFHostResult* host) if (manufacturer) ffCfStrGetString(manufacturer, &host->vendor); + FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("version"), kCFAllocatorDefault, kNilOptions); + if (version) + ffCfStrGetString(version, &host->version); + return NULL; } diff --git a/src/detection/host/host_linux.c b/src/detection/host/host_linux.c index 2ed4d71adc..7f8108cc81 100644 --- a/src/detection/host/host_linux.c +++ b/src/detection/host/host_linux.c @@ -77,10 +77,11 @@ const char* ffDetectHost(FFHostResult* host) //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->name, "Windows Subsystem for Linux"); + ffStrbufSetStatic(&host->name, "Windows Subsystem for Linux"); if (wslDistroName) ffStrbufAppendF(&host->name, " - %s", wslDistroName); - ffStrbufAppendS(&host->family, "WSL"); + ffStrbufSetStatic(&host->family, "WSL"); + ffStrbufSetStatic(&host->vendor, "Microsoft Corporation"); if (instance.config.general.detectVersion) { @@ -92,6 +93,17 @@ const char* ffDetectHost(FFHostResult* host) }); // supported in 2.2.3 and later } } + else if (ffStrbufStartsWithS(&instance.state.platform.sysinfo.version, "FreeBSD ")) + { + ffStrbufSetStatic(&host->name, "Linux Binary Compatibility on FreeBSD"); + ffStrbufSetStatic(&host->family, "FreeBSD"); + ffStrbufSetStatic(&host->vendor, "FreeBSD Foundation"); + if (instance.config.general.detectVersion) + { + ffStrbufSetS(&host->version, instance.state.platform.sysinfo.version.chars + strlen("FreeBSD ")); + ffStrbufSubstrBeforeFirstC(&host->version, ' '); + } + } } return NULL; diff --git a/src/detection/os/os_apple.m b/src/detection/os/os_apple.m index dc8e30a126..e404e0d429 100644 --- a/src/detection/os/os_apple.m +++ b/src/detection/os/os_apple.m @@ -37,6 +37,8 @@ static bool detectOSCodeName(FFOSResult* os) switch (num) { + case 26: + case 16: ffStrbufSetStatic(&os->codename, "Tahoe"); return true; case 15: ffStrbufSetStatic(&os->codename, "Sequoia"); return true; case 14: ffStrbufSetStatic(&os->codename, "Sonoma"); return true; case 13: ffStrbufSetStatic(&os->codename, "Ventura"); return true; diff --git a/src/detection/os/os_linux.c b/src/detection/os/os_linux.c index 1397febe66..a7150cda8f 100644 --- a/src/detection/os/os_linux.c +++ b/src/detection/os/os_linux.c @@ -231,6 +231,24 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result) ffStrbufSetF(&result->prettyName, "Proxmox VE %s", result->versionID.chars); return true; } + else if (ffStrbufContainS(&instance.state.platform.sysinfo.release, "+rpt-rpi-")) + { + // Raspberry Pi OS + ffStrbufSetS(&result->id, "raspbian"); + ffStrbufSetS(&result->idLike, "debian"); + ffStrbufSetS(&result->name, "Raspberry Pi OS"); + ffStrbufSetS(&result->prettyName, "Raspberry Pi OS"); + return true; + } + else if (ffStrbufEndsWithS(&instance.state.platform.sysinfo.release, "+truenas")) + { + // TrueNAS Scale + ffStrbufSetS(&result->id, "truenas-scale"); + ffStrbufSetS(&result->idLike, "debian"); + ffStrbufSetS(&result->name, "TrueNAS Scale"); + ffStrbufSetS(&result->prettyName, "TrueNAS Scale"); + return true; + } else { // Hack for MX Linux. See #847 @@ -286,8 +304,19 @@ static void detectOS(FFOSResult* os) parseOsRelease(FASTFETCH_TARGET_DIR_ETC "/os-release", os); if (os->id.length == 0 || os->version.length == 0 || os->prettyName.length == 0 || os->codename.length == 0) parseLsbRelease(FASTFETCH_TARGET_DIR_ETC "/lsb-release", os); - if (os->id.length == 0 || os->name.length > 0 || os->prettyName.length > 0) + if (os->id.length == 0 || os->name.length == 0 || os->prettyName.length == 0) parseOsRelease(FASTFETCH_TARGET_DIR_USR "/lib/os-release", os); + if (os->id.length == 0 && os->name.length == 0 && os->prettyName.length == 0) + { + // HarmonyOS has no os-release file + if (ffStrbufEqualS(&instance.state.platform.sysinfo.name, "HarmonyOS")) + { + ffStrbufSetS(&os->id, "harmonyos"); + ffStrbufSetS(&os->idLike, "harmonyos"); + ffStrbufSetS(&os->name, "HarmonyOS"); + ffStrbufSetS(&os->prettyName, "HarmonyOS"); + } + } } void ffDetectOSImpl(FFOSResult* os) diff --git a/src/detection/packages/packages.c b/src/detection/packages/packages.c index 373256568b..71ca2e609d 100644 --- a/src/detection/packages/packages.c +++ b/src/detection/packages/packages.c @@ -100,22 +100,23 @@ uint32_t ffPackagesGetNumElements(const char* dirname, bool isdir) { bool ok = false; + if (entry->d_name[0] != '.') + { #if !defined(__sun) && !defined(__HAIKU__) - if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) - ok = entry->d_type == (isdir ? DT_DIR : DT_REG); - else + if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) + ok = entry->d_type == (isdir ? DT_DIR : DT_REG); + else #endif - { - struct stat stbuf; - if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0) - ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode); + { + struct stat stbuf; + if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0) + ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode); + } } if(ok) ++num_elements; } - if(isdir && num_elements >= 2) - num_elements -= 2; // accounting for . and .. return num_elements; } diff --git a/src/detection/physicaldisk/physicaldisk_haiku.c b/src/detection/physicaldisk/physicaldisk_haiku.c index 2599387ef2..2b75cde4ef 100644 --- a/src/detection/physicaldisk/physicaldisk_haiku.c +++ b/src/detection/physicaldisk/physicaldisk_haiku.c @@ -10,7 +10,7 @@ static const char* detectDisk(FFstrbuf* path, const char* diskType, FFlist* result) { - FF_AUTO_CLOSE_FD int rawfd = open(path->chars, O_RDONLY); + FF_AUTO_CLOSE_FD int rawfd = open(path->chars, O_RDONLY | O_CLOEXEC); if (rawfd < 0) return "detectDisk: open(rawfd) failed"; device_geometry geometry; diff --git a/src/detection/sound/sound_bsd.c b/src/detection/sound/sound_bsd.c index fd6236cf15..dae28a4ed9 100644 --- a/src/detection/sound/sound_bsd.c +++ b/src/detection/sound/sound_bsd.c @@ -32,7 +32,7 @@ const char* ffDetectSound(FFlist* devices) for (int idev = 0; idev <= info.nummixers; ++idev) { path[strlen("/dev/mixer")] = (char) ('0' + idev); - FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR); + FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC); if (fd < 0) break; if (idev == 0) diff --git a/src/detection/sound/sound_nbsd.c b/src/detection/sound/sound_nbsd.c index 8ce71d77dc..88fd5f5050 100644 --- a/src/detection/sound/sound_nbsd.c +++ b/src/detection/sound/sound_nbsd.c @@ -25,7 +25,7 @@ const char* ffDetectSound(FFlist* devices) for (int idev = 0; idev < 9; ++idev) { path[strlen("/dev/audio")] = (char) ('0' + idev); - FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR); + FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC); if (fd < 0) break; audio_device_t ad; diff --git a/src/detection/terminalfont/terminalfont.c b/src/detection/terminalfont/terminalfont.c index 156cfb3c70..fe1f8e52c1 100644 --- a/src/detection/terminalfont/terminalfont.c +++ b/src/detection/terminalfont/terminalfont.c @@ -243,6 +243,29 @@ static bool detectContour(const FFstrbuf* exe, FFTerminalFontResult* result) return true; } +static bool detectRio(FFTerminalFontResult* terminalFont) +{ + FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate(); + + FFpropquery fontQueryToml[] = { + {"family =", &fontName}, + {"size =", &fontSize}, + }; + + ffParsePropFileConfigValues("rio/config.toml", 2, fontQueryToml); + + if(fontName.length == 0) + ffStrbufAppendS(&fontName, "Cascadia Code"); + + if(fontSize.length == 0) + ffStrbufAppendS(&fontSize, "18"); + + ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars); + + return true; +} + void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont); static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) @@ -257,6 +280,8 @@ static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTermina detectContour(&terminal->exe, terminalFont); else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "ghostty")) detectGhostty(terminalFont); + else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "rio")) + detectRio(terminalFont); #ifndef _WIN32 else if(ffStrbufStartsWithIgnCaseS(&terminal->exe, "/dev/pts/")) diff --git a/src/detection/wm/wm_apple.m b/src/detection/wm/wm_apple.m index fba7b3f225..889d7ccb46 100644 --- a/src/detection/wm/wm_apple.m +++ b/src/detection/wm/wm_apple.m @@ -30,6 +30,7 @@ !ffStrEqualsIgnCase(comm, "kwm") && !ffStrEqualsIgnCase(comm, "chunkwm") && !ffStrEqualsIgnCase(comm, "yabai") && + !ffStrEqualsIgnCase(comm, "aerospace") && !ffStrEqualsIgnCase(comm, "rectangle") ) continue; diff --git a/src/detection/wm/wm_linux.c b/src/detection/wm/wm_linux.c index 6d7e7b8f79..1e8870f997 100644 --- a/src/detection/wm/wm_linux.c +++ b/src/detection/wm/wm_linux.c @@ -237,7 +237,7 @@ const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE if (!wmName) return "No WM detected"; - if (ffStrbufEqualS(wmName, "Hyprland")) + if (ffStrbufIgnCaseEqualS(wmName, "Hyprland")) return getHyprland(result); if (ffStrbufEqualS(wmName, "sway")) diff --git a/src/logo/ascii/anushos.txt b/src/logo/ascii/anushos.txt new file mode 100644 index 0000000000..bf831b7708 --- /dev/null +++ b/src/logo/ascii/anushos.txt @@ -0,0 +1,20 @@ + $4####################### + $4# $2##### $4# + $4# $2####### $4# + $4# $2##$5O$2#$5O$2## $4# + $4# $2#$3#####$2# $4# + $4# $2##$1##$3###$1##$2## $4# + $4# $2#$1##########$2## $4# + $4# $2#$1############$2## $4# + $4# $2#$1######$5A_O$1####$2### $4# + $4# $3##$2#$1############$2##$3## $4# + $4#$3######$2#$1#######$2#$3######$4# + $4#$3#######$2#$1#####$2#$3#######$4# + $4# $3#####$2#######$3##### $4# + $4####################### + $4#$5╔═╗╔╗╔╦ ╦╔═╗╦ ╦╔═╗╔═╗$4# + $4#$5╠═╣║║║║ ║╚═╗╠═╣║ ║╚═╗$4# + $4#$5╩ ╩╝╚╝╚═╝╚═╝╩ ╩╚═╝╚═╝$4# + $4####################### + $4# $3WWW.ANUSHOS.ORG $4# + $4####################### diff --git a/src/logo/ascii/bedrock_small.txt b/src/logo/ascii/bedrock_small.txt index 2de5e4ddaf..59d7de1bca 100644 --- a/src/logo/ascii/bedrock_small.txt +++ b/src/logo/ascii/bedrock_small.txt @@ -1,6 +1,6 @@ - _________ -| __ | -| \ \___ | -| \ _ \ | -| \___/ | + _________ +| $2__ $1 | +| $2\ \___ $1 | +| $2 \ _ \$1 | +| $2 \___/$1 | |_________| diff --git a/src/logo/ascii/fedora2_small.txt b/src/logo/ascii/fedora2_small.txt new file mode 100644 index 0000000000..47680404ab --- /dev/null +++ b/src/logo/ascii/fedora2_small.txt @@ -0,0 +1,5 @@ + __ + / \ + __ |_ +/ | +\__/ \ No newline at end of file diff --git a/src/logo/ascii/ghostfreak.txt b/src/logo/ascii/ghostfreak.txt new file mode 100644 index 0000000000..264abea7fe --- /dev/null +++ b/src/logo/ascii/ghostfreak.txt @@ -0,0 +1,19 @@ + xSSSSSSSSSSSx: + XSSSSSSSSSSSSSSSSSSSSX + xSSSSSSSSSSSSSSSSSSSSSSSxSSX + xSSSSSSSSSSSSSSSSSSSSSSSSSSSSXSS + SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSXXXS; + +SSSSSSx++SSSSSSSSSSSSSSSSSSSSSSSSSXSX + SSSSS:::::::SSSSSSSSSSSSSXSSSSSSSSSS+S+ + XSSSX::::::::XxSSSSSSSSXSx;::xSSSSSSSSSS +;SSSS:::::::::XSSSSSSSSS+:::::::xSSSSSSSS; ++SSSSx::::::::SSSSSSSSS;:::::::::XSSSSSSSX + SSSSXSx:::::SSSSxXSSSS::::::::::XSSSSSSSX + xSSSSSSSSSSSS:::::SSSX::::::::::XSSSSSSS; + +SSSSSSSSSSSSSSX:SSSSS;:::::::SxSSSSSSS + +SSSSSSSSSSSSSSSSSSSSSSSSSXSSxSSSSSS + xxSSSSSSSSSSSSSSSSSSSSSSSSSSSSSx + SSSSSSSSSSSSSSSSSSSSSSSSSSSX + xXSSSSSSSSSSSSX + SSS +SSSxSSSSS + ;x xSSx \ No newline at end of file diff --git a/src/logo/ascii/harmonyos.txt b/src/logo/ascii/harmonyos.txt new file mode 100644 index 0000000000..cc3b7a4da6 --- /dev/null +++ b/src/logo/ascii/harmonyos.txt @@ -0,0 +1,19 @@ + ....-----.... + .-+##############+-.. + .+######################+.. + .########+- -++#######-. + .+######- -######+. + .######. .######.. + .+####+ +#####.. + .-####+. +####+. + .+####+ -####+.. + ..+####+ -####+... +$2......--$1+####+$2--.......................--$1+####+$2-......... + ..$1--++++-$2...... ...$1-++++--$2.. + ..$1--+++--$2... ...$1-+++++-$2.. + .$1--+++--$2.... ....$1--+++-$2... + ..$1-++++++--$2..... ......$1---+---$2... + ...$1-+++++++++-----$2..$1----++++++--$2.. + ...$1---++++++----++++++++---$2... + .....$1-----+++-----$2... + ...$1---$2... \ No newline at end of file diff --git a/src/logo/ascii/hydra.txt b/src/logo/ascii/hydrapwk.txt similarity index 100% rename from src/logo/ascii/hydra.txt rename to src/logo/ascii/hydrapwk.txt diff --git a/src/logo/ascii/kalpa_desktop.txt b/src/logo/ascii/kalpa_desktop.txt new file mode 100644 index 0000000000..3ca6be2010 --- /dev/null +++ b/src/logo/ascii/kalpa_desktop.txt @@ -0,0 +1,22 @@ + +++ + ++++++++ + + ++++++++++++ +++ + ++++++++++* +++++++++ ++++ + +++++++ ++++++++++++++++++ + ++++ ++++ +++++ + ++++ +++ ++++ + +++++ +++ ++++++ +++ ++++++++++++++ +++++++++ +++ ++++++++++++++ +++ +++ +++ ++++++++++++++ ++++ +++ +++ + ++++++++ +++ +++++++ +++ + +++++++ +++ + ++++++++ ++++ ++ + +++++++++++ +++++ +++++ + ++++++++ ++++++++++++ +++++++++ + ++++++++++++++ ++++++++++++++++ + ++++++++++++++++++++++++ +++++++++ + ++++++ +++++++++ ++++ + + +++++++ + +++++++ + +++++ \ No newline at end of file diff --git a/src/logo/ascii/truenas_scale.txt b/src/logo/ascii/truenas_scale.txt new file mode 100644 index 0000000000..364a6dddcb --- /dev/null +++ b/src/logo/ascii/truenas_scale.txt @@ -0,0 +1,18 @@ + ++ $2++ + $1++++++ $2++++++ + $1+++++++++ $2+++++++++ + $1+++++++ $2+++++++ + $1+++ $2+++ $1+ $3--------$1 $2+ $1+++ $2+++ + $1++++++ $2++++++ $3------$1 ++++++ $2++++++ + $1++++++++ $2++++++++++ $1++++++++++ $2++++++++ + $1+++++++ $3--$1 $2+++++++ $1+++++++ $3--$1 $2+++++++ +$2+++ $1+ $3--------$1 $2+ $1+++ $2+++ $1+ $3--------$1 $2+ $1+++ +$2++++++ $3--------$1 ++++++ $2++++++ $3--------$1 ++++++ +$2++++++++++ $1+++++++++ $2+++++++++ $1++++++++++ + $2+++++++++ $1+++++++ $3--$1 $2+++++++ $1+++++++++ + $2+++++ +++ $3--------$1 +++ +++++ + $2++ +++++++ $3------$1 +++++++ ++ + $2++++++++++ $1++++++++++ + $2++++++++ $1++++++++ + $2+++++ $1+++++ + $2++ $1++ \ No newline at end of file diff --git a/src/logo/ascii/xenia.txt b/src/logo/ascii/xenia.txt index 50764b4acc..e1aa543bb2 100644 --- a/src/logo/ascii/xenia.txt +++ b/src/logo/ascii/xenia.txt @@ -1,4 +1,4 @@ -$1 ** + ** * ** */ $2@$1///// / *** *** **** ***/ //////////////**** ** * ** *** **/ diff --git a/src/logo/ascii/xenia_old.txt b/src/logo/ascii/xenia_old.txt new file mode 100644 index 0000000000..6ddf64b181 --- /dev/null +++ b/src/logo/ascii/xenia_old.txt @@ -0,0 +1,21 @@ +$2 ,c. .c; +$2 .$1KMMMk$2.... ....$1kMMMK$2. +$2 .$1WMMMMMX$2..... .....$1KMMMMMW. +$1 XMMMMMMM0$2..... ....$1OMMMMMMMN +$1 dMMMMMMMMM;$2.... ..... ....,$1MMMMMMMMMd +$1 WMMMMMMMMMl;$3okKKKKKKKKKOo$1;cMMMMMMMMMM +$1 'MMMMMMMNX$2K0$3KKKKKKKKKKKKKKK$20K$1XNMMMMMMM; +$1 oMMMMMMM$2Oxo$3KKKKKKKKKKKKKKKKK$2oxO$1MMMMMMMd +$1 dMMMMMMM$2dxxx$3KKKKKKKKKKKKKKK$2xxxd$1NMMMMMMk +$1 :MMMMX0$2xxxxxx$30KKKKKKKK0KK0$2xxxxxx0$1XMMMMc +$1 MMMO$2xxxxxxxxdx$3kdd$20x0$3ddk$2xdxxxxxxxx$1OMMM +$1 ;$2xxkxddxxxxdodxxxxdxdxxxxdodxxxxddxkxx$1; +$1dxd$2KMMMWXo$1'.....'$2cdxxxdc$1'.....'$2lXWMMMX$1dxd +$1cxd$2XMMMN$1,..........$2dxd$1'.........'$2XMMMN$1dxl +$1 .xx$2WMMl$1...''....'.;k:.'....''...$2lMMW$1xx. +$1..:kXMMx..'....''..kMk..''....'..xMMXkc.. +$1 dMMMMMMd.....'...xMMMx...''....dMMMMMMx +$1 kMMMMWOoc:coOkolllokOoc:coOWMMMMO +$1 .MMMMMMMMl$2...$1lNMMMMMMM. +$1 KMMMMMMX$2l$1KMMMMMMX +$1 .MMMMMMMMM. \ No newline at end of file diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 6b409065aa..dc453acee7 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -252,6 +252,20 @@ static const FFlogo A[] = { .colorKeys = FF_COLOR_FG_RED, .colorTitle = FF_COLOR_FG_WHITE, }, + // AnushOS + { + .names = {"AnushOS"}, + .lines = FASTFETCH_DATATEXT_LOGO_ANUSHOS, + .colors = { + FF_COLOR_FG_WHITE, + FF_COLOR_FG_BLACK, + FF_COLOR_FG_YELLOW, + FF_COLOR_FG_CYAN, + FF_COLOR_FG_RED, + }, + .colorKeys = FF_COLOR_FG_WHITE, + .colorTitle = FF_COLOR_FG_WHITE, + }, // AoscOsRetro { .names = {"Aosc OS/Retro", "aoscosretro"}, @@ -706,10 +720,10 @@ static const FFlogo B[] = { .lines = FASTFETCH_DATATEXT_LOGO_BEDROCK, .colors = { FF_COLOR_FG_LIGHT_BLACK, //grey - FF_COLOR_FG_WHITE, + FF_COLOR_FG_DEFAULT, }, .colorKeys = FF_COLOR_FG_LIGHT_BLACK, //grey - .colorTitle = FF_COLOR_FG_WHITE, + .colorTitle = FF_COLOR_FG_DEFAULT, }, // BedrockSmall { @@ -717,10 +731,11 @@ static const FFlogo B[] = { .lines = FASTFETCH_DATATEXT_LOGO_BEDROCK_SMALL, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .colors = { - FF_COLOR_FG_WHITE, + FF_COLOR_FG_LIGHT_BLACK, //grey + FF_COLOR_FG_DEFAULT, }, - .colorKeys = FF_COLOR_FG_WHITE, - .colorTitle = FF_COLOR_FG_WHITE, + .colorKeys = FF_COLOR_FG_LIGHT_BLACK, //grey + .colorTitle = FF_COLOR_FG_DEFAULT, }, // BigLinux { @@ -1731,6 +1746,16 @@ static const FFlogo F[] = { .colorKeys = FF_COLOR_FG_BLUE, .colorTitle = FF_COLOR_FG_BLUE, }, + { + .names = {"Fedora2_small"}, + .type = FF_LOGO_LINE_TYPE_SMALL_BIT | FF_LOGO_LINE_TYPE_ALTER_BIT, + .lines = FASTFETCH_DATATEXT_LOGO_FEDORA2_SMALL, + .colors = { + FF_COLOR_FG_BLUE, + }, + .colorKeys = FF_COLOR_FG_BLUE, + .colorTitle = FF_COLOR_FG_BLUE, + }, // FedoraOld { .names = {"Fedora_old"}, @@ -1989,6 +2014,16 @@ static const FFlogo G[] = { .colorKeys = FF_COLOR_FG_BLUE, .colorTitle = FF_COLOR_FG_RED, }, + // GhostFreak + { + .names = {"GhostFreak"}, + .lines = FASTFETCH_DATATEXT_LOGO_GHOSTFREAK, + .colors = { + FF_COLOR_FG_DEFAULT, + }, + .colorKeys = FF_COLOR_FG_DEFAULT, + .colorTitle = FF_COLOR_FG_BLUE, + }, // Glaucus { .names = {"Glaucus"}, @@ -2175,6 +2210,17 @@ static const FFlogo H[] = { .colorKeys = FF_COLOR_FG_RED, .colorTitle = FF_COLOR_FG_RED, }, + // HarmonyOS + { + .names = {"HarmonyOS"}, + .lines = FASTFETCH_DATATEXT_LOGO_HARMONYOS, + .colors = { + FF_COLOR_FG_WHITE, + FF_COLOR_FG_BLUE, + }, + .colorKeys = FF_COLOR_FG_BLUE, + .colorTitle = FF_COLOR_FG_BLUE, + }, // Hash { .names = {"Hash"}, @@ -2267,13 +2313,13 @@ static const FFlogo H[] = { .colorKeys = FF_COLOR_FG_LIGHT_BLACK, .colorTitle = FF_COLOR_FG_WHITE, }, - // Hydra Framework + // HydraPWK { - .names = {"Hydra"}, - .lines = FASTFETCH_DATATEXT_LOGO_HYDRA, + .names = {"HydraPWK"}, + .lines = FASTFETCH_DATATEXT_LOGO_HYDRAPWK, .colors = { - FF_COLOR_FG_RED, - FF_COLOR_FG_WHITE, + FF_COLOR_FG_RED, + FF_COLOR_FG_DEFAULT, }, }, // LAST @@ -2378,18 +2424,18 @@ static const FFlogo K[] = { }, // Kali { - .names = {"Kali", "Kalilinux"}, + .names = {"Kali"}, .lines = FASTFETCH_DATATEXT_LOGO_KALI, .colors = { FF_COLOR_FG_BLUE, FF_COLOR_FG_LIGHT_BLACK, }, .colorKeys = FF_COLOR_FG_BLUE, - .colorTitle = FF_COLOR_FG_WHITE, + .colorTitle = FF_COLOR_FG_DEFAULT, }, // KaliSmall { - .names = {"Kali_small", "Kalilinux_small"}, + .names = {"Kali_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_KALI_SMALL, .colors = { @@ -2397,7 +2443,17 @@ static const FFlogo K[] = { FF_COLOR_FG_LIGHT_BLACK, }, .colorKeys = FF_COLOR_FG_BLUE, - .colorTitle = FF_COLOR_FG_WHITE, + .colorTitle = FF_COLOR_FG_DEFAULT, + }, + // Kalpa Desktop + { + .names = {"kalpa-desktop"}, + .lines = FASTFETCH_DATATEXT_LOGO_KALPA_DESKTOP, + .colors = { + FF_COLOR_FG_GREEN, + }, + .colorKeys = FF_COLOR_FG_GREEN, + .colorTitle = FF_COLOR_FG_DEFAULT, }, // KaOS { @@ -4728,6 +4784,18 @@ static const FFlogo T[] = { FF_COLOR_FG_CYAN, }, }, + // TrueNAS Scale + { + .names = {"TrueNAS-Scale"}, + .lines = FASTFETCH_DATATEXT_LOGO_TRUENAS_SCALE, + .colors = { + FF_COLOR_FG_256 "39", + FF_COLOR_FG_256 "32", + FF_COLOR_FG_256 "248", + }, + .colorKeys = FF_COLOR_FG_256 "248", + .colorTitle = FF_COLOR_FG_256 "32", + }, // TuxedoOS { .names = {"Tuxedo OS", "tuxedo"}, @@ -5256,15 +5324,6 @@ static const FFlogo W[] = { }; static const FFlogo X[] = { - // Xenia - { - .names = {"Xenia"}, - .lines = FASTFETCH_DATATEXT_LOGO_XENIA, - .colors = { - FF_COLOR_FG_RED, - FF_COLOR_FG_WHITE, - } - }, // XCP-ng { .names = {"XCP-ng", "xenenterprise"}, @@ -5278,14 +5337,27 @@ static const FFlogo X[] = { FF_COLOR_FG_YELLOW, } }, - // Xferience + // Xenia { - .names = {"Xferience"}, - .lines = FASTFETCH_DATATEXT_LOGO_XFERIENCE, + .names = {"Xenia"}, + .lines = FASTFETCH_DATATEXT_LOGO_XENIA, .colors = { - FF_COLOR_FG_CYAN, - FF_COLOR_FG_CYAN, + FF_COLOR_FG_RED, + FF_COLOR_FG_LIGHT_BLACK, }, + .colorKeys = FF_COLOR_FG_DEFAULT, + .colorTitle = FF_COLOR_FG_RED, + }, + // Xenia_old + { + .names = {"Xenia_old"}, + .lines = FASTFETCH_DATATEXT_LOGO_XENIA_OLD, + .type = FF_LOGO_LINE_TYPE_ALTER_BIT, + .colors = { + FF_COLOR_FG_YELLOW, + FF_COLOR_FG_GREEN, + FF_COLOR_FG_RED, + } }, //XeroArch { @@ -5300,6 +5372,15 @@ static const FFlogo X[] = { FF_COLOR_FG_256 "15", } }, + // Xferience + { + .names = {"Xferience"}, + .lines = FASTFETCH_DATATEXT_LOGO_XFERIENCE, + .colors = { + FF_COLOR_FG_CYAN, + FF_COLOR_FG_CYAN, + }, + }, // LAST {}, }; diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index edd84dc359..af579f93f9 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -535,7 +535,7 @@ void ffInitDiskOptions(FFDiskOptions* options) #if _WIN32 || __APPLE__ || __ANDROID__ ffStrbufInit(&options->hideFolders); #else - ffStrbufInitStatic(&options->hideFolders, "/efi:/boot:/boot/efi"); + ffStrbufInitStatic(&options->hideFolders, "/efi:/boot:/boot/efi:/boot/firmware"); #endif ffStrbufInit(&options->hideFS); options->showTypes = FF_DISK_VOLUME_TYPE_REGULAR_BIT | FF_DISK_VOLUME_TYPE_EXTERNAL_BIT | FF_DISK_VOLUME_TYPE_READONLY_BIT; diff --git a/src/util/binary_linux.c b/src/util/binary_linux.c index df89e160d8..a723243cd7 100644 --- a/src/util/binary_linux.c +++ b/src/util/binary_linux.c @@ -63,7 +63,7 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s return "load libelf failed"; // Open the ELF file - FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY, 0); + FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY | O_CLOEXEC); if (fd < 0) return "open() failed"; Elf* elf = elfData.ffelf_begin(fd, ELF_C_READ, NULL); diff --git a/src/util/kmod.c b/src/util/kmod.c index c558481afc..f68b970bdd 100644 --- a/src/util/kmod.c +++ b/src/util/kmod.c @@ -51,7 +51,6 @@ bool ffKmodLoaded(const char* modName) { struct iovec iov = {}; - // 初始尝试分配的内存大小 for (size_t len = 8192;; len = iov.iov_len) { iov.iov_len = len; diff --git a/src/util/smbiosHelper.c b/src/util/smbiosHelper.c index 1171d27786..87569515f0 100644 --- a/src/util/smbiosHelper.c +++ b/src/util/smbiosHelper.c @@ -183,7 +183,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() } FF_DEBUG("Parsed SMBIOS entry address: 0x%lx", (unsigned long)entryAddress); - FF_AUTO_CLOSE_FD int fd = open("/dev/mem", O_RDONLY); + FF_AUTO_CLOSE_FD int fd = open("/dev/mem", O_RDONLY | O_CLOEXEC); if (fd < 0) { FF_DEBUG("Failed to open /dev/mem: %s", strerror(errno)); return NULL; @@ -219,7 +219,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() #endif ); - FF_AUTO_CLOSE_FD int fd = open("/dev/smbios", O_RDONLY); + FF_AUTO_CLOSE_FD int fd = open("/dev/smbios", O_RDONLY | O_CLOEXEC); if (fd < 0) { FF_DEBUG("Failed to open /dev/smbios: %s", strerror(errno)); return NULL; @@ -328,7 +328,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() #else "/dev/mem" // kern.securelevel must be -1 #endif - , O_RDONLY); + , O_RDONLY | O_CLOEXEC); if (fd < 0) { FF_DEBUG("Failed to open memory device: %s", strerror(errno)); return NULL;