mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
261 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5d6006006 | |||
| 18f3809681 | |||
| 1cd87dc994 | |||
| 1e58e04024 | |||
| 408d939664 | |||
| 9b1061719c | |||
| 179539ccba | |||
| 6d73ecb944 | |||
| b981e4fd8b | |||
| 8e660136e0 | |||
| 90ca39b464 | |||
| 63f7e15554 | |||
| ab37216f7d | |||
| 57440a7a45 | |||
| f50059dc7b | |||
| 92fb5cb0c1 | |||
| 5f84630276 | |||
| 22696fe3de | |||
| cd00820546 | |||
| 918153f974 | |||
| 58e67dcc7a | |||
| 940d15c2e6 | |||
| 9ffa46652d | |||
| d45dc53da0 | |||
| 00d1812e8d | |||
| 50dc260fd6 | |||
| bf99aeda92 | |||
| 397822d0db | |||
| 12746a9681 | |||
| 355e21c099 | |||
| 9036b891a8 | |||
| b7e4e91664 | |||
| aabab6dff5 | |||
| 62c2eb4d96 | |||
| c69a6b7640 | |||
| 0521513609 | |||
| a1c5fe2bf2 | |||
| 2d4a77b6f0 | |||
| 9027f72353 | |||
| fe0f292cec | |||
| 06ecd5a1ff | |||
| 8fdaa987e3 | |||
| 15804091b0 | |||
| d8b44a5eae | |||
| 6357dcc6b4 | |||
| 947cddd926 | |||
| 246ff0bc88 | |||
| 339de56407 | |||
| 795bbde459 | |||
| f32bf9e94f | |||
| 8facb7c6e9 | |||
| 92c65aad10 | |||
| 76d6e86fe5 | |||
| e3d7eab4df | |||
| ff8d4b46ef | |||
| 4fb7860a8e | |||
| f188e9518d | |||
| a39419b12a | |||
| 941502d718 | |||
| de146c6370 | |||
| 09efb0d897 | |||
| 8defffabff | |||
| 1b543b1eb8 | |||
| ab17fb08ef | |||
| a4bc3c812d | |||
| c8fcabf4cc | |||
| a961a964ff | |||
| 412de625b2 | |||
| b739736527 | |||
| 2b19f8078e | |||
| 56eabbe2cb | |||
| b0215aae37 | |||
| 86cfa4eded | |||
| bab1e4ff82 | |||
| 6ec59f8654 | |||
| d3459af71f | |||
| 00b5f17f0d | |||
| b8ad833b4b | |||
| fb412576e1 | |||
| d551651d63 | |||
| 4e234c52a3 | |||
| edc718d1d1 | |||
| 42e01e7b8f | |||
| 8edfda979e | |||
| cc3595c3a4 | |||
| 8c72792e31 | |||
| f7ebeb58e2 | |||
| ea4a4f0691 | |||
| 81984e6e97 | |||
| f46e97fc62 | |||
| 7821552761 | |||
| cd8a0fc5f1 | |||
| 30f32f1fb5 | |||
| 9af918b1ef | |||
| 37b8bb4fc0 | |||
| 66edea702e | |||
| 930fb06ca7 | |||
| ca9c67353f | |||
| ea6ad4ac86 | |||
| 6ed8aac6bb | |||
| cfabee4ba7 | |||
| 3a35f9735b | |||
| 05fa8b0994 | |||
| 07f6f93415 | |||
| d2de3a01bb | |||
| c9b7c65ba5 | |||
| 6ad8e68d26 | |||
| b128260eb2 | |||
| ecfaf4d54d | |||
| 72bdee7fbf | |||
| bdb9593c0d | |||
| 1e234754c2 | |||
| 4a4afdadb8 | |||
| 7cadece9a0 | |||
| 724ab6ba69 | |||
| 6370485dcb | |||
| 60d343ca14 | |||
| bdc844f857 | |||
| d49c018f86 | |||
| be2201b5fc | |||
| 9ba1cd1291 | |||
| 22fa9b51e8 | |||
| f781f8d9ea | |||
| 06ecc9c480 | |||
| 50288d91e4 | |||
| 499b4ff445 | |||
| dd0021cd5e | |||
| f5b70dd8b7 | |||
| 8f8ca11203 | |||
| 121d399641 | |||
| 26ae4eb21b | |||
| 52a81dbdc4 | |||
| f924a8bf06 | |||
| c7363f904a | |||
| 53ffe8459f | |||
| 1b702e123e | |||
| 14dccce393 | |||
| d040cc810f | |||
| 224bea2559 | |||
| 777d3e599d | |||
| 7c47bc2656 | |||
| e4d31381d8 | |||
| abf8d75454 | |||
| 2ce152beaf | |||
| 766ed07999 | |||
| ddc2131343 | |||
| b64d8a013d | |||
| e6db59fdde | |||
| 7ea0bbfb21 | |||
| ab041e0ad2 | |||
| 207f742624 | |||
| 68f0b11b6f | |||
| b86c0880b9 | |||
| 75f4a3d92d | |||
| 70fa1341a8 | |||
| 0a55314d37 | |||
| 2198e6123e | |||
| dd37ee0e50 | |||
| 7006ae0420 | |||
| 86458ab32a | |||
| 67ca907e38 | |||
| e15d06bbad | |||
| eb53797174 | |||
| c8c32a78b0 | |||
| 1c032624ac | |||
| 5087ea77b4 | |||
| b6b42e69c3 | |||
| 000a688bb6 | |||
| 3e25b213b1 | |||
| a69cf456ea | |||
| 072b76cb12 | |||
| ca8f54d331 | |||
| 6423feaa94 | |||
| 92ada88ea7 | |||
| 1789ef85d7 | |||
| 42509f115c | |||
| 340a58bda1 | |||
| 08dfd1321c | |||
| 45d324a8c6 | |||
| afa986efd4 | |||
| bc6e8c7813 | |||
| 627fee23d1 | |||
| 27b474f205 | |||
| 418c7eecc7 | |||
| 350250d640 | |||
| 3cc21905af | |||
| c698eb8eb5 | |||
| 463c24beb8 | |||
| a5d1b96ecc | |||
| 63106ebdc1 | |||
| fd36783adb | |||
| 3b5186da53 | |||
| 0140a46090 | |||
| 9c38e1255f | |||
| 663f9d69ff | |||
| d12e5ab801 | |||
| 1d770d85f6 | |||
| 5b00afe45d | |||
| 5b276567ac | |||
| 56566916e3 | |||
| 2c0b4ca3a2 | |||
| 54ffdd32dc | |||
| 64f24bdee9 | |||
| 4706f97bf0 | |||
| 0bdb198d52 | |||
| fc7710821e | |||
| e22a9990ec | |||
| fc7f3a1650 | |||
| 915af9546d | |||
| 54a68640ef | |||
| ec1af7c92b | |||
| a1e20270ad | |||
| 4996986ce6 | |||
| e6de2d4fd9 | |||
| 5347e74a1b | |||
| 0ea5639a22 | |||
| aa3a916d5a | |||
| 6e64b758bf | |||
| 49ef7fc51f | |||
| 0e9a5acdbd | |||
| 4f6e80e940 | |||
| df87cdfa6e | |||
| dee4b36a46 | |||
| d04a26337a | |||
| 2afe8d11d1 | |||
| f31d3b8b21 | |||
| 8a20af9917 | |||
| fc5c2f6213 | |||
| 6c314e148a | |||
| a86d0017a9 | |||
| 4038ed2656 | |||
| 0f4bb47c2f | |||
| 19f7c67ede | |||
| ff7e81ed81 | |||
| 681a102a2b | |||
| ba27f4f2ef | |||
| cbe33a4860 | |||
| 5847e3f269 | |||
| b248dfa01c | |||
| 357aa77e21 | |||
| a44bde6f94 | |||
| 5825bce57d | |||
| 996cdd3155 | |||
| 61cdfcabf8 | |||
| 359a77097c | |||
| 1323d007d3 | |||
| d2215f26ac | |||
| 958e7dbd8f | |||
| 5b10cde59f | |||
| e8f2b9a1c7 | |||
| 0686d1db4a | |||
| 7c284f9ee8 | |||
| dc04273bd7 | |||
| d698be6239 | |||
| e44df27c96 | |||
| b365d4cca1 | |||
| 19d3c948ad | |||
| 4a581039d5 | |||
| 79849fb2b5 | |||
| c116a5abdf | |||
| 8f082730a8 |
@@ -16,6 +16,15 @@ body:
|
||||
options:
|
||||
- label: I have checked the FAQ but the issue is not covered
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Not a known issue
|
||||
description: Please check if the issue is already known and being worked on.
|
||||
options:
|
||||
- label: I have checked the existing issues but the issue is not covered
|
||||
required: true
|
||||
- label: My issue is not about crashing on Fedora and KDE 6.6
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "### General description of the bug"
|
||||
|
||||
+107
-74
@@ -13,7 +13,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install codespell
|
||||
shell: bash
|
||||
@@ -32,13 +32,13 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: uname -a
|
||||
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_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
|
||||
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_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_THREADS=OFF
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
ffversion: ${{ steps.ffversion.outputs.ffversion }}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -93,28 +93,28 @@ jobs:
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 g++-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libchafa-dev directx-headers-dev rpm ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick --ignore-dependencies
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
|
||||
- name: Initialize CodeQL
|
||||
if: matrix.arch == 'amd64'
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: c
|
||||
|
||||
- name: configure project
|
||||
run: CC=gcc-13 CXX=g++-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
- name: perform CodeQL analysis
|
||||
if: matrix.arch == 'amd64'
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v4
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
cpack -V
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
@@ -164,7 +164,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -190,7 +190,7 @@ jobs:
|
||||
run: cmake --version
|
||||
|
||||
- name: configure project
|
||||
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_DIRECTX_HEADERS=Off .
|
||||
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
@@ -217,7 +217,7 @@ jobs:
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-i686
|
||||
path: ./fastfetch-*.*
|
||||
@@ -230,24 +230,24 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: armv7
|
||||
distro: ubuntu20.04
|
||||
distro: ubuntu22.04
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y software-properties-common ca-certificates gpg curl
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
|
||||
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
|
||||
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
|
||||
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -257,7 +257,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-armv7l
|
||||
path: ./fastfetch-*.*
|
||||
@@ -270,7 +270,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -283,7 +283,7 @@ jobs:
|
||||
uname -a
|
||||
apt-get update && apt-get install -y wget
|
||||
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -293,7 +293,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-armv6l
|
||||
path: ./fastfetch-*.*
|
||||
@@ -312,7 +312,7 @@ jobs:
|
||||
- arch: s390x
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -326,7 +326,7 @@ jobs:
|
||||
apt-get update && apt-get install -y software-properties-common
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -336,7 +336,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
@@ -345,7 +345,7 @@ jobs:
|
||||
name: Musl-amd64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: setup alpine linux
|
||||
uses: jirutka/setup-alpine@master
|
||||
@@ -374,7 +374,7 @@ jobs:
|
||||
shell: alpine.sh {0}
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-musl-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -394,7 +394,7 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -413,10 +413,10 @@ jobs:
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
- name: run fastfetch
|
||||
run: time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan --stat false
|
||||
|
||||
- name: run fastfetch --format json
|
||||
run: time ./fastfetch -c presets/ci.jsonc --format json
|
||||
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan --format json
|
||||
|
||||
- name: run flashfetch
|
||||
run: time ./flashfetch
|
||||
@@ -428,42 +428,80 @@ jobs:
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-macos-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
sunos-amd64:
|
||||
omnios-amd64:
|
||||
runs-on: ubuntu-latest
|
||||
name: SunOS-amd64
|
||||
name: OmniOS-amd64
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/omnios-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
envs: 'CMAKE_BUILD_TYPE'
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update --accept
|
||||
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick
|
||||
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja
|
||||
|
||||
run: |
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja .
|
||||
cmake --build . --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
cpack
|
||||
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-omnios-amd64")' >> CPackConfig.cmake
|
||||
cpack -V
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-sunos-amd64
|
||||
name: fastfetch-omnios-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
solaris-amd64:
|
||||
runs-on: ubuntu-latest
|
||||
name: Solaris-amd64
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/solaris-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
envs: 'CMAKE_BUILD_TYPE'
|
||||
release: "11.4-gcc-14"
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg install cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja dconf mesa
|
||||
|
||||
run: |
|
||||
export PKG_CONFIG_PATH=/usr/lib/64/pkgconfig
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja .
|
||||
cmake --build . --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-solaris-amd64")' >> CPackConfig.cmake
|
||||
cpack -V
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-solaris-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
freebsd-amd64:
|
||||
@@ -474,7 +512,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -483,7 +521,8 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '14.3'
|
||||
version: '15.0'
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg update
|
||||
@@ -498,7 +537,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-freebsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -511,7 +550,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -521,6 +560,7 @@ jobs:
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '7.8'
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg_add -u
|
||||
@@ -535,7 +575,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-openbsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -548,7 +588,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -558,6 +598,7 @@ jobs:
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '10.1'
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
|
||||
@@ -571,7 +612,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-netbsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -584,12 +625,13 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/dragonflybsd-vm@v1
|
||||
with:
|
||||
usesh: yes
|
||||
envs: 'CMAKE_BUILD_TYPE'
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update
|
||||
@@ -606,7 +648,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-dragonfly-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -619,7 +661,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -629,6 +671,7 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
@@ -641,13 +684,13 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-haiku-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
windows-hosts:
|
||||
name: Windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
|
||||
name: Windows-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
permissions:
|
||||
security-events: write
|
||||
@@ -660,41 +703,30 @@ jobs:
|
||||
msystem: CLANG64
|
||||
msystem-lower: clang64
|
||||
msys-arch: x86_64
|
||||
win7-compat-flag: OFF
|
||||
win7-compat-postfix: ""
|
||||
- arch: amd64
|
||||
runs-on: windows-latest
|
||||
msystem: CLANG64
|
||||
msystem-lower: clang64
|
||||
msys-arch: x86_64
|
||||
win7-compat-flag: ON
|
||||
win7-compat-postfix: "-win7"
|
||||
- arch: aarch64
|
||||
runs-on: windows-11-arm
|
||||
msystem: CLANGARM64
|
||||
msystem-lower: clangarm64
|
||||
msys-arch: aarch64
|
||||
win7-compat-flag: OFF
|
||||
win7-compat-postfix: ""
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
update: true
|
||||
install: git mingw-w64-clang-${{ matrix.msys-arch }}-7zip mingw-w64-clang-${{ matrix.msys-arch }}-cmake mingw-w64-clang-${{ matrix.msys-arch }}-clang mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-loader mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-headers mingw-w64-clang-${{ matrix.msys-arch }}-opencl-icd mingw-w64-clang-${{ matrix.msys-arch }}-opencl-headers mingw-w64-clang-${{ matrix.msys-arch }}-cppwinrt mingw-w64-clang-${{ matrix.msys-arch }}-imagemagick mingw-w64-clang-${{ matrix.msys-arch }}-chafa
|
||||
install: git mingw-w64-clang-${{ matrix.msys-arch }}-7zip mingw-w64-clang-${{ matrix.msys-arch }}-cmake mingw-w64-clang-${{ matrix.msys-arch }}-clang mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-loader mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-headers mingw-w64-clang-${{ matrix.msys-arch }}-opencl-icd mingw-w64-clang-${{ matrix.msys-arch }}-opencl-headers mingw-w64-clang-${{ matrix.msys-arch }}-cppwinrt mingw-w64-clang-${{ matrix.msys-arch }}-imagemagick mingw-w64-clang-${{ matrix.msys-arch }}-chafa mingw-w64-clang-${{ matrix.msys-arch }}-directx-headers
|
||||
|
||||
- name: print msys version
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_WIN7_COMPAT=${{ matrix.win7-compat-flag }} .
|
||||
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --verbose -j4
|
||||
@@ -723,9 +755,9 @@ jobs:
|
||||
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
id: upload-unsigned-artifact
|
||||
name: upload artifacts for signing
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
|
||||
name: fastfetch-windows-${{ matrix.arch }}
|
||||
path: |
|
||||
*.dll
|
||||
fastfetch.exe
|
||||
@@ -744,16 +776,16 @@ jobs:
|
||||
output-artifact-directory: '.'
|
||||
|
||||
- name: create zip archive
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: create 7z archive
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload true artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
|
||||
path: ./fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.*
|
||||
name: fastfetch-windows-${{ matrix.arch }}
|
||||
path: ./fastfetch-windows-${{ matrix.arch }}.*
|
||||
overwrite: true
|
||||
|
||||
release:
|
||||
@@ -772,7 +804,8 @@ jobs:
|
||||
- openbsd-amd64
|
||||
- netbsd-amd64
|
||||
- dragonfly-amd64
|
||||
- sunos-amd64
|
||||
- solaris-amd64
|
||||
- omnios-amd64
|
||||
- haiku-amd64
|
||||
- windows-hosts
|
||||
permissions:
|
||||
@@ -786,7 +819,7 @@ jobs:
|
||||
|
||||
- name: download artifacts
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: actions/download-artifact@v5
|
||||
uses: actions/download-artifact@v8
|
||||
|
||||
- name: create release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
|
||||
+87
-2
@@ -1,3 +1,88 @@
|
||||
# 2.61.0
|
||||
|
||||
Changes:
|
||||
* Support for Windows 7 and 8 has been removed.
|
||||
* Windows 8.1 is now the oldest version supported by fastfetch.
|
||||
* The GPU module on WSL no longer relies on `DXCore`.
|
||||
* The `directx-headers` dependency is no longer required.
|
||||
* Fastfetch on Linux is now pure C; a C++ compiler is no longer required.
|
||||
* GPU type detection is now slightly less accurate, but detection speed should be slightly faster.
|
||||
* The GPU module on Windows now uses `DXCore` for more accurate GPU type detection (requires Windows 10 or later).
|
||||
* This feature is built only when `DXCore` headers are available, which requires installing `mingw-w64-<msystem>-x86_64-directx-headers` on MSYS2.
|
||||
|
||||
Features:
|
||||
* Adds a `brightness` option for color display configuration (#2238, Colors)
|
||||
* Adds support for detecting Bluetooth keyboards on Linux (#2220, Keyboard)
|
||||
* Adds support for detecting GlazeWM (WM, macOS)
|
||||
* Adds a `showEmptySlots` option to display empty memory slots on Linux (#2222, PhysicalMemory)
|
||||
* Adds marketing product name detection on Asahi Linux (Host, Linux)
|
||||
* Adds support for new M5 Mac models (Host, macOS)
|
||||
* Improves SMBIOS robustness by validating malformed data and improving error handling
|
||||
* Improves reliability when terminating child processes (Processing, Windows)
|
||||
* Improves Intel Mac support by querying SMBIOS data directly (Global, macOS)
|
||||
* Includes numerous internal cleanups and optimizations
|
||||
|
||||
Bugfixes:
|
||||
* Fixes missing memory devices on some machines (PhysicalMemory)
|
||||
* Fixes CPUCache deduplication for shared caches (#2228, CPUCache, Linux)
|
||||
* Fixes WM version reporting for niri (#2218, WM, Linux)
|
||||
* Fixes SSID decoding issues from `iw` output (Wifi, Linux)
|
||||
* Fixes the CMD code page being changed after running fastfetch on Windows (#2245, Windows)
|
||||
|
||||
# 2.60.0
|
||||
|
||||
Changes:
|
||||
* The CMake option `ENABLE_WIN7_COMPAT:BOOLEAN` now defaults to `OFF` and will be removed in v2.61.0, effectively dropping support for Windows 7 in the next release.
|
||||
* This follows the Windows 7 deprecation notice introduced in v2.57.0.
|
||||
* `wm.detectPlugin` now defaults to `true` (WM)
|
||||
|
||||
Features:
|
||||
* Adds `{cwd}` for custom title formatting, which displays the current working directory (Title)
|
||||
* Adds support for detecting the Zed version (#2200, Editor)
|
||||
* Adds support for detecting `moss` packages (Packages, Linux)
|
||||
* Adds support for detecting komorebi, FancyWM, and GlazeWM (WM, Windows)
|
||||
* Adds support for WM plugin version detection on macOS (WM, macOS)
|
||||
* Adds support for retrieving the executable path on OpenBSD (#2195, OpenBSD)
|
||||
|
||||
Bugfixes:
|
||||
* Fixes a potential segmentation fault caused by dereferencing a negative index (#2198)
|
||||
* Fixes `tempSensor` parsing so that it accepts only string values (#2202, CPU)
|
||||
* Fixes an issue that unexpectedly caused fewer devices to be reported (Keyboard, Linux)
|
||||
* Improves WM detection on LXQt by querying WM settings only when no WM has already been detected (#2199, WM, Linux)
|
||||
* Fixes memory leaks in DBus connection handling and in the OpenGL EGL context lifecycle
|
||||
* Fixes niri version detection on Fedora (WM, Linux)
|
||||
* Includes various internal cleanups and optimizations
|
||||
|
||||
Logos:
|
||||
* Adds `RengeOS` (#2170)
|
||||
* Adds `Emmabuntüs` (#2207)
|
||||
* Updates Artix Linux (#2157)
|
||||
* Updates Linux Mint (#2186)
|
||||
* Renames `Refracted Devuan` to `Refracta`
|
||||
* Renames `ExodiaPredator` to `ExodiaOS`
|
||||
|
||||
# 2.59.0
|
||||
|
||||
Changes:
|
||||
* Fastfetch no longer relies on the unreliable environment variables `$USER` or `%USERPROFILE%` to determine the current username (Title)
|
||||
* People who set `$USER` to customize the Fastfetch title should use `{ "type": "title", "format": "your-custom-user-name" }` to achieve the same result.
|
||||
* Fastfetch no longer tries to probe inaccessible remote disk drives on Windows (Disk, Windows)
|
||||
* People who have remote drives may use `{ "type": "disk", "hideFolders": "X:\\" }` to ignore problematic ones.
|
||||
* This change removes some ugly hacks from the codebase and matches the behavior on `*nix`.
|
||||
|
||||
Features:
|
||||
* Adds Oracle Solaris support (#2176, SunOS)
|
||||
* Adds UID / SID detection (Title)
|
||||
* In custom format: `{user-id}`
|
||||
* Switches to native GPU detection on GNU/Hurd and removes the `libpciaccess` dependency (GPU, Hurd)
|
||||
* Improves memory size detection on macOS (Memory, macOS)
|
||||
* Avoids relying on `hw.memsize_usable` by default, which may not be available on older macOS versions
|
||||
* Improves Windows disk detection accuracy and performance (Disk, Windows)
|
||||
* Adds more ARM CPU parts and removes duplicated cases (CPU, ARM)
|
||||
|
||||
Logos:
|
||||
* Adds 6-color support to the NixOS logo (including the small variant) (#2180)
|
||||
|
||||
# 2.58.0
|
||||
|
||||
An early release to fix compatibility issues with KDE Plasma 6.6.
|
||||
@@ -13,7 +98,7 @@ Features:
|
||||
* Honors the `DBPath` and `RootDir` settings in `pacman.conf` when detecting Pacman packages (#2154, Packages, Linux)
|
||||
|
||||
Bugfixes:
|
||||
* Fixes a crash issues on KDE Plasma 6.6 (Display, Linux)
|
||||
* Fixes a crash issue on KDE Plasma 6.6 (Display, Linux)
|
||||
* Fixes the Command module not working with `--dynamic-interval` (#2152, Command)
|
||||
* Fixes Quartz Compositor version detection. It now correctly reports the version of `WindowServer` (`SkyLight`) instead of `WindowManager`. (WM, macOS)
|
||||
|
||||
@@ -40,7 +125,7 @@ Deprecation notice:
|
||||
* Support for Windows 7 (and 8.x) is deprecated and will be removed in a future release. Extended support for Windows 7 (and 8.1) ended on January 10, 2023. These versions do not officially support ANSI escape codes (running fastfetch on them requires a third-party terminal such as ConEmu). In addition, Windows 7 lacks some APIs used by fastfetch. Fastfetch currently loads these APIs dynamically at runtime to maintain compatibility, but this adds complexity to the codebase and increases the maintenance burden.
|
||||
* A CMake flag `ENABLE_WIN7_COMPAT:BOOLEAN` has been introduced (defaults to `ON` for now). If set to `OFF`, Windows 7 compatibility code is excluded, and the resulting binaries will support only Windows 10 (version 1607 and later) and Windows 11.
|
||||
* The main prebuilt Windows binaries on the Release page (`fastfetch-windows-amd64.*`) are built with `ENABLE_WIN7_COMPAT=OFF`. These are the binaries used by `scoop` and `winget`. Users who need Windows 7 (or 8.x) support can download the `-win7` variant instead.
|
||||
* The `ENABLE_WIN7_COMPAT` CMake option and the `-win7` variant binaries are planned to be removed in 2.60.0.
|
||||
* ~~The `ENABLE_WIN7_COMPAT` CMake option and the `-win7` variant binaries are planned to be removed in 2.60.0~~.
|
||||
|
||||
Features:
|
||||
* Supports COSMIC DE version detection (DE, Linux)
|
||||
|
||||
+77
-43
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.58.0
|
||||
VERSION 2.61.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -89,10 +89,8 @@ cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR Ope
|
||||
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR ANDROID OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
|
||||
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "GNU" OFF)
|
||||
|
||||
option(ENABLE_ZLIB "Enable zlib" ON)
|
||||
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
|
||||
@@ -108,7 +106,10 @@ option(ENABLE_EMBEDDED_AMDGPUIDS "Embed amdgpu.ids into fastfetch, requires `pyt
|
||||
option(ENABLE_WORDEXP "Enable using of wordexp(3) if available, instead of glob(3)" ON)
|
||||
option(ENABLE_LIBZFS "Enable libzfs" ON)
|
||||
if(WIN32 AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
option(ENABLE_WIN7_COMPAT "Enable Windows 7 compatibility" ON)
|
||||
option(ENABLE_WIN81_COMPAT "Enable legacy Windows compatibility (Windows 8.1 and later; Windows 7 unsupported)" ON)
|
||||
endif()
|
||||
if(APPLE)
|
||||
option(ENABLE_APPLE_MEMSIZE_USABLE "Use usable memory size as total memory size in Memory module, to match other systems" OFF)
|
||||
endif()
|
||||
|
||||
set(BINARY_LINK_TYPE_OPTIONS dlopen dynamic static)
|
||||
@@ -157,7 +158,7 @@ set(WARNING_FLAGS "-Wall -Wextra -Wconversion -Werror=uninitialized -Werror=retu
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=incompatible-pointer-types -Werror=implicit-function-declaration -Werror=int-conversion")
|
||||
|
||||
if(WIN32 OR Haiku OR ENABLE_DIRECTX_HEADERS)
|
||||
if(WIN32 OR Haiku)
|
||||
enable_language(CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
|
||||
@@ -166,8 +167,8 @@ endif()
|
||||
if(WIN32)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--tsaware -Wl,--build-id")
|
||||
|
||||
if(ENABLE_WIN7_COMPAT)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,console,--major-os-version,6,--minor-os-version,1")
|
||||
if(ENABLE_WIN81_COMPAT)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,console,--major-os-version,6,--minor-os-version,3")
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,console,--major-os-version,10,--minor-os-version,0")
|
||||
endif()
|
||||
@@ -303,7 +304,8 @@ if(ENABLE_EMBEDDED_PCIIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_pciids
|
||||
RESULT_VARIABLE PYTHON_PCIIDS_RETCODE)
|
||||
if(NOT PYTHON_PCIIDS_RETCODE EQUAL 0)
|
||||
file(REMOVE "${PROJECT_BINARY_DIR}/fastfetch_pciids.c.inc")
|
||||
message(FATAL_ERROR "Failed to generate 'fastfetch_pciids.c.inc'")
|
||||
message(WARNING "Failed to generate 'fastfetch_pciids.c.inc'")
|
||||
set(ENABLE_EMBEDDED_PCIIDS OFF)
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Python3 is not found, 'fastfetch_pciids.c.inc' will not be generated")
|
||||
@@ -323,7 +325,8 @@ if(ENABLE_EMBEDDED_AMDGPUIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_amd
|
||||
RESULT_VARIABLE PYTHON_AMDGPUIDS_RETCODE)
|
||||
if(NOT PYTHON_AMDGPUIDS_RETCODE EQUAL 0)
|
||||
file(REMOVE "${PROJECT_BINARY_DIR}/fastfetch_amdgpuids.c.inc")
|
||||
message(FATAL_ERROR "Failed to generate 'fastfetch_amdgpuids.c.inc'")
|
||||
message(WARNING "Failed to generate 'fastfetch_amdgpuids.c.inc'")
|
||||
set(ENABLE_EMBEDDED_AMDGPUIDS OFF)
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Python3 is not found, 'fastfetch_amdgpuids.c.inc' will not be generated")
|
||||
@@ -396,7 +399,6 @@ set(LIBFASTFETCH_SRC
|
||||
src/common/impl/base64.c
|
||||
src/common/impl/FFlist.c
|
||||
src/common/impl/FFstrbuf.c
|
||||
src/common/impl/kmod.c
|
||||
src/common/impl/path.c
|
||||
src/common/impl/FFPlatform.c
|
||||
src/common/impl/smbiosHelper.c
|
||||
@@ -412,6 +414,7 @@ set(LIBFASTFETCH_SRC
|
||||
src/detection/editor/editor.c
|
||||
src/detection/font/font.c
|
||||
src/detection/gpu/gpu.c
|
||||
src/detection/host/host_mac.c
|
||||
src/detection/media/media.c
|
||||
src/detection/netio/netio.c
|
||||
src/detection/opencl/opencl.c
|
||||
@@ -521,6 +524,7 @@ if(LINUX)
|
||||
src/common/impl/processing_linux.c
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_linux.c
|
||||
src/common/impl/kmod_linux.c
|
||||
src/detection/battery/battery_linux.c
|
||||
src/detection/bios/bios_linux.c
|
||||
src/detection/board/board_linux.c
|
||||
@@ -557,9 +561,9 @@ if(LINUX)
|
||||
src/detection/gpu/gpu_linux.c
|
||||
src/detection/gpu/gpu_drm.c
|
||||
src/detection/gpu/gpu_pci.c
|
||||
src/detection/gpu/gpu_wsl.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_linux.c
|
||||
src/detection/host/host_mac.c
|
||||
src/detection/icons/icons_linux.c
|
||||
src/detection/initsystem/initsystem_linux.c
|
||||
src/detection/keyboard/keyboard_linux.c
|
||||
@@ -605,6 +609,7 @@ elseif(ANDROID)
|
||||
src/common/impl/processing_linux.c
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_linux.c
|
||||
src/common/impl/kmod_linux.c
|
||||
src/detection/battery/battery_android.c
|
||||
src/detection/bios/bios_android.c
|
||||
src/detection/bluetooth/bluetooth_nosupport.c
|
||||
@@ -679,6 +684,7 @@ elseif(FreeBSD)
|
||||
src/common/impl/sysctl.c
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_linux.c
|
||||
src/common/impl/kmod_bsd.c
|
||||
src/detection/battery/battery_bsd.c
|
||||
src/detection/bios/bios_bsd.c
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
@@ -716,7 +722,6 @@ elseif(FreeBSD)
|
||||
src/detection/gpu/gpu_pci.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_bsd.c
|
||||
src/detection/host/host_mac.c
|
||||
src/detection/lm/lm_linux.c
|
||||
src/detection/icons/icons_linux.c
|
||||
src/detection/initsystem/initsystem_linux.c
|
||||
@@ -772,6 +777,7 @@ elseif(NetBSD)
|
||||
src/common/impl/sysctl.c
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_linux.c
|
||||
src/common/impl/kmod_nbsd.c
|
||||
src/detection/battery/battery_nbsd.c
|
||||
src/detection/bios/bios_nbsd.c
|
||||
src/detection/bluetooth/bluetooth_bsd.c
|
||||
@@ -855,6 +861,7 @@ elseif(OpenBSD)
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_linux.c
|
||||
src/common/impl/smbiosHelper.c
|
||||
src/common/impl/kmod_nosupport.c
|
||||
src/detection/battery/battery_obsd.c
|
||||
src/detection/bios/bios_windows.c
|
||||
src/detection/bluetooth/bluetooth_nosupport.c
|
||||
@@ -936,18 +943,16 @@ elseif(APPLE)
|
||||
src/common/impl/sysctl.c
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_apple.c
|
||||
src/common/impl/kmod_apple.c
|
||||
src/common/apple/cf_helpers.c
|
||||
src/common/apple/osascript.m
|
||||
src/common/apple/smc_temps.c
|
||||
src/detection/battery/battery_apple.c
|
||||
src/detection/bios/bios_apple.c
|
||||
src/detection/bluetooth/bluetooth_apple.m
|
||||
src/detection/bluetoothradio/bluetoothradio_apple.m
|
||||
src/detection/board/board_apple.c
|
||||
src/detection/bootmgr/bootmgr_apple.c
|
||||
src/detection/brightness/brightness_apple.c
|
||||
src/detection/btrfs/btrfs_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
|
||||
@@ -955,14 +960,11 @@ elseif(APPLE)
|
||||
src/detection/disk/disk_bsd.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
|
||||
src/detection/displayserver/displayserver_apple.c
|
||||
src/detection/font/font_apple.m
|
||||
src/detection/gpu/gpu_apple.c
|
||||
src/detection/gpu/gpu_apple.m
|
||||
src/detection/host/host_apple.c
|
||||
src/detection/host/host_mac.c
|
||||
src/detection/icons/icons_nosupport.c
|
||||
src/detection/initsystem/initsystem_linux.c
|
||||
src/detection/keyboard/keyboard_apple.c
|
||||
@@ -998,6 +1000,24 @@ elseif(APPLE)
|
||||
src/detection/wmtheme/wmtheme_apple.m
|
||||
src/detection/camera/camera_apple.m
|
||||
)
|
||||
# CMAKE_SYSTEM_PROCESSOR has been normalized before
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64")
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/detection/bios/bios_windows.c
|
||||
src/detection/board/board_windows.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/host/host_windows.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
)
|
||||
else()
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/detection/bios/bios_apple.c
|
||||
src/detection/board/board_apple.c
|
||||
src/detection/chassis/chassis_apple.c
|
||||
src/detection/host/host_apple.c
|
||||
src/detection/physicalmemory/physicalmemory_apple.m
|
||||
)
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/impl/io_windows.c
|
||||
@@ -1007,11 +1027,13 @@ elseif(WIN32)
|
||||
src/common/impl/FFPlatform_windows.c
|
||||
src/common/impl/binary_windows.c
|
||||
src/common/impl/debug_windows.c
|
||||
src/common/impl/kmod_windows.c
|
||||
src/common/windows/getline.c
|
||||
src/common/windows/com.cpp
|
||||
src/common/windows/registry.c
|
||||
src/common/windows/unicode.c
|
||||
src/common/windows/wmi.cpp
|
||||
src/common/windows/variant.cpp
|
||||
src/common/windows/version.c
|
||||
src/detection/battery/battery_windows.c
|
||||
src/detection/bios/bios_windows.c
|
||||
@@ -1034,7 +1056,7 @@ elseif(WIN32)
|
||||
src/detection/dns/dns_windows.c
|
||||
src/detection/font/font_windows.c
|
||||
src/detection/gpu/gpu_windows.c
|
||||
src/detection/host/host_mac.c
|
||||
src/detection/gpu/gpu_windows.cpp
|
||||
src/detection/host/host_windows.c
|
||||
src/detection/icons/icons_windows.c
|
||||
src/detection/initsystem/initsystem_nosupport.c
|
||||
@@ -1051,7 +1073,7 @@ elseif(WIN32)
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/netio/netio_windows.c
|
||||
src/detection/opengl/opengl_windows.c
|
||||
src/detection/os/os_windows.cpp
|
||||
src/detection/os/os_windows.c
|
||||
src/detection/packages/packages_windows.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_windows.c
|
||||
@@ -1066,7 +1088,7 @@ elseif(WIN32)
|
||||
src/detection/users/users_windows.c
|
||||
src/detection/wallpaper/wallpaper_windows.c
|
||||
src/detection/wifi/wifi_windows.c
|
||||
src/detection/wm/wm_windows.cpp
|
||||
src/detection/wm/wm_windows.c
|
||||
src/detection/de/de_nosupport.c
|
||||
src/detection/wmtheme/wmtheme_windows.c
|
||||
src/detection/camera/camera_windows.cpp
|
||||
@@ -1080,6 +1102,7 @@ elseif(SunOS)
|
||||
src/common/impl/processing_linux.c
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_linux.c
|
||||
src/common/impl/kmod_sunos.c
|
||||
src/detection/battery/battery_nosupport.c
|
||||
src/detection/bios/bios_windows.c
|
||||
src/detection/board/board_windows.c
|
||||
@@ -1161,6 +1184,7 @@ elseif(Haiku)
|
||||
src/common/impl/processing_linux.c
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_linux.c
|
||||
src/common/impl/kmod_nosupport.c
|
||||
src/common/haiku/version.cpp
|
||||
src/detection/battery/battery_haiku.c
|
||||
src/detection/bios/bios_windows.c
|
||||
@@ -1230,6 +1254,7 @@ elseif(GNU)
|
||||
src/common/impl/processing_linux.c
|
||||
src/common/impl/FFPlatform_unix.c
|
||||
src/common/impl/binary_linux.c
|
||||
src/common/impl/kmod_nosupport.c
|
||||
src/detection/battery/battery_nosupport.c
|
||||
src/detection/bios/bios_nosupport.c
|
||||
src/detection/board/board_nosupport.c
|
||||
@@ -1259,7 +1284,7 @@ elseif(GNU)
|
||||
src/detection/displayserver/linux/xcb.c
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_general.c
|
||||
src/detection/gpu/gpu_gnu.c
|
||||
src/detection/gpu/gpu_pci.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_nosupport.c
|
||||
@@ -1301,11 +1326,6 @@ elseif(GNU)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENABLE_DIRECTX_HEADERS)
|
||||
message(STATUS "Enabling DirectX headers for WSL")
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_wsl.cpp)
|
||||
endif()
|
||||
|
||||
# Proprietary GPU driver APIs
|
||||
if(LINUX OR FreeBSD OR WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_nvidia.c)
|
||||
@@ -1323,6 +1343,10 @@ endif()
|
||||
if(NOT WIN32)
|
||||
check_function_exists(pipe2 HAVE_PIPE2)
|
||||
endif()
|
||||
check_function_exists(memrchr HAVE_MEMRCHR)
|
||||
if(NOT HAVE_MEMRCHR)
|
||||
list(APPEND LIBFASTFETCH_SRC src/common/impl/memrchr.c)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SYSTEM_YYJSON)
|
||||
find_package(yyjson)
|
||||
@@ -1341,6 +1365,15 @@ add_library(libfastfetch OBJECT
|
||||
${LIBFASTFETCH_SRC}
|
||||
)
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles("int main(void){int arr[1];return _Countof(arr);}" COMPILER_SUPPORTS_COUNT_OF)
|
||||
if(COMPILER_SUPPORTS_COUNT_OF)
|
||||
message(STATUS "_Countof is supported by the compiler")
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_SUPPORTS_COUNT_OF=1)
|
||||
else()
|
||||
message(STATUS "_Countof is NOT supported by the compiler")
|
||||
endif()
|
||||
|
||||
if(yyjson_FOUND)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_USE_SYSTEM_YYJSON=1)
|
||||
target_link_libraries(libfastfetch PUBLIC yyjson::yyjson)
|
||||
@@ -1424,16 +1457,24 @@ elseif(GNU)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=0)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(ENABLE_APPLE_MEMSIZE_USABLE)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_APPLE_MEMSIZE_USABLE=1)
|
||||
else()
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_APPLE_MEMSIZE_USABLE=0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
check_function_exists(_msize HAVE_MSVC_MSIZE)
|
||||
if(HAVE_MSVC_MSIZE)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_MSVC_MSIZE=1)
|
||||
endif()
|
||||
|
||||
if(ENABLE_WIN7_COMPAT)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_WIN7_COMPAT=1)
|
||||
if(ENABLE_WIN81_COMPAT)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_WIN81_COMPAT=1)
|
||||
else()
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_WIN7_COMPAT=0)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_WIN81_COMPAT=0)
|
||||
endif()
|
||||
else()
|
||||
check_function_exists(malloc_usable_size HAVE_MALLOC_USABLE_SIZE)
|
||||
@@ -1626,14 +1667,6 @@ ff_lib_enable(ELF
|
||||
"libelf"
|
||||
"libelf"
|
||||
)
|
||||
ff_lib_enable(DIRECTX_HEADERS
|
||||
"DirectX-Headers"
|
||||
"DirectX-Headers"
|
||||
)
|
||||
ff_lib_enable(PCIACCESS
|
||||
"pciaccess"
|
||||
"pciaccess"
|
||||
)
|
||||
|
||||
if(ENABLE_THREADS)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS=1)
|
||||
@@ -1657,6 +1690,9 @@ if(ENABLE_LIBZFS)
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT HAVE_MEMRCHR)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_CUSTOM_MEMRCHR=1)
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
target_link_libraries(libfastfetch
|
||||
@@ -1693,7 +1729,6 @@ elseif(APPLE)
|
||||
)
|
||||
elseif(WIN32)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "dwmapi"
|
||||
PRIVATE "gdi32"
|
||||
PRIVATE "iphlpapi"
|
||||
PRIVATE "ole32"
|
||||
@@ -1703,12 +1738,11 @@ elseif(WIN32)
|
||||
PRIVATE "version"
|
||||
PRIVATE "hid"
|
||||
PRIVATE "wtsapi32"
|
||||
PRIVATE "imagehlp"
|
||||
PRIVATE "cfgmgr32"
|
||||
PRIVATE "propsys"
|
||||
PRIVATE "winbrand"
|
||||
PRIVATE "secur32"
|
||||
)
|
||||
if(NOT ENABLE_WIN7_COMPAT)
|
||||
if(NOT ENABLE_WIN81_COMPAT)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "mincore"
|
||||
)
|
||||
@@ -2089,7 +2123,7 @@ if(LINUX)
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
endif()
|
||||
endif()
|
||||
elseif(FreeBSD)
|
||||
elseif(FreeBSD AND NOT DragonFly)
|
||||
set(CPACK_FREEBSD_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};FREEBSD")
|
||||
endif()
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
[](https://deepwiki.com/fastfetch-cli/fastfetch)
|
||||
[](README-cn.md)
|
||||
|
||||
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and illumos (SunOS).
|
||||
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 8.1+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS (illumos, Solaris).
|
||||
|
||||
> Note: Fastfetch is only actively tested on x86-64 and aarch64 platforms. It may work on other platforms but is not guaranteed to do so.
|
||||
|
||||
<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" />
|
||||
|
||||
Vendored
+6
@@ -1,3 +1,9 @@
|
||||
fastfetch (2.58.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.58.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 22 Jan 2026 15:30:58 +0800
|
||||
|
||||
fastfetch (2.57.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.57.1
|
||||
|
||||
+33
-14
@@ -318,7 +318,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"cpuFormat": {
|
||||
"description": "Output format of the module `CPU`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: X86-64 CPU microarchitecture",
|
||||
"description": "Output format of the module `CPU`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count",
|
||||
"type": "string"
|
||||
},
|
||||
"cpucacheFormat": {
|
||||
@@ -342,7 +342,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"displayFormat": {
|
||||
"description": "Output format of the module `Display`. See Wiki for formatting syntax\n 1. {width}: Screen configured width (in pixels)\n 2. {height}: Screen configured height (in pixels)\n 3. {refresh-rate}: Screen configured refresh rate (in Hz)\n 4. {scaled-width}: Screen scaled width (in pixels)\n 5. {scaled-height}: Screen scaled height (in pixels)\n 6. {name}: Screen name\n 7. {type}: Screen type (Built-in or External)\n 8. {rotation}: Screen rotation (in degrees)\n 9. {is-primary}: True if being the primary screen\n 10. {physical-width}: Screen physical width (in millimeters)\n 11. {physical-height}: Screen physical height (in millimeters)\n 12. {inch}: Physical diagonal length in inches\n 13. {ppi}: Pixels per inch (PPI)\n 14. {bit-depth}: Bits per color channel\n 15. {hdr-enabled}: True if high dynamic range (HDR) mode is enabled\n 16. {manufacture-year}: Year of manufacturing\n 17. {manufacture-week}: Nth week of manufacturing in the year\n 18. {serial}: Serial number\n 19. {platform-api}: The platform API used when detecting the display\n 20. {hdr-compatible}: True if the display is HDR compatible\n 21. {scale-factor}: HiDPI scale factor\n 22. {preferred-width}: Screen preferred width (in pixels)\n 23. {preferred-height}: Screen preferred height (in pixels)\n 24. {preferred-refresh-rate}: Screen preferred refresh rate (in Hz)",
|
||||
"description": "Output format of the module `Display`. See Wiki for formatting syntax\n 1. {width}: Screen configured width (in pixels)\n 2. {height}: Screen configured height (in pixels)\n 3. {refresh-rate}: Screen configured refresh rate (in Hz)\n 4. {scaled-width}: Screen scaled width (in pixels)\n 5. {scaled-height}: Screen scaled height (in pixels)\n 6. {name}: Screen name\n 7. {type}: Screen type (Built-in or External)\n 8. {rotation}: Screen rotation (in degrees)\n 9. {is-primary}: True if being the primary screen\n 10. {physical-width}: Screen physical width (in millimeters)\n 11. {physical-height}: Screen physical height (in millimeters)\n 12. {inch}: Physical diagonal length in inches\n 13. {ppi}: Pixels per inch (PPI)\n 14. {bit-depth}: Bits per color channel\n 15. {hdr-enabled}: True if high dynamic range (HDR) mode is enabled\n 16. {manufacture-year}: Year of manufacturing\n 17. {manufacture-week}: Nth week of manufacturing in the year\n 18. {serial}: Serial number\n 19. {platform-api}: The platform API used when detecting the display\n 20. {hdr-compatible}: True if the display is HDR compatible\n 21. {scale-factor}: HiDPI scale factor\n 22. {preferred-width}: Screen preferred width (in pixels)\n 23. {preferred-height}: Screen preferred height (in pixels)\n 24. {preferred-refresh-rate}: Screen preferred refresh rate (in Hz)\n 25. {dpi}: DPI",
|
||||
"type": "string"
|
||||
},
|
||||
"diskFormat": {
|
||||
@@ -442,7 +442,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"packagesFormat": {
|
||||
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {nix-all}: Total number of all nix packages\n 44. {flatpak-all}: Total number of all flatpak app packages\n 45. {brew-all}: Total number of all brew packages\n 46. {guix-all}: Total number of all guix packages\n 47. {hpkg-all}: Total number of all hpkg packages",
|
||||
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {kiss}: Number of kiss packages\n 44. {moss}: Number of moss packages\n 45. {nix-all}: Total number of all nix packages\n 46. {flatpak-all}: Total number of all flatpak app packages\n 47. {brew-all}: Total number of all brew packages\n 48. {guix-all}: Total number of all guix packages\n 49. {hpkg-all}: Total number of all hpkg packages",
|
||||
"type": "string"
|
||||
},
|
||||
"physicaldiskFormat": {
|
||||
@@ -450,7 +450,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"physicalmemoryFormat": {
|
||||
"description": "Output format of the module `PhysicalMemory`. See Wiki for formatting syntax\n 1. {bytes}: Size (in bytes)\n 2. {size}: Size formatted\n 3. {max-speed}: Max speed (in MT/s)\n 4. {running-speed}: Running speed (in MT/s)\n 5. {type}: Type (DDR4, DDR5, etc.)\n 6. {form-factor}: Form factor (SODIMM, DIMM, etc.)\n 7. {locator}: Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)\n 8. {vendor}: Vendor\n 9. {serial}: Serial number\n 10. {part-number}: Part number\n 11. {is-ecc-enabled}: True if ECC enabled",
|
||||
"description": "Output format of the module `PhysicalMemory`. See Wiki for formatting syntax\n 1. {bytes}: Size (in bytes)\n 2. {size}: Size formatted\n 3. {max-speed}: Max speed (in MT/s)\n 4. {running-speed}: Running speed (in MT/s)\n 5. {type}: Type (DDR4, DDR5, etc.)\n 6. {form-factor}: Form factor (SODIMM, DIMM, etc.)\n 7. {locator}: Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)\n 8. {vendor}: Vendor\n 9. {serial}: Serial number\n 10. {part-number}: Part number\n 11. {is-ecc-enabled}: True if ECC enabled\n 12. {is-installed}: True if a memory module is installed in the slot",
|
||||
"type": "string"
|
||||
},
|
||||
"playerFormat": {
|
||||
@@ -498,7 +498,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"titleFormat": {
|
||||
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name",
|
||||
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name\n 10. {user-id}: UID (*nix) / SID (Windows)\n 11. {pid}: PID of current process\n 12. {cwd}: CWD with home dir replaced by `~`",
|
||||
"type": "string"
|
||||
},
|
||||
"themeFormat": {
|
||||
@@ -546,7 +546,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"zpoolFormat": {
|
||||
"description": "Output format of the module `Zpool`. See Wiki for formatting syntax\n 1. {name}: Zpool name\n 2. {state}: Zpool state\n 3. {used}: Size used\n 4. {total}: Size total\n 5. {used-percentage}: Size percentage num\n 6. {fragmentation-percentage}: Fragmentation percentage num\n 7. {used-percentage-bar}: Size percentage bar\n 8. {fragmentation-percentage-bar}: Fragmentation percentage bar",
|
||||
"description": "Output format of the module `Zpool`. See Wiki for formatting syntax\n 1. {name}: Zpool name\n 2. {guid}: Zpool guid\n 3. {state}: Zpool state\n 4. {used}: Size used\n 5. {allocated}: Size allocated\n 6. {total}: Size total\n 7. {used-percentage}: Size used percentage num\n 8. {allocated-percentage}: Size allocated percentage num\n 9. {fragmentation-percentage}: Fragmentation percentage num\n 10. {used-percentage-bar}: Size used percentage bar\n 11. {allocated-percentage-bar}: Size allocated percentage bar\n 12. {fragmentation-percentage-bar}: Fragmentation percentage bar\n 13. {is-readonly}: Is read-only",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
@@ -1521,7 +1521,7 @@
|
||||
"description": "Print battery capacity, status, etc"
|
||||
},
|
||||
"useSetupApi": {
|
||||
"description": "Set if `SetupAPI` should be used on Windows to detect battery info, which supports multi batteries, but slower. Windows only",
|
||||
"description": "Set if `CM API` should be used on Windows to detect battery info, which supports multi batteries, but slower. Windows only",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
@@ -2044,7 +2044,7 @@
|
||||
"default": 0
|
||||
},
|
||||
"block": {
|
||||
"description": "Set behavior of block printing",
|
||||
"description": "Set behavior of block printing. Only works when symbol is set to `block` or `background`",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -2067,6 +2067,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"brightness": {
|
||||
"description": "Set the brightness of colors. Works together with the block color range to determine which colors are displayed",
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "default",
|
||||
"description": "Use the default setting (block/background: 0-15, others: 8-1)"
|
||||
},
|
||||
{
|
||||
"const": "light",
|
||||
"description": "Use ANSI bright foreground colors (codes 90-97, not color indices 9-15)"
|
||||
},
|
||||
{
|
||||
"const": "normal",
|
||||
"description": "Use normal ANSI colors (30-37; standard foreground colors, corresponding to color indices 0-7)"
|
||||
}
|
||||
],
|
||||
"default": "default"
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
},
|
||||
@@ -2518,11 +2537,6 @@
|
||||
"const": "de",
|
||||
"description": "Print desktop environment name"
|
||||
},
|
||||
"slowVersionDetection": {
|
||||
"type": "boolean",
|
||||
"description": "Set if DE version should be detected with slow operations.\nShould be unnecessary for most cases.\nThis is only used as a fallback method. Please file a bug report if you encounter any issues.",
|
||||
"default": false
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
},
|
||||
@@ -3655,6 +3669,11 @@
|
||||
"const": "physicalmemory",
|
||||
"description": "Print system physical memory devices"
|
||||
},
|
||||
"showEmptySlots": {
|
||||
"description": "Set if uninstalled memory slots should be printed",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
},
|
||||
@@ -4487,7 +4506,7 @@
|
||||
"detectPlugin": {
|
||||
"description": "Set if window manager plugin should be detected on supported platforms",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
"default": true
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
|
||||
+51
-50
@@ -9,25 +9,26 @@
|
||||
// Constants are reusable strings referenced by {$1}, {$2}, etc.
|
||||
// These contain ANSI escape codes for cursor positioning
|
||||
"constants": [
|
||||
"──────────────────────────────────────────────", // {$1} - horizontal line for borders
|
||||
"──────────────────────────────────────────────", // {$1} - horizontal line for inner borders
|
||||
"\u001b[47D", // {$2} - move cursor left 47 columns
|
||||
"\u001b[47C", // {$3} - move cursor right 47 columns
|
||||
"\u001b[46C" // {$4} - move cursor right 46 columns
|
||||
"\u001b[46C", // {$4} - move cursor right 46 columns
|
||||
"══════════════════════════════════════════════" // {$5} - horizontal line for outer borders
|
||||
],
|
||||
"brightColor": false
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "version",
|
||||
"key": "┌───────────────┬─{$1}┐\u001b[41D",
|
||||
"key": "╔═══════════════╦═{$5}╗\u001b[41D",
|
||||
"format": "\u001b[1m{#keys} {1} - {2} "
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
// Key format breakdown for OS module:
|
||||
// "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
|
||||
// "║ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}║{$2}"
|
||||
//
|
||||
// │ - Left border of key block
|
||||
// ║ - Left border of key block
|
||||
// {icon} - OS icon (defined internally by fastfetch)
|
||||
// \u001b[s - ANSI escape: save cursor position (ESC[s)
|
||||
// {sysname} - Format variable: system name (e.g., "Linux", "Darwin")
|
||||
@@ -36,28 +37,28 @@
|
||||
// \u001b[10C - ANSI escape: move cursor right 10 columns (ESC[10C)
|
||||
// │ - Right border of key block (always 10 columns from left border)
|
||||
// {$3} - Reference to constants[2]: move cursor right 47 columns
|
||||
// │ - Right border of value block
|
||||
// ║ - Right border of value block
|
||||
// {$2} - Reference to constants[1]: move cursor left 47 columns
|
||||
//
|
||||
// This creates a fixed-width layout where the key block is exactly 10 columns wide,
|
||||
// regardless of the actual content length. The cursor manipulation ensures proper
|
||||
// alignment for the table-like structure.
|
||||
"key": "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
|
||||
"key": "║ {icon} \u001b[s{sysname}\u001b[u\u001b[10C║{$3}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "datetime",
|
||||
"key": "│ {icon} Fetched │{$3}│{$2}",
|
||||
"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}"
|
||||
"key": "║ {icon} Locale ║{$3}║{$2}"
|
||||
},
|
||||
|
||||
// Hardware section with cyan color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#cyan}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"key": "║{#cyan}┌──────────────┬{$1}┐{#keys}║\u001b[37D",
|
||||
"format": "{#bright_cyan} Hardware "
|
||||
},
|
||||
{
|
||||
@@ -66,113 +67,113 @@
|
||||
// │{#cyan}│ - Left border with cyan color
|
||||
// {icon} - Chassis icon
|
||||
// Chassis - Fixed label text
|
||||
// │{$4}│{#keys}│{$2} - Positioning and borders for value area
|
||||
"key": "│{#cyan}│ {icon} Chassis │{$4}│{#keys}│{$2}"
|
||||
// │{$4}│{#keys}║{$2} - Positioning and borders for value area
|
||||
"key": "║{#cyan}│ {icon} Chassis │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│{#cyan}│ {icon} RAM │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#cyan}│ {icon} RAM │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "swap",
|
||||
"key": "│{#cyan}│ {icon} SWAP │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#cyan}│ {icon} SWAP │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "cpu",
|
||||
"key": "│{#cyan}│ {icon} CPU │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#cyan}│ {icon} CPU │{$4}│{#keys}║{$2}",
|
||||
"showPeCoreCount": true
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│{#cyan}│ {icon} GPU │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#cyan}│ {icon} GPU │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": "│{#cyan}│ {icon} Disk │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#cyan}│ {icon} Disk │{$4}│{#keys}║{$2}",
|
||||
"format": "{size-used} \/ {size-total} ({size-percentage}) - {filesystem}",
|
||||
},
|
||||
{
|
||||
"type": "battery",
|
||||
"key": "│{#cyan}│ {icon} Battery │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#cyan}│ {icon} Battery │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#cyan}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#cyan}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Desktop section with green color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#green}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"key": "║{#green}┌──────────────┬{$1}┐{#keys}║\u001b[37D",
|
||||
"format": "{#bright_green} Desktop "
|
||||
},
|
||||
{
|
||||
"type": "de",
|
||||
"key": "│{#green}│ {icon} Desktop │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#green}│ {icon} Desktop │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "│{#green}│ {icon} Session │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#green}│ {icon} Session │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "display",
|
||||
"key": "│{#green}│ {icon} Display │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#green}│ {icon} Display │{$4}│{#keys}║{$2}",
|
||||
"compactType": "original-with-refresh-rate"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│{#green}│ {icon} G-Driver │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#green}│ {icon} G-Driver │{$4}│{#keys}║{$2}",
|
||||
"format": "{driver}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#green}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#green}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Terminal section with yellow color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#yellow}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"key": "║{#yellow}┌──────────────┬{$1}┐{#keys}║\u001b[37D",
|
||||
"format": "{#bright_yellow} Terminal "
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"key": "│{#yellow}│ {icon} Shell │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Shell │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "│{#yellow}│ {icon} Terminal │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Terminal │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
"key": "│{#yellow}│ {icon} Term Font │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Term Font │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminaltheme",
|
||||
"key": "│{#yellow}│ {icon} Colors │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Colors │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "packages",
|
||||
"key": "│{#yellow}│ {icon} Packages │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Packages │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#yellow}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#yellow}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Development section with red color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#red}┌──────────────┬{$1}┐{#keys}│\u001b[39D",
|
||||
"key": "║{#red}┌──────────────┬{$1}┐{#keys}║\u001b[39D",
|
||||
"format": "{#bright_red} Development "
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "", // Custom icon override
|
||||
"key": "│{#red}│ {icon} Rust │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Rust │{$4}│{#keys}║{$2}",
|
||||
"text": "rustc --version",
|
||||
"format": "rustc {~6,13}" // Print 6th to 13th characters (version number)
|
||||
},
|
||||
@@ -182,7 +183,7 @@
|
||||
"!system": "Windows" // Posix version
|
||||
},
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Clang │{$4}│{#keys}║{$2}",
|
||||
"text": "clang --version | sed -n 's/.*version \\([0-9][0-9.]*\\).*/\\1/p'",
|
||||
"format": "clang {}"
|
||||
},
|
||||
@@ -192,67 +193,67 @@
|
||||
"system": "Windows" // Windows version
|
||||
},
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Clang │{$4}│{#keys}║{$2}",
|
||||
"text": "clang --version | findstr version", // Finds the line with "version"
|
||||
"format": "clang {~-6}" // Prints the last 6 characters (version number)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} NodeJS │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} NodeJS │{$4}│{#keys}║{$2}",
|
||||
"text": "node --version",
|
||||
"format": "node {~1}" // {~1} removes first character (v)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Go │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Go │{$4}│{#keys}║{$2}",
|
||||
"text": "go version | cut -d' ' -f3",
|
||||
"format": "go {~2}" // {~2} removes first 2 characters (go)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Zig │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Zig │{$4}│{#keys}║{$2}",
|
||||
"text": "zig version",
|
||||
"format": "zig {}"
|
||||
},
|
||||
{
|
||||
"type": "editor",
|
||||
"key": "│{#red}│ {icon} Editor │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#red}│ {icon} Editor │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Git │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Git │{$4}│{#keys}║{$2}",
|
||||
"text": "git version",
|
||||
"format": "git {~12}"
|
||||
},
|
||||
{
|
||||
"type": "font",
|
||||
"key": "│{#red}│ {icon} Interface │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#red}│ {icon} Interface │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#red}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#red}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Uptime section with magenta color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#magenta}┌──────────────┬{$1}┐{#keys}│\u001b[36D",
|
||||
"key": "║{#magenta}┌──────────────┬{$1}┐{#keys}║\u001b[36D",
|
||||
"format": "{#bright_magenta} Uptime "
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"key": "│{#magenta}│ {icon} Uptime │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#magenta}│ {icon} Uptime │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "users",
|
||||
"myselfOnly": true, // Only show current user
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#magenta}│ {icon} Login │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"condition": { // Conditional module: only show on non-macOS
|
||||
@@ -260,7 +261,7 @@
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#magenta}│ {icon} OS Age │{$4}│{#keys}║{$2}",
|
||||
"folders": "/", // Check root filesystem
|
||||
"format": "{create-time:10} [{days} days]" // Show creation time and age in days
|
||||
},
|
||||
@@ -270,18 +271,18 @@
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#magenta}│ {icon} OS Age │{$4}│{#keys}║{$2}",
|
||||
"folders": "/System/Volumes/VM", // Work around for APFS on macOS
|
||||
"format": "{create-time:10} [{days} days]"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#magenta}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#magenta}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "└─────────────────{$1}┘", // Bottom border of the entire layout
|
||||
"key": "╚═════════════════{$5}╝", // Bottom border of the entire layout
|
||||
"format": ""
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Inspired by microfetch
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"type": "small"
|
||||
},
|
||||
"general": {
|
||||
"detectVersion": false
|
||||
},
|
||||
"display": {
|
||||
"separator": " ",
|
||||
"brightColor": false,
|
||||
"key": {
|
||||
"type": "both-2"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "title",
|
||||
"format": "{user-name-colored}{#light_red}@{host-name-colored} {#}{cwd}"
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "System "
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"key": "Kernel "
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"key": "Shell "
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"key": "Uptime "
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "Desktop "
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "Memory "
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": "Storage (/) ",
|
||||
"folders": "/"
|
||||
},
|
||||
{
|
||||
"type": "colors",
|
||||
"key": "Colors ",
|
||||
"symbol": "circle"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,6 +6,9 @@ def main(amdgpu_ids_path: str):
|
||||
with open(amdgpu_ids_path, 'r') as f:
|
||||
full_text = f.read()
|
||||
|
||||
if full_text == '':
|
||||
sys.exit(f'Error: {amdgpu_ids_path} file is empty')
|
||||
|
||||
products = []
|
||||
for line in full_text.split('\n'):
|
||||
if not line or line[0] == '#' or not ',\t' in line:
|
||||
|
||||
@@ -18,6 +18,9 @@ def main(keep_vendor_list: set, pci_ids_path: str):
|
||||
with open(pci_ids_path, 'r') as f:
|
||||
full_text = f.read()
|
||||
|
||||
if full_text == '':
|
||||
sys.exit(f'Error: {pci_ids_path} file is empty')
|
||||
|
||||
dev_list_text = full_text[:full_text.rfind('\n\n\n')] # remove known classes
|
||||
for line in dev_list_text.split('\n'):
|
||||
if not line or line[0] == '#':
|
||||
|
||||
@@ -19,7 +19,14 @@ typedef struct FFPlatform
|
||||
FFlist configDirs; // List of FFstrbuf, trailing slash included
|
||||
FFlist dataDirs; // List of FFstrbuf, trailing slash included
|
||||
FFstrbuf exePath; // The real path of current exe (empty if unavailable)
|
||||
FFstrbuf cwd; // Trailing slash included
|
||||
|
||||
uint32_t pid;
|
||||
#ifndef _WIN32
|
||||
uint32_t uid;
|
||||
#else
|
||||
FFstrbuf sid;
|
||||
#endif
|
||||
FFstrbuf userName;
|
||||
FFstrbuf fullUserName;
|
||||
FFstrbuf hostName;
|
||||
|
||||
@@ -106,6 +106,15 @@ static inline void ffListClear(FFlist* list)
|
||||
list->length = 0;
|
||||
}
|
||||
|
||||
static inline void ffListReserve(FFlist* list, uint32_t newCapacity)
|
||||
{
|
||||
if (__builtin_expect(newCapacity <= list->capacity, false))
|
||||
return;
|
||||
|
||||
list->data = (uint8_t*) realloc(list->data, (size_t) newCapacity * list->elementSize);
|
||||
list->capacity = newCapacity;
|
||||
}
|
||||
|
||||
#define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
|
||||
assert(sizeof(itemType) == (listVar).elementSize); \
|
||||
for(itemType* itemVarName = (itemType*)(listVar).data; \
|
||||
|
||||
@@ -230,6 +230,7 @@ static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr)
|
||||
ffStrbufInitMoveNS(strbuf, (uint32_t) strlen(heapStr), heapStr);
|
||||
}
|
||||
|
||||
// Despite the name, this function resets strbuf to the initial/unallocated state
|
||||
static inline void ffStrbufDestroy(FFstrbuf* strbuf)
|
||||
{
|
||||
if(strbuf->allocated > 0)
|
||||
@@ -627,4 +628,7 @@ static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const
|
||||
return ffStrbufSeparatedContainIgnCaseNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
// Returns true if the strbuf is modified
|
||||
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf);
|
||||
|
||||
#define FF_STRBUF_AUTO_DESTROY FFstrbuf __attribute__((__cleanup__(ffStrbufDestroy)))
|
||||
|
||||
@@ -166,7 +166,7 @@ static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl
|
||||
case 1: *value = *(uint8_t *)(val.bytes); break;
|
||||
case 2: *value = ntohs(*(uint16_t *)(val.bytes)); break;
|
||||
case 4: *value = ntohl(*(uint32_t *)(val.bytes)); break;
|
||||
case 8: *value = ntohll(*(uint64_t *)(val.bytes)); break;
|
||||
case 8: *value = (double) ntohll(*(uint64_t *)(val.bytes)); break;
|
||||
default:
|
||||
return "Unsupported SMC unsigned integer data size";
|
||||
}
|
||||
@@ -213,7 +213,7 @@ static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl
|
||||
case 1: *value = *(int8_t *)(val.bytes); break;
|
||||
case 2: *value = ntohs(*(int16_t *)(val.bytes)); break;
|
||||
case 4: *value = ntohl(*(int32_t *)(val.bytes)); break;
|
||||
case 8: *value = ntohll(*(int64_t *)(val.bytes)); break;
|
||||
case 8: *value = (double)ntohll(*(int64_t *)(val.bytes)); break;
|
||||
default: return "Unsupported SMC signed integer data size";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
// For ffRegReadValue(s)
|
||||
// If length is 0, data will be allocated with malloc() and must be freed by the caller
|
||||
// Otherwise, data must point to a buffer of at least length bytes, and the actual length of the data will be written to length.
|
||||
typedef struct FFArgBuffer
|
||||
{
|
||||
void* data;
|
||||
uint32_t length;
|
||||
} FFArgBuffer;
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFArgType
|
||||
{
|
||||
FF_ARG_TYPE_NULL = 0,
|
||||
FF_ARG_TYPE_UINT,
|
||||
FF_ARG_TYPE_UINT64,
|
||||
FF_ARG_TYPE_UINT16,
|
||||
FF_ARG_TYPE_UINT8,
|
||||
FF_ARG_TYPE_INT,
|
||||
FF_ARG_TYPE_STRING,
|
||||
FF_ARG_TYPE_STRBUF,
|
||||
FF_ARG_TYPE_FLOAT,
|
||||
FF_ARG_TYPE_DOUBLE,
|
||||
FF_ARG_TYPE_LIST,
|
||||
FF_ARG_TYPE_BOOL,
|
||||
FF_ARG_TYPE_BUFFER,
|
||||
} FFArgType;
|
||||
|
||||
#define FF_ARG(variable, var_name) { _Generic((variable), \
|
||||
uint32_t: FF_ARG_TYPE_UINT, \
|
||||
uint64_t: FF_ARG_TYPE_UINT64, \
|
||||
uint16_t: FF_ARG_TYPE_UINT16, \
|
||||
uint8_t: FF_ARG_TYPE_UINT8, \
|
||||
int32_t: FF_ARG_TYPE_INT, \
|
||||
char*: FF_ARG_TYPE_STRING, \
|
||||
const char*: FF_ARG_TYPE_STRING, \
|
||||
FFstrbuf: FF_ARG_TYPE_STRBUF, \
|
||||
float: FF_ARG_TYPE_FLOAT, \
|
||||
double: FF_ARG_TYPE_DOUBLE, \
|
||||
FFlist: FF_ARG_TYPE_LIST, \
|
||||
bool: FF_ARG_TYPE_BOOL, \
|
||||
FFArgBuffer: FF_ARG_TYPE_BUFFER \
|
||||
), _Generic((variable), char*: (variable), const char*: (variable), default: &(variable) ), (var_name) }
|
||||
@@ -3,7 +3,9 @@
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __has_builtin
|
||||
#if __has_builtin(__is_array)
|
||||
#if !__cplusplus && FF_SUPPORTS_COUNT_OF
|
||||
#define ARRAY_SIZE(x) _Countof(x)
|
||||
#elif __has_builtin(__is_array)
|
||||
#define ARRAY_SIZE(x) ({ static_assert(__is_array(__typeof__(x)), "Must be an array"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
#elif __has_builtin(__builtin_types_compatible_p)
|
||||
#define ARRAY_SIZE(x) ({ static_assert(!__builtin_types_compatible_p(__typeof__(x), __typeof__(&*(x))), "Must not be a pointer"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
|
||||
@@ -19,6 +19,7 @@ typedef struct FFDBusLibrary
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_next)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_unref)
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_send_with_reply_and_block)
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_unref)
|
||||
} FFDBusLibrary;
|
||||
|
||||
typedef struct FFDBusData
|
||||
@@ -36,10 +37,13 @@ DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char
|
||||
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
|
||||
void ffDBusDestroyData(FFDBusData* data);
|
||||
|
||||
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface)
|
||||
{
|
||||
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, NULL);
|
||||
}
|
||||
|
||||
#define FF_DBUS_AUTO_DESTROY_DATA __attribute__((__cleanup__(ffDBusDestroyData)))
|
||||
|
||||
#endif // FF_HAVE_DBUS
|
||||
|
||||
+3
-1
@@ -29,5 +29,7 @@ static inline const char* ffFindFileName(const char* file)
|
||||
#define FF_DEBUG(format, ...) FF_DEBUG_PRINT(__FILE__, __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
#if _WIN32
|
||||
const char* ffDebugWin32Error(unsigned long errorCode);
|
||||
const char* ffDebugWin32Error(DWORD errorCode);
|
||||
const char* ffDebugNtStatus(NTSTATUS status);
|
||||
const char* ffDebugHResult(HRESULT hr);
|
||||
#endif
|
||||
|
||||
@@ -10,3 +10,4 @@ void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint3
|
||||
void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm
|
||||
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week);
|
||||
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length);
|
||||
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length);
|
||||
|
||||
+2
-33
@@ -1,41 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFformatArgType
|
||||
{
|
||||
FF_FORMAT_ARG_TYPE_NULL = 0,
|
||||
FF_FORMAT_ARG_TYPE_UINT,
|
||||
FF_FORMAT_ARG_TYPE_UINT64,
|
||||
FF_FORMAT_ARG_TYPE_UINT16,
|
||||
FF_FORMAT_ARG_TYPE_UINT8,
|
||||
FF_FORMAT_ARG_TYPE_INT,
|
||||
FF_FORMAT_ARG_TYPE_STRING,
|
||||
FF_FORMAT_ARG_TYPE_STRBUF,
|
||||
FF_FORMAT_ARG_TYPE_FLOAT,
|
||||
FF_FORMAT_ARG_TYPE_DOUBLE,
|
||||
FF_FORMAT_ARG_TYPE_LIST,
|
||||
FF_FORMAT_ARG_TYPE_BOOL
|
||||
} FFformatArgType;
|
||||
|
||||
#define FF_FORMAT_ARG(variable, var_name) { _Generic((variable), \
|
||||
uint32_t: FF_FORMAT_ARG_TYPE_UINT, \
|
||||
uint64_t: FF_FORMAT_ARG_TYPE_UINT64, \
|
||||
uint16_t: FF_FORMAT_ARG_TYPE_UINT16, \
|
||||
uint8_t: FF_FORMAT_ARG_TYPE_UINT8, \
|
||||
int32_t: FF_FORMAT_ARG_TYPE_INT, \
|
||||
char*: FF_FORMAT_ARG_TYPE_STRING, \
|
||||
const char*: FF_FORMAT_ARG_TYPE_STRING, \
|
||||
FFstrbuf: FF_FORMAT_ARG_TYPE_STRBUF, \
|
||||
float: FF_FORMAT_ARG_TYPE_FLOAT, \
|
||||
double: FF_FORMAT_ARG_TYPE_DOUBLE, \
|
||||
FFlist: FF_FORMAT_ARG_TYPE_LIST, \
|
||||
bool: FF_FORMAT_ARG_TYPE_BOOL \
|
||||
), _Generic((variable), char*: (variable), const char*: (variable), default: &(variable) ), (var_name) }
|
||||
#include "common/argType.h"
|
||||
|
||||
typedef struct FFformatarg
|
||||
{
|
||||
FFformatArgType type;
|
||||
FFArgType type;
|
||||
const void* value;
|
||||
const char* name; // argument name, must start with an alphabet
|
||||
} FFformatarg;
|
||||
|
||||
@@ -10,12 +10,17 @@ void ffPlatformInit(FFPlatform* platform)
|
||||
ffListInit(&platform->configDirs, sizeof(FFstrbuf));
|
||||
ffListInit(&platform->dataDirs, sizeof(FFstrbuf));
|
||||
ffStrbufInit(&platform->exePath);
|
||||
ffStrbufInit(&platform->cwd);
|
||||
|
||||
ffStrbufInit(&platform->userName);
|
||||
ffStrbufInit(&platform->fullUserName);
|
||||
ffStrbufInit(&platform->hostName);
|
||||
ffStrbufInit(&platform->userShell);
|
||||
|
||||
#ifdef _WIN32
|
||||
ffStrbufInit(&platform->sid);
|
||||
#endif
|
||||
|
||||
FFPlatformSysinfo* info = &platform->sysinfo;
|
||||
|
||||
ffStrbufInit(&info->name);
|
||||
@@ -45,12 +50,17 @@ void ffPlatformDestroy(FFPlatform* platform)
|
||||
ffStrbufDestroy(dir);
|
||||
ffListDestroy(&platform->dataDirs);
|
||||
ffStrbufDestroy(&platform->exePath);
|
||||
ffStrbufDestroy(&platform->cwd);
|
||||
|
||||
ffStrbufDestroy(&platform->userName);
|
||||
ffStrbufDestroy(&platform->hostName);
|
||||
ffStrbufDestroy(&platform->userShell);
|
||||
ffStrbufDestroy(&platform->fullUserName);
|
||||
|
||||
#ifdef _WIN32
|
||||
ffStrbufDestroy(&platform->sid);
|
||||
#endif
|
||||
|
||||
FFPlatformSysinfo* info = &platform->sysinfo;
|
||||
ffStrbufDestroy(&info->architecture);
|
||||
ffStrbufDestroy(&info->name);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "FFPlatform_private.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/arrayUtils.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/io.h"
|
||||
#include "fastfetch_config.h"
|
||||
@@ -11,10 +12,14 @@
|
||||
#include <paths.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <libproc.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#include <kvm.h>
|
||||
#include "common/path.h"
|
||||
#elif defined(__HAIKU__)
|
||||
#include <image.h>
|
||||
#include <OS.h>
|
||||
@@ -28,15 +33,19 @@ static void getExePath(FFPlatform* platform)
|
||||
if (exePathLen >= 0)
|
||||
exePath[exePathLen] = '\0';
|
||||
#elif defined(__APPLE__)
|
||||
int exePathLen = proc_pidpath((int) getpid(), exePath, sizeof(exePath));
|
||||
uint32_t exePathLen = sizeof(exePath);
|
||||
if (_NSGetExecutablePath(exePath, &exePathLen) == 0)
|
||||
exePathLen = (uint32_t) strlen(exePath);
|
||||
else
|
||||
exePathLen = 0;
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
size_t exePathLen = sizeof(exePath);
|
||||
if(sysctl(
|
||||
(int[]){CTL_KERN,
|
||||
#ifdef __FreeBSD__
|
||||
KERN_PROC, KERN_PROC_PATHNAME, (int) getpid()
|
||||
KERN_PROC, KERN_PROC_PATHNAME, (pid_t) platform->pid
|
||||
#else
|
||||
KERN_PROC_ARGS, (int) getpid(), KERN_PROC_PATHNAME
|
||||
KERN_PROC_ARGS, platform->pid, KERN_PROC_PATHNAME
|
||||
#endif
|
||||
}, 4,
|
||||
exePath, &exePathLen,
|
||||
@@ -46,7 +55,81 @@ static void getExePath(FFPlatform* platform)
|
||||
else
|
||||
exePathLen--; // remove terminating NUL
|
||||
#elif defined(__OpenBSD__)
|
||||
// OpenBSD doesn't have a reliable way to get the executable path.
|
||||
// Current implementation uses argv[0], which can be easily spoofed.
|
||||
// See #2195
|
||||
size_t exePathLen = 0;
|
||||
kvm_t* kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
if (kd)
|
||||
{
|
||||
int kpCount;
|
||||
struct kinfo_proc* kp = kvm_getprocs(kd, KERN_PROC_PID, (pid_t) platform->pid, sizeof(*kp), &kpCount);
|
||||
if (kp && kpCount == 1)
|
||||
{
|
||||
char** argv = kvm_getargv(kd, kp, 0);
|
||||
if (argv && argv[0])
|
||||
{
|
||||
char* arg0 = argv[0];
|
||||
if (arg0[0])
|
||||
{
|
||||
if (strchr(arg0, '/') != NULL) // likely a path (absolute or relative)
|
||||
{
|
||||
exePathLen = strlen(arg0);
|
||||
if (exePathLen < ARRAY_SIZE(exePath))
|
||||
{
|
||||
memcpy(exePath, arg0, exePathLen);
|
||||
exePath[exePathLen] = '\0';
|
||||
}
|
||||
else
|
||||
exePathLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY tmpPath = ffStrbufCreate();
|
||||
if (ffFindExecutableInPath(arg0, &tmpPath) == NULL && tmpPath.length < ARRAY_SIZE(exePath))
|
||||
{
|
||||
memcpy(exePath, tmpPath.chars, tmpPath.length + 1);
|
||||
exePathLen = tmpPath.length;
|
||||
}
|
||||
}
|
||||
|
||||
if (exePathLen > 0)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(exePath, &st) == 0 && S_ISREG(st.st_mode))
|
||||
{
|
||||
int cntp;
|
||||
struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, platform->pid, sizeof(*kf), &cntp);
|
||||
if (kf)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cntp; i++)
|
||||
{
|
||||
if (kf[i].fd_fd == KERN_FILE_TEXT)
|
||||
{
|
||||
// KERN_FILE_TEXT is the executable file, not a shared library, and should be unique in the list.
|
||||
if (st.st_dev != (dev_t)kf[i].va_fsid || st.st_ino != (ino_t)kf[i].va_fileid)
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0)
|
||||
exePathLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we can't get the list of open files, we can't verify that the file is actually the executable
|
||||
// Assume it is
|
||||
}
|
||||
}
|
||||
else
|
||||
exePathLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kvm_close(kd);
|
||||
}
|
||||
#elif defined(__sun)
|
||||
ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1);
|
||||
if (exePathLen >= 0)
|
||||
@@ -177,17 +260,16 @@ static void getDataDirs(FFPlatform* platform)
|
||||
|
||||
static void getUserName(FFPlatform* platform, const struct passwd* pwd)
|
||||
{
|
||||
const char* user = getenv("USER");
|
||||
if(!ffStrSet(user) && pwd)
|
||||
user = pwd->pw_name;
|
||||
|
||||
ffStrbufAppendS(&platform->userName, user);
|
||||
|
||||
if (pwd)
|
||||
{
|
||||
ffStrbufAppendS(&platform->fullUserName, pwd->pw_gecos);
|
||||
ffStrbufSetS(&platform->userName, pwd->pw_name);
|
||||
ffStrbufSetS(&platform->fullUserName, pwd->pw_gecos);
|
||||
ffStrbufTrimSpace(&platform->fullUserName);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufSetS(&platform->userName, getenv("USER"));
|
||||
}
|
||||
}
|
||||
|
||||
static void getHostName(FFPlatform* platform, const struct utsname* uts)
|
||||
@@ -225,15 +307,28 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void getCwd(FFPlatform* platform)
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
if (getcwd(cwd, sizeof(cwd)) != NULL)
|
||||
{
|
||||
ffStrbufSetS(&platform->cwd, cwd);
|
||||
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
|
||||
}
|
||||
}
|
||||
|
||||
void ffPlatformInitImpl(FFPlatform* platform)
|
||||
{
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
platform->pid = (uint32_t) getpid();
|
||||
platform->uid = getuid();
|
||||
struct passwd* pwd = getpwuid(platform->uid);
|
||||
|
||||
struct utsname uts;
|
||||
if(uname(&uts) < 0)
|
||||
memset(&uts, 0, sizeof(uts));
|
||||
|
||||
getExePath(platform);
|
||||
getCwd(platform);
|
||||
getHomeDir(platform, pwd);
|
||||
getCacheDir(platform);
|
||||
getConfigDirs(platform);
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
#include "common/windows/registry.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#include <stdalign.h>
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <sddl.h>
|
||||
|
||||
#define SECURITY_WIN32 1 // For secext.h
|
||||
#include <secext.h>
|
||||
@@ -15,20 +17,32 @@
|
||||
static void getExePath(FFPlatform* platform)
|
||||
{
|
||||
wchar_t exePathW[MAX_PATH];
|
||||
DWORD exePathWLen = GetModuleFileNameW(NULL, exePathW, MAX_PATH);
|
||||
if (exePathWLen == 0 || exePathWLen >= MAX_PATH) return;
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(exePathW, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(
|
||||
ffGetPeb()->ProcessParameters->ImagePathName.Buffer,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
if (hPath != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_OPENED);
|
||||
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_NORMALIZED);
|
||||
if (len > 0 && len < MAX_PATH)
|
||||
exePathWLen = len;
|
||||
{
|
||||
ffStrbufSetNWS(&platform->exePath, len, exePathW);
|
||||
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\"))
|
||||
ffStrbufSubstrAfter(&platform->exePath, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (platform->exePath.length == 0)
|
||||
{
|
||||
PCUNICODE_STRING imagePathName = &ffGetPeb()->ProcessParameters->ImagePathName;
|
||||
ffStrbufSetNWS(&platform->exePath, imagePathName->Length / sizeof(wchar_t), imagePathName->Buffer);
|
||||
}
|
||||
|
||||
ffStrbufSetNWS(&platform->exePath, exePathWLen, exePathW);
|
||||
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\"))
|
||||
ffStrbufSubstrAfter(&platform->exePath, 3);
|
||||
ffStrbufReplaceAllC(&platform->exePath, '\\', '/');
|
||||
}
|
||||
|
||||
@@ -70,15 +84,15 @@ static void getCacheDir(FFPlatform* platform)
|
||||
static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId)
|
||||
{
|
||||
PWSTR pPath = NULL;
|
||||
if(SUCCEEDED(SHGetKnownFolderPath(folderId, 0, NULL, &pPath)))
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, NULL, &pPath)))
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateWS(pPath);
|
||||
CoTaskMemFree(pPath);
|
||||
ffStrbufReplaceAllC(&buffer, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&buffer, '/');
|
||||
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
|
||||
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
|
||||
}
|
||||
CoTaskMemFree(pPath);
|
||||
}
|
||||
|
||||
static void platformPathAddEnvSuffix(FFlist* dirs, const char* env, const char* suffix)
|
||||
@@ -136,21 +150,25 @@ static void getDataDirs(FFPlatform* platform)
|
||||
|
||||
static void getUserName(FFPlatform* platform)
|
||||
{
|
||||
const char* userName = getenv("USERNAME");
|
||||
if (ffStrSet(userName))
|
||||
ffStrbufSetS(&platform->userName, userName);
|
||||
else
|
||||
{
|
||||
wchar_t buffer[256];
|
||||
DWORD len = ARRAY_SIZE(buffer);
|
||||
if(GetUserNameW(buffer, &len))
|
||||
ffStrbufSetWS(&platform->userName, buffer);
|
||||
}
|
||||
|
||||
wchar_t buffer[256];
|
||||
DWORD len = ARRAY_SIZE(buffer);
|
||||
if (GetUserNameExW(NameDisplay, buffer, &len))
|
||||
DWORD size = ARRAY_SIZE(buffer);
|
||||
if (GetUserNameExW(NameDisplay, buffer, &size))
|
||||
ffStrbufSetWS(&platform->fullUserName, buffer);
|
||||
|
||||
size = ARRAY_SIZE(buffer);
|
||||
if (GetUserNameW(buffer, &size)) // GetUserNameExW(10002)?
|
||||
ffStrbufSetWS(&platform->userName, buffer);
|
||||
else
|
||||
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
|
||||
|
||||
alignas(TOKEN_USER) char buf[SECURITY_MAX_SID_SIZE + sizeof(TOKEN_USER)];
|
||||
if (NT_SUCCESS(NtQueryInformationToken(NtCurrentProcessToken(), TokenUser, buf, sizeof(buf), &size)))
|
||||
{
|
||||
TOKEN_USER* tokenUser = (TOKEN_USER*) buf;
|
||||
UNICODE_STRING sidString = { .Buffer = buffer, .Length = 0, .MaximumLength = sizeof(buffer) };
|
||||
if (NT_SUCCESS(RtlConvertSidToUnicodeString(&sidString, tokenUser->User.Sid, FALSE)))
|
||||
ffStrbufSetNWS(&platform->sid, sidString.Length / sizeof(wchar_t), sidString.Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void getHostName(FFPlatform* platform)
|
||||
@@ -181,7 +199,7 @@ static void getUserShell(FFPlatform* platform)
|
||||
static const char* detectWine(void)
|
||||
{
|
||||
const char * __cdecl wine_get_version(void);
|
||||
HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
|
||||
void* hntdll = ffLibraryGetModule(L"ntdll.dll");
|
||||
if (!hntdll) return NULL;
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(hntdll, wine_get_version);
|
||||
if (!ffwine_get_version) return NULL;
|
||||
@@ -190,53 +208,48 @@ static const char* detectWine(void)
|
||||
|
||||
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
|
||||
{
|
||||
RTL_OSVERSIONINFOW osVersion = { .dwOSVersionInfoSize = sizeof(osVersion) };
|
||||
if (!NT_SUCCESS(RtlGetVersion(&osVersion)))
|
||||
return;
|
||||
|
||||
FF_HKEY_AUTO_DESTROY hKey = NULL;
|
||||
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL))
|
||||
return;
|
||||
|
||||
uint32_t ubr = 0;
|
||||
ffRegReadUint(hKey, L"UBR", &ubr, NULL);
|
||||
ffRegReadValues(hKey, 2, (FFRegValueArg[]) {
|
||||
FF_ARG(ubr, L"UBR"),
|
||||
FF_ARG(info->version, L"BuildLabEx"),
|
||||
}, NULL);
|
||||
|
||||
ffStrbufAppendF(&info->release,
|
||||
PPEB_FULL peb = ffGetPeb();
|
||||
|
||||
ffStrbufSetF(&info->release,
|
||||
"%u.%u.%u.%u",
|
||||
(unsigned) osVersion.dwMajorVersion,
|
||||
(unsigned) osVersion.dwMinorVersion,
|
||||
(unsigned) osVersion.dwBuildNumber,
|
||||
(unsigned) peb->OSMajorVersion,
|
||||
(unsigned) peb->OSMinorVersion,
|
||||
(unsigned) peb->OSBuildNumber,
|
||||
(unsigned) ubr);
|
||||
|
||||
ffRegReadStrbuf(hKey, L"BuildLabEx", &info->version, NULL);
|
||||
|
||||
const char* wineVersion = detectWine();
|
||||
if (wineVersion)
|
||||
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
|
||||
else
|
||||
{
|
||||
switch (osVersion.dwPlatformId)
|
||||
{
|
||||
case VER_PLATFORM_WIN32s:
|
||||
ffStrbufSetStatic(&info->name, "WIN32s");
|
||||
break;
|
||||
case VER_PLATFORM_WIN32_WINDOWS:
|
||||
ffStrbufSetStatic(&info->name, "WIN32_WINDOWS");
|
||||
break;
|
||||
case VER_PLATFORM_WIN32_NT:
|
||||
ffStrbufSetStatic(&info->name, "WIN32_NT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ffStrbufSetStatic(&info->name, "WIN32_NT");
|
||||
}
|
||||
|
||||
static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
|
||||
static void getSystemPageSize(FFPlatformSysinfo* info)
|
||||
{
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetNativeSystemInfo(&sysInfo);
|
||||
SYSTEM_BASIC_INFORMATION sbi;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL)))
|
||||
info->pageSize = sbi.PhysicalPageSize;
|
||||
else
|
||||
info->pageSize = 4096;
|
||||
}
|
||||
|
||||
switch(sysInfo.wProcessorArchitecture)
|
||||
static void getSystemArchitecture(FFPlatformSysinfo* info)
|
||||
{
|
||||
SYSTEM_PROCESSOR_INFORMATION spi;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorInformation, &spi, sizeof(spi), NULL)))
|
||||
{
|
||||
switch (spi.ProcessorArchitecture)
|
||||
{
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
ffStrbufSetStatic(&info->architecture, "x86_64");
|
||||
break;
|
||||
@@ -244,7 +257,7 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
|
||||
ffStrbufSetStatic(&info->architecture, "ia64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
switch (sysInfo.wProcessorLevel)
|
||||
switch (spi.ProcessorLevel)
|
||||
{
|
||||
case 4:
|
||||
ffStrbufSetStatic(&info->architecture, "i486");
|
||||
@@ -282,14 +295,23 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
|
||||
default:
|
||||
ffStrbufSetStatic(&info->architecture, "unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->pageSize = sysInfo.dwPageSize;
|
||||
static void getCwd(FFPlatform* platform)
|
||||
{
|
||||
PCURDIR cwd = &ffGetPeb()->ProcessParameters->CurrentDirectory;
|
||||
ffStrbufSetNWS(&platform->cwd, cwd->DosPath.Length / sizeof(WCHAR), cwd->DosPath.Buffer);
|
||||
ffStrbufReplaceAllC(&platform->cwd, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
|
||||
}
|
||||
|
||||
void ffPlatformInitImpl(FFPlatform* platform)
|
||||
{
|
||||
platform->pid = (uint32_t) (uintptr_t) ffGetTeb()->ClientId.UniqueProcess;
|
||||
getExePath(platform);
|
||||
getCwd(platform);
|
||||
getHomeDir(platform);
|
||||
getCacheDir(platform);
|
||||
getConfigDirs(platform);
|
||||
@@ -300,5 +322,6 @@ void ffPlatformInitImpl(FFPlatform* platform)
|
||||
getUserShell(platform);
|
||||
|
||||
getSystemReleaseAndVersion(&platform->sysinfo);
|
||||
getSystemArchitectureAndPageSize(&platform->sysinfo);
|
||||
getSystemArchitecture(&platform->sysinfo);
|
||||
getSystemPageSize(&platform->sysinfo);
|
||||
}
|
||||
|
||||
@@ -6,11 +6,7 @@
|
||||
void* ffListAdd(FFlist* list)
|
||||
{
|
||||
if(list->length == list->capacity)
|
||||
{
|
||||
list->capacity = list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2;
|
||||
// realloc(NULL, newSize) is same as malloc(newSize)
|
||||
list->data = realloc(list->data, (size_t)list->capacity * list->elementSize);
|
||||
}
|
||||
ffListReserve(list, list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2);
|
||||
|
||||
++list->length;
|
||||
return ffListGet(list, list->length - 1);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
@@ -183,7 +184,7 @@ const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char unti
|
||||
if(value == NULL)
|
||||
return NULL;
|
||||
|
||||
char* end = strchr(value, until);
|
||||
const char* end = strchr(value, until);
|
||||
if(end == NULL)
|
||||
ffStrbufAppendS(strbuf, value);
|
||||
else
|
||||
@@ -915,3 +916,44 @@ bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLeng
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf)
|
||||
{
|
||||
assert(strbuf);
|
||||
|
||||
if (strbuf->length < 4)
|
||||
return false;
|
||||
|
||||
// Static string must be converted first.
|
||||
assert(strbuf->allocated > 0);
|
||||
|
||||
bool changed = false;
|
||||
uint32_t read = 0;
|
||||
uint32_t write = 0;
|
||||
|
||||
while (read < strbuf->length)
|
||||
{
|
||||
if (
|
||||
read + 3 < strbuf->length &&
|
||||
strbuf->chars[read] == '\\' &&
|
||||
strbuf->chars[read + 1] == 'x'
|
||||
)
|
||||
{
|
||||
int8_t hi = ffHexCharToInt(strbuf->chars[read + 2]);
|
||||
int8_t lo = ffHexCharToInt(strbuf->chars[read + 3]);
|
||||
if (hi >= 0 && lo >= 0)
|
||||
{
|
||||
strbuf->chars[write++] = (char) ((hi << 4) | lo);
|
||||
read += 4;
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
strbuf->chars[write++] = strbuf->chars[read++];
|
||||
}
|
||||
|
||||
strbuf->length = write;
|
||||
strbuf->chars[write] = '\0';
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include "common/binary.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -17,19 +16,34 @@
|
||||
*/
|
||||
const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
// Use MapAndLoad with cleanup attribute to ensure proper unloading
|
||||
__attribute__((__cleanup__(UnMapAndLoad))) LOADED_IMAGE loadedImage = {};
|
||||
if (!MapAndLoad(peFile, NULL, &loadedImage, FALSE, TRUE))
|
||||
return "File could not be loaded";
|
||||
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileA(peFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return "CreateFileA() failed";
|
||||
|
||||
// Iterate through all sections in the PE file
|
||||
for (ULONG i = 0; i < loadedImage.NumberOfSections; ++i)
|
||||
FF_AUTO_CLOSE_FD HANDLE hSection = NULL;
|
||||
if (!NT_SUCCESS(NtCreateSection(&hSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, hFile)))
|
||||
return "NtCreateSection() failed";
|
||||
|
||||
PVOID base = NULL;
|
||||
SIZE_T viewSize = 0;
|
||||
if (!NT_SUCCESS(NtMapViewOfSection(hSection, NtCurrentProcess(), &base, 0, 0, NULL, &viewSize, ViewUnmap, 0, PAGE_READONLY)))
|
||||
return "NtMapViewOfSection() failed";
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader(base);
|
||||
if (!ntHeaders)
|
||||
{
|
||||
NtUnmapViewOfSection(NtCurrentProcess(), base);
|
||||
return "RtlImageNtHeader() failed";
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
|
||||
for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER section = &loadedImage.Sections[i];
|
||||
// Look for initialized data sections with the name ".rdata" which typically contains string literals
|
||||
if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) && ffStrEquals((const char*) section->Name, ".rdata"))
|
||||
{
|
||||
uint8_t *data = (uint8_t *) loadedImage.MappedAddress + section->PointerToRawData;
|
||||
uint8_t *data = (uint8_t *) base + section->PointerToRawData;
|
||||
|
||||
// Scan the section for string literals
|
||||
for (size_t off = 0; off < section->SizeOfRawData; ++off)
|
||||
@@ -48,5 +62,6 @@ const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *st
|
||||
}
|
||||
}
|
||||
|
||||
NtUnmapViewOfSection(NtCurrentProcess(), base);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ bool ffParseModuleOptions(const char* key, const char* value)
|
||||
}
|
||||
fprintf(stderr, "Error: Unsupported module option: %s\n", key);
|
||||
fputs(" Support of module options has been removed. Please add the flag to the JSON config instead.\n", stderr);
|
||||
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ? value : "true", value ? "\"" : "");
|
||||
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ?: "true", value ? "\"" : "");
|
||||
fputs(" See <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration> for more information.\n", stderr);
|
||||
exit(477);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ static bool loadLibSymbols(FFDBusLibrary* lib)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_next, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_unref, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_send_with_reply_and_block, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_unref, false)
|
||||
dbus = NULL; // don't auto dlclose
|
||||
return true;
|
||||
}
|
||||
@@ -51,6 +52,15 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDBusDestroyData(FFDBusData* data)
|
||||
{
|
||||
if (data->connection != NULL)
|
||||
{
|
||||
data->lib->ffdbus_connection_unref(data->connection);
|
||||
data->connection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
|
||||
{
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
@@ -10,7 +10,7 @@ const char* ffDebugWin32Error(DWORD errorCode)
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
(DWORD) errorCode,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
0,
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
NULL);
|
||||
@@ -19,10 +19,32 @@ const char* ffDebugWin32Error(DWORD errorCode)
|
||||
snprintf(buffer, sizeof(buffer), "Unknown error code (%lu)", errorCode);
|
||||
} else {
|
||||
// Remove trailing newline
|
||||
if (buffer[len - 1] == '\n') buffer[len - 1] = '\0';
|
||||
if (buffer[len - 2] == '\r') buffer[len - 2] = '\0';
|
||||
snprintf(buffer + len - 2, sizeof(buffer) - len + 2, " (%lu)", errorCode);
|
||||
while (len > 0 && (buffer[len - 1] == '\r' || buffer[len - 1] == '\n')) {
|
||||
buffer[--len] = '\0';
|
||||
}
|
||||
snprintf(buffer + len, sizeof(buffer) - len + 2, " (%lu)", errorCode);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* ffDebugNtStatus(NTSTATUS status)
|
||||
{
|
||||
return ffDebugWin32Error(RtlNtStatusToDosError(status));
|
||||
}
|
||||
|
||||
static inline DWORD HRESULTToWin32Error(HRESULT hr)
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
return HRESULT_CODE(hr);
|
||||
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
const char* ffDebugHResult(HRESULT hr)
|
||||
{
|
||||
return ffDebugWin32Error(HRESULTToWin32Error(hr));
|
||||
}
|
||||
|
||||
@@ -128,3 +128,16 @@ bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length)
|
||||
{
|
||||
if (length < 128 || length % 128 != 0) return false;
|
||||
|
||||
static const uint8_t edidHeader[] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
||||
if (memcmp(edid, edidHeader, sizeof(edidHeader)) != 0) return false;
|
||||
|
||||
uint8_t sum = 0;
|
||||
for (uint32_t i = 0; i < 128; i++) sum += edid[i];
|
||||
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
+32
-25
@@ -10,37 +10,37 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
{
|
||||
switch(formatarg->type)
|
||||
{
|
||||
case FF_FORMAT_ARG_TYPE_INT:
|
||||
case FF_ARG_TYPE_INT:
|
||||
ffStrbufAppendSInt(buffer, *(int32_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT:
|
||||
case FF_ARG_TYPE_UINT:
|
||||
ffStrbufAppendUInt(buffer, *(uint32_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT64:
|
||||
case FF_ARG_TYPE_UINT64:
|
||||
ffStrbufAppendUInt(buffer, *(uint64_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT16:
|
||||
case FF_ARG_TYPE_UINT16:
|
||||
ffStrbufAppendUInt(buffer, *(uint16_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT8:
|
||||
case FF_ARG_TYPE_UINT8:
|
||||
ffStrbufAppendUInt(buffer, *(uint8_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_STRING:
|
||||
case FF_ARG_TYPE_STRING:
|
||||
ffStrbufAppendS(buffer, (const char*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_STRBUF:
|
||||
case FF_ARG_TYPE_STRBUF:
|
||||
ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_FLOAT:
|
||||
case FF_ARG_TYPE_FLOAT:
|
||||
ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_DOUBLE:
|
||||
case FF_ARG_TYPE_DOUBLE:
|
||||
ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_BOOL:
|
||||
case FF_ARG_TYPE_BOOL:
|
||||
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_LIST:
|
||||
case FF_ARG_TYPE_LIST:
|
||||
{
|
||||
const FFlist* list = (const FFlist*) formatarg->value;
|
||||
for(uint32_t i = 0; i < list->length; i++)
|
||||
@@ -51,8 +51,15 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FF_ARG_TYPE_BUFFER:
|
||||
{
|
||||
// Placeholder for binary data, just print the size for now
|
||||
const FFArgBuffer* argBuffer = (const FFArgBuffer*) formatarg->value;
|
||||
ffStrbufAppendF(buffer, "buffer(%u bytes)", argBuffer->length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if(formatarg->type != FF_FORMAT_ARG_TYPE_NULL)
|
||||
if(formatarg->type != FF_ARG_TYPE_NULL)
|
||||
fprintf(stderr, "Error: format string \"%s\": argument is not implemented: %i\n", buffer->chars, formatarg->type);
|
||||
break;
|
||||
}
|
||||
@@ -87,7 +94,7 @@ static uint32_t getArgumentIndex(const char* placeholderValue, uint32_t numArgs,
|
||||
for (uint32_t i = 0; i < numArgs; ++i)
|
||||
{
|
||||
const FFformatarg* arg = &arguments[i];
|
||||
if (arg->name && strcasecmp(placeholderValue, arg->name) == 0)
|
||||
if (arg->name && ffStrEqualsIgnCase(placeholderValue, arg->name))
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
@@ -107,16 +114,16 @@ static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start,
|
||||
static inline bool formatArgSet(const FFformatarg* arg)
|
||||
{
|
||||
return arg->value != NULL && (
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_BOOL && *(bool*)arg->value) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_LIST && ((FFlist*)arg->value)->length > 0)
|
||||
(arg->type == FF_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) ||
|
||||
(arg->type == FF_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
|
||||
(arg->type == FF_ARG_TYPE_INT && *(int*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_BOOL && *(bool*)arg->value) ||
|
||||
(arg->type == FF_ARG_TYPE_LIST && ((FFlist*)arg->value)->length > 0)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -204,7 +211,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
|
||||
|
||||
// testing for an invalid index
|
||||
if (index > numArgs)
|
||||
if (index > numArgs || index < 1)
|
||||
{
|
||||
appendInvalidPlaceholder(buffer, "{?", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
@@ -230,7 +237,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
|
||||
|
||||
// testing for an invalid index
|
||||
if (index > numArgs)
|
||||
if (index > numArgs || index < 1)
|
||||
{
|
||||
appendInvalidPlaceholder(buffer, "{/", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
|
||||
+22
-16
@@ -55,12 +55,15 @@ void ffInitInstance(void)
|
||||
setlocale(LC_TIME, "");
|
||||
#endif
|
||||
|
||||
initState(&instance.state);
|
||||
defaultConfig();
|
||||
initState(&instance.state);
|
||||
}
|
||||
|
||||
static volatile bool ffDisableLinewrap = true;
|
||||
static volatile bool ffHideCursor = true;
|
||||
#if _WIN32
|
||||
static volatile UINT oldCp = CP_UTF8;
|
||||
#endif
|
||||
|
||||
static void resetConsole(void)
|
||||
{
|
||||
@@ -70,12 +73,15 @@ static void resetConsole(void)
|
||||
if(ffHideCursor)
|
||||
fputs("\033[?25h", stdout);
|
||||
|
||||
#if defined(_WIN32)
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
if(instance.state.dynamicInterval > 0)
|
||||
fputs("\033[?1049l", stdout); // Disable alternate buffer
|
||||
|
||||
#if defined(_WIN32)
|
||||
fflush(stdout);
|
||||
|
||||
if(oldCp != CP_UTF8)
|
||||
SetConsoleOutputCP(oldCp);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -106,9 +112,12 @@ void ffStart(void)
|
||||
SetConsoleCtrlHandler(consoleHandler, TRUE);
|
||||
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD mode = 0;
|
||||
GetConsoleMode(hStdout, &mode);
|
||||
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
if (GetConsoleMode(hStdout, &mode))
|
||||
{
|
||||
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
oldCp = GetConsoleOutputCP();
|
||||
if (oldCp != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
|
||||
}
|
||||
#else
|
||||
if (instance.config.display.noBuffer) setvbuf(stdout, NULL, _IONBF, 0);
|
||||
struct sigaction action = { .sa_handler = exitSignalHandler };
|
||||
@@ -225,9 +234,6 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_FREETYPE
|
||||
"freetype\n"
|
||||
#endif
|
||||
#if FF_HAVE_PCIACCESS
|
||||
"libpciaccess\n"
|
||||
#endif
|
||||
#if FF_HAVE_PULSE
|
||||
"libpulse\n"
|
||||
#endif
|
||||
@@ -240,9 +246,6 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_LIBZFS
|
||||
"libzfs\n"
|
||||
#endif
|
||||
#if FF_HAVE_DIRECTX_HEADERS
|
||||
"Directx Headers\n"
|
||||
#endif
|
||||
#if FF_USE_SYSTEM_YYJSON
|
||||
"System yyjson\n"
|
||||
#endif
|
||||
@@ -255,8 +258,11 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_EMBEDDED_PCIIDS
|
||||
"Embedded pciids\n"
|
||||
#endif
|
||||
#if FF_WIN7_COMPAT
|
||||
"Windows 7 Compatibility\n"
|
||||
#if FF_WIN81_COMPAT
|
||||
"Windows 8.1 Compatibility\n"
|
||||
#endif
|
||||
#if FF_APPLE_MEMSIZE_USABLE
|
||||
"Apple memsize_usable\n"
|
||||
#endif
|
||||
""
|
||||
, stdout);
|
||||
|
||||
@@ -23,7 +23,7 @@ static void createSubfolders(const char* fileName)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
|
||||
char *token = NULL;
|
||||
const char *token = NULL;
|
||||
while((token = strchr(fileName, '/')) != NULL)
|
||||
{
|
||||
ffStrbufAppendNS(&path, (uint32_t)(token - fileName + 1), fileName);
|
||||
@@ -97,42 +97,6 @@ bool ffAppendFDBuffer(int fd, FFstrbuf* buffer)
|
||||
return buffer->length > 0;
|
||||
}
|
||||
|
||||
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
int FF_AUTO_CLOSE_FD fd = open(fileName, O_RDONLY | O_CLOEXEC);
|
||||
if(fd == -1)
|
||||
return -1;
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
}
|
||||
|
||||
ssize_t ffReadFileDataRelative(int dfd, const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
int FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
|
||||
if(fd == -1)
|
||||
return -1;
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
}
|
||||
|
||||
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
int FF_AUTO_CLOSE_FD fd = open(fileName, O_RDONLY | O_CLOEXEC);
|
||||
if(fd == -1)
|
||||
return false;
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
bool ffAppendFileBufferRelative(int dfd, const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
int FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
|
||||
if(fd == -1)
|
||||
return false;
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
+179
-68
@@ -1,32 +1,172 @@
|
||||
#include "common/io.h"
|
||||
#include "fastfetch.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include "common/windows/unicode.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "common/windows/nt.h"
|
||||
#include <ntstatus.h>
|
||||
|
||||
static void createSubfolders(const char* fileName)
|
||||
static bool createSubfolders(wchar_t* fileName)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
char *token = NULL;
|
||||
while((token = strchr(fileName, '/')) != NULL)
|
||||
HANDLE hRoot = ffGetPeb()->ProcessParameters->CurrentDirectory.Handle;
|
||||
bool closeRoot = false;
|
||||
wchar_t* ptr = fileName;
|
||||
|
||||
// Absolute drive path: C:\...
|
||||
if (ffCharIsEnglishAlphabet((char)ptr[0]) && ptr[1] == L':' && ptr[2] == L'\\')
|
||||
{
|
||||
ffStrbufAppendNS(&path, (uint32_t)(token - fileName + 1), fileName);
|
||||
CreateDirectoryA(path.chars, NULL);
|
||||
fileName = token + 1;
|
||||
wchar_t saved = ptr[3];
|
||||
ptr[3] = L'\0';
|
||||
|
||||
hRoot = CreateFileW(
|
||||
fileName,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
|
||||
ptr[3] = saved;
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
closeRoot = true;
|
||||
ptr += 3; // skip "C:\"
|
||||
}
|
||||
// UNC path: \\server\share\...
|
||||
else if (ptr[0] == L'\\' && ptr[1] == L'\\')
|
||||
{
|
||||
wchar_t* serverEnd = wcschr(ptr + 2, L'\\');
|
||||
if (serverEnd == NULL)
|
||||
return false;
|
||||
|
||||
wchar_t* shareEnd = wcschr(serverEnd + 1, L'\\');
|
||||
if (shareEnd == NULL)
|
||||
return true; // no parent subfolder exists before file name
|
||||
|
||||
wchar_t saved = *shareEnd;
|
||||
*shareEnd = L'\0';
|
||||
|
||||
hRoot = CreateFileW(
|
||||
fileName,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
|
||||
*shareEnd = saved;
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
closeRoot = true;
|
||||
ptr = shareEnd + 1; // first component under share
|
||||
}
|
||||
// Rooted path on current drive: \foo\bar
|
||||
else if (ptr[0] == L'\\')
|
||||
{
|
||||
UNICODE_STRING* dosPath = &ffGetPeb()->ProcessParameters->CurrentDirectory.DosPath;
|
||||
wchar_t driveRoot[] = { dosPath->Buffer[0], L':', L'\\', L'\0' };
|
||||
hRoot = CreateFileW(
|
||||
driveRoot,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
closeRoot = true;
|
||||
ptr++; // skip leading '\'
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
wchar_t* token = wcschr(ptr, L'\\');
|
||||
if (token == NULL)
|
||||
break;
|
||||
|
||||
// Skip empty path segments caused by duplicated '\'
|
||||
if (token == ptr)
|
||||
{
|
||||
ptr = token + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
HANDLE hNew = INVALID_HANDLE_VALUE;
|
||||
IO_STATUS_BLOCK iosb = {};
|
||||
|
||||
NTSTATUS status = NtCreateFile(
|
||||
&hNew,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
&(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = hRoot,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Buffer = ptr,
|
||||
.Length = (USHORT)((USHORT)(token - ptr) * sizeof(wchar_t)),
|
||||
.MaximumLength = (USHORT)((USHORT)(token - ptr) * sizeof(wchar_t)),
|
||||
},
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
},
|
||||
&iosb,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_OPEN_IF,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
NtClose(hRoot);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
NtClose(hRoot);
|
||||
hRoot = hNew;
|
||||
closeRoot = true;
|
||||
|
||||
ptr = token + 1;
|
||||
}
|
||||
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
NtClose(hRoot);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
|
||||
{
|
||||
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
wchar_t fileNameW[MAX_PATH];
|
||||
ULONG len = 0;
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1)))
|
||||
return false;
|
||||
|
||||
for (ULONG i = 0; i < len / sizeof(wchar_t); ++i)
|
||||
{
|
||||
if (fileNameW[i] == L'/')
|
||||
fileNameW[i] = L'\\';
|
||||
}
|
||||
|
||||
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (GetLastError() == ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
createSubfolders(fileName);
|
||||
handle = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (!createSubfolders(fileNameW))
|
||||
return false;
|
||||
handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
@@ -70,12 +210,13 @@ static inline void readUntilEOF(HANDLE handle, FFstrbuf* buffer)
|
||||
|
||||
bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer)
|
||||
{
|
||||
LARGE_INTEGER fileSize;
|
||||
if(!GetFileSizeEx(handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
FILE_STANDARD_INFORMATION fileInfo;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
if(!NT_SUCCESS(NtQueryInformationFile(handle, &iosb, &fileInfo, sizeof(fileInfo), FileStandardInformation)))
|
||||
fileInfo.EndOfFile.QuadPart = 0;
|
||||
|
||||
if (fileSize.QuadPart > 0)
|
||||
readWithLength(handle, buffer, (uint32_t)fileSize.QuadPart);
|
||||
if (fileInfo.EndOfFile.QuadPart > 0)
|
||||
readWithLength(handle, buffer, (uint32_t)fileInfo.EndOfFile.QuadPart);
|
||||
else
|
||||
readUntilEOF(handle, buffer);
|
||||
|
||||
@@ -84,24 +225,6 @@ bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer)
|
||||
return buffer->length > 0;
|
||||
}
|
||||
|
||||
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if(handle == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
return ffReadFDData(handle, dataSize, data);
|
||||
}
|
||||
|
||||
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if(handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
return ffAppendFDBuffer(handle, buffer);
|
||||
}
|
||||
|
||||
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory)
|
||||
{
|
||||
assert(fileNameLen <= 0x7FFF);
|
||||
@@ -128,38 +251,22 @@ HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool d
|
||||
return hFile;
|
||||
}
|
||||
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, bool directory)
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, int oflag)
|
||||
{
|
||||
wchar_t fileNameW[MAX_PATH];
|
||||
int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fileName, -1, fileNameW, ARRAY_SIZE(fileNameW));
|
||||
if (len == 0) return INVALID_HANDLE_VALUE;
|
||||
ULONG len;
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1)))
|
||||
return INVALID_HANDLE_VALUE;
|
||||
// Implies `fileNameW[len] = L'\0';` and `len` includes the null terminator
|
||||
len /= sizeof(wchar_t); // convert from bytes to characters
|
||||
|
||||
for (int i = 0; i < len - 1; ++i)
|
||||
for (uint32_t i = 0; i < len - 1; ++i)
|
||||
{
|
||||
if (fileNameW[i] == L'/')
|
||||
fileNameW[i] = L'\\';
|
||||
}
|
||||
|
||||
return openatW(dfd, fileNameW, (uint16_t)(len - 1), directory);
|
||||
}
|
||||
|
||||
bool ffAppendFileBufferRelative(HANDLE dfd, const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
HANDLE FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, false);
|
||||
if(fd == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
ssize_t ffReadFileDataRelative(HANDLE dfd, const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
HANDLE FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, false);
|
||||
if(fd == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
return openatW(dfd, fileNameW, (uint16_t)(len - 1), !!(oflag & O_DIRECTORY));
|
||||
}
|
||||
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
@@ -172,13 +279,17 @@ bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
}
|
||||
}
|
||||
|
||||
DWORD length = ExpandEnvironmentStringsA(in, NULL, 0);
|
||||
if (length <= 1) return false;
|
||||
wchar_t pathInW[MAX_PATH], pathOutW[MAX_PATH];
|
||||
ULONG len = (ULONG) strlen(in);
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathInW, (ULONG) sizeof(pathInW), &len, in, len)))
|
||||
return false;
|
||||
len /= sizeof(wchar_t); // convert from bytes to characters
|
||||
|
||||
ffStrbufClear(out);
|
||||
ffStrbufEnsureFree(out, (uint32_t)length);
|
||||
ExpandEnvironmentStringsA(in, out->chars, length);
|
||||
out->length = (uint32_t)length - 1;
|
||||
size_t outLen; // in characters, including null terminator
|
||||
if (!NT_SUCCESS(RtlExpandEnvironmentStrings(NULL, pathInW, len, pathOutW, ARRAY_SIZE(pathOutW), &outLen)))
|
||||
return false;
|
||||
|
||||
ffStrbufSetNWS(out, (uint32_t) outLen - 1, pathOutW);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -308,10 +419,10 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (WaitForSingleObjectEx(hInput, FF_IO_TERM_RESP_WAIT_MS, TRUE) != WAIT_OBJECT_0)
|
||||
if (NtWaitForSingleObject(hInput, FALSE, &(LARGE_INTEGER) { .QuadPart = (int64_t) FF_IO_TERM_RESP_WAIT_MS * -10000 }) != STATUS_WAIT_0)
|
||||
{
|
||||
SetConsoleMode(hInput, inputMode);
|
||||
return "WaitForSingleObject() failed or timeout";
|
||||
return "NtWaitForSingleObject() failed or timeout";
|
||||
}
|
||||
|
||||
// Ignore all unexpected input events
|
||||
@@ -350,7 +461,7 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
|
||||
va_list cargs;
|
||||
va_copy(cargs, args);
|
||||
int ret = vsscanf(buffer, format, args);
|
||||
int ret = vsscanf(buffer, format, cargs);
|
||||
va_end(cargs);
|
||||
|
||||
if (ret <= 0)
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
#include "common/kmod.h"
|
||||
|
||||
#if __linux__
|
||||
#include "common/io.h"
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
static FFstrbuf modules;
|
||||
if (modules.chars == NULL)
|
||||
{
|
||||
ffStrbufInitS(&modules, "\n");
|
||||
ffAppendFileBuffer("/proc/modules", &modules);
|
||||
}
|
||||
|
||||
if (modules.length == 0) return false;
|
||||
|
||||
uint32_t len = (uint32_t) strlen(modName);
|
||||
if (len > 250) return false;
|
||||
|
||||
char temp[256];
|
||||
temp[0] = '\n';
|
||||
memcpy(temp + 1, modName, len);
|
||||
temp[1 + len] = ' ';
|
||||
return memmem(modules.chars, modules.length, temp, len + 2) != NULL;
|
||||
}
|
||||
#elif __FreeBSD__
|
||||
#include <sys/param.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
return modfind(modName) >= 0;
|
||||
}
|
||||
#elif __NetBSD__
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <sys/module.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
typedef struct __attribute__((__packed__)) FFNbsdModList
|
||||
{
|
||||
int len;
|
||||
modstat_t mods[];
|
||||
} FFNbsdModList;
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
static FFNbsdModList* list = NULL;
|
||||
|
||||
if (list == NULL)
|
||||
{
|
||||
struct iovec iov = {};
|
||||
|
||||
for (size_t len = 8192;; len = iov.iov_len)
|
||||
{
|
||||
iov.iov_len = len;
|
||||
iov.iov_base = realloc(iov.iov_base, len);
|
||||
if (modctl(MODCTL_STAT, &iov) < 0)
|
||||
{
|
||||
free(iov.iov_base);
|
||||
return true; // ignore errors
|
||||
}
|
||||
|
||||
if (len >= iov.iov_len) break;
|
||||
}
|
||||
list = (FFNbsdModList*) iov.iov_base;
|
||||
}
|
||||
|
||||
for (int i = 0; i < list->len; i++)
|
||||
{
|
||||
if (ffStrEquals(list->mods[i].ms_name, modName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#elif __APPLE__
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include <IOKit/kext/KextManager.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, modName, kCFStringEncodingUTF8);
|
||||
FF_CFTYPE_AUTO_RELEASE CFArrayRef identifiers = CFArrayCreate(kCFAllocatorDefault, (const void**) &name, 1, &kCFTypeArrayCallBacks);
|
||||
FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL);
|
||||
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef kextInfo = KextManagerCopyLoadedKextInfo(identifiers, keys);
|
||||
return CFDictionaryContainsKey(kextInfo, name);
|
||||
}
|
||||
#else
|
||||
bool ffKmodLoaded(FF_MAYBE_UNUSED const char* modName)
|
||||
{
|
||||
return true; // Don't generate kernel module related errors
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include <IOKit/kext/KextManager.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, modName, kCFStringEncodingUTF8);
|
||||
FF_CFTYPE_AUTO_RELEASE CFArrayRef identifiers = CFArrayCreate(kCFAllocatorDefault, (const void**) &name, 1, &kCFTypeArrayCallBacks);
|
||||
FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL);
|
||||
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef kextInfo = KextManagerCopyLoadedKextInfo(identifiers, keys);
|
||||
return CFDictionaryContainsKey(kextInfo, name);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "common/kmod.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
return modfind(modName) >= 0;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/io.h"
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
static FFstrbuf modules;
|
||||
if (modules.chars == NULL)
|
||||
{
|
||||
ffStrbufInitS(&modules, "\n");
|
||||
ffAppendFileBuffer("/proc/modules", &modules);
|
||||
}
|
||||
|
||||
if (modules.length == 0) return false;
|
||||
|
||||
uint32_t len = (uint32_t) strlen(modName);
|
||||
if (len > 250) return false;
|
||||
|
||||
char temp[256];
|
||||
temp[0] = '\n';
|
||||
memcpy(temp + 1, modName, len);
|
||||
temp[1 + len] = ' ';
|
||||
return memmem(modules.chars, modules.length, temp, len + 2) != NULL;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <sys/module.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
typedef struct __attribute__((__packed__)) FFNbsdModList
|
||||
{
|
||||
int len;
|
||||
modstat_t mods[];
|
||||
} FFNbsdModList;
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
static FFNbsdModList* list = NULL;
|
||||
|
||||
if (list == NULL)
|
||||
{
|
||||
struct iovec iov = {};
|
||||
|
||||
for (size_t len = 8192;; len = iov.iov_len)
|
||||
{
|
||||
iov.iov_len = len;
|
||||
iov.iov_base = realloc(iov.iov_base, len);
|
||||
if (modctl(MODCTL_STAT, &iov) < 0)
|
||||
{
|
||||
free(iov.iov_base);
|
||||
return true; // ignore errors
|
||||
}
|
||||
|
||||
if (len >= iov.iov_len) break;
|
||||
}
|
||||
list = (FFNbsdModList*) iov.iov_base;
|
||||
}
|
||||
|
||||
for (int i = 0; i < list->len; i++)
|
||||
{
|
||||
if (ffStrEquals(list->mods[i].ms_name, modName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "common/kmod.h"
|
||||
|
||||
bool ffKmodLoaded(FF_MAYBE_UNUSED const char* modName)
|
||||
{
|
||||
return true; // Don't generate kernel module related errors
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <sys/modctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
struct modinfo modinfo = {
|
||||
.mi_id = -1,
|
||||
.mi_nextid = -1,
|
||||
.mi_info = MI_INFO_ALL,
|
||||
};
|
||||
|
||||
for (int id = -1; modctl(MODINFO, id, &modinfo) == 0; id = modinfo.mi_id)
|
||||
{
|
||||
modinfo.mi_name[MODMAXNAMELEN - 1] = '\0';
|
||||
|
||||
if (ffStrEquals(modinfo.mi_name, modName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return !(errno == EINVAL || errno == ENOENT);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
ULONG bufferSize = 0;
|
||||
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &bufferSize);
|
||||
if (bufferSize == 0)
|
||||
return true; // ignore errors
|
||||
|
||||
FF_AUTO_FREE RTL_PROCESS_MODULES* buffer = malloc(bufferSize);
|
||||
|
||||
if (!NT_SUCCESS(NtQuerySystemInformation(SystemModuleInformation, buffer, bufferSize, &bufferSize)))
|
||||
return true; // ignore errors
|
||||
|
||||
for (ULONG i = 0; i < buffer->NumberOfModules; i++)
|
||||
{
|
||||
const char* name = (const char*) buffer->Modules[i].FullPathName + buffer->Modules[i].OffsetToFileName;
|
||||
|
||||
if (ffStrEqualsIgnCase(name, modName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/library.h"
|
||||
|
||||
#if _WIN32
|
||||
#include "common/debug.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include <errno.h>
|
||||
#include <ntstatus.h>
|
||||
#endif
|
||||
|
||||
#ifndef FF_DISABLE_DLOPEN
|
||||
|
||||
#include <stdarg.h>
|
||||
@@ -36,7 +43,7 @@ static void* libraryLoad(const char* path, int maxVersion)
|
||||
if (pathLen == instance.state.platform.exePath.length)
|
||||
return result;
|
||||
|
||||
char absPath[MAX_PATH + 1];
|
||||
char absPath[MAX_PATH * 2];
|
||||
strcpy(mempcpy(absPath, instance.state.platform.exePath.chars, pathLen + 1), path);
|
||||
return dlopen(absPath, FF_DLOPEN_FLAGS);
|
||||
|
||||
@@ -92,3 +99,81 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
|
||||
void* dlopen(const char* path, FF_MAYBE_UNUSED int mode)
|
||||
{
|
||||
wchar_t pathW[MAX_PATH + 1];
|
||||
ULONG pathWBytes = 0;
|
||||
|
||||
NTSTATUS status = RtlUTF8ToUnicodeN(pathW, sizeof(pathW), &pathWBytes, path, (uint32_t)strlen(path) + 1);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
FF_DEBUG("RtlUTF8ToUnicodeN failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PVOID module = NULL;
|
||||
status = LdrLoadDll(NULL, NULL, &(UNICODE_STRING) {
|
||||
.Length = (USHORT) pathWBytes - sizeof(wchar_t), // Exclude null terminator
|
||||
.MaximumLength = (USHORT) pathWBytes,
|
||||
.Buffer = pathW,
|
||||
}, &module);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
FF_DEBUG("LdrLoadDll failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
int dlclose(void* handle)
|
||||
{
|
||||
NTSTATUS status = LdrUnloadDll(handle);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
FF_DEBUG("LdrUnloadDll failed for handle %p with status 0x%08lX: %s", handle, status, ffDebugNtStatus(status));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* dlsym(void* handle, const char* symbol)
|
||||
{
|
||||
void* address;
|
||||
USHORT symbolBytes = (USHORT) strlen(symbol) + 1;
|
||||
NTSTATUS status = LdrGetProcedureAddress(handle, &(ANSI_STRING) {
|
||||
.Length = symbolBytes - sizeof(char),
|
||||
.MaximumLength = symbolBytes,
|
||||
.Buffer = (char*) symbol,
|
||||
}, 0, &address);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
FF_DEBUG("LdrGetProcedureAddress failed for symbol %s with status 0x%08lX: %s", symbol, status, ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
void* ffLibraryGetModule(const wchar_t* libraryFileName)
|
||||
{
|
||||
assert(libraryFileName != NULL && "Use \"ffGetPeb()->ImageBaseAddress\" instead");
|
||||
|
||||
void* module = NULL;
|
||||
USHORT libraryFileNameBytes = (USHORT) (wcslen(libraryFileName) * sizeof(wchar_t)) + sizeof(wchar_t);
|
||||
NTSTATUS status = LdrGetDllHandle(NULL, NULL, &(UNICODE_STRING) {
|
||||
.Length = libraryFileNameBytes - sizeof(wchar_t),
|
||||
.MaximumLength = libraryFileNameBytes,
|
||||
.Buffer = (wchar_t*) libraryFileName,
|
||||
}, &module);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
FF_DEBUG("LdrGetDllHandle failed for library %ls with status 0x%08lX: %s", libraryFileName, status, ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
return module;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "common/memrchr.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void* memrchr(const void* s, int c, size_t n)
|
||||
{
|
||||
if (n == 0) return NULL;
|
||||
|
||||
const uint8_t uc = (uint8_t) c;
|
||||
|
||||
const uint8_t* p = (const uint8_t*) s + n;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
if (*--p == uc) return (void*) p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -72,7 +72,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
int pid = getpid();
|
||||
uint32_t pid = instance.state.platform.pid;
|
||||
|
||||
struct {
|
||||
struct rt_msghdr hdr;
|
||||
@@ -85,7 +85,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
.rtm_version = RTM_VERSION,
|
||||
.rtm_addrs = RTA_DST | RTA_IFP | RTA_IFA,
|
||||
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
|
||||
.rtm_pid = pid,
|
||||
.rtm_pid = (pid_t) pid,
|
||||
.rtm_seq = 1,
|
||||
},
|
||||
.dst = {
|
||||
@@ -99,7 +99,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
|
||||
return false;
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid))
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == (pid_t) pid))
|
||||
;
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
@@ -145,7 +145,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
int pid = getpid();
|
||||
uint32_t pid = instance.state.platform.pid;
|
||||
|
||||
struct {
|
||||
struct rt_msghdr hdr;
|
||||
@@ -158,7 +158,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
.rtm_version = RTM_VERSION,
|
||||
.rtm_addrs = RTA_DST | RTA_IFP,
|
||||
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
|
||||
.rtm_pid = pid,
|
||||
.rtm_pid = (pid_t) pid,
|
||||
.rtm_seq = 2,
|
||||
},
|
||||
.dst = {
|
||||
@@ -172,7 +172,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
|
||||
return false;
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == pid))
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == (pid_t) pid))
|
||||
;
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
|
||||
@@ -19,7 +19,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
|
||||
|
||||
unsigned pid = (unsigned) getpid();
|
||||
uint32_t pid = instance.state.platform.pid;
|
||||
FF_DEBUG("Process PID: %u", pid);
|
||||
|
||||
// Bind socket
|
||||
@@ -235,7 +235,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
|
||||
|
||||
unsigned pid = (unsigned) getpid();
|
||||
uint32_t pid = instance.state.platform.pid;
|
||||
FF_DEBUG("Process PID: %u", pid);
|
||||
|
||||
// Bind socket
|
||||
|
||||
@@ -108,8 +108,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state)
|
||||
#else
|
||||
"sendto()"
|
||||
#endif
|
||||
" %s (sent=%zd, errno=%d: %s)", errno == 0 ? "succeeded" : "was in progress",
|
||||
sent, errno, strerror(errno));
|
||||
" %s (sent=%zd, %s)", errno == 0 ? "succeeded" : "was in progress", sent, strerror(errno));
|
||||
freeaddrinfo(state->addr);
|
||||
state->addr = NULL;
|
||||
ffStrbufDestroy(&state->command);
|
||||
@@ -122,7 +121,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state)
|
||||
#else
|
||||
"sendto()"
|
||||
#endif
|
||||
" failed: %s (errno=%d)", strerror(errno), errno);
|
||||
" failed: %s", strerror(errno));
|
||||
#ifdef __APPLE__
|
||||
return "connectx() failed";
|
||||
#else
|
||||
@@ -143,7 +142,7 @@ static const char* connectAndSend(FFNetworkingState* state)
|
||||
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);
|
||||
FF_DEBUG("connect() failed: %s", strerror(errno));
|
||||
ret = "connect() failed";
|
||||
goto error;
|
||||
}
|
||||
@@ -152,7 +151,7 @@ static const char* connectAndSend(FFNetworkingState* state)
|
||||
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);
|
||||
FF_DEBUG("send() failed: %s", strerror(errno));
|
||||
ret = "send() failed";
|
||||
goto error;
|
||||
}
|
||||
@@ -227,7 +226,7 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
|
||||
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);
|
||||
FF_DEBUG("socket() failed: %s", strerror(errno));
|
||||
ret = "socket() failed";
|
||||
goto error;
|
||||
}
|
||||
@@ -399,7 +398,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
}
|
||||
else if (pollRes == -1)
|
||||
{
|
||||
FF_DEBUG("poll() failed: %s (errno=%d)", strerror(errno), errno);
|
||||
FF_DEBUG("poll() failed: %s", strerror(errno));
|
||||
close(state->sockfd);
|
||||
state->sockfd = -1;
|
||||
return "poll() failed";
|
||||
@@ -417,6 +416,12 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
}
|
||||
#endif
|
||||
|
||||
if (shutdown(state->sockfd, SHUT_WR) == -1)
|
||||
{
|
||||
FF_DEBUG("Failed to shutdown socket send: %s", strerror(errno));
|
||||
// Not a critical error, continue anyway
|
||||
}
|
||||
|
||||
FF_DEBUG("Starting data reception");
|
||||
FF_MAYBE_UNUSED int recvCount = 0;
|
||||
uint32_t contentLength = 0;
|
||||
@@ -434,7 +439,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
if (received == 0) {
|
||||
FF_DEBUG("Connection closed (received=0)");
|
||||
} else {
|
||||
FF_DEBUG("Reception failed: %s (errno=%d)", strerror(errno), errno);
|
||||
FF_DEBUG("Reception failed: %s", strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -24,19 +24,19 @@ static const char* initWsaData(WSADATA* wsaData)
|
||||
}
|
||||
|
||||
//Dummy socket needed for WSAIoctl
|
||||
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
SOCKET sockfd = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
|
||||
if(sockfd == INVALID_SOCKET) {
|
||||
FF_DEBUG("socket(AF_INET, SOCK_STREAM) failed");
|
||||
FF_DEBUG("WSASocketW(AF_INET, SOCK_STREAM) failed");
|
||||
WSACleanup();
|
||||
return "socket(AF_INET, SOCK_STREAM) failed";
|
||||
return "WSASocketW(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) {
|
||||
&guid, sizeof(guid),
|
||||
&ConnectEx, sizeof(ConnectEx),
|
||||
&dwBytes, NULL, NULL) != 0) {
|
||||
FF_DEBUG("WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
|
||||
closesocket(sockfd);
|
||||
WSACleanup();
|
||||
@@ -92,26 +92,33 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
return "initWsaData() failed before";
|
||||
}
|
||||
|
||||
struct addrinfo* addr;
|
||||
struct addrinfo hints = {
|
||||
ADDRINFOW* addr;
|
||||
ADDRINFOW hints = {
|
||||
.ai_flags = AI_NUMERICSERV,
|
||||
.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)
|
||||
wchar_t hostW[256];
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(hostW, (ULONG) sizeof(hostW), NULL, host, (ULONG) strlen(host) + 1)))
|
||||
{
|
||||
FF_DEBUG("getaddrinfo() failed");
|
||||
return "getaddrinfo() failed";
|
||||
FF_DEBUG("Failed to convert host to wide string: %s", host);
|
||||
return "Failed to convert host to wide string";
|
||||
}
|
||||
|
||||
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
|
||||
if(GetAddrInfoW(hostW, L"80", &hints, &addr) != 0)
|
||||
{
|
||||
FF_DEBUG("GetAddrInfoW() failed");
|
||||
return "GetAddrInfoW() failed";
|
||||
}
|
||||
|
||||
state->sockfd = WSASocketW(addr->ai_family, addr->ai_socktype, addr->ai_protocol, NULL, 0, 0);
|
||||
if(state->sockfd == INVALID_SOCKET)
|
||||
{
|
||||
FF_DEBUG("socket() failed");
|
||||
freeaddrinfo(addr);
|
||||
return "socket() failed";
|
||||
FF_DEBUG("WSASocketW() failed");
|
||||
FreeAddrInfoW(addr);
|
||||
return "WSASocketW() failed";
|
||||
}
|
||||
|
||||
DWORD flag = 1;
|
||||
@@ -143,7 +150,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
{
|
||||
FF_DEBUG("bind() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
closesocket(state->sockfd);
|
||||
freeaddrinfo(addr);
|
||||
FreeAddrInfoW(addr);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
return "bind() failed";
|
||||
}
|
||||
@@ -156,7 +163,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
if (state->overlapped.hEvent == WSA_INVALID_EVENT) {
|
||||
FF_DEBUG("WSACreateEvent() failed");
|
||||
closesocket(state->sockfd);
|
||||
freeaddrinfo(addr);
|
||||
FreeAddrInfoW(addr);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
return "WSACreateEvent() failed";
|
||||
}
|
||||
@@ -200,7 +207,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int)addr->ai_addrlen,
|
||||
state->command.chars, state->command.length, &sent, &state->overlapped);
|
||||
|
||||
freeaddrinfo(addr);
|
||||
FreeAddrInfoW(addr);
|
||||
addr = NULL;
|
||||
|
||||
if(!result)
|
||||
@@ -251,7 +258,8 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
} else {
|
||||
FF_DEBUG("WSAWaitForMultipleEvents failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
}
|
||||
CancelIo((HANDLE) state->sockfd);
|
||||
if (CancelIoEx((HANDLE) state->sockfd, &state->overlapped))
|
||||
WSAWaitForMultipleEvents(1, &state->overlapped.hEvent, TRUE, 10, TRUE);
|
||||
WSACloseEvent(state->overlapped.hEvent);
|
||||
closesocket(state->sockfd);
|
||||
ffStrbufDestroy(&state->command);
|
||||
@@ -279,6 +287,12 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
// Not a critical error, continue anyway
|
||||
}
|
||||
|
||||
if (shutdown(state->sockfd, SD_SEND) == SOCKET_ERROR)
|
||||
{
|
||||
FF_DEBUG("Failed to shutdown socket send: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
// Not a critical error, continue anyway
|
||||
}
|
||||
|
||||
if(timeout > 0)
|
||||
{
|
||||
FF_DEBUG("Setting receive timeout: %u ms", timeout);
|
||||
@@ -302,10 +316,14 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
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);
|
||||
DWORD received = 0, recvFlags = 0;
|
||||
int recvResult = WSARecv(state->sockfd, &(WSABUF) {
|
||||
.buf = buffer->chars + buffer->length,
|
||||
.len = (ULONG) ffStrbufGetFree(buffer),
|
||||
}, 1, &received, &recvFlags, NULL, NULL);
|
||||
|
||||
if (received <= 0) {
|
||||
if (received == 0) {
|
||||
if (recvResult == SOCKET_ERROR || received == 0) {
|
||||
if (recvResult == 0 && received == 0) {
|
||||
FF_DEBUG("Connection closed (received=0)");
|
||||
} else {
|
||||
FF_DEBUG("Reception failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
@@ -316,7 +334,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
buffer->length += (uint32_t) received;
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
|
||||
FF_DEBUG("Successfully received %zd bytes of data, total: %u bytes", received, buffer->length);
|
||||
FF_DEBUG("Successfully received %u bytes of data, total: %u bytes", (unsigned) received, buffer->length);
|
||||
|
||||
// Check if HTTP header end marker is found
|
||||
if (headerEnd == 0) {
|
||||
|
||||
+260
-1
@@ -1,6 +1,6 @@
|
||||
#include "common/path.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/arrayUtils.h"
|
||||
|
||||
#if !_WIN32
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
|
||||
@@ -49,6 +49,9 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
|
||||
}
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include <errno.h>
|
||||
#include <stdalign.h>
|
||||
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
|
||||
{
|
||||
@@ -62,4 +65,260 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
|
||||
ffStrbufSetS(result, buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int winerr2Errno(DWORD err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
case ERROR_INVALID_NAME:
|
||||
return ENOENT;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
return EACCES;
|
||||
case ERROR_BUFFER_OVERFLOW:
|
||||
case ERROR_INSUFFICIENT_BUFFER:
|
||||
return ENAMETOOLONG;
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
case ERROR_NOT_A_REPARSE_POINT:
|
||||
return EINVAL;
|
||||
default:
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
char* frealpath(HANDLE hFile, char* resolved_name)
|
||||
{
|
||||
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !hFile, false))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t resolvedNameW[MAX_PATH + 4]; /* +4 for "\\\\?\\" prefix */
|
||||
DWORD lenW = GetFinalPathNameByHandleW(hFile, resolvedNameW, (DWORD)ARRAY_SIZE(resolvedNameW), FILE_NAME_NORMALIZED);
|
||||
|
||||
if (lenW == 0)
|
||||
{
|
||||
errno = winerr2Errno(GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
if (lenW >= ARRAY_SIZE(resolvedNameW))
|
||||
{
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
lenW++; // Include null terminator
|
||||
|
||||
wchar_t* srcW = resolvedNameW;
|
||||
DWORD srcLenW = lenW;
|
||||
|
||||
if (srcLenW >= 8 && wcsncmp(resolvedNameW, L"\\\\?\\UNC\\", 8) == 0)
|
||||
{
|
||||
/* Convert "\\?\UNC\server\share" to "\\server\share" */
|
||||
srcW += 6;
|
||||
srcLenW -= 6;
|
||||
*srcW = L'\\';
|
||||
}
|
||||
else if (srcLenW >= 4 && wcsncmp(resolvedNameW, L"\\\\?\\", 4) == 0)
|
||||
{
|
||||
srcW += 4;
|
||||
srcLenW -= 4;
|
||||
}
|
||||
|
||||
if (resolved_name)
|
||||
{
|
||||
ULONG outBytes = 0;
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(resolved_name, MAX_PATH, &outBytes, srcW, (ULONG)(srcLenW * sizeof(wchar_t)))))
|
||||
{
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (outBytes > MAX_PATH)
|
||||
{
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return resolved_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* UTF-8 worst-case: up to 4 bytes per UTF-16 code unit */
|
||||
char tmp[(MAX_PATH + 4) * 4];
|
||||
ULONG outBytes = 0;
|
||||
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(tmp, (ULONG)sizeof(tmp), &outBytes, srcW, (ULONG)(srcLenW * sizeof(wchar_t)))))
|
||||
{
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resolved_name = (char*)malloc(outBytes);
|
||||
if (!resolved_name)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(resolved_name, tmp, outBytes);
|
||||
return resolved_name;
|
||||
}
|
||||
|
||||
return resolved_name;
|
||||
}
|
||||
|
||||
char* realpath(const char* __restrict file_name, char* __restrict resolved_name)
|
||||
{
|
||||
if (!file_name)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t fileNameW[MAX_PATH];
|
||||
ULONG lenBytes = 0;
|
||||
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG)sizeof(fileNameW), &lenBytes, file_name, (ULONG)strlen(file_name) + 1)))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileW(
|
||||
fileNameW,
|
||||
0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = winerr2Errno(GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return frealpath(hFile, resolved_name);
|
||||
}
|
||||
|
||||
ssize_t freadlink(HANDLE hFile, char* buf, size_t bufsiz)
|
||||
{
|
||||
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !buf || bufsiz == 0, false))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
alignas(REPARSE_DATA_BUFFER) BYTE reparseBuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||
DWORD bytesReturned = 0;
|
||||
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseBuf, (DWORD) sizeof(reparseBuf), &bytesReturned, NULL))
|
||||
{
|
||||
errno = winerr2Errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
REPARSE_DATA_BUFFER* rp = (REPARSE_DATA_BUFFER*) reparseBuf;
|
||||
const wchar_t* targetW = NULL;
|
||||
USHORT targetBytes = 0;
|
||||
|
||||
if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
|
||||
{
|
||||
if (rp->SymbolicLinkReparseBuffer.PrintNameLength > 0)
|
||||
{
|
||||
targetW = rp->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
(rp->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t));
|
||||
targetBytes = rp->SymbolicLinkReparseBuffer.PrintNameLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetW = rp->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
(rp->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
|
||||
targetBytes = rp->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||
|
||||
if (targetBytes >= 8 &&
|
||||
wcsncmp(targetW, L"\\??\\", 4) == 0)
|
||||
{
|
||||
targetW += 4;
|
||||
targetBytes -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
|
||||
{
|
||||
if (rp->MountPointReparseBuffer.PrintNameLength > 0)
|
||||
{
|
||||
targetW = rp->MountPointReparseBuffer.PathBuffer +
|
||||
(rp->MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t));
|
||||
targetBytes = rp->MountPointReparseBuffer.PrintNameLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetW = rp->MountPointReparseBuffer.PathBuffer +
|
||||
(rp->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
|
||||
targetBytes = rp->MountPointReparseBuffer.SubstituteNameLength;
|
||||
|
||||
if (targetBytes >= 8 &&
|
||||
wcsncmp(targetW, L"\\??\\", 4) == 0)
|
||||
{
|
||||
targetW += 4;
|
||||
targetBytes -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ULONG outBytes = 0;
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(buf, (ULONG) bufsiz, &outBytes, targetW, targetBytes)))
|
||||
{
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Not null-terminated
|
||||
return (ssize_t) outBytes;
|
||||
}
|
||||
|
||||
ssize_t readlink(const char* path, char* buf, size_t bufsiz)
|
||||
{
|
||||
if (!path || !buf || bufsiz == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
wchar_t pathW[MAX_PATH];
|
||||
ULONG pathWBytes = 0;
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathW, (ULONG) sizeof(pathW), &pathWBytes, path, (ULONG) strlen(path) + 1)))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileW(
|
||||
pathW,
|
||||
0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = winerr2Errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return freadlink(hFile, buf, bufsiz);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -261,6 +261,8 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha
|
||||
|
||||
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config)
|
||||
{
|
||||
assert(key);
|
||||
|
||||
if (!unsafe_yyjson_equals_str(key, "percent"))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
|
||||
FF_PARSE_FORMAT_STRING_CHECKED(&key, &moduleArgs->key, ((FFformatarg[]) {
|
||||
FF_FORMAT_ARG(moduleIndex, "index"),
|
||||
FF_FORMAT_ARG(moduleArgs->keyIcon, "icon"),
|
||||
FF_ARG(moduleIndex, "index"),
|
||||
FF_ARG(moduleArgs->keyIcon, "icon"),
|
||||
}));
|
||||
ffStrbufWriteTo(&key, stdout);
|
||||
}
|
||||
|
||||
@@ -128,6 +128,8 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
{
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
if (ret == ENOENT)
|
||||
return "command not found";
|
||||
return "posix_spawnp() failed";
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/processing.h"
|
||||
#include "common/io.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#include <stdalign.h>
|
||||
#include <windows.h>
|
||||
#include <ntstatus.h>
|
||||
#include <winternl.h>
|
||||
|
||||
enum { FF_PIPE_BUFSIZ = 8192 };
|
||||
|
||||
@@ -51,7 +54,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
|
||||
wchar_t pipeName[32];
|
||||
static unsigned pidCounter = 0;
|
||||
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", GetCurrentProcessId(), ++pidCounter);
|
||||
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", instance.state.platform.pid, ++pidCounter);
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = CreateNamedPipeW(
|
||||
pipeName,
|
||||
@@ -83,7 +86,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
|
||||
|
||||
PROCESS_INFORMATION piProcInfo = {};
|
||||
STARTUPINFOA siStartInfo = {
|
||||
STARTUPINFOW siStartInfo = {
|
||||
.cb = sizeof(siStartInfo),
|
||||
.dwFlags = STARTF_USESTDHANDLES,
|
||||
};
|
||||
@@ -98,12 +101,19 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
siStartInfo.hStdError = ffGetNullFD();
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
|
||||
argvToCmdline(argv, &cmdline);
|
||||
FF_AUTO_FREE wchar_t* cmdline = NULL;
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
|
||||
argvToCmdline(argv, &buf);
|
||||
uint32_t cmdlineBytes = (buf.length + 1) * sizeof(wchar_t);
|
||||
cmdline = malloc(cmdlineBytes);
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(cmdline, cmdlineBytes, NULL, buf.chars, buf.length + 1)))
|
||||
return "RtlUTF8ToUnicodeN() failed";
|
||||
}
|
||||
|
||||
BOOL success = CreateProcessA(
|
||||
BOOL success = CreateProcessW(
|
||||
NULL, // application name
|
||||
cmdline.chars, // command line
|
||||
cmdline, // command line
|
||||
NULL, // process security attributes
|
||||
NULL, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
@@ -114,15 +124,15 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
&piProcInfo // receives PROCESS_INFORMATION
|
||||
);
|
||||
|
||||
CloseHandle(hChildPipeWrite);
|
||||
NtClose(hChildPipeWrite);
|
||||
if(!success)
|
||||
{
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
return "command not found";
|
||||
return "CreateProcessA() failed";
|
||||
return "CreateProcessW() failed";
|
||||
}
|
||||
|
||||
CloseHandle(piProcInfo.hThread); // we don't need the thread handle
|
||||
NtClose(piProcInfo.hThread); // we don't need the thread handle
|
||||
outHandle->pid = piProcInfo.hProcess;
|
||||
outHandle->pipeRead = hChildPipeRead;
|
||||
hChildPipeRead = INVALID_HANDLE_VALUE; // ownership transferred, don't close it
|
||||
@@ -130,6 +140,17 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void terminateChildProcess(HANDLE hProcess, HANDLE hChildPipeRead, HANDLE hReadEvent, IO_STATUS_BLOCK* piosb)
|
||||
{
|
||||
IO_STATUS_BLOCK cancelIosb = {};
|
||||
if (NT_SUCCESS(NtCancelIoFileEx(hChildPipeRead, piosb, &cancelIosb)))
|
||||
{
|
||||
if (hReadEvent)
|
||||
NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) { .QuadPart = -100000 }); // wait for cancellation to complete
|
||||
}
|
||||
NtTerminateProcess(hProcess, 1);
|
||||
}
|
||||
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
{
|
||||
assert(handle->pipeRead != INVALID_HANDLE_VALUE);
|
||||
@@ -138,64 +159,74 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
int32_t timeout = instance.config.general.processingTimeout;
|
||||
FF_AUTO_CLOSE_FD HANDLE hProcess = handle->pid;
|
||||
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = handle->pipeRead;
|
||||
FF_AUTO_CLOSE_FD HANDLE hReadEvent = NULL;
|
||||
handle->pid = INVALID_HANDLE_VALUE;
|
||||
handle->pipeRead = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (timeout >= 0 && !NT_SUCCESS(NtCreateEvent(&hReadEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)))
|
||||
return "NtCreateEvent() failed";
|
||||
|
||||
char str[FF_PIPE_BUFSIZ];
|
||||
DWORD nRead = 0;
|
||||
OVERLAPPED overlapped = {};
|
||||
// ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED
|
||||
uint32_t nRead = 0;
|
||||
IO_STATUS_BLOCK iosb = {};
|
||||
do
|
||||
{
|
||||
if (!ReadFile(hChildPipeRead, str, sizeof(str), &nRead, &overlapped))
|
||||
NTSTATUS status = NtReadFile(
|
||||
hChildPipeRead,
|
||||
hReadEvent,
|
||||
NULL,
|
||||
NULL,
|
||||
&iosb,
|
||||
str,
|
||||
(ULONG) sizeof(str),
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (status == STATUS_PENDING)
|
||||
{
|
||||
switch (GetLastError())
|
||||
switch (NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 }))
|
||||
{
|
||||
case ERROR_IO_PENDING:
|
||||
#if !FF_WIN7_COMPAT
|
||||
if (!GetOverlappedResultEx(hChildPipeRead, &overlapped, &nRead, timeout < 0 ? INFINITE : (DWORD) timeout, FALSE))
|
||||
#else
|
||||
// To support Windows 7
|
||||
if (timeout >= 0 && WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
|
||||
{
|
||||
CancelIo(hChildPipeRead);
|
||||
TerminateProcess(hProcess, 1);
|
||||
return "WaitForSingleObject(hChildPipeRead) failed or timeout (try increasing --processing-timeout)";
|
||||
}
|
||||
|
||||
if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE))
|
||||
#endif
|
||||
{
|
||||
if (GetLastError() == ERROR_BROKEN_PIPE)
|
||||
return NULL;
|
||||
|
||||
CancelIo(hChildPipeRead);
|
||||
TerminateProcess(hProcess, 1);
|
||||
return "GetOverlappedResult"
|
||||
#if !FF_WIN7_COMPAT
|
||||
"Ex"
|
||||
#endif
|
||||
"(hChildPipeRead) failed";
|
||||
}
|
||||
case STATUS_WAIT_0:
|
||||
status = iosb.Status;
|
||||
break;
|
||||
|
||||
case ERROR_BROKEN_PIPE:
|
||||
goto exit;
|
||||
case STATUS_TIMEOUT:
|
||||
{
|
||||
terminateChildProcess(hProcess, hChildPipeRead, hReadEvent, &iosb);
|
||||
return "NtReadFile(hChildPipeRead) timed out";
|
||||
}
|
||||
|
||||
default:
|
||||
CancelIo(hChildPipeRead);
|
||||
TerminateProcess(hProcess, 1);
|
||||
return "ReadFile(hChildPipeRead) failed";
|
||||
terminateChildProcess(hProcess, hChildPipeRead, hReadEvent, &iosb);
|
||||
return "NtWaitForSingleObject(hReadEvent) failed";
|
||||
}
|
||||
}
|
||||
|
||||
if (status == STATUS_PIPE_BROKEN || status == STATUS_END_OF_FILE)
|
||||
goto exit;
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
terminateChildProcess(hProcess, hChildPipeRead, NULL, &iosb);
|
||||
return "NtReadFile(hChildPipeRead) failed";
|
||||
}
|
||||
|
||||
nRead = (uint32_t) iosb.Information;
|
||||
ffStrbufAppendNS(buffer, nRead, str);
|
||||
} while (nRead > 0);
|
||||
|
||||
exit:
|
||||
{
|
||||
DWORD exitCode = 0;
|
||||
if (GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE && exitCode != 0)
|
||||
return "Child process exited with an error";
|
||||
PROCESS_BASIC_INFORMATION info = {};
|
||||
ULONG size;
|
||||
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size)))
|
||||
{
|
||||
assert(size == sizeof(info));
|
||||
if (info.ExitStatus != STILL_ACTIVE && info.ExitStatus != 0)
|
||||
return "Child process exited with an error";
|
||||
}
|
||||
else
|
||||
return "NtQueryInformationProcess(ProcessBasicInformation) failed";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -203,15 +234,14 @@ exit:
|
||||
|
||||
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD HANDLE hProcess = pid == 0
|
||||
? GetCurrentProcess()
|
||||
: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
||||
|
||||
if (hProcess == NULL)
|
||||
return false;
|
||||
|
||||
if (gui)
|
||||
*gui = GetGuiResources(hProcess, GR_GDIOBJECTS) > 0;
|
||||
FF_AUTO_CLOSE_FD HANDLE hProcess = NtCurrentProcess();
|
||||
if(pid != 0)
|
||||
{
|
||||
if (!NT_SUCCESS(NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION, &(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
}, &(CLIENT_ID) { .UniqueProcess = (HANDLE)(uintptr_t) pid })))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ppid)
|
||||
{
|
||||
@@ -225,23 +255,41 @@ bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFst
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if(exe)
|
||||
{
|
||||
DWORD bufSize = exe->allocated;
|
||||
if(QueryFullProcessImageNameA(hProcess, 0, exe->chars, &bufSize))
|
||||
// TODO: It's possible to query the command line with `NtQueryInformationProcess(60/*ProcessCommandLineInformation*/)` since Windows 8.1
|
||||
|
||||
alignas(UNICODE_STRING) uint8_t buffer[4096];
|
||||
ULONG size;
|
||||
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, &buffer, sizeof(buffer), &size)))
|
||||
{
|
||||
// We use full path here
|
||||
// Querying command line of remote processes in Windows requires either WMI or ReadProcessMemory
|
||||
exe->length = bufSize;
|
||||
UNICODE_STRING* imagePath = (UNICODE_STRING*)buffer;
|
||||
ffStrbufSetNWS(exe, imagePath->Length / sizeof(wchar_t), imagePath->Buffer);
|
||||
|
||||
if (exePath) ffStrbufSet(exePath, exe);
|
||||
|
||||
if (pname && exeName)
|
||||
{
|
||||
*exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1;
|
||||
ffStrbufSetS(pname, *exeName);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
if(pname && exeName)
|
||||
|
||||
if (gui)
|
||||
{
|
||||
*exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1;
|
||||
ffStrbufSetS(pname, *exeName);
|
||||
SECTION_IMAGE_INFORMATION info = {};
|
||||
ULONG size;
|
||||
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageInformation, &info, sizeof(info), &size)))
|
||||
{
|
||||
assert(size == sizeof(info));
|
||||
*gui = info.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -201,7 +201,7 @@ FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaNa
|
||||
|
||||
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
|
||||
{
|
||||
FFDBusData dbus;
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
|
||||
return FF_VARIANT_NULL;
|
||||
|
||||
@@ -260,7 +260,7 @@ FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName,
|
||||
|
||||
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
|
||||
{
|
||||
FFDBusData dbus;
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
|
||||
return FF_VARIANT_NULL;
|
||||
|
||||
|
||||
+205
-70
@@ -18,6 +18,7 @@ bool ffIsSmbiosValueSet(FFstrbuf* value)
|
||||
!ffStrbufIgnCaseEqualS(value, "None") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "System Name") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "System Version") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "System SKU#") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "Default string") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "Undefined") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "Not Specified") &&
|
||||
@@ -32,11 +33,29 @@ bool ffIsSmbiosValueSet(FFstrbuf* value)
|
||||
!ffStrbufIgnCaseEqualS(value, "All Series") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "N/A") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "Unknown") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "Standard") &&
|
||||
!ffStrbufIgnCaseEqualS(value, "0x0000")
|
||||
!ffStrbufIgnCaseEqualS(value, "Standard") && ({
|
||||
// Some SMBIOS implementations use "0x0000" to indicate an unset value, even for strings.
|
||||
bool zero = ffStrbufStartsWithS(value, "0x0");
|
||||
if (zero)
|
||||
{
|
||||
for (size_t i = 2; i < value->length; i++)
|
||||
{
|
||||
char c = value->chars[i];
|
||||
if (c != '0')
|
||||
{
|
||||
zero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
!zero;
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
static bool smbiosTableInitialized = false;
|
||||
static FFSmbiosHeaderTable smbiosTable;
|
||||
|
||||
const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header)
|
||||
{
|
||||
const char* p = ((const char*) header) + header->Length;
|
||||
@@ -52,6 +71,74 @@ const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header)
|
||||
return (const FFSmbiosHeader*) (p + 1);
|
||||
}
|
||||
|
||||
static bool parseSmbiosTable(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
const FFSmbiosHeader* endOfTable = NULL;
|
||||
|
||||
FF_DEBUG("Parsing SMBIOS table structures with length %u bytes", length);
|
||||
FF_MAYBE_UNUSED int structureCount = 0, totalCount = 0;
|
||||
for (
|
||||
const FFSmbiosHeader* header = (const FFSmbiosHeader*) data;
|
||||
(const uint8_t*) header + sizeof(FFSmbiosHeader) < (const uint8_t*) data + length;
|
||||
header = ffSmbiosNextEntry(header)
|
||||
)
|
||||
{
|
||||
++totalCount;
|
||||
endOfTable = header;
|
||||
|
||||
// This doesn't verify the entire structure (e.g. string section can still be truncated),
|
||||
// but at least ensures the formatted section is valid and prevents infinite loops
|
||||
// when the table is severely malformed.
|
||||
if (__builtin_expect((const uint8_t*) header + header->Length > (const uint8_t*) data + length, false))
|
||||
{
|
||||
FF_DEBUG("Truncated SMBIOS structure at offset 0x%lx: length %u is too small",
|
||||
(unsigned long)((const uint8_t*) header - data), header->Length);
|
||||
break;
|
||||
}
|
||||
|
||||
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
|
||||
{
|
||||
if (!smbiosTable[header->Type])
|
||||
{
|
||||
smbiosTable[header->Type] = header;
|
||||
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
|
||||
header->Type, header->Handle, header->Length);
|
||||
structureCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Duplicate SMBIOS structure type %u, handle 0x%04X, length %u",
|
||||
header->Type, header->Handle, header->Length);
|
||||
}
|
||||
}
|
||||
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE)
|
||||
{
|
||||
FF_DEBUG("Reached SMBIOS end of type %u, handle 0x%04X, length %u",
|
||||
header->Type, header->Handle, header->Length);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Found custom SMBIOS structure type %u, handle 0x%04X, length %u; ignoring",
|
||||
header->Type, header->Handle, header->Length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!endOfTable)
|
||||
{
|
||||
FF_DEBUG("No SMBIOS structures found in table");
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_DEBUG("Parsed %d/%d SMBIOS structures, end-of-table (Type 127) %s",
|
||||
structureCount,
|
||||
totalCount,
|
||||
endOfTable->Type == FF_SMBIOS_TYPE_END_OF_TABLE ? "found." : "not found! SMBIOS data may be malformed.");
|
||||
smbiosTable[FF_SMBIOS_TYPE_END_OF_TABLE] = endOfTable;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__) || defined(__OpenBSD__) || defined(__GNU__)
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -71,17 +158,30 @@ const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header)
|
||||
#define loff_t off_t
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
|
||||
{
|
||||
if (ffReadFileBuffer(devicesPath, buffer))
|
||||
// /sys/class/dmi/id/* are all pseudo-files with very small content
|
||||
// so reading the whole file at once is efficient
|
||||
ffStrbufEnsureFixedLengthFree(buffer, 127);
|
||||
|
||||
ssize_t len = ffReadFileData(devicesPath, buffer->allocated - 1, buffer->chars);
|
||||
if (len > 0)
|
||||
{
|
||||
assert(len < buffer->allocated);
|
||||
buffer->chars[len] = '\0';
|
||||
buffer->length = (uint32_t) len;
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ffReadFileBuffer(classPath, buffer))
|
||||
len = ffReadFileData(classPath, buffer->allocated - 1, buffer->chars);
|
||||
if (len > 0)
|
||||
{
|
||||
assert(len < buffer->allocated);
|
||||
buffer->chars[len] = '\0';
|
||||
buffer->length = (uint32_t) len;
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
return true;
|
||||
@@ -90,6 +190,7 @@ bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf*
|
||||
ffStrbufClear(buffer);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct FFSmbios20EntryPoint
|
||||
{
|
||||
@@ -109,7 +210,7 @@ typedef struct FFSmbios20EntryPoint
|
||||
uint8_t SmbiosBcdRevision;
|
||||
} __attribute__((__packed__)) FFSmbios20EntryPoint;
|
||||
static_assert(offsetof(FFSmbios20EntryPoint, SmbiosBcdRevision) == 0x1E,
|
||||
"FFSmbios30EntryPoint: Wrong struct alignment");
|
||||
"FFSmbios20EntryPoint: Wrong struct alignment");
|
||||
|
||||
typedef struct FFSmbios30EntryPoint
|
||||
{
|
||||
@@ -137,10 +238,10 @@ typedef union FFSmbiosEntryPoint
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
{
|
||||
static FFstrbuf buffer;
|
||||
static FFSmbiosHeaderTable table;
|
||||
|
||||
if (buffer.chars == NULL)
|
||||
if (!smbiosTableInitialized)
|
||||
{
|
||||
smbiosTableInitialized = true;
|
||||
FF_DEBUG("Initializing SMBIOS buffer");
|
||||
ffStrbufInit(&buffer);
|
||||
#if !__HAIKU__ && !__OpenBSD__ && !__DragonFly__ && !__GNU__
|
||||
@@ -401,29 +502,8 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
}
|
||||
#endif
|
||||
|
||||
FF_DEBUG("Parsing SMBIOS table structures");
|
||||
FF_MAYBE_UNUSED int structureCount = 0;
|
||||
for (
|
||||
const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer.chars;
|
||||
(const uint8_t*) header < (const uint8_t*) buffer.chars + buffer.length;
|
||||
header = ffSmbiosNextEntry(header)
|
||||
)
|
||||
{
|
||||
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
|
||||
{
|
||||
if (!table[header->Type]) {
|
||||
table[header->Type] = header;
|
||||
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
|
||||
header->Type, header->Handle, header->Length);
|
||||
structureCount++;
|
||||
}
|
||||
}
|
||||
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
|
||||
FF_DEBUG("Reached end-of-table marker");
|
||||
break;
|
||||
}
|
||||
}
|
||||
FF_DEBUG("Parsed %d SMBIOS structures", structureCount);
|
||||
if (!parseSmbiosTable((const uint8_t*) buffer.chars, buffer.length))
|
||||
ffStrbufClear(&buffer);
|
||||
}
|
||||
|
||||
if (buffer.length == 0) {
|
||||
@@ -431,10 +511,10 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &table;
|
||||
return &smbiosTable;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmultichar"
|
||||
|
||||
@@ -450,56 +530,111 @@ typedef struct FFRawSmbiosData
|
||||
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
{
|
||||
static FFRawSmbiosData* buffer;
|
||||
static FFSmbiosHeaderTable table;
|
||||
static SYSTEM_FIRMWARE_TABLE_INFORMATION* buffer;
|
||||
|
||||
if (!buffer)
|
||||
if (!smbiosTableInitialized)
|
||||
{
|
||||
smbiosTableInitialized = true;
|
||||
FF_DEBUG("Initializing Windows SMBIOS buffer");
|
||||
const DWORD signature = 'RSMB';
|
||||
|
||||
FF_DEBUG("Querying system firmware table size with signature 'RSMB'");
|
||||
uint32_t bufSize = GetSystemFirmwareTable(signature, 0, NULL, 0);
|
||||
if (bufSize <= sizeof(FFRawSmbiosData)) {
|
||||
FF_DEBUG("Invalid firmware table size: %u (must be > %zu)",
|
||||
bufSize, sizeof(FFRawSmbiosData));
|
||||
SYSTEM_FIRMWARE_TABLE_INFORMATION sfti = {
|
||||
.ProviderSignature = 'RSMB',
|
||||
.Action = SystemFirmwareTableGet,
|
||||
};
|
||||
ULONG bufSize = 0;
|
||||
NtQuerySystemInformation(SystemFirmwareTableInformation, &sfti, sizeof(sfti), &bufSize);
|
||||
if (bufSize <= sizeof(FFRawSmbiosData) + sizeof(sfti)) {
|
||||
FF_DEBUG("Invalid firmware table size: %lu (must be > %zu)", bufSize, sizeof(FFRawSmbiosData) + sizeof(sfti));
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Firmware table size: %u bytes", bufSize);
|
||||
if (bufSize != sfti.TableBufferLength + (ULONG) sizeof(sfti)) {
|
||||
FF_DEBUG("Firmware table size mismatch: NtQuerySystemInformation returned %lu but expected %lu",
|
||||
bufSize, sfti.TableBufferLength + (ULONG) sizeof(sfti));
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Firmware table size: %lu bytes", bufSize);
|
||||
|
||||
buffer = (FFRawSmbiosData*) malloc(bufSize);
|
||||
assert(buffer);
|
||||
buffer = malloc(bufSize);
|
||||
*buffer = sfti;
|
||||
FF_DEBUG("Allocated buffer for SMBIOS data");
|
||||
|
||||
FF_MAYBE_UNUSED uint32_t resultSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize);
|
||||
assert(resultSize == bufSize);
|
||||
FF_DEBUG("Successfully retrieved SMBIOS data: version %u.%u, length %u bytes",
|
||||
buffer->SMBIOSMajorVersion, buffer->SMBIOSMinorVersion, buffer->Length);
|
||||
|
||||
FF_DEBUG("Parsing SMBIOS table structures");
|
||||
FF_MAYBE_UNUSED int structureCount = 0;
|
||||
for (
|
||||
const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer->SMBIOSTableData;
|
||||
(const uint8_t*) header < buffer->SMBIOSTableData + buffer->Length;
|
||||
header = ffSmbiosNextEntry(header)
|
||||
)
|
||||
if (!NT_SUCCESS(NtQuerySystemInformation(SystemFirmwareTableInformation, buffer, bufSize, &bufSize)))
|
||||
{
|
||||
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
|
||||
{
|
||||
if (!table[header->Type]) {
|
||||
table[header->Type] = header;
|
||||
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
|
||||
header->Type, header->Handle, header->Length);
|
||||
structureCount++;
|
||||
}
|
||||
}
|
||||
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
|
||||
FF_DEBUG("Reached end-of-table marker");
|
||||
break;
|
||||
}
|
||||
FF_DEBUG("NtQuerySystemInformation(SystemFirmwareTableInformation) failed");
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
return NULL;
|
||||
}
|
||||
FFRawSmbiosData* rawData = (FFRawSmbiosData*) buffer->TableBuffer;
|
||||
|
||||
FF_DEBUG("Successfully retrieved SMBIOS data: version %u.%u, length %u bytes",
|
||||
rawData->SMBIOSMajorVersion, rawData->SMBIOSMinorVersion, rawData->Length);
|
||||
|
||||
if (!parseSmbiosTable(rawData->SMBIOSTableData, rawData->Length))
|
||||
{
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Parsed %d SMBIOS structures", structureCount);
|
||||
}
|
||||
|
||||
return &table;
|
||||
if (!buffer) {
|
||||
FF_DEBUG("No valid SMBIOS data available");
|
||||
return NULL;
|
||||
}
|
||||
return &smbiosTable;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include "common/apple/cf_helpers.h"
|
||||
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
{
|
||||
static CFDataRef smbiosDataBuffer;
|
||||
|
||||
if (!smbiosTableInitialized)
|
||||
{
|
||||
smbiosTableInitialized = true;
|
||||
FF_DEBUG("Initializing SMBIOS buffer on Apple platform");
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMBIOS"));
|
||||
|
||||
if (!registryEntry)
|
||||
{
|
||||
FF_DEBUG("IOServiceGetMatchingService() failed to find AppleSMBIOS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_DEBUG("AppleSMBIOS service found, retrieving SMBIOS data");
|
||||
smbiosDataBuffer = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("SMBIOS"), kCFAllocatorDefault, kNilOptions);
|
||||
if (!smbiosDataBuffer)
|
||||
{
|
||||
FF_DEBUG("IORegistryEntryCreateCFProperty() failed to get SMBIOS data");
|
||||
return NULL;
|
||||
}
|
||||
if (CFGetTypeID(smbiosDataBuffer) != CFDataGetTypeID())
|
||||
{
|
||||
FF_DEBUG("Unexpected SMBIOS data type: expected CFData");
|
||||
CFRelease(smbiosDataBuffer);
|
||||
smbiosDataBuffer = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_DEBUG("Successfully retrieved SMBIOS data: %lu bytes", CFDataGetLength(smbiosDataBuffer));
|
||||
if (!parseSmbiosTable((const uint8_t*) CFDataGetBytePtr(smbiosDataBuffer), (uint32_t) CFDataGetLength(smbiosDataBuffer)))
|
||||
{
|
||||
CFRelease(smbiosDataBuffer);
|
||||
smbiosDataBuffer = NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!smbiosDataBuffer)
|
||||
{
|
||||
FF_DEBUG("No valid SMBIOS data available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &smbiosTable;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -109,6 +109,8 @@ bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char*
|
||||
|
||||
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config)
|
||||
{
|
||||
assert(key);
|
||||
|
||||
if (!unsafe_yyjson_equals_str(key, "temp"))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs)
|
||||
static void ffTimeInitQpcMultiplier(void)
|
||||
{
|
||||
LARGE_INTEGER frequency;
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
RtlQueryPerformanceFrequency(&frequency);
|
||||
ffQpcMultiplier = 1000. / (double) frequency.QuadPart;
|
||||
}
|
||||
#endif
|
||||
|
||||
+102
-42
@@ -7,6 +7,7 @@
|
||||
#include <fileapi.h>
|
||||
#include <handleapi.h>
|
||||
#include <io.h>
|
||||
#include "common/windows/nt.h"
|
||||
typedef HANDLE FFNativeFD;
|
||||
#define FF_INVALID_FD INVALID_HANDLE_VALUE
|
||||
#else
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
typedef int FFNativeFD;
|
||||
#define FF_INVALID_FD (-1)
|
||||
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
|
||||
@@ -22,6 +24,51 @@
|
||||
#define PROC_FILE_BUFFSIZ (32 * 1024)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
#ifndef O_RDONLY
|
||||
#define O_RDONLY 0
|
||||
#endif
|
||||
#ifndef O_DIRECTORY
|
||||
#define O_DIRECTORY 0200000
|
||||
#endif
|
||||
|
||||
// Only O_RDONLY is supported
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, int oflag);
|
||||
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory);
|
||||
#endif
|
||||
|
||||
|
||||
static inline bool ffIsValidNativeFD(FFNativeFD fd)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
return fd >= 0;
|
||||
#else
|
||||
// https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
|
||||
return fd != INVALID_HANDLE_VALUE && fd != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapClose(FFNativeFD* pfd)
|
||||
{
|
||||
assert(pfd);
|
||||
|
||||
if (!ffIsValidNativeFD(*pfd))
|
||||
return false;
|
||||
|
||||
#ifndef _WIN32
|
||||
close(*pfd);
|
||||
#else
|
||||
NtClose(*pfd);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
|
||||
|
||||
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
@@ -71,17 +118,60 @@ static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 3)
|
||||
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data);
|
||||
FF_C_NONNULL(2, 4)
|
||||
ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data);
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
|
||||
|
||||
FF_C_NONNULL(1, 3)
|
||||
static inline ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
FFNativeFD FF_AUTO_CLOSE_FD fd =
|
||||
#ifndef _WIN32
|
||||
open(fileName, O_RDONLY | O_CLOEXEC);
|
||||
#else
|
||||
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
#endif
|
||||
|
||||
if (!ffIsValidNativeFD(fd))
|
||||
return -1;
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2, 4)
|
||||
static inline ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
FFNativeFD FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
|
||||
if (!ffIsValidNativeFD(fd))
|
||||
return -1;
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer);
|
||||
static inline bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
FFNativeFD FF_AUTO_CLOSE_FD fd =
|
||||
#ifndef _WIN32
|
||||
open(fileName, O_RDONLY | O_CLOEXEC);
|
||||
#else
|
||||
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
#endif
|
||||
|
||||
if (!ffIsValidNativeFD(fd))
|
||||
return false;
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2, 3)
|
||||
bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer);
|
||||
static inline bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
FFNativeFD FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
|
||||
if (!ffIsValidNativeFD(fd))
|
||||
return false;
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
static inline bool ffReadFDBuffer(FFNativeFD fd, FFstrbuf* buffer)
|
||||
@@ -117,7 +207,11 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
DWORD attr = GetFileAttributesA(path);
|
||||
wchar_t wPath[MAX_PATH];
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(wPath, (ULONG) sizeof(wPath), NULL, path, (ULONG)strlen(path) + 1)))
|
||||
return false;
|
||||
|
||||
DWORD attr = GetFileAttributesW(wPath);
|
||||
|
||||
if(attr == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
@@ -178,34 +272,6 @@ static inline void ffUnsuppressIO(bool* suppressed)
|
||||
|
||||
void ffListFilesRecursively(const char* path, bool pretty);
|
||||
|
||||
static inline bool ffIsValidNativeFD(FFNativeFD fd)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
return fd >= 0;
|
||||
#else
|
||||
// https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
|
||||
return fd != INVALID_HANDLE_VALUE && fd != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapClose(FFNativeFD* pfd)
|
||||
{
|
||||
assert(pfd);
|
||||
|
||||
if (!ffIsValidNativeFD(*pfd))
|
||||
return false;
|
||||
|
||||
#ifndef _WIN32
|
||||
close(*pfd);
|
||||
#else
|
||||
CloseHandle(*pfd);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapFclose(FILE** pfile)
|
||||
{
|
||||
@@ -257,9 +323,3 @@ static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char*
|
||||
|
||||
FFNativeFD ffGetNullFD(void);
|
||||
bool ffRemoveFile(const char* fileName);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Only O_RDONLY is supported
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, bool directory);
|
||||
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory);
|
||||
#endif
|
||||
|
||||
+17
-15
@@ -6,11 +6,10 @@
|
||||
#ifndef FF_DISABLE_DLOPEN
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <libloaderapi.h>
|
||||
#define FF_DLOPEN_FLAGS 0
|
||||
FF_C_NODISCARD static inline void* dlopen(const char* path, int mode) { FF_UNUSED(mode); return LoadLibraryA(path); }
|
||||
FF_C_NODISCARD static inline void* dlsym(void* handle, const char* symbol) { return (void*) GetProcAddress((HMODULE)handle, symbol); }
|
||||
static inline int dlclose(void* handle) { return !FreeLibrary((HMODULE)handle); }
|
||||
FF_C_NODISCARD void* dlopen(const char* path, int mode);
|
||||
FF_C_NODISCARD void* dlsym(void* handle, const char* symbol);
|
||||
int dlclose(void* handle);
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
@@ -30,6 +29,10 @@ static inline void ffLibraryUnload(void** handle)
|
||||
dlclose(*handle);
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
#define __auto_type auto
|
||||
#endif
|
||||
|
||||
#define FF_LIBRARY_SYMBOL(symbolName) \
|
||||
__typeof__(&symbolName) ff ## symbolName;
|
||||
|
||||
@@ -38,13 +41,8 @@ static inline void ffLibraryUnload(void** handle)
|
||||
if(libraryObjectName == NULL) \
|
||||
return returnValue;
|
||||
|
||||
#if _WIN32
|
||||
#define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
|
||||
FF_LIBRARY_LOAD(libraryObjectName, "LoadLibraryA(" libraryFileName ") failed", libraryFileName, maxVersion, ##__VA_ARGS__)
|
||||
#else
|
||||
#define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
|
||||
FF_LIBRARY_LOAD(libraryObjectName, "dlopen(" libraryFileName ") failed", libraryFileName, maxVersion, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
|
||||
symbolMapping = (__typeof__(&symbolName)) dlsym(library, #symbolName); \
|
||||
@@ -52,13 +50,13 @@ static inline void ffLibraryUnload(void** handle)
|
||||
return returnValue;
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
|
||||
__typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
|
||||
__auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
|
||||
__typeof__(&symbolName) ff ## symbolName = (__typeof__(&symbolName)) dlsym(library, #symbolName);
|
||||
__auto_type ff ## symbolName = (__typeof__(&symbolName)) dlsym(library, #symbolName);
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
|
||||
__typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
__auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff ## symbolName, symbolName, returnValue);
|
||||
@@ -88,13 +86,13 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...);
|
||||
symbolMapping = (__typeof__(&symbolName)) &symbolName;
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
|
||||
FF_MAYBE_UNUSED __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
|
||||
FF_MAYBE_UNUSED __auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
|
||||
FF_MAYBE_UNUSED __typeof__(&symbolName) ff ## symbolName = (__typeof__(&symbolName)) &symbolName;
|
||||
FF_MAYBE_UNUSED __auto_type ff ## symbolName = (__typeof__(&symbolName)) &symbolName;
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
|
||||
FF_MAYBE_UNUSED __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
FF_MAYBE_UNUSED __auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff ## symbolName, symbolName, returnValue);
|
||||
@@ -106,3 +104,7 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...);
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff ## symbolName, symbolName, returnValue);
|
||||
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
void* ffLibraryGetModule(const wchar_t* libraryFileName);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// `memrchr` is a GNU extension and may not be declared by system headers even when the symbol exists.
|
||||
// Declare it unconditionally; the build system provides a fallback implementation when missing.
|
||||
void* memrchr(const void* s, int c, size_t n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -13,3 +13,10 @@ static inline bool ffIsAbsolutePath(const char* path)
|
||||
return path[0] == '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
char* frealpath(void* __restrict hFile, char* __restrict resolved_name /*MAX_PATH*/);
|
||||
char* realpath(const char* __restrict file_name, char* __restrict resolved_name /*MAX_PATH*/);
|
||||
ssize_t freadlink(void* hFile, char* buf, size_t bufsiz);
|
||||
ssize_t readlink(const char* path, char* buf, size_t bufsiz);
|
||||
#endif
|
||||
|
||||
@@ -63,14 +63,22 @@ typedef enum __attribute__((__packed__)) FFSmbiosType // : uint8_t
|
||||
FF_SMBIOS_TYPE_STRING_PROPERTY = 46,
|
||||
FF_SMBIOS_TYPE_INACTIVE = 126,
|
||||
FF_SMBIOS_TYPE_END_OF_TABLE = 127,
|
||||
FF_SMBIOS_TYPE__MAX,
|
||||
// system- and OEM-specific information 128~256
|
||||
} FFSmbiosType;
|
||||
static_assert(sizeof(FFSmbiosType) == 1, "FFSmbiosType should be 1 byte");
|
||||
|
||||
typedef struct FFSmbiosHeader
|
||||
{
|
||||
// Type of SMBIOS structure. Do NOT test `Type == FF_SMBIOS_END_OF_TABLE` to determine the end of the table,
|
||||
// as malformed tables may be missing the end-of-table marker.
|
||||
// **Use FFSmbiosHeaderTable[FF_SMBIOS_TYPE_END_OF_TABLE] pointer instead.**
|
||||
FFSmbiosType Type;
|
||||
// Length of formatted section, excluding unformatted string section
|
||||
// Must be at least 4 (sizeof(FFSmbiosHeader)) to be valid
|
||||
uint8_t Length;
|
||||
// Unique handle, used to reference this structure from other structures.
|
||||
// Not guaranteed to be consistent across reboots or even multiple reads of the same table.
|
||||
uint16_t Handle;
|
||||
} __attribute__((__packed__)) FFSmbiosHeader;
|
||||
static_assert(sizeof(FFSmbiosHeader) == 4, "FFSmbiosHeader should be 4 bytes");
|
||||
@@ -84,7 +92,7 @@ static inline const char* ffSmbiosLocateString(const char* start, uint8_t index
|
||||
return start;
|
||||
}
|
||||
|
||||
typedef const FFSmbiosHeader* FFSmbiosHeaderTable[FF_SMBIOS_TYPE_END_OF_TABLE];
|
||||
typedef const FFSmbiosHeader* FFSmbiosHeaderTable[FF_SMBIOS_TYPE__MAX];
|
||||
|
||||
const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header);
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable();
|
||||
|
||||
@@ -80,6 +80,23 @@ static inline bool ffCharIsDigit(char c)
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
|
||||
static inline bool ffCharIsHexDigit(char c)
|
||||
{
|
||||
return ffCharIsDigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
|
||||
}
|
||||
|
||||
static inline int8_t ffHexCharToInt(char c)
|
||||
{
|
||||
if (ffCharIsDigit(c))
|
||||
return (int8_t) (c - '0');
|
||||
else if ('a' <= c && c <= 'f')
|
||||
return (int8_t) (c - 'a' + 10);
|
||||
else if ('A' <= c && c <= 'F')
|
||||
return (int8_t) (c - 'A' + 10);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copies at most (dstBufSiz - 1) bytes from src to dst; dst is always null-terminated
|
||||
static inline char* ffStrCopy(char* __restrict__ dst, const char* __restrict__ src, size_t dstBufSiz)
|
||||
{
|
||||
|
||||
+5
-5
@@ -4,7 +4,7 @@
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
#if defined(_WIN32)
|
||||
#include <handleapi.h>
|
||||
#include <winternl.h>
|
||||
#include <synchapi.h>
|
||||
#include <process.h>
|
||||
#include <processthreadsapi.h>
|
||||
@@ -18,16 +18,16 @@
|
||||
}
|
||||
#define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) static __stdcall unsigned fn ## ThreadMain (void* data) { fn((paramType)data); return 0; }
|
||||
#define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) static __stdcall unsigned fn ## ThreadMain () { fn(); return 0; }
|
||||
static inline void ffThreadDetach(FFThreadType thread) { CloseHandle(thread); }
|
||||
static inline void ffThreadDetach(FFThreadType thread) { NtClose(thread); }
|
||||
static inline bool ffThreadJoin(FFThreadType thread, uint32_t timeout)
|
||||
{
|
||||
if (WaitForSingleObject(thread, timeout == 0 ? (DWORD) -1 : timeout) != 0 /*WAIT_OBJECT_0*/)
|
||||
if (NtWaitForSingleObject(thread, FALSE, timeout == 0 ? NULL : &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 }) != STATUS_WAIT_0)
|
||||
{
|
||||
TerminateThread(thread, (DWORD) -1);
|
||||
CloseHandle(thread);
|
||||
NtClose(thread);
|
||||
return false;
|
||||
}
|
||||
CloseHandle(thread);
|
||||
NtClose(thread);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
|
||||
+14
-14
@@ -4,17 +4,9 @@
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#ifdef _WIN32
|
||||
#include <ntdef.h>
|
||||
#include <ntstatus.h>
|
||||
#include "common/windows/nt.h"
|
||||
#include <profileapi.h>
|
||||
#include <sysinfoapi.h>
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtDelayExecution(
|
||||
_In_ BOOLEAN Alertable,
|
||||
_In_ PLARGE_INTEGER DelayInterval);
|
||||
#elif defined(__HAIKU__)
|
||||
#include <OS.h>
|
||||
#endif
|
||||
@@ -26,7 +18,7 @@ static inline double ffTimeGetTick(void) //In msec
|
||||
#ifdef _WIN32
|
||||
extern double ffQpcMultiplier;
|
||||
LARGE_INTEGER start;
|
||||
QueryPerformanceCounter(&start);
|
||||
RtlQueryPerformanceCounter(&start);
|
||||
return (double) start.QuadPart * ffQpcMultiplier;
|
||||
#elif defined(__HAIKU__)
|
||||
return (double) system_time() / 1000.;
|
||||
@@ -37,12 +29,20 @@ static inline double ffTimeGetTick(void) //In msec
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
static inline uint64_t ffFileTimeToUnixMs(uint64_t value)
|
||||
{
|
||||
if (__builtin_expect(__builtin_usubll_overflow(value, 116444736000000000ull, &value), false))
|
||||
return 0;
|
||||
return value / 10000ull;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint64_t ffTimeGetNow(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
uint64_t timeNow;
|
||||
GetSystemTimeAsFileTime((FILETIME*) &timeNow);
|
||||
return (timeNow - 116444736000000000ull) / 10000ull;
|
||||
uint64_t timeNow = ffKSystemTimeToUInt64(&SharedUserData->SystemTime);
|
||||
return ffFileTimeToUnixMs((uint64_t) timeNow);
|
||||
#elif defined(__HAIKU__)
|
||||
return (uint64_t) real_time_clock_usecs() / 1000u;
|
||||
#else
|
||||
@@ -58,7 +58,7 @@ static inline bool ffTimeSleep(uint32_t msec)
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER interval;
|
||||
interval.QuadPart = -(int64_t) msec * 10000; // Relative time in 100-nanosecond intervals
|
||||
return NtDelayExecution(TRUE, &interval) == STATUS_SUCCESS;
|
||||
return NT_SUCCESS(NtDelayExecution(TRUE, &interval));
|
||||
#else
|
||||
return nanosleep(&(struct timespec){ msec / 1000, (long) (msec % 1000) * 1000000 }, NULL) == 0;
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,8 @@ static const char* doInitCom()
|
||||
return "CoInitializeEx() failed";
|
||||
|
||||
// Set general COM security levels
|
||||
if (FAILED(CoInitializeSecurity(
|
||||
|
||||
HRESULT hRes = CoInitializeSecurity(
|
||||
NULL,
|
||||
-1, // COM authentication
|
||||
NULL, // Authentication services
|
||||
@@ -27,7 +28,9 @@ static const char* doInitCom()
|
||||
NULL, // Authentication info
|
||||
EOAC_NONE, // Additional capabilities
|
||||
NULL // Reserved
|
||||
)))
|
||||
);
|
||||
|
||||
if (FAILED(hRes) && hRes != RPC_E_TOO_LATE /* Has been set by a random dll */)
|
||||
{
|
||||
CoUninitialize();
|
||||
return "CoInitializeSecurity() failed";
|
||||
|
||||
@@ -2,21 +2,16 @@
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!--This Id value indicates the application supports Windows 7 functionality-->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
<!--This Id value indicates the application supports Windows 8 functionality-->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!--This Id value indicates the application supports Windows 8.1 functionality-->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!--This Id value indicates the application supports Windows 10, 11 functionality-->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/><!-- 8.1 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/><!-- 10/11 -->
|
||||
</application>
|
||||
</compatibility>
|
||||
<assemblyIdentity type="win32" name="com.github.fastfetch" version="0.0.0.0"/>
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings>
|
||||
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
|
||||
<heapType xmlns="http://schemas.microsoft.com/SMI/2020/WindowsSettings">SegmentHeap</heapType>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
|
||||
+1357
-221
File diff suppressed because it is too large
Load Diff
+362
-111
@@ -1,17 +1,22 @@
|
||||
#include "registry.h"
|
||||
#include "unicode.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
static const char* hKey2Str(HKEY hKey)
|
||||
#include <stdalign.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
static HANDLE hRootKeys[8 /*(uintptr_t) HKEY_CURRENT_USER_LOCAL_SETTINGS - (uintptr_t) HKEY_CLASSES_ROOT + 1*/];
|
||||
|
||||
static const char* hKey2Str(HANDLE hRootKey)
|
||||
{
|
||||
#define HKEY_CASE(compareKey) if(hKey == compareKey) return #compareKey;
|
||||
#define HKEY_CASE(compareKey) if(hRootKey == hRootKeys[(uintptr_t)compareKey - (uintptr_t)HKEY_CLASSES_ROOT]) return #compareKey;
|
||||
HKEY_CASE(HKEY_CLASSES_ROOT)
|
||||
HKEY_CASE(HKEY_CURRENT_USER)
|
||||
HKEY_CASE(HKEY_LOCAL_MACHINE)
|
||||
HKEY_CASE(HKEY_USERS)
|
||||
HKEY_CASE(HKEY_PERFORMANCE_DATA)
|
||||
HKEY_CASE(HKEY_PERFORMANCE_TEXT)
|
||||
HKEY_CASE(HKEY_PERFORMANCE_NLSTEXT)
|
||||
HKEY_CASE(HKEY_CURRENT_CONFIG)
|
||||
HKEY_CASE(HKEY_DYN_DATA)
|
||||
HKEY_CASE(HKEY_CURRENT_USER_LOCAL_SETTINGS)
|
||||
@@ -20,152 +25,398 @@ static const char* hKey2Str(HKEY hKey)
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error)
|
||||
HANDLE ffRegGetRootKeyHandle(HKEY hKey)
|
||||
{
|
||||
if(RegOpenKeyExW(hKey, subKeyW, 0, KEY_READ, result) != ERROR_SUCCESS)
|
||||
assert(hKey);
|
||||
assert((uintptr_t) hKey >= (uintptr_t) HKEY_CLASSES_ROOT && (uintptr_t) hKey <= (uintptr_t) HKEY_CURRENT_USER_LOCAL_SETTINGS);
|
||||
|
||||
FF_DEBUG("Getting root key handle for HKEY %08llx", (uint64_t)(uintptr_t) hKey);
|
||||
|
||||
HANDLE result = hRootKeys[(uintptr_t) hKey - (uintptr_t) HKEY_CLASSES_ROOT];
|
||||
if (result)
|
||||
{
|
||||
if(error)
|
||||
FF_DEBUG("Found cached root key handle for %s -> %p", hKey2Str(result), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
switch ((uintptr_t) hKey)
|
||||
{
|
||||
case (uintptr_t) HKEY_CURRENT_USER: {
|
||||
NTSTATUS status = RtlOpenCurrentUser(KEY_READ, &result);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
FF_DEBUG("RtlOpenCurrentUser() failed: %s", ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case (uintptr_t) HKEY_LOCAL_MACHINE: {
|
||||
UNICODE_STRING path = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
|
||||
NTSTATUS status = NtOpenKey(&result, KEY_READ, &(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = NULL,
|
||||
.ObjectName = &path,
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
});
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
FF_DEBUG("NtOpenKey(%ls) failed: %s (0x%08lx)", path.Buffer, ffDebugNtStatus(status), status);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Unsupported
|
||||
FF_DEBUG("Unsupported root key: %p", hKey);
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
hRootKeys[(uintptr_t) hKey - (uintptr_t) HKEY_CLASSES_ROOT] = result;
|
||||
FF_DEBUG("Opened root key %s -> %p", hKey2Str(result), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error)
|
||||
{
|
||||
assert(hKey);
|
||||
assert(subKeyW);
|
||||
assert(result);
|
||||
|
||||
FF_DEBUG("Opening subkey %s\\%ls for read", hKey2Str(hKey), subKeyW);
|
||||
|
||||
USHORT subKeyLen = (USHORT) (wcslen(subKeyW) * sizeof(wchar_t));
|
||||
if (!NT_SUCCESS(NtOpenKey(result, KEY_READ, &(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = hKey,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Length = subKeyLen,
|
||||
.MaximumLength = subKeyLen + (USHORT) sizeof(wchar_t),
|
||||
.Buffer = (wchar_t*) subKeyW,
|
||||
},
|
||||
})))
|
||||
{
|
||||
FF_DEBUG("NtOpenKey(%s\\<subkey>) failed", hKey2Str(hKey));
|
||||
if (error)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY subKeyA = ffStrbufCreateWS(subKeyW);
|
||||
ffStrbufAppendF(error, "RegOpenKeyExW(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars);
|
||||
ffStrbufAppendF(error, "NtOpenKey(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Opened subkey under %s -> %p", hKey2Str(hKey), *result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error)
|
||||
static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const void* regData, ULONG regDataLen, FFstrbuf* error)
|
||||
{
|
||||
DWORD bufSize; //with tailing '\0'
|
||||
if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, NULL, &bufSize) != ERROR_SUCCESS)
|
||||
switch (arg->type)
|
||||
{
|
||||
if(error)
|
||||
case FF_ARG_TYPE_STRBUF:
|
||||
{
|
||||
if(!valueNameW)
|
||||
valueNameW = L"(default)";
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
|
||||
ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_SZ) failed", valueNameA.chars);
|
||||
if (regType != REG_SZ && regType != REG_EXPAND_SZ)
|
||||
goto type_mismatch;
|
||||
|
||||
FFstrbuf* strbuf = (FFstrbuf*) arg->value;
|
||||
uint32_t strLen = regDataLen / sizeof(wchar_t);
|
||||
if (strLen == 0)
|
||||
ffStrbufClear(strbuf);
|
||||
else
|
||||
{
|
||||
const wchar_t* ws = (const wchar_t*) regData;
|
||||
if (ws[strLen - 1] == L'\0')
|
||||
--strLen;
|
||||
ffStrbufSetNWS(strbuf, strLen, ws);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
assert(bufSize >= sizeof(wchar_t));
|
||||
wchar_t* FF_AUTO_FREE resultW = (wchar_t*)malloc(bufSize);
|
||||
if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, resultW, &bufSize) != ERROR_SUCCESS)
|
||||
{
|
||||
if(error)
|
||||
|
||||
case FF_ARG_TYPE_UINT:
|
||||
case FF_ARG_TYPE_UINT64:
|
||||
case FF_ARG_TYPE_UINT16:
|
||||
case FF_ARG_TYPE_UINT8:
|
||||
case FF_ARG_TYPE_BOOL:
|
||||
{
|
||||
if(!valueNameW)
|
||||
valueNameW = L"(default)";
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
|
||||
ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_REG_SZ) failed", valueNameA.chars);
|
||||
uint64_t value = 0;
|
||||
|
||||
if (regType == REG_DWORD)
|
||||
{
|
||||
if (regDataLen < sizeof(uint32_t))
|
||||
goto type_mismatch;
|
||||
value = *(uint32_t*) regData;
|
||||
}
|
||||
else if (regType == REG_QWORD)
|
||||
{
|
||||
if (regDataLen < sizeof(uint64_t))
|
||||
goto type_mismatch;
|
||||
value = *(uint64_t*) regData;
|
||||
}
|
||||
else
|
||||
goto type_mismatch;
|
||||
|
||||
if (arg->type == FF_ARG_TYPE_UINT) *(uint32_t*) arg->value = (uint32_t) value;
|
||||
else if (arg->type == FF_ARG_TYPE_UINT64) *(uint64_t*) arg->value = (uint64_t) value;
|
||||
else if (arg->type == FF_ARG_TYPE_UINT16) *(uint16_t*) arg->value = (uint16_t) value;
|
||||
else if (arg->type == FF_ARG_TYPE_UINT8) *(uint8_t*) arg->value = (uint8_t) value;
|
||||
else if (arg->type == FF_ARG_TYPE_BOOL) *(bool*) arg->value = value != 0;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
||||
case FF_ARG_TYPE_FLOAT:
|
||||
{
|
||||
if (regDataLen < sizeof(float))
|
||||
goto type_mismatch;
|
||||
*(float*) arg->value = *(float*) regData;
|
||||
break;
|
||||
}
|
||||
|
||||
case FF_ARG_TYPE_DOUBLE:
|
||||
{
|
||||
if (regDataLen < sizeof(double))
|
||||
goto type_mismatch;
|
||||
*(double*) arg->value = *(double*) regData;
|
||||
break;
|
||||
}
|
||||
|
||||
case FF_ARG_TYPE_LIST:
|
||||
{
|
||||
if (regType != REG_MULTI_SZ)
|
||||
goto type_mismatch;
|
||||
|
||||
FFlist* list = (FFlist*) arg->value;
|
||||
if (list->elementSize != sizeof(FFstrbuf))
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: expected list of strbuf for REG_MULTI_SZ", nameA.chars);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ffListClear(list);
|
||||
|
||||
for (
|
||||
const wchar_t* ptr = (const wchar_t*) regData;
|
||||
(const uint8_t*) ptr < (const uint8_t*) regData + regDataLen && *ptr;
|
||||
ptr++
|
||||
)
|
||||
{
|
||||
uint32_t strLen = (uint32_t) wcsnlen(ptr, regDataLen / sizeof(wchar_t) - (size_t) (ptr - (const wchar_t*) regData));
|
||||
ffStrbufInitNWS(FF_LIST_ADD(FFstrbuf, *list), strLen, ptr);
|
||||
ptr += strLen;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FF_ARG_TYPE_BUFFER:
|
||||
{
|
||||
if (regType != REG_BINARY)
|
||||
goto type_mismatch;
|
||||
|
||||
FFArgBuffer* buffer = (FFArgBuffer*) arg->value;
|
||||
if (buffer->length == 0)
|
||||
{
|
||||
buffer->data = malloc(regDataLen);
|
||||
}
|
||||
else if (buffer->length < regDataLen)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "ffRegReadValues(%s) buffer too small (%u): expected %u", nameA.chars, (unsigned) buffer->length, (unsigned) regDataLen);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
buffer->length = regDataLen;
|
||||
memcpy(buffer->data, regData, regDataLen);
|
||||
break;
|
||||
}
|
||||
|
||||
case FF_ARG_TYPE_INT: // Use UINT instead
|
||||
case FF_ARG_TYPE_STRING:
|
||||
case FF_ARG_TYPE_NULL:
|
||||
default:
|
||||
if (error)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "processRegValue(%s) unsupported FFArgType %u", nameA.chars, (unsigned) arg->type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ffStrbufSetNWS(result, (uint32_t) (bufSize / sizeof(*resultW) - 1), resultW);
|
||||
|
||||
return true;
|
||||
|
||||
type_mismatch:
|
||||
FF_DEBUG("ffRegReadValues(%ls) type mismatch: regType=%u, argType=%u, dataLen=%u",
|
||||
arg->name ?: L"(default)", (unsigned) regType, (unsigned) arg->type, (unsigned) regDataLen);
|
||||
if (error)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: regType=%u, argType=%u, dataLen=%u",
|
||||
nameA.chars, (unsigned) regType, (unsigned) arg->type, (unsigned) regDataLen);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t** result, uint32_t* length, FFstrbuf* error)
|
||||
bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error)
|
||||
{
|
||||
assert(result && length);
|
||||
DWORD bufSize = 0;
|
||||
LONG err = RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_BINARY, NULL, NULL, &bufSize);
|
||||
if(err != ERROR_SUCCESS || bufSize == 0)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
if(!valueNameW)
|
||||
valueNameW = L"(default)";
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
|
||||
ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_BINARY, NULL, NULL, &bufSize) failed", valueNameA.chars);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
UNICODE_STRING* valueNameU = &(UNICODE_STRING) {
|
||||
.Length = arg->name ? (USHORT) (wcslen(arg->name) * sizeof(wchar_t)) : 0 /*(default)*/,
|
||||
.MaximumLength = 0,
|
||||
.Buffer = (wchar_t*) arg->name,
|
||||
};
|
||||
|
||||
uint8_t* buf = (uint8_t*) malloc(bufSize);
|
||||
err = RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_BINARY, NULL, buf, &bufSize);
|
||||
if(err != ERROR_SUCCESS)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
if(!valueNameW)
|
||||
valueNameW = L"(default)";
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
|
||||
ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_BINARY, NULL, length) failed", valueNameA.chars);
|
||||
}
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
*result = buf;
|
||||
*length = bufSize;
|
||||
return true;
|
||||
}
|
||||
alignas(KEY_VALUE_PARTIAL_INFORMATION) uint8_t staticBuffer[128 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
|
||||
FF_AUTO_FREE uint8_t* dynamicBuffer = NULL;
|
||||
|
||||
bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error)
|
||||
{
|
||||
DWORD bufSize = sizeof(*result);
|
||||
if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_DWORD, NULL, result, &bufSize) != ERROR_SUCCESS)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
if(!valueNameW)
|
||||
valueNameW = L"(default)";
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
|
||||
ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_DWORD) failed", valueNameA.chars);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
KEY_VALUE_PARTIAL_INFORMATION* buffer = (KEY_VALUE_PARTIAL_INFORMATION*) &staticBuffer;
|
||||
DWORD bufSize = sizeof(staticBuffer);
|
||||
if (NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize)))
|
||||
goto process_value;
|
||||
|
||||
bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error)
|
||||
{
|
||||
DWORD bufSize = sizeof(*result);
|
||||
if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_QWORD, NULL, result, &bufSize) != ERROR_SUCCESS)
|
||||
{
|
||||
if(error)
|
||||
{
|
||||
if(!valueNameW)
|
||||
valueNameW = L"(default)";
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW);
|
||||
ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_QWORD) failed", valueNameA.chars);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error)
|
||||
{
|
||||
DWORD bufSize = 0;
|
||||
if(RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, &bufSize, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
||||
if (bufSize == 0)
|
||||
{
|
||||
FF_DEBUG("NtQueryValueKey(%p, %ls) failed (bufSize=0)", hKey, arg->name ?: L"(default)");
|
||||
if (error)
|
||||
ffStrbufAppendS(error, "RegQueryInfoKeyW(hKey) failed");
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "NtQueryValueKey(%p, %s) failed", hKey, valueNameA.chars);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
++bufSize;
|
||||
wchar_t* FF_AUTO_FREE resultW = (wchar_t*) malloc(bufSize * sizeof(*resultW));
|
||||
if(RegEnumKeyExW(hKey, index, resultW, &bufSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
||||
|
||||
dynamicBuffer = (uint8_t*) malloc(bufSize);
|
||||
buffer = (KEY_VALUE_PARTIAL_INFORMATION*) dynamicBuffer;
|
||||
|
||||
if (!NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize)))
|
||||
{
|
||||
FF_DEBUG("NtQueryValueKey(%p, %ls, buffer=%u) failed", hKey, arg->name ?: L"(default)", (unsigned) bufSize);
|
||||
if (error)
|
||||
ffStrbufAppendF(error, "RegEnumKeyExW(hKey, %u) failed", (unsigned) index);
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "NtQueryValueKey(%p, %s, buffer) failed", hKey, valueNameA.chars);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ffStrbufSetWS(result, resultW);
|
||||
return true;
|
||||
|
||||
process_value:
|
||||
FF_DEBUG("Read value from %p (%ls), type=%u, len=%u", hKey, arg->name ?: L"(default)", (unsigned) buffer->Type, (unsigned) buffer->DataLength);
|
||||
return processRegValue(arg, buffer->Type, buffer->Data, buffer->DataLength, error);
|
||||
}
|
||||
|
||||
bool ffRegGetNSubKeys(HKEY hKey, uint32_t* result, FFstrbuf* error)
|
||||
bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFstrbuf* error)
|
||||
{
|
||||
DWORD buffer;
|
||||
if(RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &buffer, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
||||
if (__builtin_expect(argc == 0, false))
|
||||
return true;
|
||||
|
||||
assert(argv);
|
||||
|
||||
FF_AUTO_FREE UNICODE_STRING* names = (UNICODE_STRING*) calloc(argc, sizeof(*names));
|
||||
FF_AUTO_FREE KEY_VALUE_ENTRY* entries = (KEY_VALUE_ENTRY*) calloc(argc, sizeof(*entries));
|
||||
|
||||
for (uint32_t i = 0; i < argc; ++i)
|
||||
{
|
||||
if (__builtin_expect(!argv[i].value, false))
|
||||
{
|
||||
FF_DEBUG("ffRegReadValues(argv[%u].value) is NULL", (unsigned) i);
|
||||
if (error) ffStrbufAppendF(error, "ffRegReadValues(argv[%u].pVar) is NULL", (unsigned) i);
|
||||
return false;
|
||||
}
|
||||
|
||||
names[i] = (UNICODE_STRING) {
|
||||
.Length = argv[i].name ? (USHORT) (wcslen(argv[i].name) * sizeof(wchar_t)) : 0 /*(default)*/,
|
||||
.MaximumLength = 0,
|
||||
.Buffer = (wchar_t*) argv[i].name,
|
||||
};
|
||||
entries[i].ValueName = &names[i];
|
||||
}
|
||||
|
||||
ULONG bufferSize = argc * 128;
|
||||
if (bufferSize < 512)
|
||||
bufferSize = 512;
|
||||
|
||||
FF_AUTO_FREE uint8_t* buffer = NULL;
|
||||
|
||||
while (true)
|
||||
{
|
||||
buffer = (uint8_t*) realloc(buffer, bufferSize);
|
||||
|
||||
ULONG writtenSize = bufferSize;
|
||||
ULONG requiredSize = 0;
|
||||
NTSTATUS status = NtQueryMultipleValueKey(hKey, entries, argc, buffer, &writtenSize, &requiredSize);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
// Buffer too small: docs guarantee requiredSize is returned when provided.
|
||||
if (requiredSize > bufferSize)
|
||||
{
|
||||
FF_DEBUG("NtQueryMultipleValueKey(%p) resize buffer: %u -> %u", hKey, (unsigned) bufferSize, (unsigned) requiredSize);
|
||||
bufferSize = requiredSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_DEBUG("NtQueryMultipleValueKey(%p, argc=%u) failed, status=0x%08X", hKey, (unsigned) argc, (unsigned) status);
|
||||
if (error)
|
||||
ffStrbufAppendF(error, "NtQueryMultipleValueKey(%p, argc=%u) failed, status=0x%08X",
|
||||
hKey, (unsigned) argc, (unsigned) status);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < argc; ++i)
|
||||
{
|
||||
const FFRegValueArg* arg = &argv[i];
|
||||
const KEY_VALUE_ENTRY* entry = &entries[i];
|
||||
|
||||
FF_DEBUG("Read value[%u] from %p: type=%u, len=%u", (unsigned) i, hKey, (unsigned) entry->Type, (unsigned) entry->DataLength);
|
||||
if (!processRegValue(arg, entry->Type, buffer + entry->DataOffset, entry->DataLength, error))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error)
|
||||
{
|
||||
assert(hKey);
|
||||
assert(result);
|
||||
|
||||
alignas(KEY_BASIC_INFORMATION) uint8_t buffer[sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(wchar_t)];
|
||||
ULONG bufSize = (ULONG) sizeof(buffer);
|
||||
KEY_BASIC_INFORMATION* keyInfo = (KEY_BASIC_INFORMATION*) buffer;
|
||||
|
||||
if (!NT_SUCCESS(NtEnumerateKey(hKey, index, KeyBasicInformation, keyInfo, bufSize, &bufSize)))
|
||||
{
|
||||
FF_DEBUG("NtEnumerateKey(hKey=%p, index=%u) failed", hKey, (unsigned) index);
|
||||
if (error)
|
||||
ffStrbufAppendS(error, "RegQueryInfoKeyW(hKey) failed");
|
||||
ffStrbufAppendF(error, "NtEnumerateKey(hKey=%p, %u, keyInfo) failed", hKey, (unsigned) index);
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = buffer;
|
||||
ffStrbufSetNWS(result, keyInfo->NameLength / sizeof(wchar_t), keyInfo->Name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error)
|
||||
{
|
||||
assert(hKey);
|
||||
assert(result);
|
||||
|
||||
alignas(KEY_FULL_INFORMATION) uint8_t buffer[sizeof(KEY_FULL_INFORMATION) + MAX_PATH * sizeof(wchar_t)];
|
||||
ULONG bufSize = sizeof(buffer);
|
||||
KEY_FULL_INFORMATION* keyInfo = (KEY_FULL_INFORMATION*) buffer;
|
||||
|
||||
if (!NT_SUCCESS(NtQueryKey(hKey, KeyFullInformation, keyInfo, bufSize, &bufSize)))
|
||||
{
|
||||
FF_DEBUG("NtQueryKey(hKey=%p, KeyFullInformation) failed", hKey);
|
||||
if (error)
|
||||
ffStrbufAppendF(error, "NtQueryKey(hKey=%p, KeyFullInformation, keyInfo) failed", hKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = (uint32_t) keyInfo->SubKeys;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "common/argType.h"
|
||||
#include "common/io.h"
|
||||
|
||||
#include <windows.h>
|
||||
#ifndef HKEY_CURRENT_USER
|
||||
#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000))
|
||||
#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001))
|
||||
#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002))
|
||||
#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003))
|
||||
#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004))
|
||||
#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005))
|
||||
#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006))
|
||||
#define HKEY_CURRENT_USER_LOCAL_SETTINGS ((HKEY) (ULONG_PTR)((LONG)0x80000007))
|
||||
#endif
|
||||
|
||||
static inline void wrapRegCloseKey(HKEY* phKey)
|
||||
typedef struct FFRegValueArg
|
||||
{
|
||||
if(*phKey)
|
||||
RegCloseKey(*phKey);
|
||||
FFArgType type;
|
||||
const void* value;
|
||||
const wchar_t* name;
|
||||
} FFRegValueArg;
|
||||
|
||||
HANDLE ffRegGetRootKeyHandle(HKEY hKey);
|
||||
bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error);
|
||||
bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error);
|
||||
bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFstrbuf* error);
|
||||
bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error);
|
||||
bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error);
|
||||
|
||||
static inline bool ffRegOpenKeyForRead(HKEY hRootKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error)
|
||||
{
|
||||
return ffRegOpenSubkeyForRead(ffRegGetRootKeyHandle(hRootKey), subKeyW, result, error);
|
||||
}
|
||||
|
||||
#define FF_HKEY_AUTO_DESTROY HKEY __attribute__((__cleanup__(wrapRegCloseKey)))
|
||||
|
||||
bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error);
|
||||
bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error);
|
||||
bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t** result, uint32_t* length, FFstrbuf* error);
|
||||
bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error);
|
||||
bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error);
|
||||
bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error);
|
||||
bool ffRegGetNSubKeys(HKEY hKey, uint32_t* result, FFstrbuf* error);
|
||||
static inline bool ffRegReadStrbuf(HANDLE hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error)
|
||||
{
|
||||
return ffRegReadValue(hKey, &(FFRegValueArg) {
|
||||
.type = FF_ARG_TYPE_STRBUF,
|
||||
.value = result,
|
||||
.name = valueNameW,
|
||||
}, error);
|
||||
}
|
||||
static inline bool ffRegReadUint(HANDLE hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error)
|
||||
{
|
||||
return ffRegReadValue(hKey, &(FFRegValueArg) {
|
||||
.type = FF_ARG_TYPE_UINT,
|
||||
.value = result,
|
||||
.name = valueNameW,
|
||||
}, error);
|
||||
}
|
||||
static inline bool ffRegReadUint64(HANDLE hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error)
|
||||
{
|
||||
return ffRegReadValue(hKey, &(FFRegValueArg) {
|
||||
.type = FF_ARG_TYPE_UINT64,
|
||||
.value = result,
|
||||
.name = valueNameW,
|
||||
}, error);
|
||||
}
|
||||
static inline bool ffRegReadData(HANDLE hKey, const wchar_t* valueNameW, FFArgBuffer* buffer, FFstrbuf* error)
|
||||
{
|
||||
return ffRegReadValue(hKey, &(FFRegValueArg) {
|
||||
.type = FF_ARG_TYPE_BUFFER,
|
||||
.value = buffer,
|
||||
.name = valueNameW,
|
||||
}, error);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "unicode.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
void ffStrbufSetNWS(FFstrbuf* result, uint32_t length, const wchar_t* source)
|
||||
{
|
||||
@@ -10,15 +10,19 @@ void ffStrbufSetNWS(FFstrbuf* result, uint32_t length, const wchar_t* source)
|
||||
return;
|
||||
}
|
||||
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, source, (int)length, NULL, 0, NULL, NULL);
|
||||
if (size_needed <= 0)
|
||||
ULONG size_needed = 0;
|
||||
NTSTATUS status = RtlUnicodeToUTF8N(NULL, 0, &size_needed, source, length * sizeof(wchar_t));
|
||||
|
||||
if (size_needed == 0)
|
||||
{
|
||||
ffStrbufSetF(result, "WCTMB failed: %u", (unsigned) GetLastError());
|
||||
ffStrbufSetF(result, "RtlUnicodeToUTF8N failed: %X", (unsigned) status);
|
||||
return;
|
||||
}
|
||||
ffStrbufEnsureFixedLengthFree(result, (uint32_t)size_needed);
|
||||
WideCharToMultiByte(CP_UTF8, 0, source, (int)length, result->chars, size_needed, NULL, NULL);
|
||||
result->length = (uint32_t)size_needed;
|
||||
|
||||
ffStrbufEnsureFixedLengthFree(result, size_needed);
|
||||
RtlUnicodeToUTF8N(result->chars, size_needed, &size_needed, source, length * sizeof(wchar_t));
|
||||
|
||||
result->length = size_needed;
|
||||
result->chars[size_needed] = '\0';
|
||||
}
|
||||
|
||||
@@ -27,12 +31,18 @@ void ffStrbufAppendNWS(FFstrbuf* result, uint32_t length, const wchar_t* source)
|
||||
if(!length)
|
||||
return;
|
||||
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, source, (int)length, NULL, 0, NULL, NULL);
|
||||
if (size_needed <= 0)
|
||||
return;
|
||||
ULONG size_needed = 0;
|
||||
NTSTATUS status = RtlUnicodeToUTF8N(NULL, 0, &size_needed, source, length * sizeof(wchar_t));
|
||||
|
||||
ffStrbufEnsureFree(result, (uint32_t)size_needed);
|
||||
WideCharToMultiByte(CP_UTF8, 0, source, (int)length, result->chars + result->length, size_needed, NULL, NULL);
|
||||
result->length += (uint32_t)size_needed;
|
||||
if (size_needed == 0)
|
||||
{
|
||||
ffStrbufAppendF(result, "RtlUnicodeToUTF8N failed: %X", (unsigned) status);
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufEnsureFree(result, size_needed);
|
||||
RtlUnicodeToUTF8N(result->chars + result->length, size_needed, &size_needed, source, length * sizeof(wchar_t));
|
||||
|
||||
result->length += size_needed;
|
||||
result->chars[result->length] = '\0';
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ static inline void ffStrbufInitWSV(FFstrbuf* result, const std::wstring_view sou
|
||||
return ffStrbufInitNWS(result, (uint32_t) source.size(), source.data());
|
||||
}
|
||||
|
||||
static inline FFstrbuf ffStrbufCreateWSV(const std::wstring_view source)
|
||||
{
|
||||
return ffStrbufCreateNWS((uint32_t) source.size(), source.data());
|
||||
}
|
||||
|
||||
static inline void ffStrbufSetWSV(FFstrbuf* result, const std::wstring_view source)
|
||||
{
|
||||
return ffStrbufSetNWS(result, (uint32_t) source.size(), source.data());
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "variant.hpp"
|
||||
|
||||
#include <oleauto.h>
|
||||
|
||||
FFWmiVariant::FFWmiVariant(std::initializer_list<PCWSTR> strings): FFWmiVariant()
|
||||
{
|
||||
SAFEARRAYBOUND bound = {
|
||||
.cElements = (ULONG) strings.size(),
|
||||
.lLbound = 0,
|
||||
};
|
||||
SAFEARRAY* psa = SafeArrayCreate(VT_BSTR, 1, &bound);
|
||||
|
||||
LONG i = 0;
|
||||
for (PCWSTR str : strings) {
|
||||
SafeArrayPutElement(psa, &i, bstr_t(str));
|
||||
++i;
|
||||
}
|
||||
|
||||
this->vt = VT_ARRAY | VT_BSTR;
|
||||
this->parray = psa;
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <string_view>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
template <typename TVariant>
|
||||
struct FFBaseVariant: TVariant
|
||||
@@ -137,6 +139,7 @@ struct FFWmiVariant: FFBaseVariant<VARIANT>
|
||||
FFWmiVariant(const FFWmiVariant&) = delete;
|
||||
FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
|
||||
explicit FFWmiVariant() { VariantInit(this); }
|
||||
explicit FFWmiVariant(std::initializer_list<PCWSTR> strings);
|
||||
~FFWmiVariant() { VariantClear(this); }
|
||||
};
|
||||
static_assert(sizeof(FFWmiVariant) == sizeof(VARIANT), "");
|
||||
@@ -149,3 +152,18 @@ struct FFPropVariant: FFBaseVariant<PROPVARIANT>
|
||||
~FFPropVariant() { PropVariantClear(this); }
|
||||
};
|
||||
static_assert(sizeof(FFPropVariant) == sizeof(PROPVARIANT), "");
|
||||
|
||||
namespace
|
||||
{
|
||||
// Provide our bstr_t to avoid libstdc++ dependency
|
||||
struct bstr_t
|
||||
{
|
||||
explicit bstr_t(const wchar_t* str) noexcept: _bstr(SysAllocString(str)) {}
|
||||
~bstr_t(void) noexcept { SysFreeString(_bstr); }
|
||||
explicit operator const wchar_t*(void) const noexcept { return _bstr; }
|
||||
operator BSTR(void) const noexcept { return _bstr; }
|
||||
|
||||
private:
|
||||
BSTR _bstr;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,62 +1,92 @@
|
||||
#include "common/windows/version.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/windows/version.h"
|
||||
#include "common/windows/unicode.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
bool ffGetFileVersion(const wchar_t* filePath, const wchar_t* stringName, FFstrbuf* version)
|
||||
{
|
||||
FF_DEBUG("ffGetFileVersion: enter filePath=%ls stringName=%ls", filePath, stringName);
|
||||
|
||||
DWORD handle;
|
||||
DWORD size = GetFileVersionInfoSizeW(filePath, &handle);
|
||||
if (size > 0)
|
||||
if (size == 0)
|
||||
{
|
||||
FF_AUTO_FREE void *versionData = malloc(size);
|
||||
if (GetFileVersionInfoW(filePath, handle, size, versionData))
|
||||
{
|
||||
if (!stringName)
|
||||
{
|
||||
VS_FIXEDFILEINFO* verInfo;
|
||||
UINT len;
|
||||
if (VerQueryValueW(versionData, L"\\", (void **)&verInfo, &len) && len && verInfo->dwSignature == 0xFEEF04BD)
|
||||
{
|
||||
ffStrbufAppendF(version, "%u.%u.%u.%u",
|
||||
(unsigned)((verInfo->dwProductVersionMS >> 16) & 0xffff),
|
||||
(unsigned)((verInfo->dwProductVersionMS >> 0) & 0xffff),
|
||||
(unsigned)((verInfo->dwProductVersionLS >> 16) & 0xffff),
|
||||
(unsigned)((verInfo->dwProductVersionLS >> 0) & 0xffff));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct
|
||||
{
|
||||
WORD language;
|
||||
WORD codePage;
|
||||
}* translations;
|
||||
|
||||
UINT translationsLen;
|
||||
|
||||
if (VerQueryValueW(versionData, L"\\VarFileInfo\\Translation",
|
||||
(void **) &translations, &translationsLen) &&
|
||||
translationsLen >= sizeof(*translations))
|
||||
{
|
||||
wchar_t subBlock[128];
|
||||
snwprintf(subBlock, ARRAY_SIZE(subBlock), L"\\StringFileInfo\\%04x%04x\\%ls",
|
||||
translations[0].language, translations[0].codePage, stringName);
|
||||
|
||||
wchar_t* value;
|
||||
UINT valueLen;
|
||||
|
||||
if (VerQueryValueW(versionData, subBlock, (void **)&value, &valueLen) && valueLen > 0)
|
||||
{
|
||||
ffStrbufSetWS(version, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DWORD err = GetLastError();
|
||||
FF_DEBUG("GetFileVersionInfoSizeW failed: err=%lu (%s)",
|
||||
(unsigned long) err, ffDebugWin32Error(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_DEBUG("GetFileVersionInfoSizeW ok: size=%lu handle=%lu",
|
||||
(unsigned long) size, (unsigned long) handle);
|
||||
|
||||
FF_AUTO_FREE void* versionData = malloc(size);
|
||||
if (!versionData)
|
||||
{
|
||||
FF_DEBUG("malloc failed: size=%lu", (unsigned long) size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetFileVersionInfoW(filePath, handle, size, versionData))
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
FF_DEBUG("GetFileVersionInfoW failed: err=%lu (%s)",
|
||||
(unsigned long) err, ffDebugWin32Error(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_DEBUG("GetFileVersionInfoW ok");
|
||||
|
||||
if (!stringName)
|
||||
{
|
||||
VS_FIXEDFILEINFO* verInfo;
|
||||
UINT len;
|
||||
if (VerQueryValueW(versionData, L"\\", (void**) &verInfo, &len) &&
|
||||
len &&
|
||||
verInfo->dwSignature == 0xFEEF04BD)
|
||||
{
|
||||
ffStrbufSetF(version, "%u.%u.%u.%u",
|
||||
(unsigned) ((verInfo->dwProductVersionMS >> 16) & 0xffff),
|
||||
(unsigned) ((verInfo->dwProductVersionMS >> 0) & 0xffff),
|
||||
(unsigned) ((verInfo->dwProductVersionLS >> 16) & 0xffff),
|
||||
(unsigned) ((verInfo->dwProductVersionLS >> 0) & 0xffff));
|
||||
FF_DEBUG("fixed version resolved: %s", version->chars);
|
||||
return true;
|
||||
}
|
||||
|
||||
FF_DEBUG("fixed version query failed or invalid signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct { WORD language; WORD codePage; }* translations;
|
||||
UINT translationsLen;
|
||||
|
||||
if (VerQueryValueW(versionData, L"\\VarFileInfo\\Translation", (void**) &translations, &translationsLen) &&
|
||||
translationsLen >= sizeof(*translations))
|
||||
{
|
||||
wchar_t subBlock[128];
|
||||
snwprintf(subBlock, ARRAY_SIZE(subBlock), L"\\StringFileInfo\\%04x%04x\\%ls",
|
||||
translations[0].language, translations[0].codePage, stringName);
|
||||
FF_DEBUG("query version string with translation: %ls", subBlock);
|
||||
|
||||
wchar_t* value;
|
||||
UINT valueLen; // Number of characters, including null terminator
|
||||
if (VerQueryValueW(versionData, subBlock, (void**) &value, &valueLen) && valueLen > 0)
|
||||
{
|
||||
ffStrbufSetNWS(version, valueLen - 1, value);
|
||||
FF_DEBUG("version string resolved (translation fallback): %s", version->chars);
|
||||
return true;
|
||||
}
|
||||
|
||||
FF_DEBUG("translation fallback query failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("no translation table found in version resource");
|
||||
}
|
||||
|
||||
FF_DEBUG("ffGetFileVersion failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ extern "C" {
|
||||
|
||||
#include <initguid.h>
|
||||
#include <wbemidl.h>
|
||||
#include <cassert>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
@@ -74,21 +73,6 @@ struct FFWmiQuery
|
||||
}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
// Provide our bstr_t to avoid libstdc++ dependency
|
||||
struct bstr_t
|
||||
{
|
||||
explicit bstr_t(const wchar_t* str) noexcept: _bstr(SysAllocString(str)) {}
|
||||
~bstr_t(void) noexcept { SysFreeString(_bstr); }
|
||||
explicit operator const wchar_t*(void) const noexcept { return _bstr; }
|
||||
operator BSTR(void) const noexcept { return _bstr; }
|
||||
|
||||
private:
|
||||
BSTR _bstr;
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
// Win32 COM headers requires C++ compiler
|
||||
#error Must be included in C++ source file
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <batclass.h>
|
||||
#include <devguid.h>
|
||||
#include <cfgmgr32.h>
|
||||
#include <winternl.h>
|
||||
|
||||
static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
|
||||
@@ -29,20 +29,18 @@ const char* ffDetectBios(FFBiosResult* bios)
|
||||
if (!device)
|
||||
return "IODeviceTree:/ not found";
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef deviceProps = NULL;
|
||||
if(IORegistryEntryCreateCFProperties(device, &deviceProps, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
return "IORegistryEntryCreateCFProperties(device) failed";
|
||||
|
||||
ffCfDictGetString(deviceProps, CFSTR("manufacturer"), &bios->vendor);
|
||||
ffCfDictGetString(deviceProps, CFSTR("time-stamp"), &bios->date);
|
||||
FF_CFTYPE_AUTO_RELEASE CFDataRef manufacturer = IORegistryEntryCreateCFProperty(device, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
|
||||
ffCfStrGetString(manufacturer, &bios->vendor);
|
||||
FF_CFTYPE_AUTO_RELEASE CFDataRef timeStamp = IORegistryEntryCreateCFProperty(device, CFSTR("time-stamp"), kCFAllocatorDefault, kNilOptions);
|
||||
ffCfStrGetString(timeStamp, &bios->date);
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceChosen = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
|
||||
if (deviceChosen)
|
||||
{
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef systemFirmWareVersion = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (systemFirmWareVersion)
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef systemFirmwareVersion = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (systemFirmwareVersion)
|
||||
{
|
||||
ffCfStrGetString(systemFirmWareVersion, &bios->version);
|
||||
ffCfStrGetString(systemFirmwareVersion, &bios->version);
|
||||
uint32_t index = ffStrbufFirstIndexC(&bios->version, '-');
|
||||
if (index != bios->version.length)
|
||||
{
|
||||
|
||||
@@ -2,14 +2,20 @@
|
||||
#include "common/io.h"
|
||||
#include "common/smbiosHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_vendor", "/sys/class/dmi/id/bios_vendor", &bios->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_version", "/sys/class/dmi/id/bios_version", &bios->version);
|
||||
if (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);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_vendor", "/sys/class/dmi/id/bios_vendor", &bios->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/bios_version", "/sys/class/dmi/id/bios_version", &bios->version);
|
||||
}
|
||||
else if (ffReadFileBuffer("/proc/device-tree/chosen/u-boot,version", &bios->version))
|
||||
{
|
||||
ffStrbufTrimRight(&bios->version, '\0');
|
||||
ffStrbufSetStatic(&bios->vendor, "U-Boot");
|
||||
}
|
||||
|
||||
if (ffPathExists("/sys/firmware/efi/", FF_PATHTYPE_DIRECTORY) || ffPathExists("/sys/firmware/acpi/tables/UEFI", FF_PATHTYPE_FILE))
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
else
|
||||
|
||||
@@ -5,37 +5,18 @@
|
||||
#include "common/windows/registry.h"
|
||||
|
||||
#include <ntstatus.h>
|
||||
#include <winternl.h>
|
||||
|
||||
typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
|
||||
{
|
||||
GUID BootIdentifier;
|
||||
FIRMWARE_TYPE FirmwareType;
|
||||
union
|
||||
{
|
||||
ULONGLONG BootFlags;
|
||||
struct
|
||||
{
|
||||
ULONGLONG DbgMenuOsSelection : 1; // REDSTONE4
|
||||
ULONGLONG DbgHiberBoot : 1;
|
||||
ULONGLONG DbgSoftBoot : 1;
|
||||
ULONGLONG DbgMeasuredLaunch : 1;
|
||||
ULONGLONG DbgMeasuredLaunchCapable : 1; // 19H1
|
||||
ULONGLONG DbgSystemHiveReplace : 1;
|
||||
ULONGLONG DbgMeasuredLaunchSmmProtections : 1;
|
||||
ULONGLONG DbgMeasuredLaunchSmmLevel : 7; // 20H1
|
||||
};
|
||||
};
|
||||
} SYSTEM_BOOT_ENVIRONMENT_INFORMATION;
|
||||
#include "common/windows/nt.h"
|
||||
#elif __OpenBSD__
|
||||
#include "common/io.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#elif __sun
|
||||
#include <libdevinfo.h>
|
||||
#include <sys/sunddi.h>
|
||||
#elif __APPLE__
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#endif
|
||||
|
||||
typedef struct FFSmbiosBios
|
||||
@@ -90,7 +71,7 @@ const char* ffDetectBios(FFBiosResult* bios)
|
||||
// Same as GetFirmwareType, but support (?) Windows 7
|
||||
// https://ntdoc.m417z.com/system_information_class
|
||||
SYSTEM_BOOT_ENVIRONMENT_INFORMATION sbei;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(90 /*SystemBootEnvironmentInformation*/, &sbei, sizeof(sbei), NULL)))
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemBootEnvironmentInformation, &sbei, sizeof(sbei), NULL)))
|
||||
{
|
||||
switch (sbei.FirmwareType)
|
||||
{
|
||||
@@ -111,8 +92,12 @@ const char* ffDetectBios(FFBiosResult* bios)
|
||||
}
|
||||
di_fini(rootNode);
|
||||
#elif __HAIKU__ || __OpenBSD__
|
||||
// Currently SMBIOS detection is supported in legancy BIOS only
|
||||
// Currently SMBIOS detection is supported in legacy BIOS only
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
#elif __APPLE__
|
||||
// Intel Macs use UEFI from day one
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceEfi = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/efi");
|
||||
ffStrbufSetStatic(&bios->type, deviceEfi ? "UEFI" : "BIOS");
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -191,7 +191,7 @@ static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIt
|
||||
|
||||
static const char* detectBluetooth(FFlist* devices, int32_t connectedCount)
|
||||
{
|
||||
FFDBusData dbus;
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
|
||||
if(error)
|
||||
return error;
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
|
||||
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
// Actually bluetoothapis.dll, but it's missing on Windows 7
|
||||
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bthprops.cpl", 1)
|
||||
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstDevice)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindNextDevice)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindDeviceClose)
|
||||
|
||||
@@ -6,8 +6,6 @@ extern "C"
|
||||
#include "common/windows/unicode.hpp"
|
||||
#include "common/windows/util.hpp"
|
||||
|
||||
STDAPI InitVariantFromStringArray(_In_reads_(cElems) PCWSTR *prgsz, _In_ ULONG cElems, _Out_ VARIANT *pvar);
|
||||
|
||||
extern "C"
|
||||
const char* ffBluetoothDetectBattery(FFlist* devices)
|
||||
{
|
||||
@@ -27,13 +25,7 @@ const char* ffBluetoothDetectBattery(FFlist* devices)
|
||||
if (FAILED(pnpEntityClass->GetMethod(bstr_t(L"GetDeviceProperties"), 0, &pInParams, NULL)))
|
||||
return "Failed to get GetDeviceProperties method";
|
||||
|
||||
VARIANT devicePropertyKeys;
|
||||
PCWSTR props[] = { L"{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2", L"DEVPKEY_Bluetooth_DeviceAddress" };
|
||||
|
||||
if (FAILED(InitVariantFromStringArray(props, ARRAY_SIZE(props), &devicePropertyKeys)))
|
||||
return "Failed to init variant from string array";
|
||||
on_scope_exit releaseDevicePropertyKeys([&] { VariantClear(&devicePropertyKeys); });
|
||||
|
||||
FFWmiVariant devicePropertyKeys({ L"{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2", L"DEVPKEY_Bluetooth_DeviceAddress" });
|
||||
if (FAILED(pInParams->Put(L"devicePropertyKeys", 0, &devicePropertyKeys, CIM_FLAG_ARRAY | CIM_STRING)))
|
||||
return "Failed to put devicePropertyKeys";
|
||||
}
|
||||
@@ -79,8 +71,7 @@ const char* ffBluetoothDetectBattery(FFlist* devices)
|
||||
batt = data.get<uint8_t>();
|
||||
else
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY addr; // MAC address without colon
|
||||
ffStrbufInitWSV(&addr, data.get<std::wstring_view>());
|
||||
FF_STRBUF_AUTO_DESTROY addr = ffStrbufCreateWSV(data.get<std::wstring_view>()); // MAC address without colon
|
||||
if (__builtin_expect(addr.length != 12, 0))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ static const char* detectBluetooth(FFlist* devices)
|
||||
if(dirp == NULL)
|
||||
return "Failed to open /sys/class/bluetooth";
|
||||
|
||||
FFDBusData dbus;
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
|
||||
if(error)
|
||||
return error;
|
||||
|
||||
@@ -54,7 +54,7 @@ static_assert(sizeof(BTH_LOCAL_RADIO_INFO) == 292, "BTH_LOCAL_RADIO_INFO should
|
||||
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
|
||||
{
|
||||
// Actually bluetoothapis.dll, but it's missing on Windows 7
|
||||
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bthprops.cpl", 1)
|
||||
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstRadio)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindNextRadio)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindRadioClose)
|
||||
@@ -98,7 +98,7 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
|
||||
device->connectable = ffBluetoothIsConnectable(hRadio);
|
||||
device->discoverable = ffBluetoothIsDiscoverable(hRadio);
|
||||
|
||||
CloseHandle(hRadio);
|
||||
NtClose(hRadio);
|
||||
} while (ffBluetoothFindNextRadio(hFind, &hRadio));
|
||||
|
||||
ffBluetoothFindRadioClose(hFind);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdalign.h>
|
||||
|
||||
#ifdef __NetBSD__
|
||||
typedef uint16_t efi_char;
|
||||
@@ -23,7 +24,7 @@ const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR | O_CLOEXEC);
|
||||
if (efifd < 0) return "open(/dev/efi) failed";
|
||||
|
||||
uint8_t buffer[2048];
|
||||
alignas(uint16_t) uint8_t buffer[2048];
|
||||
struct efi_var_ioc ioc = {
|
||||
.vendor = EFI_GLOBAL_VARIABLE,
|
||||
.data = buffer,
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
#include "common/io.h"
|
||||
#include "efi_helper.h"
|
||||
|
||||
#include <stdalign.h>
|
||||
|
||||
#define FF_EFIVARS_PATH_PREFIX "/sys/firmware/efi/efivars/"
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
{
|
||||
uint8_t buffer[2048];
|
||||
alignas(uint16_t) uint8_t buffer[2048];
|
||||
|
||||
if (ffReadFileData(FF_EFIVARS_PATH_PREFIX "BootCurrent-" FF_EFI_GLOBAL_GUID, sizeof(buffer), buffer) != 6)
|
||||
return "Failed to read efivar: BootCurrent";
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#include "bootmgr.h"
|
||||
#include "efi_helper.h"
|
||||
#include "common/io.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#include <ntstatus.h>
|
||||
#include <windows.h>
|
||||
|
||||
const char* enablePrivilege(const wchar_t* privilege)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD HANDLE token = NULL;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
|
||||
return "OpenProcessToken() failed";
|
||||
if (!NT_SUCCESS(NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)))
|
||||
return "NtOpenProcessToken() failed";
|
||||
|
||||
TOKEN_PRIVILEGES tp = {
|
||||
.PrivilegeCount = 1,
|
||||
@@ -19,35 +21,46 @@ const char* enablePrivilege(const wchar_t* privilege)
|
||||
if (!LookupPrivilegeValueW(NULL, privilege, &tp.Privileges[0].Luid))
|
||||
return "LookupPrivilegeValue() failed";
|
||||
|
||||
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(tp), NULL, NULL))
|
||||
return "AdjustTokenPrivileges() failed";
|
||||
NTSTATUS status = NtAdjustPrivilegesToken(token, false, &tp, sizeof(tp), NULL, NULL);
|
||||
if (!NT_SUCCESS(status))
|
||||
return "NtAdjustPrivilegesToken() failed";
|
||||
|
||||
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
|
||||
return "The token does not have the specified privilege";
|
||||
if (status == STATUS_NOT_ALL_ASSIGNED)
|
||||
return "The token does not have the specified privilege; try sudo please";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
{
|
||||
if (enablePrivilege(L"SeSystemEnvironmentPrivilege") != NULL)
|
||||
return "Failed to enable SeSystemEnvironmentPrivilege";
|
||||
const char* err = enablePrivilege(L"SeSystemEnvironmentPrivilege");
|
||||
if (err != NULL)
|
||||
return err;
|
||||
|
||||
if (GetFirmwareEnvironmentVariableW(L"BootCurrent", L"{" FF_EFI_GLOBAL_GUID L"}", &result->order, sizeof(result->order)) != 2)
|
||||
return "GetFirmwareEnvironmentVariableW(BootCurrent) failed";
|
||||
GUID efiGlobalGuid;
|
||||
if (!NT_SUCCESS(RtlGUIDFromString(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"{" FF_EFI_GLOBAL_GUID L"}"), &efiGlobalGuid)))
|
||||
return "RtlGUIDFromString() failed";
|
||||
|
||||
ULONG size = sizeof(result->order);
|
||||
if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"BootCurrent"), &efiGlobalGuid, &result->order, &size, NULL)))
|
||||
return "NtQuerySystemEnvironmentValueEx(BootCurrent) failed";
|
||||
if (size != sizeof(result->order))
|
||||
return "NtQuerySystemEnvironmentValueEx(BootCurrent) returned unexpected size";
|
||||
|
||||
uint8_t buffer[2048];
|
||||
wchar_t key[16];
|
||||
wchar_t key[9];
|
||||
swprintf(key, ARRAY_SIZE(key), L"Boot%04X", result->order);
|
||||
uint32_t size = GetFirmwareEnvironmentVariableW(key, L"{" FF_EFI_GLOBAL_GUID L"}", buffer, sizeof(buffer));
|
||||
size = sizeof(buffer);
|
||||
if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(key), &efiGlobalGuid, buffer, &size, NULL)))
|
||||
return "NtQuerySystemEnvironmentValueEx(Boot####) failed";
|
||||
if (size < sizeof(FFEfiLoadOption) || size == ARRAY_SIZE(buffer))
|
||||
return "GetFirmwareEnvironmentVariableW(Boot####) failed";
|
||||
return "NtQuerySystemEnvironmentValueEx(Boot####) returned unexpected size";
|
||||
|
||||
ffEfiFillLoadOption((FFEfiLoadOption *)buffer, result);
|
||||
|
||||
DWORD uefiSecureBootEnabled = 0, bufSize = 0;
|
||||
if (RegGetValueW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\SecureBoot\\State", L"UEFISecureBootEnabled", RRF_RT_REG_DWORD, NULL, &uefiSecureBootEnabled, &bufSize) == ERROR_SUCCESS)
|
||||
result->secureBoot = !!uefiSecureBootEnabled;
|
||||
SYSTEM_SECUREBOOT_INFORMATION ssi;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemSecureBootInformation, &ssi, sizeof(ssi), NULL)))
|
||||
result->secureBoot = ssi.SecureBootEnabled;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -110,26 +110,29 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED FFBrightnessOptions* options,
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libddcutil, ddca_close_display)
|
||||
|
||||
#ifndef FF_DISABLE_DLOPEN
|
||||
__typeof__(&ddca_init) ffddca_init = dlsym(libddcutil, "ddca_init");
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(libddcutil, ddca_init)
|
||||
if (ffddca_init)
|
||||
#else
|
||||
__typeof__(&ddca_init) ffddca_init = ddca_init;
|
||||
#endif
|
||||
{
|
||||
FF_SUPPRESS_IO();
|
||||
// Ref: https://github.com/rockowitz/ddcutil/issues/344
|
||||
if (ffddca_init(NULL, -1 /*DDCA_SYSLOG_NOT_SET*/, 1 /*DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE*/) < 0)
|
||||
return "ddca_init() failed";
|
||||
}
|
||||
#ifndef FF_DISABLE_DLOPEN
|
||||
else
|
||||
{
|
||||
__typeof__(&ddca_set_default_sleep_multiplier) ffddca_set_default_sleep_multiplier = dlsym(libddcutil, "ddca_set_default_sleep_multiplier");
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(libddcutil, ddca_set_default_sleep_multiplier);
|
||||
if (ffddca_set_default_sleep_multiplier)
|
||||
ffddca_set_default_sleep_multiplier(options->ddcciSleep / 40.0);
|
||||
|
||||
libddcutil = NULL; // Don't dlclose libddcutil. See https://github.com/rockowitz/ddcutil/issues/330
|
||||
}
|
||||
#else
|
||||
#if DDCUTIL_VMAJOR >= 2
|
||||
if (ddca_init(NULL, -1 /*DDCA_SYSLOG_NOT_SET*/, 1 /*DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE*/) < 0)
|
||||
return "ddca_init() failed";
|
||||
#else
|
||||
ddca_set_default_sleep_multiplier(options->ddcciSleep / 40.0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
FF_AUTO_FREE DDCA_Display_Info_List* infoList = NULL;
|
||||
|
||||
@@ -7,8 +7,37 @@ extern "C"
|
||||
#include "common/windows/wmi.hpp"
|
||||
#include "common/windows/unicode.hpp"
|
||||
|
||||
#include <highlevelmonitorconfigurationapi.h>
|
||||
#include <physicalmonitorenumerationapi.h>
|
||||
#include <winternl.h>
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI GetPhysicalMonitors(
|
||||
_In_ UNICODE_STRING *pstrDeviceName,
|
||||
_In_ DWORD dwPhysicalMonitorArraySize,
|
||||
_Out_ DWORD *pdwNumPhysicalMonitorHandlesInArray,
|
||||
_Out_ HANDLE *phPhysicalMonitorArray
|
||||
);
|
||||
|
||||
typedef enum _MC_VCP_CODE_TYPE {
|
||||
MC_MOMENTARY,
|
||||
MC_SET_PARAMETER
|
||||
} MC_VCP_CODE_TYPE, *LPMC_VCP_CODE_TYPE;
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI DDCCIGetVCPFeature(
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwVCPCode,
|
||||
_Out_opt_ LPMC_VCP_CODE_TYPE pvct,
|
||||
_Out_ DWORD *pdwCurrentValue,
|
||||
_Out_opt_ DWORD *pdwMaximumValue
|
||||
);
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI DestroyPhysicalMonitorInternal(
|
||||
_In_ HANDLE hMonitor
|
||||
);
|
||||
|
||||
NTSTATUS WINAPI GetPhysicalMonitorDescription(
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwPhysicalMonitorDescriptionSizeInChars,
|
||||
_Out_ LPWSTR szPhysicalMonitorDescription
|
||||
);
|
||||
|
||||
static const char* detectWithWmi(FFlist* result)
|
||||
{
|
||||
@@ -40,33 +69,55 @@ static const char* detectWithWmi(FFlist* result)
|
||||
|
||||
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFlist* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD_MESSAGE(dxva2, "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)
|
||||
void* gdi32 = ffLibraryGetModule(L"gdi32.dll");
|
||||
if (!gdi32) return "ffLibraryGetModule(gdi32.dll) failed";
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, GetPhysicalMonitors)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DDCCIGetVCPFeature)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DestroyPhysicalMonitorInternal)
|
||||
|
||||
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
|
||||
{
|
||||
PHYSICAL_MONITOR physicalMonitor;
|
||||
if (ffGetPhysicalMonitorsFromHMONITOR((HMONITOR)(uintptr_t) display->id, 1, &physicalMonitor))
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN) continue;
|
||||
|
||||
MONITORINFOEXW mi;
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (!GetMonitorInfoW((HMONITOR)(uintptr_t) display->id, (LPMONITORINFO) &mi))
|
||||
continue;
|
||||
|
||||
UNICODE_STRING deviceName = {
|
||||
.Length = (USHORT) (wcslen(mi.szDevice) * sizeof(wchar_t)),
|
||||
.MaximumLength = 0,
|
||||
.Buffer = mi.szDevice,
|
||||
};
|
||||
HANDLE physicalMonitor;
|
||||
DWORD monitorCount = 0;
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitors(&deviceName, 1, &monitorCount, &physicalMonitor)) && monitorCount >= 1)
|
||||
{
|
||||
DWORD min = 0, curr = 0, max = 0;
|
||||
if (ffGetMonitorBrightness(physicalMonitor.hPhysicalMonitor, &min, &curr, &max))
|
||||
DWORD curr = 0, max = 0;
|
||||
if (NT_SUCCESS(ffDDCCIGetVCPFeature(physicalMonitor, 0x10 /* luminance */, NULL, &curr, &max)))
|
||||
{
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
|
||||
if (display->name.length)
|
||||
if (display->name.length > 0)
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
else
|
||||
ffStrbufInitWS(&brightness->name, physicalMonitor.szPhysicalMonitorDescription);
|
||||
|
||||
{
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(gdi32, GetPhysicalMonitorDescription)
|
||||
if (ffGetPhysicalMonitorDescription)
|
||||
{
|
||||
wchar_t description[128 /*MUST be PHYSICAL_MONITOR_DESCRIPTION_SIZE*/];
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitorDescription(physicalMonitor, ARRAY_SIZE(description), description)))
|
||||
ffStrbufInitWS(&brightness->name, description);
|
||||
}
|
||||
if (brightness->name.length == 0)
|
||||
ffStrbufSetNWS(&brightness->name, deviceName.Length / 2, deviceName.Buffer);
|
||||
}
|
||||
brightness->max = max;
|
||||
brightness->min = min;
|
||||
brightness->min = 0;
|
||||
brightness->current = curr;
|
||||
brightness->builtin = false;
|
||||
}
|
||||
|
||||
ffDestroyPhysicalMonitor(physicalMonitor.hPhysicalMonitor);
|
||||
ffDestroyPhysicalMonitorInternal(physicalMonitor);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
@@ -46,7 +46,7 @@ static const char* armPartId2name(uint32_t partId)
|
||||
case 0xa20: return "ARM1020";
|
||||
case 0xa22: return "ARM1022";
|
||||
case 0xa26: return "ARM1026";
|
||||
case 0xb02: return "ARM11 MPCore";
|
||||
case 0xb02: return "ARM11-MPCore";
|
||||
case 0xb36: return "ARM1136";
|
||||
case 0xb56: return "ARM1156";
|
||||
case 0xb76: return "ARM1176";
|
||||
@@ -82,10 +82,12 @@ static const char* armPartId2name(uint32_t partId)
|
||||
case 0xd0d: return "Cortex-A77";
|
||||
case 0xd0e: return "Cortex-A76AE";
|
||||
case 0xd13: return "Cortex-R52";
|
||||
case 0xd14: return "Cortex-R82AE";
|
||||
case 0xd15: return "Cortex-R82";
|
||||
case 0xd16: return "Cortex-R52+";
|
||||
case 0xd20: return "Cortex-M23";
|
||||
case 0xd21: return "Cortex-M33";
|
||||
case 0xd24: return "Cortex-M52";
|
||||
case 0xd22: return "Cortex-M55";
|
||||
case 0xd23: return "Cortex-M85";
|
||||
case 0xd40: return "Neoverse-V1";
|
||||
@@ -215,7 +217,7 @@ static const char* nvidiaPartId2name(uint32_t partId)
|
||||
switch (partId)
|
||||
{
|
||||
case 0x000: return "Denver";
|
||||
case 0x003: return "Denver 2";
|
||||
case 0x003: return "Denver-2";
|
||||
case 0x004: return "Carmel";
|
||||
case 0x010: return "Olympus";
|
||||
default: return NULL;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include "common/windows/perflib_.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include <wchar.h>
|
||||
|
||||
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery)
|
||||
@@ -37,10 +38,8 @@ const char* detectThermalTemp(const FFCPUOptions* options, double* result)
|
||||
|
||||
if (options->tempSensor.length > 0)
|
||||
{
|
||||
int written = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, options->tempSensor.chars, (int) options->tempSensor.length, querySpec.Name, (int)(ARRAY_SIZE(querySpec.Name) - 1));
|
||||
if (written == 0)
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(querySpec.Name, (ULONG) sizeof(querySpec.Name), NULL, options->tempSensor.chars, (ULONG)options->tempSensor.length + 1)))
|
||||
return "Invalid temp sensor string";
|
||||
querySpec.Name[written] = L'\0';
|
||||
}
|
||||
|
||||
DWORD dataSize = 0;
|
||||
@@ -212,15 +211,16 @@ static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu)
|
||||
|
||||
static const char* detectNCores(FFCPUResult* cpu)
|
||||
{
|
||||
DWORD length = 0;
|
||||
GetLogicalProcessorInformationEx(RelationAll, NULL, &length);
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP lpr = RelationAll;
|
||||
ULONG length = 0;
|
||||
NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), NULL, 0, &length);
|
||||
if (length == 0)
|
||||
return "GetLogicalProcessorInformationEx(RelationAll, NULL, &length) failed";
|
||||
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE
|
||||
pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length);
|
||||
|
||||
if (!pProcessorInfo || !GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length))
|
||||
if (!NT_SUCCESS(NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), pProcessorInfo, length, &length)))
|
||||
return "GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length) failed";
|
||||
|
||||
for(
|
||||
@@ -250,28 +250,18 @@ static const char* detectNCores(FFCPUResult* cpu)
|
||||
|
||||
static const char* detectByRegistry(FFCPUResult* cpu)
|
||||
{
|
||||
FF_HKEY_AUTO_DESTROY hKey = NULL;
|
||||
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey, NULL))
|
||||
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed";
|
||||
|
||||
ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL);
|
||||
if (ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL))
|
||||
if (ffRegReadValues(hKey, 3, (FFRegValueArg[]) {
|
||||
FF_ARG(cpu->name, L"ProcessorNameString"),
|
||||
FF_ARG(cpu->vendor, L"VendorIdentifier"),
|
||||
FF_ARG(cpu->frequencyBase, L"~MHz"),
|
||||
}, NULL))
|
||||
ffStrbufTrimRightSpace(&cpu->vendor);
|
||||
|
||||
if (cpu->coresLogical == 0)
|
||||
{
|
||||
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;
|
||||
if(ffRegReadUint(hKey, L"~MHz", &mhz, NULL))
|
||||
cpu->frequencyBase = mhz;
|
||||
else
|
||||
return "ffRegReadValues() failed for CPU registry key";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -44,12 +44,15 @@ static const char* parseCpuCacheIndex(FFstrbuf* path, FFCPUCacheResult* result,
|
||||
|
||||
ffStrbufSubstrBefore(path, baseLen);
|
||||
ffStrbufAppendS(path, "/shared_cpu_list");
|
||||
if (!ffReadFileBuffer(path->chars, buffer))
|
||||
return "ffReadFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/shared_cpu_list\") == NULL";
|
||||
ffStrbufClear(buffer);
|
||||
ffStrbufAppendC(buffer, '[');
|
||||
if (!ffAppendFileBuffer(path->chars, buffer))
|
||||
return "ffAppendFileBuffer(\"/sys/devices/system/cpu/cpuX/cache/indexX/shared_cpu_list\") == NULL";
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
|
||||
// deduplicate shared caches
|
||||
ffStrbufAppendF(buffer, "_%u_%u_%u_%u\n", level, sizeKb, lineSize, cacheType);
|
||||
ffStrbufAppendF(buffer, "_%u_%u_%u_%u]", level, sizeKb, lineSize, cacheType);
|
||||
|
||||
if (ffStrbufContain(added, buffer)) return NULL;
|
||||
ffStrbufAppend(added, buffer);
|
||||
ffCPUCacheAddItem(result, level, sizeKb * 1024, lineSize, cacheType);
|
||||
|
||||
@@ -37,9 +37,12 @@ const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
if (!data)
|
||||
return "Cache information is not found in SMBIOS data";
|
||||
|
||||
for (; data->Header.Type == FF_SMBIOS_TYPE_CACHE_INFO;
|
||||
data = (const FFSmbiosCacheInfo*) ffSmbiosNextEntry(&data->Header))
|
||||
const FFSmbiosCacheInfo* endOfTable = (const FFSmbiosCacheInfo*) (*smbiosTable)[FF_SMBIOS_TYPE_END_OF_TABLE];
|
||||
for (; data != endOfTable; data = (const FFSmbiosCacheInfo*) ffSmbiosNextEntry(&data->Header))
|
||||
{
|
||||
if (data->Header.Type != FF_SMBIOS_TYPE_CACHE_INFO)
|
||||
continue;
|
||||
|
||||
bool enabled = !!(data->CacheConfiguration & (1 << 7));
|
||||
if (!enabled)
|
||||
continue;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#include "cpucache.h"
|
||||
#include "common/mallocHelper.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result)
|
||||
{
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP lpr = RelationCache;
|
||||
DWORD length = 0;
|
||||
GetLogicalProcessorInformationEx(RelationCache, NULL, &length);
|
||||
NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), NULL, 0, &length);
|
||||
if (length == 0)
|
||||
return "GetLogicalProcessorInformationEx(RelationCache, NULL, &length) failed";
|
||||
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE
|
||||
pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length);
|
||||
|
||||
if (!pProcessorInfo || !GetLogicalProcessorInformationEx(RelationCache, pProcessorInfo, &length))
|
||||
if (!NT_SUCCESS(NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), pProcessorInfo, length, &length)))
|
||||
return "GetLogicalProcessorInformationEx(RelationCache, pProcessorInfo, &length) failed";
|
||||
|
||||
for(
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#include "fastfetch.h"
|
||||
#include "detection/cpuusage/cpuusage.h"
|
||||
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#include <ntstatus.h>
|
||||
#include <winternl.h>
|
||||
#include <windows.h>
|
||||
#include <wchar.h>
|
||||
#include "common/windows/perflib_.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
static const char* getInfoByNqsi(FFlist* cpuTimes)
|
||||
{
|
||||
@@ -155,20 +154,17 @@ static const char* getInfoByPerflib(FFlist* cpuTimes)
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
#if !FF_WIN7_COMPAT
|
||||
static uint8_t winver = 10; // Assume Windows 10 or later for WoA
|
||||
#else
|
||||
static uint8_t winver = 0;
|
||||
if (winver == 0)
|
||||
winver = (uint8_t) ffStrbufToUInt(&instance.state.platform.sysinfo.release, 1);
|
||||
#endif
|
||||
const char* error = NULL;
|
||||
|
||||
if (winver >= 10)
|
||||
if (ffIsWindows10OrGreater())
|
||||
{
|
||||
if (getInfoByPerflib(cpuTimes) == NULL) return NULL;
|
||||
error = getInfoByPerflib(cpuTimes);
|
||||
FF_DEBUG("Get CPU usage info by Perflib: %s", error ?: "success");
|
||||
if (!error) return NULL;
|
||||
ffListClear(cpuTimes);
|
||||
winver = 1; // Fall back to NQSI
|
||||
}
|
||||
|
||||
return getInfoByNqsi(cpuTimes);
|
||||
error = getInfoByNqsi(cpuTimes);
|
||||
FF_DEBUG("Get CPU usage info by NtQuerySystemInformation: %s", error ?: "success");
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
#include "cursor.h"
|
||||
|
||||
#include "common/io.h"
|
||||
#include "common/windows/registry.h"
|
||||
|
||||
void ffDetectCursor(FFCursorResult* result)
|
||||
{
|
||||
FF_HKEY_AUTO_DESTROY hKey;
|
||||
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
|
||||
if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Control Panel\\Cursors", &hKey, &result->error))
|
||||
{
|
||||
if (!ffRegReadStrbuf(hKey, NULL, &result->theme, &result->error))
|
||||
return;
|
||||
|
||||
uint32_t cursorBaseSize;
|
||||
if (ffRegReadUint(hKey, L"CursorBaseSize", &cursorBaseSize, NULL))
|
||||
ffStrbufAppendF(&result->size, "%u", (unsigned) cursorBaseSize);
|
||||
if (ffRegReadValues(hKey, 2, (FFRegValueArg[]) {
|
||||
FF_ARG(result->theme, NULL),
|
||||
FF_ARG(cursorBaseSize, L"CursorBaseSize"),
|
||||
}, &result->error))
|
||||
ffStrbufAppendUInt(&result->size, cursorBaseSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ static void getKDE(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
||||
static const char* getGnomeByDbus(FF_MAYBE_UNUSED FFstrbuf* result)
|
||||
{
|
||||
#ifdef FF_HAVE_DBUS
|
||||
FFDBusData dbus;
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
|
||||
return "ffDBusLoadData() failed";
|
||||
|
||||
|
||||
@@ -140,21 +140,7 @@ static void detectName(FFDisk* disk)
|
||||
|
||||
if (disk->name.length == 0) return;
|
||||
|
||||
// Basic\x20data\x20partition
|
||||
for (uint32_t i = ffStrbufFirstIndexS(&disk->name, "\\x");
|
||||
i != disk->name.length;
|
||||
i = ffStrbufNextIndexS(&disk->name, i + 1, "\\x"))
|
||||
{
|
||||
uint32_t len = (uint32_t) strlen("\\x20");
|
||||
if (disk->name.length >= len)
|
||||
{
|
||||
char bak = disk->name.chars[i + len];
|
||||
disk->name.chars[i + len] = '\0';
|
||||
disk->name.chars[i] = (char) strtoul(&disk->name.chars[i + 2], NULL, 16);
|
||||
ffStrbufRemoveSubstr(&disk->name, i + 1, i + len);
|
||||
disk->name.chars[i + 1] = bak;
|
||||
}
|
||||
}
|
||||
ffStrbufDecodeHexEscapeSequences(&disk->name);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user