mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
265 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b40a81e22 | |||
| 8be64714ba | |||
| fe5d739cba | |||
| dba0672a11 | |||
| 3ed6acf3ca | |||
| 8c74c54bb0 | |||
| 818473102c | |||
| f1cc4a7805 | |||
| c574af97a4 | |||
| 74ae84e719 | |||
| 98738b6920 | |||
| 2e5769def2 | |||
| 18a6929662 | |||
| 0e61d1134d | |||
| 4abb183735 | |||
| d5b56be4ff | |||
| 1854953d8c | |||
| 2406015c81 | |||
| ec7f14ab96 | |||
| d94cdf4424 | |||
| 40e57b7698 | |||
| 974c658fff | |||
| ad0ddfd7f1 | |||
| 1da8367f55 | |||
| bdbc885811 | |||
| 86e5a5997b | |||
| 9832a0e45b | |||
| addf674621 | |||
| 863c5583ef | |||
| 45cbc6de83 | |||
| e68f766b4d | |||
| 29d7a1acac | |||
| 8d59d14b80 | |||
| ed1883909a | |||
| 049701a8a9 | |||
| 13b7bc89eb | |||
| 92fe44183d | |||
| 8ebc980c17 | |||
| dbeb338bda | |||
| 65ff11a8d0 | |||
| 7a73211484 | |||
| ca049997b1 | |||
| a9f021ccb9 | |||
| 55249c2294 | |||
| c13da56959 | |||
| 665c7cd5d3 | |||
| 469e21cce9 | |||
| 925e09c88a | |||
| 488454c1aa | |||
| c67c52d606 | |||
| e4e11ee509 | |||
| a3e2592555 | |||
| e0e966dadf | |||
| b079a8643b | |||
| 3291a9945f | |||
| 68fd21d0e4 | |||
| 0e1ef96992 | |||
| c377872438 | |||
| 4f42d38e4d | |||
| 7b2243496b | |||
| 960a817d03 | |||
| 6917f9479e | |||
| 8559cc45eb | |||
| 40e33c676d | |||
| d20371040e | |||
| 71faf1c7e3 | |||
| d182f3f743 | |||
| 39e009b945 | |||
| a1873f3e9e | |||
| 636bcaaaf9 | |||
| 3fcbd80ef0 | |||
| 38887e7fbd | |||
| da958e11f9 | |||
| c2ed71c4eb | |||
| 2e1ddcf9f8 | |||
| f1cc2d124c | |||
| 1e32a95f83 | |||
| 9e959bc57f | |||
| e68406ee22 | |||
| ba69e316b2 | |||
| f3e8e8af52 | |||
| c9adab3892 | |||
| c8d1d29017 | |||
| 541acca7c0 | |||
| ddf5099461 | |||
| 781a692b06 | |||
| 9c37f1b370 | |||
| a66c26f4df | |||
| 3bd750bedf | |||
| 4a1ada604c | |||
| e5f57a34a2 | |||
| 20a3737dce | |||
| e0452d9db5 | |||
| d8e74ba84c | |||
| 04b13096ac | |||
| 64d4035cae | |||
| 5e0ba57f53 | |||
| d89263c218 | |||
| 6a42588786 | |||
| 5883bf359c | |||
| 6a6b4070ca | |||
| 2c80cd6d29 | |||
| fa4b00b027 | |||
| 5fdc924b5d | |||
| 3d4a117093 | |||
| 7ec0c664c5 | |||
| 9d2df589b5 | |||
| 7107d08e92 | |||
| 4c34f99c12 | |||
| d7a8c92b46 | |||
| bbb29ff766 | |||
| 35235b9557 | |||
| 6b94605804 | |||
| 4b2fa07fdc | |||
| e203f4eeaf | |||
| 8db70b40e2 | |||
| 1f967849e5 | |||
| d60b2ddfd4 | |||
| fb68d8a841 | |||
| 047411ba87 | |||
| 08ed14b42a | |||
| d94a41cc1b | |||
| 81b7fb06c1 | |||
| c8debccd16 | |||
| 2853bd15c0 | |||
| 2f4146fde8 | |||
| eeceade14e | |||
| 1875c78e96 | |||
| f389864e17 | |||
| b9317734b9 | |||
| 4df4a1de78 | |||
| 0cd8c6ead6 | |||
| f8479dae94 | |||
| a7d623fa75 | |||
| 7a8ffb27bd | |||
| 73c0347469 | |||
| fde5f3bd0f | |||
| 9e1b1302fb | |||
| 7e235b6be0 | |||
| f43e1fd614 | |||
| c7b061eebd | |||
| a0f579072f | |||
| d439ce8eb5 | |||
| e2a714732a | |||
| a993a6f126 | |||
| 8eb8f710d0 | |||
| 526868e355 | |||
| 768238cb46 | |||
| 2d938042d0 | |||
| 9a54d92e9f | |||
| 839abab744 | |||
| c054570308 | |||
| ed69a7059b | |||
| 6b92659512 | |||
| 7e04305d1c | |||
| 87e13543da | |||
| 7a2cbc060f | |||
| f22d73d473 | |||
| e629126d73 | |||
| 9ac635e2e6 | |||
| 1b1b0521f4 | |||
| 41d0f61ee0 | |||
| 9de5d9008b | |||
| 576a9cc6fe | |||
| bd61d08afe | |||
| 4672b78481 | |||
| 36b0fdbcda | |||
| 7626ef6eaa | |||
| 115108b3f1 | |||
| 154f9f462b | |||
| a96a9fc31d | |||
| 23b43244c5 | |||
| 9dfb404a0d | |||
| ff3028c656 | |||
| 2f706ed494 | |||
| 06427ee62b | |||
| fe66eb3df0 | |||
| 6e1ab12399 | |||
| 484e05eae3 | |||
| 5d3fb98072 | |||
| 0c30590088 | |||
| 20cd4ce125 | |||
| 1c7aa89228 | |||
| f270255770 | |||
| 4b62a3c75b | |||
| 1557f0c556 | |||
| ef7f61309f | |||
| f59491b25d | |||
| e3592eb2c3 | |||
| 305776eb94 | |||
| 599e0d393d | |||
| 561574ae94 | |||
| 3dd78422eb | |||
| 5c546ab8e7 | |||
| 3e9274040d | |||
| 630d876e2d | |||
| 1938be86ff | |||
| 0980d5f0ad | |||
| d8c1b3b61b | |||
| 969523ae8a | |||
| 5d960ec744 | |||
| 3b36b8ca57 | |||
| 05f14764e6 | |||
| 3a180b24e3 | |||
| 02ab58e001 | |||
| fd158b41e1 | |||
| 89e0ede12f | |||
| 4d7b2410ef | |||
| c1f6a2f755 | |||
| 9c455c3b0f | |||
| d4ea9dfd21 | |||
| 08071e6e7e | |||
| ec87174f30 | |||
| 835e5b51c9 | |||
| 07c5ef255e | |||
| 476b55c17d | |||
| 4a53cfa312 | |||
| 50ea515476 | |||
| cbd9f72bc8 | |||
| 29eaa35f4c | |||
| 97c89c39d3 | |||
| 5769791185 | |||
| 894c66d793 | |||
| 75290154b0 | |||
| b08eea76b1 | |||
| 61d83af9ea | |||
| 2d497038eb | |||
| f8a5d5561a | |||
| 2e7e68ef23 | |||
| b812f3ccde | |||
| 6da8181bbe | |||
| a51dd641c1 | |||
| 0d20164d40 | |||
| 3320532668 | |||
| bcc6492115 | |||
| c60bc8ee5b | |||
| 4eefab8ccf | |||
| 9cda7e20fb | |||
| 79d0197dcf | |||
| ba01b1e4ce | |||
| 58908f69ba | |||
| 114088b845 | |||
| 6e77b592cb | |||
| 73bc71e922 | |||
| 090529ffef | |||
| 3c291f1af9 | |||
| fc31fe4aa4 | |||
| 563f9598be | |||
| 03bc2dade9 | |||
| 09d683b706 | |||
| 523a9590b8 | |||
| 3c3188eb05 | |||
| 354062118f | |||
| 85d7390fa8 | |||
| 8509f97054 | |||
| 8d5d8b4c90 | |||
| 536ad9594e | |||
| a57bbbadf4 | |||
| 3def466ee0 | |||
| 59868c66a0 | |||
| e13eb05073 | |||
| cdda65e6ad | |||
| a7ac89818c | |||
| 06956d2cf4 | |||
| ac52ea1afb |
+1
-1
@@ -1,5 +1,5 @@
|
||||
[codespell]
|
||||
check-filenames =
|
||||
builtin = clear,rare,usage,informal
|
||||
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii
|
||||
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h
|
||||
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu
|
||||
|
||||
+203
-13
@@ -60,7 +60,7 @@ jobs:
|
||||
|
||||
linux-amd64:
|
||||
name: Linux-amd64
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -80,12 +80,12 @@ jobs:
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev
|
||||
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa ddcutil --ignore-dependencies
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
@@ -151,8 +151,13 @@ jobs:
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
@@ -378,7 +383,7 @@ jobs:
|
||||
run: |
|
||||
cat /etc/alpine-release
|
||||
uname -a
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
shell: alpine.sh --root {0}
|
||||
|
||||
- name: build
|
||||
@@ -403,9 +408,9 @@ jobs:
|
||||
name: fastfetch-musl-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
macos-universal:
|
||||
name: macOS-universal
|
||||
runs-on: macos-latest
|
||||
macos-amd64:
|
||||
name: macOS-amd64
|
||||
runs-on: macos-13
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -421,7 +426,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
|
||||
@@ -447,7 +452,54 @@ jobs:
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-macos-universal
|
||||
name: fastfetch-macos-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
macos-aarch64:
|
||||
name: macOS-aarch64
|
||||
runs-on: macos-latest
|
||||
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-aarch64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
sunos-amd64:
|
||||
@@ -500,7 +552,7 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '14.2'
|
||||
version: '14.3'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg update
|
||||
@@ -537,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
|
||||
@@ -592,6 +644,80 @@ jobs:
|
||||
name: fastfetch-netbsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
dragonfly-amd64:
|
||||
name: DragonFly-amd64
|
||||
runs-on: ubuntu-latest
|
||||
if: false
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/dragonflybsd-vm@v1
|
||||
with:
|
||||
usesh: yes
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update
|
||||
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf
|
||||
|
||||
run: |
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --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
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-dragonfly-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
haiku-amd64:
|
||||
name: Haiku-amd64
|
||||
runs-on: ubuntu-latest
|
||||
if: false
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: 'r1beta5'
|
||||
run: |
|
||||
uname -a
|
||||
ls -l
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --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
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-haiku-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
windows-amd64:
|
||||
name: Windows-amd64
|
||||
runs-on: windows-latest
|
||||
@@ -654,6 +780,68 @@ jobs:
|
||||
name: fastfetch-windows-amd64
|
||||
path: ./fastfetch-windows-amd64.*
|
||||
|
||||
windows-aarch64:
|
||||
name: Windows-aarch64
|
||||
runs-on: windows-11-arm
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: CLANGARM64
|
||||
update: true
|
||||
install: git mingw-w64-clang-aarch64-7zip mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-vulkan-loader mingw-w64-clang-aarch64-vulkan-headers mingw-w64-clang-aarch64-opencl-icd mingw-w64-clang-aarch64-opencl-headers mingw-w64-clang-aarch64-cppwinrt mingw-w64-clang-aarch64-imagemagick
|
||||
|
||||
- name: print msys version
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: env PKG_CONFIG_PATH=/clangarm64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --verbose -j4
|
||||
|
||||
- name: copy necessary dlls
|
||||
run: cp /clangarm64/bin/{OpenCL,vulkan-1}.dll .
|
||||
|
||||
- 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: ldd fastfetch
|
||||
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: create zip archive
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-aarch64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: create 7z archive
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-aarch64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-windows-aarch64
|
||||
path: ./fastfetch-windows-aarch64.*
|
||||
|
||||
release:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
name: Release
|
||||
@@ -667,12 +855,14 @@ jobs:
|
||||
- linux-ppc64le
|
||||
- linux-s390x
|
||||
- musl-amd64
|
||||
- macos-universal
|
||||
- macos-amd64
|
||||
- macos-aarch64
|
||||
- freebsd-amd64
|
||||
- openbsd-amd64
|
||||
- netbsd-amd64
|
||||
- sunos-amd64
|
||||
- windows-amd64
|
||||
- windows-aarch64
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
|
||||
+198
-1
@@ -1,3 +1,200 @@
|
||||
# 2.47.0
|
||||
|
||||
Features:
|
||||
* Various improvements for Solaris / OpenIndiana support
|
||||
* Support BIOS (UEFI or legacy) type detection (BIOS)
|
||||
* Support physical disk detection (PhysicalDisk)
|
||||
* Remove leading `-` from login shells (Shell)
|
||||
* Improve GPU detection performance (GPU)
|
||||
* Drop `libpciaccess` dependency
|
||||
* Use native API to detect sound devices (Sound)
|
||||
* Drop `PulseAudio` dependency
|
||||
* Improve DietPi OS and Raspberry Pi OS detection (#1816, OS, Linux)
|
||||
* Force reporting version 26 on macOS Tahoe (OS, macOS)
|
||||
* Append version string to Ubuntu variants (OS, Linux)
|
||||
* Improve performance of media detection for macOS 15.4+ (Media, macOS)
|
||||
* Increase `PROC_FILE_BUFFSIZ` to avoid possible short reads (Linux)
|
||||
* Fix potential bugs in `DiskIO`, `NetIO` and `CPUUsage` modules
|
||||
* Improve accuracy of CPU usage calculations by including interrupt and softirq times (CPUUsage, Linux / *BSD)
|
||||
* Ignore `init` and `systemd` processes when detecting terminals (Terminal, Linux)
|
||||
* Improve accuracy of CPU usage detection on Windows 10+ with perflib, which matches values reported by Task Manager (CPUUsage, Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Fix `pci.ids` file location (#1819, GPU, OpenBSD)
|
||||
* Fix compiling on FreeBSD when `libdrm` support is disabled (#1820, GPU, FreeBSD)
|
||||
|
||||
Logos:
|
||||
* Improve visibility on white-background terminals for some logos by replacing white with the default foreground color
|
||||
* According to Wikipedia, the default foreground color is implementation-defined. It's usually black for white themes and white for dark themes. However, some terminals, notably Konsole with the default theme, use a different color, which may cause issues with some logos.
|
||||
* Add Xubuntu
|
||||
|
||||
# 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` dependency (#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:
|
||||
* Support OnePlus marketing name detection (#1768, Host, Android)
|
||||
* Recognize additional GPU vendors (GPU, Linux)
|
||||
* Support CTWM, FVWM and I3 window manager version detection (WM)
|
||||
* Support KDE version detection on *BSD (DE, FreeBSD)
|
||||
* Support `"logo": { "type": "command-raw" }` to run a command and display its output as logo (#1780, Logo)
|
||||
* Useful for displaying custom logos generated by other programs such as `pokeget`: `{ "type": "command-raw", "source": "pokeget random --hide-name" }`
|
||||
* Supported in JSONC config file only. `pokeget random --hide-name | fastfetch --file-raw -` should be used in shell.
|
||||
* Acquire SMBIOS information on DragonFly BSD from `/dev/mem`; legacy BIOS only (PhysicalMemory, DragonFly)
|
||||
* Support swap usage detection on DragonFly BSD (Swap, DragonFly)
|
||||
* Support `--swap-separate` to display detailed swap devices on separate lines (Swap)
|
||||
|
||||
Bugfixes
|
||||
* Fix MacBook Air model name (#1779, Host, macOS)
|
||||
* Don't ignore sshfs mountpoints (#1776, Disk, Linux / FreeBSD)
|
||||
* Fix dnf package count detection (#1777, Packages, Linux)
|
||||
|
||||
Logos:
|
||||
* Add Starry Linux (#1771)
|
||||
* Add rhel_small (#1774)
|
||||
* Update color palette of voidlinux (#1775)
|
||||
* Add void2
|
||||
* Update Xenia Linux (#1783)
|
||||
|
||||
# 2.44.0
|
||||
|
||||
Features:
|
||||
* Add option `--disk-hide-folders` and `--disk-hide-fs` to hide specific mountpoints and filesystems in Disk module (Disk)
|
||||
* `--disk-hide-folders` defaults to `/efi:/boot:/boot/efi` on Linux and *BSD. Previously these EFI-related folders were hardcoded to be hidden on Linux.
|
||||
|
||||
Bugfixes:
|
||||
* Fix Apple Terminal compatibility with `--stat` (macOS, #1755)
|
||||
* Ignore `/usr/bin/script` when detecting shell and terminal (Terminal / Shell, #1761)
|
||||
* Fix compatibility with KDE Plasma 6.4 which is in beta currently (Display, Linux, #1765)
|
||||
|
||||
Logos:
|
||||
* Add Kylin (#1760)
|
||||
* Add UBLinux (#1764)
|
||||
|
||||
# 2.43.0
|
||||
|
||||
Features:
|
||||
* Support physical core count and package count detection on Solaris (CPU, SunOS)
|
||||
* Improve physical core count detection on FreeBSD (CPU, FreeBSD)
|
||||
* Add option to hide unknown GPUs (GPU)
|
||||
* Detect VRAM type of AMD GPUs on Linux (GPU, Linux)
|
||||
* Support playing media detection on macOS 15.4 (#1737, Media, macOS)
|
||||
* Whether it works on newer versions is unknown
|
||||
* Detect player name for Windows UMP apps (Media, Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Fix disk usage detection on 32-bit Linux (#1734, Disk, Linux)
|
||||
* Fix compiling on Asahi Linux (GPU, Linux)
|
||||
* Fix duplicated playback status (Media, Linux)
|
||||
* Don't show 255 in custom format when muted on macOS (#1750, Sound, macOS)
|
||||
* Remove shared memory detection for AMD GPUs, which doesn't work as expected (GPU, Windows)
|
||||
|
||||
Logos:
|
||||
* new AthenaOS
|
||||
* add Hydra Framework
|
||||
|
||||
# 2.42.0
|
||||
|
||||
Changes:
|
||||
* Normalize the module name `Bios` to `BIOS` (#1721)
|
||||
* No configuration file changes are required because fastfetch parses module names case-insensitively.
|
||||
|
||||
Bugfixes:
|
||||
* Disable disk type detection for virtual disks (PhysicalDisk, Linux, #1669)
|
||||
* Fix incorrect CPU temperature reporting (CPU, OpenBSD)
|
||||
* Fix setting `logo.chafa.symbols` in JSON configuration (Logo, #1709)
|
||||
* Fix non-normalized time display (Uptime, #1720)
|
||||
* Miscellaneous minor fixes
|
||||
|
||||
Features:
|
||||
* Add CPU temperature detection support (CPU, SunOS)
|
||||
* Improve CPU frequency detection (CPU, NetBSD)
|
||||
* Add Wi-Fi detection support (Wifi, NetBSD)
|
||||
* Add Webcam detection support (Camera, OpenBSD)
|
||||
* Requires root privileges
|
||||
|
||||
Logos:
|
||||
* Remove GoralixOS logo (#1699)
|
||||
* Add Aurora logo (#1700)
|
||||
* Add Codex Linux logo (#1701)
|
||||
|
||||
# 2.41.0
|
||||
|
||||
Changes:
|
||||
* Due to [the deprecation](https://github.com/actions/runner-images/issues/11101), Linux x86_64 binaries are now built with Ubuntu 22.04 (Glibc 2.35, Debian 12)
|
||||
* You can always build fastfetch yourself on your own. Please don't report bugs related to this change.
|
||||
|
||||
Features:
|
||||
* Support physical core count detection on non-x86 platforms (CPU, Linux / FreeBSD)
|
||||
* Support CPU frequency detection on PPC64 (CPU, FreeBSD)
|
||||
* Support soar packages count detection (Packages, Linux)
|
||||
* Support `~` path expanding on Windows (Logo, Windows)
|
||||
* Support retrieving full user name (Title)
|
||||
* Exposed with `--title-format '{full-user-name}'`
|
||||
* Improve CPU (thermal zone) temperature detection on Windows (CPU, Windows)
|
||||
* Administrator privileges are no longer needed
|
||||
* Support base Wifi info detection on OpenBSD (Wifi, OpenBSD)
|
||||
* To be tested
|
||||
* Support GPU temperature detection for Intel dGPU on Linux (GPU, Linux)
|
||||
* To be tested
|
||||
* Add new ARM CPU part numbers (CPU, Linux)
|
||||
* Add base implementation of Bluetooth device detection (Bluetooth, NetBSD, #1690)
|
||||
* Some small improvements
|
||||
|
||||
Logo:
|
||||
* Add anduinos
|
||||
* Add 2 more Alpine logos
|
||||
|
||||
# 2.40.4
|
||||
|
||||
Bugfixes:
|
||||
* Fix loading presets config on Windows (Windows, #1682)
|
||||
* Regression of v2.40.0
|
||||
* Remove the prefix `v` of Hyprland version on Arch Linux (WM, Linux)
|
||||
|
||||
# 2.40.3
|
||||
|
||||
Bugfixes:
|
||||
* Fix loading example configs from presets directory (#1672)
|
||||
* Regression of v2.40.2
|
||||
* Mark kitty image protocol support for warp terminal on macOS too (Logo)
|
||||
|
||||
# 2.40.2
|
||||
|
||||
Changes:
|
||||
@@ -837,7 +1034,7 @@ Bugfixes:
|
||||
* Fix some presets
|
||||
* Better detection for XTerm terminal fonts (#1095, TerminalFont, Linux)
|
||||
* Remove debug output (#1097, Windows)
|
||||
* Fix command line option `--gpu-hide-type` doesn't work (#1098, GPU)
|
||||
* Fix flag `--gpu-hide-type` doesn't work (#1098, GPU)
|
||||
* Fix wrong date on Raspbian 10 (#1108, DateTime, Linux)
|
||||
* Use `brightness` instead of `actuall_brightness` when detecting current brightness level (Brightness, Linux)
|
||||
* Ref: https://bugzilla.kernel.org/show_bug.cgi?id=203905
|
||||
|
||||
+60
-30
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.40.2
|
||||
VERSION 2.47.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)
|
||||
@@ -76,13 +76,13 @@ cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD O
|
||||
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
|
||||
cmake_dependent_option(ENABLE_LIBZFS "Enable libzfs" ON "LINUX OR FreeBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD" OFF)
|
||||
|
||||
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
|
||||
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
|
||||
@@ -102,7 +102,7 @@ if(NOT BINARY_LINK_TYPE IN_LIST BINARY_LINK_TYPE_OPTIONS)
|
||||
message(FATAL_ERROR "BINARY_LINK_TYPE must be one of ${BINARY_LINK_TYPE_OPTIONS}")
|
||||
endif()
|
||||
|
||||
set(PACKAGE_MANAGERS AM APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SORCERY WINGET XBPS)
|
||||
set(PACKAGE_MANAGERS AM APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SOAR SORCERY WINGET XBPS)
|
||||
foreach(package_manager ${PACKAGE_MANAGERS})
|
||||
if(package_manager STREQUAL "WINGET")
|
||||
option(PACKAGES_DISABLE_${package_manager} "Disable ${package_manager} package manager detection by default" ON)
|
||||
@@ -342,7 +342,6 @@ foreach(file ${LOGO_FILES})
|
||||
fastfetch_load_text("${file}" content)
|
||||
get_filename_component(file "${file}" NAME_WE)
|
||||
string(TOUPPER "${file}" file)
|
||||
string(REGEX REPLACE "\\$\\{c([0-9]+)\\}" "$\\1" content "${content}")
|
||||
set(LOGO_BUILTIN_H "${LOGO_BUILTIN_H}#define FASTFETCH_DATATEXT_LOGO_${file} ${content}\n")
|
||||
endforeach()
|
||||
file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
|
||||
@@ -525,6 +524,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
|
||||
@@ -672,6 +672,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
|
||||
@@ -705,7 +706,7 @@ elseif(FreeBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
@@ -734,7 +735,7 @@ elseif(NetBSD)
|
||||
src/common/sysctl.c
|
||||
src/detection/battery/battery_nbsd.c
|
||||
src/detection/bios/bios_nbsd.c
|
||||
src/detection/bluetooth/bluetooth_nosupport.c
|
||||
src/detection/bluetooth/bluetooth_bsd.c
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
src/detection/board/board_nbsd.c
|
||||
src/detection/bootmgr/bootmgr_bsd.c
|
||||
@@ -783,7 +784,7 @@ elseif(NetBSD)
|
||||
src/detection/netio/netio_bsd.c
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_nbsd.c
|
||||
src/detection/packages/packages_obsd.c
|
||||
src/detection/packages/packages_nbsd.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_nbsd.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
@@ -797,8 +798,8 @@ elseif(NetBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/wifi/wifi_nbsd.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
@@ -879,8 +880,8 @@ elseif(OpenBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_obsd.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/wifi/wifi_obsd.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
@@ -977,7 +978,6 @@ elseif(WIN32)
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/cpu/cpu_windows.c
|
||||
src/detection/cpu/cpu_windows.cpp
|
||||
src/detection/cpucache/cpucache_windows.c
|
||||
src/detection/cpuusage/cpuusage_windows.c
|
||||
src/detection/cursor/cursor_windows.c
|
||||
@@ -1057,7 +1057,7 @@ elseif(SunOS)
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
src/detection/disk/disk_sunos.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_nosupport.c
|
||||
src/detection/physicaldisk/physicaldisk_sunos.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/diskio/diskio_sunos.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
@@ -1097,7 +1097,7 @@ elseif(SunOS)
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_linux.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
src/detection/sound/sound_linux.c
|
||||
src/detection/sound/sound_sunos.c
|
||||
src/detection/swap/swap_sunos.c
|
||||
src/detection/terminalfont/terminalfont_linux.c
|
||||
src/detection/terminalshell/terminalshell_linux.c
|
||||
@@ -1589,7 +1589,14 @@ elseif(WIN32)
|
||||
PRIVATE "cfgmgr32"
|
||||
PRIVATE "winbrand"
|
||||
PRIVATE "propsys"
|
||||
PRIVATE "secur32"
|
||||
)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||
# WoA only works on Windows 10 or higher
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "mincore"
|
||||
)
|
||||
endif()
|
||||
elseif(FreeBSD)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "m"
|
||||
@@ -1613,6 +1620,7 @@ elseif(OpenBSD)
|
||||
)
|
||||
elseif(NetBSD)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "bluetooth"
|
||||
PRIVATE "m"
|
||||
PRIVATE "prop"
|
||||
)
|
||||
@@ -1624,6 +1632,7 @@ elseif(SunOS)
|
||||
PRIVATE "proc"
|
||||
PRIVATE "zfs"
|
||||
PRIVATE "nvpair"
|
||||
PRIVATE "devinfo"
|
||||
)
|
||||
elseif(ANDROID)
|
||||
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
|
||||
@@ -1826,10 +1835,26 @@ if (BUILD_TESTS)
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
add_executable(fastfetch-test-color
|
||||
tests/color.c
|
||||
)
|
||||
target_link_libraries(fastfetch-test-color
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
add_executable(fastfetch-test-duration
|
||||
tests/duration.c
|
||||
)
|
||||
target_link_libraries(fastfetch-test-duration
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
|
||||
add_test(NAME test-list COMMAND fastfetch-test-list)
|
||||
add_test(NAME test-format COMMAND fastfetch-test-format)
|
||||
add_test(NAME test-color COMMAND fastfetch-test-color)
|
||||
add_test(NAME test-duration COMMAND fastfetch-test-duration)
|
||||
endif()
|
||||
|
||||
##################
|
||||
@@ -1897,17 +1922,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)
|
||||
@@ -1933,12 +1958,17 @@ if(LINUX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(HAVE_RPMBUILD "rpmbuild")
|
||||
if(HAVE_RPMBUILD)
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
|
||||
if(NOT IS_MUSL)
|
||||
find_program(HAVE_RPMBUILD "rpmbuild")
|
||||
if(HAVE_RPMBUILD)
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
endif()
|
||||
endif()
|
||||
elseif(FreeBSD)
|
||||
set(CPACK_FREEBSD_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};FREEBSD")
|
||||
endif()
|
||||
|
||||
set(CPACK_SET_DESTDIR ON)
|
||||
|
||||
@@ -21,6 +21,8 @@ Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for
|
||||
<img src="screenshots/example3.png" width="48%" align="top" />
|
||||
<img src="screenshots/example5.png" height="15%" align="top" />
|
||||
|
||||
According configuration files for examples are located [here](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets/examples).
|
||||
|
||||
There are [screenshots on different platforms](https://github.com/fastfetch-cli/fastfetch/wiki).
|
||||
|
||||
## Installation
|
||||
@@ -67,9 +69,12 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
|
||||
|
||||
You may also download the program directly from [the GitHub releases page](https://github.com/fastfetch-cli/fastfetch/releases/latest) in the form of an archive file.
|
||||
|
||||
### FreeBSD
|
||||
### BSD systems
|
||||
|
||||
* `pkg install fastfetch`
|
||||
* FreeBSD: `pkg install fastfetch`
|
||||
* NetBSD: `pkgin in fastfetch`
|
||||
* OpenBSD: `pkg_add fastfetch` (Snapshots only)
|
||||
* DragonFly BSD: `pkg install fastfetch` (Snapshots only)
|
||||
|
||||
### Android (Termux)
|
||||
|
||||
@@ -230,6 +235,56 @@ Set the key to a white space.
|
||||
}
|
||||
```
|
||||
|
||||
### Q: How can I display images on Windows?
|
||||
|
||||
As of April 2025:
|
||||
|
||||
#### mintty and Wezterm
|
||||
|
||||
mintty (used by Bash on Windows and MSYS2) and Wezterm (nightly build only) support the iTerm image protocol on Windows.
|
||||
|
||||
In `config.jsonc`:
|
||||
```json
|
||||
{
|
||||
"logo": {
|
||||
"type": "iterm",
|
||||
"source": "C:/path/to/image.png",
|
||||
"width": <num-in-chars>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Windows Terminal
|
||||
|
||||
Windows Terminal supports the sixel image protocol only.
|
||||
|
||||
* If you installed fastfetch through MSYS2:
|
||||
1. Install imagemagick: `pacman -S mingw-w64-<subsystem>-x86_64-imagemagick`
|
||||
2. In `config.jsonc`:
|
||||
```jsonc
|
||||
{
|
||||
"logo": {
|
||||
"type": "sixel", // DO NOT USE "auto"
|
||||
"source": "C:/path/to/image.png", // Do NOT use `~` as fastfetch is a native Windows program and doesn't apply cygwin path conversion
|
||||
"width": <image-width-in-chars>, // Optional
|
||||
"height": <image-height-in-chars> // Optional
|
||||
}
|
||||
}
|
||||
```
|
||||
* If you installed fastfetch via scoop or downloaded the binary directly from the GitHub Releases page:
|
||||
1. Convert your image manually to sixel format using [any online image conversion service](https://www.google.com/search?q=convert+image+to+sixel)
|
||||
2. In `config.jsonc`:
|
||||
```jsonc
|
||||
{
|
||||
"logo": {
|
||||
"type": "raw", // DO NOT USE "auto"
|
||||
"source": "C:/path/to/image.sixel",
|
||||
"width": <image-width-in-chars>, // Required
|
||||
"height": <image-height-in-chars> // Required
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Q: I want feature A / B / C. Will fastfetch support it?
|
||||
|
||||
Fastfetch is a system information tool. We only accept hardware or system-level software feature requests. For most personal uses, I recommend using the `Command` module to implement custom functionality, which can be used to grab output from a custom shell script:
|
||||
|
||||
@@ -62,11 +62,17 @@ end
|
||||
echo '
|
||||
import json, subprocess, sys
|
||||
|
||||
|
||||
def main():
|
||||
data: dict[str, list[dict]] = json.loads(subprocess.check_output(["fastfetch", "--help-raw"]))
|
||||
|
||||
for key in data:
|
||||
for flag in data[key]:
|
||||
if flag["long"] == "logo-color-[1-9]":
|
||||
for i in range(1, 10):
|
||||
print(f"""complete -c fastfetch -d "{flag["desc"]}" -l "logo-color-{i}" -x -a "(__fastfetch_complete_color)" """)
|
||||
continue
|
||||
|
||||
if flag.get("pseudo", False):
|
||||
continue
|
||||
|
||||
@@ -75,7 +81,7 @@ def main():
|
||||
command_prefix += f""" -o {flag["short"]}"""
|
||||
|
||||
if "arg" in flag:
|
||||
type: str = flag["arg"]["type"];
|
||||
type: str = flag["arg"]["type"]
|
||||
if type == "bool":
|
||||
print(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
|
||||
elif type == "color":
|
||||
@@ -98,6 +104,7 @@ def main():
|
||||
else:
|
||||
print(f"{command_prefix} -f")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
|
||||
Vendored
+48
@@ -1,3 +1,51 @@
|
||||
fastfetch (2.46.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.46.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 20 Jun 2025 15:01:21 +0800
|
||||
|
||||
fastfetch (2.45.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.45.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 05 Jun 2025 10:56:38 +0800
|
||||
|
||||
fastfetch (2.44.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.44.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 26 May 2025 14:59:01 +0800
|
||||
|
||||
fastfetch (2.43.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.43.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 14 May 2025 09:49:50 +0800
|
||||
|
||||
fastfetch (2.42.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.42.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 30 Apr 2025 14:08:57 +0800
|
||||
|
||||
fastfetch (2.41.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.41.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 16 Apr 2025 13:42:58 +0800
|
||||
|
||||
fastfetch (2.40.4) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.4
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 10 Apr 2025 15:38:21 +0800
|
||||
|
||||
fastfetch (2.40.3) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.3
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 07 Apr 2025 09:29:27 +0800
|
||||
|
||||
fastfetch (2.40.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.0
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
fastfetch_2.40.0_source.buildinfo universe/utils optional
|
||||
fastfetch_2.46.0_source.buildinfo universe/utils optional
|
||||
|
||||
+18
-3
@@ -115,7 +115,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"biosFormat": {
|
||||
"description": "Output format of the module `Bios`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
|
||||
"description": "Output format of the module `BIOS`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
|
||||
"type": "string"
|
||||
},
|
||||
"bluetoothFormat": {
|
||||
@@ -279,7 +279,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}: Number of scoop packages\n 21. {choco}: Number of choco packages\n 22. {pkgtool}: Number of pkgtool packages\n 23. {paludis}: Number of paludis packages\n 24. {winget}: Number of winget packages\n 25. {opkg}: Number of opkg packages\n 26. {am-system}: Number of am-system packages\n 27. {sorcery}: Number of sorcery packages\n 28. {lpkg}: Number of lpkg packages\n 29. {lpkgbuild}: Number of lpkgbuild packages\n 30. {guix-system}: Number of guix-system packages\n 31. {guix-user}: Number of guix-user packages\n 32. {guix-home}: Number of guix-home packages\n 33. {linglong}: Number of linglong packages\n 34. {pacstall}: Number of pacstall packages\n 35. {mport}: Number of mport packages\n 36. {qi}: Number of qi 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. {nix-all}: Total number of all nix packages\n 43. {flatpak-all}: Total number of all flatpak app packages\n 44. {brew-all}: Total number of all brew packages\n 45. {guix-all}: Total number of all guix packages\n 46. {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}: Number of scoop packages\n 21. {choco}: Number of choco packages\n 22. {pkgtool}: Number of pkgtool packages\n 23. {paludis}: Number of paludis packages\n 24. {winget}: Number of winget packages\n 25. {opkg}: Number of opkg packages\n 26. {am-system}: Number of am-system packages\n 27. {sorcery}: Number of sorcery packages\n 28. {lpkg}: Number of lpkg packages\n 29. {lpkgbuild}: Number of lpkgbuild packages\n 30. {guix-system}: Number of guix-system packages\n 31. {guix-user}: Number of guix-user packages\n 32. {guix-home}: Number of guix-home packages\n 33. {linglong}: Number of linglong packages\n 34. {pacstall}: Number of pacstall packages\n 35. {mport}: Number of mport packages\n 36. {qi}: Number of qi 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",
|
||||
"type": "string"
|
||||
},
|
||||
"physicaldiskFormat": {
|
||||
@@ -339,7 +339,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)",
|
||||
"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",
|
||||
"type": "string"
|
||||
},
|
||||
"themeFormat": {
|
||||
@@ -429,6 +429,7 @@
|
||||
"file-raw",
|
||||
"data",
|
||||
"data-raw",
|
||||
"command-raw",
|
||||
"sixel",
|
||||
"kitty",
|
||||
"kitty-direct",
|
||||
@@ -1754,6 +1755,14 @@
|
||||
"type": "string",
|
||||
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options"
|
||||
},
|
||||
"hideFolders": {
|
||||
"type": "string",
|
||||
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output\nDefault: /efi:/boot:/boot/efi"
|
||||
},
|
||||
"hideFS": {
|
||||
"type": "string",
|
||||
"description": "A colon separated file systems to hide from the disk output"
|
||||
},
|
||||
"showExternal": {
|
||||
"type": "boolean",
|
||||
"description": "Set if external volume should be printed",
|
||||
@@ -2053,6 +2062,7 @@
|
||||
"enum": [
|
||||
"integrated",
|
||||
"discrete",
|
||||
"unknown",
|
||||
"none"
|
||||
],
|
||||
"default": "none"
|
||||
@@ -2992,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"
|
||||
},
|
||||
|
||||
+4
-1
@@ -52,7 +52,10 @@
|
||||
},
|
||||
"memory",
|
||||
"physicalmemory",
|
||||
"swap",
|
||||
{
|
||||
"type": "swap",
|
||||
"separate": true
|
||||
},
|
||||
"disk",
|
||||
"btrfs",
|
||||
"zpool",
|
||||
|
||||
+4
-1
@@ -54,7 +54,10 @@
|
||||
},
|
||||
"memory",
|
||||
"physicalmemory",
|
||||
"swap",
|
||||
{
|
||||
"type": "swap",
|
||||
"separate": true
|
||||
},
|
||||
"disk",
|
||||
"btrfs",
|
||||
"zpool",
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/ibireme/yyjson",
|
||||
"license": "MIT ( embed in source )",
|
||||
"version": "0.10.0",
|
||||
"version": "0.11.1",
|
||||
"author": "ibireme"
|
||||
}
|
||||
|
||||
Vendored
+2508
-1264
File diff suppressed because it is too large
Load Diff
Vendored
+800
-570
File diff suppressed because it is too large
Load Diff
@@ -134,7 +134,7 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/init.h"
|
||||
#include "common/parsing.h"
|
||||
#include "common/thread.h"
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
@@ -104,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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
void ffInitInstance(void);
|
||||
void ffStart(void);
|
||||
void ffFinish(void);
|
||||
void ffDestroyInstance(void);
|
||||
void ffListFeatures(void);
|
||||
+1
-2
@@ -19,8 +19,7 @@
|
||||
#define FF_INVALID_FD (-1)
|
||||
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
|
||||
// one safe way to read correct data is reading the whole file in a single read syscall
|
||||
// 8192 comes from procps-ng: https://gitlab.com/procps-ng/procps/-/blob/master/library/meminfo.c?ref_type=heads#L39
|
||||
#define PROC_FILE_BUFFSIZ 8192
|
||||
#define PROC_FILE_BUFFSIZ (32 * 1024)
|
||||
#endif
|
||||
|
||||
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -147,6 +147,14 @@ ssize_t ffReadFileDataRelative(HANDLE dfd, const char* fileName, size_t dataSize
|
||||
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
{
|
||||
if (in[0] == '~') {
|
||||
if ((in[1] == '/' || in[1] == '\\' || in[1] == '\0') && !ffStrContainsC(in, '%')) {
|
||||
ffStrbufSet(out, &instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(out, in + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD length = ExpandEnvironmentStringsA(in, NULL, 0);
|
||||
if (length <= 1) return false;
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -177,6 +177,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
if (ffCharIsEnglishAlphabet(value[0]))
|
||||
{
|
||||
FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET)
|
||||
else FF_APPEND_COLOR_CODE_COND(bold_, FF_COLOR_MODE_BOLD)
|
||||
else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD)
|
||||
else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM)
|
||||
else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC)
|
||||
@@ -212,6 +213,35 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
exit(479);
|
||||
}
|
||||
}
|
||||
else if (value[0] == '#')
|
||||
{
|
||||
// RGB color
|
||||
++value;
|
||||
char* pend = NULL;
|
||||
uint32_t rgb = (uint32_t) strtoul(value, &pend, 16);
|
||||
if (pend == value) {
|
||||
fprintf(stderr, "Error: invalid RGB color code found: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
if (pend - value > 6) {
|
||||
fprintf(stderr, "Error: RGB color code too long: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
else if (pend - value == 3) {
|
||||
rgb = ((rgb & 0xF00) >> 8) * 0x110000 +
|
||||
((rgb & 0x0F0) >> 4) * 0x001100 +
|
||||
((rgb & 0x00F) >> 0) * 0x000011;
|
||||
}
|
||||
else if (pend - value != 6) {
|
||||
fprintf(stderr, "Error: invalid RGB color code length: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
|
||||
uint32_t r = rgb >> 16, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
|
||||
ffStrbufAppendF(buffer, FF_COLOR_FG_RGB "%u;%u;%u", r, g, b);
|
||||
value = pend;
|
||||
continue;
|
||||
}
|
||||
ffStrbufAppendC(buffer, *value);
|
||||
++value;
|
||||
|
||||
|
||||
+15
-8
@@ -190,19 +190,26 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
}
|
||||
}
|
||||
|
||||
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result)
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
if(days == 0 && hours == 0 && minutes == 0)
|
||||
if(totalSeconds < 60)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u seconds", seconds);
|
||||
ffStrbufAppendF(result, "%u second", (unsigned) totalSeconds);
|
||||
if (totalSeconds != 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
return;
|
||||
}
|
||||
|
||||
if(seconds >= 30)
|
||||
{
|
||||
minutes++;
|
||||
seconds = 0;
|
||||
}
|
||||
uint32_t seconds = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
if (seconds >= 30)
|
||||
totalSeconds++;
|
||||
|
||||
uint32_t minutes = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
uint32_t hours = (uint32_t) (totalSeconds % 24);
|
||||
totalSeconds /= 24;
|
||||
uint32_t days = (uint32_t) totalSeconds;
|
||||
|
||||
if(days > 0)
|
||||
{
|
||||
|
||||
@@ -27,4 +27,4 @@ int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
|
||||
|
||||
void ffParseSize(uint64_t bytes, FFstrbuf* result);
|
||||
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result);
|
||||
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result);
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/printing.h"
|
||||
#include "logo/logo.h"
|
||||
#include "util/textModifier.h"
|
||||
|
||||
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType)
|
||||
@@ -99,7 +100,7 @@ void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleAr
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
}
|
||||
|
||||
static void printError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, va_list arguments)
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
|
||||
{
|
||||
if(!instance.config.display.showErrors)
|
||||
return;
|
||||
@@ -109,7 +110,10 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
if(!instance.config.display.pipe)
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
|
||||
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
vprintf(message, arguments);
|
||||
va_end(arguments);
|
||||
|
||||
if(!instance.config.display.pipe)
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
@@ -117,14 +121,6 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
printError(moduleName, moduleIndex, moduleArgs, printType, message, arguments);
|
||||
va_end(arguments);
|
||||
}
|
||||
|
||||
void ffPrintColor(const FFstrbuf* colorValue)
|
||||
{
|
||||
//If the color is not set, this would reset in \033[m, which resets everything.
|
||||
|
||||
@@ -279,8 +279,10 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
|
||||
psinfo_t proc;
|
||||
if (ffReadFileData(filePath, sizeof(proc), &proc) == sizeof(proc))
|
||||
{
|
||||
ffStrbufSetS(exe, proc.pr_psargs);
|
||||
ffStrbufSubstrBeforeFirstC(exe, ' ');
|
||||
const char* args = proc.pr_psargs;
|
||||
if (args[0] == '-') ++args;
|
||||
const char* end = strchr(args, ' ');
|
||||
ffStrbufSetNS(exe, end ? (uint32_t) (end - args) : (uint32_t) strlen(args), args);
|
||||
}
|
||||
|
||||
if (exePath)
|
||||
|
||||
@@ -130,7 +130,11 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_IO_PENDING:
|
||||
if (!timeout || WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
|
||||
#if __aarch64__
|
||||
if (!GetOverlappedResultEx(hChildPipeRead, &overlapped, &nRead, timeout < 0 ? INFINITE : (DWORD) timeout, FALSE))
|
||||
#else
|
||||
// To support Windows 7
|
||||
if (timeout >= 0 && WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
|
||||
{
|
||||
CancelIo(hChildPipeRead);
|
||||
TerminateProcess(hProcess, 1);
|
||||
@@ -138,13 +142,18 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
}
|
||||
|
||||
if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE))
|
||||
#endif
|
||||
{
|
||||
if (GetLastError() == ERROR_BROKEN_PIPE)
|
||||
return NULL;
|
||||
|
||||
CancelIo(hChildPipeRead);
|
||||
TerminateProcess(hProcess, 1);
|
||||
return "GetOverlappedResult(hChildPipeRead) failed";
|
||||
return "GetOverlappedResult"
|
||||
#if __aarch64__
|
||||
"Ex"
|
||||
#endif
|
||||
"(hChildPipeRead) failed";
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+20
-3
@@ -840,6 +840,22 @@
|
||||
"default": "Auto detection using mount-points"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-hide-folders",
|
||||
"desc": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output",
|
||||
"arg": {
|
||||
"type": "path",
|
||||
"default": "/efi:/boot:/boot/efi"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-hide-fs",
|
||||
"desc": "A colon separated list of file systems to hide from the disk output",
|
||||
"arg": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-regular",
|
||||
"desc": "Specify whether regular volumes should be displayed",
|
||||
@@ -1128,23 +1144,24 @@
|
||||
"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"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "gpu-hide-type",
|
||||
"desc": "Specify which types of GPUs should not be displayed",
|
||||
"desc": "Specify which types of GPUs should not be displayed (default: all GPUs are shown, regardless of recognition)",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"integrated": "Hide integrated GPUs",
|
||||
"discrete": "Hide discrete GPUs",
|
||||
"unknown": "Hide unknown (unrecognized) GPUs",
|
||||
"none": "Do not hide any GPUs"
|
||||
},
|
||||
"default": "none"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#elif __sun
|
||||
#include <libdevinfo.h>
|
||||
#include <sys/sunddi.h>
|
||||
#endif
|
||||
|
||||
typedef struct FFSmbiosBios
|
||||
@@ -59,6 +63,7 @@ typedef struct FFSmbiosBios
|
||||
static_assert(offsetof(FFSmbiosBios, ExtendedBiosRomSize) == 0x18,
|
||||
"FFSmbiosBios: Wrong struct alignment");
|
||||
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
@@ -94,6 +99,17 @@ const char* ffDetectBios(FFBiosResult* bios)
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
#elif __sun
|
||||
di_node_t rootNode = di_init("/", DINFOPROP);
|
||||
if (rootNode != DI_NODE_NIL)
|
||||
{
|
||||
char* efiVersion = NULL;
|
||||
if (di_prop_lookup_strings(DDI_DEV_T_ANY, rootNode, "efi-version", &efiVersion) > 0)
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
else
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
}
|
||||
di_fini(rootNode);
|
||||
#elif __HAIKU__ || __OpenBSD__
|
||||
// Currently SMBIOS detection is supported in legancy BIOS only
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
static int enumDev(FF_MAYBE_UNUSED int sockfd, struct bt_devinfo const* dev, FFlist* devices)
|
||||
{
|
||||
FFBluetoothResult* device = ffListAdd(devices);
|
||||
ffStrbufInitS(&device->name, bt_devremote_name_gen(dev->devname, &dev->bdaddr));
|
||||
ffStrbufInitS(&device->name,
|
||||
#if __FreeBSD__
|
||||
bt_devremote_name_gen(dev->devname, &dev->bdaddr)
|
||||
#else
|
||||
dev->devname
|
||||
#endif
|
||||
);
|
||||
ffStrbufInitS(&device->address, bt_ntoa(&dev->bdaddr, NULL));
|
||||
ffStrbufUpperCase(&device->address);
|
||||
ffStrbufInit(&device->type);
|
||||
|
||||
@@ -232,7 +232,7 @@ static uint32_t connectedDevices(void)
|
||||
|
||||
#endif
|
||||
|
||||
const char* ffDetectBluetooth(FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
#ifdef FF_HAVE_DBUS
|
||||
int32_t connectedCount = -1;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#if FF_HAVE_LINUX_VIDEODEV2
|
||||
#include <linux/videodev2.h>
|
||||
#elif __has_include(<sys/videoio.h>) // OpenBSD
|
||||
#include <sys/videoio.h>
|
||||
#define FF_HAVE_LINUX_VIDEODEV2 1
|
||||
#endif
|
||||
|
||||
const char* ffDetectCamera(FFlist* result)
|
||||
@@ -17,9 +20,15 @@ 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)
|
||||
break;
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
if (errno == ENXIO)
|
||||
continue;
|
||||
return "Failed to open /dev/videoN";
|
||||
}
|
||||
|
||||
struct v4l2_capability cap = {};
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
||||
|
||||
@@ -106,9 +106,14 @@ static const char* armPartId2name(uint32_t partId)
|
||||
case 0xd80: return "Cortex-A520";
|
||||
case 0xd81: return "Cortex-A720";
|
||||
case 0xd82: return "Cortex-X4";
|
||||
case 0xd83: return "Neoverse-V3AE";
|
||||
case 0xd84: return "Neoverse-V3";
|
||||
case 0xd85: return "Cortex-X925";
|
||||
case 0xd87: return "Cortex-A725";
|
||||
case 0xd88: return "Cortex-A520AE";
|
||||
case 0xd89: return "Cortex-A720AE";
|
||||
case 0xd8e: return "Neoverse-N3";
|
||||
case 0xd8f: return "Cortex-A320";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
@@ -314,6 +319,7 @@ static const char* fujitsuPartId2name(uint32_t partId)
|
||||
switch (partId)
|
||||
{
|
||||
case 0x001: return "A64FX";
|
||||
case 0x003: return "MONAKA";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+36
-23
@@ -1,5 +1,6 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#if __has_include(<sys/cpuset.h>)
|
||||
@@ -34,36 +35,30 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
if (ffSysctlGetString("hw.model", &cpu->name) != NULL)
|
||||
return "sysctlbyname(hw.model) failed";
|
||||
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
|
||||
cpu->coresLogical = cpu->coresPhysical;
|
||||
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("kern.smp.cores", 0);
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt("kern.smp.cpus", cpu->coresLogical);
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
if (ffSysctlGetString("kern.sched.topology_spec", &buffer) == NULL && buffer.length > 0)
|
||||
{
|
||||
// <groups>
|
||||
// <group level="1" cache-level="3">
|
||||
// <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
|
||||
// <children>
|
||||
// <group level="2" cache-level="2">
|
||||
// <cpu count="2" mask="3,0,0,0">0, 1</cpu>
|
||||
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
|
||||
// </group>
|
||||
// <group level="2" cache-level="2">
|
||||
// <cpu count="2" mask="c,0,0,0">2, 3</cpu>
|
||||
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
|
||||
// </group>
|
||||
// </children>
|
||||
// </group>
|
||||
// <group level="1" cache-level="3">
|
||||
// <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
|
||||
// <children>
|
||||
// <group level="2" cache-level="2">
|
||||
// <cpu count="2" mask="3,0,0,0">0, 1</cpu>
|
||||
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
|
||||
// </group>
|
||||
// <group level="2" cache-level="2">
|
||||
// <cpu count="2" mask="c,0,0,0">2, 3</cpu>
|
||||
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
|
||||
// </group>
|
||||
// </children>
|
||||
// </group>
|
||||
// </groups>
|
||||
uint32_t i = 0;
|
||||
while (true)
|
||||
{
|
||||
i = ffStrbufNextIndexS(&buffer, i, "<flag name=\"THREAD\">THREAD group</flag>"); // Find physical core with hyper-threading enabled
|
||||
if (i >= buffer.length) break;
|
||||
cpu->coresPhysical--;
|
||||
i += (uint32_t) strlen("<flag name=\"THREAD\">THREAD group</flag>");
|
||||
}
|
||||
for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p)
|
||||
cpu->packages++;
|
||||
}
|
||||
|
||||
#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
|
||||
@@ -79,6 +74,24 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
|
||||
uint32_t clockrate = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
|
||||
if (clockrate > cpu->frequencyBase) cpu->frequencyBase = clockrate;
|
||||
|
||||
for (uint16_t i = 0; i < cpu->coresLogical; ++i)
|
||||
{
|
||||
ffStrbufClear(&buffer);
|
||||
char key[32];
|
||||
snprintf(key, sizeof(key), "dev.cpu.%u.freq_levels", i);
|
||||
if (ffSysctlGetString(key, &buffer) == NULL)
|
||||
{
|
||||
if (buffer.length == 0) continue;
|
||||
|
||||
// MHz/Watts pairs like: 2501/32000 2187/27125 2000/24000
|
||||
uint32_t fmax = (uint32_t) strtoul(buffer.chars, NULL, 10);
|
||||
if (cpu->frequencyMax < fmax) cpu->frequencyMax = fmax;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
|
||||
if (options->temp)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define FF_CPUINFO_PATH "/proc/cpuinfo"
|
||||
|
||||
@@ -432,11 +433,11 @@ FF_MAYBE_UNUSED static uint16_t getPackageCount(FFstrbuf* cpuinfo)
|
||||
{
|
||||
p += strlen("\nphysical id\t:");
|
||||
char* pend;
|
||||
unsigned long id = strtoul(p, &pend, 10);
|
||||
unsigned long long id = strtoul(p, &pend, 10);
|
||||
if (__builtin_expect(id > 64, false)) // Do 129-socket boards exist?
|
||||
high |= 1 << (id - 64);
|
||||
high |= 1ULL << (id - 64);
|
||||
else
|
||||
low |= 1 << id;
|
||||
low |= 1ULL << id;
|
||||
p = pend;
|
||||
}
|
||||
|
||||
@@ -458,9 +459,7 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
|
||||
cpu->coresOnline = (uint16_t) get_nprocs();
|
||||
cpu->packages = getPackageCount(&cpuinfo);
|
||||
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, 0); // physical cores in single package
|
||||
if (cpu->coresPhysical == 0)
|
||||
cpu->coresPhysical = cpu->coresLogical;
|
||||
else if (cpu->packages > 1)
|
||||
if (cpu->coresPhysical > 0 && cpu->packages > 1)
|
||||
cpu->coresPhysical *= cpu->packages;
|
||||
|
||||
// Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252
|
||||
@@ -473,6 +472,82 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
|
||||
|
||||
#else
|
||||
|
||||
static const char* detectPhysicalCores(FFCPUResult* cpu)
|
||||
{
|
||||
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);
|
||||
if (!dir) return "fdopendir(dfd) failed";
|
||||
|
||||
uint64_t pkgLow = 0, pkgHigh = 0;
|
||||
|
||||
struct dirent* entry;
|
||||
FF_LIST_AUTO_DESTROY cpuList = ffListCreate(sizeof(uint32_t));
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
if (entry->d_type != DT_DIR || !ffStrStartsWith(entry->d_name, "cpu") || !ffCharIsDigit(entry->d_name[strlen("cpu")]))
|
||||
continue;
|
||||
|
||||
FF_AUTO_CLOSE_FD int cpuxfd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_DIRECTORY);
|
||||
if (cpuxfd < 0)
|
||||
continue;
|
||||
|
||||
char buf[128];
|
||||
|
||||
// Check if the directory contains a file named "topology/physical_package_id"
|
||||
// that lists the physical package id of the CPU.
|
||||
|
||||
ssize_t len = ffReadFileDataRelative(cpuxfd, "topology/physical_package_id", sizeof(buf) - 1, buf);
|
||||
if (len > 0)
|
||||
{
|
||||
buf[len] = '\0';
|
||||
unsigned long long id = strtoul(buf, NULL, 10);
|
||||
if (__builtin_expect(id > 64, false)) // Do 129-socket boards exist?
|
||||
pkgHigh |= 1ULL << (id - 64);
|
||||
else
|
||||
pkgLow |= 1ULL << id;
|
||||
}
|
||||
|
||||
// Check if the directory contains a file named "topology/core_cpus_list"
|
||||
// that lists the physical cores in the package.
|
||||
|
||||
len = ffReadFileDataRelative(cpuxfd, "topology/core_cpus_list", sizeof(buf) - 1, buf);
|
||||
if (len > 0)
|
||||
{
|
||||
buf[len] = '\0'; // low-high or low
|
||||
|
||||
for (const char* p = buf; *p;)
|
||||
{
|
||||
char* pend;
|
||||
uint32_t coreId = (uint32_t) strtoul(p, &pend, 10);
|
||||
if (pend == p) break;
|
||||
|
||||
bool found = false;
|
||||
FF_LIST_FOR_EACH(uint32_t, id, cpuList)
|
||||
{
|
||||
if (*id == coreId)
|
||||
{
|
||||
// This core is already counted
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
*(uint32_t*) ffListAdd(&cpuList) = coreId;
|
||||
|
||||
p = strchr(pend, ',');
|
||||
if (!p) break;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cpu->coresPhysical = (uint16_t) cpuList.length;
|
||||
cpu->packages = (uint16_t) (__builtin_popcountll(pkgLow) + __builtin_popcountll(pkgHigh));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_MAYBE_UNUSED static void parseIsa(FFstrbuf* cpuIsa)
|
||||
{
|
||||
// Always use the last part of the ISA string. Ref: #590 #1204
|
||||
@@ -601,7 +676,7 @@ FF_MAYBE_UNUSED static uint16_t getLoongarchPropCount(FFstrbuf* cpuinfo, const c
|
||||
|
||||
FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
cpu->coresPhysical = cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
||||
cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
||||
cpu->coresOnline = (uint16_t) get_nprocs();
|
||||
|
||||
#if __ANDROID__
|
||||
@@ -663,6 +738,9 @@ FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options,
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cpu->coresPhysical == 0)
|
||||
detectPhysicalCores(cpu);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -67,6 +68,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
|
||||
uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
|
||||
if (freq == 0) freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
|
||||
if (freq == 0) freq = (uint32_t) ffSysctlGetInt("machdep.dmi.processor-frequency", 0);
|
||||
if (freq > cpu->frequencyBase) cpu->frequencyBase = freq;
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
|
||||
@@ -1,10 +1,53 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sensors.h>
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
static const char* detectCPUTemp(FFCPUResult* cpu)
|
||||
{
|
||||
int mib[5] = {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0};
|
||||
|
||||
for (mib[2] = 0; mib[2] < 1024; mib[2]++)
|
||||
{
|
||||
struct sensordev sensordev;
|
||||
size_t sdlen = sizeof(struct sensordev);
|
||||
if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
if (errno == ENXIO)
|
||||
continue;
|
||||
return "sysctl(sensordev) failed";
|
||||
}
|
||||
|
||||
if (!ffStrStartsWith(sensordev.xname, "cpu"))
|
||||
continue;
|
||||
|
||||
for (mib[4] = 0; mib[4] < sensordev.maxnumt[SENSOR_TEMP]; mib[4]++)
|
||||
{
|
||||
struct sensor sensor;
|
||||
size_t slen = sizeof(struct sensor);
|
||||
if (sysctl(mib, 5, &sensor, &slen, NULL, 0) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return "sysctl(sensor) failed";
|
||||
continue;
|
||||
}
|
||||
if (sensor.flags & SENSOR_FINVALID)
|
||||
continue;
|
||||
|
||||
cpu->temperature = (double)(sensor.value - 273150000) / 1E6;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "No sensor for CPU temp found";
|
||||
}
|
||||
|
||||
const char *ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
if (ffSysctlGetString(CTL_HW, HW_MODEL, &cpu->name))
|
||||
return "sysctl(hw.model) failed";
|
||||
@@ -19,13 +62,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
if (cpuspeed > cpu->frequencyBase) cpu->frequencyBase = cpuspeed;
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
if (options->temp)
|
||||
{
|
||||
struct sensor sensors;
|
||||
size_t size = sizeof(sensors);
|
||||
if (sysctl((int[]) {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0}, 5, &sensors, &size, NULL, 0) == 0)
|
||||
cpu->temperature = (double) (sensors.value - 273150000) / 1E6;
|
||||
}
|
||||
if (options->temp) detectCPUTemp(cpu);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,60 @@
|
||||
#include "cpu.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include <kstat.h>
|
||||
|
||||
static const char* detectCPUTempByKstat(kstat_ctl_t* kc, FFCPUResult* cpu)
|
||||
{
|
||||
const char* possibleModules[] = {"temperature", "cpu_temp", "acpi_thermal", NULL};
|
||||
|
||||
for (int i = 0; possibleModules[i] != NULL; i++) {
|
||||
kstat_t* ks = kstat_lookup(kc, possibleModules[i], -1, NULL);
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0) {
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "temperature");
|
||||
if (kn) {
|
||||
switch (kn->data_type) {
|
||||
case KSTAT_DATA_INT32:
|
||||
cpu->temperature = (float)kn->value.i32;
|
||||
return NULL;
|
||||
case KSTAT_DATA_UINT32:
|
||||
cpu->temperature = (float)kn->value.ui32;
|
||||
return NULL;
|
||||
case KSTAT_DATA_FLOAT:
|
||||
cpu->temperature = kn->value.f;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "Failed to find CPU temperature using kstat";
|
||||
}
|
||||
|
||||
static const char* detectCPUTempByIpmiTool(FFCPUResult* cpu)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]){
|
||||
"ipmitool",
|
||||
"-c",
|
||||
"sdr",
|
||||
"list",
|
||||
NULL
|
||||
});
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
while (ffStrbufGetline(&line, &len, &buffer))
|
||||
{
|
||||
if (sscanf(line, "CPU%*d Temp,%lf,degrees C,ok", &cpu->temperature) == 1)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "ipmitool sdr list failed to find CPU temperature";
|
||||
}
|
||||
|
||||
static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
{
|
||||
assert(pkc);
|
||||
@@ -8,7 +62,46 @@ static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
kstat_close(*pkc);
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
static inline uint16_t countTypeId(kstat_ctl_t* kc, const char* type)
|
||||
{
|
||||
uint64_t low = 0, high = 0;
|
||||
for (kstat_t* ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
|
||||
{
|
||||
if (ffStrStartsWith(ksp->ks_module, "cpu_info"))
|
||||
{
|
||||
if (kstat_read(kc, ksp, NULL) < 0)
|
||||
continue;
|
||||
|
||||
kstat_named_t* stat = kstat_data_lookup(ksp, type);
|
||||
if (!stat)
|
||||
continue;
|
||||
|
||||
uint32_t id = 0;
|
||||
switch (stat->data_type)
|
||||
{
|
||||
#ifdef _INT64_TYPE
|
||||
case KSTAT_DATA_INT64:
|
||||
case KSTAT_DATA_UINT64:
|
||||
id = (uint32_t) stat->value.ui64;
|
||||
break;
|
||||
#endif
|
||||
case KSTAT_DATA_INT32:
|
||||
case KSTAT_DATA_UINT32:
|
||||
id = stat->value.ui32;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (__builtin_expect(id > 64, false))
|
||||
high |= 1ULL << (id - 64);
|
||||
else
|
||||
low |= 1ULL << id;
|
||||
}
|
||||
}
|
||||
return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high));
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
__attribute__((__cleanup__(kstatFreeWrap))) kstat_ctl_t* kc = kstat_open();
|
||||
if (!kc)
|
||||
@@ -40,7 +133,16 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0)
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "ncpus");
|
||||
if (kn) cpu->coresLogical = cpu->coresPhysical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
if (kn) cpu->coresLogical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
}
|
||||
|
||||
cpu->packages = countTypeId(kc, "chip_id");
|
||||
cpu->coresPhysical = countTypeId(kc, "core_id");
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
if (detectCPUTempByKstat(kc, cpu) != NULL)
|
||||
detectCPUTempByIpmiTool(cpu);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -4,6 +4,120 @@
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "util/windows/perflib_.h"
|
||||
#include <wchar.h>
|
||||
|
||||
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery)
|
||||
{
|
||||
if (*phQuery != NULL)
|
||||
{
|
||||
PerfCloseQueryHandle(*phQuery);
|
||||
*phQuery = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char* detectThermalTemp(double* result)
|
||||
{
|
||||
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;
|
||||
|
||||
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
|
||||
return "PerfOpenQueryHandle() failed";
|
||||
|
||||
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
|
||||
return "PerfAddCounters() failed";
|
||||
|
||||
if (querySpec.Identifier.Status != ERROR_SUCCESS)
|
||||
return "PerfAddCounters() reports invalid identifier";
|
||||
|
||||
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
return "PerfQueryCounterData(NULL) failed";
|
||||
|
||||
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER)) // PERF_ERROR_RETURN, should not happen
|
||||
return "instance doesn't exist";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 7.5
|
||||
typedef struct FFSmbiosProcessorInfo
|
||||
{
|
||||
@@ -111,7 +225,7 @@ static const char* detectNCores(FFCPUResult* cpu)
|
||||
else if (ptr->Relationship == RelationProcessorCore)
|
||||
++cpu->coresPhysical;
|
||||
else if (ptr->Relationship == RelationProcessorPackage)
|
||||
cpu->packages++;
|
||||
++cpu->packages;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -165,8 +279,6 @@ static const char* detectCoreTypes(FFCPUResult* cpu)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* detectThermalTemp(double* current, double* critical);
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
detectNCores(cpu);
|
||||
@@ -182,7 +294,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
detectMaxSpeedBySmbios(cpu);
|
||||
|
||||
if(options->temp)
|
||||
detectThermalTemp(&cpu->temperature, NULL);
|
||||
detectThermalTemp(&cpu->temperature);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#include "util/windows/wmi.hpp"
|
||||
|
||||
extern "C"
|
||||
const char* detectThermalTemp(double* current, double* critical)
|
||||
{
|
||||
// Requires Administrator privileges
|
||||
// https://wutils.com/wmi/root/wmi/msacpi_thermalzonetemperature/#properties
|
||||
FFWmiQuery query(L"SELECT CurrentTemperature, CriticalTripPoint FROM MSAcpi_ThermalZoneTemperature WHERE Active = TRUE", nullptr, FFWmiNamespace::WMI);
|
||||
if(!query)
|
||||
return "Query WMI service failed";
|
||||
|
||||
if(FFWmiRecord record = query.next())
|
||||
{
|
||||
if (current)
|
||||
{
|
||||
if(auto vtCurrent = record.get(L"CurrentTemperature"))
|
||||
*current = vtCurrent.get<int32_t>() / 10 - 273.15; // In tenth of degrees Kelvin
|
||||
else
|
||||
*current = 0.0/0.0;
|
||||
}
|
||||
|
||||
if (critical)
|
||||
{
|
||||
if(auto vtCritical = record.get(L"CriticalTripPoint"))
|
||||
*critical = vtCritical.get<int32_t>() / 10 - 273.15; // In tenth of degrees Kelvin
|
||||
else
|
||||
*critical = 0.0/0.0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "No WMI result returned";
|
||||
}
|
||||
@@ -5,12 +5,14 @@
|
||||
#include <stdint.h>
|
||||
|
||||
static FFlist cpuTimes1;
|
||||
static uint64_t startTime;
|
||||
|
||||
void ffPrepareCPUUsage(void)
|
||||
{
|
||||
assert(cpuTimes1.elementSize == 0);
|
||||
ffListInit(&cpuTimes1, sizeof(FFCpuUsageInfo));
|
||||
ffGetCpuUsageInfo(&cpuTimes1);
|
||||
startTime = ffTimeGetNow();
|
||||
}
|
||||
|
||||
const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
|
||||
@@ -23,6 +25,12 @@ const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
|
||||
if(error) return error;
|
||||
ffTimeSleep(options->waitTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t elapsedTime = ffTimeGetNow() - startTime;
|
||||
if (elapsedTime < options->waitTime)
|
||||
ffTimeSleep(options->waitTime - (uint32_t)elapsedTime);
|
||||
}
|
||||
|
||||
if(cpuTimes1.length == 0) return "No CPU cores found";
|
||||
|
||||
@@ -57,5 +65,6 @@ retry:
|
||||
cpuTime1->inUseAll = cpuTime2->inUseAll;
|
||||
cpuTime1->totalAll = cpuTime2->totalAll;
|
||||
}
|
||||
startTime = ffTimeGetNow();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
for (uint32_t i = 0; i < coreCount; ++i)
|
||||
{
|
||||
uint64_t* cpTime = cpTimes[i];
|
||||
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS];
|
||||
uint64_t total = inUse + cpTime[CP_INTR] + cpTime[CP_IDLE];
|
||||
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS] + cpTime[CP_INTR];
|
||||
uint64_t total = inUse + cpTime[CP_IDLE];
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
|
||||
@@ -31,8 +31,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
if(sscanf(start, "cpu%*d%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%*[^\n]\n", &user, &nice, &system, &idle, &iowait, &irq, &softirq) == 7)
|
||||
{
|
||||
uint64_t inUse = user + nice + system;
|
||||
uint64_t total = inUse + idle + iowait + irq + softirq;
|
||||
uint64_t inUse = user + nice + system + irq + softirq;
|
||||
uint64_t total = inUse + idle + iowait;
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
|
||||
#include <ntstatus.h>
|
||||
#include <winternl.h>
|
||||
#include <windows.h>
|
||||
#include <wchar.h>
|
||||
#include "util/windows/perflib_.h"
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
static const char* getInfoByNqsi(FFlist* cpuTimes)
|
||||
{
|
||||
ULONG size = 0;
|
||||
if(NtQuerySystemInformation(SystemProcessorPerformanceInformation, NULL, 0, &size) != STATUS_INFO_LENGTH_MISMATCH)
|
||||
@@ -20,11 +23,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* coreInfo = pinfo + i;
|
||||
|
||||
// KernelTime includes idle time.
|
||||
LONGLONG dpcTime = coreInfo->Reserved1[0].QuadPart;
|
||||
LONGLONG interruptTime = coreInfo->Reserved1[1].QuadPart;
|
||||
// KernelTime includes IdleTime and DpcTime.
|
||||
coreInfo->KernelTime.QuadPart -= coreInfo->IdleTime.QuadPart;
|
||||
coreInfo->KernelTime.QuadPart += dpcTime + interruptTime;
|
||||
|
||||
uint64_t inUse = (uint64_t) (coreInfo->UserTime.QuadPart + coreInfo->KernelTime.QuadPart);
|
||||
uint64_t total = inUse + (uint64_t)coreInfo->IdleTime.QuadPart;
|
||||
@@ -38,3 +38,137 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* getInfoByPerflib(FFlist* cpuTimes)
|
||||
{
|
||||
static HANDLE hQuery = NULL;
|
||||
|
||||
if (hQuery == NULL)
|
||||
{
|
||||
struct FFPerfQuerySpec
|
||||
{
|
||||
PERF_COUNTER_IDENTIFIER Identifier;
|
||||
WCHAR Name[16];
|
||||
} querySpec = {
|
||||
.Identifier = {
|
||||
// Processor Information GUID
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{b4fc721a-0378-476f-89ba-a5a79f810b36}
|
||||
.CounterSetGuid = { 0xb4fc721a, 0x0378, 0x476f, {0x89, 0xba, 0xa5, 0xa7, 0x9f, 0x81, 0x0b, 0x36} },
|
||||
.Size = sizeof(querySpec),
|
||||
.CounterId = PERF_WILDCARD_COUNTER, // https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
|
||||
.InstanceId = PERF_WILDCARD_COUNTER,
|
||||
},
|
||||
.Name = PERF_WILDCARD_INSTANCE,
|
||||
};
|
||||
|
||||
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
|
||||
{
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfOpenQueryHandle() failed";
|
||||
}
|
||||
|
||||
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
|
||||
{
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfAddCounters() failed";
|
||||
}
|
||||
|
||||
if (querySpec.Identifier.Status != ERROR_SUCCESS)
|
||||
{
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfAddCounters() reports invalid identifier";
|
||||
}
|
||||
}
|
||||
|
||||
if (hQuery == INVALID_HANDLE_VALUE)
|
||||
return "Init hQuery failed";
|
||||
|
||||
DWORD dataSize = 0;
|
||||
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
return "PerfQueryCounterData(NULL) failed";
|
||||
|
||||
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER))
|
||||
return "instance doesn't exist";
|
||||
|
||||
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = (PERF_DATA_HEADER*)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_COUNTERSET)
|
||||
return "Invalid counter type";
|
||||
|
||||
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
|
||||
if (pMultiCounters->dwCounters == 0)
|
||||
return "No CPU counters found";
|
||||
|
||||
PERF_MULTI_INSTANCES* pMultiInstances = (PERF_MULTI_INSTANCES*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
|
||||
if (pMultiInstances->dwInstances == 0)
|
||||
return "No CPU instances found";
|
||||
|
||||
PERF_INSTANCE_HEADER* pInstanceHeader = (PERF_INSTANCE_HEADER*)(pMultiInstances + 1);
|
||||
for (DWORD iInstance = 0; iInstance < pMultiInstances->dwInstances; ++iInstance)
|
||||
{
|
||||
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
|
||||
|
||||
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
|
||||
|
||||
uint64_t processorUtility = UINT64_MAX, utilityBase = UINT64_MAX;
|
||||
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
|
||||
{
|
||||
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
|
||||
// https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
|
||||
switch (pCounterIds[iCounter]) {
|
||||
case 26: // % Processor Utility (#26, Type=PERF_AVERAGE_BULK)
|
||||
assert(pCounterData->dwDataSize == sizeof(uint64_t));
|
||||
processorUtility = *(uint64_t*)(pCounterData + 1);
|
||||
break;
|
||||
case 27: // % Utility Base (#27, Type=PERF_AVERAGE_BASE)
|
||||
assert(pCounterData->dwDataSize == sizeof(uint32_t));
|
||||
utilityBase = *(uint32_t*)(pCounterData + 1) * 100LLU;
|
||||
break;
|
||||
}
|
||||
|
||||
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
|
||||
}
|
||||
|
||||
if (wcschr(instanceName, L'_') == NULL /* ignore `_Total` */)
|
||||
{
|
||||
if (processorUtility == UINT64_MAX)
|
||||
return "Counter \"% Processor Utility\" are not supported";
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
.inUseAll = processorUtility,
|
||||
.totalAll = utilityBase,
|
||||
};
|
||||
}
|
||||
|
||||
pInstanceHeader = (PERF_INSTANCE_HEADER*)pCounterData;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
#if __aarch64__
|
||||
static uint8_t winver = 10; // Assume Windows 10 or later for WoA
|
||||
#else
|
||||
static uint8_t winver = 0;
|
||||
if (winver == 0)
|
||||
winver = (uint8_t) ffStrbufToUInt(&instance.state.platform.sysinfo.release, 1);
|
||||
#endif
|
||||
|
||||
if (winver >= 10)
|
||||
{
|
||||
if (getInfoByPerflib(cpuTimes) == NULL) return NULL;
|
||||
ffListClear(cpuTimes);
|
||||
winver = 1; // Fall back to NQSI
|
||||
}
|
||||
|
||||
return getInfoByNqsi(cpuTimes);
|
||||
}
|
||||
|
||||
@@ -10,18 +10,29 @@
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <paths.h>
|
||||
#ifndef _PATH_LOCALBASE
|
||||
#define _PATH_LOCALBASE "/usr/local"
|
||||
#endif
|
||||
#elif __OpenBSD__
|
||||
#define _PATH_LOCALBASE "/usr/local"
|
||||
#elif __NetBSD__
|
||||
#define _PATH_LOCALBASE "/usr/pkg"
|
||||
#endif
|
||||
|
||||
static void getKDE(FFstrbuf* result, FFDEOptions* options)
|
||||
{
|
||||
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", 1, (FFpropquery[]) {
|
||||
{"X-KDE-PluginInfo-Version =", result}
|
||||
});
|
||||
#ifdef _PATH_LOCALBASE
|
||||
ffParsePropFile(_PATH_LOCALBASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
{
|
||||
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", 1, (FFpropquery[]) {
|
||||
{"X-KDE-PluginInfo-Version =", result}
|
||||
});
|
||||
}
|
||||
ffParsePropFile(_PATH_LOCALBASE "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
#else
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
#endif
|
||||
|
||||
if(result->length == 0)
|
||||
ffParsePropFileData("xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "disk.h"
|
||||
|
||||
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
|
||||
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char separator = ';';
|
||||
@@ -11,12 +11,12 @@ bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
|
||||
uint32_t mountpointLength = (uint32_t) strlen(mountpoint);
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < options->folders.length)
|
||||
while(startIndex < folders->length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&options->folders, startIndex, separator);
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(folders, startIndex, separator);
|
||||
|
||||
uint32_t folderLength = colonIndex - startIndex;
|
||||
if (folderLength == mountpointLength && memcmp(options->folders.chars + startIndex, mountpoint, mountpointLength) == 0)
|
||||
if (folderLength == mountpointLength && memcmp(folders->chars + startIndex, mountpoint, mountpointLength) == 0)
|
||||
return true;
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
|
||||
@@ -28,4 +28,4 @@ typedef struct FFDisk
|
||||
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
|
||||
|
||||
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
|
||||
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint);
|
||||
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint);
|
||||
|
||||
@@ -52,7 +52,7 @@ static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
|
||||
static const char* detectFsLabel(FF_MAYBE_UNUSED struct statfs* fs, FF_MAYBE_UNUSED FFDisk* disk)
|
||||
{
|
||||
return "Fastfetch was compiled without libgeom support";
|
||||
}
|
||||
@@ -145,10 +145,10 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
{
|
||||
if(__builtin_expect(options->folders.length > 0, 0))
|
||||
{
|
||||
if(!ffDiskMatchMountpoint(options, fs->f_mntonname))
|
||||
if(!ffDiskMatchMountpoint(&options->folders, fs->f_mntonname))
|
||||
continue;
|
||||
}
|
||||
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs"))
|
||||
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs"))
|
||||
continue;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
@@ -159,13 +159,13 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
FFDisk* disk = ffListAdd(disks);
|
||||
|
||||
disk->bytesTotal = (uint64_t)fs->f_blocks * fs->f_bsize;
|
||||
disk->bytesFree = (uint64_t)fs->f_bfree * fs->f_bsize;
|
||||
disk->bytesAvailable = (uint64_t)fs->f_bavail * fs->f_bsize;
|
||||
disk->bytesTotal = (uint64_t)fs->f_blocks * (uint64_t)fs->f_bsize;
|
||||
disk->bytesFree = (uint64_t)fs->f_bfree * (uint64_t)fs->f_bsize;
|
||||
disk->bytesAvailable = (uint64_t)fs->f_bavail * (uint64_t)fs->f_bsize;
|
||||
disk->bytesUsed = 0; // To be filled in ./disk.c
|
||||
|
||||
disk->filesTotal = (uint32_t) fs->f_files;
|
||||
disk->filesUsed = (uint32_t) (fs->f_files - fs->f_ffree);
|
||||
disk->filesUsed = (uint32_t) fs->f_files - (uint32_t) fs->f_ffree;
|
||||
|
||||
ffStrbufInitS(&disk->mountFrom, fs->f_mntfromname);
|
||||
ffStrbufInitS(&disk->mountpoint, fs->f_mntonname);
|
||||
|
||||
@@ -23,7 +23,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, path.Path()))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, path.Path()))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ static bool isPhysicalDevice(const struct mntent* device)
|
||||
if(ffStrEquals(device->mnt_type, "zfs"))
|
||||
return true;
|
||||
|
||||
//sshfs
|
||||
if(ffStrEquals(device->mnt_type, "fuse.sshfs"))
|
||||
return true;
|
||||
|
||||
//Pseudo filesystems don't have a device in /dev
|
||||
if(!ffStrStartsWith(device->mnt_fsname, "/dev/"))
|
||||
return false;
|
||||
@@ -220,7 +224,7 @@ static bool isRemovable(FFDisk* currentDisk)
|
||||
|
||||
static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mntent* device)
|
||||
{
|
||||
if(ffStrbufStartsWithS(¤tDisk->mountpoint, "/boot") || ffStrbufStartsWithS(¤tDisk->mountpoint, "/efi"))
|
||||
if(hasmntopt(device, "x-gvfs-hide") || hasmntopt(device, "hidden"))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
|
||||
else if(isSubvolume(disks, currentDisk))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
|
||||
@@ -240,9 +244,9 @@ static void detectStats(FFDisk* disk)
|
||||
if(statvfs(disk->mountpoint.chars, &fs) != 0)
|
||||
memset(&fs, 0, sizeof(fs)); //Set all values to 0, so our values get initialized to 0 too
|
||||
|
||||
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
|
||||
disk->bytesFree = fs.f_bfree * fs.f_frsize;
|
||||
disk->bytesAvailable = fs.f_bavail * fs.f_frsize;
|
||||
disk->bytesTotal = fs.f_blocks * (uint64_t) fs.f_frsize;
|
||||
disk->bytesFree = fs.f_bfree * (uint64_t) fs.f_frsize;
|
||||
disk->bytesAvailable = fs.f_bavail * (uint64_t) fs.f_frsize;
|
||||
disk->bytesUsed = 0; // To be filled in ./disk.c
|
||||
|
||||
if (fs.f_files >= fs.f_ffree)
|
||||
@@ -281,7 +285,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
{
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, device->mnt_dir))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
|
||||
continue;
|
||||
}
|
||||
else if(!isPhysicalDevice(device))
|
||||
|
||||
@@ -113,7 +113,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
{
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, device.mnt_mountp))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, device.mnt_mountp))
|
||||
continue;
|
||||
}
|
||||
else if(!isPhysicalDevice(&device))
|
||||
|
||||
@@ -47,7 +47,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
if (__builtin_expect((long) options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, buffer.chars))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, buffer.chars))
|
||||
continue;
|
||||
}
|
||||
else if(driveType == DRIVE_NO_ROOT_DIR)
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "util/apple/cf_helpers.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/edidHelper.h"
|
||||
#include "detection/os/os.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result)
|
||||
|
||||
#endif
|
||||
|
||||
const char* ffdsConnectDrm(FFDisplayServerResult* result)
|
||||
const char* ffdsConnectDrm(FF_MAYBE_UNUSED FFDisplayServerResult* result)
|
||||
{
|
||||
#ifdef FF_HAVE_DRM
|
||||
if (instance.config.general.dsForceDrm != FF_DS_FORCE_DRM_TYPE_SYSFS_ONLY)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -214,6 +214,26 @@ enum kde_output_device_v2_capability {
|
||||
* @since 9
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS = 0x80,
|
||||
/**
|
||||
* if this outputdevice supports the built-in color profile
|
||||
* @since 12
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR = 0x100,
|
||||
/**
|
||||
* if this outputdevice supports DDC/CI
|
||||
* @since 14
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI = 0x200,
|
||||
/**
|
||||
* if this outputdevice supports setting max bpc
|
||||
* @since 15
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR = 0x400,
|
||||
/**
|
||||
* if this outputdevice supports EDR
|
||||
* @since 16
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR = 0x800,
|
||||
};
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
@@ -235,6 +255,22 @@ enum kde_output_device_v2_capability {
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS_SINCE_VERSION 9
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR_SINCE_VERSION 12
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI_SINCE_VERSION 14
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR_SINCE_VERSION 16
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM
|
||||
@@ -316,6 +352,18 @@ enum kde_output_device_v2_color_power_tradeoff {
|
||||
};
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
|
||||
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
* when the compositor may make use of EDR
|
||||
*/
|
||||
enum kde_output_device_v2_edr_policy {
|
||||
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_NEVER = 0,
|
||||
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ALWAYS = 1,
|
||||
};
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM */
|
||||
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
* @struct kde_output_device_v2_listener
|
||||
@@ -658,6 +706,74 @@ struct kde_output_device_v2_listener {
|
||||
void (*dimming)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t multiplier);
|
||||
/**
|
||||
* source output for mirroring
|
||||
*
|
||||
*
|
||||
* @param source uuid of the source output
|
||||
* @since 13
|
||||
*/
|
||||
void (*replication_source)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
const char *source);
|
||||
/**
|
||||
* if DDC/CI should be used to control brightness etc.
|
||||
*
|
||||
* If the ddc_ci capability is present, this determines if
|
||||
* settings such as brightness, contrast or others should be set
|
||||
* using DDC/CI.
|
||||
* @param allowed 1 if allowed, 0 if disabled
|
||||
* @since 14
|
||||
*/
|
||||
void (*ddc_ci_allowed)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t allowed);
|
||||
/**
|
||||
* override max bpc
|
||||
*
|
||||
* This limits the amount of bits per color that are sent to the
|
||||
* display.
|
||||
* @param max_bpc 0 for the default / automatic
|
||||
* @since 15
|
||||
*/
|
||||
void (*max_bits_per_color)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t max_bpc);
|
||||
/**
|
||||
* range of max bits per color value
|
||||
*
|
||||
*
|
||||
* @param min_value the minimum supported by the driver
|
||||
* @param max_value the maximum supported by the driver
|
||||
* @since 15
|
||||
*/
|
||||
void (*max_bits_per_color_range)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t min_value,
|
||||
uint32_t max_value);
|
||||
/**
|
||||
* if and to what value automatic max bpc is limited
|
||||
*
|
||||
*
|
||||
* @param max_bpc_limit which value automatic bpc gets limited to. 0 if not limited
|
||||
* @since 15
|
||||
*/
|
||||
void (*automatic_max_bits_per_color_limit)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t max_bpc_limit);
|
||||
/**
|
||||
* when the compositor may apply EDR
|
||||
*
|
||||
* When EDR is enabled, the compositor may increase the backlight
|
||||
* beyond the user-specified setting, in order to present HDR
|
||||
* content on displays without native HDR support. This will
|
||||
* usually result in better visuals, but also increases battery
|
||||
* usage.
|
||||
* @since 16
|
||||
*/
|
||||
void (*edr_policy)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t policy);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -779,6 +895,30 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_DIMMING_SINCE_VERSION 11
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_REPLICATION_SOURCE_SINCE_VERSION 13
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_DDC_CI_ALLOWED_SINCE_VERSION 14
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_RANGE_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_AUTOMATIC_MAX_BITS_PER_COLOR_LIMIT_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_SINCE_VERSION 16
|
||||
|
||||
|
||||
/** @ingroup iface_kde_output_device_v2 */
|
||||
|
||||
@@ -60,12 +60,18 @@ static const struct wl_message kde_output_device_v2_events[] = {
|
||||
{ "brightness", "8u", kde_output_device_v2_types + 0 },
|
||||
{ "color_power_tradeoff", "10u", kde_output_device_v2_types + 0 },
|
||||
{ "dimming", "11u", kde_output_device_v2_types + 0 },
|
||||
{ "replication_source", "13s", kde_output_device_v2_types + 0 },
|
||||
{ "ddc_ci_allowed", "14u", kde_output_device_v2_types + 0 },
|
||||
{ "max_bits_per_color", "15u", kde_output_device_v2_types + 0 },
|
||||
{ "max_bits_per_color_range", "15uu", kde_output_device_v2_types + 0 },
|
||||
{ "automatic_max_bits_per_color_limit", "15u", kde_output_device_v2_types + 0 },
|
||||
{ "edr_policy", "16u", kde_output_device_v2_types + 0 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
|
||||
"kde_output_device_v2", 11,
|
||||
"kde_output_device_v2", 16,
|
||||
0, NULL,
|
||||
27, kde_output_device_v2_events,
|
||||
33, kde_output_device_v2_events,
|
||||
};
|
||||
|
||||
static const struct wl_message kde_output_device_mode_v2_events[] = {
|
||||
|
||||
@@ -137,6 +137,12 @@ static void waylandKdeHdrListener(void *data, FF_MAYBE_UNUSED struct kde_output_
|
||||
display->hdrEnabled = !!hdr_enabled;
|
||||
}
|
||||
|
||||
static void waylandKdeMaxBitsPerColorListener(void *data, FF_MAYBE_UNUSED struct kde_output_device_v2 *kde_output_device_v2, uint32_t max_bpc)
|
||||
{
|
||||
WaylandDisplay* display = data;
|
||||
display->bitDepth = (uint8_t) max_bpc;
|
||||
}
|
||||
|
||||
static struct kde_output_device_v2_listener outputListener = {
|
||||
.geometry = waylandKdeGeometryListener,
|
||||
.current_mode = waylandKdeCurrentModeListener,
|
||||
@@ -165,6 +171,12 @@ static struct kde_output_device_v2_listener outputListener = {
|
||||
.brightness = (void*) stubListener,
|
||||
.color_power_tradeoff = (void*) stubListener,
|
||||
.dimming = (void*) stubListener,
|
||||
.replication_source = (void*) stubListener,
|
||||
.ddc_ci_allowed = (void*) stubListener,
|
||||
.max_bits_per_color = (void*) waylandKdeMaxBitsPerColorListener,
|
||||
.max_bits_per_color_range = (void*) stubListener,
|
||||
.automatic_max_bits_per_color_limit = (void*) stubListener,
|
||||
.edr_policy = (void*) stubListener,
|
||||
};
|
||||
|
||||
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
|
||||
@@ -237,6 +249,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
|
||||
item->manufactureYear = display.myear;
|
||||
item->manufactureWeek = display.mweek;
|
||||
item->serial = display.serial;
|
||||
item->bitDepth = display.bitDepth;
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&display.description);
|
||||
|
||||
@@ -34,6 +34,7 @@ typedef struct WaylandData
|
||||
typedef struct WaylandDisplay
|
||||
{
|
||||
WaylandData* parent;
|
||||
void* internal;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t refreshRate;
|
||||
@@ -55,7 +56,7 @@ typedef struct WaylandDisplay
|
||||
uint16_t myear;
|
||||
uint16_t mweek;
|
||||
uint32_t serial;
|
||||
void* internal;
|
||||
uint8_t bitDepth;
|
||||
} WaylandDisplay;
|
||||
|
||||
inline static void stubListener(void* data, ...)
|
||||
|
||||
@@ -335,6 +335,7 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(xcbRandr, "dlopen libxcb-randr failed", "libxcb-randr" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connect)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connection_has_error)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_get_setup)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_setup_roots_iterator)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_screen_next)
|
||||
@@ -368,8 +369,11 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
|
||||
|
||||
data.connection = ffxcb_connect(NULL, NULL);
|
||||
if(data.connection == NULL)
|
||||
if(ffxcb_connection_has_error(data.connection) > 0)
|
||||
{
|
||||
ffxcb_disconnect(data.connection);
|
||||
return "xcb_connect() failed";
|
||||
}
|
||||
|
||||
|
||||
data.result = result;
|
||||
|
||||
@@ -20,9 +20,6 @@ extern int ADL2_Adapter_Graphic_Core_Info_Get(ADL_CONTEXT_HANDLE context, int iA
|
||||
// Function to retrieve memory information from the adapter. Version 2
|
||||
extern int ADL2_Adapter_MemoryInfo2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLMemoryInfo2* lpMemoryInfo2);
|
||||
|
||||
// This function retrieves the VRAM usage of given adapter.
|
||||
extern int ADL2_Adapter_VRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
|
||||
|
||||
// This function retrieves the Dedicated VRAM usage of given adapter.
|
||||
extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+12
-2
@@ -15,6 +15,11 @@ const char* FF_GPU_VENDOR_NAME_PARALLEL = "Parallel";
|
||||
const char* FF_GPU_VENDOR_NAME_MICROSOFT = "Microsoft";
|
||||
const char* FF_GPU_VENDOR_NAME_REDHAT = "RedHat";
|
||||
const char* FF_GPU_VENDOR_NAME_ORACLE = "Oracle";
|
||||
const char* FF_GPU_VENDOR_NAME_BROADCOM = "Broadcom";
|
||||
const char* FF_GPU_VENDOR_NAME_LOONGSON = "Loongson";
|
||||
const char* FF_GPU_VENDOR_NAME_JINGJIA_MICRO = "Jingjia Micro";
|
||||
const char* FF_GPU_VENDOR_NAME_HUAWEI = "Huawei";
|
||||
const char* FF_GPU_VENDOR_NAME_ZHAOXIN = "Zhaoxin";
|
||||
|
||||
const char* ffGPUGetVendorString(unsigned vendorId)
|
||||
{
|
||||
@@ -22,17 +27,22 @@ const char* ffGPUGetVendorString(unsigned vendorId)
|
||||
switch (vendorId)
|
||||
{
|
||||
case 0x106b: return FF_GPU_VENDOR_NAME_APPLE;
|
||||
case 0x1002: case 0x1022: return FF_GPU_VENDOR_NAME_AMD;
|
||||
case 0x1002: case 0x1022: case 0x1dd8: return FF_GPU_VENDOR_NAME_AMD;
|
||||
case 0x8086: case 0x8087: case 0x03e7: return FF_GPU_VENDOR_NAME_INTEL;
|
||||
case 0x0955: case 0x10de: case 0x12d2: return FF_GPU_VENDOR_NAME_NVIDIA;
|
||||
case 0x1ed5: return FF_GPU_VENDOR_NAME_MTHREADS;
|
||||
case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
|
||||
case 0x17cb: case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
|
||||
case 0x14c3: return FF_GPU_VENDOR_NAME_MTK;
|
||||
case 0x15ad: return FF_GPU_VENDOR_NAME_VMWARE;
|
||||
case 0x1af4: return FF_GPU_VENDOR_NAME_REDHAT;
|
||||
case 0x1ab8: return FF_GPU_VENDOR_NAME_PARALLEL;
|
||||
case 0x1414: return FF_GPU_VENDOR_NAME_MICROSOFT;
|
||||
case 0x108e: return FF_GPU_VENDOR_NAME_ORACLE;
|
||||
case 0x182f: case 0x14e4: return FF_GPU_VENDOR_NAME_BROADCOM;
|
||||
case 0x0014: return FF_GPU_VENDOR_NAME_LOONGSON;
|
||||
case 0x0731: return FF_GPU_VENDOR_NAME_JINGJIA_MICRO;
|
||||
case 0x19e5: return FF_GPU_VENDOR_NAME_HUAWEI;
|
||||
case 0x1d17: return FF_GPU_VENDOR_NAME_ZHAOXIN;
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -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)
|
||||
|
||||
@@ -49,7 +49,6 @@ struct FFAdlData {
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_Graphic_Core_Info_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_VRAMUsage_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Overdrive_Caps)
|
||||
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_CapabilitiesX2_Get)
|
||||
@@ -91,7 +90,6 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_Graphic_Core_Info_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_VRAMUsage_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive_Caps)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_CapabilitiesX2_Get)
|
||||
@@ -188,29 +186,12 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
|
||||
FF_DEBUG("ADL2_Adapter_DedicatedVRAMUsage_Get returned %s (%d), usage: %d MB",
|
||||
ffAdlStatusToString(status), status, vramUsage);
|
||||
|
||||
if (status == ADL_OK) {
|
||||
if (status == ADL_OK && vramUsage >= 0) {
|
||||
result.memory->used = (uint64_t) vramUsage * 1024 * 1024;
|
||||
FF_DEBUG("Dedicated VRAM usage: %llu bytes (%d MB)", result.memory->used, vramUsage);
|
||||
} else {
|
||||
FF_DEBUG("Failed to get dedicated VRAM usage");
|
||||
}
|
||||
|
||||
if (result.sharedMemory)
|
||||
{
|
||||
vramUsage = 0;
|
||||
status = adlData.ffADL2_Adapter_VRAMUsage_Get(adlData.apiHandle, device->iAdapterIndex, &vramUsage);
|
||||
FF_DEBUG("ADL2_Adapter_VRAMUsage_Get returned %s (%d), usage: %d MB",
|
||||
ffAdlStatusToString(status), status, vramUsage);
|
||||
|
||||
if (status == ADL_OK) {
|
||||
uint64_t totalUsage = (uint64_t) vramUsage * 1024 * 1024;
|
||||
result.sharedMemory->used = totalUsage - result.memory->used;
|
||||
FF_DEBUG("Total VRAM usage: %llu bytes, Shared VRAM usage: %llu bytes (%llu MB)",
|
||||
totalUsage, result.sharedMemory->used, result.sharedMemory->used / (1024 * 1024));
|
||||
} else {
|
||||
FF_DEBUG("Failed to get total VRAM usage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.memoryType)
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#import <Metal/MTLDevice.h>
|
||||
#import <IOKit/kext/KextManager.h>
|
||||
|
||||
#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 @@ const char* ffGpuDetectMetal(FFlist* gpus)
|
||||
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");
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#if __aarch64__ && FF_HAVE_DRM
|
||||
|
||||
#include <drm.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if __has_include(<drm/asahi_drm.h>)
|
||||
|
||||
#include <drm/asahi_drm.h>
|
||||
|
||||
#else
|
||||
|
||||
// https://github.com/AsahiLinux/linux/blob/asahi/include/uapi/drm/asahi_drm.h
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/* Copyright (C) The Asahi Linux Contributors */
|
||||
|
||||
#define DRM_ASAHI_UNSTABLE_UABI_VERSION 10011
|
||||
|
||||
#define DRM_ASAHI_GET_PARAMS 0x00
|
||||
#define DRM_ASAHI_MAX_CLUSTERS 32
|
||||
struct drm_asahi_params_global
|
||||
{
|
||||
__u32 unstable_uabi_version;
|
||||
__u32 pad0;
|
||||
|
||||
__u64 feat_compat;
|
||||
__u64 feat_incompat;
|
||||
|
||||
__u32 gpu_generation;
|
||||
__u32 gpu_variant;
|
||||
__u32 gpu_revision;
|
||||
__u32 chip_id;
|
||||
|
||||
__u32 num_dies;
|
||||
__u32 num_clusters_total;
|
||||
__u32 num_cores_per_cluster;
|
||||
__u32 num_frags_per_cluster;
|
||||
__u32 num_gps_per_cluster;
|
||||
__u32 num_cores_total_active;
|
||||
__u64 core_masks[DRM_ASAHI_MAX_CLUSTERS];
|
||||
|
||||
__u32 vm_page_size;
|
||||
__u32 pad1;
|
||||
__u64 vm_user_start;
|
||||
__u64 vm_user_end;
|
||||
__u64 vm_usc_start;
|
||||
__u64 vm_usc_end;
|
||||
__u64 vm_kernel_min_size;
|
||||
|
||||
__u32 max_syncs_per_submission;
|
||||
__u32 max_commands_per_submission;
|
||||
__u32 max_commands_in_flight;
|
||||
__u32 max_attachments;
|
||||
|
||||
__u32 timer_frequency_hz;
|
||||
__u32 min_frequency_khz;
|
||||
__u32 max_frequency_khz;
|
||||
__u32 max_power_mw;
|
||||
|
||||
__u32 result_render_size;
|
||||
__u32 result_compute_size;
|
||||
|
||||
__u32 firmware_version[4];
|
||||
};
|
||||
|
||||
struct drm_asahi_get_params
|
||||
{
|
||||
/** @extensions: Pointer to the first extension struct, if any */
|
||||
__u64 extensions;
|
||||
|
||||
/** @param: Parameter group to fetch (MBZ) */
|
||||
__u32 param_group;
|
||||
|
||||
/** @pad: MBZ */
|
||||
__u32 pad;
|
||||
|
||||
/** @value: User pointer to write parameter struct */
|
||||
__u64 pointer;
|
||||
|
||||
/** @value: Size of user buffer, max size supported on return */
|
||||
__u64 size;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DRM_IOCTL_ASAHI_GET_PARAMS = DRM_IOWR(DRM_COMMAND_BASE + DRM_ASAHI_GET_PARAMS, struct drm_asahi_get_params),
|
||||
};
|
||||
|
||||
#endif // __has_include
|
||||
|
||||
#endif // FF_HAVE_DRM
|
||||
+158
-44
@@ -1,6 +1,7 @@
|
||||
#include "gpu_driver_specific.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <sys/pciio.h>
|
||||
#include <fcntl.h>
|
||||
@@ -10,11 +11,145 @@
|
||||
#include <bus/pci/pcireg.h> // DragonFly
|
||||
#endif
|
||||
|
||||
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
static void fillGPUTypeGeneric(FFGPUResult* gpu)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY, 0);
|
||||
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 <xf86drm.h>
|
||||
|
||||
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 | 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,21 @@ 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 FF_HAVE_DRM
|
||||
if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO)
|
||||
{
|
||||
detectByDrm(options, gpus);
|
||||
if (gpus->length > 0) return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return detectByPci(options, gpus);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
#include "gpu.h"
|
||||
|
||||
#if FF_HAVE_DRM
|
||||
#include <drm.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#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 <radeon_drm.h>
|
||||
|
||||
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 <amdgpu.h>
|
||||
#include <amdgpu_drm.h>
|
||||
|
||||
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";
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
+100
-295
@@ -21,10 +21,16 @@
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "gpu_asahi.h"
|
||||
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
#if defined(FF_HAVE_DRM) && defined(__aarch64__)
|
||||
// https://github.com/alyssarosenzweig/linux/blob/agx-uapi-v7/include/uapi/drm/asahi_drm.h
|
||||
// Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
|
||||
#if __has_include(<drm/asahi_drm.h>)
|
||||
#include <drm/asahi_drm.h>
|
||||
#else
|
||||
#include "asahi_drm.h"
|
||||
#endif
|
||||
#define FF_HAVE_DRM_ASAHI 1
|
||||
#endif
|
||||
|
||||
static bool pciDetectDriver(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
|
||||
{
|
||||
@@ -99,73 +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)
|
||||
|
||||
#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
|
||||
{
|
||||
const char* error = drmFindRenderFromCard(drmKey, buffer);
|
||||
if (error) return error;
|
||||
#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
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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 (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
|
||||
}
|
||||
|
||||
@@ -189,46 +145,54 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pciDetectIntelSpecific(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer, const char* drmKey)
|
||||
static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer, const char* drmKey)
|
||||
{
|
||||
// Works for Intel GPUs
|
||||
// https://patchwork.kernel.org/project/intel-gfx/patch/1422039866-11572-3-git-send-email-ville.syrjala@linux.intel.com/
|
||||
@@ -238,40 +202,46 @@ static void pciDetectIntelSpecific(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf*
|
||||
|
||||
if (!drmKey) return;
|
||||
|
||||
if (ffStrbufEqualS(&gpu->driver, "xe"))
|
||||
const uint32_t pciDirLen = pciDir->length;
|
||||
|
||||
bool isXE = ffStrbufEqualS(&gpu->driver, "xe");
|
||||
if (isXE)
|
||||
ffStrbufAppendS(pciDir, "/tile0/gt0/freq0/max_freq");
|
||||
else
|
||||
ffStrbufAppendF(pciDir, "/drm/%s/gt_max_freq_mhz", drmKey);
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer))
|
||||
gpu->frequency = (uint32_t) ffStrbufToUInt(buffer, 0);
|
||||
}
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
|
||||
static inline int popcountBytes(uint8_t* bytes, uint32_t length)
|
||||
{
|
||||
int count = 0;
|
||||
while (length >= 8)
|
||||
if (options->temp)
|
||||
{
|
||||
count += __builtin_popcountll(*(uint64_t*) bytes);
|
||||
bytes += 8;
|
||||
length -= 8;
|
||||
ffStrbufAppendS(pciDir, "/hwmon/");
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pciDir->chars);
|
||||
if (dirp)
|
||||
{
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen + strlen("/hwmon/"));
|
||||
ffStrbufAppendS(pciDir, entry->d_name);
|
||||
// https://github.com/Syllo/nvtop/blob/73291884d926445e499d6b9b71cb7a9bdbc7c393/src/extract_gpuinfo_intel.c#L279-L281
|
||||
ffStrbufAppendS(pciDir, isXE ? "/temp2_input" : "/temp1_input");
|
||||
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer))
|
||||
{
|
||||
uint64_t value = ffStrbufToUInt(buffer, 0);
|
||||
if (value > 0)
|
||||
{
|
||||
gpu->temperature = (double) value / 1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
}
|
||||
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)
|
||||
@@ -279,120 +249,14 @@ static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey,
|
||||
#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 = {
|
||||
.extensions = 0,
|
||||
.query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
|
||||
.size = 0,
|
||||
.data = 0,
|
||||
};
|
||||
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";
|
||||
@@ -500,36 +364,19 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
|
||||
}
|
||||
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
|
||||
{
|
||||
pciDetectIntelSpecific(gpu, deviceDir, buffer, drmKey);
|
||||
pciDetectIntelSpecific(options, gpu, deviceDir, buffer, drmKey);
|
||||
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
|
||||
if (options->driverSpecific && drmKey)
|
||||
drmDetectIntelSpecific(gpu, drmKey, buffer);
|
||||
}
|
||||
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)
|
||||
@@ -556,60 +403,18 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
|
||||
|
||||
#if __aarch64__
|
||||
|
||||
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FFstrbuf* buffer, const char* drmKey)
|
||||
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FF_MAYBE_UNUSED FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
|
||||
{
|
||||
if (sscanf(name, "agx-t%lu", &gpu->deviceId) == 1)
|
||||
ffStrbufSetStatic(&gpu->name, ffCPUAppleCodeToName((uint32_t) gpu->deviceId));
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
|
||||
|
||||
#if FF_HAVE_DRM
|
||||
#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)
|
||||
{
|
||||
ffStrbufAppendF(&gpu->driver, " %u", paramsGlobal.unstable_uabi_version);
|
||||
|
||||
// FIXME: They will introduce ABI breaking changes. Always check the latest version
|
||||
// https://www.reddit.com/r/AsahiLinux/comments/1ei2qiv/comment/lgm0v5s/
|
||||
if (paramsGlobal.unstable_uabi_version == DRM_ASAHI_UNSTABLE_UABI_VERSION)
|
||||
{
|
||||
gpu->coreCount = (int) paramsGlobal.num_cores_total_active;
|
||||
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;
|
||||
|
||||
@@ -45,8 +45,10 @@ static const FFstrbuf* loadPciIds()
|
||||
if (pciids.length == 0)
|
||||
ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/local/share/hwdata/pci.ids", &pciids);
|
||||
}
|
||||
#elif __FreeBSD__ || __OpenBSD__ || __NetBSD__
|
||||
#elif __FreeBSD__ || __NetBSD__
|
||||
ffReadFileBuffer(_PATH_LOCALBASE "/share/pciids/pci.ids", &pciids);
|
||||
#elif __OpenBSD__
|
||||
ffReadFileBuffer(_PATH_LOCALBASE "/share/hwdata/pci.ids", &pciids);
|
||||
#elif __sun
|
||||
ffReadFileBuffer(FASTFETCH_TARGET_DIR_ROOT "/usr/share/hwdata/pci.ids", &pciids);
|
||||
#elif __HAIKU__
|
||||
|
||||
@@ -1,83 +1,57 @@
|
||||
#include "gpu.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
#include <libdevinfo.h>
|
||||
|
||||
static int walkDevTree(di_node_t node, FF_MAYBE_UNUSED di_minor_t minor, FFlist* gpus)
|
||||
{
|
||||
// SunOS requires root permission to query PCI device list, except `/usr/bin/scanpci`
|
||||
// Same behavior can be observed with `cp $(which scanpci) /tmp/ && /tmp/scanpci`
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
|
||||
"/usr/bin/scanpci",
|
||||
"-v",
|
||||
NULL,
|
||||
});
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!ffStrbufStartsWithS(&buffer, "\npci "))
|
||||
return "Invalid scanpci result";
|
||||
|
||||
// pci bus 0x0000 cardnum 0x00 function 0x00: vendor 0x1414 device 0x008e
|
||||
// Device unknown
|
||||
// CardVendor 0x0000 card 0x0000 (Card unknown)
|
||||
// STATUS 0x0010 COMMAND 0x0007
|
||||
// CLASS 0x03 0x02 0x00 REVISION 0x00
|
||||
// BIST 0x00 HEADER 0x00 LATENCY 0x00 CACHE 0x00
|
||||
// MAX_LAT 0x00 MIN_GNT 0x00 INT_PIN 0x00 INT_LINE 0x00
|
||||
|
||||
for (
|
||||
const char* pclass = strstr(buffer.chars, "\n CLASS 0x03 ");
|
||||
pclass;
|
||||
pclass = strstr(pclass, "\n CLASS 0x03 ")
|
||||
)
|
||||
int* vendorId;
|
||||
int* deviceId;
|
||||
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id", &vendorId) > 0
|
||||
&& di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id", &deviceId) > 0)
|
||||
{
|
||||
// find the start of device entry
|
||||
const char* pstart = memrchr(buffer.chars, '\n', (size_t) (pclass - buffer.chars));
|
||||
if (pstart == NULL)
|
||||
return "PCI info not found, invalid scanpci result";
|
||||
while (pstart[1] != 'p')
|
||||
{
|
||||
pstart = memrchr(buffer.chars, '\n', (size_t) (pstart - buffer.chars - 1));
|
||||
if (pstart == NULL)
|
||||
return "PCI info not found, invalid scanpci result";
|
||||
}
|
||||
++pstart;
|
||||
|
||||
uint32_t vendorId, deviceId;
|
||||
if (sscanf(pstart, "pci %*[^:]: vendor %x device %x",
|
||||
&vendorId, &deviceId) != 2)
|
||||
return "PCI info not found, invalid scanpci result";
|
||||
|
||||
pclass += strlen("\n CLASS 0x03 ");
|
||||
uint32_t subclass = (uint32_t) strtoul(pclass, NULL, 16);
|
||||
pclass += strlen("0x02 0x00 REVISION ");
|
||||
uint32_t revision = (uint32_t) strtoul(pclass, NULL, 16);
|
||||
|
||||
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
|
||||
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
|
||||
ffStrbufInit(&gpu->memoryType);
|
||||
ffStrbufInitS(&gpu->vendor, ffGPUGetVendorString((uint16_t) *vendorId));
|
||||
ffStrbufInit(&gpu->name);
|
||||
ffStrbufInit(&gpu->driver);
|
||||
ffStrbufInitStatic(&gpu->platformApi, "/usr/bin/scanpci");
|
||||
ffStrbufInitS(&gpu->driver, di_driver_name(node));
|
||||
ffStrbufInitStatic(&gpu->platformApi, "libdevinfo");
|
||||
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->deviceId = strtoul(di_bus_addr(node), NULL, 16);
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
|
||||
ffGPUQueryAmdGpuName((uint16_t) deviceId, (uint8_t) revision, gpu);
|
||||
{
|
||||
int* revId;
|
||||
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "revision-id", &revId) > 0)
|
||||
ffGPUQueryAmdGpuName((uint16_t) *deviceId, (uint8_t) *revId, gpu);
|
||||
}
|
||||
|
||||
if (gpu->name.length == 0)
|
||||
{
|
||||
ffGPUFillVendorAndName((uint8_t) subclass, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
|
||||
uint8_t subclass = 0; // assume VGA
|
||||
int* classCode;
|
||||
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "class-code", &classCode) > 0)
|
||||
subclass = (uint8_t) (*classCode & 0xFFFF);
|
||||
ffGPUFillVendorAndName(subclass, (uint16_t) *vendorId, (uint16_t) *deviceId, gpu);
|
||||
}
|
||||
}
|
||||
|
||||
return DI_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
di_node_t rootNode = di_init("/", DINFOCPYALL);
|
||||
if (rootNode == DI_NODE_NIL)
|
||||
return "di_init() failed";
|
||||
di_walk_minor(rootNode, DDI_NT_DISPLAY, DI_WALK_CLDFIRST, gpus, (void*) walkDevTree);
|
||||
di_fini(rootNode);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ const char* ffDetectHost(FFHostResult* host)
|
||||
|| ffSettingsGetAndroidProperty("ro.vivo.market.name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.vendor.oplus.market.enname", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.devicename", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->name)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -121,7 +121,7 @@ const char* ffHostGetMacProductNameWithHwModel(const FFstrbuf* hwModel)
|
||||
ffStrEquals(version, "16,5")) return "MacBook Pro (16-inch, 2024, Three Thunderbolt 5 ports)";
|
||||
if(ffStrEquals(version, "15,14")) return "Mac Studio (M3 Ultra, 2025)";
|
||||
if(ffStrEquals(version, "15,13")) return "MacBook Air (15-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,2")) return "MacBook Air (13-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,12")) return "MacBook Air (13-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,3")) return "MacBook Pro (14-inch, Nov 2023, Two Thunderbolt / USB 4 ports)";
|
||||
if(ffStrEquals(version, "15,4")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports)";
|
||||
if(ffStrEquals(version, "15,5")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports, Two USB 3 ports)";
|
||||
|
||||
@@ -1,48 +1,35 @@
|
||||
#include "fastfetch.h"
|
||||
#include "detection/media/media.h"
|
||||
#include "common/library.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/apple/cf_helpers.h"
|
||||
#include "util/apple/osascript.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
// https://github.com/andrewwiik/iOS-Blocks/blob/master/Widgets/Music/MediaRemote.h
|
||||
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)) __attribute__((weak_import));
|
||||
extern void MRMediaRemoteGetNowPlayingClient(dispatch_queue_t dispatcher, void (^callback)(_Nullable id clientObj)) __attribute__((weak_import));
|
||||
extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribute__((weak_import));
|
||||
extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import));
|
||||
void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationDisplayID(dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef displayID)) __attribute__((weak_import));
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationDisplayName(int unknown, dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef name)) __attribute__((weak_import));
|
||||
|
||||
static const char* getMedia(FFMediaResult* result)
|
||||
static const char* getMediaByMediaRemote(FFMediaResult* result)
|
||||
{
|
||||
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingClient);
|
||||
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetBundleIdentifier);
|
||||
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetParentAppBundleIdentifier);
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingApplicationIsPlaying);
|
||||
#undef FF_TEST_FN_EXISTANCE
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
|
||||
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
|
||||
ffStrbufSetStatic(&result->status, playing ? "Playing" : "Paused");
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
|
||||
dispatch_group_enter(group);
|
||||
__block const char* error = NULL;
|
||||
MRMediaRemoteGetNowPlayingInfo(queue, ^(_Nullable CFDictionaryRef info) {
|
||||
if(info != nil)
|
||||
{
|
||||
error = ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
|
||||
if(!error)
|
||||
{
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
|
||||
}
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
|
||||
}
|
||||
else
|
||||
error = "MRMediaRemoteGetNowPlayingInfo() failed";
|
||||
@@ -51,36 +38,104 @@ static const char* getMedia(FFMediaResult* result)
|
||||
});
|
||||
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingClient(queue, ^(_Nullable id clientObj) {
|
||||
if (clientObj != nil)
|
||||
{
|
||||
CFStringRef identifier = MRNowPlayingClientGetBundleIdentifier(clientObj);
|
||||
if (identifier == nil)
|
||||
identifier = MRNowPlayingClientGetParentAppBundleIdentifier(clientObj);
|
||||
if (identifier != nil)
|
||||
ffCfStrGetString(identifier, &result->playerId);
|
||||
}
|
||||
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
|
||||
ffStrbufSetStatic(&result->status, playing ? "Playing" : "Paused");
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
|
||||
if (MRMediaRemoteGetNowPlayingApplicationDisplayID)
|
||||
{
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingApplicationDisplayID(queue, ^(_Nullable CFStringRef displayID) {
|
||||
ffCfStrGetString(displayID, &result->playerId);
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
}
|
||||
|
||||
if (MRMediaRemoteGetNowPlayingApplicationDisplayName)
|
||||
{
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingApplicationDisplayName(0, queue, ^(_Nullable CFStringRef name) {
|
||||
ffCfStrGetString(name, &result->player);
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
}
|
||||
|
||||
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
||||
// Don't dispatch_release because we are using ARC
|
||||
|
||||
if(result->playerId.length > 0)
|
||||
{
|
||||
char buf[128];
|
||||
snprintf(buf, ARRAY_SIZE(buf), "name of app id \"%s\"", result->playerId.chars);
|
||||
ffOsascript(buf, &result->player);
|
||||
}
|
||||
|
||||
if(result->song.length > 0)
|
||||
return NULL;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"), used))
|
||||
int ffPrintMediaByMediaRemote(void)
|
||||
{
|
||||
FFMediaResult media = {
|
||||
.status = ffStrbufCreate(),
|
||||
.song = ffStrbufCreate(),
|
||||
.artist = ffStrbufCreate(),
|
||||
.album = ffStrbufCreate(),
|
||||
.playerId = ffStrbufCreate(),
|
||||
.player = ffStrbufCreate(),
|
||||
};
|
||||
if (getMediaByMediaRemote(&media) != NULL)
|
||||
return 1;
|
||||
ffStrbufPutTo(&media.status, stdout);
|
||||
ffStrbufPutTo(&media.song, stdout);
|
||||
ffStrbufPutTo(&media.artist, stdout);
|
||||
ffStrbufPutTo(&media.album, stdout);
|
||||
ffStrbufPutTo(&media.playerId, stdout);
|
||||
ffStrbufPutTo(&media.player, stdout);
|
||||
ffStrbufDestroy(&media.status);
|
||||
ffStrbufDestroy(&media.song);
|
||||
ffStrbufDestroy(&media.artist);
|
||||
ffStrbufDestroy(&media.album);
|
||||
ffStrbufDestroy(&media.playerId);
|
||||
ffStrbufDestroy(&media.player);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
|
||||
{
|
||||
// #1737
|
||||
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote()", instance.state.platform.exePath.chars);
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
|
||||
"/usr/bin/python3", // Must be signed by Apple. Homebrew python doesn't work
|
||||
"-c",
|
||||
script.chars,
|
||||
nil
|
||||
});
|
||||
if (error) return error;
|
||||
if (buffer.length == 0) return "No media found";
|
||||
|
||||
// status\ntitle\nartist\nalbum\nbundleName\nappName
|
||||
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player };
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i)
|
||||
ffStrbufSetS(varList[i], line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media)
|
||||
{
|
||||
const char* error = getMedia(media);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
const char* error;
|
||||
if (@available(macOS 15.4, *))
|
||||
error = getMediaByAuthorizedProcess(media);
|
||||
else
|
||||
error = getMediaByMediaRemote(media);
|
||||
if (error)
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
else if (media->player.length == 0 && media->playerId.length > 0)
|
||||
{
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufStartsWithIgnCaseS(&media->player, "com."))
|
||||
ffStrbufSubstrAfter(&media->player, strlen("com.") - 1);
|
||||
ffStrbufReplaceAllC(&media->player, '.', ' ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul
|
||||
ffStrbufClear(&result->artist);
|
||||
ffStrbufClear(&result->album);
|
||||
ffStrbufClear(&result->url);
|
||||
ffStrbufClear(&result->status);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,16 @@ static const char* getMedia(FFMediaResult* media)
|
||||
}
|
||||
|
||||
ffStrbufSetWS(&media->playerId, result.playerId);
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
|
||||
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
|
||||
if (result.playerName[0])
|
||||
{
|
||||
ffStrbufSetWS(&media->player, result.playerName);
|
||||
}
|
||||
else
|
||||
ffStrbufSubstrAfterFirstC(&media->player, '!'); // UWP ID
|
||||
{
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
|
||||
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
|
||||
}
|
||||
ffStrbufSetWS(&media->song, result.song);
|
||||
ffStrbufSetWS(&media->artist, result.artist);
|
||||
ffStrbufSetWS(&media->album, result.album);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Media.Control.h>
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <wchar.h>
|
||||
|
||||
extern "C"
|
||||
@@ -11,6 +12,7 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
|
||||
// C++/WinRT requires Windows 8.1+ and C++ runtime (std::string, exceptions and other stuff)
|
||||
// Make it a separate dll in order not to break Windows 7 support
|
||||
using namespace winrt::Windows::Media::Control;
|
||||
using namespace winrt::Windows::ApplicationModel;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -48,6 +50,11 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
|
||||
::wcsncpy(result->song, mediaProps.Title().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
::wcsncpy(result->artist, mediaProps.Artist().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
::wcsncpy(result->album, mediaProps.AlbumTitle().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
try
|
||||
{
|
||||
// Only works for UWP apps
|
||||
::wcsncpy(result->playerName, AppInfo::GetFromAppUserModelId(session.SourceAppUserModelId()).DisplayInfo().DisplayName().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
} catch (...) { }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
typedef struct FFWinrtMediaResult
|
||||
{
|
||||
wchar_t playerId[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t playerName[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t song[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t artist[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t album[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
|
||||
@@ -8,8 +8,9 @@ const char* ffDetectMemory(FFMemoryResult* ram)
|
||||
if (get_system_info(&info) != B_OK)
|
||||
return "Error getting system info";
|
||||
|
||||
ram->bytesTotal = B_PAGE_SIZE * info.max_pages;
|
||||
ram->bytesUsed = B_PAGE_SIZE * info.used_pages;
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
ram->bytesTotal = pageSize * info.max_pages;
|
||||
ram->bytesUsed = pageSize * info.used_pages;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -4,60 +4,46 @@
|
||||
#include "common/netif/netif.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <net/if.h>
|
||||
|
||||
static void getData(FFstrbuf* buffer, const char* ifName, bool isDefaultRoute, FFstrbuf* path, FFlist* result)
|
||||
static void getData(FFstrbuf* buffer, const char* ifName, bool isDefaultRoute, int basefd, FFlist* result)
|
||||
{
|
||||
ffStrbufSetF(path, "/sys/class/net/%s/operstate", ifName);
|
||||
if(!ffReadFileBuffer(path->chars, buffer) || !ffStrbufEqualS(buffer, "up\n"))
|
||||
FF_AUTO_CLOSE_FD int dfd = openat(basefd, ifName, O_RDONLY | O_DIRECTORY);
|
||||
if (dfd < 0)
|
||||
return;
|
||||
|
||||
char operstate;
|
||||
if(!ffReadFileDataRelative(dfd, "operstate", 1, &operstate) || operstate != 'u' /* up or unknown */)
|
||||
return;
|
||||
|
||||
FFNetIOResult* counters = (FFNetIOResult*) ffListAdd(result);
|
||||
ffStrbufInitS(&counters->name, ifName);
|
||||
counters->defaultRoute = isDefaultRoute;
|
||||
|
||||
ffStrbufSetF(path, "/sys/class/net/%s/statistics/", ifName);
|
||||
uint32_t statLen = path->length;
|
||||
|
||||
ffStrbufAppendS(path, "rx_bytes");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "statistics/rx_bytes", buffer))
|
||||
counters->rxBytes = ffStrbufToUInt(buffer, 0);
|
||||
ffStrbufSubstrBefore(path, statLen);
|
||||
|
||||
ffStrbufAppendS(path, "tx_bytes");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "statistics/tx_bytes", buffer))
|
||||
counters->txBytes = ffStrbufToUInt(buffer, 0);
|
||||
ffStrbufSubstrBefore(path, statLen);
|
||||
|
||||
ffStrbufAppendS(path, "rx_packets");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "statistics/rx_packets", buffer))
|
||||
counters->rxPackets = ffStrbufToUInt(buffer, 0);
|
||||
ffStrbufSubstrBefore(path, statLen);
|
||||
|
||||
ffStrbufAppendS(path, "tx_packets");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "statistics/tx_packets", buffer))
|
||||
counters->txPackets = ffStrbufToUInt(buffer, 0);
|
||||
ffStrbufSubstrBefore(path, statLen);
|
||||
|
||||
ffStrbufAppendS(path, "rx_errors");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "statistics/rx_errors", buffer))
|
||||
counters->rxErrors = ffStrbufToUInt(buffer, 0);
|
||||
ffStrbufSubstrBefore(path, statLen);
|
||||
|
||||
ffStrbufAppendS(path, "tx_errors");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "statistics/tx_errors", buffer))
|
||||
counters->txErrors = ffStrbufToUInt(buffer, 0);
|
||||
ffStrbufSubstrBefore(path, statLen);
|
||||
|
||||
ffStrbufAppendS(path, "rx_dropped");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "statistics/rx_dropped", buffer))
|
||||
counters->rxDrops = ffStrbufToUInt(buffer, 0);
|
||||
ffStrbufSubstrBefore(path, statLen);
|
||||
|
||||
ffStrbufAppendS(path, "tx_dropped");
|
||||
if (ffReadFileBuffer(path->chars, buffer))
|
||||
if (ffReadFileBufferRelative(dfd, "statistics/tx_dropped", buffer))
|
||||
counters->txDrops = ffStrbufToUInt(buffer, 0);
|
||||
ffStrbufSubstrBefore(path, statLen);
|
||||
}
|
||||
|
||||
const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
@@ -65,7 +51,6 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/net");
|
||||
if (!dirp) return "opendir(\"/sys/class/net\") == NULL";
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateA(64);
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName();
|
||||
@@ -75,7 +60,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
if (options->namePrefix.length && strncmp(defaultRouteIfName, options->namePrefix.chars, options->namePrefix.length) != 0)
|
||||
return NULL;
|
||||
|
||||
getData(&buffer, defaultRouteIfName, true, &path, result);
|
||||
getData(&buffer, defaultRouteIfName, true, dirfd(dirp), result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -89,7 +74,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
if (options->namePrefix.length && strncmp(ifName, options->namePrefix.chars, options->namePrefix.length) != 0)
|
||||
continue;
|
||||
|
||||
getData(&buffer, ifName, ffStrEquals(ifName, defaultRouteIfName), &path, result);
|
||||
getData(&buffer, ifName, ffStrEquals(ifName, defaultRouteIfName), dirfd(dirp), result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,11 @@ static void parseSystemVersion(FFOSResult* os)
|
||||
ffStrbufInitS(&os->version, value.UTF8String);
|
||||
if((value = dict[@"ProductBuildVersion"]))
|
||||
ffStrbufInitS(&os->buildID, value.UTF8String);
|
||||
if (ffStrbufStartsWithS(&os->version, "16."))
|
||||
{
|
||||
// macOS 26 Tahoe. #1809
|
||||
os->version.chars[0] = '2';
|
||||
}
|
||||
}
|
||||
|
||||
static bool detectOSCodeName(FFOSResult* os)
|
||||
@@ -37,6 +42,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;
|
||||
@@ -62,7 +69,7 @@ static bool detectOSCodeName(FFOSResult* os)
|
||||
case 6: ffStrbufSetStatic(&os->codename, "Snow Leopard"); return true;
|
||||
case 5: ffStrbufSetStatic(&os->codename, "Leopard"); return true;
|
||||
case 4: ffStrbufSetStatic(&os->codename, "Tiger"); return true;
|
||||
case 3: ffStrbufSetStatic(&os->codename, "Panther"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
|
||||
case 3: ffStrbufSetStatic(&os->codename, "Panther"); return true;
|
||||
case 2: ffStrbufSetStatic(&os->codename, "Jaguar"); return true;
|
||||
case 1: ffStrbufSetStatic(&os->codename, "Puma"); return true;
|
||||
case 0: ffStrbufSetStatic(&os->codename, "Cheetah"); return true;
|
||||
|
||||
+106
-60
@@ -47,7 +47,7 @@ FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result)
|
||||
// - `Armbian_Security` for images with kali repo added
|
||||
// - `Armbian-unofficial` for an unofficial image built from source, e.g. during development and testing
|
||||
if (ffStrbufStartsWithS(&result->prettyName, "Armbian"))
|
||||
ffStrbufSetS(&result->name, "Armbian");
|
||||
ffStrbufSetStatic(&result->name, "Armbian");
|
||||
else
|
||||
return false;
|
||||
ffStrbufSet(&result->idLike, &result->id);
|
||||
@@ -69,113 +69,113 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
|
||||
return;
|
||||
else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Linux Lite");
|
||||
ffStrbufSetS(&result->id, "linuxlite");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Linux Lite");
|
||||
ffStrbufSetStatic(&result->id, "linuxlite");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Linux Lite "));
|
||||
return;
|
||||
}
|
||||
else if(ffStrbufStartsWithS(&result->prettyName, "Rhino Linux "))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Rhino Linux");
|
||||
ffStrbufSetS(&result->id, "rhinolinux");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Rhino Linux");
|
||||
ffStrbufSetStatic(&result->id, "rhinolinux");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Rhino Linux "));
|
||||
return;
|
||||
}
|
||||
else if(ffStrbufStartsWithS(&result->prettyName, "VanillaOS "))
|
||||
{
|
||||
ffStrbufSetS(&result->id, "vanilla");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->id, "vanilla");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Kubuntu");
|
||||
ffStrbufSetS(&result->prettyName, "Kubuntu");
|
||||
ffStrbufSetS(&result->id, "kubuntu");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Kubuntu");
|
||||
ffStrbufSetF(&result->prettyName, "Kubuntu %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "kubuntu");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "xfce") || ffStrContains(xdgConfigDirs, "xubuntu"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Xubuntu");
|
||||
ffStrbufSetS(&result->prettyName, "Xubuntu");
|
||||
ffStrbufSetS(&result->id, "xubuntu");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Xubuntu");
|
||||
ffStrbufSetF(&result->prettyName, "Xubuntu %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "xubuntu");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "lxqt") || ffStrContains(xdgConfigDirs, "lubuntu"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Lubuntu");
|
||||
ffStrbufSetS(&result->prettyName, "Lubuntu");
|
||||
ffStrbufSetS(&result->id, "lubuntu");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Lubuntu");
|
||||
ffStrbufSetF(&result->prettyName, "Lubuntu %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "lubuntu");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "budgie"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Budgie");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Budgie");
|
||||
ffStrbufSetS(&result->id, "ubuntu-budgie");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Budgie");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Budgie %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-budgie");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "cinnamon"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Cinnamon");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Cinnamon");
|
||||
ffStrbufSetS(&result->id, "ubuntu-cinnamon");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Cinnamon");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Cinnamon %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-cinnamon");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "mate"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu MATE");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu MATE");
|
||||
ffStrbufSetS(&result->id, "ubuntu-mate");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu MATE");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu MATE %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-mate");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "studio"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Studio");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Studio");
|
||||
ffStrbufSetS(&result->id, "ubuntu-studio");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Studio");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Studio %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-studio");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "sway"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Sway");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Sway");
|
||||
ffStrbufSetS(&result->id, "ubuntu-sway");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Sway");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Sway %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-sway");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "touch"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Touch");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Touch");
|
||||
ffStrbufSetS(&result->id, "ubuntu-touch");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Touch");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Touch %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-touch");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "lliurex"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "LliureX");
|
||||
ffStrbufSetS(&result->prettyName, "LliureX");
|
||||
ffStrbufSetS(&result->id, "lliurex");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "LliureX");
|
||||
ffStrbufSetF(&result->prettyName, "LliureX %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "lliurex");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -196,8 +196,8 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
|
||||
return true;
|
||||
else if (ffStrbufStartsWithS(&result->name, "Loc-OS"))
|
||||
{
|
||||
ffStrbufSetS(&result->id, "locos");
|
||||
ffStrbufSetS(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->id, "locos");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
return true;
|
||||
}
|
||||
else if (ffStrbufEqualS(&result->name, "Parrot Security"))
|
||||
@@ -210,15 +210,15 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
|
||||
else if (ffStrbufStartsWithS(&result->name, "Lilidog GNU/Linux"))
|
||||
{
|
||||
// https://github.com/fastfetch-cli/fastfetch/issues/1373
|
||||
ffStrbufSetS(&result->id, "lilidog");
|
||||
ffStrbufSetS(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->id, "lilidog");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
return true;
|
||||
}
|
||||
else if (access("/usr/bin/pveversion", X_OK) == 0)
|
||||
{
|
||||
ffStrbufSetS(&result->id, "pve");
|
||||
ffStrbufSetS(&result->idLike, "debian");
|
||||
ffStrbufSetS(&result->name, "Proxmox VE");
|
||||
ffStrbufSetStatic(&result->id, "pve");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->name, "Proxmox VE");
|
||||
ffStrbufClear(&result->versionID);
|
||||
if (ffProcessAppendStdOut(&result->versionID, (char* const[]) {
|
||||
"/usr/bin/dpkg-query",
|
||||
@@ -231,15 +231,50 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
|
||||
ffStrbufSetF(&result->prettyName, "Proxmox VE %s", result->versionID.chars);
|
||||
return true;
|
||||
}
|
||||
else if (ffPathExists("/etc/rpi-issue", FF_PATHTYPE_FILE))
|
||||
{
|
||||
// Raspberry Pi OS
|
||||
ffStrbufSetStatic(&result->id, "raspbian");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->name, "Raspberry Pi OS");
|
||||
ffStrbufSetStatic(&result->prettyName, "Raspberry Pi OS");
|
||||
return true;
|
||||
}
|
||||
else if (ffPathExists("/boot/dietpi/.version", FF_PATHTYPE_FILE))
|
||||
{
|
||||
// DietPi
|
||||
ffStrbufSetStatic(&result->id, "dietpi");
|
||||
ffStrbufSetStatic(&result->name, "DietPi");
|
||||
ffStrbufSetStatic(&result->prettyName, "DietPi");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
FF_STRBUF_AUTO_DESTROY core = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY sub = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY rc = ffStrbufCreate();
|
||||
if (ffParsePropFileValues("/boot/dietpi/.version", 3, (FFpropquery[]) {
|
||||
{"G_DIETPI_VERSION_CORE=", &core},
|
||||
{"G_DIETPI_VERSION_SUB=", &sub},
|
||||
{"G_DIETPI_VERSION_RC=", &rc},
|
||||
})) ffStrbufAppendF(&result->prettyName, " %s.%s.%s", core.chars, sub.chars, rc.chars);
|
||||
return true;
|
||||
}
|
||||
else if (ffStrbufEndsWithS(&instance.state.platform.sysinfo.release, "+truenas"))
|
||||
{
|
||||
// TrueNAS Scale
|
||||
ffStrbufSetStatic(&result->id, "truenas-scale");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->name, "TrueNAS Scale");
|
||||
ffStrbufSetStatic(&result->prettyName, "TrueNAS Scale");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hack for MX Linux. See #847
|
||||
FF_STRBUF_AUTO_DESTROY lsbRelease = ffStrbufCreate();
|
||||
if (ffAppendFileBuffer("/etc/lsb-release", &lsbRelease) && ffStrbufContainS(&lsbRelease, "DISTRIB_ID=MX"))
|
||||
{
|
||||
ffStrbufSetS(&result->id, "mx");
|
||||
ffStrbufSetS(&result->idLike, "debian");
|
||||
ffStrbufSetS(&result->name, "MX");
|
||||
ffStrbufSetStatic(&result->id, "mx");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->name, "MX");
|
||||
|
||||
ffStrbufClear(&result->version);
|
||||
ffParsePropLines(lsbRelease.chars, "DISTRIB_RELEASE=", &result->version);
|
||||
@@ -286,8 +321,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)
|
||||
|
||||
@@ -100,22 +100,23 @@ uint32_t ffPackagesGetNumElements(const char* dirname, bool isdir)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
#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
|
||||
#endif
|
||||
if (entry->d_name[0] != '.')
|
||||
{
|
||||
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 !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
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
if(ok) ++num_elements;
|
||||
}
|
||||
|
||||
if(isdir && num_elements >= 2)
|
||||
num_elements -= 2; // accounting for . and ..
|
||||
|
||||
return num_elements;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef struct FFPackagesResult
|
||||
uint32_t rpm;
|
||||
uint32_t scoop;
|
||||
uint32_t snap;
|
||||
uint32_t soar;
|
||||
uint32_t sorcery;
|
||||
uint32_t winget;
|
||||
uint32_t xbps;
|
||||
|
||||
@@ -554,7 +554,11 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", true);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages", "rpm");
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT))
|
||||
{
|
||||
// `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey` package
|
||||
packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Sigmd5", "rpm");
|
||||
}
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
|
||||
@@ -682,4 +686,7 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT))
|
||||
result->amUser = getAMUser();
|
||||
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_SOAR_BIT))
|
||||
result->soar += getSQLite3Int(&baseDir, ".local/share/soar/db/soar.db", "SELECT COUNT(DISTINCT pkg_id || pkg_name) FROM packages WHERE is_installed = true", "soar");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "packages.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
|
||||
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
{
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
|
||||
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
|
||||
}
|
||||
@@ -4,11 +4,6 @@
|
||||
|
||||
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
{
|
||||
#if __OpenBSD__
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKG_BIT))
|
||||
result->pkg = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg", true);
|
||||
#elif __NetBSD__
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
|
||||
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
|
||||
ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
|
||||
ffStrbufInitMove(&device->serial, &identifier);
|
||||
ffStrbufTrim(&device->serial, ' ');
|
||||
ffStrbufInit(&device->revision);
|
||||
ffStrbufInit(&device->interconnect);
|
||||
switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -78,10 +78,18 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
|
||||
ffStrbufInitMove(&device->name, &name);
|
||||
ffStrbufInitF(&device->devPath, "/dev/%s", devName);
|
||||
|
||||
bool isVirtual = false;
|
||||
{
|
||||
ffStrbufInit(&device->interconnect);
|
||||
if (ffStrStartsWith(devName, "nvme"))
|
||||
ffStrbufSetStatic(&device->interconnect, "NVMe");
|
||||
else if (ffStrStartsWith(devName, "mmcblk"))
|
||||
ffStrbufSetStatic(&device->interconnect, "MMC");
|
||||
else if (ffStrStartsWith(devName, "md"))
|
||||
{
|
||||
ffStrbufSetStatic(&device->interconnect, "RAID");
|
||||
isVirtual = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
char pathSysDeviceLink[64];
|
||||
@@ -97,6 +105,11 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
|
||||
ffStrbufSetStatic(&device->interconnect, "SCSI");
|
||||
else if (strstr(pathSysDeviceReal, "/nvme") != NULL)
|
||||
ffStrbufSetStatic(&device->interconnect, "NVMe");
|
||||
else if (strstr(pathSysDeviceReal, "/virtio") != NULL)
|
||||
{
|
||||
ffStrbufSetStatic(&device->interconnect, "Virtual");
|
||||
isVirtual = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect))
|
||||
@@ -106,6 +119,7 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
|
||||
}
|
||||
}
|
||||
|
||||
if (!isVirtual)
|
||||
{
|
||||
char isRotationalChar = '1';
|
||||
if (ffReadFileDataRelative(dfd, "queue/rotational", 1, &isRotationalChar) > 0)
|
||||
@@ -139,7 +153,7 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
|
||||
{
|
||||
ffStrbufInit(&device->serial);
|
||||
if (ffReadFileBufferRelative(devfd, "serial", &device->serial))
|
||||
ffStrbufTrimRightSpace(&device->serial);
|
||||
ffStrbufTrim(&device->serial, ' ');
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "physicaldisk.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "sys/scsi/generic/inquiry.h"
|
||||
|
||||
#include <libdevinfo.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
struct FFWalkTreeBundle
|
||||
{
|
||||
FFPhysicalDiskOptions* options;
|
||||
FFlist* disks;
|
||||
};
|
||||
|
||||
static int walkDevTree(di_node_t node, di_minor_t minor, struct FFWalkTreeBundle* bundle)
|
||||
{
|
||||
if (di_minor_spectype(minor) != S_IFCHR || !ffStrEquals(di_minor_name(minor), "a,raw")) return DI_WALK_CONTINUE;
|
||||
|
||||
char* productId;
|
||||
char* vendorId;
|
||||
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-product-id", &productId) > 0
|
||||
&& di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-vendor-id", &vendorId) > 0)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateF("%s %s", vendorId, productId);
|
||||
if (bundle->options->namePrefix.length && !ffStrbufStartsWithIgnCase(&name, &bundle->options->namePrefix))
|
||||
return DI_WALK_CONTINUE;
|
||||
|
||||
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(bundle->disks);
|
||||
ffStrbufInitMove(&device->name, &name);
|
||||
ffStrbufInitF(&device->devPath, "/devices%s", di_devfs_path(node));
|
||||
ffStrbufInit(&device->serial);
|
||||
ffStrbufInit(&device->revision);
|
||||
ffStrbufInit(&device->interconnect);
|
||||
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
|
||||
device->type = FF_PHYSICALDISK_TYPE_NONE;
|
||||
device->size = 0;
|
||||
|
||||
char* buf;
|
||||
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-serial-no", &buf) > 0)
|
||||
ffStrbufSetS(&device->serial, buf);
|
||||
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-revision-id", &buf) > 0)
|
||||
ffStrbufSetS(&device->revision, buf);
|
||||
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "class", &buf) > 0)
|
||||
ffStrbufSetS(&device->interconnect, buf);
|
||||
|
||||
device->type |= di_prop_find(DDI_DEV_T_ANY, node, "removable-media") ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
|
||||
|
||||
int* value;
|
||||
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-solid-state", &value) > 0)
|
||||
device->type |= *value ? FF_PHYSICALDISK_TYPE_SSD : FF_PHYSICALDISK_TYPE_HDD;
|
||||
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type", &value) > 0)
|
||||
device->type |= *value == DTYPE_DIRECT ? FF_PHYSICALDISK_TYPE_READWRITE : *value == DTYPE_RODIRECT ? FF_PHYSICALDISK_TYPE_READONLY : 0;
|
||||
|
||||
int64_t* nblocks;
|
||||
if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "device-nblocks", &nblocks) > 0
|
||||
&& di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-blksize", &value) > 0)
|
||||
device->size = (uint64_t) ((uint64_t) *nblocks * (uint64_t) *value);
|
||||
}
|
||||
|
||||
return DI_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
{
|
||||
di_node_t rootNode = di_init("/", DINFOCPYALL);
|
||||
if (rootNode == DI_NODE_NIL)
|
||||
return "di_init() failed";
|
||||
di_walk_minor(rootNode, DDI_NT_BLOCK, DI_WALK_CLDFIRST, &(struct FFWalkTreeBundle) { options, result }, (void*) walkDevTree);
|
||||
di_fini(rootNode);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user