mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 09:58:03 +02:00
Compare commits
172 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f833dda3b9 | |||
| ceecb39bc5 | |||
| c957ca7230 | |||
| 5dfd2676c2 | |||
| d650f67ece | |||
| 760e82913a | |||
| e64a44a3e6 | |||
| be9cf00b05 | |||
| 52fdabeb2e | |||
| 846f4c003e | |||
| dc5f2ac577 | |||
| 663650cb61 | |||
| 45aecae221 | |||
| 3d3669ae3a | |||
| ac2aba0faf | |||
| d0ca944b9c | |||
| 3d7c631abd | |||
| abe78823b6 | |||
| 7e03b03cb7 | |||
| 27fe997dc3 | |||
| fe46159e40 | |||
| 031aa985f1 | |||
| 07c61f70d9 | |||
| 71b05d2594 | |||
| 98665d1b82 | |||
| da0eedf888 | |||
| 1133cb619b | |||
| a091d209cf | |||
| 47c658815b | |||
| b0d0c74073 | |||
| 9535b4d480 | |||
| c64cbf57d8 | |||
| d11235bbe2 | |||
| 3054c6618e | |||
| f34d51dddc | |||
| e05ac797cc | |||
| 187059deef | |||
| 5c9f184314 | |||
| 49725c2cc6 | |||
| eec9a26952 | |||
| 88d616e978 | |||
| 4fccad5d10 | |||
| ec18363f51 | |||
| b87a36785b | |||
| 1d7b212d8d | |||
| 4b6f2a9efa | |||
| bdaf303da4 | |||
| 3fb773eedd | |||
| e73647973d | |||
| d2b3a075b2 | |||
| f139148745 | |||
| e2ec2c695c | |||
| ba4ec47a8c | |||
| de5ef3842c | |||
| 1129ed9be4 | |||
| 0d4f1544c7 | |||
| e68a9476b5 | |||
| 17556c7a95 | |||
| eca9f626a5 | |||
| 7562e05123 | |||
| bf17f2b4b9 | |||
| 88e193e9fd | |||
| e474a47fad | |||
| c77fb71a69 | |||
| 48dd5976e1 | |||
| 093f7e438b | |||
| 0a0c1745b3 | |||
| 7b5dc58140 | |||
| 8681d2f74a | |||
| 2b20ed873c | |||
| ae3c15b7fd | |||
| 8dafd8f300 | |||
| c9a1765f29 | |||
| cc246ea239 | |||
| 0ae5fceb07 | |||
| 6dd18050be | |||
| 9eca6e0b48 | |||
| 4d58d1be66 | |||
| 6694388969 | |||
| f7058cd125 | |||
| 80033b656f | |||
| 1c719fa743 | |||
| a9f5722fd9 | |||
| 0952d7917f | |||
| a3f50f32bf | |||
| ab1bfffbd4 | |||
| 41d6187f11 | |||
| d4b175b146 | |||
| 8905962389 | |||
| d9d34ccbbb | |||
| d21048c165 | |||
| 8b0c32a35f | |||
| db269d29e8 | |||
| f9f628eae6 | |||
| 92e9fbf2eb | |||
| db6e4f4bfc | |||
| b662db452f | |||
| 0d2ccb5fe5 | |||
| d33b5d60b6 | |||
| ef5d12395b | |||
| e18c261054 | |||
| 8851821484 | |||
| 3489cc8fe8 | |||
| 28bc97b92b | |||
| dbc5a7961e | |||
| 5f43f63990 | |||
| b775fe7486 | |||
| 60eaa326a2 | |||
| 672d4ad543 | |||
| 96e9e61437 | |||
| dbc6f70f19 | |||
| dfc9bc265c | |||
| 2ce511c4d3 | |||
| 99415a3841 | |||
| 244625d26a | |||
| 840434e709 | |||
| 72afa9ef99 | |||
| 7400f14322 | |||
| 85654316c7 | |||
| 8ecd58dd14 | |||
| 65c7f68c31 | |||
| bf6d0f871a | |||
| 3cd7c6c916 | |||
| 3227e934de | |||
| b66a009046 | |||
| 6ef4f62d5b | |||
| c038024108 | |||
| df49a01827 | |||
| 924c670915 | |||
| be89dff12a | |||
| c1807a1108 | |||
| b569acbb5d | |||
| 6e571a3163 | |||
| 01e78e2179 | |||
| 1b219a9d5c | |||
| 0ac01003b2 | |||
| a36bdfabd0 | |||
| 570abb194a | |||
| 4e00f37be9 | |||
| 334afc9838 | |||
| 64f9e53a36 | |||
| b94c6ab8d5 | |||
| 38ea333644 | |||
| efbdaf7aaf | |||
| aee7b37fc8 | |||
| 664460cd34 | |||
| a66e1b2e6d | |||
| 8000574a82 | |||
| 2eae5a86d2 | |||
| 75da934815 | |||
| ac71ebcad9 | |||
| 383a6c8a05 | |||
| 8e79fde0d9 | |||
| 4f4622eab9 | |||
| a2327b7350 | |||
| b76ada7f30 | |||
| 59b568a6d0 | |||
| 3d6bd26e59 | |||
| 4e17688b7c | |||
| f34548621f | |||
| 7a2e071081 | |||
| de7b57d807 | |||
| 6de9d0c024 | |||
| 8f69533f30 | |||
| d463853aeb | |||
| 1047d1cf6e | |||
| 0bfa12c38c | |||
| c8e4962cfd | |||
| 171005b6a3 | |||
| 8526f4a021 | |||
| 3e5d129248 | |||
| 6e98db3bf3 |
+21
-70
@@ -35,7 +35,7 @@ jobs:
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_XFCONF=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OSMESA=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_XFCONF=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
@@ -80,7 +80,7 @@ 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 libosmesa6-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 directx-headers-dev
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
@@ -149,7 +149,7 @@ 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 libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm
|
||||
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: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
@@ -187,7 +187,7 @@ jobs:
|
||||
|
||||
linux-armv7l:
|
||||
name: Linux-armv7l
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -196,7 +196,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v2
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: armv7
|
||||
@@ -208,7 +208,7 @@ jobs:
|
||||
# CMake installed by apt has bug `list sub-command REMOVE_ITEM requires two or more arguments`
|
||||
wget --no-check-certificate https://apt.kitware.com/ubuntu/pool/main/c/cmake/{cmake_3.29.2-0kitware1ubuntu20.04.1_armhf.deb,cmake-data_3.29.2-0kitware1ubuntu20.04.1_all.deb}
|
||||
dpkg -i *.deb
|
||||
apt-get install -y make g++ 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 libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
|
||||
apt-get install -y make g++ 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 rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -226,7 +226,7 @@ jobs:
|
||||
|
||||
linux-armv6l:
|
||||
name: Linux-armv6l
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -235,7 +235,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v2
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: armv6
|
||||
@@ -244,7 +244,7 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y wget
|
||||
apt-get install -y cmake make g++ 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 libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
|
||||
apt-get install -y cmake make g++ 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 rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -262,7 +262,7 @@ jobs:
|
||||
|
||||
linux-riscv64:
|
||||
name: Linux-riscv64
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -271,7 +271,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v2
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: riscv64
|
||||
@@ -279,7 +279,7 @@ jobs:
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ 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 libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libddcutil-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
apt-get update && apt-get install -y cmake make g++ 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 libddcutil-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -297,7 +297,7 @@ jobs:
|
||||
|
||||
linux-ppc64le:
|
||||
name: Linux-ppc64le
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -306,7 +306,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v2
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: ppc64le
|
||||
@@ -314,7 +314,7 @@ jobs:
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ 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 libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
apt-get update && apt-get install -y cmake make g++ 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 libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -332,7 +332,7 @@ jobs:
|
||||
|
||||
linux-s390x:
|
||||
name: Linux-s390x
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -341,7 +341,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v2
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: s390x
|
||||
@@ -349,7 +349,7 @@ jobs:
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ 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 libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
apt-get update && apt-get install -y cmake make g++ 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 libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -373,8 +373,6 @@ jobs:
|
||||
|
||||
- name: setup alpine linux
|
||||
uses: jirutka/setup-alpine@master
|
||||
with:
|
||||
branch: v3.19
|
||||
|
||||
- name: install dependencies
|
||||
run: |
|
||||
@@ -422,20 +420,12 @@ jobs:
|
||||
run: |
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: c
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
- name: perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
@@ -514,7 +504,7 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg update
|
||||
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl libosmesa opencl ocl-icd v4l_compat chafa
|
||||
sudo 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
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -530,41 +520,6 @@ jobs:
|
||||
name: fastfetch-freebsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
dragonfly-amd64:
|
||||
name: DragonFly-amd64
|
||||
runs-on: ubuntu-latest
|
||||
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 libosmesa 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-*.*
|
||||
|
||||
openbsd-amd64:
|
||||
name: OpenBSD-amd64
|
||||
runs-on: ubuntu-latest
|
||||
@@ -585,7 +540,7 @@ jobs:
|
||||
version: '7.6'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa pulseaudio hwdata
|
||||
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -621,7 +576,7 @@ jobs:
|
||||
version: '10.1'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick pulseaudio opencl-headers ocl-icd
|
||||
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick opencl-headers ocl-icd
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -669,9 +624,6 @@ jobs:
|
||||
- name: copy necessary dlls
|
||||
run: cp /clang64/bin/{OpenCL,vulkan-1}.dll .
|
||||
|
||||
- name: download amd_ags
|
||||
run: curl -LO https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/raw/master/ags_lib/lib/amd_ags_x64.dll
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
@@ -719,7 +671,6 @@ jobs:
|
||||
- freebsd-amd64
|
||||
- openbsd-amd64
|
||||
- netbsd-amd64
|
||||
- dragonfly-amd64
|
||||
- sunos-amd64
|
||||
- windows-amd64
|
||||
permissions:
|
||||
|
||||
+94
-1
@@ -1,3 +1,96 @@
|
||||
# 2.40.0
|
||||
|
||||
Changes:
|
||||
* In `key-format` of `LocalIP` module, `{name}` has been renamed to `{ifname}` for consistency (LocalIP, #1639)
|
||||
|
||||
Features:
|
||||
* Support Warp Terminal font detection (TerminalFont, Windows)
|
||||
* Support more AMD GPU information using ADL SDK, including memory type detection (GPU, Windows)
|
||||
* Support Intel dGPU memory type detection (GPU, Windows)
|
||||
* Support Nvidia VMEM type detection via NVAPI (GPU, Windows, #993)
|
||||
* Support Boot manager detection for OpenBSD and NetBSD (Bootmgr, OpenBSD / NetBSD)
|
||||
* Use `SystemConfiguration` for DNS entries detection (DNS, macOS)
|
||||
* Add `systemd-resolved` support for DNS module (DNS, Linux, #1646)
|
||||
* Improve performance and accuracy of Wifi detection on FreeBSD using ioctl (Wifi, FreeBSD)
|
||||
* Support remaining time reporting for batteries on NetBSD (Battery, NetBSD)
|
||||
* Add new Mac models support (Host, macOS)
|
||||
* Load config from fastfetch binary path with `--config` option (#1649)
|
||||
* Support TPM detection on macOS (TPM, macOS)
|
||||
* Support IPv6 client address report (Users, Linux / Windows)
|
||||
* Support default route detection for IPv6 (LocalIP, Linux)
|
||||
* Round seconds to the nearest minute to match the behavior of `uptime` command (Uptime)
|
||||
|
||||
Bugfixes:
|
||||
* Fix `outputColor` not working when `length` is set in Separator module (#1644)
|
||||
* Fix CPU detection on PowerPC platforms (#1640, CPU, Linux)
|
||||
* Fix battery manufacture date detection (Battery, macOS)
|
||||
* Fix battery critical state detection (Battery, Linux)
|
||||
* Fix Warp Terminal PID detection (Terminal, macOS)
|
||||
* Remove disk creation time detection support on SunOS as ctim is file status change timestamp, not creation time (Disk, SunOS)
|
||||
* Fall back to KDGKBINFO if `usbhid` fails (Keyboard, FreeBSD)
|
||||
* Fix multiple paging file support (Swap, Windows)
|
||||
* Fix memleaks, code smells in multiple modules
|
||||
* Fix boot time calculation on NetBSD (Uptime, NetBSD)
|
||||
* Temporarily fix Hyprland version detection (WM, Linux, #1657)
|
||||
|
||||
Logo:
|
||||
* Fix opensuse-tumbleweed_small (#1636)
|
||||
* Change WiiLinuxNgx to more generic name with aliases Wii-Linux and WiiLinux (#1633)
|
||||
* Change name of Xray-OS to Ada (#1651)
|
||||
* Change Nexa Linux logo (#1653)
|
||||
|
||||
# 2.39.1
|
||||
|
||||
Bugfixes:
|
||||
* Fix a regression that PublicIP detection fails randomly (PublicIP, #1629)
|
||||
|
||||
# 2.39.0
|
||||
|
||||
Changes:
|
||||
* OSMesa backend for OpenGL detection is removed (#1618)
|
||||
* Fastfetch no longer tries to use the private framework `Apple80211` to acquire SSID for Wifi module, which is only useful for macOS Sonoma (Wifi, macOS)
|
||||
|
||||
Features:
|
||||
* Improve accuracy of HDR support on Windows 11 24H2 (Display, Windows)
|
||||
* Improve performance of SSID detection on macOS Sequoia (Wifi, macOS, #1597)
|
||||
* Support warp terminal version detection on Windows (Terminal, Windows)
|
||||
* Support default route detection on OpenBSD & DragonFly BSD (LocalIP, OpenBSD / DragonFly)
|
||||
* Improve bash completion script
|
||||
* Improve performance of networking (PublicIP / Weather)
|
||||
* Support pkgsrc package manager detection on Linux (Packages, Linux)
|
||||
|
||||
Logo:
|
||||
* Add Common Torizon OS
|
||||
* Change FoxOS to WolfOS
|
||||
* Add Bredos
|
||||
* Add NetBSD2
|
||||
|
||||
# 2.38.0
|
||||
|
||||
Bugfixes:
|
||||
* Fix empty battery slots handling (Battery, Haiku, #1575)
|
||||
* Fix `{day-pretty}` output in custom format (DateTime, Windows)
|
||||
* Fix VanillaOS detection (OS, Linux)
|
||||
* Fix secure boot testing (Bootmgr, Linux, #1584)
|
||||
* Fix the SI unit "kB" in help message (#1589)
|
||||
* Fix segfault on macOS 10.15 when using the binary downloaded from Github Releases (Camera, macOS, #1594)
|
||||
|
||||
Features:
|
||||
* Support Chassis module in macOS (Chassis, macOS)
|
||||
* Allow customize key format with kernel name and distro name (OS)
|
||||
* Add missing `{icon}` in custom key format (Battery)
|
||||
* Add missing `{mountpoint}` and `{mount-from}` in custom output format (Disk, #1577)
|
||||
* Support percentage num & bar in custom format (GPU, #1583)
|
||||
* Support `pisi` package manager detection (Packages, Linux)
|
||||
* Support termite terminal font detection (TerminalFont, Linux)
|
||||
* Report monitor type in Brightness module (Brightness)
|
||||
|
||||
Logo:
|
||||
* Add `opensuse-tumbleweed_small`
|
||||
* Add `Bedrock_small`
|
||||
* Add `fastfetch`
|
||||
* Remove some unnecessary distro names
|
||||
|
||||
# 2.37.0
|
||||
|
||||
Changes:
|
||||
@@ -284,7 +377,7 @@ Features:
|
||||
* Support tilix version detection (Terminal, Linux)
|
||||
* Support percent type config in module level. Example:
|
||||
|
||||
```json
|
||||
```jsonc
|
||||
{
|
||||
"type": "memory",
|
||||
"percent": {
|
||||
|
||||
+26
-28
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.37.0
|
||||
VERSION 2.40.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -74,7 +74,6 @@ cmake_dependent_option(ENABLE_CHAFA "Enable chafa" ON "ENABLE_IMAGEMAGICK6 OR EN
|
||||
cmake_dependent_option(ENABLE_ZLIB "Enable zlib" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF)
|
||||
cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR WIN32 OR SunOS OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_OSMESA "Enable osmesa" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" 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)
|
||||
@@ -103,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 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 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)
|
||||
@@ -365,6 +364,7 @@ set(LIBFASTFETCH_SRC
|
||||
src/common/library.c
|
||||
src/common/modules.c
|
||||
src/common/netif/netif.c
|
||||
src/common/networking/networking_common.c
|
||||
src/common/option.c
|
||||
src/common/parsing.c
|
||||
src/common/printing.c
|
||||
@@ -493,7 +493,7 @@ if(LINUX)
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_linux.c
|
||||
src/common/networking_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/detection/battery/battery_linux.c
|
||||
src/detection/bios/bios_linux.c
|
||||
@@ -574,7 +574,7 @@ elseif(ANDROID)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_linux.c
|
||||
src/common/networking_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/detection/battery/battery_android.c
|
||||
src/detection/bios/bios_android.c
|
||||
@@ -640,7 +640,7 @@ elseif(FreeBSD)
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/networking_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/common/sysctl.c
|
||||
src/detection/battery/battery_bsd.c
|
||||
@@ -708,7 +708,6 @@ elseif(FreeBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_bsd.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
@@ -720,10 +719,12 @@ elseif(FreeBSD)
|
||||
if(DragonFly)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/detection/bluetooth/bluetooth_nosupport.c
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
)
|
||||
else()
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/detection/bluetooth/bluetooth_bsd.c
|
||||
src/detection/wifi/wifi_bsd.c
|
||||
)
|
||||
endif()
|
||||
elseif(NetBSD)
|
||||
@@ -731,7 +732,7 @@ elseif(NetBSD)
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/networking_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/common/sysctl.c
|
||||
src/detection/battery/battery_nbsd.c
|
||||
@@ -739,7 +740,7 @@ elseif(NetBSD)
|
||||
src/detection/bluetooth/bluetooth_nosupport.c
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
src/detection/board/board_nbsd.c
|
||||
src/detection/bootmgr/bootmgr_nosupport.c
|
||||
src/detection/bootmgr/bootmgr_bsd.c
|
||||
src/detection/brightness/brightness_nbsd.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_nbsd.c
|
||||
@@ -813,26 +814,26 @@ elseif(OpenBSD)
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/networking_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/common/sysctl.c
|
||||
src/detection/battery/battery_obsd.c
|
||||
src/detection/bios/bios_nosupport.c
|
||||
src/detection/bios/bios_windows.c
|
||||
src/detection/bluetooth/bluetooth_nosupport.c
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
src/detection/board/board_nosupport.c
|
||||
src/detection/bootmgr/bootmgr_nosupport.c
|
||||
src/detection/board/board_windows.c
|
||||
src/detection/bootmgr/bootmgr_bsd.c
|
||||
src/detection/brightness/brightness_obsd.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_nosupport.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/cpu/cpu_obsd.c
|
||||
src/detection/cpucache/cpucache_nosupport.c
|
||||
src/detection/cpucache/cpucache_shared.c
|
||||
src/detection/cpuusage/cpuusage_bsd.c
|
||||
src/detection/cursor/cursor_linux.c
|
||||
src/detection/disk/disk_bsd.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_nosupport.c
|
||||
src/detection/physicalmemory/physicalmemory_nosupport.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/diskio/diskio_obsd.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/drm.c
|
||||
@@ -889,12 +890,13 @@ elseif(OpenBSD)
|
||||
src/detection/zpool/zpool_nosupport.c
|
||||
src/util/platform/FFPlatform_unix.c
|
||||
src/util/binary_linux.c
|
||||
src/util/smbiosHelper.c
|
||||
)
|
||||
elseif(APPLE)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/networking_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/common/sysctl.c
|
||||
src/detection/battery/battery_apple.c
|
||||
@@ -905,13 +907,13 @@ elseif(APPLE)
|
||||
src/detection/bootmgr/bootmgr_apple.c
|
||||
src/detection/brightness/brightness_apple.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_nosupport.c
|
||||
src/detection/chassis/chassis_apple.c
|
||||
src/detection/cpu/cpu_apple.c
|
||||
src/detection/cpucache/cpucache_apple.c
|
||||
src/detection/cpuusage/cpuusage_apple.c
|
||||
src/detection/cursor/cursor_apple.m
|
||||
src/detection/disk/disk_bsd.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/dns/dns_apple.c
|
||||
src/detection/physicaldisk/physicaldisk_apple.c
|
||||
src/detection/physicalmemory/physicalmemory_apple.m
|
||||
src/detection/diskio/diskio_apple.c
|
||||
@@ -945,7 +947,7 @@ elseif(APPLE)
|
||||
src/detection/terminalshell/terminalshell_linux.c
|
||||
src/detection/terminalsize/terminalsize_linux.c
|
||||
src/detection/theme/theme_nosupport.c
|
||||
src/detection/tpm/tpm_nosupport.c
|
||||
src/detection/tpm/tpm_apple.c
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_apple.m
|
||||
@@ -965,7 +967,7 @@ elseif(WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/io/io_windows.c
|
||||
src/common/netif/netif_windows.c
|
||||
src/common/networking_windows.c
|
||||
src/common/networking/networking_windows.c
|
||||
src/common/processing_windows.c
|
||||
src/detection/battery/battery_windows.c
|
||||
src/detection/bios/bios_windows.c
|
||||
@@ -1034,13 +1036,14 @@ elseif(WIN32)
|
||||
src/util/windows/version.c
|
||||
src/util/platform/FFPlatform_windows.c
|
||||
src/util/binary_windows.c
|
||||
src/util/debug_windows.c
|
||||
)
|
||||
elseif(SunOS)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/networking_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/detection/battery/battery_nosupport.c
|
||||
src/detection/bios/bios_windows.c
|
||||
@@ -1121,7 +1124,7 @@ elseif(Haiku)
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_haiku.c
|
||||
src/common/networking_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/detection/battery/battery_haiku.c
|
||||
src/detection/bios/bios_windows.c
|
||||
@@ -1478,10 +1481,6 @@ else()
|
||||
"GL"
|
||||
)
|
||||
endif()
|
||||
ff_lib_enable(OSMESA
|
||||
"osmesa"
|
||||
"OSMesa"
|
||||
)
|
||||
ff_lib_enable(OPENCL
|
||||
"OpenCL"
|
||||
"OpenCL"
|
||||
@@ -1575,7 +1574,6 @@ elseif(APPLE)
|
||||
PRIVATE "-F /System/Library/PrivateFrameworks"
|
||||
PRIVATE "-weak_framework DisplayServices"
|
||||
PRIVATE "-weak_framework MediaRemote"
|
||||
PRIVATE "-weak_framework Apple80211"
|
||||
)
|
||||
elseif(WIN32)
|
||||
target_link_libraries(libfastfetch
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
|
||||
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it prettily. It is written mainly in C, with performance and customizability in mind. Currently, Linux, Android, FreeBSD, macOS, SunOS and Windows 7+ are supported.
|
||||
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it prettily. It is written mainly in C, with performance and customizability in mind. Currently, Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS are supported.
|
||||
|
||||
<img src="screenshots/example1.png" width="49%" align="left" />
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/2/24/Transparent_Square_Tiles_Texture.png" width="49%" height="16px" align="left" />
|
||||
|
||||
+119
-428
@@ -1,430 +1,121 @@
|
||||
__fastfetch_complete_help()
|
||||
{
|
||||
local __ff_helps=(
|
||||
"color"
|
||||
"format"
|
||||
"config"
|
||||
"os-format"
|
||||
"host-format"
|
||||
"kernel-format"
|
||||
"uptime-format"
|
||||
"processes-format"
|
||||
"packages-format"
|
||||
"shell-format"
|
||||
"display-format"
|
||||
"de-format"
|
||||
"wm-format"
|
||||
"wmtheme-format"
|
||||
"theme-format"
|
||||
"icons-format"
|
||||
"font-format"
|
||||
"cursor-format"
|
||||
"terminal-format"
|
||||
"terminalfont-format"
|
||||
"cpu-format"
|
||||
"cpuusage-format"
|
||||
"gpu-format"
|
||||
"memory-format"
|
||||
"swap-format"
|
||||
"disk-format"
|
||||
"battery-format"
|
||||
"poweradapter-format"
|
||||
"locale-format"
|
||||
"localip-format"
|
||||
"publicip-format"
|
||||
"player-format"
|
||||
"media-format"
|
||||
"datetime-format"
|
||||
"date-format"
|
||||
"time-format"
|
||||
"vulkan-format"
|
||||
"opengl-format"
|
||||
"opencl-format"
|
||||
"bluetooth-format"
|
||||
)
|
||||
COMPREPLY=($(compgen -W "${__ff_helps[*]}" -- "$CURRENT_WORD"))
|
||||
#!/usr/bin/env bash
|
||||
|
||||
_fastfetch() {
|
||||
# Use Bash built-in variables directly
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
local prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
|
||||
# Check if Python is available
|
||||
if ! command -v python3 &>/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Handle standard completion cases
|
||||
case "$prev" in
|
||||
--color|--color-keys|--color-title|--color-output|--color-separator|--*-color|--*-key-color|--*-output-color|--logo-color-[1-9]|--percent-color-*|--temp-color-*)
|
||||
local -a colors=("black" "red" "green" "yellow" "blue" "magenta" "cyan" "white" "default")
|
||||
COMPREPLY=($(compgen -W "${colors[*]}" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
--logo|-l)
|
||||
local -a logos
|
||||
readarray -t logos < <(fastfetch --list-logos autocompletion 2>/dev/null)
|
||||
logos+=("none" "small")
|
||||
COMPREPLY=($(compgen -W "${logos[*]}" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
--config|-c)
|
||||
local -a presets
|
||||
readarray -t presets < <(fastfetch --list-presets autocompletion 2>/dev/null)
|
||||
presets+=("none")
|
||||
COMPREPLY=($(compgen -W "${presets[*]}" -- "$cur"))
|
||||
# Also allow file path completion
|
||||
if type _filedir &>/dev/null; then
|
||||
_filedir
|
||||
elif type compgen &>/dev/null; then
|
||||
COMPREPLY+=($(compgen -f -- "$cur"))
|
||||
fi
|
||||
return
|
||||
;;
|
||||
--structure|-s)
|
||||
# Get all module names in lowercase only
|
||||
local -a structures
|
||||
readarray -t structures < <(fastfetch --list-modules autocompletion 2>/dev/null | cut -d':' -f1 | tr '[:upper:]' '[:lower:]')
|
||||
COMPREPLY=($(compgen -W "${structures[*]}" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
--help|-h)
|
||||
local -a modules
|
||||
readarray -t modules < <(fastfetch --list-modules autocompletion 2>/dev/null)
|
||||
# Convert to lowercase and keep only module names
|
||||
local -a module_names=()
|
||||
for module in "${modules[@]}"; do
|
||||
module_names+=($(echo "$module" | cut -d':' -f1 | tr '[:upper:]' '[:lower:]')-format)
|
||||
done
|
||||
module_names+=("format" "color")
|
||||
COMPREPLY=($(compgen -W "${module_names[*]}" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
--format)
|
||||
COMPREPLY=($(compgen -W "json default" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
--*-format)
|
||||
# Format string completion, handle spaces
|
||||
return
|
||||
;;
|
||||
--*path*|--*file*|--gen-config*|--*data*)
|
||||
# File path completion
|
||||
if type _filedir &>/dev/null; then
|
||||
_filedir
|
||||
elif type compgen &>/dev/null; then
|
||||
COMPREPLY=($(compgen -f -- "$cur"))
|
||||
fi
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
# If not a special option, generate all possible options
|
||||
if [[ "$cur" == -* ]]; then
|
||||
local -a opts
|
||||
readarray -t opts < <(python3 - "$cur" <<'EOF'
|
||||
import json
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
def main(current):
|
||||
try:
|
||||
# Use fastfetch --help-raw to get option data
|
||||
output = subprocess.check_output(['fastfetch', '--help-raw'], stderr=subprocess.DEVNULL)
|
||||
data = json.loads(output)
|
||||
|
||||
for category in data.values():
|
||||
for flag in category:
|
||||
if flag.get("pseudo", False):
|
||||
continue
|
||||
|
||||
if "short" in flag:
|
||||
print(f"-{flag['short']}")
|
||||
|
||||
if "long" in flag:
|
||||
if flag["long"] == "logo-color-[1-9]":
|
||||
for i in range(1, 10):
|
||||
print(f"--logo-color-{i}")
|
||||
else:
|
||||
print(f"--{flag['long']}")
|
||||
except Exception:
|
||||
# If error occurs, return no options
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1])
|
||||
EOF
|
||||
)
|
||||
COMPREPLY=($(compgen -W "${opts[*]}" -- "$cur"))
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
__fastfetch_complete_bool()
|
||||
{
|
||||
COMPREPLY=($(compgen -W "true false" -- "$CURRENT_WORD"))
|
||||
}
|
||||
|
||||
__fastfetch_complete_string()
|
||||
{
|
||||
if [[ $CURRENT_WORD != "" ]]; then
|
||||
COMPREPLY=("$CURRENT_WORD")
|
||||
fi
|
||||
}
|
||||
|
||||
__fastfetch_complete_path()
|
||||
{
|
||||
COMPREPLY=($(compgen -A file -- "$CURRENT_WORD"))
|
||||
}
|
||||
|
||||
__fastfetch_complete_logo()
|
||||
{
|
||||
COMPREPLY=($(compgen -W "$(fastfetch --list-logos autocompletion)" -- "$CURRENT_WORD"))
|
||||
}
|
||||
|
||||
__fastfetch_complete_logo_type()
|
||||
{
|
||||
local __ff_logo_types=(
|
||||
"auto"
|
||||
"builtin"
|
||||
"file"
|
||||
"raw"
|
||||
"sixel"
|
||||
"kitty"
|
||||
"chafa"
|
||||
)
|
||||
COMPREPLY=($(compgen -W "${__ff_logo_types[*]}" -- "$CURRENT_WORD"))
|
||||
}
|
||||
|
||||
__fastfetch_complete_binary_prefix()
|
||||
{
|
||||
local __ff_size_binary_prefixes=(
|
||||
"iec"
|
||||
"si"
|
||||
"jedec"
|
||||
)
|
||||
COMPREPLY=($(compgen -W "${__ff_size_binary_prefixes[*]}" -- "$CURRENT_WORD"))
|
||||
}
|
||||
|
||||
__fastfetch_complete_gl()
|
||||
{
|
||||
local __ff_gl_types=(
|
||||
"auto"
|
||||
"egl"
|
||||
"glx"
|
||||
"osmesa"
|
||||
)
|
||||
COMPREPLY=($(compgen -W "${__ff_gl_types[*]}" -- "$CURRENT_WORD"))
|
||||
}
|
||||
|
||||
__fastfetch_complete_option()
|
||||
{
|
||||
local FF_OPTIONS_ALL=(
|
||||
"${FF_OPTIONS_BOOL[@]}"
|
||||
"${FF_OPTIONS_STRING[@]}"
|
||||
"${FF_OPTIONS_PATH[@]}"
|
||||
"${FF_OPTIONS_LOGO[@]}"
|
||||
"${FF_OPTIONS_LOGO_TYPE[@]}"
|
||||
"${FF_OPTIONS_BINARY_PREFIX[@]}"
|
||||
"${FF_OPTIONS_OPENGL[@]}"
|
||||
)
|
||||
|
||||
if [[ $WORD_COUND -lt 3 ]]; then
|
||||
FF_OPTIONS_ALL+=(
|
||||
"${FF_OPTIONS_SINGLE[@]}"
|
||||
"${FF_OPTIONS_HELP[@]}"
|
||||
)
|
||||
fi
|
||||
|
||||
for ff_word in ${COMP_WORDS[@]}; do
|
||||
if [[ $ff_word == $CURRENT_WORD ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
FF_OPTIONS_ALL=("${FF_OPTIONS_ALL[@]/$ff_word}")
|
||||
done
|
||||
|
||||
COMPREPLY=($(compgen -W "${FF_OPTIONS_ALL[*]}" -- "$CURRENT_WORD"))
|
||||
}
|
||||
|
||||
__fastfetch_previous_matches()
|
||||
{
|
||||
for ff_option in "$@"; do
|
||||
if [[ $ff_option == "$PREVIOUS_WORD" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
__fastfetch_completion()
|
||||
{
|
||||
local CURRENT_WORD="${COMP_WORDS[$COMP_CWORD]}"
|
||||
local PREVIOUS_WORD="${COMP_WORDS[$COMP_CWORD - 1]}"
|
||||
local WORD_COUND="${#COMP_WORDS[@]}"
|
||||
|
||||
local FF_OPTIONS_SINGLE=(
|
||||
"-v"
|
||||
"--version"
|
||||
"--list-logos"
|
||||
"--list-modules"
|
||||
"--list-presets"
|
||||
"--list-features"
|
||||
"--print-logos"
|
||||
"--print-config-system"
|
||||
"--print-config-user"
|
||||
"--print-structure"
|
||||
"--gen-config"
|
||||
"--gen-config-force"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_HELP=(
|
||||
"-h"
|
||||
"--help"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_BOOL=(
|
||||
"-r"
|
||||
"--show-errors"
|
||||
"--logo-print-remaining"
|
||||
"--multithreading"
|
||||
"--stat"
|
||||
"--allow-slow-operations"
|
||||
"--disable-linewrap"
|
||||
"--hide-cursor"
|
||||
"--cpu-temp"
|
||||
"--gpu-temp"
|
||||
"--battery-temp"
|
||||
"--display-precise-refresh-rate"
|
||||
"--localip-show-ipv4"
|
||||
"--localip-show-ipv6"
|
||||
"--localip-show-flags"
|
||||
"--localip-show-loop"
|
||||
"--localip-show-mtu"
|
||||
"--localip-show-speed"
|
||||
"--localip-name-prefix"
|
||||
"--localip-compact-type"
|
||||
"--escape-bedrock"
|
||||
"--pipe"
|
||||
"--title-fqdn"
|
||||
"--disk-folders"
|
||||
"--disk-show-external"
|
||||
"--disk-show-hidden"
|
||||
"--disk-show-subvolumes"
|
||||
"--gpu-hide-integrated"
|
||||
"--gpu-hide-discrete"
|
||||
"--gpu-force-method"
|
||||
"--disk-show-unknown"
|
||||
"--bluetooth-show-disconnected"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_STRING=(
|
||||
"--logo-type"
|
||||
"--logo-padding"
|
||||
"--logo-padding-left"
|
||||
"--logo-padding-right"
|
||||
"--logo-padding-top"
|
||||
"--logo-color-1"
|
||||
"--logo-color-2"
|
||||
"--logo-color-3"
|
||||
"--logo-color-4"
|
||||
"--logo-color-5"
|
||||
"--logo-color-6"
|
||||
"--logo-color-7"
|
||||
"--logo-color-8"
|
||||
"--logo-color-9"
|
||||
"--logo-width"
|
||||
"--logo-height"
|
||||
"--color"
|
||||
"--color-keys"
|
||||
"--color-title"
|
||||
"--display-compact-type"
|
||||
"--separator"
|
||||
"-s"
|
||||
"--structure"
|
||||
"--player-name"
|
||||
"--percent-type"
|
||||
"--publicip-url"
|
||||
"--publicip-timeout"
|
||||
"--weather-output-format"
|
||||
"--weather-timeout"
|
||||
"--os-key"
|
||||
"--os-format"
|
||||
"--os-key-color"
|
||||
"--host-key"
|
||||
"--host-format"
|
||||
"--host-key-color"
|
||||
"--kernel-key"
|
||||
"--kernel-format"
|
||||
"--kernel-key-color"
|
||||
"--uptime-key"
|
||||
"--uptime-format"
|
||||
"--uptime-key-color"
|
||||
"--processes-key"
|
||||
"--processes-format"
|
||||
"--processes-key-color"
|
||||
"--packages-key"
|
||||
"--packages-format"
|
||||
"--packages-key-color"
|
||||
"--shell-key"
|
||||
"--shell-format"
|
||||
"--shell-key-color"
|
||||
"--display-key"
|
||||
"--display-format"
|
||||
"--display-key-color"
|
||||
"--de-key"
|
||||
"--de-format"
|
||||
"--de-key-color"
|
||||
"--wm-key"
|
||||
"--wm-format"
|
||||
"--wm-key-color"
|
||||
"--wmtheme-key"
|
||||
"--wmtheme-format"
|
||||
"--wmtheme-key-color"
|
||||
"--theme-key"
|
||||
"--theme-format"
|
||||
"--theme-key-color"
|
||||
"--icons-key"
|
||||
"--icons-format"
|
||||
"--icons-key-color"
|
||||
"--font-key"
|
||||
"--font-format"
|
||||
"--font-key-color"
|
||||
"--cursor-key"
|
||||
"--cursor-format"
|
||||
"--cursor-key-color"
|
||||
"--terminal-key"
|
||||
"--terminal-format"
|
||||
"--terminal-key-color"
|
||||
"--terminalfont-key"
|
||||
"--terminalfont-format"
|
||||
"--terminalfont-key-color"
|
||||
"--cpu-key"
|
||||
"--cpu-format"
|
||||
"--cpu-key-color"
|
||||
"--cpu-useage-key"
|
||||
"--cpu-useage-format"
|
||||
"--cpu-useage-key-color"
|
||||
"--gpu-key"
|
||||
"--gpu-format"
|
||||
"--gpu-key-color"
|
||||
"--memory-key"
|
||||
"--memory-format"
|
||||
"--memory-key-color"
|
||||
"--swap-key"
|
||||
"--swap-format"
|
||||
"--swap-key-color"
|
||||
"--disk-key"
|
||||
"--disk-format"
|
||||
"--disk-key-color"
|
||||
"--battery-key"
|
||||
"--battery-format"
|
||||
"--battery-key-color"
|
||||
"--poweradapter-key"
|
||||
"--poweradapter-format"
|
||||
"--poweradapter-key-color"
|
||||
"--locale-key"
|
||||
"--locale-format"
|
||||
"--locale-key-color"
|
||||
"--localip-key"
|
||||
"--localip-format"
|
||||
"--localip-key-color"
|
||||
"--publicip-key"
|
||||
"--publicip-format"
|
||||
"--publicip-key-color"
|
||||
"--wifi-key"
|
||||
"--wifi-format"
|
||||
"--wifi-key-color"
|
||||
"--weather-key"
|
||||
"--weather-format"
|
||||
"--weather-key-color"
|
||||
"--player-key"
|
||||
"--player-format"
|
||||
"--player-key-color"
|
||||
"--media-key"
|
||||
"--media-format"
|
||||
"--media-key-color"
|
||||
"--datetime-key"
|
||||
"--datetime-format"
|
||||
"--datetime-key-color"
|
||||
"--date-key"
|
||||
"--date-format"
|
||||
"--date-key-color"
|
||||
"--time-key"
|
||||
"--time-format"
|
||||
"--time-key-color"
|
||||
"--vulkan-key"
|
||||
"--vulkan-format"
|
||||
"--vulkan-key-color"
|
||||
"--opengl-key"
|
||||
"--opengl-format"
|
||||
"--opengl-key-color"
|
||||
"--opencl-key"
|
||||
"--opencl-format"
|
||||
"--opencl-key-color"
|
||||
"--users-key"
|
||||
"--users-format"
|
||||
"--users-key-color"
|
||||
"--users-myself-only"
|
||||
"--bluetooth-key"
|
||||
"--bluetooth-format"
|
||||
"--bluetooth-key-color"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_PATH=(
|
||||
"-c"
|
||||
"--config"
|
||||
"--lib-vulkan"
|
||||
"--lib-wayland"
|
||||
"--lib-xcb-randr"
|
||||
"--lib-xcb"
|
||||
"--lib-xrandr"
|
||||
"--lib-X11"
|
||||
"--lib-gio"
|
||||
"--lib-dconf"
|
||||
"--lib-dbus"
|
||||
"--lib-xfconf"
|
||||
"--lib-sqlite3"
|
||||
"--lib-rpm"
|
||||
"--lib-imagemagick"
|
||||
"--lib-z"
|
||||
"--lib-chafa"
|
||||
"--lib-egl"
|
||||
"--lib-glx"
|
||||
"--lib-osmesa"
|
||||
"--lib-opencl"
|
||||
"--lib-pulse"
|
||||
"--lib-ddcutil"
|
||||
"--lib-nm"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_LOGO=(
|
||||
"-l"
|
||||
"--logo"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_LOGO_TYPE=(
|
||||
"--logo-type"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_BINARY_PREFIX=(
|
||||
"--binary-prefix"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_OPENGL=(
|
||||
"--opengl-type"
|
||||
)
|
||||
|
||||
if __fastfetch_previous_matches "${FF_OPTIONS_SINGLE[@]}"; then
|
||||
return
|
||||
elif [[ $WORD_COUND -gt 3 && ( ${COMP_WORDS[$COMP_CWORD - 2]} == "--help" || ${COMP_WORDS[$COMP_CWORD - 2]} == "-h" ) ]]; then
|
||||
return
|
||||
elif [[ $CURRENT_WORD == "-"* ]]; then
|
||||
__fastfetch_complete_option
|
||||
elif __fastfetch_previous_matches "${FF_OPTIONS_HELP[@]}"; then
|
||||
__fastfetch_complete_help
|
||||
elif __fastfetch_previous_matches "${FF_OPTIONS_BOOL[@]}"; then
|
||||
__fastfetch_complete_bool
|
||||
elif __fastfetch_previous_matches "${FF_OPTIONS_STRING[@]}"; then
|
||||
__fastfetch_complete_string
|
||||
elif __fastfetch_previous_matches "${FF_OPTIONS_PATH[@]}"; then
|
||||
__fastfetch_complete_path
|
||||
elif __fastfetch_previous_matches "${FF_OPTIONS_LOGO[@]}"; then
|
||||
__fastfetch_complete_logo
|
||||
elif __fastfetch_previous_matches "${FF_OPTIONS_LOGO_TYPE[@]}"; then
|
||||
__fastfetch_complete_logo_type
|
||||
elif __fastfetch_previous_matches "${FF_OPTIONS_BINARY_PREFIX[@]}"; then
|
||||
__fastfetch_complete_binary_prefix
|
||||
elif __fastfetch_previous_matches "${FF_OPTIONS_OPENGL[@]}"; then
|
||||
__fastfetch_complete_gl
|
||||
else
|
||||
__fastfetch_complete_option
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F __fastfetch_completion fastfetch
|
||||
# Register completion
|
||||
complete -F _fastfetch fastfetch
|
||||
|
||||
Vendored
+30
@@ -1,3 +1,33 @@
|
||||
fastfetch (2.39.1) jammy; urgency=medium
|
||||
|
||||
* Update to 2.39.1
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 21 Mar 2025 11:02:19 +0800
|
||||
|
||||
fastfetch (2.39.0ubuntu1) jammy; urgency=medium
|
||||
|
||||
* Remove unwanted debugging code
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 20 Mar 2025 10:39:22 +0800
|
||||
|
||||
fastfetch (2.39.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.39.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 20 Mar 2025 10:35:18 +0800
|
||||
|
||||
fastfetch (2.38.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.38.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 05 Mar 2025 14:56:24 +0800
|
||||
|
||||
fastfetch (2.37.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.37.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 19 Feb 2025 15:43:42 +0800
|
||||
|
||||
fastfetch (2.36.1) jammy; urgency=medium
|
||||
|
||||
* Update to 2.36.1
|
||||
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ Source: fastfetch
|
||||
Section: universe/utils
|
||||
Priority: optional
|
||||
Maintainer: Carter Li <zhangsongcui@live.cn>
|
||||
Build-Depends: 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, libosmesa6-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
|
||||
Build-Depends: 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, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
|
||||
Standards-Version: 4.0.0
|
||||
Homepage: https://github.com/fastfetch-cli/fastfetch
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
fastfetch_2.36.1_source.buildinfo universe/utils optional
|
||||
fastfetch_2.39.1_source.buildinfo universe/utils optional
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"diskFormat": {
|
||||
"description": "Output format of the module `Disk`. See `-h format` for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation",
|
||||
"description": "Output format of the module `Disk`. See `-h format` for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter\n 21. {mount-from}: Mount from (device path)",
|
||||
"type": "string"
|
||||
},
|
||||
"diskioFormat": {
|
||||
@@ -207,7 +207,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"gpuFormat": {
|
||||
"description": "Output format of the module `GPU`. See `-h format` for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index",
|
||||
"description": "Output format of the module `GPU`. See `-h format` for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num (supports Nvidia & Apple GPU only)\n 19. {core-usage-bar}: Core usage percentage bar (supports Nvidia & Apple GPU only)",
|
||||
"type": "string"
|
||||
},
|
||||
"hostFormat": {
|
||||
@@ -279,7 +279,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"packagesFormat": {
|
||||
"description": "Output format of the module `Packages`. See `-h format` 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. {nix-all}: Total number of all nix packages\n 40. {flatpak-all}: Total number of all flatpak app packages\n 41. {brew-all}: Total number of all brew packages\n 42. {guix-all}: Total number of all guix packages",
|
||||
"description": "Output format of the module `Packages`. See `-h format` 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",
|
||||
"type": "string"
|
||||
},
|
||||
"physicaldiskFormat": {
|
||||
@@ -786,11 +786,11 @@
|
||||
},
|
||||
{
|
||||
"const": "si",
|
||||
"description": "1000 Bytes = 1 KB, 1000 KB = 1 MB, ..."
|
||||
"description": "1000 Bytes = 1 kB, 1000 kB = 1 MB, ..."
|
||||
},
|
||||
{
|
||||
"const": "jedec",
|
||||
"description": "1024 Bytes = 1 kB, 1024 K = 1 MB, ..."
|
||||
"description": "1024 Bytes = 1 KB, 1024 KB = 1 MB, ..."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -2563,8 +2563,7 @@
|
||||
"enum": [
|
||||
"auto",
|
||||
"egl",
|
||||
"glx",
|
||||
"osmesa"
|
||||
"glx"
|
||||
],
|
||||
"default": "auto"
|
||||
},
|
||||
@@ -2652,6 +2651,7 @@
|
||||
"pacman",
|
||||
"pacstall",
|
||||
"paludis",
|
||||
"pisi",
|
||||
"pkg",
|
||||
"pkgtool",
|
||||
"qi",
|
||||
|
||||
+11
-11
@@ -28,38 +28,38 @@
|
||||
{
|
||||
"type": "title",
|
||||
"key": "{#90}{$1}│ {#92}User {#90}│",
|
||||
"format": "{$2}{$3}{user-name} {#2}[{home-dir}]"
|
||||
"format": "{$2}{$3}{user-name} {#2}[{home-dir}]"
|
||||
},
|
||||
{
|
||||
"type": "users",
|
||||
"key": "{#90}{$1}│ {#92}Users {#90}│",
|
||||
"myselfOnly": false,
|
||||
"format": "{$2}{$3}{1}@{host-name}{/host-name}localhost{/}{?client-ip} {#2}[IP:{client-ip}]{?} {#2}[Login time: {login-time}]",
|
||||
"format": "{$2}{$3}{1}@{host-name}{/host-name}localhost{/}{?client-ip} {#2}[IP:{client-ip}]{?} [Login time: {login-time}]"
|
||||
},
|
||||
{
|
||||
"type": "datetime",
|
||||
"key": "{#90}{$1}│ {#92}Datetime {#90}│",
|
||||
"format": "{$2}{$3}{year}-{month-pretty}-{day-in-month} {hour-pretty}:{minute-pretty}:{second-pretty} {#2}{weekday} {#2}[W{week}] {#2}[UTC{offset-from-utc}]"
|
||||
"format": "{$2}{$3}{year}-{month-pretty}-{day-in-month} {hour-pretty}:{minute-pretty}:{second-pretty} [{weekday}] [W{week}] [UTC{offset-from-utc}]"
|
||||
},
|
||||
{
|
||||
"type": "title",
|
||||
"key": "{#90}{$1}│ {#93}Host: {#90}│",
|
||||
"format": "{$2}{$3}{#1}{#36}{host-name}"
|
||||
"key": "{#90}{$1}│ {#93}Host {#90}│",
|
||||
"format": "{$2}{$3}{host-name}"
|
||||
},
|
||||
{
|
||||
"type": "host",
|
||||
"key": "{#90}{$1}│ {#93}Machine {#90}│",
|
||||
"format": "{$2}{$3}{name} {#2}{version}"
|
||||
"format": "{$2}{$3}{name} {#2}{version}"
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "{#90}{$1}│ {#93}OS {#90}│",
|
||||
"format": "{$2}{$3}{pretty-name} {codename} {#2}[v{version}] {#2}[{arch}]"
|
||||
"format": "{$2}{$3}{?pretty-name}{pretty-name}{?}{/pretty-name}{name}{/} {codename} {#2}[v{version}] [{arch}]"
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"key": "{#90}{$1}│ {#93}Kernel {#90}│",
|
||||
"format": "{$2}{$3}{sysname} {#2}[v{release}]"
|
||||
"format": "{$2}{$3}{sysname} {#2}[v{release}]"
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
@@ -71,14 +71,14 @@
|
||||
"key": "{#90}{$1}│ {#91}CPU {#90}│",
|
||||
"showPeCoreCount": true,
|
||||
"temp": true,
|
||||
"format": "{$2}{$3}{name} {#2}[C:{core-types}] {#2}[{freq-max}]"
|
||||
"format": "{$2}{$3}{name} {#2}[C:{core-types}] [{freq-max}]"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "{#90}{$1}│ {#91}GPU {#90}│",
|
||||
"detectionMethod": "auto",
|
||||
"driverSpecific": true,
|
||||
"format": "{$2}{$3}{name} {#2}[C:{core-count}] {#2}[{type}]"
|
||||
"format": "{$2}{$3}{name} {#2}[C:{core-count}]{?frequency} [{frequency}]{?} [{type}]"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
@@ -98,7 +98,7 @@
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "{#90}{$1}│ {#95}Terminal {#90}│",
|
||||
"format": "{$2}{$3}{pretty-name} {#2}[{version}] [PID:{pid}]"
|
||||
"format": "{$2}{$3}{pretty-name} {#2}[{version}] [PID:{pid}]"
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
// Based on #1576
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"display": {
|
||||
"color": {
|
||||
"keys": "blue"
|
||||
},
|
||||
"separator": "",
|
||||
"constants": [
|
||||
"──────────────────────────────────────────────",
|
||||
"\u001b[47D",
|
||||
"\u001b[47C",
|
||||
"\u001b[46C"
|
||||
],
|
||||
"brightColor": false
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "version",
|
||||
"key": "┌───────────────┬─{$1}┐\u001b[41D",
|
||||
"format": "\u001b[1m{#keys} {1} - {2} "
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "datetime",
|
||||
"key": "│ {icon} Fetched │{$3}│{$2}",
|
||||
"format": "{year}-{month-pretty}-{day-pretty} {hour-pretty}:{minute-pretty}:{second-pretty} {timezone-name}"
|
||||
},
|
||||
{
|
||||
"type": "locale",
|
||||
"key": "│ {icon} Locale │{$3}│{$2}"
|
||||
},
|
||||
|
||||
// Hardware
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#cyan}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"format": "{#bright_cyan} Hardware "
|
||||
},
|
||||
{
|
||||
"type": "chassis",
|
||||
"key": "│{#cyan}│ {icon} Chassis │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│{#cyan}│ {icon} RAM │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "swap",
|
||||
"key": "│{#cyan}│ {icon} SWAP │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "cpu",
|
||||
"key": "│{#cyan}│ {icon} CPU │{$4}│{#keys}│{$2}",
|
||||
"showPeCoreCount": true
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│{#cyan}│ {icon} GPU │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": "│{#cyan}│ {icon} Disk │{$4}│{#keys}│{$2}",
|
||||
"format": "{size-used} \/ {size-total} ({size-percentage}) - {filesystem}",
|
||||
},
|
||||
{
|
||||
"type": "battery",
|
||||
"key": "│{#cyan}│ {icon} Battery │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#cyan}└──────────────┴{$1}┘{#keys}│",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Desktop
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#green}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"format": "{#bright_green} Desktop "
|
||||
},
|
||||
{
|
||||
"type": "de",
|
||||
"key": "│{#green}│ {icon} Desktop │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "│{#green}│ {icon} Session │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "display",
|
||||
"key": "│{#green}│ {icon} Display │{$4}│{#keys}│{$2}",
|
||||
"compactType": "original-with-refresh-rate"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│{#green}│ {icon} G-Driver │{$4}│{#keys}│{$2}",
|
||||
"format": "{driver}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#green}└──────────────┴{$1}┘{#keys}│",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Terminal
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#yellow}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"format": "{#bright_yellow} Terminal "
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"key": "│{#yellow}│ {icon} Shell │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "│{#yellow}│ {icon} Terminal │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
"key": "│{#yellow}│ {icon} Term Font │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminaltheme",
|
||||
"key": "│{#yellow}│ {icon} Colors │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "packages",
|
||||
"key": "│{#yellow}│ {icon} Packages │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#yellow}└──────────────┴{$1}┘{#keys}│",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Development
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#red}┌──────────────┬{$1}┐{#keys}│\u001b[39D",
|
||||
"format": "{#bright_red} Development "
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Rust │{$4}│{#keys}│{$2}",
|
||||
"text": "rustc --version | cut -d' ' -f2",
|
||||
"format": "rustc {}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
|
||||
"text": "clang --version | head -1 | awk '{print $NF}'",
|
||||
"format": "clang {}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} NodeJS │{$4}│{#keys}│{$2}",
|
||||
"text": "node --version",
|
||||
"format": "node {~1}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Go │{$4}│{#keys}│{$2}",
|
||||
"text": "go version | cut -d' ' -f3",
|
||||
"format": "go {~2}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Zig │{$4}│{#keys}│{$2}",
|
||||
"text": "zig version",
|
||||
"format": "zig {}"
|
||||
},
|
||||
{
|
||||
"type": "editor",
|
||||
"key": "│{#red}│ {icon} Editor │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Git │{$4}│{#keys}│{$2}",
|
||||
"text": "git version",
|
||||
"format": "git {~12}"
|
||||
},
|
||||
{
|
||||
"type": "font",
|
||||
"key": "│{#red}│ {icon} Interface │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#red}└──────────────┴{$1}┘{#keys}│",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Uptime
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#magenta}┌──────────────┬{$1}┐{#keys}│\u001b[36D",
|
||||
"format": "{#bright_magenta} Uptime "
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"key": "│{#magenta}│ {icon} Uptime │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "users",
|
||||
"myselfOnly": true,
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"folders": "/", // On macOS, "/System/Volumes/VM" works for me
|
||||
"format": "{create-time:10} [{days} days]"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#magenta}└──────────────┴{$1}┘{#keys}│",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "└─────────────────{$1}┘",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// End
|
||||
"break",
|
||||
"colors"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
// Modified from: 24.jsonc
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"padding": {
|
||||
"top": 2
|
||||
}
|
||||
},
|
||||
"display": {
|
||||
"separator": "",
|
||||
"constants": [
|
||||
// CONSTANT {$1} - VERTICAL BARS AT START AND 75th CHARACTERS FORWARD AND BACKWARD
|
||||
"\u001b[90m│ │\u001b[60D\u001b[39m"
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
// CUSTOM - Top UI bar
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "{#90}╭ Keys ───────╮",
|
||||
"format": "{#90}╭ Values ────────────────────────────────────────────────────╮",
|
||||
},
|
||||
{
|
||||
"type": "title",
|
||||
"key": "{#90}│ {#92}User {#90}│",
|
||||
"format": "{$1}{user-name} {#2}[{home-dir}]"
|
||||
},
|
||||
{
|
||||
"type": "users",
|
||||
"key": "{#90}│ {#92}Users {#90}│",
|
||||
"myselfOnly": false,
|
||||
"format": "{$1}{1}@{host-name}{/host-name}localhost{/}{?client-ip} {#2}[IP:{client-ip}]{?} [Login time: {login-time}]"
|
||||
},
|
||||
{
|
||||
"type": "datetime",
|
||||
"key": "{#90}│ {#92}Datetime {#90}│",
|
||||
"format": "{$1}{year}-{month-pretty}-{day-in-month} {hour-pretty}:{minute-pretty}:{second-pretty} {#2}[{weekday}] [W{week}] [UTC{offset-from-utc}]"
|
||||
},
|
||||
{
|
||||
"type": "title",
|
||||
"key": "{#90}│ {#93}Host {#90}│",
|
||||
"format": "{$1}{host-name}"
|
||||
},
|
||||
{
|
||||
"type": "host",
|
||||
"key": "{#90}│ {#93}Machine {#90}│",
|
||||
"format": "{$1}{name} {#2}{version}"
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "{#90}│ {#93}OS {#90}│",
|
||||
"format": "{$1}{?pretty-name}{pretty-name}{?}{/pretty-name}{name}{/} {codename} {#2}[v{version}] [{arch}]"
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"key": "{#90}│ {#93}Kernel {#90}│",
|
||||
"format": "{$1}{sysname} {#2}[v{release}]"
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"key": "{#90}│ {#93}Uptime {#90}│",
|
||||
"format": "{$1}{?days}{days} Days + {?}{hours}:{minutes}:{seconds}"
|
||||
},
|
||||
{
|
||||
"type": "cpu",
|
||||
"key": "{#90}│ {#91}CPU {#90}│",
|
||||
"showPeCoreCount": true,
|
||||
"temp": true,
|
||||
"format": "{$1}{name} {#2}[C:{core-types}] [{freq-max}]"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "{#90}│ {#91}GPU {#90}│",
|
||||
"detectionMethod": "auto",
|
||||
"driverSpecific": true,
|
||||
"format": "{$1}{name} {#2}[C:{core-count}]{?frequency} [{frequency}]{?} {#2}[{type}]"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "{#90}│ {#91}Memory {#90}│",
|
||||
"format": "{$1}{used} / {total} ({percentage})"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": "{#90}│ {#91}Disk {#90}│",
|
||||
"format": "{$1}{size-used} / {size-total} ({size-percentage})"
|
||||
},
|
||||
{
|
||||
"type": "poweradapter",
|
||||
"key": "{#90}│ {#91}Power {#90}│",
|
||||
"format": "{$1}{name}"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "{#90}│ {#95}Terminal {#90}│",
|
||||
"format": "{$1}{pretty-name} {#2}[{version}] [PID:{pid}]"
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
"key": "{#90}│ {#95}Font {#90}│",
|
||||
"format": "{$1}{name} {#2}[{size}]"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"key": "{#90}│ {#95}Shell {#90}│",
|
||||
"format": "{$1}{pretty-name} {#2}[v{version}] [PID:{pid}]"
|
||||
},
|
||||
{
|
||||
// localip IPv4
|
||||
"type": "localip",
|
||||
"key": "{#90}│ {#94}Local IPv4 {#90}│",
|
||||
"showPrefixLen": true,
|
||||
"showIpv4": true,
|
||||
"showIpv6": false,
|
||||
"showMtu": true,
|
||||
"format": "{$1}{ifname}: {ipv4} {#2}[MTU:{mtu}]"
|
||||
},
|
||||
{
|
||||
// localip IPv6
|
||||
"type": "localip",
|
||||
"key": "{#90}│ {#94}Local IPv6 {#90}│",
|
||||
"showPrefixLen": true,
|
||||
"showIpv4": false,
|
||||
"showIpv6": true,
|
||||
"showMtu": true,
|
||||
"format": "{$1}{ifname}: {ipv6} {#2}[MTU:{mtu}]"
|
||||
},
|
||||
{
|
||||
"type": "publicip",
|
||||
"key": "{#90}│ {#94}Public IPv4 {#90}│",
|
||||
"ipv6": false,
|
||||
"format": "{$1}{ip} {#2}[{location}]"
|
||||
},
|
||||
{
|
||||
"type": "publicip",
|
||||
"key": "{#90}│ {#94}Public IPv6 {#90}│",
|
||||
"ipv6": true,
|
||||
"format": "{$1}{ip} {#2}[{location}]"
|
||||
},
|
||||
// CUSTOM - Button UI bar
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "{#90}╰─────────────╯",
|
||||
"format": "{#90}╰────────────────────────────────────────────────────────────╯",
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"key": " ",
|
||||
"format": "{#90}╭ Colors ───────────────────────────────────────────────────────────────────╮",
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "{#90}│ {#40} {#41} {#42} {#43} {#44} {#45} {#46} {#47} {#} {#90}│",
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "{#90}│ {#100} {#101} {#102} {#103} {#104} {#105} {#106} {#107} {#} {#90}│",
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "{#90}╰───────────────────────────────────────────────────────────────────────────╯",
|
||||
},
|
||||
]
|
||||
}
|
||||
Vendored
-383
@@ -1,383 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
/// \file
|
||||
/// \mainpage
|
||||
/// AGS Library Overview
|
||||
/// --------------------
|
||||
/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query
|
||||
/// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs.
|
||||
///
|
||||
/// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/.
|
||||
/// It is also worth checking http://gpuopen.com/gaming-product/amd-gpu-services-ags-library/ for any updates and articles on AGS.
|
||||
/// \internal
|
||||
/// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/
|
||||
/// \endinternal
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 6.2 since version 6.1
|
||||
/// ---------------------------------------
|
||||
/// AGS 6.2 includes the following updates:
|
||||
/// * Shader clock intrinsics
|
||||
/// * Minor improvements and fixes
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 6.1 since version 6.0
|
||||
/// ---------------------------------------
|
||||
/// AGS 6.1 includes the following updates:
|
||||
/// * RDNA3 detection
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 6.0 since version 5.4.2
|
||||
/// ---------------------------------------
|
||||
/// AGS 6.0 includes the following updates:
|
||||
/// * DX12 ray tracing hit token for RDNA2 hardware.
|
||||
/// * Shader intrinsic that exposes ReadLaneAt in DX12.
|
||||
/// * Shader intrinsics that expose explicit float conversions in DX12.
|
||||
/// * Refactored and revised API to minimize user error.
|
||||
/// * Added agsGetVersionNumber.
|
||||
/// * Detection for external GPUs.
|
||||
/// * Detection of RDNA2 architecture.
|
||||
/// * Grouped the more established intrinsics together into per year support.
|
||||
/// * Function pointer typedefs for the API
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 5.4.2 since version 5.4.1
|
||||
/// ---------------------------------------
|
||||
/// AGS 5.4.2 includes the following updates:
|
||||
/// * sharedMemoryInBytes has been reinstated.
|
||||
/// * Clock speed returned for APUs.
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 5.4.1 since version 5.4.0
|
||||
/// ---------------------------------------
|
||||
/// AGS 5.4.1 includes the following updates:
|
||||
/// * AsicFamily_Count to help with code maintenance.
|
||||
/// * Visual Studio 2019 support.
|
||||
/// * x86 support
|
||||
/// * BaseInstance and BaseVertex intrinsics along with corresponding caps bits.
|
||||
/// * GetWaveSize intrinsic along with corresponding caps bits.
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 5.4 since version 5.3
|
||||
/// ---------------------------------------
|
||||
/// AGS 5.4 includes the following updates:
|
||||
/// * A more detailed description of the GPU architecture, now including RDNA GPUs.
|
||||
/// * Radeon 7 core and memory speeds returned.
|
||||
/// * Draw index and Atomic U64 intrinsics for both DX11 and DX12.
|
||||
///
|
||||
/// ---------------------------------------
|
||||
/// What's new in AGS 5.3 since version 5.2
|
||||
/// ---------------------------------------
|
||||
/// AGS 5.3 includes the following updates:
|
||||
/// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions.
|
||||
/// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements.
|
||||
/// * Freesync HDR Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync HDR scRGB.
|
||||
///
|
||||
/// Using the AGS library
|
||||
/// ---------------------
|
||||
/// It is recommended to take a look at the source code for the samples that come with the AGS SDK:
|
||||
/// * AGSSample
|
||||
/// * CrossfireSample
|
||||
/// * EyefinitySample
|
||||
/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state.
|
||||
/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more
|
||||
/// extensive example of Eyefinity setup than the basic example provided in AGSSample.
|
||||
/// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples.
|
||||
///
|
||||
/// To add AGS support to an existing project, follow these steps:
|
||||
/// * Link your project against the correct import library. Choose from either the 32 bit or 64 bit version.
|
||||
/// * Copy the AGS dll into the same directory as your game executable.
|
||||
/// * Include the amd_ags.h header file from your source code.
|
||||
/// * Include the AGS hlsl files if you are using the shader intrinsics.
|
||||
/// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS.
|
||||
/// * On game initialization, call \ref agsInitialize passing in the address of the context. On success, this function will return a valid context pointer.
|
||||
///
|
||||
/// Don't forget to cleanup AGS by calling \ref agsDeInitialize when the app exits, after the device has been destroyed.
|
||||
|
||||
#ifndef AMD_AGS_H
|
||||
#define AMD_AGS_H
|
||||
|
||||
#define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version
|
||||
#define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version
|
||||
#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// \defgroup Defines AGS defines
|
||||
/// @{
|
||||
#if defined (AGS_GCC)
|
||||
#define AMD_AGS_API
|
||||
#else
|
||||
#define AMD_AGS_API __declspec(dllexport) ///< AGS exported functions
|
||||
#endif
|
||||
|
||||
#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version
|
||||
#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version
|
||||
#define AGS_CURRENT_VERSION AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ) ///< Macro to return the current AGS version as defined by the AGS header file
|
||||
/// @}
|
||||
|
||||
/// \defgroup enums General enumerations
|
||||
/// @{
|
||||
|
||||
/// The return codes
|
||||
typedef enum AGSReturnCode
|
||||
{
|
||||
AGS_SUCCESS, ///< Successful function call
|
||||
AGS_FAILURE, ///< Failed to complete call for some unspecified reason
|
||||
AGS_INVALID_ARGS, ///< Invalid arguments into the function
|
||||
AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally
|
||||
AGS_MISSING_D3D_DLL, ///< Returned when a D3D dll fails to load
|
||||
AGS_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver
|
||||
AGS_NO_AMD_DRIVER_INSTALLED, ///< Returned if the AMD GPU driver does not appear to be installed
|
||||
AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension
|
||||
AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library)
|
||||
AGS_DX_FAILURE, ///< Failure from DirectX runtime
|
||||
AGS_D3DDEVICE_NOT_CREATED ///< Failure due to not creating the D3D device successfully via AGS.
|
||||
} AGSReturnCode;
|
||||
|
||||
/// @}
|
||||
|
||||
typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInitialize
|
||||
|
||||
/// The rectangle struct used by AGS.
|
||||
typedef struct AGSRect
|
||||
{
|
||||
int offsetX; ///< Offset on X axis
|
||||
int offsetY; ///< Offset on Y axis
|
||||
int width; ///< Width of rectangle
|
||||
int height; ///< Height of rectangle
|
||||
} AGSRect;
|
||||
|
||||
/// The display info struct used to describe a display enumerated by AGS
|
||||
typedef struct AGSDisplayInfo
|
||||
{
|
||||
char name[ 256 ]; ///< The name of the display
|
||||
char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName
|
||||
|
||||
unsigned int isPrimaryDisplay : 1; ///< Whether this display is marked as the primary display
|
||||
unsigned int HDR10 : 1; ///< HDR10 is supported on this display
|
||||
unsigned int dolbyVision : 1; ///< Dolby Vision is supported on this display
|
||||
unsigned int freesync : 1; ///< Freesync is supported on this display
|
||||
unsigned int freesyncHDR : 1; ///< Freesync HDR is supported on this display
|
||||
unsigned int eyefinityInGroup : 1; ///< The display is part of the Eyefinity group
|
||||
unsigned int eyefinityPreferredDisplay : 1; ///< The display is the preferred display in the Eyefinity group for displaying the UI
|
||||
unsigned int eyefinityInPortraitMode : 1; ///< The display is in the Eyefinity group but in portrait mode
|
||||
unsigned int reservedPadding : 24; ///< Reserved for future use
|
||||
|
||||
int maxResolutionX; ///< The maximum supported resolution of the unrotated display
|
||||
int maxResolutionY; ///< The maximum supported resolution of the unrotated display
|
||||
float maxRefreshRate; ///< The maximum supported refresh rate of the display
|
||||
|
||||
AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation
|
||||
AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will
|
||||
///< be the sub region in the Eyefinity single large surface (SLS)
|
||||
float currentRefreshRate; ///< The current refresh rate
|
||||
|
||||
int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group
|
||||
int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group
|
||||
|
||||
double chromaticityRedX; ///< Red display primary X coord
|
||||
double chromaticityRedY; ///< Red display primary Y coord
|
||||
|
||||
double chromaticityGreenX; ///< Green display primary X coord
|
||||
double chromaticityGreenY; ///< Green display primary Y coord
|
||||
|
||||
double chromaticityBlueX; ///< Blue display primary X coord
|
||||
double chromaticityBlueY; ///< Blue display primary Y coord
|
||||
|
||||
double chromaticityWhitePointX; ///< White point X coord
|
||||
double chromaticityWhitePointY; ///< White point Y coord
|
||||
|
||||
double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1
|
||||
double screenSpecularReflectance; ///< Percentage expressed between 0 - 1
|
||||
|
||||
double minLuminance; ///< The minimum luminance of the display in nits
|
||||
double maxLuminance; ///< The maximum luminance of the display in nits
|
||||
double avgLuminance; ///< The average luminance of the display in nits
|
||||
|
||||
int logicalDisplayIndex; ///< The internally used index of this display
|
||||
int adlAdapterIndex; ///< The internally used ADL adapter index
|
||||
int reserved; ///< reserved field
|
||||
} AGSDisplayInfo;
|
||||
|
||||
/// The ASIC family
|
||||
typedef enum AsicFamily
|
||||
{
|
||||
AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId
|
||||
AsicFamily_PreGCN, ///< Pre GCN architecture.
|
||||
AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti.
|
||||
AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo.
|
||||
AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji.
|
||||
AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris.
|
||||
AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU).
|
||||
AsicFamily_RDNA, ///< AMD RDNA architecture
|
||||
AsicFamily_RDNA2, ///< AMD RDNA2 architecture
|
||||
AsicFamily_RDNA3, ///< AMD RDNA3 architecture
|
||||
|
||||
AsicFamily_Count ///< Number of enumerated ASIC families
|
||||
} AsicFamily;
|
||||
|
||||
/// The device info struct used to describe a physical GPU enumerated by AGS
|
||||
typedef struct AGSDeviceInfo
|
||||
{
|
||||
const char* adapterString; ///< The adapter name string
|
||||
AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware
|
||||
unsigned int isAPU : 1; ///< Whether this device is an APU
|
||||
unsigned int isPrimaryDevice : 1; ///< Whether this device is marked as the primary device
|
||||
unsigned int isExternal :1; ///< Whether this device is a detachable, external device
|
||||
unsigned int reservedPadding : 29; ///< Reserved for future use
|
||||
|
||||
int vendorId; ///< The vendor id
|
||||
int deviceId; ///< The device id
|
||||
int revisionId; ///< The revision id
|
||||
|
||||
int numCUs; ///< Number of compute units
|
||||
int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards.
|
||||
|
||||
int numROPs; ///< Number of ROPs
|
||||
int coreClock; ///< Core clock speed at 100% power in MHz
|
||||
int memoryClock; ///< Memory clock speed at 100% power in MHz
|
||||
int memoryBandwidth; ///< Memory bandwidth in MB/s
|
||||
float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD
|
||||
|
||||
unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware.
|
||||
unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs
|
||||
///< as the reported local memory will only be a small fraction of the total memory available to the GPU.
|
||||
|
||||
int numDisplays; ///< The number of active displays found to be attached to this adapter.
|
||||
AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length.
|
||||
|
||||
int eyefinityEnabled; ///< Indicates if Eyefinity is active
|
||||
int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface.
|
||||
int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface.
|
||||
int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface.
|
||||
int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface.
|
||||
int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled.
|
||||
|
||||
int adlAdapterIndex; ///< Internally used index into the ADL list of adapters
|
||||
int reserved; ///< reserved field
|
||||
} AGSDeviceInfo;
|
||||
|
||||
/// \defgroup general General API functions
|
||||
/// API for initialization, cleanup, HDR display modes and Crossfire GPU count
|
||||
/// @{
|
||||
|
||||
typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype
|
||||
typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype
|
||||
|
||||
/// The configuration options that can be passed in to \ref agsInitialize
|
||||
typedef struct AGSConfiguration
|
||||
{
|
||||
AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used
|
||||
AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used
|
||||
} AGSConfiguration;
|
||||
|
||||
/// The top level GPU information returned from \ref agsInitialize
|
||||
typedef struct AGSGPUInfo
|
||||
{
|
||||
const char* driverVersion; ///< The AMD driver package version
|
||||
const char* radeonSoftwareVersion; ///< The Radeon Software Version
|
||||
|
||||
int numDevices; ///< Number of GPUs in the system
|
||||
AGSDeviceInfo* devices; ///< List of GPUs in the system
|
||||
} AGSGPUInfo;
|
||||
|
||||
/// The struct to specify the display settings to the driver.
|
||||
typedef struct AGSDisplaySettings AGSDisplaySettings;
|
||||
|
||||
|
||||
/// The result returned from \ref agsCheckDriverVersion
|
||||
typedef enum AGSDriverVersionResult
|
||||
{
|
||||
AGS_SOFTWAREVERSIONCHECK_OK, ///< The reported Radeon Software Version is newer or the same as the required version
|
||||
AGS_SOFTWAREVERSIONCHECK_OLDER, ///< The reported Radeon Software Version is older than the required version
|
||||
AGS_SOFTWAREVERSIONCHECK_UNDEFINED ///< The check could not determine as result. This could be because it is a private or custom driver or just invalid arguments.
|
||||
} AGSDriverVersionResult;
|
||||
|
||||
///
|
||||
/// Helper function to check the installed software version against the required software version.
|
||||
///
|
||||
/// \param [in] radeonSoftwareVersionReported The Radeon Software Version returned from \ref AGSGPUInfo::radeonSoftwareVersion.
|
||||
/// \param [in] radeonSoftwareVersionRequired The Radeon Software Version to check against. This is specificed using \ref AGS_MAKE_VERSION.
|
||||
/// \return The result of the check.
|
||||
///
|
||||
AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired );
|
||||
|
||||
///
|
||||
/// Function to return the AGS version number.
|
||||
///
|
||||
/// \return The version number made using AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ).
|
||||
///
|
||||
AMD_AGS_API int agsGetVersionNumber();
|
||||
|
||||
///
|
||||
/// Function used to initialize the AGS library.
|
||||
/// agsVersion must be specified as AGS_CURRENT_VERSION or the call will return \ref AGS_INVALID_ARGS.
|
||||
/// Must be called prior to any of the subsequent AGS API calls.
|
||||
/// Must be called prior to ID3D11Device or ID3D12Device creation.
|
||||
/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInitialize if there is an AMD GPU present.
|
||||
/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system.
|
||||
/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20.
|
||||
///
|
||||
/// \param [in] agsVersion The API version specified using the \ref AGS_CURRENT_VERSION macro. If this does not match the version in the binary this initialization call will fail.
|
||||
/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration.
|
||||
/// \param [out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls.
|
||||
/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system.
|
||||
///
|
||||
AMD_AGS_API AGSReturnCode agsInitialize( int agsVersion, const AGSConfiguration* config, AGSContext** context, AGSGPUInfo* gpuInfo );
|
||||
|
||||
///
|
||||
/// Function used to clean up the AGS library.
|
||||
///
|
||||
/// \param [in] context Pointer to a context. This function will deallocate the context from the heap.
|
||||
///
|
||||
AMD_AGS_API AGSReturnCode agsDeInitialize( AGSContext* context );
|
||||
|
||||
///
|
||||
/// Function used to set a specific display into HDR mode
|
||||
/// \note Setting all of the values apart from color space and transfer function to zero will cause the display to use defaults.
|
||||
/// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc).
|
||||
/// \note HDR10 PQ mode requires a 1010102 swapchain.
|
||||
/// \note HDR10 scRGB mode requires an FP16 swapchain.
|
||||
/// \note Freesync HDR scRGB mode requires an FP16 swapchain.
|
||||
/// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain.
|
||||
/// \note Dolby Vision requires a 8888 UNORM swapchain.
|
||||
///
|
||||
/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize
|
||||
/// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices.
|
||||
/// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays.
|
||||
/// \param [in] settings Pointer to the display settings to use.
|
||||
///
|
||||
AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceIndex, int displayIndex, const AGSDisplaySettings* settings );
|
||||
|
||||
/// @}
|
||||
|
||||
/// @}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // AMD_AGS_H
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"home": "https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK",
|
||||
"license": "MIT (embeded in source)",
|
||||
"version": "AGS v6.2.0",
|
||||
"author": "Advanced Micro Devices, Inc",
|
||||
"modified": "CarterLi"
|
||||
}
|
||||
+2596
File diff suppressed because it is too large
Load Diff
+46
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Copyright (c) 2016 - 2022 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// MIT LICENSE:
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
/// \file adl_sdk.h
|
||||
/// \brief Contains the definition of the Memory Allocation Callback.\n <b>Included in ADL SDK</b>
|
||||
///
|
||||
/// \n\n
|
||||
/// This file contains the definition of the Memory Allocation Callback.\n
|
||||
/// It also includes definitions of the respective structures and constants.\n
|
||||
/// <b> This is the only header file to be included in a C/C++ project using ADL </b>
|
||||
|
||||
#ifndef ADL_SDK_H_
|
||||
#define ADL_SDK_H_
|
||||
|
||||
#include "adl_structures.h"
|
||||
|
||||
#if defined (LINUX)
|
||||
#define __stdcall
|
||||
#endif /* (LINUX) */
|
||||
|
||||
/// Memory Allocation Call back
|
||||
typedef void* ( __stdcall *ADL_MAIN_MALLOC_CALLBACK )( int );
|
||||
|
||||
#define ADL_SDK_MAJOR_VERSION 17
|
||||
#define ADL_SDK_MINOR_VERSION 1
|
||||
|
||||
#endif /* ADL_SDK_H_ */
|
||||
+4289
File diff suppressed because it is too large
Load Diff
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/GPUOpen-LibrariesAndSDKs/display-library",
|
||||
"license": "MIT (embeded in source)",
|
||||
"version": "ADL SDK 17.1",
|
||||
"author": "Advanced Micro Devices, Inc"
|
||||
}
|
||||
@@ -227,9 +227,6 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_GLX
|
||||
"glx\n"
|
||||
#endif
|
||||
#if FF_HAVE_OSMESA
|
||||
"osmesa\n"
|
||||
#endif
|
||||
#if FF_HAVE_OPENCL
|
||||
"opencl\n"
|
||||
#endif
|
||||
|
||||
@@ -256,6 +256,11 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
|
||||
bool ffSuppressIO(bool suppress)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (instance.config.display.debugMode)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
static bool init = false;
|
||||
static int origOut = -1;
|
||||
static int origErr = -1;
|
||||
|
||||
@@ -159,6 +159,11 @@ bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
|
||||
bool ffSuppressIO(bool suppress)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (instance.config.display.debugMode)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
static bool init = false;
|
||||
static HANDLE hOrigOut = INVALID_HANDLE_VALUE;
|
||||
static HANDLE hOrigErr = INVALID_HANDLE_VALUE;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#else
|
||||
#define IF_NAMESIZE 16
|
||||
#define IF_NAMESIZE 0
|
||||
#endif
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "netif.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
@@ -8,13 +9,17 @@
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
#elif defined(__NetBSD__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
|
||||
#elif defined(__FreeBSD__)
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
#elif defined(__OpenBSD__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
@@ -47,6 +52,39 @@ get_rt_address(struct rt_msghdr *rtm, int desired)
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY};
|
||||
size_t needed;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
|
||||
return false;
|
||||
|
||||
FF_AUTO_FREE char* buf = malloc(needed);
|
||||
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
|
||||
return false;
|
||||
|
||||
char* lim = buf + needed;
|
||||
struct rt_msghdr* rtm;
|
||||
for (char* next = buf; next < lim; next += rtm->rtm_msglen)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
|
||||
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && (sa->sa_family == AF_INET))
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl->sdl_family == AF_LINK)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(iface, sdl->sdl_data, sdl->sdl_nlen);
|
||||
iface[sdl->sdl_nlen] = '\0';
|
||||
*ifIndex = sdl->sdl_index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET);
|
||||
@@ -106,5 +144,7 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
static bool getDefaultRouteIPv4(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/route", "r");
|
||||
if (!netRoute) return false;
|
||||
@@ -15,12 +15,38 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
// skip first line
|
||||
FF_UNUSED(fscanf(netRoute, "%*[^\n]\n"));
|
||||
|
||||
unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu,
|
||||
unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu, ...
|
||||
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", iface, &destination) == 2)
|
||||
{
|
||||
if (destination != 0) continue;
|
||||
*ifIndex = if_nametoindex(iface);
|
||||
return true;
|
||||
}
|
||||
iface[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool getDefaultRouteIPv6(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/ipv6_route", "r");
|
||||
if (!netRoute) return false;
|
||||
|
||||
uint32_t prefixLen;
|
||||
//destination, dest_prefix_len, source, src_prefix_len, next hop, metric, ref counter, use counter, flags, iface
|
||||
while (fscanf(netRoute, "%*s %x %*s %*s %*s %*s %*s %*s %*s %" FF_STR(IF_NAMESIZE) "s", &prefixLen, iface) == 2)
|
||||
{
|
||||
if (prefixLen != 0) continue;
|
||||
*ifIndex = if_nametoindex(iface);
|
||||
return true;
|
||||
}
|
||||
iface[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
if (getDefaultRouteIPv4(iface, ifIndex))
|
||||
return true;
|
||||
|
||||
return getDefaultRouteIPv6(iface, ifIndex);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,36 @@
|
||||
#include "netif.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
|
||||
#include <iphlpapi.h>
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(FF_MAYBE_UNUSED char* iface/* unsupported */, uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImpl(FF_MAYBE_UNUSED char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
ULONG size = 0;
|
||||
if (GetIpForwardTable(NULL, &size, TRUE) != ERROR_INSUFFICIENT_BUFFER)
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
DWORD result = GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable);
|
||||
|
||||
if (result != NO_ERROR)
|
||||
return false;
|
||||
|
||||
FF_AUTO_FREE MIB_IPFORWARDTABLE* pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(size);
|
||||
if (GetIpForwardTable(pIpForwardTable, &size, TRUE) != ERROR_SUCCESS)
|
||||
return false;
|
||||
bool foundDefault = false;
|
||||
|
||||
for (uint32_t i = 0; i < pIpForwardTable->dwNumEntries; ++i)
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
|
||||
{
|
||||
MIB_IPFORWARDROW* ipForwardRow = &pIpForwardTable->table[i];
|
||||
if (ipForwardRow->dwForwardDest == 0 && ipForwardRow->dwForwardMask == 0)
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if ((row->DestinationPrefix.PrefixLength == 0) &&
|
||||
((row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0) ||
|
||||
(row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr))))
|
||||
{
|
||||
*ifIndex = ipForwardRow->dwForwardIfIndex;
|
||||
*ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
FreeMibTable(pIpForwardTable);
|
||||
|
||||
return foundDefault;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,16 @@
|
||||
#include <minwindef.h>
|
||||
#endif
|
||||
|
||||
struct addrinfo;
|
||||
|
||||
typedef struct FFNetworkingState {
|
||||
#ifdef _WIN32
|
||||
uintptr_t sockfd;
|
||||
OVERLAPPED overlapped;
|
||||
#else
|
||||
int sockfd;
|
||||
FFstrbuf host;
|
||||
FFstrbuf command;
|
||||
struct addrinfo* addr;
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
FFThreadType thread;
|
||||
@@ -23,7 +25,14 @@ typedef struct FFNetworkingState {
|
||||
|
||||
uint32_t timeout;
|
||||
bool ipv6;
|
||||
bool compression; // if true, HTTP content compression will be enabled if supported
|
||||
bool tfo; // if true, TCP Fast Open will be attempted first, and fallback to traditional connection if it fails
|
||||
} FFNetworkingState;
|
||||
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers);
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer);
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
const char* ffNetworkingLoadZlibLibrary(void);
|
||||
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd);
|
||||
#endif
|
||||
@@ -0,0 +1,194 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/library.h"
|
||||
#include "common/networking/networking.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
#include <zlib.h>
|
||||
|
||||
struct FFZlibLibrary
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(inflateInit2_)
|
||||
FF_LIBRARY_SYMBOL(inflate)
|
||||
FF_LIBRARY_SYMBOL(inflateEnd)
|
||||
FF_LIBRARY_SYMBOL(inflateGetHeader)
|
||||
|
||||
bool inited;
|
||||
} zlibData;
|
||||
|
||||
const char* ffNetworkingLoadZlibLibrary(void)
|
||||
{
|
||||
if (!zlibData.inited)
|
||||
{
|
||||
zlibData.inited = true;
|
||||
FF_LIBRARY_LOAD(zlib, "dlopen libz failed",
|
||||
#ifdef _WIN32
|
||||
"zlib1"
|
||||
#else
|
||||
"libz"
|
||||
#endif
|
||||
FF_LIBRARY_EXTENSION, 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateInit2_)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflate)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateEnd)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateGetHeader)
|
||||
zlib = NULL; // don't auto dlclose
|
||||
}
|
||||
return zlibData.ffinflateEnd == NULL ? "Failed to load libz" : NULL;
|
||||
}
|
||||
|
||||
// Try to pre-read gzip header to determine uncompressed size
|
||||
static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize)
|
||||
{
|
||||
// gzip file format: http://www.zlib.org/rfc-gzip.html
|
||||
if (dataSize < 10 || ((const uint8_t*)data)[0] != 0x1f || ((const uint8_t*)data)[1] != 0x8b)
|
||||
return 0;
|
||||
|
||||
// Uncompressed size in gzip format is stored in the last 4 bytes, but only valid if data is less than 4GB
|
||||
if (dataSize > 18) {
|
||||
// Get ISIZE value from the end of file (little endian)
|
||||
const uint8_t* tail = (const uint8_t*)data + dataSize - 4;
|
||||
uint32_t uncompressedSize = (uint32_t) tail[0] | ((uint32_t) tail[1] << 8u) | ((uint32_t) tail[2] << 16u) | ((uint32_t) tail[3] << 24u);
|
||||
|
||||
// For valid gzip files, this value is the length of the uncompressed data modulo 2^32
|
||||
if (uncompressedSize > 0) {
|
||||
FF_DEBUG("Read uncompressed size from GZIP trailer: %u bytes", uncompressedSize);
|
||||
// Add some margin to the estimated size for safety
|
||||
return uncompressedSize + 64;
|
||||
}
|
||||
}
|
||||
|
||||
// If unable to get size from trailer or size is 0, use estimated value
|
||||
// Typically, text data compression ratio is between 3-5x, we use the larger value
|
||||
uint32_t estimatedSize = dataSize * 5;
|
||||
FF_DEBUG("Unable to read exact uncompressed size, estimated as 5x of compressed data: %u bytes", estimatedSize);
|
||||
return estimatedSize;
|
||||
}
|
||||
|
||||
// Decompress gzip content
|
||||
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
|
||||
{
|
||||
// Calculate header size
|
||||
uint32_t headerSize = (uint32_t) (headerEnd - buffer->chars);
|
||||
|
||||
*headerEnd = '\0'; // Replace delimiter with null character for easier processing
|
||||
// Ensure Content-Encoding is in response headers, not in response body
|
||||
bool hasGzip = strcasestr(buffer->chars, "\nContent-Encoding: gzip") != NULL;
|
||||
*headerEnd = '\r'; // Restore delimiter
|
||||
|
||||
if (!hasGzip) {
|
||||
FF_DEBUG("No gzip compressed content detected, skipping decompression");
|
||||
return true;
|
||||
}
|
||||
|
||||
FF_DEBUG("Gzip compressed content detected, preparing for decompression");
|
||||
|
||||
const char* bodyStart = headerEnd + 4; // Skip delimiter
|
||||
|
||||
// Calculate compressed content size
|
||||
uint32_t compressedSize = buffer->length - headerSize - 4;
|
||||
|
||||
if (compressedSize <= 0) {
|
||||
// No content to decompress
|
||||
FF_DEBUG("Compressed content size is 0, skipping decompression");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if content is actually in gzip format (gzip header magic is 0x1f 0x8b)
|
||||
if (compressedSize < 2 || (uint8_t)bodyStart[0] != 0x1f || (uint8_t)bodyStart[1] != 0x8b) {
|
||||
FF_DEBUG("Content is not valid gzip format, skipping decompression");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Predict uncompressed size
|
||||
uint32_t estimatedSize = guessGzipOutputSize(bodyStart, compressedSize);
|
||||
|
||||
// Create decompression buffer with estimated size
|
||||
FF_STRBUF_AUTO_DESTROY decompressedBuffer = ffStrbufCreateA(estimatedSize > 0 ? estimatedSize : compressedSize * 5);
|
||||
FF_DEBUG("Created decompression buffer: %u bytes", decompressedBuffer.allocated);
|
||||
|
||||
// Initialize decompression
|
||||
z_stream zs = {
|
||||
.zalloc = Z_NULL,
|
||||
.zfree = Z_NULL,
|
||||
.opaque = Z_NULL,
|
||||
.avail_in = (uInt)compressedSize,
|
||||
.next_in = (Bytef*)bodyStart,
|
||||
.avail_out = (uInt)ffStrbufGetFree(&decompressedBuffer),
|
||||
.next_out = (Bytef*)decompressedBuffer.chars,
|
||||
};
|
||||
|
||||
// Initialize decompression engine
|
||||
if (zlibData.ffinflateInit2_(&zs, 16 + MAX_WBITS, ZLIB_VERSION, (int)sizeof(z_stream)) != Z_OK) {
|
||||
FF_DEBUG("Failed to initialize decompression engine");
|
||||
return false;
|
||||
}
|
||||
uInt availableOut = zs.avail_out;
|
||||
|
||||
// Perform decompression
|
||||
int result = zlibData.ffinflate(&zs, Z_FINISH);
|
||||
|
||||
// If output buffer is insufficient, try to extend buffer
|
||||
while (result == Z_BUF_ERROR || (result != Z_STREAM_END && zs.avail_out == 0))
|
||||
{
|
||||
FF_DEBUG("Output buffer insufficient, trying to extend");
|
||||
|
||||
// Save already decompressed data amount
|
||||
uint32_t alreadyDecompressed = (uint32_t)(availableOut - zs.avail_out);
|
||||
decompressedBuffer.length += alreadyDecompressed;
|
||||
decompressedBuffer.chars[decompressedBuffer.length] = '\0'; // Ensure null-terminated string
|
||||
|
||||
ffStrbufEnsureFree(&decompressedBuffer, decompressedBuffer.length / 2);
|
||||
|
||||
// Set output parameters to point to new buffer
|
||||
zs.avail_out = (uInt)ffStrbufGetFree(&decompressedBuffer);
|
||||
zs.next_out = (Bytef*)(decompressedBuffer.chars + decompressedBuffer.length);
|
||||
availableOut = zs.avail_out;
|
||||
|
||||
// Decompress again
|
||||
result = zlibData.ffinflate(&zs, Z_FINISH);
|
||||
}
|
||||
|
||||
zlibData.ffinflateEnd(&zs);
|
||||
|
||||
// Calculate decompressed size
|
||||
uint32_t decompressedSize = (uint32_t)(availableOut - zs.avail_out);
|
||||
decompressedBuffer.length += decompressedSize;
|
||||
decompressedBuffer.chars[decompressedSize] = '\0'; // Ensure null-terminated string
|
||||
FF_DEBUG("Successfully decompressed %u bytes compressed data to %u bytes", compressedSize, decompressedBuffer.length);
|
||||
|
||||
// Modify Content-Length header and remove Content-Encoding header
|
||||
FF_STRBUF_AUTO_DESTROY newBuffer = ffStrbufCreateA(headerSize + decompressedSize + 64);
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
while (ffStrbufGetline(&line, &len, buffer))
|
||||
{
|
||||
if (ffStrStartsWithIgnCase(line, "Content-Encoding:"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (ffStrStartsWithIgnCase(line, "Content-Length:"))
|
||||
{
|
||||
ffStrbufAppendF(&newBuffer, "Content-Length: %u\r\n", decompressedSize);
|
||||
continue;
|
||||
}
|
||||
else if (line[0] == '\r')
|
||||
{
|
||||
ffStrbufAppendS(&newBuffer, "\r\n");
|
||||
ffStrbufGetlineRestore(&line, &len, buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&newBuffer, line);
|
||||
ffStrbufAppendC(&newBuffer, '\n');
|
||||
}
|
||||
|
||||
ffStrbufAppend(&newBuffer, &decompressedBuffer);
|
||||
ffStrbufDestroy(buffer);
|
||||
ffStrbufInitMove(buffer, &newBuffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // FF_HAVE_ZLIB
|
||||
@@ -0,0 +1,500 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/networking/networking.h"
|
||||
#include "common/time.h"
|
||||
#include "common/library.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h> // For FreeBSD
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static const char* tryNonThreadingFastPath(FFNetworkingState* state)
|
||||
{
|
||||
#if defined(TCP_FASTOPEN) || __APPLE__
|
||||
|
||||
if (!state->tfo)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// Linux doesn't support sendto() on unconnected sockets
|
||||
FF_DEBUG("TCP Fast Open disabled, skipping");
|
||||
return "TCP Fast Open disabled";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Attempting to use TCP Fast Open to connect");
|
||||
|
||||
#ifndef __APPLE__ // On macOS, TCP_FASTOPEN doesn't seem to be needed
|
||||
// Set TCP Fast Open
|
||||
#ifdef __linux__
|
||||
int flag = 5; // the queue length of pending packets
|
||||
#else
|
||||
int flag = 1; // enable TCP Fast Open
|
||||
#endif
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP,
|
||||
#ifdef __APPLE__
|
||||
// https://github.com/rust-lang/libc/pull/3135
|
||||
0x218 // TCP_FASTOPEN_FORCE_ENABLE
|
||||
#else
|
||||
TCP_FASTOPEN
|
||||
#endif
|
||||
, &flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_FASTOPEN option: %s", strerror(errno));
|
||||
return "setsockopt(TCP_FASTOPEN) failed";
|
||||
} else {
|
||||
#ifdef __linux__
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option, queue length: %d", flag);
|
||||
#elif defined(__APPLE__)
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN_FORCE_ENABLE option");
|
||||
#else
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
FF_DEBUG("Using sendto() + MSG_DONTWAIT to send %u bytes of data", state->command.length);
|
||||
ssize_t sent = sendto(state->sockfd,
|
||||
state->command.chars,
|
||||
state->command.length,
|
||||
#ifdef MSG_FASTOPEN
|
||||
MSG_FASTOPEN |
|
||||
#endif
|
||||
#ifdef MSG_NOSIGNAL
|
||||
MSG_NOSIGNAL |
|
||||
#endif
|
||||
MSG_DONTWAIT,
|
||||
state->addr->ai_addr,
|
||||
state->addr->ai_addrlen);
|
||||
#else
|
||||
if (fcntl(state->sockfd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
FF_DEBUG("fcntl(F_SETFL) failed: %s", strerror(errno));
|
||||
return "fcntl(F_SETFL) failed";
|
||||
}
|
||||
FF_DEBUG("Using connectx() to send %u bytes of data", state->command.length);
|
||||
// Use connectx to establish connection and send data in one call
|
||||
size_t sent;
|
||||
if (connectx(state->sockfd,
|
||||
&(sa_endpoints_t) {
|
||||
.sae_dstaddr = state->addr->ai_addr,
|
||||
.sae_dstaddrlen = state->addr->ai_addrlen,
|
||||
},
|
||||
SAE_ASSOCID_ANY, state->tfo ? CONNECT_DATA_IDEMPOTENT : 0,
|
||||
&(struct iovec) {
|
||||
.iov_base = state->command.chars,
|
||||
.iov_len = state->command.length,
|
||||
}, 1, &sent, NULL) != 0) sent = 0;
|
||||
if (fcntl(state->sockfd, F_SETFL, 0) == -1) {
|
||||
FF_DEBUG("fcntl(F_SETFL) failed: %s", strerror(errno));
|
||||
return "fcntl(F_SETFL) failed";
|
||||
}
|
||||
#endif
|
||||
if (sent > 0 || (errno == EAGAIN || errno == EWOULDBLOCK
|
||||
#ifdef __APPLE__
|
||||
// On macOS EINPROGRESS means the connection cannot be completed immediately
|
||||
// On Linux, it means the TFO cookie is not available locally
|
||||
|| errno == EINPROGRESS
|
||||
#endif
|
||||
))
|
||||
{
|
||||
FF_DEBUG(
|
||||
#ifdef __APPLE__
|
||||
"connectx()"
|
||||
#else
|
||||
"sendto()"
|
||||
#endif
|
||||
" %s (sent=%zd, errno=%d: %s)", errno == 0 ? "succeeded" : "was in progress",
|
||||
sent, errno, strerror(errno));
|
||||
freeaddrinfo(state->addr);
|
||||
state->addr = NULL;
|
||||
ffStrbufDestroy(&state->command);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_DEBUG(
|
||||
#ifdef __APPLE__
|
||||
"connectx()"
|
||||
#else
|
||||
"sendto()"
|
||||
#endif
|
||||
" failed: %s (errno=%d)", strerror(errno), errno);
|
||||
#ifdef __APPLE__
|
||||
return "connectx() failed";
|
||||
#else
|
||||
return "sendto() failed";
|
||||
#endif
|
||||
#else
|
||||
FF_UNUSED(state);
|
||||
return "TFO support is not available";
|
||||
#endif
|
||||
}
|
||||
|
||||
// Traditional connect and send function
|
||||
static const char* connectAndSend(FFNetworkingState* state)
|
||||
{
|
||||
const char* ret = NULL;
|
||||
FF_DEBUG("Using traditional connection method to connect");
|
||||
|
||||
FF_DEBUG("Attempting connect() to server...");
|
||||
if(connect(state->sockfd, state->addr->ai_addr, state->addr->ai_addrlen) == -1)
|
||||
{
|
||||
FF_DEBUG("connect() failed: %s (errno=%d)", strerror(errno), errno);
|
||||
ret = "connect() failed";
|
||||
goto error;
|
||||
}
|
||||
FF_DEBUG("connect() succeeded");
|
||||
|
||||
FF_DEBUG("Attempting to send %u bytes of data...", state->command.length);
|
||||
if(send(state->sockfd, state->command.chars, state->command.length, 0) < 0)
|
||||
{
|
||||
FF_DEBUG("send() failed: %s (errno=%d)", strerror(errno), errno);
|
||||
ret = "send() failed";
|
||||
goto error;
|
||||
}
|
||||
FF_DEBUG("Data sent successfully");
|
||||
|
||||
goto exit;
|
||||
|
||||
error:
|
||||
FF_DEBUG("Error occurred, closing socket");
|
||||
close(state->sockfd);
|
||||
state->sockfd = -1;
|
||||
|
||||
exit:
|
||||
FF_DEBUG("Releasing address info and other resources");
|
||||
freeaddrinfo(state->addr);
|
||||
state->addr = NULL;
|
||||
ffStrbufDestroy(&state->command);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FF_THREAD_ENTRY_DECL_WRAPPER(connectAndSend, FFNetworkingState*);
|
||||
|
||||
// Parallel DNS resolution and socket creation
|
||||
static const char* initNetworkingState(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
FF_DEBUG("Initializing network connection state: host=%s, path=%s", host, path);
|
||||
|
||||
// Initialize command and host information
|
||||
ffStrbufInitA(&state->command, 64);
|
||||
ffStrbufAppendS(&state->command, "GET ");
|
||||
ffStrbufAppendS(&state->command, path);
|
||||
ffStrbufAppendS(&state->command, " HTTP/1.0\nHost: ");
|
||||
ffStrbufAppendS(&state->command, host);
|
||||
ffStrbufAppendS(&state->command, "\r\n");
|
||||
|
||||
// Add extra optimized HTTP headers
|
||||
ffStrbufAppendS(&state->command, "Connection: close\r\n"); // Explicitly tell the server we don't need to keep the connection
|
||||
|
||||
// If compression needs to be enabled
|
||||
if (state->compression) {
|
||||
FF_DEBUG("Enabling HTTP content compression");
|
||||
ffStrbufAppendS(&state->command, "Accept-Encoding: gzip\r\n");
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&state->command, headers);
|
||||
ffStrbufAppendS(&state->command, "\r\n");
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
state->thread = 0;
|
||||
FF_DEBUG("Thread ID initialized to 0");
|
||||
#endif
|
||||
|
||||
const char* ret = NULL;
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_flags = AI_NUMERICSERV
|
||||
};
|
||||
|
||||
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
|
||||
// Use AI_NUMERICSERV flag to indicate the service is a numeric port, reducing parsing time
|
||||
|
||||
if(getaddrinfo(host, "80", &hints, &state->addr) != 0)
|
||||
{
|
||||
FF_DEBUG("getaddrinfo() failed: %s", gai_strerror(errno));
|
||||
ret = "getaddrinfo() failed";
|
||||
goto error;
|
||||
}
|
||||
FF_DEBUG("Address resolution successful");
|
||||
|
||||
FF_DEBUG("Creating socket");
|
||||
state->sockfd = socket(state->addr->ai_family, state->addr->ai_socktype, state->addr->ai_protocol);
|
||||
if(state->sockfd == -1)
|
||||
{
|
||||
FF_DEBUG("socket() failed: %s (errno=%d)", strerror(errno), errno);
|
||||
ret = "socket() failed";
|
||||
goto error;
|
||||
}
|
||||
FF_DEBUG("Socket creation successful: fd=%d", state->sockfd);
|
||||
|
||||
int flag = 1;
|
||||
#ifdef TCP_NODELAY
|
||||
// Disable Nagle's algorithm to reduce small packet transmission delay
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_NODELAY: %s", strerror(errno));
|
||||
} else {
|
||||
FF_DEBUG("Successfully disabled Nagle's algorithm");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TCP_QUICKACK
|
||||
// Set TCP_QUICKACK option to avoid delayed acknowledgments
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_QUICKACK: %s", strerror(errno));
|
||||
} else {
|
||||
FF_DEBUG("Successfully enabled TCP quick acknowledgment");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (state->timeout > 0)
|
||||
{
|
||||
FF_DEBUG("Setting connection timeout: %u ms", state->timeout);
|
||||
FF_MAYBE_UNUSED uint32_t sec = state->timeout / 1000;
|
||||
if (sec == 0) sec = 1;
|
||||
|
||||
#ifdef TCP_CONNECTIONTIMEOUT
|
||||
FF_DEBUG("Using TCP_CONNECTIONTIMEOUT: %u seconds", sec);
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &sec, sizeof(sec));
|
||||
#elif defined(TCP_KEEPINIT)
|
||||
FF_DEBUG("Using TCP_KEEPINIT: %u seconds", sec);
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_KEEPINIT, &sec, sizeof(sec));
|
||||
#elif defined(TCP_USER_TIMEOUT)
|
||||
FF_DEBUG("Using TCP_USER_TIMEOUT: %u milliseconds", state->timeout);
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_USER_TIMEOUT, &state->timeout, sizeof(state->timeout));
|
||||
#else
|
||||
FF_DEBUG("Current platform does not support TCP connection timeout");
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
error:
|
||||
FF_DEBUG("Error occurred during initialization");
|
||||
if (state->addr != NULL)
|
||||
{
|
||||
FF_DEBUG("Releasing address information");
|
||||
freeaddrinfo(state->addr);
|
||||
state->addr = NULL;
|
||||
}
|
||||
|
||||
if (state->sockfd > 0)
|
||||
{
|
||||
FF_DEBUG("Closing socket: fd=%d", state->sockfd);
|
||||
close(state->sockfd);
|
||||
state->sockfd = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
FF_DEBUG("Preparing to send HTTP request: host=%s, path=%s", host, path);
|
||||
|
||||
if (state->compression)
|
||||
{
|
||||
FF_DEBUG("Compression enabled, checking if zlib is available");
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
const char* zlibError = ffNetworkingLoadZlibLibrary();
|
||||
// Only enable compression if zlib library is successfully loaded
|
||||
if (zlibError == NULL)
|
||||
{
|
||||
FF_DEBUG("Successfully loaded zlib library, compression enabled");
|
||||
} else {
|
||||
FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError);
|
||||
state->compression = false;
|
||||
}
|
||||
#else
|
||||
FF_DEBUG("zlib not supported at build time, compression disabled");
|
||||
state->compression = false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Compression disabled");
|
||||
}
|
||||
|
||||
const char* initResult = initNetworkingState(state, host, path, headers);
|
||||
if (initResult != NULL) {
|
||||
FF_DEBUG("Initialization failed: %s", initResult);
|
||||
return initResult;
|
||||
}
|
||||
FF_DEBUG("Network state initialization successful");
|
||||
|
||||
const char* tfoResult = tryNonThreadingFastPath(state);
|
||||
if (tfoResult == NULL) {
|
||||
FF_DEBUG("TryNonThreadingFastPath() succeeded or in progress");
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("TryNonThreadingFastPath() failed: %s, trying traditional connection", tfoResult);
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
if (instance.config.general.multithreading)
|
||||
{
|
||||
FF_DEBUG("Multithreading mode enabled, creating connection thread");
|
||||
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
|
||||
if (state->thread) {
|
||||
FF_DEBUG("Thread creation successful: thread=%p", (void*)state->thread);
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Thread creation failed");
|
||||
} else {
|
||||
FF_DEBUG("Multithreading mode disabled, connecting in main thread");
|
||||
}
|
||||
#endif
|
||||
|
||||
return connectAndSend(state);
|
||||
}
|
||||
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
|
||||
{
|
||||
FF_DEBUG("Preparing to receive HTTP response");
|
||||
uint32_t timeout = state->timeout;
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
if (state->thread)
|
||||
{
|
||||
FF_DEBUG("Connection thread is running, waiting for it to complete (timeout=%u ms)", timeout);
|
||||
if (!ffThreadJoin(state->thread, timeout)) {
|
||||
FF_DEBUG("Thread join failed or timed out");
|
||||
return "ffThreadJoin() failed or timeout";
|
||||
}
|
||||
FF_DEBUG("Thread completed successfully");
|
||||
state->thread = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(state->sockfd == -1)
|
||||
{
|
||||
FF_DEBUG("Invalid socket, HTTP request might have failed");
|
||||
return "ffNetworkingSendHttpRequest() failed";
|
||||
}
|
||||
|
||||
// Set larger initial receive buffer instead of small repeated receives
|
||||
int rcvbuf = 65536; // 64KB
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
|
||||
|
||||
#ifdef __APPLE__
|
||||
// poll for the socket to be readable.
|
||||
// Because of the non-blocking connectx() call, the connection might not be established yet
|
||||
FF_DEBUG("Using poll() to check if socket is readable");
|
||||
if (poll(&(struct pollfd) {
|
||||
.fd = state->sockfd,
|
||||
.events = POLLIN
|
||||
}, 1, timeout > 0 ? (int) timeout : -1) == -1)
|
||||
{
|
||||
FF_DEBUG("poll() failed: %s (errno=%d)", strerror(errno), errno);
|
||||
close(state->sockfd);
|
||||
state->sockfd = -1;
|
||||
return "poll() failed";
|
||||
}
|
||||
FF_DEBUG("Socket is readable, proceeding to receive data");
|
||||
#else
|
||||
if(timeout > 0)
|
||||
{
|
||||
FF_DEBUG("Setting receive timeout: %u ms", timeout);
|
||||
struct timeval timev;
|
||||
timev.tv_sec = timeout / 1000;
|
||||
timev.tv_usec = (__typeof__(timev.tv_usec)) ((timeout % 1000) * 1000); //milliseconds to microseconds
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev));
|
||||
}
|
||||
#endif
|
||||
|
||||
FF_DEBUG("Starting data reception");
|
||||
FF_MAYBE_UNUSED int recvCount = 0;
|
||||
uint32_t contentLength = 0;
|
||||
char* headerEnd = NULL;
|
||||
|
||||
do {
|
||||
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
|
||||
++recvCount, buffer->length, ffStrbufGetFree(buffer));
|
||||
|
||||
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, ffStrbufGetFree(buffer), MSG_WAITALL);
|
||||
|
||||
if (received <= 0) {
|
||||
if (received == 0) {
|
||||
FF_DEBUG("Connection closed (received=0)");
|
||||
} else {
|
||||
FF_DEBUG("Reception failed: %s (errno=%d)", strerror(errno), errno);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
buffer->length += (uint32_t) received;
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
|
||||
FF_DEBUG("Successfully received %zd bytes of data, total: %u bytes", received, buffer->length);
|
||||
|
||||
// Check if HTTP header end marker is found
|
||||
if (headerEnd == NULL) {
|
||||
headerEnd = memmem(buffer->chars, buffer->length, "\r\n\r\n", 4);
|
||||
if (headerEnd != NULL) {
|
||||
FF_DEBUG("Found HTTP header end marker, position: %ld", (long)(headerEnd - buffer->chars));
|
||||
|
||||
// Check for Content-Length header to pre-allocate enough memory
|
||||
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
|
||||
if (clHeader) {
|
||||
contentLength = (uint32_t) strtoul(clHeader + 16, NULL, 10);
|
||||
if (contentLength > 0) {
|
||||
FF_DEBUG("Detected Content-Length: %u, pre-allocating buffer", contentLength);
|
||||
// Ensure buffer is large enough, adding header size and some margin
|
||||
ffStrbufEnsureFree(buffer, contentLength + 16);
|
||||
FF_DEBUG("Extended receive buffer to %u bytes", buffer->length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (ffStrbufGetFree(buffer) > 0);
|
||||
|
||||
FF_DEBUG("Closing socket: fd=%d", state->sockfd);
|
||||
close(state->sockfd);
|
||||
state->sockfd = -1;
|
||||
|
||||
if (buffer->length == 0) {
|
||||
FF_DEBUG("Server response is empty");
|
||||
return "Empty server response received";
|
||||
}
|
||||
|
||||
if (headerEnd == NULL) {
|
||||
FF_DEBUG("No HTTP header end marker found");
|
||||
return "No HTTP header end found";
|
||||
}
|
||||
if (contentLength > 0 && buffer->length != contentLength + (uint32_t)(headerEnd - buffer->chars) + 4) {
|
||||
FF_DEBUG("Received content length mismatches: %u != %u", buffer->length, contentLength + (uint32_t)(headerEnd - buffer->chars) + 4);
|
||||
return "Content length mismatch";
|
||||
}
|
||||
|
||||
if (ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
|
||||
FF_DEBUG("Received valid HTTP 200 response, content %u bytes, total %u bytes", contentLength, buffer->length);
|
||||
} else {
|
||||
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
|
||||
return "Invalid response";
|
||||
}
|
||||
|
||||
// If compression was used, try to decompress
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
if (state->compression) {
|
||||
FF_DEBUG("Content received, checking if compressed");
|
||||
if (!ffNetworkingDecompressGzip(buffer, headerEnd)) {
|
||||
FF_DEBUG("Decompression failed or invalid compression format");
|
||||
return "Failed to decompress or invalid format";
|
||||
} else {
|
||||
FF_DEBUG("Decompression successful or no decompression needed, total length after decompression: %u bytes", buffer->length);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
#include <mswsock.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
//Must be included after <mswsock.h>
|
||||
#include "fastfetch.h"
|
||||
#include "common/networking/networking.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
static LPFN_CONNECTEX ConnectEx;
|
||||
|
||||
static const char* initWsaData(WSADATA* wsaData)
|
||||
{
|
||||
FF_DEBUG("Initializing WinSock");
|
||||
if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0) {
|
||||
FF_DEBUG("WSAStartup() failed");
|
||||
return "WSAStartup() failed";
|
||||
}
|
||||
|
||||
if(LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2) {
|
||||
FF_DEBUG("Invalid wsaData version found: %d.%d", LOBYTE(wsaData->wVersion), HIBYTE(wsaData->wVersion));
|
||||
return "Invalid wsaData version found";
|
||||
}
|
||||
|
||||
//Dummy socket needed for WSAIoctl
|
||||
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(sockfd == INVALID_SOCKET) {
|
||||
FF_DEBUG("socket(AF_INET, SOCK_STREAM) failed");
|
||||
return "socket(AF_INET, SOCK_STREAM) failed";
|
||||
}
|
||||
|
||||
DWORD dwBytes;
|
||||
GUID guid = WSAID_CONNECTEX;
|
||||
if(WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||
&guid, sizeof(guid),
|
||||
&ConnectEx, sizeof(ConnectEx),
|
||||
&dwBytes, NULL, NULL) != 0) {
|
||||
FF_DEBUG("WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
|
||||
return "WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed";
|
||||
}
|
||||
|
||||
closesocket(sockfd);
|
||||
FF_DEBUG("WinSock initialized successfully");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
FF_DEBUG("Preparing to send HTTP request: host=%s, path=%s", host, path);
|
||||
|
||||
if (state->compression)
|
||||
{
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
const char* zlibError = ffNetworkingLoadZlibLibrary();
|
||||
// Only enable compression if zlib library is successfully loaded
|
||||
if (zlibError == NULL)
|
||||
{
|
||||
FF_DEBUG("Successfully loaded zlib library, compression enabled");
|
||||
} else {
|
||||
FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError);
|
||||
state->compression = false;
|
||||
}
|
||||
#else
|
||||
FF_DEBUG("zlib not supported at build time, compression disabled");
|
||||
state->compression = false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Compression disabled");
|
||||
}
|
||||
|
||||
static WSADATA wsaData;
|
||||
if (wsaData.wVersion == 0)
|
||||
{
|
||||
const char* error = initWsaData(&wsaData);
|
||||
if (error != NULL)
|
||||
{
|
||||
wsaData.wVersion = (WORD) -1;
|
||||
FF_DEBUG("WinSock initialization failed: %s", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
else if (wsaData.wVersion == (WORD) -1)
|
||||
{
|
||||
FF_DEBUG("WinSock initialization previously failed");
|
||||
return "initWsaData() failed before";
|
||||
}
|
||||
|
||||
struct addrinfo* addr;
|
||||
struct addrinfo hints = {
|
||||
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_flags = AI_NUMERICSERV,
|
||||
};
|
||||
|
||||
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
|
||||
if(getaddrinfo(host, "80", &hints, &addr) != 0)
|
||||
{
|
||||
FF_DEBUG("getaddrinfo() failed");
|
||||
return "getaddrinfo() failed";
|
||||
}
|
||||
|
||||
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if(state->sockfd == INVALID_SOCKET)
|
||||
{
|
||||
FF_DEBUG("socket() failed");
|
||||
freeaddrinfo(addr);
|
||||
return "socket() failed";
|
||||
}
|
||||
|
||||
DWORD flag = 1;
|
||||
#ifdef TCP_NODELAY
|
||||
// Enable TCP_NODELAY to disable Nagle's algorithm
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_NODELAY: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
} else {
|
||||
FF_DEBUG("Successfully disabled Nagle's algorithm");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set timeout if needed
|
||||
if (state->timeout > 0) {
|
||||
FF_DEBUG("Setting connection timeout: %u ms", state->timeout);
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&state->timeout, sizeof(state->timeout));
|
||||
}
|
||||
|
||||
//ConnectEx requires the socket to be initially bound
|
||||
if((state->ipv6
|
||||
? bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in6) {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = in6addr_any,
|
||||
}, sizeof(struct sockaddr_in6))
|
||||
: bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in) {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = INADDR_ANY,
|
||||
}, sizeof(struct sockaddr_in))) != 0)
|
||||
{
|
||||
FF_DEBUG("bind() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
closesocket(state->sockfd);
|
||||
freeaddrinfo(addr);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
return "bind() failed";
|
||||
}
|
||||
|
||||
// Initialize overlapped structure for asynchronous I/O
|
||||
memset(&state->overlapped, 0, sizeof(OVERLAPPED));
|
||||
|
||||
// Build HTTP command
|
||||
FF_STRBUF_AUTO_DESTROY command = ffStrbufCreateA(64);
|
||||
ffStrbufAppendS(&command, "GET ");
|
||||
ffStrbufAppendS(&command, path);
|
||||
ffStrbufAppendS(&command, " HTTP/1.0\nHost: ");
|
||||
ffStrbufAppendS(&command, host);
|
||||
ffStrbufAppendS(&command, "\r\n");
|
||||
ffStrbufAppendS(&command, "Connection: close\r\n"); // Explicitly request connection closure
|
||||
|
||||
// Add compression support if enabled
|
||||
if (state->compression) {
|
||||
FF_DEBUG("Enabling HTTP content compression");
|
||||
ffStrbufAppendS(&command, "Accept-Encoding: gzip\r\n");
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&command, headers);
|
||||
ffStrbufAppendS(&command, "\r\n");
|
||||
|
||||
#ifdef TCP_FASTOPEN
|
||||
if (state->tfo)
|
||||
{
|
||||
// Set TCP Fast Open
|
||||
flag = 1;
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_FASTOPEN, (char*)&flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_FASTOPEN option: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
} else {
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("TCP Fast Open disabled");
|
||||
}
|
||||
#endif
|
||||
|
||||
FF_DEBUG("Using ConnectEx to send %u bytes of data", command.length);
|
||||
DWORD sent = 0;
|
||||
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int)addr->ai_addrlen,
|
||||
command.chars, command.length, &sent, &state->overlapped);
|
||||
|
||||
freeaddrinfo(addr);
|
||||
addr = NULL;
|
||||
|
||||
if(!result)
|
||||
{
|
||||
if (WSAGetLastError() != WSA_IO_PENDING)
|
||||
{
|
||||
FF_DEBUG("ConnectEx() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
closesocket(state->sockfd);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
return "ConnectEx() failed";
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("ConnectEx() pending");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("ConnectEx() succeeded, sent %u bytes of data", (unsigned) sent);
|
||||
}
|
||||
|
||||
// No need to cleanup state fields here since we need them in the receive function
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
|
||||
{
|
||||
FF_DEBUG("Preparing to receive HTTP response");
|
||||
|
||||
if (state->sockfd == INVALID_SOCKET)
|
||||
{
|
||||
FF_DEBUG("Invalid socket, HTTP request might have failed");
|
||||
return "ffNetworkingSendHttpRequest() failed";
|
||||
}
|
||||
|
||||
uint32_t timeout = state->timeout;
|
||||
if (timeout > 0)
|
||||
{
|
||||
FF_DEBUG("WaitForSingleObject with timeout: %u ms", timeout);
|
||||
if (WaitForSingleObject((HANDLE)state->sockfd, timeout) != WAIT_OBJECT_0)
|
||||
{
|
||||
FF_DEBUG("WaitForSingleObject failed or timed out");
|
||||
CancelIo((HANDLE) state->sockfd);
|
||||
closesocket(state->sockfd);
|
||||
return "WaitForSingleObject(state->sockfd) failed or timeout";
|
||||
}
|
||||
}
|
||||
|
||||
DWORD transfer, flags;
|
||||
if (!WSAGetOverlappedResult(state->sockfd, &state->overlapped, &transfer, TRUE, &flags))
|
||||
{
|
||||
FF_DEBUG("WSAGetOverlappedResult failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
closesocket(state->sockfd);
|
||||
return "WSAGetOverlappedResult() failed";
|
||||
}
|
||||
|
||||
if(timeout > 0)
|
||||
{
|
||||
FF_DEBUG("Setting receive timeout: %u ms", timeout);
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
// Set larger receive buffer for better performance
|
||||
int rcvbuf = 65536; // 64KB
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&rcvbuf, sizeof(rcvbuf));
|
||||
|
||||
FF_DEBUG("Starting data reception");
|
||||
FF_MAYBE_UNUSED int recvCount = 0;
|
||||
uint32_t contentLength = 0;
|
||||
char* headerEnd = NULL;
|
||||
|
||||
do {
|
||||
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
|
||||
++recvCount, buffer->length, ffStrbufGetFree(buffer));
|
||||
|
||||
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, (int)ffStrbufGetFree(buffer), 0);
|
||||
|
||||
if (received <= 0) {
|
||||
if (received == 0) {
|
||||
FF_DEBUG("Connection closed (received=0)");
|
||||
} else {
|
||||
FF_DEBUG("Reception failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
buffer->length += (uint32_t) received;
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
|
||||
FF_DEBUG("Successfully received %zd bytes of data, total: %u bytes", received, buffer->length);
|
||||
|
||||
// Check if HTTP header end marker is found
|
||||
if (headerEnd == NULL) {
|
||||
headerEnd = strstr(buffer->chars, "\r\n\r\n");
|
||||
if (headerEnd != NULL) {
|
||||
FF_DEBUG("Found HTTP header end marker, position: %ld", (long)(headerEnd - buffer->chars));
|
||||
|
||||
// Check for Content-Length header to pre-allocate enough memory
|
||||
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
|
||||
if (clHeader) {
|
||||
contentLength = (uint32_t) strtoul(clHeader + 16, NULL, 10);
|
||||
if (contentLength > 0) {
|
||||
FF_DEBUG("Detected Content-Length: %u, pre-allocating buffer", contentLength);
|
||||
// Ensure buffer is large enough, adding header size and some margin
|
||||
ffStrbufEnsureFree(buffer, contentLength + 16);
|
||||
FF_DEBUG("Extended receive buffer to %u bytes", buffer->allocated);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (ffStrbufGetFree(buffer) > 0);
|
||||
|
||||
FF_DEBUG("Closing socket: fd=%u", (unsigned)state->sockfd);
|
||||
closesocket(state->sockfd);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
|
||||
if (buffer->length == 0) {
|
||||
FF_DEBUG("Server response is empty");
|
||||
return "Empty server response received";
|
||||
}
|
||||
|
||||
if (headerEnd == NULL) {
|
||||
FF_DEBUG("No HTTP header end marker found");
|
||||
return "No HTTP header end found";
|
||||
}
|
||||
|
||||
if (ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
|
||||
FF_DEBUG("Received valid HTTP 200 response, content length: %u bytes, total length: %u bytes",
|
||||
contentLength, buffer->length);
|
||||
} else {
|
||||
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
|
||||
return "Invalid response";
|
||||
}
|
||||
|
||||
// If compression was used, try to decompress
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
if (state->compression) {
|
||||
FF_DEBUG("Content received, checking if compressed");
|
||||
if (!ffNetworkingDecompressGzip(buffer, headerEnd)) {
|
||||
FF_DEBUG("Decompression failed or invalid compression format");
|
||||
return "Failed to decompress or invalid format";
|
||||
} else {
|
||||
FF_DEBUG("Decompression successful or no decompression needed, total length after decompression: %u bytes", buffer->length);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/networking.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h> // For FreeBSD
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
static const char* connectAndSend(FFNetworkingState* state)
|
||||
{
|
||||
const char* ret = NULL;
|
||||
struct addrinfo* addr;
|
||||
|
||||
if(getaddrinfo(state->host.chars, "80", &(struct addrinfo) {
|
||||
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
}, &addr) != 0)
|
||||
{
|
||||
ret = "getaddrinfo() failed";
|
||||
goto error;
|
||||
}
|
||||
|
||||
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if(state->sockfd == -1)
|
||||
{
|
||||
freeaddrinfo(addr);
|
||||
ret = "socket() failed";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (state->timeout > 0)
|
||||
{
|
||||
FF_MAYBE_UNUSED uint32_t sec = state->timeout / 1000;
|
||||
if (sec == 0) sec = 1;
|
||||
|
||||
#ifdef TCP_CONNECTIONTIMEOUT
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &sec, sizeof(sec));
|
||||
#elif defined(TCP_KEEPINIT)
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_KEEPINIT, &sec, sizeof(sec));
|
||||
#elif defined(TCP_USER_TIMEOUT)
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_USER_TIMEOUT, &state->timeout, sizeof(state->timeout));
|
||||
#endif
|
||||
}
|
||||
|
||||
if(connect(state->sockfd, addr->ai_addr, addr->ai_addrlen) == -1)
|
||||
{
|
||||
close(state->sockfd);
|
||||
freeaddrinfo(addr);
|
||||
ret = "connect() failed";
|
||||
goto error;
|
||||
}
|
||||
|
||||
freeaddrinfo(addr);
|
||||
|
||||
if(send(state->sockfd, state->command.chars, state->command.length, 0) < 0)
|
||||
{
|
||||
close(state->sockfd);
|
||||
ret = "send() failed";
|
||||
goto error;
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
error:
|
||||
state->sockfd = -1;
|
||||
|
||||
exit:
|
||||
ffStrbufDestroy(&state->host);
|
||||
ffStrbufDestroy(&state->command);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FF_THREAD_ENTRY_DECL_WRAPPER(connectAndSend, FFNetworkingState*);
|
||||
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
ffStrbufInitS(&state->host, host);
|
||||
|
||||
ffStrbufInitA(&state->command, 64);
|
||||
ffStrbufAppendS(&state->command, "GET ");
|
||||
ffStrbufAppendS(&state->command, path);
|
||||
ffStrbufAppendS(&state->command, " HTTP/1.1\nHost: ");
|
||||
ffStrbufAppendS(&state->command, host);
|
||||
ffStrbufAppendS(&state->command, "\r\n");
|
||||
ffStrbufAppendS(&state->command, headers);
|
||||
ffStrbufAppendS(&state->command, "\r\n");
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
if (instance.config.general.multithreading)
|
||||
{
|
||||
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
|
||||
return state->thread ? NULL : "ffThreadCreate(connectAndSend) failed";
|
||||
}
|
||||
#endif
|
||||
|
||||
return connectAndSend(state);
|
||||
}
|
||||
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
|
||||
{
|
||||
uint32_t timeout = state->timeout;
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
if (instance.config.general.multithreading)
|
||||
{
|
||||
if (!ffThreadJoin(state->thread, timeout))
|
||||
return "ffThreadJoin() failed or timeout";
|
||||
}
|
||||
#endif
|
||||
|
||||
if(state->sockfd == -1)
|
||||
return "ffNetworkingSendHttpRequest() failed";
|
||||
|
||||
if(timeout > 0)
|
||||
{
|
||||
struct timeval timev;
|
||||
timev.tv_sec = timeout / 1000;
|
||||
timev.tv_usec = (__typeof__(timev.tv_usec)) ((timeout % 1000) * 1000); //milliseconds to microseconds
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev));
|
||||
}
|
||||
|
||||
uint32_t recvStart;
|
||||
do {
|
||||
recvStart = buffer->length;
|
||||
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, ffStrbufGetFree(buffer), 0);
|
||||
if (received <= 0) break;
|
||||
buffer->length += (uint32_t) received;
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
} while (ffStrbufGetFree(buffer) > 0 && strstr(buffer->chars + recvStart, "\r\n\r\n") == NULL);
|
||||
|
||||
close(state->sockfd);
|
||||
if (buffer->length == 0) return "Empty server response received";
|
||||
return ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n") ? NULL : "Invalid response";
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
#include <mswsock.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
//Must be included after <mswsock.h>
|
||||
#include "fastfetch.h"
|
||||
#include "common/networking.h"
|
||||
|
||||
static LPFN_CONNECTEX ConnectEx;
|
||||
|
||||
static const char* initWsaData(WSADATA* wsaData)
|
||||
{
|
||||
if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0)
|
||||
return "WSAStartup() failed";
|
||||
|
||||
if(LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2)
|
||||
return "Invalid wsaData version found";
|
||||
|
||||
//Dummy socket needed for WSAIoctl
|
||||
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(sockfd == INVALID_SOCKET)
|
||||
return "socket(AF_INET, SOCK_STREAM) failed";
|
||||
|
||||
DWORD dwBytes;
|
||||
GUID guid = WSAID_CONNECTEX;
|
||||
if(WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||
&guid, sizeof(guid),
|
||||
&ConnectEx, sizeof(ConnectEx),
|
||||
&dwBytes, NULL, NULL) != 0)
|
||||
return "WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed";
|
||||
|
||||
closesocket(sockfd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
static WSADATA wsaData;
|
||||
if (wsaData.wVersion == 0)
|
||||
{
|
||||
const char* error = initWsaData(&wsaData);
|
||||
if (error != NULL)
|
||||
{
|
||||
wsaData.wVersion = (WORD) -1;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
else if (wsaData.wVersion == (WORD) -1)
|
||||
return "initWsaData() failed before";
|
||||
|
||||
struct addrinfo* addr;
|
||||
|
||||
if(getaddrinfo(host, "80", &(struct addrinfo) {
|
||||
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
}, &addr) != 0)
|
||||
return "getaddrinfo() failed";
|
||||
|
||||
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if(state->sockfd == INVALID_SOCKET)
|
||||
{
|
||||
freeaddrinfo(addr);
|
||||
return "socket() failed";
|
||||
}
|
||||
|
||||
//ConnectEx requires the socket to be initially bound
|
||||
if((state->ipv6
|
||||
? bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in6) {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = in6addr_any,
|
||||
}, sizeof(struct sockaddr_in6))
|
||||
: bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in) {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = INADDR_ANY,
|
||||
}, sizeof(struct sockaddr_in))) != 0)
|
||||
{
|
||||
closesocket(state->sockfd);
|
||||
freeaddrinfo(addr);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
return "bind() failed";
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY command = ffStrbufCreateA(64);
|
||||
ffStrbufAppendS(&command, "GET ");
|
||||
ffStrbufAppendS(&command, path);
|
||||
ffStrbufAppendS(&command, " HTTP/1.1\nHost: ");
|
||||
ffStrbufAppendS(&command, host);
|
||||
ffStrbufAppendS(&command, "\r\n");
|
||||
ffStrbufAppendS(&command, headers);
|
||||
ffStrbufAppendS(&command, "\r\n");
|
||||
|
||||
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int)addr->ai_addrlen, command.chars, command.length, NULL, &state->overlapped);
|
||||
freeaddrinfo(addr);
|
||||
|
||||
if(!result && WSAGetLastError() != WSA_IO_PENDING)
|
||||
{
|
||||
closesocket(state->sockfd);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
return "ConnectEx() failed";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
|
||||
{
|
||||
if (state->sockfd == INVALID_SOCKET)
|
||||
return "ffNetworkingSendHttpRequest() failed";
|
||||
|
||||
uint32_t timeout = state->timeout;
|
||||
if (timeout > 0)
|
||||
{
|
||||
if (WaitForSingleObject((HANDLE) state->sockfd, timeout) != WAIT_OBJECT_0)
|
||||
{
|
||||
CancelIo((HANDLE) state->sockfd);
|
||||
closesocket(state->sockfd);
|
||||
return "WaitForSingleObject(state->sockfd) failed or timeout";
|
||||
}
|
||||
}
|
||||
|
||||
DWORD transfer, flags;
|
||||
if (!WSAGetOverlappedResult(state->sockfd, &state->overlapped, &transfer, TRUE, &flags))
|
||||
{
|
||||
closesocket(state->sockfd);
|
||||
return "WSAGetOverlappedResult() failed";
|
||||
}
|
||||
|
||||
if(timeout > 0)
|
||||
{
|
||||
//https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
uint32_t recvStart;
|
||||
do {
|
||||
recvStart = buffer->length;
|
||||
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, (int) ffStrbufGetFree(buffer), 0);
|
||||
if (received <= 0) break;
|
||||
buffer->length = recvStart + (uint32_t) received;
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
} while (ffStrbufGetFree(buffer) > 0 && strstr(buffer->chars + recvStart, "\r\n\r\n") == NULL);
|
||||
|
||||
closesocket(state->sockfd);
|
||||
if (buffer->length == 0) return "Empty server response received";
|
||||
return ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n") ? NULL : "Invalid response";
|
||||
}
|
||||
@@ -198,6 +198,12 @@ void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t s
|
||||
return;
|
||||
}
|
||||
|
||||
if(seconds >= 30)
|
||||
{
|
||||
minutes++;
|
||||
seconds = 0;
|
||||
}
|
||||
|
||||
if(days > 0)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u day", days);
|
||||
|
||||
+2
-2
@@ -65,8 +65,8 @@
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
|
||||
{
|
||||
ts.tv_sec += ts.tv_sec / 1000;
|
||||
ts.tv_nsec += (ts.tv_nsec % 1000) * 1000000;
|
||||
ts.tv_sec += timeout / 1000;
|
||||
ts.tv_nsec += (timeout % 1000) * 1000000;
|
||||
if (pthread_timedjoin_np(thread, NULL, &ts) != 0)
|
||||
{
|
||||
pthread_kill(thread, SIGTERM);
|
||||
|
||||
@@ -82,6 +82,18 @@ static inline const char* ffTimeToShortStr(uint64_t msec)
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Not thread-safe
|
||||
static inline const char* ffTimeToTimeStr(uint64_t msec)
|
||||
{
|
||||
if (msec == 0) return "";
|
||||
time_t tsec = (time_t) (msec / 1000);
|
||||
|
||||
static char buf[32];
|
||||
strftime(buf, sizeof(buf), "%T", localtime(&tsec));
|
||||
sprintf(buf + __builtin_strlen("00:00:00"), ".%03u", (unsigned) (msec % 1000));
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
+4
-5
@@ -683,8 +683,8 @@
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"IEC": "1024 Bytes = 1 KiB, 1024 KiB = 1 MiB, ...",
|
||||
"SI": "1000 Bytes = 1 KB, 1000 KB = 1 MB, ...",
|
||||
"JEDEC": "1024 Bytes = 1 kB, 1024 kB = 1 MB, ..."
|
||||
"SI": "1000 Bytes = 1 kB, 1000 kB = 1 MB, ...",
|
||||
"JEDEC": "1024 Bytes = 1 KB, 1024 KB = 1 MB, ..."
|
||||
},
|
||||
"default": "IEC"
|
||||
}
|
||||
@@ -1419,10 +1419,9 @@
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"auto": "Auto detection",
|
||||
"auto": "Prefer EGL on *nix; prefer platform specific implementation on others",
|
||||
"egl": "EGL",
|
||||
"glx": "GLX",
|
||||
"osmesa": "OSMesa"
|
||||
"glx": "GLX (*nix only)"
|
||||
},
|
||||
"default": "auto"
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
// https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419
|
||||
int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8;
|
||||
int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0');
|
||||
int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '5');
|
||||
int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '0');
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ const char* parseBattery(int dfd, const char* battId, FFlist* results)
|
||||
if (ioctl(fd, GET_EXTENDED_BATTERY_INFO, &extended, sizeof(extended)) != 0)
|
||||
return "ioctl(GET_EXTENDED_BATTERY_INFO) failed";
|
||||
|
||||
if (extended.last_full_charge == (uint32)-1)
|
||||
return "Skipped";
|
||||
|
||||
FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results);
|
||||
ffStrbufInitS(&battery->modelName, extended.model_number);
|
||||
ffStrbufInitS(&battery->manufacturer, extended.oem_info);
|
||||
|
||||
@@ -108,7 +108,7 @@ static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFl
|
||||
|
||||
if (ffReadFileBufferRelative(dfd, "capacity_level", &tmpBuffer))
|
||||
{
|
||||
ffStrbufTrimRightSpace(&result->manufacturer);
|
||||
ffStrbufTrimRightSpace(&tmpBuffer);
|
||||
if (ffStrbufEqualS(&tmpBuffer, "Critical"))
|
||||
{
|
||||
if (result->status.length)
|
||||
|
||||
@@ -70,9 +70,7 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r
|
||||
critical = true;
|
||||
}
|
||||
else if (ffStrEquals(desc, "discharge rate"))
|
||||
{
|
||||
prop_dictionary_get_uint(dict, "cur-value", &dischargeRate);
|
||||
}
|
||||
}
|
||||
|
||||
if (max > 0)
|
||||
@@ -92,7 +90,10 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r
|
||||
if (charging)
|
||||
ffStrbufAppendS(&battery->status, "Charging, ");
|
||||
else if (dischargeRate)
|
||||
{
|
||||
ffStrbufAppendS(&battery->status, "Discharging, ");
|
||||
battery->timeRemaining = (int32_t)((double)curr / dischargeRate * 3600);
|
||||
}
|
||||
if (critical)
|
||||
ffStrbufAppendS(&battery->status, "Critical, ");
|
||||
if (acConnected)
|
||||
@@ -100,8 +101,11 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r
|
||||
ffStrbufTrimRight(&battery->status, ' ');
|
||||
ffStrbufTrimRight(&battery->status, ',');
|
||||
}
|
||||
|
||||
prop_object_iterator_release(iter);
|
||||
}
|
||||
prop_object_iterator_release(itKey);
|
||||
prop_object_release(root);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ const char* ffDetectBios(FFBiosResult* result)
|
||||
{
|
||||
ffStrbufSetStatic(&result->type,
|
||||
ffPathExists("/dev/efi" /*efidev*/, FF_PATHTYPE_FILE) ||
|
||||
ffPathExists("/boot/efi/efi/" /*efi partition*/, FF_PATHTYPE_DIRECTORY)
|
||||
ffPathExists("/boot/efi/efi/" /*efi partition. Note /boot/efi exists on BIOS system*/, FF_PATHTYPE_DIRECTORY)
|
||||
? "UEFI" : "BIOS");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
const char *ffDetectBios(FFBiosResult *bios)
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_date", "/sys/class/dmi/id/bios_date", &bios->date);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_release", "/sys/class/dmi/id/bios_release", &bios->release);
|
||||
|
||||
@@ -27,6 +27,11 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
|
||||
};
|
||||
};
|
||||
} SYSTEM_BOOT_ENVIRONMENT_INFORMATION;
|
||||
#elif __OpenBSD__
|
||||
#include "common/io/io.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
typedef struct FFSmbiosBios
|
||||
@@ -89,8 +94,8 @@ const char* ffDetectBios(FFBiosResult* bios)
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
#elif __HAIKU__
|
||||
// Currently SMBIOS detection is supported in legency BIOS only
|
||||
#elif __HAIKU__ || __OpenBSD__
|
||||
// Currently SMBIOS detection is supported in legancy BIOS only
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
#endif
|
||||
|
||||
|
||||
@@ -21,5 +21,5 @@ const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MA
|
||||
if (bt_devenum((void*) enumDev, devices) < 0)
|
||||
return "bt_devenum() failed";
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
#import <IOBluetooth/IOBluetooth.h>
|
||||
|
||||
// For some reason the official declaration of IOBluetoothHostController don't include property `controllers`
|
||||
// For some reason the official declaration of IOBluetoothHostController doesn't include property `controllers`
|
||||
@interface IOBluetoothHostController()
|
||||
+ (id)controllers;
|
||||
@end
|
||||
|
||||
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothResult */)
|
||||
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
|
||||
{
|
||||
NSArray<IOBluetoothHostController*>* ctrls = IOBluetoothHostController.controllers;
|
||||
if(!ctrls)
|
||||
|
||||
@@ -83,7 +83,7 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
|
||||
ffStrbufInitS(&device->name, blri.localInfo.name);
|
||||
|
||||
BLUETOOTH_ADDRESS_STRUCT addr = { .ullLong = blri.localInfo.address };
|
||||
ffStrbufInitF(&device->address, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ffStrbufInitF(&device->address, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
addr.rgBytes[5],
|
||||
addr.rgBytes[4],
|
||||
addr.rgBytes[3],
|
||||
@@ -97,6 +97,8 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
|
||||
device->enabled = true;
|
||||
device->connectable = ffBluetoothIsConnectable(hRadio);
|
||||
device->discoverable = ffBluetoothIsDiscoverable(hRadio);
|
||||
|
||||
CloseHandle(hRadio);
|
||||
} while (ffBluetoothFindNextRadio(hFind, &hRadio));
|
||||
|
||||
ffBluetoothFindRadioClose(hFind);
|
||||
|
||||
@@ -6,6 +6,7 @@ typedef struct FFBootmgrResult
|
||||
{
|
||||
FFstrbuf name;
|
||||
FFstrbuf firmware;
|
||||
uint16_t order;
|
||||
bool secureBoot;
|
||||
} FFBootmgrResult;
|
||||
|
||||
|
||||
@@ -2,10 +2,22 @@
|
||||
#include "efi_helper.h"
|
||||
#include "common/io/io.h"
|
||||
|
||||
#include <sys/efiio.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <dev/efi/efiio.h>
|
||||
#else
|
||||
#include <sys/efiio.h>
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef __NetBSD__
|
||||
typedef uint16_t efi_char;
|
||||
#endif
|
||||
|
||||
#ifndef EFI_GLOBAL_VARIABLE
|
||||
#define EFI_GLOBAL_VARIABLE { 0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, { 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c } }
|
||||
#endif
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR);
|
||||
@@ -13,7 +25,7 @@ const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
|
||||
uint8_t buffer[2048];
|
||||
struct efi_var_ioc ioc = {
|
||||
.vendor = { 0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, { 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c } },
|
||||
.vendor = EFI_GLOBAL_VARIABLE,
|
||||
.data = buffer,
|
||||
};
|
||||
|
||||
@@ -23,8 +35,10 @@ const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
if (ioctl(efifd, EFIIOC_VAR_GET, &ioc) < 0 || ioc.datasize != 2)
|
||||
return "ioctl(EFIIOC_VAR_GET, BootCurrent) failed";
|
||||
|
||||
result->order = *(uint16_t*)buffer;
|
||||
|
||||
unsigned char hex[5];
|
||||
snprintf((char*) hex, sizeof(hex), "%04X", *(uint16_t*)buffer);
|
||||
snprintf((char*) hex, sizeof(hex), "%04X", result->order);
|
||||
ioc.datasize = sizeof(buffer);
|
||||
ioc.name = (efi_char[]){ 'B', 'o', 'o', 't', hex[0], hex[1], hex[2], hex[3], '\0' };
|
||||
ioc.namesize = sizeof("Boot####") * 2;
|
||||
|
||||
@@ -11,8 +11,10 @@ const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "BootCurrent-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) != 6)
|
||||
return "Failed to read efivar: BootCurrent";
|
||||
|
||||
uint16_t value = *(uint16_t *)&buffer[4];
|
||||
snprintf((char*) buffer, sizeof(buffer), FF_EFIVARS_PATH_PREFIX "Boot%04X-" FF_EFI_GLOBAL_GUID, value);
|
||||
|
||||
result->order = *(uint16_t *)&buffer[4];
|
||||
|
||||
snprintf((char*) buffer, sizeof(buffer), FF_EFIVARS_PATH_PREFIX "Boot%04X-" FF_EFI_GLOBAL_GUID, result->order);
|
||||
|
||||
ssize_t size = ffReadFileData((const char*) buffer, sizeof(buffer), buffer);
|
||||
if (size < 5 + (int) sizeof(FFEfiLoadOption) || size == (ssize_t) sizeof(buffer))
|
||||
@@ -20,7 +22,7 @@ const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
|
||||
ffEfiFillLoadOption((FFEfiLoadOption *)&buffer[4], result);
|
||||
|
||||
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "SecureBoot-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) == 6)
|
||||
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "SecureBoot-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) >= 5)
|
||||
result->secureBoot = buffer[4] == 1;
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "bootmgr.h"
|
||||
#include "efi_helper.h"
|
||||
#include "common/io/io.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
const char* enablePrivilege(const wchar_t* privilege)
|
||||
{
|
||||
HANDLE token;
|
||||
FF_AUTO_CLOSE_FD HANDLE token = NULL;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
|
||||
return "OpenProcessToken() failed";
|
||||
|
||||
@@ -32,13 +33,12 @@ const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
if (enablePrivilege(L"SeSystemEnvironmentPrivilege") != NULL)
|
||||
return "Failed to enable SeSystemEnvironmentPrivilege";
|
||||
|
||||
uint16_t value;
|
||||
if (GetFirmwareEnvironmentVariableW(L"BootCurrent", L"{" FF_EFI_GLOBAL_GUID L"}", &value, sizeof(value)) != 2)
|
||||
if (GetFirmwareEnvironmentVariableW(L"BootCurrent", L"{" FF_EFI_GLOBAL_GUID L"}", &result->order, sizeof(result->order)) != 2)
|
||||
return "GetFirmwareEnvironmentVariableW(BootCurrent) failed";
|
||||
|
||||
uint8_t buffer[2048];
|
||||
wchar_t key[16];
|
||||
swprintf(key, ARRAY_SIZE(key), L"Boot%04X", value);
|
||||
swprintf(key, ARRAY_SIZE(key), L"Boot%04X", result->order);
|
||||
uint32_t size = GetFirmwareEnvironmentVariableW(key, L"{" FF_EFI_GLOBAL_GUID L"}", buffer, sizeof(buffer));
|
||||
if (size < sizeof(FFEfiLoadOption) || size == ARRAY_SIZE(buffer))
|
||||
return "GetFirmwareEnvironmentVariableW(Boot####) failed";
|
||||
|
||||
@@ -7,6 +7,7 @@ typedef struct FFBrightnessResult
|
||||
{
|
||||
FFstrbuf name;
|
||||
double min, max, current;
|
||||
bool builtin;
|
||||
} FFBrightnessResult;
|
||||
|
||||
const char* ffDetectBrightness(FFBrightnessOptions* options, FFlist* result); // list of FFBrightnessResult
|
||||
|
||||
@@ -42,6 +42,7 @@ static const char* detectWithDisplayServices(const FFDisplayServerResult* displa
|
||||
brightness->max = 1;
|
||||
brightness->min = 0;
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
brightness->builtin = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,6 +112,7 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult*
|
||||
brightness->min = 0;
|
||||
brightness->current = current;
|
||||
ffStrbufInit(&brightness->name);
|
||||
brightness->builtin = false;
|
||||
|
||||
uint8_t edid[128] = {};
|
||||
if (IOAVServiceReadI2C(service, 0x50, 0x00, edid, ARRAY_SIZE(edid)) == KERN_SUCCESS)
|
||||
@@ -179,6 +181,7 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
brightness->min = 0;
|
||||
brightness->current = current;
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
brightness->builtin = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
|
||||
brightness->max = BACKLIGHTMAXLEVELS;
|
||||
brightness->min = 0;
|
||||
brightness->current = status.brightness;
|
||||
brightness->builtin = true;
|
||||
|
||||
struct backlight_info info;
|
||||
if(ioctl(blfd, BACKLIGHTGETINFO, &info) == 0)
|
||||
|
||||
@@ -74,6 +74,7 @@ static const char* detectWithBacklight(FFlist* result)
|
||||
brightness->max = ffStrbufToDouble(&buffer);
|
||||
brightness->min = 0;
|
||||
brightness->current = actualBrightness;
|
||||
brightness->builtin = true;
|
||||
}
|
||||
}
|
||||
ffStrbufSubstrBefore(&backlightDir, backlightDirLength);
|
||||
|
||||
@@ -7,7 +7,7 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
|
||||
// https://man.netbsd.org/NetBSD-10.1/acpiout.4#DESCRIPTION
|
||||
char key[] = "hw.acpi.acpiout0.brightness";
|
||||
char* pn = key + strlen("hw.acpi.acpiout");
|
||||
|
||||
|
||||
for (uint32_t i = 0; i <= 9; ++i)
|
||||
{
|
||||
*pn = (char) ('0' + i);
|
||||
@@ -20,6 +20,7 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
|
||||
brightness->max = 100;
|
||||
brightness->min = 0;
|
||||
brightness->current = value;
|
||||
brightness->builtin = true;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -8,23 +8,35 @@
|
||||
|
||||
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int devfd = open("/dev/ttyC0", O_RDONLY);
|
||||
char path[] = "/dev/ttyCX";
|
||||
for (char i = '0'; i <= '9'; ++i) {
|
||||
path[strlen("/dev/ttyC")] = i;
|
||||
|
||||
if (devfd < 0) return "open(dev/ttyC0, O_RDONLY) failed";
|
||||
FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY);
|
||||
|
||||
struct wsdisplay_param param = {
|
||||
.param = WSDISPLAYIO_PARAM_BRIGHTNESS,
|
||||
};
|
||||
if (devfd < 0) {
|
||||
if (errno == EACCES && i == '0')
|
||||
return "Permission denied when opening tty device";
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ioctl(devfd, WSDISPLAYIO_GETPARAM, ¶m) < 0)
|
||||
return "ioctl(WSDISPLAYIO_GETPARAM) failed";
|
||||
struct wsdisplay_param param = {
|
||||
.param = WSDISPLAYIO_PARAM_BRIGHTNESS,
|
||||
};
|
||||
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
ffStrbufInitStatic(&brightness->name, "wsdisplay");
|
||||
if (ioctl(devfd, WSDISPLAYIO_GETPARAM, ¶m) < 0)
|
||||
continue;
|
||||
|
||||
brightness->max = param.max;
|
||||
brightness->min = param.min;
|
||||
brightness->current = param.curval;
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
ffStrbufInitF(&brightness->name, "ttyC%c", i);
|
||||
|
||||
brightness->max = param.max;
|
||||
brightness->min = param.min;
|
||||
brightness->current = param.curval;
|
||||
brightness->builtin = true;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ static const char* detectWithWmi(FFlist* result)
|
||||
brightness->max = 100;
|
||||
brightness->min = 0;
|
||||
brightness->current = vtValue.get<uint8_t>();
|
||||
brightness->builtin = true;
|
||||
|
||||
ffStrbufInit(&brightness->name);
|
||||
if (FFWmiVariant vtName = record.get(L"InstanceName"))
|
||||
@@ -42,6 +43,7 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
FF_LIBRARY_LOAD(dxva2, "dlopen dxva2" FF_LIBRARY_EXTENSION " failed", "dxva2" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxva2, GetPhysicalMonitorsFromHMONITOR)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxva2, GetMonitorBrightness)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxva2, DestroyPhysicalMonitor)
|
||||
|
||||
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
|
||||
{
|
||||
@@ -61,7 +63,10 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
brightness->max = max;
|
||||
brightness->min = min;
|
||||
brightness->current = curr;
|
||||
brightness->builtin = false;
|
||||
}
|
||||
|
||||
ffDestroyPhysicalMonitor(physicalMonitor.hPhysicalMonitor);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
@@ -12,7 +12,10 @@ static const char* enumerateDevices(FFBtrfsResult* item, int dfd, FFstrbuf* buff
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = fdopendir(subfd);
|
||||
if(dirp == NULL)
|
||||
{
|
||||
close(subfd);
|
||||
return "fdopendir(\"/sys/fs/btrfs/UUID/devices\") == NULL";
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
|
||||
@@ -16,18 +16,18 @@ const char* ffDetectCamera(FFlist* result)
|
||||
#ifdef MAC_OS_X_VERSION_10_15
|
||||
FF_SUPPRESS_IO(); // #822
|
||||
|
||||
AVCaptureDeviceType deviceType;
|
||||
AVCaptureDeviceType deviceType = NULL;
|
||||
|
||||
#ifdef MAC_OS_VERSION_14_0
|
||||
// Strangely `@available(macOS 14.0, *)` doesn't work here (#1594)
|
||||
if (@available(macOS 14.0, *))
|
||||
{
|
||||
deviceType = AVCaptureDeviceTypeExternal;
|
||||
if (&AVCaptureDeviceTypeExternal)
|
||||
deviceType = AVCaptureDeviceTypeExternal;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (deviceType == NULL)
|
||||
deviceType = AVCaptureDeviceTypeExternalUnknown;
|
||||
}
|
||||
|
||||
AVCaptureDeviceDiscoverySession* session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera, deviceType]
|
||||
mediaType:AVMediaTypeVideo
|
||||
|
||||
@@ -37,7 +37,7 @@ const char* ffDetectCamera(FFlist* result)
|
||||
{
|
||||
case V4L2_COLORSPACE_SMPTE170M: ffStrbufInitStatic(&camera->colorspace, "SMPTE 170M"); break;
|
||||
case V4L2_COLORSPACE_SMPTE240M: ffStrbufInitStatic(&camera->colorspace, "SMPTE 240M"); break;
|
||||
case V4L2_COLORSPACE_BT878: ffStrbufInitStatic(&camera->colorspace, "BT.808"); break;
|
||||
case V4L2_COLORSPACE_BT878: ffStrbufInitStatic(&camera->colorspace, "BT.878"); break;
|
||||
case V4L2_COLORSPACE_470_SYSTEM_M: ffStrbufInitStatic(&camera->colorspace, "NTSC"); break;
|
||||
case V4L2_COLORSPACE_470_SYSTEM_BG: ffStrbufInitStatic(&camera->colorspace, "EBU 3213"); break;
|
||||
case V4L2_COLORSPACE_JPEG: ffStrbufInitStatic(&camera->colorspace, "JPEG"); break;
|
||||
|
||||
@@ -48,7 +48,7 @@ const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
IMFActivate* device = devices[i];
|
||||
IMFActivate* FF_AUTO_RELEASE_COM_OBJECT device = devices[i];
|
||||
|
||||
wchar_t buffer[256];
|
||||
uint32_t length = 0;
|
||||
@@ -90,9 +90,11 @@ const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
continue;
|
||||
|
||||
// Assume first type is the maximum resolution
|
||||
IMFMediaType* FF_AUTO_RELEASE_COM_OBJECT type = NULL;
|
||||
IMFMediaType* type = NULL;
|
||||
for (DWORD idx = 0; SUCCEEDED(handler->GetMediaTypeByIndex(idx, &type)); ++idx)
|
||||
{
|
||||
on_scope_exit destroyType([=] { type->Release(); });
|
||||
|
||||
GUID majorType;
|
||||
if (FAILED(type->GetMajorType(&majorType)) || majorType != MFMediaType_Video)
|
||||
continue;
|
||||
@@ -123,7 +125,7 @@ const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
}
|
||||
}
|
||||
|
||||
CoTaskMemFree(devices);
|
||||
if (devices) CoTaskMemFree(devices);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ const char* ffChassisTypeToString(uint32_t type)
|
||||
case 0x1A: return "Compact PCI";
|
||||
case 0x1B: return "Advanced TCA";
|
||||
case 0x1C: return "Blade";
|
||||
case 0x1D: return "Mobile Workstation";
|
||||
case 0x1E: return "Tablet";
|
||||
case 0x1F: return "Convertible";
|
||||
case 0x20: return "Detachable";
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "chassis.h"
|
||||
#include "detection/host/host.h"
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result)
|
||||
{
|
||||
FFHostResult host = {
|
||||
.family = ffStrbufCreate(),
|
||||
.name = ffStrbufCreate(),
|
||||
.version = ffStrbufCreate(),
|
||||
.sku = ffStrbufCreate(),
|
||||
.serial = ffStrbufCreate(),
|
||||
.uuid = ffStrbufCreate(),
|
||||
.vendor = ffStrbufCreate(),
|
||||
};
|
||||
if (ffDetectHost(&host) != NULL)
|
||||
return "Failed to detect host";
|
||||
|
||||
if (ffStrbufStartsWithS(&host.name, "MacBook "))
|
||||
ffStrbufSetStatic(&result->type, "Laptop");
|
||||
else if (ffStrbufStartsWithS(&host.name, "Mac mini ") ||
|
||||
ffStrbufStartsWithS(&host.name, "Mac Studio "))
|
||||
ffStrbufSetStatic(&result->type, "Mini PC");
|
||||
else if (ffStrbufStartsWithS(&host.name, "iMac "))
|
||||
ffStrbufSetStatic(&result->type, "All in One");
|
||||
else
|
||||
ffStrbufSetStatic(&result->type, "Desktop");
|
||||
|
||||
ffStrbufSet(&result->vendor, &host.vendor);
|
||||
|
||||
ffStrbufDestroy(&host.family);
|
||||
ffStrbufDestroy(&host.name);
|
||||
ffStrbufDestroy(&host.version);
|
||||
ffStrbufDestroy(&host.sku);
|
||||
ffStrbufDestroy(&host.serial);
|
||||
ffStrbufDestroy(&host.uuid);
|
||||
ffStrbufDestroy(&host.vendor);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -430,7 +430,6 @@ FF_MAYBE_UNUSED static uint16_t getPackageCount(FFstrbuf* cpuinfo)
|
||||
|
||||
while ((p = memmem(p, cpuinfo->length - (uint32_t) (p - cpuinfo->chars), "\nphysical id\t:", strlen("\nphysical id\t:"))))
|
||||
{
|
||||
if (!p) break;
|
||||
p += strlen("\nphysical id\t:");
|
||||
char* pend;
|
||||
unsigned long id = strtoul(p, &pend, 10);
|
||||
@@ -586,7 +585,6 @@ FF_MAYBE_UNUSED static uint16_t getLoongarchPropCount(FFstrbuf* cpuinfo, const c
|
||||
|
||||
while ((p = memmem(p, cpuinfo->length - (uint32_t) (p - cpuinfo->chars), key, keylen)))
|
||||
{
|
||||
if (!p) break;
|
||||
p += keylen;
|
||||
char* pend;
|
||||
unsigned long id = strtoul(p, &pend, 10);
|
||||
@@ -608,7 +606,7 @@ FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options,
|
||||
|
||||
#if __ANDROID__
|
||||
detectAndroid(cpu);
|
||||
#else
|
||||
#elif !__powerpc__ && !__powerpc
|
||||
detectSocName(cpu);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -9,12 +9,19 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static void freePropDict(prop_dictionary_t* pdict)
|
||||
{
|
||||
assert(pdict != NULL);
|
||||
if (*pdict == NULL) return;
|
||||
prop_object_release(*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";
|
||||
|
||||
prop_dictionary_t root = NULL;
|
||||
__attribute__((__cleanup__(freePropDict))) prop_dictionary_t root = NULL;
|
||||
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
|
||||
return "prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed";
|
||||
|
||||
|
||||
@@ -23,22 +23,24 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe
|
||||
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "brand");
|
||||
ffStrbufSetNS(&cpu->name, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
if (kn) ffStrbufSetNS(&cpu->name, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
}
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "vendor_id");
|
||||
ffStrbufSetNS(&cpu->vendor, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
if (kn) ffStrbufSetNS(&cpu->vendor, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
}
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "clock_MHz");
|
||||
if (kn->value.ui32 > cpu->frequencyBase)
|
||||
cpu->frequencyBase = kn->value.ui32;
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "clock_MHz");
|
||||
if (kn && kn->value.ui32 > cpu->frequencyBase)
|
||||
cpu->frequencyBase = kn->value.ui32;
|
||||
}
|
||||
|
||||
ks = kstat_lookup(kc, "unix", -1, "system_misc");
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0)
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "ncpus");
|
||||
cpu->coresLogical = cpu->coresPhysical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
if (kn) cpu->coresLogical = cpu->coresPhysical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -128,9 +128,13 @@ static const char* detectByRegistry(FFCPUResult* cpu)
|
||||
|
||||
if (cpu->coresLogical == 0)
|
||||
{
|
||||
DWORD cores;
|
||||
if (RegQueryInfoKeyW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor", NULL, NULL, &cores, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
||||
cpu->coresOnline = cpu->coresPhysical = cpu->coresLogical = (uint16_t) cores;
|
||||
FF_HKEY_AUTO_DESTROY hProcsKey = NULL;
|
||||
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &hProcsKey, NULL))
|
||||
{
|
||||
uint32_t cores;
|
||||
if (ffRegGetNSubKeys(hProcsKey, &cores, NULL))
|
||||
cpu->coresOnline = cpu->coresPhysical = cpu->coresLogical = (uint16_t) cores;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t mhz;
|
||||
|
||||
@@ -26,6 +26,8 @@ const char* detectThermalTemp(double* current, double* critical)
|
||||
else
|
||||
*critical = 0.0/0.0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "No WMI result returned";
|
||||
|
||||
@@ -31,7 +31,7 @@ const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
case CacheInstruction: cacheType = FF_CPU_CACHE_TYPE_INSTRUCTION; break;
|
||||
case CacheData: cacheType = FF_CPU_CACHE_TYPE_DATA; break;
|
||||
case CacheTrace: cacheType = FF_CPU_CACHE_TYPE_TRACE; break;
|
||||
default: __builtin_unreachable(); break;
|
||||
default: break;
|
||||
}
|
||||
ffCPUCacheAddItem(result, ptr->Cache.Level, ptr->Cache.CacheSize, ptr->Cache.LineSize, cacheType);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <mach/processor_info.h>
|
||||
#include <mach/mach_host.h>
|
||||
#include <mach/vm_map.h>
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
@@ -28,5 +29,7 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
.totalAll = (uint64_t)total,
|
||||
};
|
||||
}
|
||||
|
||||
vm_deallocate(mach_task_self(), (vm_address_t) cpuInfo, numCpuInfo * sizeof(integer_t));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
|
||||
return "geom_gettree() failed";
|
||||
}
|
||||
|
||||
for (cLabels = geomTree.lg_class.lh_first; !ffStrEquals(cLabels->lg_name, "LABEL"); cLabels = cLabels->lg_class.le_next);
|
||||
for (cLabels = geomTree.lg_class.lh_first; cLabels && !ffStrEquals(cLabels->lg_name, "LABEL"); cLabels = cLabels->lg_class.le_next);
|
||||
if (!cLabels)
|
||||
return "Class LABEL is not found";
|
||||
}
|
||||
@@ -165,7 +165,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
disk->bytesUsed = 0; // To be filled in ./disk.c
|
||||
|
||||
disk->filesTotal = (uint32_t) fs->f_files;
|
||||
disk->filesUsed = (uint32_t) (disk->filesTotal - (uint64_t)fs->f_ffree);
|
||||
disk->filesUsed = (uint32_t) (fs->f_files - fs->f_ffree);
|
||||
|
||||
ffStrbufInitS(&disk->mountFrom, fs->f_mntfromname);
|
||||
ffStrbufInitS(&disk->mountpoint, fs->f_mntonname);
|
||||
@@ -185,7 +185,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
#ifndef __DragonFly__
|
||||
struct stat st;
|
||||
if(stat(fs->f_mntonname, &st) == 0 && st.st_birthtimespec.tv_sec > 0)
|
||||
disk->createTime = (uint64_t)((st.st_birthtimespec.tv_sec * 1000) + (st.st_birthtimespec.tv_nsec / 1000000));
|
||||
disk->createTime = (uint64_t)(((uint64_t) st.st_birthtimespec.tv_sec * 1000) + ((uint64_t) st.st_birthtimespec.tv_nsec / 1000000));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
for (dev_t dev; (dev = next_dev(&pos)) >= B_OK;)
|
||||
{
|
||||
fs_info fs;
|
||||
if (fs_stat_dev(dev, &fs) < -1) continue;
|
||||
if (fs_stat_dev(dev, &fs) < 0) continue;
|
||||
|
||||
node_ref node(fs.dev, fs.root);
|
||||
BDirectory dir(&node);
|
||||
@@ -32,10 +32,10 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
disk->bytesTotal = (uint64_t)fs.total_blocks * (uint64_t) fs.block_size;
|
||||
disk->bytesFree = (uint64_t)fs.free_blocks * (uint64_t) fs.block_size;
|
||||
disk->bytesAvailable = disk->bytesFree;
|
||||
disk->bytesUsed = 0; // To be filled in ./disk. c
|
||||
disk->bytesUsed = 0; // To be filled in ./disk.c
|
||||
|
||||
disk->filesTotal = (uint32_t) fs.total_nodes;
|
||||
disk->filesUsed = (uint32_t) (disk->filesTotal - (uint64_t)fs.free_nodes);
|
||||
disk->filesUsed = (uint32_t) (fs.total_nodes - fs.free_nodes);
|
||||
|
||||
ffStrbufInitS(&disk->mountFrom, fs.device_name);
|
||||
ffStrbufInitS(&disk->mountpoint, path.Path());
|
||||
|
||||
@@ -209,7 +209,10 @@ static bool isRemovable(FFDisk* currentDisk)
|
||||
char sysBlockVolume[PATH_MAX]; // /sys/devices/pci0000:00/0000:00:14.0/usb4/4-3/4-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
|
||||
if (realpath(sysBlockPartition, sysBlockVolume) == NULL)
|
||||
return false;
|
||||
strcpy(strrchr(sysBlockVolume, '/') + 1, "removable");
|
||||
char* lastSlash = strrchr(sysBlockVolume, '/');
|
||||
if (lastSlash == NULL)
|
||||
return false;
|
||||
strcpy(lastSlash + 1, "removable");
|
||||
|
||||
char removableChar = '0';
|
||||
return ffReadFileData(sysBlockVolume, 1, &removableChar) > 0 && removableChar == '1';
|
||||
|
||||
@@ -99,9 +99,6 @@ static void detectStats(FFDisk* disk)
|
||||
ffStrbufSetS(&disk->name, fs.f_fstr);
|
||||
|
||||
disk->createTime = 0;
|
||||
struct stat deviceStat;
|
||||
if(stat(disk->mountpoint.chars, &deviceStat) == 0)
|
||||
disk->createTime = (uint64_t) deviceStat.st_ctim.tv_sec * 1000 + (uint64_t) deviceStat.st_ctim.tv_nsec / 1000000000;
|
||||
}
|
||||
|
||||
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
@@ -69,10 +69,15 @@ const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options)
|
||||
uint64_t temp = *currValue;
|
||||
*currValue -= *prevValue;
|
||||
*currValue /= (time2 - time1) / 1000 /* seconds */;
|
||||
|
||||
// For next function call
|
||||
*prevValue = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// For next function call
|
||||
time1 = time2;
|
||||
// Leak ioCounters1 here
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
|
||||
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
{
|
||||
struct gmesh geomTree;
|
||||
__attribute__((__cleanup__(geom_deletetree)))
|
||||
struct gmesh geomTree = {};
|
||||
if (geom_gettree(&geomTree) < 0)
|
||||
return "geom_gettree() failed";
|
||||
|
||||
@@ -21,6 +22,9 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
return "geom_stats_open() failed";
|
||||
|
||||
void* snap = geom_stats_snapshot_get();
|
||||
if (!snap)
|
||||
return "geom_stats_snapshot_get() failed";
|
||||
|
||||
struct devstat* snapIter;
|
||||
while ((snapIter = geom_stats_snapshot_next(snap)) != NULL)
|
||||
{
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static void parseDiskIOCounters(int dfd, const char* devName, FFlist* result, FFDiskIOOptions* options)
|
||||
static const char* parseDiskIOCounters(int dfd, const char* devName, FFlist* result, FFDiskIOOptions* options)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int devfd = openat(dfd, "device", O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
|
||||
if (devfd < 0) return; // virtual device
|
||||
if (devfd < 0) return "virtual device";
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
|
||||
|
||||
@@ -49,7 +49,7 @@ static void parseDiskIOCounters(int dfd, const char* devName, FFlist* result, FF
|
||||
}
|
||||
|
||||
if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix))
|
||||
return;
|
||||
return "ignored";
|
||||
}
|
||||
|
||||
// I/Os merges sectors ticks ...
|
||||
@@ -57,10 +57,10 @@ static void parseDiskIOCounters(int dfd, const char* devName, FFlist* result, FF
|
||||
{
|
||||
char sysBlockStat[PROC_FILE_BUFFSIZ];
|
||||
ssize_t fileSize = ffReadFileDataRelative(dfd, "stat", ARRAY_SIZE(sysBlockStat) - 1, sysBlockStat);
|
||||
if (fileSize <= 0) return;
|
||||
if (fileSize <= 0) return "failed to read stat file";
|
||||
sysBlockStat[fileSize] = '\0';
|
||||
if (sscanf(sysBlockStat, "%" PRIu64 "%*u%" PRIu64 "%*u%" PRIu64 "%*u%" PRIu64 "%*u", &nRead, §orRead, &nWritten, §orWritten) <= 0)
|
||||
return;
|
||||
return "invalid stat file format";
|
||||
}
|
||||
|
||||
FFDiskIOResult* device = (FFDiskIOResult*) ffListAdd(result);
|
||||
@@ -70,6 +70,8 @@ static void parseDiskIOCounters(int dfd, const char* devName, FFlist* result, FF
|
||||
device->bytesWritten = sectorWritten * 512;
|
||||
device->readCount = nRead;
|
||||
device->writeCount = nWritten;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
@@ -83,7 +85,7 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
{
|
||||
const char* const devName = sysBlockEntry->d_name;
|
||||
|
||||
if (devName[0] == '.') continue;;
|
||||
if (devName[0] == '.') continue;
|
||||
|
||||
FF_AUTO_CLOSE_FD int dfd = openat(dirfd(sysBlockDirp), devName, O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
|
||||
if (dfd > 0) parseDiskIOCounters(dfd, devName, result, options);
|
||||
|
||||
@@ -12,12 +12,12 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), NULL, &len, NULL, 0) < 0)
|
||||
return "sysctl({HW_IOSTATS}, NULL) failed";
|
||||
uint32_t nDrive = (uint32_t) (len / sizeof(struct io_sysctl));
|
||||
|
||||
struct io_sysctl* stats = malloc(len);
|
||||
|
||||
FF_AUTO_FREE struct io_sysctl* stats = malloc(len);
|
||||
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), stats, &len, NULL, 0) < 0)
|
||||
return "sysctl({HW_IOSTATS}, stats) failed";
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < nDrive; ++i)
|
||||
{
|
||||
struct io_sysctl* st = &stats[i];
|
||||
|
||||
@@ -13,7 +13,7 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
return "sysctl({HW_DISKSTATS}, NULL) failed";
|
||||
uint32_t nDrive = (uint32_t) (len / sizeof(struct diskstats));
|
||||
|
||||
struct diskstats* stats = malloc(len);
|
||||
FF_AUTO_FREE struct diskstats* stats = malloc(len);
|
||||
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), stats, &len, NULL, 0) < 0)
|
||||
return "sysctl({HW_DISKSTATS}, stats) failed";
|
||||
|
||||
@@ -27,7 +27,7 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
continue;
|
||||
|
||||
FFDiskIOResult* device = (FFDiskIOResult*) ffListAdd(result);
|
||||
ffStrbufInit(&device->devPath);
|
||||
ffStrbufInit(&device->devPath); // unlike other platforms, `/dev/ks_name` is not available
|
||||
ffStrbufInitS(&device->name, ks->ks_name);
|
||||
device->bytesRead = kio.nread;
|
||||
device->readCount = kio.reads;
|
||||
|
||||
@@ -56,8 +56,6 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFDiskIO
|
||||
return true;
|
||||
}
|
||||
|
||||
ffStrbufInitWS(&device->devPath, szDevice);
|
||||
|
||||
DISK_PERFORMANCE dp = {};
|
||||
if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &dp, sizeof(dp), &retSize, NULL))
|
||||
{
|
||||
@@ -72,6 +70,8 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFDiskIO
|
||||
result->length--;
|
||||
}
|
||||
|
||||
ffStrbufInitWS(&device->devPath, szDevice);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,33 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static bool checkHdrStatus(FFDisplayResult* display)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
if (ffSettingsGetAndroidProperty("ro.surface_flinger.has_HDR_display", &buffer))
|
||||
{
|
||||
if (ffStrbufIgnCaseEqualS(&buffer, "true"))
|
||||
{
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
|
||||
|
||||
if (ffSettingsGetAndroidProperty("persist.sys.hdr_mode", &buffer) &&
|
||||
ffStrbufToUInt(&buffer, 0) > 0)
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void detectWithDumpsys(FFDisplayServerResult* ds)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
|
||||
@@ -54,7 +81,7 @@ static void detectWithDumpsys(FFDisplayServerResult* ds)
|
||||
}
|
||||
|
||||
ffStrbufRecalculateLength(&name);
|
||||
ffdsAppendDisplay(ds,
|
||||
FFDisplayResult* display = ffdsAppendDisplay(ds,
|
||||
(uint32_t)width,
|
||||
(uint32_t)height,
|
||||
refreshRate,
|
||||
@@ -72,6 +99,7 @@ static void detectWithDumpsys(FFDisplayServerResult* ds)
|
||||
0,
|
||||
"dumpsys"
|
||||
);
|
||||
if (display) display->hdrStatus = checkHdrStatus(display);
|
||||
}
|
||||
|
||||
index = nextIndex + 1;
|
||||
@@ -92,7 +120,7 @@ static bool detectWithGetprop(FFDisplayServerResult* ds)
|
||||
uint32_t height = (uint32_t) ffStrbufToUInt(&buffer, 0);
|
||||
ffStrbufSubstrAfterFirstC(&buffer, ',');
|
||||
double scaleFactor = (double) ffStrbufToUInt(&buffer, 0) / 160.;
|
||||
return ffdsAppendDisplay(ds,
|
||||
FFDisplayResult* display = ffdsAppendDisplay(ds,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
@@ -110,6 +138,8 @@ static bool detectWithGetprop(FFDisplayServerResult* ds)
|
||||
0,
|
||||
"getprop"
|
||||
);
|
||||
if (display) display->hdrStatus = checkHdrStatus(display);
|
||||
return !!display;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -68,7 +68,7 @@ static void detectDisplays(FFDisplayServerResult* ds)
|
||||
if(displayInfo)
|
||||
{
|
||||
CFDictionaryRef productNames;
|
||||
if(!ffCfDictGetDict(displayInfo, CFSTR(kDisplayProductName), &productNames))
|
||||
if(ffCfDictGetDict(displayInfo, CFSTR(kDisplayProductName), &productNames) == NULL)
|
||||
ffCfDictGetString(productNames, CFSTR("en_US"), &buffer);
|
||||
|
||||
// CGDisplayScreenSize reports invalid result for external displays on old Intel MacBook Pro
|
||||
|
||||
@@ -189,26 +189,47 @@ static void detectDisplays(FFDisplayServerResult* ds)
|
||||
|
||||
if (display)
|
||||
{
|
||||
DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO advColorInfo = {
|
||||
DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO_2 advColorInfo2 = {
|
||||
.header = {
|
||||
.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO,
|
||||
.size = sizeof(advColorInfo),
|
||||
.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2,
|
||||
.size = sizeof(advColorInfo2),
|
||||
.adapterId = path->targetInfo.adapterId,
|
||||
.id = path->targetInfo.id,
|
||||
}
|
||||
};
|
||||
if (DisplayConfigGetDeviceInfo(&advColorInfo.header) == ERROR_SUCCESS)
|
||||
if (DisplayConfigGetDeviceInfo(&advColorInfo2.header) == ERROR_SUCCESS)
|
||||
{
|
||||
if (advColorInfo.advancedColorEnabled)
|
||||
if (advColorInfo2.highDynamicRangeUserEnabled)
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED;
|
||||
else if (advColorInfo.advancedColorSupported)
|
||||
else if (advColorInfo2.highDynamicRangeSupported)
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
|
||||
else
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
|
||||
display->bitDepth = (uint8_t) advColorInfo.bitsPerColorChannel;
|
||||
display->bitDepth = (uint8_t) advColorInfo2.bitsPerColorChannel;
|
||||
}
|
||||
else
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
|
||||
{
|
||||
DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO advColorInfo = {
|
||||
.header = {
|
||||
.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO,
|
||||
.size = sizeof(advColorInfo),
|
||||
.adapterId = path->targetInfo.adapterId,
|
||||
.id = path->targetInfo.id,
|
||||
}
|
||||
};
|
||||
if (DisplayConfigGetDeviceInfo(&advColorInfo.header) == ERROR_SUCCESS)
|
||||
{
|
||||
if (advColorInfo.advancedColorEnabled)
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED;
|
||||
else if (advColorInfo.advancedColorSupported)
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
|
||||
else
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
|
||||
display->bitDepth = (uint8_t) advColorInfo.bitsPerColorChannel;
|
||||
}
|
||||
else
|
||||
display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
|
||||
}
|
||||
if (edidLength > 0)
|
||||
ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ static const char* drmParseSysfs(FFDisplayServerResult* result)
|
||||
|
||||
char buf;
|
||||
ffStrbufAppendS(&drmDir, "/enabled");
|
||||
if (!ffReadFileData(drmDir.chars, sizeof(buf), &buf) || buf != 'e') {
|
||||
if (ffReadFileData(drmDir.chars, sizeof(buf), &buf) <= 0 || buf != 'e') {
|
||||
/* read failed or enabled != "enabled" */
|
||||
ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength);
|
||||
ffStrbufAppendS(&drmDir, "/status");
|
||||
|
||||
@@ -273,7 +273,7 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result)
|
||||
FF_LIST_FOR_EACH(FFstrbuf, basePath, instance.state.platform.configDirs)
|
||||
{
|
||||
char path[1024];
|
||||
snprintf(path, ARRAY_SIZE(path) - 1, "%s%s", basePath->chars, fileName);
|
||||
snprintf(path, ARRAY_SIZE(path), "%s%s", basePath->chars, fileName);
|
||||
if (ffReadFileBuffer(path, &monitorsXml))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ static const char* getFromProcesses(FFDisplayServerResult* result)
|
||||
ffStrbufAppendS(&procPath, dirent->d_name);
|
||||
uint32_t procFolderPathLength = procPath.length;
|
||||
|
||||
//Don't check for processes not owend by the current user.
|
||||
//Don't check for processes not owned by the current user.
|
||||
ffStrbufAppendS(&procPath, "/loginuid");
|
||||
ffReadFileBuffer(procPath.chars, &loginuid);
|
||||
if(ffStrbufToUInt(&loginuid, (uint64_t) -1) != userId)
|
||||
|
||||
@@ -26,7 +26,7 @@ typedef struct XcbPropertyData
|
||||
FF_LIBRARY_SYMBOL(xcb_get_atom_name_reply)
|
||||
} XcbPropertyData;
|
||||
|
||||
static bool xcbInitPropertyData(void* libraryHandle, XcbPropertyData* propertyData)
|
||||
static bool xcbInitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, XcbPropertyData* propertyData)
|
||||
{
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_intern_atom, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_intern_atom_reply, false)
|
||||
@@ -333,7 +333,7 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
|
||||
|
||||
const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(xcbRandr, "dlopen lbxcb-randr failed", "libxcb-randr" FF_LIBRARY_EXTENSION, 1)
|
||||
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_get_setup)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_setup_roots_iterator)
|
||||
@@ -369,7 +369,7 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
|
||||
data.connection = ffxcb_connect(NULL, NULL);
|
||||
if(data.connection == NULL)
|
||||
return "xcb_connect failed";
|
||||
return "xcb_connect() failed";
|
||||
|
||||
|
||||
data.result = result;
|
||||
|
||||
@@ -17,7 +17,7 @@ typedef struct X11PropertyData
|
||||
FF_LIBRARY_SYMBOL(XFree)
|
||||
} X11PropertyData;
|
||||
|
||||
static bool x11InitPropertyData(void* libraryHandle, X11PropertyData* propertyData)
|
||||
static bool x11InitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, X11PropertyData* propertyData)
|
||||
{
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XInternAtom, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XGetWindowProperty, false)
|
||||
@@ -147,7 +147,7 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf*
|
||||
"xlib-randr-crtc"
|
||||
);
|
||||
|
||||
if (edidLength)
|
||||
if (item && edidLength)
|
||||
{
|
||||
item->hdrStatus = ffEdidGetHdrCompatible(edidData, edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
|
||||
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
|
||||
@@ -231,7 +231,7 @@ static bool xrandrHandleMonitors(XrandrData* data, Screen* screen)
|
||||
if(monitorInfos == NULL)
|
||||
return false;
|
||||
|
||||
bool foundAMonitor;
|
||||
bool foundAMonitor = false;
|
||||
|
||||
for(int i = 0; i < numberOfMonitors; i++)
|
||||
{
|
||||
@@ -272,7 +272,7 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen)
|
||||
0,
|
||||
(uint32_t) WidthMMOfScreen(screen),
|
||||
(uint32_t) HeightMMOfScreen(screen),
|
||||
"xlib_randr_screen"
|
||||
"xlib-randr-screen"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "detection/dns/dns.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/apple/cf_helpers.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#include <SystemConfiguration/SystemConfiguration.h>
|
||||
|
||||
static const char* detectDnsFromConf(const char* path, FFDNSOptions* options, FFlist* results)
|
||||
{
|
||||
FF_DEBUG("Attempting to read DNS config from %s", path);
|
||||
|
||||
FF_AUTO_CLOSE_FILE FILE* file = fopen(path, "r");
|
||||
if (!file)
|
||||
{
|
||||
FF_DEBUG("Failed to open %s: %m", path);
|
||||
return "fopen(path, r) failed";
|
||||
}
|
||||
|
||||
if (results->length > 0)
|
||||
{
|
||||
FF_DEBUG("Clearing existing DNS entries (%u entries)", results->length);
|
||||
FF_LIST_FOR_EACH(FFstrbuf, item, *results)
|
||||
ffStrbufDestroy(item);
|
||||
ffListClear(results);
|
||||
}
|
||||
|
||||
FF_AUTO_FREE char* line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
while (getline(&line, &len, file) != -1)
|
||||
{
|
||||
if (ffStrStartsWith(line, "nameserver"))
|
||||
{
|
||||
char* nameserver = line + strlen("nameserver");
|
||||
while (*nameserver == ' ' || *nameserver == '\t')
|
||||
nameserver++;
|
||||
if (*nameserver == '\0') continue;
|
||||
|
||||
char* comment = strchr(nameserver, '#');
|
||||
if (comment) *comment = '\0';
|
||||
|
||||
if ((ffStrContainsC(nameserver, ':') && !(options->showType & FF_DNS_TYPE_IPV6_BIT)) ||
|
||||
(ffStrContainsC(nameserver, '.') && !(options->showType & FF_DNS_TYPE_IPV4_BIT)))
|
||||
continue;
|
||||
|
||||
FFstrbuf* item = (FFstrbuf*) ffListAdd(results);
|
||||
ffStrbufInitS(item, nameserver);
|
||||
ffStrbufTrimRightSpace(item);
|
||||
FF_DEBUG("Found DNS server: %s", item->chars);
|
||||
}
|
||||
}
|
||||
|
||||
FF_DEBUG("Found %u DNS servers in %s", results->length, path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectDNS(FFDNSOptions* options, FFlist* results)
|
||||
{
|
||||
// Handle macOS-specific DNS configurations
|
||||
FF_DEBUG("Using SystemConfiguration framework for macOS");
|
||||
|
||||
// Create a reference to the dynamic store
|
||||
FF_CFTYPE_AUTO_RELEASE SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("fastfetch"), NULL, NULL);
|
||||
if (store)
|
||||
{
|
||||
// Get the network global IPv4 and IPv6 configuration
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
|
||||
if (key)
|
||||
{
|
||||
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef dict = SCDynamicStoreCopyValue(store, key);
|
||||
if (dict)
|
||||
{
|
||||
// Get the DNS server addresses array
|
||||
CFArrayRef dnsServers = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
|
||||
|
||||
if (dnsServers)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(dnsServers); i++)
|
||||
{
|
||||
if (ffCfStrGetString(CFArrayGetValueAtIndex(dnsServers, i), &buffer) == NULL)
|
||||
{
|
||||
// Check if the address matches our filter
|
||||
if ((ffStrbufContainC(&buffer, ':') && !(options->showType & FF_DNS_TYPE_IPV6_BIT)) ||
|
||||
(ffStrbufContainC(&buffer, '.') && !(options->showType & FF_DNS_TYPE_IPV4_BIT)))
|
||||
continue;
|
||||
|
||||
// Add to results
|
||||
FFstrbuf* item = (FFstrbuf*) ffListAdd(results);
|
||||
ffStrbufInitMove(item, &buffer);
|
||||
FF_DEBUG("Found DNS server on macOS: %s", item->chars);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find any servers, try resolv.conf as fallback
|
||||
if (results->length > 0)
|
||||
return NULL;
|
||||
|
||||
FF_DEBUG("No DNS servers found via SystemConfiguration, trying resolv.conf");
|
||||
// Try standard resolv.conf location on macOS as a fallback
|
||||
return detectDnsFromConf("/var/run/resolv.conf", options, results);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#define RESOLV_CONF "/system/settings/network/resolv.conf"
|
||||
@@ -10,11 +11,24 @@
|
||||
#define RESOLV_CONF "/etc/resolv.conf"
|
||||
#endif
|
||||
|
||||
const char* ffDetectDNS(FFDNSOptions* options, FFlist* results)
|
||||
static const char* detectDnsFromConf(const char* path, FFDNSOptions* options, FFlist* results)
|
||||
{
|
||||
FF_AUTO_CLOSE_FILE FILE* file = fopen(FASTFETCH_TARGET_DIR_ROOT RESOLV_CONF, "r");
|
||||
FF_DEBUG("Attempting to read DNS config from %s", path);
|
||||
|
||||
FF_AUTO_CLOSE_FILE FILE* file = fopen(path, "r");
|
||||
if (!file)
|
||||
return "fopen (" FASTFETCH_TARGET_DIR_ROOT "/etc/resolv.conf) failed";
|
||||
{
|
||||
FF_DEBUG("Failed to open %s: %m", path);
|
||||
return "fopen(path, r) failed";
|
||||
}
|
||||
|
||||
if (results->length > 0)
|
||||
{
|
||||
FF_DEBUG("Clearing existing DNS entries (%u entries)", results->length);
|
||||
FF_LIST_FOR_EACH(FFstrbuf, item, *results)
|
||||
ffStrbufDestroy(item);
|
||||
ffListClear(results);
|
||||
}
|
||||
|
||||
FF_AUTO_FREE char* line = NULL;
|
||||
size_t len = 0;
|
||||
@@ -38,7 +52,90 @@ const char* ffDetectDNS(FFDNSOptions* options, FFlist* results)
|
||||
FFstrbuf* item = (FFstrbuf*) ffListAdd(results);
|
||||
ffStrbufInitS(item, nameserver);
|
||||
ffStrbufTrimRightSpace(item);
|
||||
FF_DEBUG("Found DNS server: %s", item->chars);
|
||||
}
|
||||
}
|
||||
|
||||
FF_DEBUG("Found %u DNS servers in %s", results->length, path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectDNS(FFDNSOptions* options, FFlist* results)
|
||||
{
|
||||
FF_DEBUG("Starting DNS detection");
|
||||
|
||||
const char* error = detectDnsFromConf(FASTFETCH_TARGET_DIR_ROOT RESOLV_CONF, options, results);
|
||||
if (error != NULL)
|
||||
{
|
||||
FF_DEBUG("Error detecting DNS: %s", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
#if __linux__ && !__ANDROID__
|
||||
// Handle different DNS management services
|
||||
if (results->length == 1)
|
||||
{
|
||||
const FFstrbuf* firstEntry = FF_LIST_GET(FFstrbuf, *results, 0);
|
||||
|
||||
if (ffStrbufEqualS(firstEntry, "127.0.0.53"))
|
||||
{
|
||||
FF_DEBUG("Detected systemd-resolved (127.0.0.53), checking actual DNS servers");
|
||||
// Managed by systemd-resolved
|
||||
if (detectDnsFromConf("/run/systemd/resolve/resolv.conf", options, results) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
else if (ffStrbufEqualS(firstEntry, "127.0.0.1"))
|
||||
{
|
||||
FF_DEBUG("Detected possible NetworkManager (127.0.0.1), checking actual DNS servers");
|
||||
// Managed by NetworkManager
|
||||
if (detectDnsFromConf("/var/run/NetworkManager/resolv.conf", options, results) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Check other possible DNS configuration files
|
||||
if (results->length == 0)
|
||||
{
|
||||
FF_DEBUG("No DNS servers found, trying alternative config files");
|
||||
|
||||
// Try resolvconf
|
||||
FF_DEBUG("Trying resolvconf configuration");
|
||||
if (detectDnsFromConf(FASTFETCH_TARGET_DIR_ROOT "/run/resolvconf/resolv.conf", options, results) == NULL && results->length > 0)
|
||||
return NULL;
|
||||
|
||||
// Try dnsmasq
|
||||
FF_DEBUG("Trying dnsmasq configuration");
|
||||
if (detectDnsFromConf(FASTFETCH_TARGET_DIR_ROOT "/var/run/dnsmasq/resolv.conf", options, results) == NULL && results->length > 0)
|
||||
return NULL;
|
||||
|
||||
// Try openresolv
|
||||
FF_DEBUG("Trying openresolv configuration");
|
||||
if (detectDnsFromConf(FASTFETCH_TARGET_DIR_ROOT "/etc/resolv.conf.openresolv", options, results) == NULL && results->length > 0)
|
||||
return NULL;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
// Handle BSD-specific DNS configurations
|
||||
if (results->length == 0)
|
||||
{
|
||||
FF_DEBUG("No DNS servers found, trying BSD-specific config files");
|
||||
|
||||
// FreeBSD and other BSDs may use resolvconf service
|
||||
FF_DEBUG("Trying BSD resolvconf configuration");
|
||||
if (detectDnsFromConf(FASTFETCH_TARGET_DIR_ROOT "/var/run/resolvconf/resolv.conf", options, results) == NULL && results->length > 0)
|
||||
return NULL;
|
||||
|
||||
// Some BSDs store DNS configuration here
|
||||
FF_DEBUG("Trying BSD nameserver configuration");
|
||||
if (detectDnsFromConf(FASTFETCH_TARGET_DIR_ROOT "/var/run/nameserver", options, results) == NULL && results->length > 0)
|
||||
return NULL;
|
||||
|
||||
// Try common BSD paths
|
||||
FF_DEBUG("Trying BSD common paths");
|
||||
if (detectDnsFromConf(FASTFETCH_TARGET_DIR_ROOT "/etc/nameserver", options, results) == NULL && results->length > 0)
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
FF_DEBUG("DNS detection completed with %u servers found", results->length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifdef _WIN32
|
||||
static inline char* realpath(const char* restrict file_name, char* restrict resolved_name)
|
||||
{
|
||||
assert(resolved_name != NULL);
|
||||
return _fullpath(resolved_name, file_name, _MAX_PATH);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,8 +20,12 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
{
|
||||
snprintf(path, ARRAY_SIZE(path), "/dev/uhid%d", i);
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) continue;
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
break; // No more devices
|
||||
continue; // Device not found
|
||||
}
|
||||
report_desc_t repDesc = hid_get_report_desc(fd);
|
||||
if (!repDesc) continue;
|
||||
|
||||
@@ -53,6 +57,7 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
device->battery = 0;
|
||||
}
|
||||
}
|
||||
hid_end_parse(hData);
|
||||
}
|
||||
|
||||
hid_dispose_report_desc(repDesc);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include "3rdparty/display-library/adl_sdk.h"
|
||||
|
||||
// https://gpuopen-librariesandsdks.github.io/adl/modules.html
|
||||
|
||||
// Function to initialize the ADL2 interface and to obtain client's context handle.
|
||||
extern int ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK callback, int iEnumConnectedAdapters, ADL_CONTEXT_HANDLE* context);
|
||||
|
||||
// Destroy client's ADL context.
|
||||
extern int ADL2_Main_Control_Destroy(ADL_CONTEXT_HANDLE context);
|
||||
|
||||
// Retrieves adapter information for given adapter or all OS-known adapters.
|
||||
// Return ADL_OK on success, DESPITE THE OFFICIAL DOCUMENT SAYS IT RETURNS 1 FOR SUCCESS!
|
||||
extern int ADL2_Adapter_AdapterInfoX3_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* numAdapters, AdapterInfo** lppAdapterInfo);
|
||||
|
||||
// Function to retrieve Graphic Core Info.
|
||||
extern int ADL2_Adapter_Graphic_Core_Info_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLGraphicCoreInfo* pGraphicCoreInfo);
|
||||
|
||||
// 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);
|
||||
|
||||
// Function to get the ASICFamilyType from the adapter.
|
||||
extern int ADL2_Adapter_ASICFamilyType_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* lpAsicTypes, int* lpValids);
|
||||
|
||||
|
||||
// Function to retrieve current power management capabilities.
|
||||
extern int ADL2_Overdrive_Caps(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iSupported, int* iEnabled, int* iVersion);
|
||||
|
||||
|
||||
/////////// Overdrive 6 functions
|
||||
|
||||
// Function to retrieve current Overdrive and performance-related activity.
|
||||
extern int ADL2_Overdrive6_CurrentStatus_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLOD6CurrentStatus* lpCurrentStatus);
|
||||
|
||||
// Function to retrieve GPU temperature from the thermal controller.
|
||||
extern int ADL2_Overdrive6_Temperature_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* lpTemperature);
|
||||
|
||||
// Function to retrieve the current or default Overdrive clock ranges.
|
||||
extern int ADL2_Overdrive6_StateInfo_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int iStateType, ADLOD6StateInfo* lpStateInfo);
|
||||
|
||||
|
||||
/// Overdrive N functions
|
||||
|
||||
// Despite the name (N means Next), this is actually Overdrive7 API
|
||||
// https://github.com/GPUOpen-LibrariesAndSDKs/display-library/blob/master/Sample/OverdriveN/OverdriveN.cpp#L209
|
||||
|
||||
// Function to retrieve the OverdriveN capabilities.
|
||||
extern int ADL2_OverdriveN_CapabilitiesX2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLODNCapabilitiesX2* lpODCapabilities);
|
||||
|
||||
// Function to retrieve the current OD performance status.
|
||||
extern int ADL2_OverdriveN_PerformanceStatus_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLODNPerformanceStatus *lpODPerformanceStatus);
|
||||
|
||||
// Function to retrieve the current temperature.
|
||||
extern int ADL2_OverdriveN_Temperature_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int iTemperatureType, int *iTemperature);
|
||||
|
||||
// Function to retrieve the current GPU clocks settings.
|
||||
extern int ADL2_OverdriveN_SystemClocksX2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLODNPerformanceLevelsX2 *lpODPerformanceLevels);
|
||||
|
||||
|
||||
/// Overdrive 8 functions
|
||||
|
||||
// Function to retrieve the Overdrive8 current settings.
|
||||
extern int ADL2_Overdrive8_Current_Setting_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLOD8CurrentSetting *lpCurrentSetting);
|
||||
|
||||
// Function to retrieve the Overdrive8 current settings.
|
||||
extern int ADL2_New_QueryPMLogData_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLPMLogDataOutput *lpDataOutput);
|
||||
@@ -55,6 +55,7 @@ const char* detectByOpenGL(FFlist* gpus)
|
||||
ffStrbufInitMove(&gpu->name, &result.renderer);
|
||||
ffStrbufInit(&gpu->driver);
|
||||
ffStrbufInitF(&gpu->platformApi, "OpenGL %s", result.version.chars);
|
||||
ffStrbufInit(&gpu->memoryType);
|
||||
gpu->index = FF_GPU_INDEX_UNSET;
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
||||
|
||||
@@ -34,6 +34,7 @@ typedef struct FFGPUResult
|
||||
FFstrbuf name;
|
||||
FFstrbuf driver;
|
||||
FFstrbuf platformApi;
|
||||
FFstrbuf memoryType;
|
||||
double temperature;
|
||||
double coreUsage;
|
||||
int32_t coreCount;
|
||||
|
||||
+505
-35
@@ -1,75 +1,545 @@
|
||||
#include "gpu_driver_specific.h"
|
||||
|
||||
// Everything detected in this file is static.
|
||||
// The real time monitoring requires ADLX, whose interface is much more complicated than AGS
|
||||
// Whoever has AMD graphic cards interested in this may contribute
|
||||
// * ADLX (AMD Device Library eXtra): https://github.com/GPUOpen-LibrariesAndSDKs/ADLX
|
||||
|
||||
#include "3rdparty/ags/amd_ags.h"
|
||||
#include "adl.h"
|
||||
#include "common/library.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
// Helper function to convert ADL status code to string
|
||||
FF_MAYBE_UNUSED static const char* ffAdlStatusToString(int status) {
|
||||
switch (status) {
|
||||
#define FF_ADL_STATUS_CASE(name) case name: return #name;
|
||||
FF_ADL_STATUS_CASE(ADL_OK)
|
||||
FF_ADL_STATUS_CASE(ADL_OK_WARNING)
|
||||
FF_ADL_STATUS_CASE(ADL_OK_MODE_CHANGE)
|
||||
FF_ADL_STATUS_CASE(ADL_OK_RESTART)
|
||||
FF_ADL_STATUS_CASE(ADL_OK_WAIT)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_NOT_INIT)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_INVALID_PARAM)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_INVALID_PARAM_SIZE)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_INVALID_ADL_IDX)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_INVALID_CONTROLLER_IDX)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_INVALID_DIPLAY_IDX)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_NOT_SUPPORTED)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_NULL_POINTER)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_DISABLED_ADAPTER)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_INVALID_CALLBACK)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_RESOURCE_CONFLICT)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_SET_INCOMPLETE)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_NO_XDISPLAY)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_CALL_TO_INCOMPATIABLE_DRIVER)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_NO_ADMINISTRATOR_PRIVILEGES)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_FEATURESYNC_NOT_STARTED)
|
||||
FF_ADL_STATUS_CASE(ADL_ERR_INVALID_POWER_STATE)
|
||||
#undef FF_ADL_STATUS_CASE
|
||||
default: return "Unknown ADL error";
|
||||
}
|
||||
}
|
||||
|
||||
// Memory allocation function
|
||||
static void* __attribute__((__stdcall__)) ffAdlMainMemoryAlloc(int iSize)
|
||||
{
|
||||
return malloc((size_t) iSize);
|
||||
}
|
||||
|
||||
struct FFAdlData {
|
||||
FF_LIBRARY_SYMBOL(ADL2_Main_Control_Destroy)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_AdapterInfoX3_Get)
|
||||
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)
|
||||
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_SystemClocksX2_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_PerformanceStatus_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_Temperature_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Overdrive8_Current_Setting_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_New_QueryPMLogData_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Overdrive6_CurrentStatus_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Overdrive6_Temperature_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Overdrive6_StateInfo_Get)
|
||||
|
||||
bool inited;
|
||||
ADL_CONTEXT_HANDLE apiHandle;
|
||||
} adlData;
|
||||
|
||||
static void shutdownAdl()
|
||||
{
|
||||
if (adlData.apiHandle)
|
||||
{
|
||||
FF_DEBUG("Destroying ADL context");
|
||||
adlData.ffADL2_Main_Control_Destroy(adlData.apiHandle);
|
||||
adlData.apiHandle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
|
||||
{
|
||||
static bool inited = false;
|
||||
static AGSGPUInfo gpuInfo;
|
||||
FF_DEBUG("Attempting to detect AMD GPU info using '%s'", soName);
|
||||
|
||||
if (!inited)
|
||||
if (!adlData.inited)
|
||||
{
|
||||
inited = true;
|
||||
FF_LIBRARY_LOAD(libags, "dlopen amd_ags failed", soName , 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libags, agsInitialize)
|
||||
adlData.inited = true;
|
||||
FF_DEBUG("Initializing ADL library");
|
||||
FF_LIBRARY_LOAD(atiadl, "dlopen atiadlxx failed", soName , 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(atiadl, ADL2_Main_Control_Create)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Main_Control_Destroy)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_AdapterInfoX3_Get)
|
||||
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)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_SystemClocksX2_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_PerformanceStatus_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive8_Current_Setting_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_New_QueryPMLogData_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_Temperature_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive6_CurrentStatus_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive6_Temperature_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive6_StateInfo_Get)
|
||||
FF_DEBUG("ADL library loaded");
|
||||
|
||||
struct AGSContext* apiHandle;
|
||||
if (ffagsInitialize(AGS_CURRENT_VERSION, NULL, &apiHandle, &gpuInfo) != AGS_SUCCESS)
|
||||
return "loading ags library failed";
|
||||
int result = ffADL2_Main_Control_Create(ffAdlMainMemoryAlloc, 1 /*iEnumConnectedAdapters*/, &adlData.apiHandle);
|
||||
FF_DEBUG("ADL2_Main_Control_Create returned %s (%d)", ffAdlStatusToString(result), result);
|
||||
if (result != ADL_OK)
|
||||
return "ffADL2_Main_Control_Create() failed";
|
||||
|
||||
// agsDeInitialize will free pointers allocated in gpuInfo. Just leak them.
|
||||
atexit(shutdownAdl);
|
||||
atiadl = NULL; // don't close atiadl
|
||||
FF_DEBUG("ADL initialization complete");
|
||||
}
|
||||
|
||||
if (gpuInfo.numDevices == 0)
|
||||
return "loading ags library failed or no AMD gpus found";
|
||||
|
||||
AGSDeviceInfo* device = NULL;
|
||||
|
||||
for (int iDev = 0; iDev < gpuInfo.numDevices; iDev++)
|
||||
if (!adlData.apiHandle)
|
||||
{
|
||||
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID)
|
||||
FF_DEBUG("ADL context not initialized");
|
||||
return "ffADL2_Main_Control_Create() failed";
|
||||
}
|
||||
|
||||
FF_AUTO_FREE AdapterInfo* devices = NULL;
|
||||
int numDevices = 0;
|
||||
int adapterResult = adlData.ffADL2_Adapter_AdapterInfoX3_Get(adlData.apiHandle, -1, &numDevices, &devices);
|
||||
FF_DEBUG("ADL2_Adapter_AdapterInfoX3_Get returned %s (%d)", ffAdlStatusToString(adapterResult), adapterResult);
|
||||
|
||||
if (adapterResult == ADL_OK)
|
||||
{
|
||||
FF_DEBUG("found %d adapters", numDevices);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("ffADL2_Adapter_AdapterInfoX3_Get() failed");
|
||||
return "ffADL2_Adapter_AdapterInfoX3_Get() failed";
|
||||
}
|
||||
|
||||
const AdapterInfo* device = NULL;
|
||||
for (int iDev = 0; iDev < numDevices; iDev++)
|
||||
{
|
||||
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
|
||||
{
|
||||
FF_DEBUG("Checking device %d: bus=%d, device=%d, func=%d against requested bus=%u, device=%u, func=%u",
|
||||
iDev, devices[iDev].iBusNumber, devices[iDev].iDeviceNumber, devices[iDev].iFunctionNumber,
|
||||
cond->pciBusId.bus, cond->pciBusId.device, cond->pciBusId.func);
|
||||
|
||||
if (
|
||||
cond->pciDeviceId.deviceId == (uint32_t) gpuInfo.devices[iDev].deviceId &&
|
||||
cond->pciDeviceId.vendorId == (uint32_t) gpuInfo.devices[iDev].vendorId &&
|
||||
cond->pciDeviceId.revId == (uint32_t) gpuInfo.devices[iDev].revisionId)
|
||||
cond->pciBusId.bus == (uint32_t) devices[iDev].iBusNumber &&
|
||||
cond->pciBusId.device == (uint32_t) devices[iDev].iDeviceNumber &&
|
||||
cond->pciBusId.func == (uint32_t) devices[iDev].iFunctionNumber)
|
||||
{
|
||||
device = &gpuInfo.devices[iDev];
|
||||
device = &devices[iDev];
|
||||
FF_DEBUG("Found matching device: %s (index: %d)", device->strAdapterName, device->iAdapterIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!device)
|
||||
{
|
||||
FF_DEBUG("Device not found");
|
||||
return "Device not found";
|
||||
}
|
||||
|
||||
if (result.coreCount)
|
||||
*result.coreCount = (uint32_t) device->numCUs;
|
||||
{
|
||||
ADLGraphicCoreInfo coreInfo;
|
||||
int status = adlData.ffADL2_Adapter_Graphic_Core_Info_Get(adlData.apiHandle, device->iAdapterIndex, &coreInfo);
|
||||
FF_DEBUG("ADL2_Adapter_Graphic_Core_Info_Get returned %s (%d)", ffAdlStatusToString(status), status);
|
||||
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
FF_DEBUG("Core info - NumCUs: %d, NumPEsPerCU: %d", coreInfo.iNumCUs, coreInfo.iNumPEsPerCU);
|
||||
*result.coreCount = (uint32_t) coreInfo.iNumCUs * (uint32_t) coreInfo.iNumPEsPerCU;
|
||||
FF_DEBUG("Got core count: %u", *result.coreCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get core count");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.memory)
|
||||
{
|
||||
result.memory->total = device->localMemoryInBytes;
|
||||
result.memory->used = FF_GPU_VMEM_SIZE_UNSET;
|
||||
int vramUsage = 0;
|
||||
int status = adlData.ffADL2_Adapter_DedicatedVRAMUsage_Get(adlData.apiHandle, device->iAdapterIndex, &vramUsage);
|
||||
FF_DEBUG("ADL2_Adapter_DedicatedVRAMUsage_Get returned %s (%d), usage: %d MB",
|
||||
ffAdlStatusToString(status), status, vramUsage);
|
||||
|
||||
if (status == ADL_OK) {
|
||||
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.frequency)
|
||||
*result.frequency = (uint32_t) device->coreClock; // Maximum frequency
|
||||
if (result.memoryType)
|
||||
{
|
||||
ADLMemoryInfo2 memoryInfo;
|
||||
int status = adlData.ffADL2_Adapter_MemoryInfo2_Get(adlData.apiHandle, device->iAdapterIndex, &memoryInfo);
|
||||
FF_DEBUG("ADL2_Adapter_MemoryInfo2_Get returned %s (%d)", ffAdlStatusToString(status), status);
|
||||
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
FF_DEBUG("Memory info - Type: %s, Size: %lld MB", memoryInfo.strMemoryType, memoryInfo.iMemorySize / 1024 / 1024);
|
||||
ffStrbufSetS(result.memoryType, memoryInfo.strMemoryType);
|
||||
FF_DEBUG("Got memory type: %s", memoryInfo.strMemoryType);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get memory type");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.type)
|
||||
*result.type = device->isAPU ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
{
|
||||
int asicTypes = 0;
|
||||
int valids = 0;
|
||||
int status = adlData.ffADL2_Adapter_ASICFamilyType_Get(adlData.apiHandle, device->iAdapterIndex, &asicTypes, &valids);
|
||||
FF_DEBUG("ADL2_Adapter_ASICFamilyType_Get returned %s (%d), asicTypes: 0x%x, valids: 0x%x",
|
||||
ffAdlStatusToString(status), status, asicTypes, valids);
|
||||
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
asicTypes &= valids; // This design is strange
|
||||
*result.type = asicTypes & ADL_ASIC_INTEGRATED ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
FF_DEBUG("GPU type: %s (asicTypes: 0x%x, valids: 0x%x)",
|
||||
*result.type == FF_GPU_TYPE_INTEGRATED ? "Integrated" : "Discrete", asicTypes, valids);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get GPU type");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.index)
|
||||
*result.index = (uint32_t) device->adlAdapterIndex;
|
||||
{
|
||||
*result.index = (uint32_t) device->iAdapterIndex;
|
||||
FF_DEBUG("Setting adapter index: %u", *result.index);
|
||||
}
|
||||
|
||||
if (result.name)
|
||||
ffStrbufSetS(result.name, device->adapterString);
|
||||
{
|
||||
ffStrbufSetS(result.name, device->strAdapterName);
|
||||
FF_DEBUG("Setting adapter name: %s; UDID: %s, Present: %d, Exist: %d", device->strAdapterName, device->strUDID, device->iPresent, device->iExist);
|
||||
}
|
||||
|
||||
int odVersion = 0;
|
||||
|
||||
{
|
||||
int odSupported = 0;
|
||||
int odEnabled = 0;
|
||||
int status = adlData.ffADL2_Overdrive_Caps(adlData.apiHandle, device->iAdapterIndex, &odSupported, &odEnabled, &odVersion);
|
||||
FF_DEBUG("ADL2_Overdrive_Caps returned %s (%d); supported %d, enabled %d; version %d",
|
||||
ffAdlStatusToString(status), status, odSupported, odEnabled, odVersion);
|
||||
if (status != ADL_OK)
|
||||
{
|
||||
FF_DEBUG("Overdrive not supported, results may be inaccurate");
|
||||
// Note even if Overdrive is not supported, we can still get the OD version
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (odVersion == 8)
|
||||
{
|
||||
FF_DEBUG("Using Overdrive8 API (odVersion=%d)", odVersion);
|
||||
|
||||
if (result.frequency)
|
||||
{
|
||||
ADLOD8CurrentSetting currentSetting = { .count = OD8_COUNT };
|
||||
int status = adlData.ffADL2_Overdrive8_Current_Setting_Get(adlData.apiHandle, device->iAdapterIndex, ¤tSetting);
|
||||
FF_DEBUG("ADL2_Overdrive8_Current_Setting_Get returned %s (%d)", ffAdlStatusToString(status), status);
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
FF_DEBUG("OD8 Settings count: %d", currentSetting.count);
|
||||
|
||||
*result.frequency = (uint32_t) currentSetting.Od8SettingTable[OD8_GFXCLK_FMAX];
|
||||
FF_DEBUG("Got max engine clock (OD8_GFXCLK_FMAX): %u MHz", *result.frequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get max frequency information");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.temp || result.coreUsage)
|
||||
{
|
||||
ADLPMLogDataOutput pmLogDataOutput = {};
|
||||
int status = adlData.ffADL2_New_QueryPMLogData_Get(adlData.apiHandle, device->iAdapterIndex, &pmLogDataOutput);
|
||||
FF_DEBUG("ADL2_New_QueryPMLogData_Get returned %s (%d)", ffAdlStatusToString(status), status);
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
if (result.temp)
|
||||
{
|
||||
ADLSingleSensorData* sensor = &pmLogDataOutput.sensors[ADL_PMLOG_TEMPERATURE_HOTSPOT];
|
||||
FF_DEBUG("Sensor %d: %s, supported: %d, value: %d", ADL_PMLOG_TEMPERATURE_HOTSPOT, "ADL_PMLOG_TEMPERATURE_HOTSPOT", sensor->supported, sensor->value);
|
||||
if (sensor->supported)
|
||||
{
|
||||
*result.temp = sensor->value;
|
||||
FF_DEBUG("Temperature: %.1f°C (HOTSPOT)", *result.temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
sensor = &pmLogDataOutput.sensors[ADL_PMLOG_TEMPERATURE_GFX];
|
||||
FF_DEBUG("Sensor %d: %s, supported: %d, value: %d", ADL_PMLOG_TEMPERATURE_GFX, "ADL_PMLOG_TEMPERATURE_GFX", sensor->supported, sensor->value);
|
||||
if (sensor->supported)
|
||||
{
|
||||
*result.temp = sensor->value;
|
||||
FF_DEBUG("Temperature: %.1f°C (GFX)", *result.temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
sensor = &pmLogDataOutput.sensors[ADL_PMLOG_TEMPERATURE_SOC];
|
||||
FF_DEBUG("Sensor %d: %s, supported: %d, value: %d", ADL_PMLOG_TEMPERATURE_SOC, "ADL_PMLOG_TEMPERATURE_SOC", sensor->supported, sensor->value);
|
||||
if (sensor->supported)
|
||||
{
|
||||
*result.temp = sensor->value;
|
||||
FF_DEBUG("Temperature: %.1f°C (SOC)", *result.temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("No supported temp sensor found, temp detection failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.coreUsage)
|
||||
{
|
||||
ADLSingleSensorData* activity = &pmLogDataOutput.sensors[ADL_PMLOG_INFO_ACTIVITY_GFX];
|
||||
FF_DEBUG("Sensor %d: %s, supported: %d, value: %d", ADL_PMLOG_INFO_ACTIVITY_GFX, "ADL_PMLOG_INFO_ACTIVITY_GFX", activity->supported, activity->value);
|
||||
if (activity->supported)
|
||||
{
|
||||
*result.coreUsage = activity->value;
|
||||
FF_DEBUG("Core usage: %.1f%%", *result.coreUsage);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Sensor %d not supported, GPU usage detection failed", ADL_PMLOG_INFO_ACTIVITY_GFX);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get temperature / GPU activity");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (odVersion == 7)
|
||||
{
|
||||
FF_DEBUG("Using OverdriveN API (odVersion=%d)", odVersion);
|
||||
|
||||
if (result.frequency)
|
||||
{
|
||||
// https://github.com/MaynardMiner/odvii/blob/master/OverdriveN.cpp#L176
|
||||
ADLODNCapabilitiesX2 odCapabilities = {};
|
||||
int status = adlData.ffADL2_OverdriveN_CapabilitiesX2_Get(adlData.apiHandle, device->iAdapterIndex, &odCapabilities);
|
||||
FF_DEBUG("ADL2_OverdriveN_CapabilitiesX2_Get returned %s (%d)", ffAdlStatusToString(status), status);
|
||||
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
if (odCapabilities.iMaximumNumberOfPerformanceLevels == 0)
|
||||
{
|
||||
FF_DEBUG("ADL2_OverdriveN_CapabilitiesX2_Get: no performance levels available");
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("ODN Capabilities - MaxPerformanceLevels: %d, GPU Clock Range: [%d - %d]",
|
||||
odCapabilities.iMaximumNumberOfPerformanceLevels,
|
||||
odCapabilities.sEngineClockRange.iMin, odCapabilities.sEngineClockRange.iMax);
|
||||
|
||||
size_t size = sizeof(ADLODNPerformanceLevelsX2) + sizeof(ADLODNPerformanceLevelX2) * ((unsigned) odCapabilities.iMaximumNumberOfPerformanceLevels - 1);
|
||||
FF_AUTO_FREE ADLODNPerformanceLevelsX2* odPerfLevels = calloc(size, 1);
|
||||
odPerfLevels->iSize = (int) size;
|
||||
odPerfLevels->iNumberOfPerformanceLevels = odCapabilities.iMaximumNumberOfPerformanceLevels;
|
||||
odPerfLevels->iMode = ODNControlType_Current;
|
||||
|
||||
int status = adlData.ffADL2_OverdriveN_SystemClocksX2_Get(adlData.apiHandle, device->iAdapterIndex, odPerfLevels);
|
||||
FF_DEBUG("ADL2_OverdriveN_SystemClocksX2_Get returned %s (%d), levels: %d",
|
||||
ffAdlStatusToString(status), status, odPerfLevels->iNumberOfPerformanceLevels);
|
||||
|
||||
if (status != ADL_OK)
|
||||
{
|
||||
FF_DEBUG("Failed to get frequency information");
|
||||
}
|
||||
else
|
||||
{
|
||||
// lowest to highest
|
||||
for (int i = odPerfLevels->iNumberOfPerformanceLevels - 1; i >= 0 ; i--)
|
||||
{
|
||||
ADLODNPerformanceLevelX2* level = &odPerfLevels->aLevels[i];
|
||||
FF_DEBUG("Performance level %d: enabled: %d, engine clock = %d", i, level->iEnabled, level->iClock);
|
||||
if (level->iEnabled)
|
||||
{
|
||||
*result.frequency = (uint32_t) level->iClock / 100; // in 10 kHz
|
||||
FF_DEBUG("Got max engine clock: %u MHz", *result.frequency);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get frequency information");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.coreUsage)
|
||||
{
|
||||
ADLODNPerformanceStatus performanceStatus = {};
|
||||
int status = adlData.ffADL2_OverdriveN_PerformanceStatus_Get(adlData.apiHandle, device->iAdapterIndex, &performanceStatus);
|
||||
FF_DEBUG("ADL2_OverdriveN_PerformanceStatus_Get returned %s (%d)", ffAdlStatusToString(status), status);
|
||||
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
FF_DEBUG("Performance Status - Activity: %d%%, CoreClock: %dMHz, MemoryClock: %dMHz",
|
||||
performanceStatus.iGPUActivityPercent,
|
||||
performanceStatus.iCoreClock,
|
||||
performanceStatus.iMemoryClock);
|
||||
|
||||
*result.coreUsage = performanceStatus.iGPUActivityPercent;
|
||||
FF_DEBUG("Got GPU activity: %d%%", performanceStatus.iGPUActivityPercent);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get GPU activity");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.temp)
|
||||
{
|
||||
int milliDegrees = 0;
|
||||
int status = adlData.ffADL2_OverdriveN_Temperature_Get(adlData.apiHandle, device->iAdapterIndex, 1, &milliDegrees);
|
||||
FF_DEBUG("ADL2_OverdriveN_Temperature_Get returned %s (%d)", ffAdlStatusToString(status), status);
|
||||
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
*result.temp = milliDegrees / 1000.0;
|
||||
FF_DEBUG("Temperature: %.1f°C (raw: %d milliC)", *result.temp, milliDegrees);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get temperature");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (odVersion == 6)
|
||||
{
|
||||
FF_DEBUG("Using Overdrive6 API (odVersion=%d)", odVersion);
|
||||
|
||||
if (result.frequency)
|
||||
{
|
||||
FF_AUTO_FREE ADLOD6StateInfo* stateInfo = calloc(sizeof(ADLOD6StateInfo) + sizeof(ADLOD6PerformanceLevel), 1);
|
||||
stateInfo->iNumberOfPerformanceLevels = 2;
|
||||
|
||||
int status = adlData.ffADL2_Overdrive6_StateInfo_Get(adlData.apiHandle, device->iAdapterIndex, ADL_OD6_GETSTATEINFO_CUSTOM_PERFORMANCE, stateInfo);
|
||||
FF_DEBUG("ADL2_Overdrive6_StateInfo_Get returned %s (%d), performance levels: %d",
|
||||
ffAdlStatusToString(status), status, stateInfo->iNumberOfPerformanceLevels);
|
||||
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
// OD6 uses clock ranges instead of discrete performance levels.
|
||||
// iNumberOfPerformanceLevels is always 2.
|
||||
// The 1st level indicates the minimum clocks in the range.
|
||||
// The 2nd level indicates the maximum clocks in the range.
|
||||
if (stateInfo->iNumberOfPerformanceLevels != 2)
|
||||
{
|
||||
FF_DEBUG("ADL2_Overdrive6_StateInfo_Get: unexpected number of performance levels: %d", stateInfo->iNumberOfPerformanceLevels);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("OD6 Settings - MinPerformanceLevels: %d, MaxPerformanceLevels: %d",
|
||||
stateInfo->aLevels[0].iEngineClock, stateInfo->aLevels[1].iEngineClock);
|
||||
*result.frequency = (uint32_t) stateInfo->aLevels[1].iEngineClock / 100; // in 10 kHz
|
||||
FF_DEBUG("Got max engine clock: %u MHz", *result.frequency);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get frequency information");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.coreUsage)
|
||||
{
|
||||
ADLOD6CurrentStatus status = {};
|
||||
int apiStatus = adlData.ffADL2_Overdrive6_CurrentStatus_Get(adlData.apiHandle, device->iAdapterIndex, &status);
|
||||
FF_DEBUG("ADL2_Overdrive6_CurrentStatus_Get returned %s (%d)", ffAdlStatusToString(apiStatus), apiStatus);
|
||||
|
||||
if (apiStatus == ADL_OK)
|
||||
{
|
||||
*result.coreUsage = status.iActivityPercent;
|
||||
FF_DEBUG("Got GPU activity: %d%%", status.iActivityPercent);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get GPU activity");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.temp)
|
||||
{
|
||||
int milliDegrees = 0;
|
||||
int status = adlData.ffADL2_Overdrive6_Temperature_Get(adlData.apiHandle, device->iAdapterIndex, &milliDegrees);
|
||||
FF_DEBUG("ADL2_Overdrive6_Temperature_Get returned %s (%d), temperature: %d milliC",
|
||||
ffAdlStatusToString(status), status, milliDegrees);
|
||||
|
||||
if (status == ADL_OK)
|
||||
{
|
||||
*result.temp = milliDegrees / 1000.0;
|
||||
FF_DEBUG("Temperature: %.1f°C", *result.temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get temperature");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Unknown Overdrive version: %d", odVersion);
|
||||
return "Unknown Overdrive version";
|
||||
}
|
||||
FF_DEBUG("AMD GPU detection complete - returning success");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -18,11 +18,12 @@ static double detectGpuTemp(const FFstrbuf* gpuName)
|
||||
{
|
||||
switch (strtol(gpuName->chars + strlen("Apple M"), NULL, 10))
|
||||
{
|
||||
case 0: error = "Invalid Apple Silicon GPU"; break;
|
||||
case 1: error = ffDetectSmcTemps(FF_TEMP_GPU_M1X, &result); break;
|
||||
case 2: error = ffDetectSmcTemps(FF_TEMP_GPU_M2X, &result); break;
|
||||
case 3: error = ffDetectSmcTemps(FF_TEMP_GPU_M3X, &result); break;
|
||||
case 4: error = ffDetectSmcTemps(FF_TEMP_GPU_M4X, &result); break;
|
||||
default: error = "Unsupported Apple Silicon GPU";
|
||||
default: error = "Unsupported Apple Silicon GPU"; break;
|
||||
}
|
||||
}
|
||||
else if (ffStrbufStartsWithS(gpuName, "Intel"))
|
||||
@@ -102,7 +103,8 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
}
|
||||
|
||||
FFGPUResult* gpu = ffListAdd(gpus);
|
||||
|
||||
gpu->index = FF_GPU_INDEX_UNSET;
|
||||
ffStrbufInit(&gpu->memoryType);
|
||||
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
|
||||
gpu->type = FF_GPU_TYPE_UNKNOWN;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
@@ -112,7 +114,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
ffStrbufInit(&gpu->driver); // Ok for both Apple and Intel
|
||||
ffCfDictGetString(properties, CFSTR("CFBundleIdentifier"), &gpu->driver);
|
||||
|
||||
if(ffCfDictGetInt(properties, CFSTR("gpu-core-count"), &gpu->coreCount)) // For Apple
|
||||
if(ffCfDictGetInt(properties, CFSTR("gpu-core-count"), &gpu->coreCount) != NULL) // For Apple
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
||||
|
||||
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
|
||||
@@ -131,9 +133,9 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
if (ffCfDictGetInt64(perfStatistics, CFSTR("In use system memory"), (int64_t*) &vramUsed) != NULL)
|
||||
vramTotal = 0;
|
||||
}
|
||||
else if (ffCfDictGetInt64(perfStatistics, CFSTR("vramUsedBytes"), (int64_t*) &vramTotal) == NULL)
|
||||
else if (ffCfDictGetInt64(perfStatistics, CFSTR("vramFreeBytes"), (int64_t*) &vramTotal) == NULL)
|
||||
{
|
||||
if (ffCfDictGetInt64(perfStatistics, CFSTR("vramFreeBytes"), (int64_t*) &vramUsed) == NULL)
|
||||
if (ffCfDictGetInt64(perfStatistics, CFSTR("vramUsedBytes"), (int64_t*) &vramUsed) == NULL)
|
||||
vramTotal += vramUsed;
|
||||
else
|
||||
vramTotal = 0;
|
||||
@@ -143,15 +145,15 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
ffStrbufInit(&gpu->name);
|
||||
//IOAccelerator returns model / vendor-id properties for Apple Silicon, but not for Intel Iris GPUs.
|
||||
//Still needs testing for AMD's
|
||||
if(ffCfDictGetString(properties, CFSTR("model"), &gpu->name))
|
||||
if(ffCfDictGetString(properties, CFSTR("model"), &gpu->name) != NULL)
|
||||
{
|
||||
CFRelease(properties);
|
||||
properties = NULL;
|
||||
|
||||
io_registry_entry_t parentEntry;
|
||||
IORegistryEntryGetParentEntry(registryEntry, kIOServicePlane, &parentEntry);
|
||||
if(IORegistryEntryCreateCFProperties(parentEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t parentEntry = 0;
|
||||
if(IORegistryEntryGetParentEntry(registryEntry, kIOServicePlane, &parentEntry) != kIOReturnSuccess ||
|
||||
IORegistryEntryCreateCFProperties(parentEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
{
|
||||
IOObjectRelease(parentEntry);
|
||||
IOObjectRelease(registryEntry);
|
||||
continue;
|
||||
}
|
||||
@@ -179,7 +181,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
gpu->shared.total = vramTotal;
|
||||
gpu->shared.used = vramUsed;
|
||||
}
|
||||
else
|
||||
else if (gpu->type == FF_GPU_TYPE_DISCRETE)
|
||||
{
|
||||
gpu->dedicated.total = vramTotal;
|
||||
gpu->dedicated.used = vramUsed;
|
||||
|
||||
@@ -29,6 +29,7 @@ const char* ffGpuDetectDriverVersion(FFlist* gpus)
|
||||
ffStrbufAppendS(&x->driver, version.UTF8String);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return "Unsupported macOS version";
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return "open(\"/dev/pci\", O_RDONLY, 0) failed";
|
||||
|
||||
struct pci_conf confs[128];
|
||||
struct pci_match_conf match = {
|
||||
.pc_class = PCIC_DISPLAY,
|
||||
@@ -40,7 +43,8 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pc->pc_vendor));
|
||||
ffStrbufInit(&gpu->name);
|
||||
ffStrbufInitS(&gpu->driver, pc->pd_name);
|
||||
ffStrbufInit(&gpu->platformApi);
|
||||
ffStrbufInitStatic(&gpu->platformApi, "/dev/pci");
|
||||
ffStrbufInit(&gpu->memoryType);
|
||||
gpu->index = FF_GPU_INDEX_UNSET;
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
||||
@@ -77,7 +81,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
|
||||
ffGPUQueryAmdGpuName(pc->pc_device, pc->pc_revid, gpu);
|
||||
if (gpu->name.length == 0)
|
||||
ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu);
|
||||
ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu);
|
||||
}
|
||||
|
||||
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
|
||||
|
||||
@@ -41,6 +41,8 @@ typedef struct FFGpuDriverResult
|
||||
uint32_t* index;
|
||||
double* temp;
|
||||
FFGPUMemory* memory;
|
||||
FFstrbuf* memoryType;
|
||||
FFGPUMemory* sharedMemory;
|
||||
uint32_t* coreCount;
|
||||
double* coreUsage;
|
||||
FFGPUType* type;
|
||||
@@ -87,9 +89,9 @@ FF_MAYBE_UNUSED static inline bool getDriverSpecificDetectionFn(const char* vend
|
||||
{
|
||||
*pDetectFn = ffDetectAmdGpuInfo;
|
||||
#ifdef _WIN64
|
||||
*pDllName = "amd_ags_x64.dll";
|
||||
*pDllName = "atiadlxx.dll";
|
||||
#else
|
||||
*pDllName = "amd_ags_x86.dll";
|
||||
*pDllName = "atiadlxy.dll";
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user