Merge pull request #2183 from fastfetch-cli/dev

Release: v2.59.0
This commit is contained in:
Carter Li
2026-02-14 00:15:11 +08:00
committed by GitHub
56 changed files with 845 additions and 353 deletions
+79 -42
View File
@@ -13,7 +13,7 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install codespell
shell: bash
@@ -32,7 +32,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: uname -a
run: uname -a
@@ -78,7 +78,7 @@ jobs:
ffversion: ${{ steps.ffversion.outputs.ffversion }}
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: uname -a
run: uname -a
@@ -102,7 +102,7 @@ jobs:
- name: Initialize CodeQL
if: matrix.arch == 'amd64'
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: c
@@ -114,7 +114,7 @@ jobs:
- name: perform CodeQL analysis
if: matrix.arch == 'amd64'
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
- name: list features
run: ./fastfetch --list-features
@@ -151,7 +151,7 @@ jobs:
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
@@ -164,7 +164,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: uname -a
run: uname -a
@@ -217,7 +217,7 @@ jobs:
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-i686
path: ./fastfetch-*.*
@@ -230,7 +230,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: uraimo/run-on-arch-action@v3
@@ -257,7 +257,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-armv7l
path: ./fastfetch-*.*
@@ -270,7 +270,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: uraimo/run-on-arch-action@v3
@@ -293,7 +293,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-armv6l
path: ./fastfetch-*.*
@@ -312,7 +312,7 @@ jobs:
- arch: s390x
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: uraimo/run-on-arch-action@v3
@@ -336,7 +336,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
@@ -345,7 +345,7 @@ jobs:
name: Musl-amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: setup alpine linux
uses: jirutka/setup-alpine@master
@@ -374,7 +374,7 @@ jobs:
shell: alpine.sh {0}
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
@@ -394,7 +394,7 @@ jobs:
runs-on: macos-latest
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: uname -a
run: uname -a
@@ -428,17 +428,17 @@ jobs:
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-macos-${{ matrix.arch }}
path: ./fastfetch-*.*
sunos-amd64:
omnios-amd64:
runs-on: ubuntu-latest
name: SunOS-amd64
name: OmniOS-amd64
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: vmactions/omnios-vm@v1
@@ -447,23 +447,59 @@ jobs:
prepare: |
uname -a
pkg update --accept
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
cmake --build . --target package --verbose -j4
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja .
cmake --build . --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
cpack
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-omnios-amd64")' >> CPackConfig.cmake
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-sunos-amd64
name: fastfetch-omnios-amd64
path: ./fastfetch-*.*
solaris-amd64:
runs-on: ubuntu-latest
name: Solaris-amd64
steps:
- name: checkout repository
uses: actions/checkout@v6
- name: run VM
uses: vmactions/solaris-vm@v1
with:
usesh: true
release: "11.4-gcc-14"
prepare: |
uname -a
pkg install cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja dconf mesa
run: |
export PKG_CONFIG_PATH=/usr/lib/64/pkgconfig
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja .
cmake --build . --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-solaris-amd64")' >> CPackConfig.cmake
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v6
with:
name: fastfetch-solaris-amd64
path: ./fastfetch-*.*
freebsd-amd64:
@@ -474,7 +510,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: cross-platform-actions/action@master
@@ -483,7 +519,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '14.3'
version: '15.0'
run: |
uname -a
sudo pkg update
@@ -498,7 +534,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-freebsd-amd64
path: ./fastfetch-*.*
@@ -511,7 +547,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: cross-platform-actions/action@master
@@ -535,7 +571,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-openbsd-amd64
path: ./fastfetch-*.*
@@ -548,7 +584,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: cross-platform-actions/action@master
@@ -571,7 +607,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-netbsd-amd64
path: ./fastfetch-*.*
@@ -584,7 +620,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: vmactions/dragonflybsd-vm@v1
@@ -606,7 +642,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-dragonfly-amd64
path: ./fastfetch-*.*
@@ -619,7 +655,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: cross-platform-actions/action@master
@@ -641,7 +677,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-haiku-amd64
path: ./fastfetch-*.*
@@ -681,7 +717,7 @@ jobs:
shell: msys2 {0}
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: setup-msys2
uses: msys2/setup-msys2@v2
@@ -723,7 +759,7 @@ jobs:
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
id: upload-unsigned-artifact
name: upload artifacts for signing
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
path: |
@@ -750,7 +786,7 @@ jobs:
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload true artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
path: ./fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.*
@@ -772,7 +808,8 @@ jobs:
- openbsd-amd64
- netbsd-amd64
- dragonfly-amd64
- sunos-amd64
- solaris-amd64
- omnios-amd64
- haiku-amd64
- windows-hosts
permissions:
+22
View File
@@ -1,3 +1,25 @@
# 2.59.0
Changes:
* Fastfetch no longer relies on the unreliable environment variables `$USER` or `%USERPROFILE%` to determine the current username (Title)
* People who set `$USER` to customize the Fastfetch title should use `{ "type": "title", "format": "your-custom-user-name" }` to achieve the same result.
* Fastfetch no longer tries to probe inaccessible remote disk drives on Windows (Disk, Windows)
* People who have remote drives may use `{ "type": "disk", "hideFolders": "X:\\" }` to ignore problematic ones.
* This change removes some ugly hacks from the codebase and matches the behavior on `*nix`.
Features:
* Adds Oracle Solaris support (#2176, SunOS)
* Adds UID / SID detection (Title)
* In custom format: `{user-id}`
* Switches to native GPU detection on GNU/Hurd and removes the `libpciaccess` dependency (GPU, Hurd)
* Improves memory size detection on macOS (Memory, macOS)
* Avoids relying on `hw.memsize_usable` by default, which may not be available on older macOS versions
* Improves Windows disk detection accuracy and performance (Disk, Windows)
* Adds more ARM CPU parts and removes duplicated cases (CPU, ARM)
Logos:
* Adds 6-color support to the NixOS logo (including the small variant) (#2180)
# 2.58.0
An early release to fix compatibility issues with KDE Plasma 6.6.
+30 -8
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.58.0
VERSION 2.59.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -92,7 +92,6 @@ 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_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "GNU" OFF)
option(ENABLE_ZLIB "Enable zlib" ON)
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
@@ -110,6 +109,9 @@ option(ENABLE_LIBZFS "Enable libzfs" ON)
if(WIN32 AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
option(ENABLE_WIN7_COMPAT "Enable Windows 7 compatibility" ON)
endif()
if(APPLE)
option(ENABLE_APPLE_MEMSIZE_USABLE "Use usable memory size as total memory size in Memory module, to match other systems" OFF)
endif()
set(BINARY_LINK_TYPE_OPTIONS dlopen dynamic static)
set(BINARY_LINK_TYPE dlopen CACHE STRING "How to link fastfetch")
@@ -1259,7 +1261,7 @@ elseif(GNU)
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_general.c
src/detection/gpu/gpu_gnu.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_nosupport.c
@@ -1323,6 +1325,10 @@ endif()
if(NOT WIN32)
check_function_exists(pipe2 HAVE_PIPE2)
endif()
check_function_exists(memrchr HAVE_MEMRCHR)
if(NOT HAVE_MEMRCHR)
list(APPEND LIBFASTFETCH_SRC src/common/impl/memrchr.c)
endif()
if(ENABLE_SYSTEM_YYJSON)
find_package(yyjson)
@@ -1341,6 +1347,15 @@ add_library(libfastfetch OBJECT
${LIBFASTFETCH_SRC}
)
include(CheckCSourceCompiles)
check_c_source_compiles("int main(void){int arr[1];return _Countof(arr);}" COMPILER_SUPPORTS_COUNT_OF)
if(COMPILER_SUPPORTS_COUNT_OF)
message(STATUS "_Countof is supported by the compiler")
target_compile_definitions(libfastfetch PUBLIC FF_SUPPORTS_COUNT_OF=1)
else()
message(STATUS "_Countof is NOT supported by the compiler")
endif()
if(yyjson_FOUND)
target_compile_definitions(libfastfetch PUBLIC FF_USE_SYSTEM_YYJSON=1)
target_link_libraries(libfastfetch PUBLIC yyjson::yyjson)
@@ -1424,6 +1439,14 @@ elseif(GNU)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=0)
endif()
if(APPLE)
if(ENABLE_APPLE_MEMSIZE_USABLE)
target_compile_definitions(libfastfetch PUBLIC FF_APPLE_MEMSIZE_USABLE=1)
else()
target_compile_definitions(libfastfetch PUBLIC FF_APPLE_MEMSIZE_USABLE=0)
endif()
endif()
if(WIN32)
check_function_exists(_msize HAVE_MSVC_MSIZE)
if(HAVE_MSVC_MSIZE)
@@ -1630,10 +1653,6 @@ ff_lib_enable(DIRECTX_HEADERS
"DirectX-Headers"
"DirectX-Headers"
)
ff_lib_enable(PCIACCESS
"pciaccess"
"pciaccess"
)
if(ENABLE_THREADS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS=1)
@@ -1657,6 +1676,9 @@ if(ENABLE_LIBZFS)
)
endif()
endif()
if(NOT HAVE_MEMRCHR)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_CUSTOM_MEMRCHR=1)
endif()
if(LINUX)
target_link_libraries(libfastfetch
@@ -2089,7 +2111,7 @@ if(LINUX)
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
endif()
endif()
elseif(FreeBSD)
elseif(FreeBSD AND NOT DragonFly)
set(CPACK_FREEBSD_PACKAGE_LICENSE "MIT")
set(CPACK_GENERATOR "${CPACK_GENERATOR};FREEBSD")
endif()
+1 -1
View File
@@ -13,7 +13,7 @@
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/fastfetch-cli/fastfetch)
[![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-red)](README-cn.md)
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and illumos (SunOS).
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, illumos (SunOS), and Solaris.
<img src="screenshots/example1.png" width="49%" align="left" />
<img src="https://upload.wikimedia.org/wikipedia/commons/2/24/Transparent_Square_Tiles_Texture.png" width="49%" height="16px" align="left" />
+6
View File
@@ -1,3 +1,9 @@
fastfetch (2.58.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.58.0
-- Carter Li <zhangsongcui@live.cn> Thu, 22 Jan 2026 15:30:58 +0800
fastfetch (2.57.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.57.1
+4 -4
View File
@@ -318,7 +318,7 @@
"type": "string"
},
"cpuFormat": {
"description": "Output format of the module `CPU`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: X86-64 CPU microarchitecture",
"description": "Output format of the module `CPU`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count",
"type": "string"
},
"cpucacheFormat": {
@@ -442,7 +442,7 @@
"type": "string"
},
"packagesFormat": {
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {nix-all}: Total number of all nix packages\n 44. {flatpak-all}: Total number of all flatpak app packages\n 45. {brew-all}: Total number of all brew packages\n 46. {guix-all}: Total number of all guix packages\n 47. {hpkg-all}: Total number of all hpkg packages",
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {kiss}: Number of kiss packages\n 44. {nix-all}: Total number of all nix packages\n 45. {flatpak-all}: Total number of all flatpak app packages\n 46. {brew-all}: Total number of all brew packages\n 47. {guix-all}: Total number of all guix packages\n 48. {hpkg-all}: Total number of all hpkg packages",
"type": "string"
},
"physicaldiskFormat": {
@@ -498,7 +498,7 @@
"type": "string"
},
"titleFormat": {
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name",
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name\n 10. {user-id}: UID (*nix) / SID (Windows)\n 11. {pid}: PID of current process",
"type": "string"
},
"themeFormat": {
@@ -546,7 +546,7 @@
"type": "string"
},
"zpoolFormat": {
"description": "Output format of the module `Zpool`. See Wiki for formatting syntax\n 1. {name}: Zpool name\n 2. {state}: Zpool state\n 3. {used}: Size used\n 4. {total}: Size total\n 5. {used-percentage}: Size percentage num\n 6. {fragmentation-percentage}: Fragmentation percentage num\n 7. {used-percentage-bar}: Size percentage bar\n 8. {fragmentation-percentage-bar}: Fragmentation percentage bar",
"description": "Output format of the module `Zpool`. See Wiki for formatting syntax\n 1. {name}: Zpool name\n 2. {guid}: Zpool guid\n 3. {state}: Zpool state\n 4. {used}: Size used\n 5. {allocated}: Size allocated\n 6. {total}: Size total\n 7. {used-percentage}: Size used percentage num\n 8. {allocated-percentage}: Size allocated percentage num\n 9. {fragmentation-percentage}: Fragmentation percentage num\n 10. {used-percentage-bar}: Size used percentage bar\n 11. {allocated-percentage-bar}: Size allocated percentage bar\n 12. {fragmentation-percentage-bar}: Fragmentation percentage bar\n 13. {is-readonly}: Is read-only",
"type": "string"
}
},
+6
View File
@@ -20,6 +20,12 @@ typedef struct FFPlatform
FFlist dataDirs; // List of FFstrbuf, trailing slash included
FFstrbuf exePath; // The real path of current exe (empty if unavailable)
uint32_t pid;
#ifndef _WIN32
uint32_t uid;
#else
FFstrbuf sid;
#endif
FFstrbuf userName;
FFstrbuf fullUserName;
FFstrbuf hostName;
+2 -2
View File
@@ -166,7 +166,7 @@ static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl
case 1: *value = *(uint8_t *)(val.bytes); break;
case 2: *value = ntohs(*(uint16_t *)(val.bytes)); break;
case 4: *value = ntohl(*(uint32_t *)(val.bytes)); break;
case 8: *value = ntohll(*(uint64_t *)(val.bytes)); break;
case 8: *value = (double) ntohll(*(uint64_t *)(val.bytes)); break;
default:
return "Unsupported SMC unsigned integer data size";
}
@@ -213,7 +213,7 @@ static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl
case 1: *value = *(int8_t *)(val.bytes); break;
case 2: *value = ntohs(*(int16_t *)(val.bytes)); break;
case 4: *value = ntohl(*(int32_t *)(val.bytes)); break;
case 8: *value = ntohll(*(int64_t *)(val.bytes)); break;
case 8: *value = (double)ntohll(*(int64_t *)(val.bytes)); break;
default: return "Unsupported SMC signed integer data size";
}
}
+3 -1
View File
@@ -3,7 +3,9 @@
#include <assert.h>
#ifdef __has_builtin
#if __has_builtin(__is_array)
#if !__cplusplus && FF_SUPPORTS_COUNT_OF
#define ARRAY_SIZE(x) _Countof(x)
#elif __has_builtin(__is_array)
#define ARRAY_SIZE(x) ({ static_assert(__is_array(__typeof__(x)), "Must be an array"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
#elif __has_builtin(__builtin_types_compatible_p)
#define ARRAY_SIZE(x) ({ static_assert(!__builtin_types_compatible_p(__typeof__(x), __typeof__(&*(x))), "Must not be a pointer"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
+8
View File
@@ -16,6 +16,10 @@ void ffPlatformInit(FFPlatform* platform)
ffStrbufInit(&platform->hostName);
ffStrbufInit(&platform->userShell);
#ifdef _WIN32
ffStrbufInit(&platform->sid);
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
ffStrbufInit(&info->name);
@@ -51,6 +55,10 @@ void ffPlatformDestroy(FFPlatform* platform)
ffStrbufDestroy(&platform->userShell);
ffStrbufDestroy(&platform->fullUserName);
#ifdef _WIN32
ffStrbufDestroy(&platform->sid);
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
ffStrbufDestroy(&info->architecture);
ffStrbufDestroy(&info->name);
+12 -11
View File
@@ -28,15 +28,15 @@ static void getExePath(FFPlatform* platform)
if (exePathLen >= 0)
exePath[exePathLen] = '\0';
#elif defined(__APPLE__)
int exePathLen = proc_pidpath((int) getpid(), exePath, sizeof(exePath));
int exePathLen = proc_pidpath((pid_t) platform->pid, exePath, sizeof(exePath));
#elif defined(__FreeBSD__) || defined(__NetBSD__)
size_t exePathLen = sizeof(exePath);
if(sysctl(
(int[]){CTL_KERN,
#ifdef __FreeBSD__
KERN_PROC, KERN_PROC_PATHNAME, (int) getpid()
KERN_PROC, KERN_PROC_PATHNAME, (pid_t) platform->pid
#else
KERN_PROC_ARGS, (int) getpid(), KERN_PROC_PATHNAME
KERN_PROC_ARGS, platform->pid, KERN_PROC_PATHNAME
#endif
}, 4,
exePath, &exePathLen,
@@ -177,17 +177,16 @@ static void getDataDirs(FFPlatform* platform)
static void getUserName(FFPlatform* platform, const struct passwd* pwd)
{
const char* user = getenv("USER");
if(!ffStrSet(user) && pwd)
user = pwd->pw_name;
ffStrbufAppendS(&platform->userName, user);
if (pwd)
{
ffStrbufAppendS(&platform->fullUserName, pwd->pw_gecos);
ffStrbufSetS(&platform->userName, pwd->pw_name);
ffStrbufSetS(&platform->fullUserName, pwd->pw_gecos);
ffStrbufTrimSpace(&platform->fullUserName);
}
else
{
ffStrbufSetS(&platform->userName, getenv("USER"));
}
}
static void getHostName(FFPlatform* platform, const struct utsname* uts)
@@ -227,7 +226,9 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts)
void ffPlatformInitImpl(FFPlatform* platform)
{
struct passwd* pwd = getpwuid(getuid());
platform->pid = (uint32_t) getpid();
platform->uid = getuid();
struct passwd* pwd = getpwuid(platform->uid);
struct utsname uts;
if(uname(&uts) < 0)
+34 -15
View File
@@ -1,6 +1,7 @@
#include "FFPlatform_private.h"
#include "common/io.h"
#include "common/library.h"
#include "common/mallocHelper.h"
#include "common/stringUtils.h"
#include "common/windows/unicode.h"
#include "common/windows/registry.h"
@@ -8,6 +9,7 @@
#include <windows.h>
#include <shlobj.h>
#include <sddl.h>
#define SECURITY_WIN32 1 // For secext.h
#include <secext.h>
@@ -70,15 +72,15 @@ static void getCacheDir(FFPlatform* platform)
static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId)
{
PWSTR pPath = NULL;
if(SUCCEEDED(SHGetKnownFolderPath(folderId, 0, NULL, &pPath)))
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, NULL, &pPath)))
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateWS(pPath);
CoTaskMemFree(pPath);
ffStrbufReplaceAllC(&buffer, '\\', '/');
ffStrbufEnsureEndsWithC(&buffer, '/');
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
}
CoTaskMemFree(pPath);
}
static void platformPathAddEnvSuffix(FFlist* dirs, const char* env, const char* suffix)
@@ -136,21 +138,37 @@ static void getDataDirs(FFPlatform* platform)
static void getUserName(FFPlatform* platform)
{
const char* userName = getenv("USERNAME");
if (ffStrSet(userName))
ffStrbufSetS(&platform->userName, userName);
else
{
wchar_t buffer[256];
DWORD len = ARRAY_SIZE(buffer);
if(GetUserNameW(buffer, &len))
ffStrbufSetWS(&platform->userName, buffer);
}
wchar_t buffer[256];
DWORD len = ARRAY_SIZE(buffer);
if (GetUserNameExW(NameDisplay, buffer, &len))
DWORD size = ARRAY_SIZE(buffer);
if (GetUserNameExW(NameDisplay, buffer, &size))
ffStrbufSetWS(&platform->fullUserName, buffer);
size = ARRAY_SIZE(buffer);
if (GetUserNameW(buffer, &size)) // GetUserNameExW(10002)?
{
ffStrbufSetWS(&platform->userName, buffer);
size = 0;
DWORD refDomainSize = 0;
SID_NAME_USE sidNameUse = SidTypeUnknown;
LookupAccountNameW(NULL, buffer, NULL, &size, NULL, &refDomainSize, &sidNameUse);
if (size > 0)
{
FF_AUTO_FREE PSID sid = (PSID) malloc(size);
FF_AUTO_FREE LPWSTR refDomain = (LPWSTR) malloc(refDomainSize * sizeof(wchar_t));
if (LookupAccountNameW(NULL, buffer, sid, &size, refDomain, &refDomainSize, &sidNameUse))
{
LPWSTR sidString;
if (ConvertSidToStringSidW(sid, &sidString))
{
ffStrbufSetWS(&platform->sid, sidString);
LocalFree(sidString);
}
}
}
}
else
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
}
static void getHostName(FFPlatform* platform)
@@ -289,6 +307,7 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
void ffPlatformInitImpl(FFPlatform* platform)
{
platform->pid = (uint32_t) GetCurrentProcessId();
getExePath(platform);
getHomeDir(platform);
getCacheDir(platform);
+1 -1
View File
@@ -183,7 +183,7 @@ const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char unti
if(value == NULL)
return NULL;
char* end = strchr(value, until);
const char* end = strchr(value, until);
if(end == NULL)
ffStrbufAppendS(strbuf, value);
else
+1 -1
View File
@@ -61,7 +61,7 @@ bool ffParseModuleOptions(const char* key, const char* value)
}
fprintf(stderr, "Error: Unsupported module option: %s\n", key);
fputs(" Support of module options has been removed. Please add the flag to the JSON config instead.\n", stderr);
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ? value : "true", value ? "\"" : "");
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ?: "true", value ? "\"" : "");
fputs(" See <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration> for more information.\n", stderr);
exit(477);
}
+3 -3
View File
@@ -225,9 +225,6 @@ void ffListFeatures(void)
#if FF_HAVE_FREETYPE
"freetype\n"
#endif
#if FF_HAVE_PCIACCESS
"libpciaccess\n"
#endif
#if FF_HAVE_PULSE
"libpulse\n"
#endif
@@ -258,6 +255,9 @@ void ffListFeatures(void)
#if FF_WIN7_COMPAT
"Windows 7 Compatibility\n"
#endif
#if FF_APPLE_MEMSIZE_USABLE
"Apple memsize_usable\n"
#endif
""
, stdout);
}
+1 -1
View File
@@ -23,7 +23,7 @@ static void createSubfolders(const char* fileName)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
char *token = NULL;
const char *token = NULL;
while((token = strchr(fileName, '/')) != NULL)
{
ffStrbufAppendNS(&path, (uint32_t)(token - fileName + 1), fileName);
+19
View File
@@ -0,0 +1,19 @@
#include "common/memrchr.h"
#include <stddef.h>
#include <stdint.h>
void* memrchr(const void* s, int c, size_t n)
{
if (n == 0) return NULL;
const uint8_t uc = (uint8_t) c;
const uint8_t* p = (const uint8_t*) s + n;
while (n--)
{
if (*--p == uc) return (void*) p;
}
return NULL;
}
+6 -6
View File
@@ -72,7 +72,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
}
int pid = getpid();
uint32_t pid = instance.state.platform.pid;
struct {
struct rt_msghdr hdr;
@@ -85,7 +85,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
.rtm_version = RTM_VERSION,
.rtm_addrs = RTA_DST | RTA_IFP | RTA_IFA,
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
.rtm_pid = pid,
.rtm_pid = (pid_t) pid,
.rtm_seq = 1,
},
.dst = {
@@ -99,7 +99,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
return false;
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid))
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == (pid_t) pid))
;
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
@@ -145,7 +145,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
}
int pid = getpid();
uint32_t pid = instance.state.platform.pid;
struct {
struct rt_msghdr hdr;
@@ -158,7 +158,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
.rtm_version = RTM_VERSION,
.rtm_addrs = RTA_DST | RTA_IFP,
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
.rtm_pid = pid,
.rtm_pid = (pid_t) pid,
.rtm_seq = 2,
},
.dst = {
@@ -172,7 +172,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
return false;
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == pid))
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == (pid_t) pid))
;
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
+2 -2
View File
@@ -19,7 +19,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
}
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
unsigned pid = (unsigned) getpid();
uint32_t pid = instance.state.platform.pid;
FF_DEBUG("Process PID: %u", pid);
// Bind socket
@@ -235,7 +235,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
}
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
unsigned pid = (unsigned) getpid();
uint32_t pid = instance.state.platform.pid;
FF_DEBUG("Process PID: %u", pid);
// Bind socket
+23 -10
View File
@@ -1,7 +1,10 @@
#include "fastfetch.h"
#include "common/processing.h"
#include "common/io.h"
#include "common/windows/unicode.h"
#include "common/windows/nt.h"
#include <stdalign.h>
#include <windows.h>
#include <ntstatus.h>
#include <winternl.h>
@@ -51,7 +54,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
wchar_t pipeName[32];
static unsigned pidCounter = 0;
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", GetCurrentProcessId(), ++pidCounter);
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", instance.state.platform.pid, ++pidCounter);
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = CreateNamedPipeW(
pipeName,
@@ -193,9 +196,16 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
exit:
{
DWORD exitCode = 0;
if (GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE && exitCode != 0)
return "Child process exited with an error";
PROCESS_BASIC_INFORMATION info = {};
ULONG size;
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size)))
{
assert(size == sizeof(info));
if (info.ExitStatus != STILL_ACTIVE && info.ExitStatus != 0)
return "Child process exited with an error";
}
else
return "NtQueryInformationProcess(ProcessBasicInformation) failed";
}
return NULL;
@@ -204,7 +214,7 @@ exit:
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui)
{
FF_AUTO_CLOSE_FD HANDLE hProcess = pid == 0
? GetCurrentProcess()
? NtCurrentProcess()
: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProcess == NULL)
@@ -227,12 +237,15 @@ bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFst
}
if(exe)
{
DWORD bufSize = exe->allocated;
if(QueryFullProcessImageNameA(hProcess, 0, exe->chars, &bufSize))
// TODO: It's possible to query the command line with `NtQueryInformationProcess(60/*ProcessCommandLineInformation*/)` since Windows 8.1
alignas(alignof(UNICODE_STRING)) uint8_t buffer[4096];
ULONG size;
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, &buffer, sizeof(buffer), &size)))
{
// We use full path here
// Querying command line of remote processes in Windows requires either WMI or ReadProcessMemory
exe->length = bufSize;
UNICODE_STRING* imageName = (UNICODE_STRING*)buffer;
ffStrbufSetNWS(exe, imageName->Length / sizeof(wchar_t), imageName->Buffer);
if (exePath) ffStrbufSet(exePath, exe);
}
else
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
// `memrchr` is a GNU extension and may not be declared by system headers even when the symbol exists.
// Declare it unconditionally; the build system provides a fallback implementation when missing.
void* memrchr(const void* s, int c, size_t n);
#ifdef __cplusplus
}
#endif
+28 -6
View File
@@ -6,12 +6,12 @@
#define D3DKMT_ALIGN64 __attribute__((aligned(8)))
typedef struct _PROCESSOR_POWER_INFORMATION {
ULONG Number;
ULONG MaxMhz;
ULONG CurrentMhz;
ULONG MhzLimit;
ULONG MaxIdleState;
ULONG CurrentIdleState;
ULONG Number;
ULONG MaxMhz;
ULONG CurrentMhz;
ULONG MhzLimit;
ULONG MaxIdleState;
ULONG CurrentIdleState;
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
NTSTATUS NTAPI NtPowerInformation(
@@ -248,3 +248,25 @@ NtQueryDirectoryFile(
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan);
// https://ntdoc.m417z.com/process_devicemap_information_ex
typedef struct _PROCESS_DEVICEMAP_INFORMATION_EX
{
union
{
struct
{
HANDLE DirectoryHandle; // A handle to a directory object that can be set as the new device map for the process. This handle must have DIRECTORY_TRAVERSE access.
} Set;
struct
{
ULONG DriveMap; // A bitmask that indicates which drive letters are currently in use in the process's device map.
UCHAR DriveType[32]; // A value that indicates the type of each drive (e.g., local disk, network drive, etc.). // DRIVE_* WinBase.h
} Query;
};
ULONG Flags; // PROCESS_LUID_DOSDEVICES_ONLY
} PROCESS_DEVICEMAP_INFORMATION_EX, *PPROCESS_DEVICEMAP_INFORMATION_EX;
#ifndef NtCurrentProcess
#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)
#endif
+5
View File
@@ -13,6 +13,11 @@ static inline void ffStrbufInitWSV(FFstrbuf* result, const std::wstring_view sou
return ffStrbufInitNWS(result, (uint32_t) source.size(), source.data());
}
static inline FFstrbuf ffStrbufCreateWSV(const std::wstring_view source)
{
return ffStrbufCreateNWS((uint32_t) source.size(), source.data());
}
static inline void ffStrbufSetWSV(FFstrbuf* result, const std::wstring_view source)
{
return ffStrbufSetNWS(result, (uint32_t) source.size(), source.data());
+7 -1
View File
@@ -10,7 +10,13 @@
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */)
{
// Actually bluetoothapis.dll, but it's missing on Windows 7
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bthprops.cpl", 1)
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis,
#if FF_WIN7_COMPAT
"bthprops.cpl"
#else
"bluetoothapis.dll"
#endif
, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstDevice)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindNextDevice)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindDeviceClose)
@@ -79,8 +79,7 @@ const char* ffBluetoothDetectBattery(FFlist* devices)
batt = data.get<uint8_t>();
else
{
FF_STRBUF_AUTO_DESTROY addr; // MAC address without colon
ffStrbufInitWSV(&addr, data.get<std::wstring_view>());
FF_STRBUF_AUTO_DESTROY addr = ffStrbufCreateWSV(data.get<std::wstring_view>()); // MAC address without colon
if (__builtin_expect(addr.length != 12, 0))
continue;
@@ -54,7 +54,13 @@ static_assert(sizeof(BTH_LOCAL_RADIO_INFO) == 292, "BTH_LOCAL_RADIO_INFO should
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
{
// Actually bluetoothapis.dll, but it's missing on Windows 7
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bthprops.cpl", 1)
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis,
#if FF_WIN7_COMPAT
"bthprops.cpl"
#else
"bluetoothapis.dll"
#endif
, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstRadio)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindNextRadio)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindRadioClose)
+2 -1
View File
@@ -9,6 +9,7 @@
#endif
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdalign.h>
#ifdef __NetBSD__
typedef uint16_t efi_char;
@@ -23,7 +24,7 @@ const char* ffDetectBootmgr(FFBootmgrResult* result)
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];
alignas(uint16_t) uint8_t buffer[2048];
struct efi_var_ioc ioc = {
.vendor = EFI_GLOBAL_VARIABLE,
.data = buffer,
+3 -1
View File
@@ -2,11 +2,13 @@
#include "common/io.h"
#include "efi_helper.h"
#include <stdalign.h>
#define FF_EFIVARS_PATH_PREFIX "/sys/firmware/efi/efivars/"
const char* ffDetectBootmgr(FFBootmgrResult* result)
{
uint8_t buffer[2048];
alignas(uint16_t) uint8_t buffer[2048];
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "BootCurrent-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) != 6)
return "Failed to read efivar: BootCurrent";
+2 -1
View File
@@ -1,13 +1,14 @@
#include "bootmgr.h"
#include "efi_helper.h"
#include "common/io.h"
#include "common/windows/nt.h"
#include <windows.h>
const char* enablePrivilege(const wchar_t* privilege)
{
FF_AUTO_CLOSE_FD HANDLE token = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
if (!OpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
return "OpenProcessToken() failed";
TOKEN_PRIVILEGES tp = {
+4 -2
View File
@@ -46,7 +46,7 @@ static const char* armPartId2name(uint32_t partId)
case 0xa20: return "ARM1020";
case 0xa22: return "ARM1022";
case 0xa26: return "ARM1026";
case 0xb02: return "ARM11 MPCore";
case 0xb02: return "ARM11-MPCore";
case 0xb36: return "ARM1136";
case 0xb56: return "ARM1156";
case 0xb76: return "ARM1176";
@@ -82,10 +82,12 @@ static const char* armPartId2name(uint32_t partId)
case 0xd0d: return "Cortex-A77";
case 0xd0e: return "Cortex-A76AE";
case 0xd13: return "Cortex-R52";
case 0xd14: return "Cortex-R82AE";
case 0xd15: return "Cortex-R82";
case 0xd16: return "Cortex-R52+";
case 0xd20: return "Cortex-M23";
case 0xd21: return "Cortex-M33";
case 0xd24: return "Cortex-M52";
case 0xd22: return "Cortex-M55";
case 0xd23: return "Cortex-M85";
case 0xd40: return "Neoverse-V1";
@@ -215,7 +217,7 @@ static const char* nvidiaPartId2name(uint32_t partId)
switch (partId)
{
case 0x000: return "Denver";
case 0x003: return "Denver 2";
case 0x003: return "Denver-2";
case 0x004: return "Carmel";
case 0x010: return "Olympus";
default: return NULL;
+56 -66
View File
@@ -1,77 +1,67 @@
#include "disk.h"
#include "common/io.h"
#include "common/thread.h"
#include "common/windows/unicode.h"
#include "common/windows/nt.h"
#include <windows.h>
#include <winioctl.h>
static unsigned __stdcall testRemoteVolumeAccessible(void* mountpoint)
{
FF_AUTO_CLOSE_FD HANDLE handle = CreateFileW(
(wchar_t*) mountpoint,
READ_CONTROL,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
return 0;
}
#include <ntstatus.h>
#include <stdalign.h>
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
wchar_t buf[MAX_PATH + 1];
uint32_t length = GetLogicalDriveStringsW(ARRAY_SIZE(buf), buf);
if (length == 0 || length >= ARRAY_SIZE(buf))
return "GetLogicalDriveStringsW(ARRAY_SIZE(buf), buf) failed";
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
PROCESS_DEVICEMAP_INFORMATION_EX info = {};
ULONG size = 0;
if(!NT_SUCCESS(NtQueryInformationProcess(NtCurrentProcess(), ProcessDeviceMap, &info, sizeof(info), &size)))
return "NtQueryInformationProcess(ProcessDeviceMap) failed";
// For cross-platform portability; used by `presets/examples/13.jsonc`
if (__builtin_expect(options->folders.length == 1 && options->folders.chars[0] == '/', 0))
if (options->folders.length == 1 && options->folders.chars[0] == '/')
{
wchar_t path[MAX_PATH + 1];
GetSystemWindowsDirectoryW(path, ARRAY_SIZE(path));
ffStrbufSetF(&options->folders, "%c:\\", (char) path[0]);
options->folders.chars[0] = (char) path[0];
ffStrbufAppendS(&options->folders, ":\\");
}
for(uint32_t i = 0; i < length; i++)
wchar_t mountpointW[] = L"X:\\";
char mountpointA[] = "X:\\";
for (wchar_t i = L'A'; i <= L'Z'; i++)
{
wchar_t* mountpoint = buf + i;
if (!(info.Query.DriveMap & (1 << (i - L'A'))))
continue;
mountpointW[0] = i;
mountpointA[0] = (char) i;
ffStrbufSetWS(&buffer, mountpoint);
i += buffer.length;
UINT driveType = GetDriveTypeW(mountpoint);
UINT driveType = info.Query.DriveType[i - L'A'];
if (__builtin_expect((long) options->folders.length, 0))
{
if (!ffStrbufSeparatedContain(&options->folders, &buffer, FF_DISK_FOLDER_SEPARATOR))
if (!ffStrbufSeparatedContainNS(&options->folders, 3, mountpointA, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(driveType == DRIVE_NO_ROOT_DIR)
continue;
if (options->hideFolders.length && ffStrbufSeparatedContain(&options->hideFolders, &buffer, FF_DISK_FOLDER_SEPARATOR))
if (options->hideFolders.length && ffStrbufSeparatedContainNS(&options->hideFolders, 3, mountpointA, FF_DISK_FOLDER_SEPARATOR))
continue;
wchar_t diskName[MAX_PATH + 1], diskFileSystem[MAX_PATH + 1];
FF_AUTO_CLOSE_FD HANDLE handle = CreateFileW(mountpointW, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (handle == INVALID_HANDLE_VALUE)
continue;
DWORD diskFlags;
BOOL volumeInfoAvailable = GetVolumeInformationW(mountpoint,
diskName, ARRAY_SIZE(diskName), //Volume name
NULL, //Serial number
NULL, //Max component length
&diskFlags, //File system flags
diskFileSystem, ARRAY_SIZE(diskFileSystem)
);
IO_STATUS_BLOCK iosb;
alignas(FILE_FS_ATTRIBUTE_INFORMATION) uint8_t bufFsAttr[1024];
FILE_FS_ATTRIBUTE_INFORMATION* fsAttr = NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, bufFsAttr, sizeof(bufFsAttr), FileFsAttributeInformation))
? (FILE_FS_ATTRIBUTE_INFORMATION*) bufFsAttr
: NULL;
FF_STRBUF_AUTO_DESTROY diskFileSystemBuf = ffStrbufCreate();
if (volumeInfoAvailable)
if (fsAttr)
{
ffStrbufSetWS(&diskFileSystemBuf, diskFileSystem);
ffStrbufSetNWS(&diskFileSystemBuf, fsAttr->FileSystemNameLength / sizeof(WCHAR), fsAttr->FileSystemName);
if (options->hideFS.length && ffStrbufSeparatedContain(&options->hideFS, &diskFileSystemBuf, ':'))
continue;
}
@@ -87,7 +77,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
disk->createTime = 0;
ffStrbufInit(&disk->filesystem);
ffStrbufInit(&disk->name);
ffStrbufInitMove(&disk->mountpoint, &buffer);
ffStrbufInitNS(&disk->mountpoint, 3, mountpointA);
ffStrbufInit(&disk->mountFrom);
disk->type = driveType == DRIVE_REMOVABLE || driveType == DRIVE_REMOTE || driveType == DRIVE_CDROM
? FF_DISK_VOLUME_TYPE_EXTERNAL_BIT
@@ -95,42 +85,42 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
? FF_DISK_VOLUME_TYPE_REGULAR_BIT
: FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
if (mountpoint[2] == L'\\' && mountpoint[3] == L'\0')
{
wchar_t volumeName[MAX_PATH + 1];
mountpoint[2] = L'\0';
if(QueryDosDeviceW(mountpoint, volumeName, ARRAY_SIZE(volumeName)))
mountpointW[2] = L'\0';
if(QueryDosDeviceW(mountpointW, volumeName, ARRAY_SIZE(volumeName)))
ffStrbufSetWS(&disk->mountFrom, volumeName);
mountpoint[2] = L'\\';
mountpointW[2] = L'\\';
}
#ifdef FF_HAVE_THREADS
if (driveType == DRIVE_REMOTE)
alignas(FILE_FS_VOLUME_INFORMATION) uint8_t bufFsVolume[1024];
FILE_FS_VOLUME_INFORMATION* fsVolume = NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, bufFsVolume, sizeof(bufFsVolume), FileFsVolumeInformation))
? (FILE_FS_VOLUME_INFORMATION*) bufFsVolume
: NULL;
if (fsVolume)
{
FFThreadType thread = ffThreadCreate(testRemoteVolumeAccessible, mountpoint);
if (!ffThreadJoin(thread, 500))
continue;
if (fsVolume->VolumeLabelLength > 0)
ffStrbufSetNWS(&disk->name, fsVolume->VolumeLabelLength / sizeof(WCHAR), fsVolume->VolumeLabel);
if (fsVolume->VolumeCreationTime.QuadPart)
disk->createTime = ((uint64_t) fsVolume->VolumeCreationTime.QuadPart - 116444736000000000ull) / 10000ull;
}
#endif
GetDiskFreeSpaceExW(
mountpoint,
(PULARGE_INTEGER)&disk->bytesAvailable,
(PULARGE_INTEGER)&disk->bytesTotal,
(PULARGE_INTEGER)&disk->bytesFree
);
if(volumeInfoAvailable)
if (fsAttr)
{
ffStrbufInitMove(&disk->filesystem, &diskFileSystemBuf);
ffStrbufSetWS(&disk->name, diskName);
if(diskFlags & FILE_READ_ONLY_VOLUME)
if(fsAttr->FileSystemAttributes & FILE_READ_ONLY_VOLUME)
disk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT;
}
WIN32_FILE_ATTRIBUTE_DATA data;
if(GetFileAttributesExW(mountpoint, GetFileExInfoStandard, &data) && data.ftCreationTime.dwHighDateTime > 0)
disk->createTime = (*(uint64_t*) &data.ftCreationTime - 116444736000000000ull) / 10000ull;
FILE_FS_FULL_SIZE_INFORMATION fsFullSize;
if (NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, &fsFullSize, sizeof(fsFullSize), FileFsFullSizeInformation)))
{
uint64_t units = fsFullSize.BytesPerSector * fsFullSize.SectorsPerAllocationUnit;
disk->bytesTotal = (uint64_t) fsFullSize.TotalAllocationUnits.QuadPart * units;
disk->bytesFree = (uint64_t) fsFullSize.ActualAvailableAllocationUnits.QuadPart * units;
disk->bytesAvailable = (uint64_t) fsFullSize.CallerAvailableAllocationUnits.QuadPart * units;
}
}
return NULL;
@@ -186,9 +186,12 @@ static bool detectDE(FFDisplayServerResult* ds)
ffStrbufPrependS(&ds->dePrettyName, "OxygenOS");
return true;
}
if (ffSettingsGetAndroidProperty("ro.build.display.id", &ds->dePrettyName) && ffStrbufStartsWithS(&ds->dePrettyName, "RedMagicOS"))
if (ffSettingsGetAndroidProperty("ro.build.display.id", &ds->dePrettyName))
{
ffStrbufInsertNC(&ds->dePrettyName, strlen("RedMagicOS"), 1, ' ');
if (ffStrbufStartsWithS(&ds->dePrettyName, "RedMagicOS"))
ffStrbufInsertNC(&ds->dePrettyName, strlen("RedMagicOS"), 1, ' ');
// Google Pixel uses native Android
return true;
}
+1 -1
View File
@@ -266,7 +266,7 @@ static void applyPrettyNameIfDE(FFDisplayServerResult* result, const char* name)
static const char* getFromProcesses(FFDisplayServerResult* result)
{
uint32_t userId = getuid();
uint32_t userId = instance.state.platform.uid;
#if __FreeBSD__
#ifdef __DragonFly__
+50 -2
View File
@@ -1,4 +1,5 @@
#include "gpu.h"
#include "common/debug.h"
#include "detection/vulkan/vulkan.h"
#include "detection/opencl/opencl.h"
#include "detection/opengl/opengl.h"
@@ -50,6 +51,8 @@ const char* ffGPUGetVendorString(unsigned vendorId)
const char* detectByOpenGL(FFlist* gpus)
{
FF_DEBUG("Starting OpenGL GPU detection fallback");
FFOpenGLResult result;
ffStrbufInit(&result.version);
ffStrbufInit(&result.renderer);
@@ -60,6 +63,7 @@ const char* detectByOpenGL(FFlist* gpus)
__attribute__((__cleanup__(ffDestroyOpenGLOptions))) FFOpenGLOptions options;
ffInitOpenGLOptions(&options);
const char* error = ffDetectOpenGL(&options, &result);
FF_DEBUG("OpenGL detection returns: %s", error ?: "success");
if (!error)
{
@@ -78,6 +82,11 @@ const char* detectByOpenGL(FFlist* gpus)
gpu->dedicated = gpu->shared = (FFGPUMemory){0, 0};
gpu->deviceId = 0;
FF_DEBUG("OpenGL reported renderer='%s', vendor='%s', version='%s'",
gpu->name.chars,
gpu->vendor.chars,
result.version.chars);
if (ffStrbufContainS(&gpu->name, "Apple"))
{
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
@@ -92,6 +101,11 @@ const char* detectByOpenGL(FFlist* gpus)
else if (ffStrbufContainS(&gpu->name, "MTT"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_MTHREADS);
FF_DEBUG("OpenGL fallback produced GPU: name='%s', vendor='%s', type=%u",
gpu->name.chars,
gpu->vendor.chars,
gpu->type);
}
ffStrbufDestroy(&result.version);
@@ -104,43 +118,77 @@ const char* detectByOpenGL(FFlist* gpus)
const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result)
{
FF_DEBUG("Starting GPU detection with method=%d", (int) options->detectionMethod);
if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_PCI)
{
FF_DEBUG("Trying PCI/native GPU detection");
const char* error = ffDetectGPUImpl(options, result);
if (!error && result->length > 0) return NULL;
if (!error && result->length > 0)
{
FF_DEBUG("PCI/native GPU detection succeeded with %u GPU(s)", result->length);
return NULL;
}
FF_DEBUG("PCI/native GPU detection did not produce results (error=%s, gpuCount=%u)",
error ?: "none",
result->length);
}
if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_VULKAN)
{
FF_DEBUG("Trying Vulkan GPU detection fallback");
FFVulkanResult* vulkan = ffDetectVulkan();
if (!vulkan->error && vulkan->gpus.length > 0)
{
FF_DEBUG("Vulkan detection succeeded with %u GPU(s)", vulkan->gpus.length);
ffListDestroy(result);
ffListInitMove(result, &vulkan->gpus);
#ifdef __ANDROID__
double ffGPUDetectTempFromTZ(void);
if (options->temp && result->length == 1)
{
FF_DEBUG("Applying Android thermal-zone temperature to single Vulkan GPU");
FF_LIST_GET(FFGPUResult, *result, 0)->temperature = ffGPUDetectTempFromTZ();
}
#endif
return NULL;
}
FF_DEBUG("Vulkan detection did not produce results (error=%s, gpuCount=%u)",
vulkan->error ?: "none",
vulkan->gpus.length);
}
if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_OPENCL)
{
FF_DEBUG("Trying OpenCL GPU detection fallback");
FFOpenCLResult* opencl = ffDetectOpenCL();
if (!opencl->error && opencl->gpus.length > 0)
{
FF_DEBUG("OpenCL detection succeeded with %u GPU(s)", opencl->gpus.length);
ffListDestroy(result);
ffListInitMove(result, &opencl->gpus);
return NULL;
}
FF_DEBUG("OpenCL detection did not produce results (error=%s, gpuCount=%u)",
opencl->error ?: "none",
opencl->gpus.length);
}
if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_OPENGL)
{
if (detectByOpenGL(result) == NULL)
FF_DEBUG("Trying OpenGL GPU detection fallback");
const char* error = detectByOpenGL(result);
if (error == NULL)
{
FF_DEBUG("OpenGL fallback succeeded with %u GPU(s)", result->length);
return NULL;
}
FF_DEBUG("OpenGL fallback failed: %s", error);
}
FF_DEBUG("GPU detection failed in all enabled backends");
return "GPU detection failed";
}
-70
View File
@@ -1,70 +0,0 @@
#include "gpu.h"
#ifdef FF_HAVE_PCIACCESS
#include "common/io.h"
#include "common/library.h"
#include <pciaccess.h>
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
FF_LIBRARY_LOAD_MESSAGE(pciaccess, "libpciaccess" FF_LIBRARY_EXTENSION, 0)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_system_init)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_slot_match_iterator_create)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_device_next)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_system_cleanup)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_iterator_destroy)
{
// Requires root access
// Same behavior can be observed with `cp $(which scanpci) /tmp/ && /tmp/scanpci`
FF_SUPPRESS_IO();
if (ffpci_system_init() < 0)
return "pci_system_init() failed";
}
struct pci_device_iterator* iter = ffpci_slot_match_iterator_create(NULL);
for (struct pci_device* dev = NULL; (dev = ffpci_device_next(iter)); )
{
if (dev->device_class >> 16 != 0x03 /*PCI_BASE_CLASS_DISPLAY*/)
continue;
uint8_t subclass = (dev->device_class >> 8) & 0xFF;
if (dev->func > 0 && subclass == 0x80 /*PCI_CLASS_DISPLAY_OTHER*/)
continue; // Likely an auxiliary display controller (#2034)
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->vendor_id));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitStatic(&gpu->platformApi, "libpciaccess");
ffStrbufInit(&gpu->memoryType);
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 = ffGPUPciAddr2Id(dev->domain, dev->bus, dev->dev, dev->func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName(dev->device_id, dev->revision, gpu);
if (gpu->name.length == 0)
ffGPUFillVendorAndName(subclass, dev->vendor_id, dev->device_id, gpu);
}
ffpci_iterator_destroy(iter);
ffpci_system_cleanup();
return NULL;
}
#else
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FF_MAYBE_UNUSED FFlist* gpus)
{
return "Fastfetch was built without libpciaccess support";
}
#endif
+123
View File
@@ -0,0 +1,123 @@
#include "gpu.h"
#include "common/io.h"
#include <hurd.h>
#include <hurd/pci.h>
#include <hurd/paths.h>
enum {
PCI_VENDOR_ID = 0x00,
PCI_DEVICE_ID = 0x02,
PCI_REVISION_ID = 0x08,
PCI_CLASS_PROG = 0x09,
PCI_SUBCLASS = 0x0a,
PCI_CLASS_DEVICE = 0x0b,
PCI_CONF_SIZE = 0x40,
};
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
int dDomainFd = open(_SERVERS_BUS "/pci/0000", O_RDONLY | O_CLOEXEC);
if (dDomainFd < 0) return "open(_SERVERS_BUS \"/pci/0000\") failed";
FF_AUTO_CLOSE_DIR DIR* dirDomain = fdopendir(dDomainFd);
if (dirDomain == NULL) return "fdopendir(domain) failed";
struct dirent* busEntry;
while ((busEntry = readdir(dirDomain)) != NULL)
{
if (busEntry->d_type != DT_DIR || busEntry->d_name[0] == '.')
continue;
char* endptr;
uint16_t pciBus = (uint16_t) strtoul(busEntry->d_name, &endptr, 16);
if (*endptr != '\0') continue;
int dBusFd = openat(dDomainFd, busEntry->d_name, O_RDONLY | O_CLOEXEC);
if (dBusFd < 0) continue;
FF_AUTO_CLOSE_DIR DIR* dirBus = fdopendir(dBusFd);
if (dirBus == NULL) continue;
struct dirent* devEntry;
while ((devEntry = readdir(dirBus)) != NULL)
{
if (devEntry->d_type != DT_DIR || devEntry->d_name[0] == '.')
continue;
uint8_t pciDev = (uint8_t) strtoul(devEntry->d_name, &endptr, 16);
if (*endptr != '\0') continue;
int dDevFd = openat(dBusFd, devEntry->d_name, O_RDONLY | O_CLOEXEC);
if (dDevFd < 0) continue;
FF_AUTO_CLOSE_DIR DIR* dirDev = fdopendir(dDevFd);
if (dirDev == NULL) continue;
struct dirent* funcEntry;
while ((funcEntry = readdir(dirDev)) != NULL)
{
if (funcEntry->d_type != DT_DIR || funcEntry->d_name[0] == '.')
continue;
uint8_t pciFunc = (uint8_t) strtoul(funcEntry->d_name, &endptr, 16);
if (*endptr != '\0') continue;
char subpath[PATH_MAX];
snprintf(subpath, ARRAY_SIZE(subpath), "%s/%s/%s/%s/config", _SERVERS_BUS "/pci/0000", busEntry->d_name, devEntry->d_name, funcEntry->d_name);
mach_port_t devicePort = file_name_lookup(subpath, 0, 0);
if (devicePort == MACH_PORT_NULL)
continue;
mach_msg_type_number_t nread = 0;
uint8_t data[PCI_CONF_SIZE];
data_t pData = (data_t) data;
kern_return_t kr = pci_conf_read(devicePort, 0, &pData, &nread, PCI_CONF_SIZE);
mach_port_deallocate(mach_task_self(), devicePort);
if (kr != KERN_SUCCESS || nread < PCI_CONF_SIZE) continue;
if (pData != (data_t) data)
{
memcpy(data, pData, PCI_CONF_SIZE);
vm_deallocate(mach_task_self(), (vm_address_t)pData, nread);
}
uint8_t classBase = data[PCI_CLASS_DEVICE];
if (classBase != 0x03 /*PCI_BASE_CLASS_DISPLAY*/)
continue;
uint8_t classSub = data[PCI_SUBCLASS];
if (pciFunc > 0 && classSub == 0x80 /*PCI_CLASS_DISPLAY_OTHER*/) // Likely an auxiliary display controller (#2034)
continue;
uint8_t revision = data[PCI_REVISION_ID];
uint16_t vendorId = data[PCI_VENDOR_ID] | (data[PCI_VENDOR_ID + 1] << 8);
uint16_t deviceId = data[PCI_DEVICE_ID] | (data[PCI_DEVICE_ID + 1] << 8);
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitStatic(&gpu->platformApi, "/servers/bus/pci");
ffStrbufInit(&gpu->memoryType);
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 = ffGPUPciAddr2Id(0, pciBus, pciDev, pciFunc);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName(deviceId, revision, gpu);
if (gpu->name.length == 0)
ffGPUFillVendorAndName(classSub, vendorId, deviceId, gpu);
}
}
}
return NULL;
}
+1 -1
View File
@@ -560,7 +560,7 @@ static const char* detectOf(FFlist* gpus, FFstrbuf* buffer, FFstrbuf* drmDir, co
if (!gpu->name.length)
{
ffStrbufSetS(&gpu->name, name ? name : compatible);
ffStrbufSetS(&gpu->name, name ?: compatible);
ffStrbufTrimRightSpace(&gpu->name);
}
if (!gpu->vendor.length && name)
+1
View File
@@ -1,6 +1,7 @@
#include "gpu.h"
#include "common/io.h"
#include "common/properties.h"
#include "common/memrchr.h"
#include <stdlib.h>
#ifdef __FreeBSD__
+1 -1
View File
@@ -142,7 +142,7 @@ const char* ffDetectLM(FFLMResult* result)
{
// On some incorrectly configured systems, $XDG_SESSION_ID is not set. Try finding it ourself
// WARNING: This is private data. Do not parse
ffStrbufSetF(&path, FF_SYSTEMD_USERS_PATH "%d", getuid());
ffStrbufSetF(&path, FF_SYSTEMD_USERS_PATH "%d", instance.state.platform.uid);
// This is actually buggy, and assumes current user is using DE
// `sd_pid_get_session` can be a better option, but we need to find a pid to use
+1
View File
@@ -1,6 +1,7 @@
#include "fastfetch.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/memrchr.h"
#include "detection/media/media.h"
#include <string.h>
+11 -10
View File
@@ -1,4 +1,5 @@
#include "memory.h"
#include "common/debug.h"
#include <string.h>
#include <mach/mach.h>
@@ -8,25 +9,25 @@
const char* ffDetectMemory(FFMemoryResult* ram)
{
size_t length = sizeof(ram->bytesTotal);
#if FF_APPLE_MEMSIZE_USABLE
if (sysctlbyname("hw.memsize_usable", &ram->bytesTotal, &length, NULL, 0) != 0)
return "Failed to read hw.memsize_usable";
#else
if (sysctl((int[]){ CTL_HW, HW_MEMSIZE }, 2, &ram->bytesTotal, &length, NULL, 0) != 0)
return "Failed to read hw.memsize";
uint64_t usableMemory = 0;
length = sizeof(usableMemory);
if (sysctlbyname("hw.memsize_usable", &usableMemory, &length, NULL, 0) != 0)
usableMemory = ram->bytesTotal;
#endif
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
vm_statistics64_data_t vmstat;
if(host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) (&vmstat), &count) != KERN_SUCCESS)
return "Failed to read host_statistics64";
uint64_t pageSize = instance.state.platform.sysinfo.pageSize;
uint64_t appMemory = vmstat.internal_page_count * pageSize;
uint64_t wiredMemory = vmstat.wire_count * pageSize;
uint64_t compressed = vmstat.compressor_page_count * pageSize;
uint64_t reserved = ram->bytesTotal - usableMemory;
// https://github.com/st3fan/osx-10.9/blob/34e34a6a539b5a822cda4074e56a7ced9b57da71/system_cmds-597.1.1/vm_stat.tproj/vm_stat.c#L139
ram->bytesUsed = appMemory + wiredMemory + compressed + reserved;
uint64_t pagesFree = vmstat.free_count - vmstat.speculative_count;
uint64_t pagesFileBacked = vmstat.external_page_count; // Cached files
ram->bytesUsed = ram->bytesTotal - (pagesFree + pagesFileBacked) * instance.state.platform.sysinfo.pageSize;
return NULL;
}
+3
View File
@@ -7,6 +7,9 @@ const char* ffDetectMemory(FFMemoryResult* ram)
MEMORYSTATUSEX statex = {
.dwLength = sizeof(statex),
};
// GlobalMemoryStatusEx() internally uses
// NtQuerySystemInformation(SystemBasicPerformanceInformation) in Win 7, and
// NtQuerySystemInformation(SystemMemoryUsageInformation) in Win 10
if (!GlobalMemoryStatusEx(&statex))
return "GlobalMemoryStatusEx() failed";
+72 -1
View File
@@ -1,4 +1,5 @@
#include "opengl.h"
#include "common/debug.h"
#include "common/library.h"
#if __has_include(<GL/gl.h>)
@@ -56,26 +57,48 @@ typedef struct EGLData
static const char* eglHandleContext(FFOpenGLResult* result, EGLData* data)
{
FF_DEBUG("Making EGL context current");
if(data->ffeglMakeCurrent(data->display, data->surface, data->surface, data->context) != EGL_TRUE)
{
FF_DEBUG("eglMakeCurrent() returned EGL_FALSE");
return "eglMakeCurrent returned EGL_FALSE";
}
ffOpenGLHandleResult(result, data->ffglGetString);
ffStrbufSetF(&result->library, "EGL %s", data->ffeglQueryString(data->display, EGL_VERSION));
FF_DEBUG("OpenGL via EGL detected: version='%s', renderer='%s', vendor='%s', slv='%s', library='%s'",
result->version.chars,
result->renderer.chars,
result->vendor.chars,
result->slv.chars,
result->library.chars);
return NULL;
}
static const char* eglHandleSurface(FFOpenGLResult* result, EGLData* data, bool gles)
{
FF_DEBUG("Creating EGL context (preferred API=%s, client version=%d)", gles ? "OpenGL ES" : "OpenGL", gles ? 2 : 1);
data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){
EGL_CONTEXT_CLIENT_VERSION, gles ? 2 : 1, // Try GLES 2.0+ first
EGL_NONE
});
if(data->context == EGL_NO_CONTEXT && gles) // Some ANGLE builds support GLES 1.1 only
{
FF_DEBUG("EGL context creation with GLES 2.x failed, retrying with default attributes (GLES 1.1 fallback)");
data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){EGL_NONE});
}
if(data->context == EGL_NO_CONTEXT)
{
FF_DEBUG("eglCreateContext() returned EGL_NO_CONTEXT");
return "eglCreateContext returned EGL_NO_CONTEXT";
}
FF_DEBUG("EGL context created successfully");
const char* error = eglHandleContext(result, data);
FF_DEBUG("eglHandleContext() returns: %s", error ?: "success");
FF_DEBUG("Destroying EGL context");
data->ffeglDestroyContext(data->display, data->context);
return error;
}
@@ -84,13 +107,21 @@ static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data)
{
// try use OpenGL API. If failed, use the default API (usually OpenGL ES)
bool gles = !data->ffeglBindAPI(EGL_OPENGL_API);
FF_DEBUG("eglBindAPI(EGL_OPENGL_API) %s, effective API=%s",
gles ? "failed" : "succeeded",
gles ? "default (usually OpenGL ES)" : "OpenGL");
EGLint eglConfigCount;
data->ffeglGetConfigs(data->display, &data->config, 1, &eglConfigCount);
FF_DEBUG("eglGetConfigs() returned %d config(s)", eglConfigCount);
if(eglConfigCount == 0)
{
FF_DEBUG("No EGL config is available");
return "eglGetConfigs returned 0 configs";
}
FF_DEBUG("Creating EGL pbuffer surface (%dx%d)", FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT);
data->surface = data->ffeglCreatePbufferSurface(data->display, data->config, (EGLint[]){
EGL_WIDTH, FF_OPENGL_BUFFER_WIDTH,
EGL_HEIGHT, FF_OPENGL_BUFFER_HEIGHT,
@@ -98,39 +129,71 @@ static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data)
});
if(data->surface == EGL_NO_SURFACE)
{
FF_DEBUG("eglCreatePbufferSurface() returned EGL_NO_SURFACE");
return "eglCreatePbufferSurface returned EGL_NO_SURFACE";
}
FF_DEBUG("EGL pbuffer surface created successfully");
const char* error = eglHandleSurface(result, data, gles);
FF_DEBUG("eglHandleSurface() returns: %s", error ?: "success");
FF_DEBUG("Destroying EGL surface");
data->ffeglDestroySurface(data->display, data->surface);
return error;
}
static const char* eglHandleData(FFOpenGLResult* result, EGLData* data)
{
FF_DEBUG("Resolving glGetString via eglGetProcAddress()");
data->ffglGetString = (__typeof__(&glGetString)) data->ffeglGetProcAddress("glGetString");
if(!data->ffglGetString)
{
FF_DEBUG("eglGetProcAddress('glGetString') returned NULL");
return "eglGetProcAddress(glGetString) returned NULL";
}
#if EGL_VERSION_1_5
PFNEGLGETPLATFORMDISPLAYEXTPROC ffeglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC) data->ffeglGetProcAddress("eglGetPlatformDisplay");
if (ffeglGetPlatformDisplay)
{
FF_DEBUG("Trying eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA)");
data->display = ffeglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA, NULL, NULL);
FF_DEBUG("eglGetPlatformDisplay() %s", data->display == EGL_NO_DISPLAY ? "failed" : "succeeded");
}
else
FF_DEBUG("eglGetPlatformDisplay is unavailable, falling back to eglGetDisplay");
if(!ffeglGetPlatformDisplay || data->display == EGL_NO_DISPLAY)
#endif
{
FF_DEBUG("Trying eglGetDisplay(EGL_DEFAULT_DISPLAY)");
data->display = data->ffeglGetDisplay(EGL_DEFAULT_DISPLAY);
if(data->display == EGL_NO_DISPLAY)
{
FF_DEBUG("eglGetDisplay() returned EGL_NO_DISPLAY");
return "eglGetDisplay returned EGL_NO_DISPLAY";
}
FF_DEBUG("eglGetDisplay() succeeded");
}
EGLint major, minor;
if(data->ffeglInitialize(data->display, &major, &minor) == EGL_FALSE)
{
FF_DEBUG("eglInitialize() returned EGL_FALSE");
return "eglInitialize returned EGL_FALSE";
}
FF_DEBUG("EGL initialized successfully: %d.%d", major, minor);
const char* error = eglHandleDisplay(result, data);
FF_DEBUG("eglHandleDisplay() returns: %s", error ?: "success");
FF_DEBUG("Terminating EGL display connection");
data->ffeglTerminate(data->display);
return error;
}
@@ -138,6 +201,7 @@ static const char* eglHandleData(FFOpenGLResult* result, EGLData* data)
const char* ffOpenGLDetectByEGL(FFOpenGLResult* result)
{
FF_DEBUG("Starting OpenGL detection via EGL");
EGLData eglData;
FF_LIBRARY_LOAD_MESSAGE(egl, "libEGL" FF_LIBRARY_EXTENSION, 1);
@@ -154,8 +218,15 @@ const char* ffOpenGLDetectByEGL(FFOpenGLResult* result)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglDestroySurface);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglTerminate);
FF_DEBUG("Loaded EGL library and required symbols");
FF_SUPPRESS_IO();
return eglHandleData(result, &eglData);
FF_DEBUG("Suppressed stdout/stderr during EGL probing");
const char* error = eglHandleData(result, &eglData);
FF_DEBUG("OpenGL detection via EGL returns: %s", error ?: "success");
return error;
}
#endif //FF_HAVE_EGL
+10 -3
View File
@@ -6,9 +6,11 @@
#include "common/mallocHelper.h"
#include "common/io.h"
#include <stdalign.h>
#include <windows.h>
#include "common/windows/nt.h"
#include <ntstatus.h>
#include <shlobj.h>
static uint32_t getNumElements(const char* searchPath, DWORD type, const wchar_t* ignore)
{
@@ -17,7 +19,7 @@ static uint32_t getNumElements(const char* searchPath, DWORD type, const wchar_t
bool flag = ignore == NULL;
uint32_t counter = 0;
uint8_t buffer[64 * 1024] __attribute__((aligned(8))); // Required for WoA
alignas(8) uint8_t buffer[64 * 1024];
BOOLEAN firstScan = TRUE;
size_t ignoreLen = ignore ? wcslen(ignore) : 0;
@@ -76,7 +78,7 @@ static inline void wrapYyjsonFree(yyjson_doc** doc)
static void detectScoop(FFPackagesResult* result)
{
FF_STRBUF_AUTO_DESTROY scoopPath = ffStrbufCreateA(MAX_PATH + 3);
ffStrbufAppendS(&scoopPath, instance.state.platform.homeDir.chars);
ffStrbufAppend(&scoopPath, &instance.state.platform.homeDir);
ffStrbufAppendS(&scoopPath, ".config/scoop/config.json");
yyjson_val* root = NULL;
@@ -107,7 +109,12 @@ static void detectScoop(FFPackagesResult* result)
ffStrbufSetJsonVal(&scoopPath, yyjson_obj_get(root, "global_path"));
if (scoopPath.length == 0)
{
ffStrbufSetS(&scoopPath, getenv("ProgramData"));
PWSTR pPath = NULL;
if (SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_ProgramData, KF_FLAG_DEFAULT, NULL, &pPath)))
{
ffStrbufSetWS(&scoopPath, pPath);
CoTaskMemFree(pPath);
}
ffStrbufAppendS(&scoopPath, "/scoop");
}
ffStrbufAppendS(&scoopPath, "/apps/");
@@ -2,6 +2,7 @@
#include "common/io.h"
#include "common/windows/unicode.h"
#include <stdalign.h>
#include <windows.h>
#include <winioctl.h>
@@ -135,7 +136,7 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysic
}
{
uint8_t buffer[sizeof(GET_MEDIA_TYPES) + sizeof(DEVICE_MEDIA_INFO) * 7] = "";
alignas(GET_MEDIA_TYPES) uint8_t buffer[sizeof(GET_MEDIA_TYPES) + sizeof(DEVICE_MEDIA_INFO) * 7] = {};
GET_MEDIA_TYPES* gmt = (GET_MEDIA_TYPES*) buffer;
if(DeviceIoControl(
hDevice,
+2 -1
View File
@@ -2,13 +2,14 @@
#include <sys/stat.h>
#include <sys/swap.h>
#include <limits.h>
#include <stdalign.h>
enum { FFMaxNSwap = 8 };
const char* ffDetectSwap(FFlist* result)
{
char strings[FFMaxNSwap][PATH_MAX];
uint8_t buffer[sizeof(swaptbl_t) + sizeof(swapent_t) * (FFMaxNSwap - 1)] = {};
alignas(swaptbl_t) uint8_t buffer[sizeof(swaptbl_t) + sizeof(swapent_t) * (FFMaxNSwap - 1)] = {};
swaptbl_t* table = (swaptbl_t*) buffer;
table->swt_n = FFMaxNSwap;
for (int i = 0; i < FFMaxNSwap; ++i)
+3 -25
View File
@@ -5,11 +5,11 @@
#include <winternl.h>
#include <ntstatus.h>
#include <windows.h>
#include <psapi.h>
#include <stdalign.h>
const char* detectByNqsi(FFlist* result)
const char* ffDetectSwap(FFlist* result)
{
uint8_t buffer[4096];
alignas(SYSTEM_PAGEFILE_INFORMATION) uint8_t buffer[4096];
ULONG size = sizeof(buffer);
SYSTEM_PAGEFILE_INFORMATION* pstart = (SYSTEM_PAGEFILE_INFORMATION*) buffer;
if(!NT_SUCCESS(NtQuerySystemInformation(SystemPagefileInformation, pstart, size, &size)))
@@ -29,25 +29,3 @@ const char* detectByNqsi(FFlist* result)
}
return NULL;
}
const char* detectByKgpi(FFlist* result)
{
PERFORMANCE_INFORMATION pi = {};
if (!K32GetPerformanceInfo(&pi, sizeof(pi)))
return "K32GetPerformanceInfo(&pi, sizeof(pi)) failed";
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitS(&swap->name, "Page File");
swap->bytesTotal = (uint64_t) (pi.CommitLimit > pi.PhysicalTotal ? pi.CommitLimit - pi.PhysicalTotal : 0) * pi.PageSize;
swap->bytesUsed = (uint64_t) (pi.CommitTotal > pi.PhysicalTotal ? pi.CommitTotal - pi.PhysicalTotal : 0) * pi.PageSize;
return NULL;
}
const char* ffDetectSwap(FFlist* result)
{
const char* err = detectByNqsi(result);
if (err == NULL)
return NULL;
return detectByKgpi(result);
}
@@ -6,11 +6,16 @@
#include "common/windows/registry.h"
#include "common/windows/unicode.h"
#include "common/windows/version.h"
#include "common/windows/nt.h"
#include "common/stringUtils.h"
#include <stdalign.h>
#include <windows.h>
#include <wchar.h>
#include <tlhelp32.h>
#include <ntstatus.h>
#include <winternl.h>
#include <shlobj.h>
bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version);
@@ -186,17 +191,29 @@ static bool detectDefaultTerminal(FFTerminalResult* result)
{
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))
PWSTR programFiles = NULL;
if (SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &programFiles)))
{
result->exeName = result->exe.chars + ffStrbufLastIndexC(&result->exe, '\\') + 1;
ffStrbufSet(&result->exePath, &result->exe);
}
else
{
ffStrbufDestroy(&result->exe);
ffStrbufInitMove(&result->exe, &path);
result->exeName = "";
ffStrbufSetWS(&result->exe, programFiles);
CoTaskMemFree(programFiles);
programFiles = NULL;
ffStrbufAppendS(&result->exe, "\\WindowsApps\\");
ffStrbufAppend(&result->exe, &path);
ffStrbufAppendS(&result->exe, "\\WindowsTerminal.exe");
if(ffPathExists(result->exe.chars, FF_PATHTYPE_FILE))
{
result->exeName = result->exe.chars + ffStrbufLastIndexC(&result->exe, '\\') + 1;
ffStrbufSet(&result->exePath, &result->exe);
}
else
{
ffStrbufDestroy(&result->exe);
ffStrbufInitMove(&result->exe, &path);
result->exeName = "";
}
}
return true;
}
@@ -204,14 +221,19 @@ static bool detectDefaultTerminal(FFTerminalResult* result)
}
}
conhost:
ffStrbufSetF(&result->exe, "%s\\System32\\conhost.exe", getenv("SystemRoot"));
if(ffPathExists(result->exe.chars, FF_PATHTYPE_FILE))
conhost:;
ULONG_PTR conhostPid = 0;
ULONG size;
if(NT_SUCCESS(NtQueryInformationProcess(NtCurrentProcess(), ProcessConsoleHostProcess, &conhostPid, sizeof(conhostPid), &size)) && conhostPid != 0)
{
ffStrbufSetS(&result->processName, "conhost.exe");
ffStrbufSetS(&result->prettyName, "conhost");
result->exeName = result->exe.chars + ffStrbufLastIndexC(&result->exe, '\\') + 1;
return true;
// For Windows Terminal, it reports the PID of OpenConsole
if(ffProcessGetInfoWindows((uint32_t) conhostPid, NULL, &result->processName, &result->exe, &result->exeName, &result->exePath, NULL))
{
ffStrbufSet(&result->prettyName, &result->processName);
if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe"))
ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4);
return true;
}
}
ffStrbufClear(&result->exe);
+1 -1
View File
@@ -100,7 +100,7 @@ const char* detectBySystemd(FFUsersOptions* options, FFlist* users)
if (options->myselfOnly)
{
ffStrbufAppendUInt(&pathUsers, getuid());
ffStrbufAppendUInt(&pathUsers, instance.state.platform.uid);
detectUserBySystemd(&pathUsers, users);
}
else
+71
View File
@@ -1,4 +1,5 @@
#include "fastfetch.h"
#include "common/debug.h"
#include "detection/gpu/gpu.h"
#include "detection/vulkan/vulkan.h"
@@ -39,6 +40,8 @@ static void applyDriverName(VkPhysicalDeviceDriverPropertiesKHR* properties, FFs
static const char* detectVulkan(FFVulkanResult* result)
{
FF_DEBUG("Starting Vulkan detection");
FF_LIBRARY_LOAD_MESSAGE(vulkan,
#if __APPLE__
"libMoltenVK" FF_LIBRARY_EXTENSION, -1
@@ -56,6 +59,7 @@ static const char* detectVulkan(FFVulkanResult* result)
//Some drivers (nvdc) print messages to stdout
//and that is the best way I found to disable that
FF_SUPPRESS_IO();
FF_DEBUG("Suppressed stdout/stderr during Vulkan probing to avoid noisy drivers");
FFVersion instanceVersion = FF_VERSION_INIT;
@@ -66,8 +70,15 @@ static const char* detectVulkan(FFVulkanResult* result)
{
uint32_t version;
if(ffvkEnumerateInstanceVersion(&version) == VK_SUCCESS)
{
applyVulkanVersion(version, &instanceVersion);
FF_DEBUG("Detected Vulkan instance version: %u.%u.%u", instanceVersion.major, instanceVersion.minor, instanceVersion.patch);
}
else
FF_DEBUG("vkEnumerateInstanceVersion() is available but returned a non-success status");
}
else
FF_DEBUG("vkEnumerateInstanceVersion() is unavailable (likely Vulkan 1.0 runtime)");
const uint32_t projectVersion = VK_MAKE_VERSION(
FASTFETCH_PROJECT_VERSION_MAJOR,
@@ -76,6 +87,7 @@ static const char* detectVulkan(FFVulkanResult* result)
);
VkInstance vkInstance;
FF_DEBUG("Creating Vulkan instance with requested API version %s", instanceVersion.minor >= 1 ? "1.1" : "1.0");
VkResult res = ffvkCreateInstance(&(VkInstanceCreateInfo) {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = NULL,
@@ -98,6 +110,7 @@ static const char* detectVulkan(FFVulkanResult* result)
}, NULL, &vkInstance);
if(res != VK_SUCCESS)
{
FF_DEBUG("ffvkCreateInstance() failed with VkResult=%d", res);
switch (res)
{
case VK_ERROR_OUT_OF_HOST_MEMORY:
@@ -116,17 +129,22 @@ static const char* detectVulkan(FFVulkanResult* result)
return "ffvkCreateInstance() failed: unknown error";
}
}
FF_DEBUG("Vulkan instance created successfully");
//if instance creation succeeded, but vkEnumerateInstanceVersion didn't, this means we are running against a vulkan 1.0 implementation
//explicitly set this version, if no device is found, so we still have at least this info
if(instanceVersion.major == 0 && instanceVersion.minor == 0 && instanceVersion.patch == 0)
{
instanceVersion.major = 1;
FF_DEBUG("Falling back to Vulkan instance version 1.0 due to unavailable enumerate call");
}
VkPhysicalDevice physicalDevices[128];
uint32_t physicalDeviceCount = (uint32_t) ARRAY_SIZE(physicalDevices);
res = ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices);
if(res != VK_SUCCESS)
{
FF_DEBUG("ffvkEnumeratePhysicalDevices() failed with VkResult=%d", res);
ffvkDestroyInstance(vkInstance, NULL);
switch (res)
{
@@ -142,13 +160,22 @@ static const char* detectVulkan(FFVulkanResult* result)
return "ffvkEnumeratePhysicalDevices() failed";
}
}
FF_DEBUG("Enumerated %u Vulkan physical device(s)", physicalDeviceCount);
PFN_vkGetPhysicalDeviceProperties ffvkGetPhysicalDeviceProperties = NULL;
PFN_vkGetPhysicalDeviceProperties2 ffvkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties2"); // 1.1
if(!ffvkGetPhysicalDeviceProperties2)
ffvkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties");
FF_DEBUG("Using %s for querying physical device properties", ffvkGetPhysicalDeviceProperties2 ? "vkGetPhysicalDeviceProperties2" : "vkGetPhysicalDeviceProperties");
PFN_vkGetPhysicalDeviceMemoryProperties ffvkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceMemoryProperties");
if(!ffvkGetPhysicalDeviceMemoryProperties)
{
FF_DEBUG("vkGetPhysicalDeviceMemoryProperties is unavailable");
ffvkDestroyInstance(vkInstance, NULL);
return "vkGetPhysicalDeviceMemoryProperties is not available";
}
FFVersion maxDeviceApiVersion = FF_VERSION_INIT;
FFVersion maxDeviceConformanceVersion = FF_VERSION_INIT;
@@ -172,10 +199,19 @@ static const char* detectVulkan(FFVulkanResult* result)
else
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties.properties);
FF_DEBUG("Processing Vulkan device #%u: name='%s', vendorId=0x%04X, deviceId=0x%04X, type=%u", i,
physicalDeviceProperties.properties.deviceName,
physicalDeviceProperties.properties.vendorID,
physicalDeviceProperties.properties.deviceID,
physicalDeviceProperties.properties.deviceType);
//We don't want software rasterizers to show up as physical gpu
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
{
FF_DEBUG("Skipping CPU Vulkan device '%s'", physicalDeviceProperties.properties.deviceName);
continue;
}
//If the device api version is higher than the current highest device api version, overwrite it
//In this case, also use the current device driver name as the shown driver name
@@ -186,6 +222,11 @@ static const char* detectVulkan(FFVulkanResult* result)
{
maxDeviceApiVersion = deviceAPIVersion;
applyDriverName(&driverProperties, &result->driver);
FF_DEBUG("Updated max Vulkan device API version to %u.%u.%u (driver='%s')",
maxDeviceApiVersion.major,
maxDeviceApiVersion.minor,
maxDeviceApiVersion.patch,
result->driver.chars);
}
//If the device conformance version is higher than the current highest device conformance version, overwrite it
@@ -198,7 +239,13 @@ static const char* detectVulkan(FFVulkanResult* result)
};
if(ffVersionCompare(&deviceConformanceVersion, &maxDeviceConformanceVersion) > 0)
{
maxDeviceConformanceVersion = deviceConformanceVersion;
FF_DEBUG("Updated max Vulkan conformance version to %u.%u.%u",
maxDeviceConformanceVersion.major,
maxDeviceConformanceVersion.minor,
maxDeviceConformanceVersion.patch);
}
}
//Add the device to the list of devices shown by the GPU module
@@ -207,7 +254,10 @@ static const char* detectVulkan(FFVulkanResult* result)
FF_LIST_FOR_EACH(FFGPUResult, gpu, result->gpus)
{
if (gpu->deviceId == physicalDeviceProperties.properties.deviceID)
{
FF_DEBUG("Skipping duplicate Vulkan GPU entry for deviceId=0x%04X", physicalDeviceProperties.properties.deviceID);
goto next;
}
}
FFGPUResult* gpu = ffListAdd(&result->gpus);
@@ -221,6 +271,10 @@ static const char* detectVulkan(FFVulkanResult* result)
ffStrbufInitS(&gpu->vendor, ffGPUGetVendorString(physicalDeviceProperties.properties.vendorID));
ffStrbufInitS(&gpu->driver, driverProperties.driverInfo);
ffStrbufInit(&gpu->memoryType);
FF_DEBUG("Added Vulkan GPU '%s' (vendor='%s', type=%s)",
gpu->name.chars,
gpu->vendor.chars,
gpu->type == FF_GPU_TYPE_DISCRETE ? "discrete" : "integrated");
VkPhysicalDeviceMemoryProperties memoryProperties = {};
ffvkGetPhysicalDeviceMemoryProperties(physicalDevices[i], &memoryProperties);
@@ -233,6 +287,10 @@ static const char* detectVulkan(FFVulkanResult* result)
FFGPUMemory* vmem = gpu->type == FF_GPU_TYPE_DISCRETE && (heap->flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? &gpu->dedicated : &gpu->shared;
vmem->total += heap->size;
}
FF_DEBUG("Computed memory for '%s': dedicatedTotal=%llu, sharedTotal=%llu",
gpu->name.chars,
(unsigned long long) gpu->dedicated.total,
(unsigned long long) gpu->shared.total);
//No way to detect those using vulkan
gpu->index = FF_GPU_INDEX_UNSET;
@@ -249,7 +307,14 @@ static const char* detectVulkan(FFVulkanResult* result)
ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion);
ffVersionToPretty(&maxDeviceConformanceVersion, &result->conformanceVersion);
FF_DEBUG("Vulkan detection finished: instanceVersion=%s, apiVersion=%s, conformanceVersion=%s, gpuCount=%u",
result->instanceVersion.chars,
result->apiVersion.chars,
result->conformanceVersion.chars,
result->gpus.length);
ffvkDestroyInstance(vkInstance, NULL);
FF_DEBUG("Destroyed Vulkan instance");
return NULL;
}
@@ -261,6 +326,7 @@ FFVulkanResult* ffDetectVulkan(void)
if (result.gpus.elementSize == 0)
{
FF_DEBUG("Initializing Vulkan detection cache");
ffStrbufInit(&result.driver);
ffStrbufInit(&result.apiVersion);
ffStrbufInit(&result.conformanceVersion);
@@ -269,10 +335,15 @@ FFVulkanResult* ffDetectVulkan(void)
#ifdef FF_HAVE_VULKAN
result.error = detectVulkan(&result);
if (result.error)
FF_DEBUG("Vulkan detection returned error: %s", result.error);
#else
result.error = "fastfetch was compiled without vulkan support";
FF_DEBUG("Vulkan support is disabled at compile time");
#endif
}
else
FF_DEBUG("Reusing cached Vulkan detection result");
return &result;
}
+5
View File
@@ -6,6 +6,11 @@
#ifdef __sun
#include <libzfs.h>
#ifndef __illumos__
// On Solaris 11, zpool_get_prop has only 5 arguments. #2173
#define ffzpool_get_prop(zhp, prop, buf, len, srctype, literal) \
ffzpool_get_prop(zhp, prop, buf, len, srctype)
#endif
#else
#include "libzfs_simplified.h"
#endif
+20 -20
View File
@@ -1,20 +1,20 @@
$1 ▗▄▄▄ $2▗▄▄▄▄ ▄▄▄▖
$1 ▜███▙ $2▜███▙ ▟███▛
$1 ▜███▙ $2▜███▙▟███▛
$1 ▜███▙ $2▜██████▛
$1 ▟█████████████████▙ $2▜████▛ $1▟▙
$1 ▟███████████████████▙ $2▜███▙ $1▟██▙
$2 ▄▄▄▄▖ ▜███▙ $1▟███▛
$2 ▟███▛ ▜██▛ $1▟███▛
$2 ▟███▛ ▜▛ $1▟███▛
$2▟███████████▛ $1▟██████████▙
$2▜██████████▛ $1▟███████████▛
$2 ▟███▛ $1▟▙ ▟███▛
$2 ▟███▛ $1▟██▙ ▟███▛
$2 ▟███▛ $1▜███▙ ▝▀▀▀▀
$2 ▜██▛ $1▜███▙ $2▜██████████████████▛
$2 ▜▛ $1▟████▙ $2▜████████████████▛
$1 ▟██████▙ $2▜███▙
$1 ▟███▛▜███▙ $2▜███▙
$1 ▟███▛ ▜███▙ $2▜███▙
$1 ▝▀▀▀ ▀▀▀▀▘ $2▀▀▀▘
$1▗▄▄▄ $2▗▄▄▄▄ ▄▄▄▖
$1▜███▙ $2▜███▙ ▟███▛
$1▜███▙ $2▜███▙▟███▛
$1▜███▙ $2▜██████▛
$1▟█████████████████▙ $2▜████▛ $3▟▙
$1▟███████████████████▙ $2▜███▙ $3▟██▙
$6▄▄▄▄▖ $2▜███▙ $3▟███▛
$6▟███▛ $2▜██▛ $3▟███▛
$6▟███▛ $2▜▛ $3▟███▛
$6▟███████████▛ $3▟██████████▙
$6▜██████████▛ $3▟███████████▛
$6▟███▛ $5▟▙ $3▟███▛
$6▟███▛ $5▟██▙ $3▟███▛
$6▟███▛ $5▜███▙ $3▝▀▀▀▀
$6▜██▛ $5▜███▙ $4▜██████████████████▛
$6▜▛ $5▟████▙ $4▜████████████████▛
$5▟██████▙ $4▜███▙
$5▟███▛▜███▙ $4▜███▙
$5▟███▛ ▜███▙ $4▜███▙
$5▝▀▀▀ ▀▀▀▀▘ $4▀▀▀▘
+6 -6
View File
@@ -1,7 +1,7 @@
$1 ▗▄ $2▗▄ ▄▖
$1 ▄▄🬸█▄▄▄$2🬸█▛ $1▃
$2 ▟▛ ▜$1▃▟🬕
$2🬋🬋🬫█ $1█🬛🬋🬋
$2 🬷▛🮃$1▙ ▟▛
$2 🮃 $1▟█🬴$2▀▀▀█🬴▀▀
$1 ▝▀ ▀▘ $2▀▘
$1 ▄▄🬸█▄▄▄$2🬸█▛ $3▃
$6 ▟▛ ▜$3▃▟🬕
$6🬋🬋🬫█ $3█🬛🬋🬋
$6 🬷▛🮃$5▙ $4▟▛
$6 🮃 $5▟█🬴$4▀▀▀█🬴▀▀
$5▝▀ ▀▘ $4▀▘
+8
View File
@@ -3305,6 +3305,10 @@ static const FFlogo N[] = {
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_CYAN,
FF_COLOR_FG_BLUE,
FF_COLOR_FG_CYAN,
FF_COLOR_FG_BLUE,
FF_COLOR_FG_CYAN,
},
},
// NixOSSmall
@@ -3315,6 +3319,10 @@ static const FFlogo N[] = {
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_CYAN,
FF_COLOR_FG_BLUE,
FF_COLOR_FG_CYAN,
FF_COLOR_FG_BLUE,
FF_COLOR_FG_CYAN,
},
},
// NixOSOld
+2 -2
View File
@@ -307,10 +307,10 @@ void ffLogoPrintChars(const char* data, bool doColorReplacement)
static void logoApplyColors(const FFlogo* logo, bool replacement)
{
if(instance.config.display.colorTitle.length == 0)
ffStrbufAppendS(&instance.config.display.colorTitle, logo->colorTitle ? logo->colorTitle : logo->colors[0]);
ffStrbufAppendS(&instance.config.display.colorTitle, logo->colorTitle ?: logo->colors[0]);
if(instance.config.display.colorKeys.length == 0)
ffStrbufAppendS(&instance.config.display.colorKeys, logo->colorKeys ? logo->colorKeys : logo->colors[1]);
ffStrbufAppendS(&instance.config.display.colorKeys, logo->colorKeys ?: logo->colors[1]);
if (replacement)
{
+14
View File
@@ -64,6 +64,12 @@ bool ffPrintTitle(FFTitleOptions* options)
FF_FORMAT_ARG(atColored, "at-symbol-colored"),
FF_FORMAT_ARG(hostNameColored, "host-name-colored"),
FF_FORMAT_ARG(instance.state.platform.fullUserName, "full-user-name"),
#ifndef _WIN32
FF_FORMAT_ARG(instance.state.platform.uid, "user-id"),
#else
FF_FORMAT_ARG(instance.state.platform.sid, "user-id"),
#endif
FF_FORMAT_ARG(instance.state.platform.pid, "pid"),
}));
}
@@ -121,12 +127,18 @@ void ffGenerateTitleJsonConfig(FFTitleOptions* options, yyjson_mut_doc* doc, yyj
bool ffGenerateTitleJsonResult(FF_MAYBE_UNUSED FFTitleOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result");
#ifdef _WIN32
yyjson_mut_obj_add_strbuf(doc, obj, "userId", &instance.state.platform.sid);
#else
yyjson_mut_obj_add_uint(doc, obj, "userId", instance.state.platform.uid);
#endif
yyjson_mut_obj_add_strbuf(doc, obj, "userName", &instance.state.platform.userName);
yyjson_mut_obj_add_strbuf(doc, obj, "fullUserName", &instance.state.platform.fullUserName);
yyjson_mut_obj_add_strbuf(doc, obj, "hostName", &instance.state.platform.hostName);
yyjson_mut_obj_add_strbuf(doc, obj, "homeDir", &instance.state.platform.homeDir);
yyjson_mut_obj_add_strbuf(doc, obj, "exePath", &instance.state.platform.exePath);
yyjson_mut_obj_add_strbuf(doc, obj, "userShell", &instance.state.platform.userShell);
yyjson_mut_obj_add_uint(doc, obj, "pid", instance.state.platform.pid);
return true;
}
@@ -169,5 +181,7 @@ FFModuleBaseInfo ffTitleModuleInfo = {
{"@ symbol (colored)", "at-symbol-colored"},
{"Host name (colored)", "host-name-colored"},
{"Full user name", "full-user-name"},
{"UID (*nix) / SID (Windows)", "user-id"},
{"PID of current process", "pid"},
}))
};