Compare commits

...

82 Commits

Author SHA1 Message Date
Carter Li b80da99fac Merge pull request #677 from fastfetch-cli/dev
Release: v2.5.0
2024-01-01 11:52:51 +08:00
李通洲 a95a80aa93 README: remove invalid info 2024-01-01 10:50:04 +08:00
AlbydS 553338b2bc Add more Linux distributions to installation guide
I added Alpine Linux, NixOS and openSUSE to the installation guide.
2024-01-01 10:29:57 +08:00
李通洲 a56c092a78 Release: v2.5.0
Happy new year!
2023-12-31 18:44:32 +08:00
李通洲 3f553b3266 Doc: update changelog 2023-12-31 18:43:44 +08:00
Souma cae4b1c657 chore(terminalshell_linux.c): Ignore cwterm as well as figterm
Since CodeWhisperer overrides the terminal environment.
2023-12-31 18:19:04 +08:00
李通洲 bb489f9af3 Common: get rid of detection/internal.h 2023-12-30 18:13:54 +08:00
李通洲 275b53c6c0 Vulkan: don't print software renderers 2023-12-30 18:12:21 +08:00
李通洲 adae31304d Media (macOS): tidy 2023-12-30 14:21:52 +08:00
李通洲 db6d5d7fd6 Windows: get rid of InitOnceExecuteOnce 2023-12-30 14:19:25 +08:00
Carter Li bce96cf3f0 Doc: update changelog 2023-12-29 23:35:47 +08:00
Carter Li 0707902532 PhysicalDisk (Apple): trim strings 2023-12-29 23:33:16 +08:00
李通洲 ef1d102e05 GPU (Windows): clean up vendor name 2023-12-29 23:13:44 +08:00
李通洲 c1f511c8f2 GPU: detect supported platform graphic API version 2023-12-29 23:13:44 +08:00
李通洲 0284f6bfd1 Font: tidy 2023-12-28 15:42:07 +08:00
李通洲 6d50f1efdd Doc: update changelog 2023-12-28 15:12:20 +08:00
李通洲 4066c0d9e8 PhysicalDisk (Windows): improve stability 2023-12-28 14:50:39 +08:00
李通洲 150e9fc650 PhysicalDisk: prettify interconnect type 2023-12-28 13:47:21 +08:00
李通洲 36bce8fb0e PhysicalDisk (macOS): fix a possible segfault 2023-12-28 13:41:40 +08:00
Carter Li e5e70c1d92 PhysicalDisk (Linux): prettify interconnect type 2023-12-28 10:31:28 +08:00
Carter Li 12065bcfb0 PhysicalDisk (Linux): display nvme namespace id if needed 2023-12-28 10:28:21 +08:00
Carter Li 73a30da7bc Disk (FreeBSD): detect partition name 2023-12-27 16:26:58 +08:00
Carter Li 01fb491289 PhysicalDisk (FreeBSD): detect NVMe connect type 2023-12-27 15:32:17 +08:00
李通洲 6c4a4bfe13 Disk (macOS): support name detection of iso volumes 2023-12-27 14:15:50 +08:00
Carter Li 62647c3cb9 PhysicalDisk (FreeBSD): add comments 2023-12-27 11:14:15 +08:00
Carter Li 42694042f5 PhysicalDisk (FreeBSD): fix read-only type detection 2023-12-27 11:03:01 +08:00
李通洲 d5997b9f29 Doc: document --physicaldisk-temp 2023-12-27 10:16:33 +08:00
李通洲 969a67ed0f PhysicalDisk (macOS): detect temp 2023-12-27 10:00:29 +08:00
李通洲 54bd4346ec Temps (macOS): rename functions 2023-12-27 08:46:49 +08:00
李通洲 17d6f84850 Temps (macOS): update sensors of M2X 2023-12-27 08:45:02 +08:00
李通洲 0972eb6986 PhysicalDisk: detect temp 2023-12-26 19:57:24 +08:00
李通洲 0ee892f2de Disk (Linux): simplify impl of detecting partition removable 2023-12-26 18:58:05 +08:00
Carter Li b1f54ab7a2 Battery (Linux): fix temp detection for asahi 2023-12-26 16:44:13 +08:00
Carter Li 5a372882fa Battery (Linux): tidy 2023-12-26 16:44:13 +08:00
李通洲 16d34b6933 Doc: update changelog 2023-12-26 15:50:48 +08:00
李通洲 f319a80dc5 CPU (Linux): if we failed to detect the number of physical cores, assume all logical cores are physical 2023-12-26 13:40:41 +08:00
李通洲 60f5cc9079 CPU (Linux): don't print - 2023-12-26 13:34:58 +08:00
Carter Li dd3b3f22ba CPU (Linux): detect multi cpu models by lscpu
Supports asahi linux
2023-12-26 11:20:40 +08:00
Carter Li e672e40f8b GPU: detect devices by OpenGL
which works for asahi linux
2023-12-26 11:19:33 +08:00
李通洲 91089a7fe9 PhysicalDisk (Windows): init variables 2023-12-25 20:02:41 +08:00
李通洲 677f39420b PhysicalDisk: print product revision 2023-12-25 18:33:39 +08:00
李通洲 f2da8305c7 PhysicalDisk (Windows): detect revision 2023-12-25 18:22:04 +08:00
李通洲 060082885b PhysicalDisk: rename firmwareRev to revision 2023-12-25 18:21:23 +08:00
李通洲 3134a04b5c PhysicalDisk (Linux): don't append diskseq 2023-12-25 18:12:02 +08:00
李通洲 d3bcef61da PhysicalDisk (macOS): detect firmware revision 2023-12-25 16:40:59 +08:00
Carter Li b2cabd2af7 PhysicalDisk (Linux): detect firmware revision 2023-12-25 16:32:34 +08:00
Carter Li 5e85864ab0 PhysicalDisk (FreeBSD): detect read-only 2023-12-25 14:49:49 +08:00
李通洲 cb68dccd0e GPU (AMD): fix a silly bug 2023-12-25 14:47:12 +08:00
李通洲 3b6d5468da PhysicalDisk (macOS): detect read-only 2023-12-25 14:47:12 +08:00
李通洲 350388295d Doc: fix --help messages 2023-12-25 14:47:12 +08:00
apocelipes e7aa6c3757 fix(Battery): fix overflow and uninitializations of battery cycle counts 2023-12-25 06:45:47 +00:00
李通洲 c100e0dff7 PhysicalDisk (Windows): detect CDROMs; detect read-only 2023-12-24 23:27:57 +08:00
李通洲 02999ae4bf PhysicalDisk (Linux): detect readonly 2023-12-24 22:34:45 +08:00
李通洲 b5a01400e9 PhysicalDisk (Linux): detect more interconnect type 2023-12-24 22:31:36 +08:00
李通洲 ef8bd63075 PhysicalDisk (Linux): remove trailing spaces 2023-12-24 21:33:57 +08:00
李通洲 58e8403e16 Disk (Linux): be more careful to detect external type 2023-12-24 20:53:11 +08:00
李通洲 34b0bbac26 PhysicalDisk (Linux): be more careful to detect connection type 2023-12-24 20:52:05 +08:00
李通洲 97c6966939 Disk (Linux): detect subvolume first
Fix #674
2023-12-24 20:32:43 +08:00
李通洲 be38182ab2 Disk (WSL): fix Windows volume detection 2023-12-24 19:42:10 +08:00
李通洲 d2d4ee89d8 GPU (WSL): fix gpu temp detection for nvidia cards 2023-12-24 19:41:20 +08:00
apocelipes 113b1b8fc2 fix: fix trailing space 2023-12-23 02:55:14 +00:00
Carter Li cf98e6f5a1 Global: remove unexpected trailing line endings
Ref: https://github.com/fastfetch-cli/fastfetch/pull/671#issuecomment-1867777472
2023-12-23 00:19:50 +08:00
apocelipes e85a4b9ff5 refactor(IO): clean up ffAppendFDBuffer
for 2 reasons:

- Simplify the Code.
- ffAppendFDBuffer can't make assumptions about how the read data will
  be processed, so the trim calls are inappropriate.
2023-12-22 11:49:57 +00:00
FilippoULIVO b7935aa238 Update README.md 2023-12-22 11:06:00 +00:00
李通洲 a13520c5ff 3rdparty: remove unused types in amd_ags and make it complies in C
Ref: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/issues/48
2023-12-21 19:20:35 +08:00
李通洲 dfb0eecf86 3rdparty: add amd_ags 2023-12-21 18:52:38 +08:00
李通洲 c5695542b2 CI: generate sha256sum for source tarballs
Ref: https://github.com/ncipollo/release-action/issues/400
2023-12-21 10:31:25 +08:00
李通洲 a1d81b4964 fastfetch: fix compiler warnings 2023-12-21 09:52:20 +08:00
李通洲 72ed11ec9e 3rdparty: oops 2023-12-20 22:23:02 +08:00
李通洲 1c5179d3b0 GPU (Intel): actually detect real time clock frequency 2023-12-20 22:19:15 +08:00
李通洲 adc506d2b3 GPU: fix clock frequency detection and overall tidy 2023-12-20 19:13:00 +08:00
apocelipes b2236cc046 refactor(TerminalFont): use ffSearchUserConfigFile 2023-12-20 10:28:51 +00:00
apocelipes 3040bc38cb refactor(WMTheme): use ffSearchUserConfigFile 2023-12-20 10:28:51 +00:00
apocelipes b9368ac20d feature(IO): support searching user's config file from configDirs 2023-12-20 10:28:51 +00:00
Carter Li a4f5a9af03 Brightness (Linux): show meaningfull name on asahi 2023-12-20 16:44:30 +08:00
李通洲 f8be6322df GPU: rename use-nvml to driver-specific
Because we are supporting drivers other than NVML
2023-12-20 15:32:55 +08:00
李通洲 4a1bbb6a03 GPU: huge improvement of driver specific detection code 2023-12-20 14:45:27 +08:00
李通洲 961e9a6a5f GPU (Windows): detection with intel driver (WIP) 2023-12-20 00:49:56 +08:00
李通洲 2f4b210f33 CI: generate sha256sum 2023-12-19 18:48:38 +08:00
李通洲 456a58c8f5 fastfetch: default preset names to .jsonc
Fix #666
2023-12-19 18:48:38 +08:00
李通洲 b8b15c5170 Wifi (macOS): support most auth types 2023-12-19 18:48:38 +08:00
apocelipes 61485cb133 refactor(WMTheme): clean up detectOpenbox
Simplify the code and implement stricter checking of xml contents.
2023-12-19 08:31:57 +00:00
97 changed files with 9952 additions and 881 deletions
+35 -10
View File
@@ -132,7 +132,7 @@ jobs:
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
- name: upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux
path: ./fastfetch-*.*
@@ -188,7 +188,7 @@ jobs:
run: ctest
- name: upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos
path: ./fastfetch-*.*
@@ -204,7 +204,7 @@ jobs:
uses: actions/checkout@v4
- name: run VM
uses: cross-platform-actions/action@v0.21.1
uses: cross-platform-actions/action@master
with:
operating_system: freebsd
version: '13.2'
@@ -222,7 +222,7 @@ jobs:
ctest
- name: upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: fastfetch-freebsd
path: ./fastfetch-*.*
@@ -284,7 +284,7 @@ jobs:
run: 7z a -t7z -mx9 -bd -y fastfetch-$(./fastfetch --version-raw)-Win64.7z *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: fastfetch-win64
path: ./fastfetch-*-Win64.*
@@ -351,7 +351,7 @@ jobs:
run: 7z a -t7z -mx9 -bd -y fastfetch-$(./fastfetch --version-raw)-Win32.7z *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: fastfetch-win32
path: ./fastfetch-*-Win32.*
@@ -369,15 +369,16 @@ jobs:
permissions:
contents: write
steps:
- name: download artifacts
uses: actions/download-artifact@v3
- name: get latest release version
id: get_version_release
uses: pozetroninc/github-action-get-latest-release@master
with:
repository: ${{ github.repository }}
- name: download artifacts
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v4
- name: create release
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
@@ -385,4 +386,28 @@ jobs:
tag: ${{ needs.linux.outputs.ffversion }}
commit: ${{ github.sha }}
artifactErrorsFailBuild: true
artifacts: fastfetch-linux/*,fastfetch-macos/*,fastfetch-freebsd/*,fastfetch-win64/*,fastfetch-win32/*
artifacts: fastfetch-*/fastfetch-*
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux.outputs.ffversion }}/CHANGELOG.md) for details."
- name: download source tarballs
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
run: |
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
ls fastfetch-*/*
- name: generate release notes
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
run: |
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
echo -e "\n---\n\n<details><summary>SHA256SUMs</summary><br>\n\n\`\`\`" >> fastfetch-release-notes.md
sha256sum fastfetch-*/* >> fastfetch-release-notes.md
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
- name: update release body
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.linux.outputs.ffversion }}
commit: ${{ github.sha }}
bodyFile: fastfetch-release-notes.md
allowUpdates: true
+22
View File
@@ -1,3 +1,25 @@
# 2.5.0
Changes:
* `--gpu-use-nvml` has been renamed to `--gpu-driver-specific` due to using of `IGCL` and `AGS`
* We now detect external partitions more conservatively in Linux. USB partitions will not be detected as external always ( eg. The Linux kernel itself is installed in a USB drive )
Features:
* Support more authentication type detection for macOS Sonoma (Wifi, macOS)
* Default preset names to `.jsonc`. For example, `fastfetch -c all` will load `presets/all.jsonc` (#666)
* Use Intel Graphics Control Library (IGCL) to detect more GPU information. Windows only (GPU, Windows)
* Improve support of Asahi Linux (Brightness / CPU / GPU / Disk, Linux)
* Support more properties of physical disks (PhysicalDisk)
* Support SSD temperature detection with `--physicaldisk-temp` (PhysicalDisk)
* Support partition label detection (Disk, FreeBSD)
* Support platform specific graphic API version detection (GPU, macOS / Windows)
Bugfixes:
* Fix Windows partition detection for WSL2 (Linux, Disk)
* Fix Btrfs subvolumes being detected as external partitions some times (Linux, Disk)
* Fix battery cycle counts in some places (Battery)
* Fix CodeWhisperer compatibility (#676, Terminal, macOS)
# 2.4.0
**We are deprecating flags based config files (will be removed in v3.0.0). We suggest you migrate to json based config files.** One may use `-c /path/to/config.conf --gen-config` to migrate existing flag based config files.
+5 -1
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.4.0
VERSION 2.5.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -575,6 +575,7 @@ elseif(APPLE)
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/lm/lm_nosupport.c
src/detection/icons/icons_nosupport.c
@@ -630,6 +631,8 @@ elseif(WIN32)
src/detection/font/font_windows.c
src/detection/gpu/gpu_windows.c
src/detection/gpu/gpu_nvidia.c
src/detection/gpu/gpu_intel.c
src/detection/gpu/gpu_amd.c
src/detection/host/host_windows.c
src/detection/icons/icons_windows.c
src/detection/libc/libc_windows.cpp
@@ -903,6 +906,7 @@ elseif(APPLE)
PRIVATE "-framework CoreWLAN"
PRIVATE "-framework IOBluetooth"
PRIVATE "-framework IOKit"
PRIVATE "-framework Metal"
PRIVATE "-framework OpenGL"
PRIVATE "-framework OpenCL"
PRIVATE "-framework SystemConfiguration"
+5 -1
View File
@@ -27,10 +27,14 @@ There are [screenshots on different platforms](https://github.com/fastfetch-cli/
### Linux
* Debian / Ubuntu: Download `fastfetch-<version>-Linux.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and `sudo apt install fastfetch-<version>-Linux.deb`
* Debian / Ubuntu: Download `fastfetch-<version>-Linux.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and `dpkg -i fastfetch-<version>-Linux.deb`
* Arch Linux: `sudo pacman -S fastfetch`
* Fedora: `sudo dnf install fastfetch`
* Gentoo: `sudo emerge --ask app-misc/fastfetch`
* NixOS: `sudo nix-shell -p fastfetch`
* openSUSE: `sudo zypper install fastfetch`
Replace sudo with doas depending on what you use.
[See also if fastfetch has been packaged for your favorite Linux distro](#Packaging)
+7 -2
View File
@@ -1191,8 +1191,8 @@
"type": "boolean",
"default": false
},
"useNvml": {
"description": "Use nvml (NVIDIA Management Library) to detect more detailed GPU information (memory usage, CUDA core count, etc)",
"driverSpecific": {
"description": "Use driver specific method to detect more detailed GPU information (memory usage, core count, etc)",
"type": "boolean",
"default": false
},
@@ -1381,6 +1381,11 @@
"description": "Show disks with given name prefix only",
"type": "string"
},
"temp": {
"description": "Detect and display SSD temperature if supported",
"type": "boolean",
"default": false
},
"key": {
"$ref": "#/$defs/key"
},
+383
View File
@@ -0,0 +1,383 @@
//
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
/// \file
/// \mainpage
/// AGS Library Overview
/// --------------------
/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query
/// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs.
///
/// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/.
/// It is also worth checking http://gpuopen.com/gaming-product/amd-gpu-services-ags-library/ for any updates and articles on AGS.
/// \internal
/// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/
/// \endinternal
///
/// ---------------------------------------
/// What's new in AGS 6.2 since version 6.1
/// ---------------------------------------
/// AGS 6.2 includes the following updates:
/// * Shader clock intrinsics
/// * Minor improvements and fixes
///
/// ---------------------------------------
/// What's new in AGS 6.1 since version 6.0
/// ---------------------------------------
/// AGS 6.1 includes the following updates:
/// * RDNA3 detection
///
/// ---------------------------------------
/// What's new in AGS 6.0 since version 5.4.2
/// ---------------------------------------
/// AGS 6.0 includes the following updates:
/// * DX12 ray tracing hit token for RDNA2 hardware.
/// * Shader intrinsic that exposes ReadLaneAt in DX12.
/// * Shader intrinsics that expose explicit float conversions in DX12.
/// * Refactored and revised API to minimize user error.
/// * Added agsGetVersionNumber.
/// * Detection for external GPUs.
/// * Detection of RDNA2 architecture.
/// * Grouped the more established intrinsics together into per year support.
/// * Function pointer typedefs for the API
///
/// ---------------------------------------
/// What's new in AGS 5.4.2 since version 5.4.1
/// ---------------------------------------
/// AGS 5.4.2 includes the following updates:
/// * sharedMemoryInBytes has been reinstated.
/// * Clock speed returned for APUs.
///
/// ---------------------------------------
/// What's new in AGS 5.4.1 since version 5.4.0
/// ---------------------------------------
/// AGS 5.4.1 includes the following updates:
/// * AsicFamily_Count to help with code maintenance.
/// * Visual Studio 2019 support.
/// * x86 support
/// * BaseInstance and BaseVertex intrinsics along with corresponding caps bits.
/// * GetWaveSize intrinsic along with corresponding caps bits.
///
/// ---------------------------------------
/// What's new in AGS 5.4 since version 5.3
/// ---------------------------------------
/// AGS 5.4 includes the following updates:
/// * A more detailed description of the GPU architecture, now including RDNA GPUs.
/// * Radeon 7 core and memory speeds returned.
/// * Draw index and Atomic U64 intrinsics for both DX11 and DX12.
///
/// ---------------------------------------
/// What's new in AGS 5.3 since version 5.2
/// ---------------------------------------
/// AGS 5.3 includes the following updates:
/// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions.
/// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements.
/// * Freesync HDR Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync HDR scRGB.
///
/// Using the AGS library
/// ---------------------
/// It is recommended to take a look at the source code for the samples that come with the AGS SDK:
/// * AGSSample
/// * CrossfireSample
/// * EyefinitySample
/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state.
/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more
/// extensive example of Eyefinity setup than the basic example provided in AGSSample.
/// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples.
///
/// To add AGS support to an existing project, follow these steps:
/// * Link your project against the correct import library. Choose from either the 32 bit or 64 bit version.
/// * Copy the AGS dll into the same directory as your game executable.
/// * Include the amd_ags.h header file from your source code.
/// * Include the AGS hlsl files if you are using the shader intrinsics.
/// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS.
/// * On game initialization, call \ref agsInitialize passing in the address of the context. On success, this function will return a valid context pointer.
///
/// Don't forget to cleanup AGS by calling \ref agsDeInitialize when the app exits, after the device has been destroyed.
#ifndef AMD_AGS_H
#define AMD_AGS_H
#define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version
#define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version
#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version
#ifdef __cplusplus
extern "C" {
#endif
/// \defgroup Defines AGS defines
/// @{
#if defined (AGS_GCC)
#define AMD_AGS_API
#else
#define AMD_AGS_API __declspec(dllexport) ///< AGS exported functions
#endif
#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version
#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version
#define AGS_CURRENT_VERSION AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ) ///< Macro to return the current AGS version as defined by the AGS header file
/// @}
/// \defgroup enums General enumerations
/// @{
/// The return codes
typedef enum AGSReturnCode
{
AGS_SUCCESS, ///< Successful function call
AGS_FAILURE, ///< Failed to complete call for some unspecified reason
AGS_INVALID_ARGS, ///< Invalid arguments into the function
AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally
AGS_MISSING_D3D_DLL, ///< Returned when a D3D dll fails to load
AGS_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver
AGS_NO_AMD_DRIVER_INSTALLED, ///< Returned if the AMD GPU driver does not appear to be installed
AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension
AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library)
AGS_DX_FAILURE, ///< Failure from DirectX runtime
AGS_D3DDEVICE_NOT_CREATED ///< Failure due to not creating the D3D device successfully via AGS.
} AGSReturnCode;
/// @}
typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInitialize
/// The rectangle struct used by AGS.
typedef struct AGSRect
{
int offsetX; ///< Offset on X axis
int offsetY; ///< Offset on Y axis
int width; ///< Width of rectangle
int height; ///< Height of rectangle
} AGSRect;
/// The display info struct used to describe a display enumerated by AGS
typedef struct AGSDisplayInfo
{
char name[ 256 ]; ///< The name of the display
char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName
unsigned int isPrimaryDisplay : 1; ///< Whether this display is marked as the primary display
unsigned int HDR10 : 1; ///< HDR10 is supported on this display
unsigned int dolbyVision : 1; ///< Dolby Vision is supported on this display
unsigned int freesync : 1; ///< Freesync is supported on this display
unsigned int freesyncHDR : 1; ///< Freesync HDR is supported on this display
unsigned int eyefinityInGroup : 1; ///< The display is part of the Eyefinity group
unsigned int eyefinityPreferredDisplay : 1; ///< The display is the preferred display in the Eyefinity group for displaying the UI
unsigned int eyefinityInPortraitMode : 1; ///< The display is in the Eyefinity group but in portrait mode
unsigned int reservedPadding : 24; ///< Reserved for future use
int maxResolutionX; ///< The maximum supported resolution of the unrotated display
int maxResolutionY; ///< The maximum supported resolution of the unrotated display
float maxRefreshRate; ///< The maximum supported refresh rate of the display
AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation
AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will
///< be the sub region in the Eyefinity single large surface (SLS)
float currentRefreshRate; ///< The current refresh rate
int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group
int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group
double chromaticityRedX; ///< Red display primary X coord
double chromaticityRedY; ///< Red display primary Y coord
double chromaticityGreenX; ///< Green display primary X coord
double chromaticityGreenY; ///< Green display primary Y coord
double chromaticityBlueX; ///< Blue display primary X coord
double chromaticityBlueY; ///< Blue display primary Y coord
double chromaticityWhitePointX; ///< White point X coord
double chromaticityWhitePointY; ///< White point Y coord
double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1
double screenSpecularReflectance; ///< Percentage expressed between 0 - 1
double minLuminance; ///< The minimum luminance of the display in nits
double maxLuminance; ///< The maximum luminance of the display in nits
double avgLuminance; ///< The average luminance of the display in nits
int logicalDisplayIndex; ///< The internally used index of this display
int adlAdapterIndex; ///< The internally used ADL adapter index
int reserved; ///< reserved field
} AGSDisplayInfo;
/// The ASIC family
typedef enum AsicFamily
{
AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId
AsicFamily_PreGCN, ///< Pre GCN architecture.
AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti.
AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo.
AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji.
AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris.
AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU).
AsicFamily_RDNA, ///< AMD RDNA architecture
AsicFamily_RDNA2, ///< AMD RDNA2 architecture
AsicFamily_RDNA3, ///< AMD RDNA3 architecture
AsicFamily_Count ///< Number of enumerated ASIC families
} AsicFamily;
/// The device info struct used to describe a physical GPU enumerated by AGS
typedef struct AGSDeviceInfo
{
const char* adapterString; ///< The adapter name string
AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware
unsigned int isAPU : 1; ///< Whether this device is an APU
unsigned int isPrimaryDevice : 1; ///< Whether this device is marked as the primary device
unsigned int isExternal :1; ///< Whether this device is a detachable, external device
unsigned int reservedPadding : 29; ///< Reserved for future use
int vendorId; ///< The vendor id
int deviceId; ///< The device id
int revisionId; ///< The revision id
int numCUs; ///< Number of compute units
int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards.
int numROPs; ///< Number of ROPs
int coreClock; ///< Core clock speed at 100% power in MHz
int memoryClock; ///< Memory clock speed at 100% power in MHz
int memoryBandwidth; ///< Memory bandwidth in MB/s
float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD
unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware.
unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs
///< as the reported local memory will only be a small fraction of the total memory available to the GPU.
int numDisplays; ///< The number of active displays found to be attached to this adapter.
AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length.
int eyefinityEnabled; ///< Indicates if Eyefinity is active
int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface.
int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface.
int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface.
int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface.
int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled.
int adlAdapterIndex; ///< Internally used index into the ADL list of adapters
int reserved; ///< reserved field
} AGSDeviceInfo;
/// \defgroup general General API functions
/// API for initialization, cleanup, HDR display modes and Crossfire GPU count
/// @{
typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype
typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype
/// The configuration options that can be passed in to \ref agsInitialize
typedef struct AGSConfiguration
{
AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used
AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used
} AGSConfiguration;
/// The top level GPU information returned from \ref agsInitialize
typedef struct AGSGPUInfo
{
const char* driverVersion; ///< The AMD driver package version
const char* radeonSoftwareVersion; ///< The Radeon Software Version
int numDevices; ///< Number of GPUs in the system
AGSDeviceInfo* devices; ///< List of GPUs in the system
} AGSGPUInfo;
/// The struct to specify the display settings to the driver.
typedef struct AGSDisplaySettings AGSDisplaySettings;
/// The result returned from \ref agsCheckDriverVersion
typedef enum AGSDriverVersionResult
{
AGS_SOFTWAREVERSIONCHECK_OK, ///< The reported Radeon Software Version is newer or the same as the required version
AGS_SOFTWAREVERSIONCHECK_OLDER, ///< The reported Radeon Software Version is older than the required version
AGS_SOFTWAREVERSIONCHECK_UNDEFINED ///< The check could not determine as result. This could be because it is a private or custom driver or just invalid arguments.
} AGSDriverVersionResult;
///
/// Helper function to check the installed software version against the required software version.
///
/// \param [in] radeonSoftwareVersionReported The Radeon Software Version returned from \ref AGSGPUInfo::radeonSoftwareVersion.
/// \param [in] radeonSoftwareVersionRequired The Radeon Software Version to check against. This is specificed using \ref AGS_MAKE_VERSION.
/// \return The result of the check.
///
AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired );
///
/// Function to return the AGS version number.
///
/// \return The version number made using AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ).
///
AMD_AGS_API int agsGetVersionNumber();
///
/// Function used to initialize the AGS library.
/// agsVersion must be specified as AGS_CURRENT_VERSION or the call will return \ref AGS_INVALID_ARGS.
/// Must be called prior to any of the subsequent AGS API calls.
/// Must be called prior to ID3D11Device or ID3D12Device creation.
/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInitialize if there is an AMD GPU present.
/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system.
/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20.
///
/// \param [in] agsVersion The API version specified using the \ref AGS_CURRENT_VERSION macro. If this does not match the version in the binary this initialization call will fail.
/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration.
/// \param [out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls.
/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system.
///
AMD_AGS_API AGSReturnCode agsInitialize( int agsVersion, const AGSConfiguration* config, AGSContext** context, AGSGPUInfo* gpuInfo );
///
/// Function used to clean up the AGS library.
///
/// \param [in] context Pointer to a context. This function will deallocate the context from the heap.
///
AMD_AGS_API AGSReturnCode agsDeInitialize( AGSContext* context );
///
/// Function used to set a specific display into HDR mode
/// \note Setting all of the values apart from color space and transfer function to zero will cause the display to use defaults.
/// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc).
/// \note HDR10 PQ mode requires a 1010102 swapchain.
/// \note HDR10 scRGB mode requires an FP16 swapchain.
/// \note Freesync HDR scRGB mode requires an FP16 swapchain.
/// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain.
/// \note Dolby Vision requires a 8888 UNORM swapchain.
///
/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize
/// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices.
/// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays.
/// \param [in] settings Pointer to the display settings to use.
///
AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceIndex, int displayIndex, const AGSDisplaySettings* settings );
/// @}
/// @}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AMD_AGS_H
+7
View File
@@ -0,0 +1,7 @@
{
"home": "https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK",
"license": "MIT (embeded in source)",
"version": "AGS v6.2.0",
"author": "Advanced Micro Devices, Inc",
"modified": "CarterLi"
}
+27
View File
@@ -0,0 +1,27 @@
Intel Software License Agreement
10.07.21
Use and Redistribution. You may use and redistribute Intels Control API software and the header files for the Intel® Graphics Control Library (collectively, the “Software”), solely for use on Intel platforms, provided the following conditions are met:
* Redistributions must reproduce the above copyright notice and the following terms of use in the Software and in the documentation and/or other materials provided with the distribution.
* Neither the name of Intel nor the names of its suppliers may be used to endorse or promote products derived from this Software without specific prior written permission.
* No reverse engineering, decompilation, or disassembly of Software provided to you in binary form is permitted.
Third Party Software. The Software may contain Third Party Software. “Third Party Software” is third party software, open source software or other Intel software listed in the “third-party-software.txt” or other similarly named text file that is included with the Software. Third Party Software, even if included with the distribution of the Software, may be governed by separate license terms, including without limitation, third party license terms, open source software notices and terms, and/or other Intel software license terms. These separate license terms solely govern your use of the Third Party Software.
Ownership. Title to the Software and all copies remain with Intel or its suppliers.
DISCLAIMER. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. THIS SOFTWARE IS NOT INTENDED FOR USE IN SYSTEMS OR APPLICATIONS WHERE FAILURE OF THE SOFTWARE MAY CAUSE PERSONAL INJURY OR DEATH AND YOU AGREE THAT YOU ARE FULLY RESPONSIBLE FOR ANY CLAIMS, COSTS, DAMAGES, EXPENSES, AND ATTORNEYS FEES ARISING OUT OF ANY SUCH USE, EVEN IF ANY CLAIM ALLEGES THAT INTEL WAS NEGLIGENT REGARDING THE DESIGN OR MANUFACTURE OF THE SOFTWARE.
LIMITATION OF LIABILITY; INDEMNITY. IN NO EVENT WILL INTEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. YOU AGREE TO INDEMNIFY, DEFEND, AND HOLD INTEL HARMLESS AGAINST ANY CLAIMS, DAMAGES, AND EXPENSES RESULTING FROM YOUR USE OR UNAUTHORIZED USE OF THE SOFTWARE.
No support. Intel may make changes to the Software, at any time without notice, and is not obligated to support, update or provide training for the Software.
Termination. Your right to use the Software is terminated immediately in the event of your breach of this agreement.
Feedback. Should you provide Intel with comments, modifications, corrections, enhancements or other input (“Feedback”) related to the Software Intel will be free to use, disclose, reproduce, license or otherwise distribute or exploit the Feedback in its sole discretion without any obligations or restrictions of any kind, including without limitation, intellectual property rights or licensing obligations.
Compliance with laws. You agree to comply with all applicable laws and regulations governing your use, transfer, import or export (or prohibition thereof) of the Software.
Governing law. All disputes will be governed by the laws of the United States of America and the State of Delaware without reference to conflict of law principles and subject to the exclusive jurisdiction of the state or federal courts sitting in the State of Delaware, and each party agrees that it submits to the personal jurisdiction and venue of those courts and waives any objections. The United Nations Convention on Contracts for the International Sale of Goods (1980) is specifically excluded and will not apply to the Software.
Severability. The parties intend that if a court holds that any provision of this agreement is invalid or unenforceable under applicable law, the court will modify the provision to the minimum extent necessary to make it valid and enforceable or sever and delete the provision from this agreement. Any change to or deletion of a provision of this agreement under this Section will not affect the validity or enforceability of the remainder of this agreement, which will continue in full force and effect.
+7649
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
{
"home": "https://github.com/intel/drivers.gpu.control-library",
"license": "./LICENSE",
"version": "e1776b7be2ceead1296204371447b27860d25a66",
"author": "Intel Corporation"
}
+18 -7
View File
@@ -12,6 +12,22 @@ void ffFontInit(FFfont* font)
ffListInit(&font->styles, sizeof(FFstrbuf));
}
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
{
if(value == NULL || length == 0)
return;
ffStrbufEnsureFree(strbuf, length);
for(uint32_t i = 0; i < length; i++)
{
if(value[i] != exclude)
strbuf->chars[strbuf->length++] = value[i];
}
strbuf->chars[strbuf->length] = '\0';
}
static void fontInitPretty(FFfont* font)
{
ffStrbufAppend(&font->pretty, &font->name);
@@ -155,7 +171,7 @@ static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* altern
ffStrbufInit(alternativeBuffer);
}
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
if(
strncasecmp(wordStart, "Ultra ", 6) == 0 ||
@@ -171,7 +187,7 @@ static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* altern
if(alternativeBuffer != NULL)
{
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
return;
}
@@ -200,11 +216,6 @@ void ffFontInitValues(FFfont* font, const char* name, const char* size)
fontInitPretty(font);
}
void ffFontInitCopy(FFfont* font, const char* name)
{
ffFontInitValues(font, name, NULL);
}
void ffFontInitWithSpace(FFfont* font, const char* rawName)
{
const char* pspace = strrchr(rawName, ' ');
+5 -1
View File
@@ -14,7 +14,11 @@ typedef struct FFfont
void ffFontInit(FFfont* font);
void ffFontInitQt(FFfont* font, const char* data);
void ffFontInitPango(FFfont* font, const char* data);
void ffFontInitCopy(FFfont* font, const char* name);
void ffFontInitValues(FFfont* font, const char* name, const char* size);
void ffFontInitWithSpace(FFfont* font, const char* rawName);
void ffFontDestroy(FFfont* font);
static inline void ffFontInitCopy(FFfont* font, const char* name)
{
ffFontInitValues(font, name, NULL);
}
+16
View File
@@ -1,6 +1,7 @@
#pragma once
#include "util/FFstrbuf.h"
#include "util/FFlist.h"
#ifdef _WIN32
#include <fileapi.h>
@@ -185,3 +186,18 @@ static inline bool wrapClosedir(HANDLE* pdir)
}
#endif
#define FF_AUTO_CLOSE_DIR __attribute__((__cleanup__(wrapClosedir)))
static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result)
{
// configDirs is a list of FFstrbufs include the trailing slash
FF_LIST_FOR_EACH(FFstrbuf, dir, *configDirs)
{
ffStrbufClear(result);
ffStrbufAppend(result, dir);
ffStrbufAppendS(result, fileSubpath);
if (ffPathExists(result->chars, FF_PATHTYPE_FILE))
return true;
}
return false;
}
+29 -29
View File
@@ -47,46 +47,46 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
return write(fd, data, dataSize) > 0;
}
static inline void readWithLength(int fd, FFstrbuf* buffer, uint32_t length)
{
ffStrbufEnsureFixedLengthFree(buffer, length);
ssize_t bytesRead = 0;
while(
length > 0 && (bytesRead = read(fd, buffer->chars + buffer->length, length)) > 0
) {
buffer->length += (uint32_t) bytesRead;
length -= (uint32_t) bytesRead;
}
}
static inline void readUntilEOF(int fd, FFstrbuf* buffer)
{
ffStrbufEnsureFree(buffer, 31);
uint32_t available = ffStrbufGetFree(buffer);
ssize_t bytesRead = 0;
while(
(bytesRead = read(fd, buffer->chars + buffer->length, available)) > 0
) {
buffer->length += (uint32_t) bytesRead;
if((uint32_t) bytesRead == available)
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
available = ffStrbufGetFree(buffer);
}
}
bool ffAppendFDBuffer(int fd, FFstrbuf* buffer)
{
ssize_t bytesRead = 0;
struct stat fileInfo;
if(fstat(fd, &fileInfo) != 0)
return false;
if (fileInfo.st_size > 0)
{
// optimize for files has a fixed length,
// file can be very large, only keep necessary memory to save time and resources.
ffStrbufEnsureFixedLengthFree(buffer, (uint32_t)fileInfo.st_size);
}
readWithLength(fd, buffer, (uint32_t)fileInfo.st_size);
else
ffStrbufEnsureFree(buffer, 31);
uint32_t free = ffStrbufGetFree(buffer);
// procfs file's st_size is always zero
// choose a signed int type so that can store a native number
ssize_t remain = fileInfo.st_size;
while(
(bytesRead = read(fd, buffer->chars + buffer->length, free)) > 0
) {
buffer->length += (uint32_t) bytesRead;
// if remain > 0, it means there is some data left in the file.
// if remain == 0, it means reading has completed, no need to grow up the buffer.
// if remain < 0, we are reading a file from procfs/sysfs and its st_size is zero,
// we cannot detect how many data remains in the file, we only can call ffStrbufEnsureFree and read again.
remain -= bytesRead;
if((uint32_t) bytesRead == free && remain != 0)
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
free = ffStrbufGetFree(buffer);
}
readUntilEOF(fd, buffer);
buffer->chars[buffer->length] = '\0';
ffStrbufTrimRight(buffer, '\n');
ffStrbufTrimRight(buffer, ' ');
return buffer->length > 0;
}
+33 -26
View File
@@ -35,43 +35,50 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
return !!WriteFile(handle, data, (DWORD)dataSize, &written, NULL);
}
static inline void readWithLength(HANDLE handle, FFstrbuf* buffer, uint32_t length)
{
ffStrbufEnsureFixedLengthFree(buffer, length);
DWORD bytesRead = 0;
while(
length > 0 &&
ReadFile(handle, buffer->chars + buffer->length, length, &bytesRead, NULL) != FALSE &&
bytesRead > 0
) {
buffer->length += (uint32_t) bytesRead;
length -= (uint32_t) bytesRead;
}
}
static inline void readUntilEOF(HANDLE handle, FFstrbuf* buffer)
{
ffStrbufEnsureFree(buffer, 31);
uint32_t available = ffStrbufGetFree(buffer);
DWORD bytesRead = 0;
while(
ReadFile(handle, buffer->chars + buffer->length, available, &bytesRead, NULL) != FALSE &&
bytesRead > 0
) {
buffer->length += (uint32_t) bytesRead;
if((uint32_t) bytesRead == available)
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
available = ffStrbufGetFree(buffer);
}
}
bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer)
{
DWORD bytesRead = 0;
LARGE_INTEGER fileSize;
if(!GetFileSizeEx(handle, &fileSize))
fileSize.QuadPart = 0;
if (fileSize.QuadPart > 0)
{
// optimize for files has a fixed length,
// file can be very large, only keep necessary memory to save time and resources.
ffStrbufEnsureFixedLengthFree(buffer, (uint32_t)fileSize.QuadPart);
}
readWithLength(handle, buffer, (uint32_t)fileSize.QuadPart);
else
ffStrbufEnsureFree(buffer, 31);
uint32_t free = ffStrbufGetFree(buffer);
ssize_t remain = fileSize.QuadPart;
bool success;
while(
(success = !!ReadFile(handle, buffer->chars + buffer->length, free, &bytesRead, NULL)) &&
bytesRead > 0
) {
buffer->length += (uint32_t) bytesRead;
remain -= (ssize_t)bytesRead;
if((uint32_t) bytesRead == free && remain != 0)
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
free = ffStrbufGetFree(buffer);
}
readUntilEOF(handle, buffer);
buffer->chars[buffer->length] = '\0';
ffStrbufTrimRight(buffer, '\n');
ffStrbufTrimRight(buffer, ' ');
return success;
return buffer->length > 0;
}
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
+24 -21
View File
@@ -7,22 +7,18 @@
static LPFN_CONNECTEX ConnectEx;
static BOOL WINAPI initWsaData(PINIT_ONCE once, PVOID param, PVOID* context)
static const char* initWsaData(WSADATA* wsaData)
{
(void)once;
(void)param;
static WSADATA wsaData;
*context = &wsaData;
if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
return FALSE;
if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0)
return "WSAStartup() failed";
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
return FALSE;
if(LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2)
return "Invalid wsaData version found";
//Dummy socket needed for WSAIoctl
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == INVALID_SOCKET)
return FALSE;
return "socket(AF_INET, SOCK_STREAM) failed";
DWORD dwBytes;
GUID guid = WSAID_CONNECTEX;
@@ -30,28 +26,35 @@ static BOOL WINAPI initWsaData(PINIT_ONCE once, PVOID param, PVOID* context)
&guid, sizeof(guid),
&ConnectEx, sizeof(ConnectEx),
&dwBytes, NULL, NULL) != 0)
return FALSE;
return "WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed";
return closesocket(sockfd) == 0;
closesocket(sockfd);
return NULL;
}
bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
WSADATA* pData;
if(!InitOnceExecuteOnce(&once, initWsaData, NULL, (LPVOID*) &pData))
static WSADATA wsaData;
if (wsaData.wVersion == 0)
{
if (initWsaData(&wsaData) != NULL)
{
wsaData.wVersion = (WORD) -1;
return false;
}
}
else if (wsaData.wVersion == (WORD) -1)
return false;
memset(state, 0, sizeof(*state));
struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo* addr;
if(getaddrinfo(host, "80", &hints, &addr) != 0)
if(getaddrinfo(host, "80", &(struct addrinfo) {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
}, &addr) != 0)
return false;
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+13 -4
View File
@@ -82,7 +82,7 @@
}
}
],
"pseudo": [
"General": [
{
"long": "thread",
"desc": "Use separate threads to send HTTP requests",
@@ -954,6 +954,15 @@
"type": "str"
}
},
{
"long": "physicaldisk-temp",
"desc": "Detect and display SSD temperature if supported",
"arg": {
"type": "bool",
"optional": true,
"default": false
}
},
{
"long": "bluetooth-show-disconnected",
"desc": "Set if disconnected bluetooth devices should be printed",
@@ -1082,9 +1091,9 @@
}
},
{
"long": "gpu-use-nvml",
"desc": "Use nvml (NVIDIA Management Library) to detect more detailed GPU information",
"remark": "Detects memory usage, CUDA core count, etc. Requires NVIDIA proprietary driver installed",
"long": "gpu-driver-specific",
"desc": "Use driver specific method to detect more detailed GPU information (memory usage, core count, etc)",
"remark": "Correctly NVML (NVIDIA) and IGCL (Intel, Windows only) are supported. Both require the latest proprietary driver to be installed",
"arg": {
"type": "bool",
"optional": true,
+1
View File
@@ -71,6 +71,7 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
FFBatteryResult* battery = ffListAdd(results);
battery->temperature = FF_BATTERY_TEMP_UNSET;
battery->cycleCount = 0;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
+4 -2
View File
@@ -56,7 +56,9 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
ffStrbufAppendS(&battery->modelName, "Built-in");
}
ffCfDictGetInt(properties, CFSTR("CycleCount"), (int32_t*) &battery->cycleCount);
int32_t cycleCount = 0;
ffCfDictGetInt(properties, CFSTR("CycleCount"), &cycleCount);
battery->cycleCount = cycleCount < 0 ? 0 : (uint32_t) cycleCount;
if (!ffCfDictGetBool(properties, CFSTR("ExternalConnected"), &boolValue) && boolValue)
ffStrbufAppendS(&battery->status, "AC connected, ");
@@ -75,7 +77,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
if (!ffCfDictGetInt64(properties, CFSTR("Temperature"), &temp))
battery->temperature = (double) temp / 10 - 273.15;
else
ffDetectCoreTemps(FF_TEMP_BATTERY, &battery->temperature);
ffDetectSmcTemps(FF_TEMP_BATTERY, &battery->temperature);
}
IOObjectRelease(registryEntry);
+16 -13
View File
@@ -14,6 +14,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
//type must exist and be "Battery"
ffStrbufAppendS(dir, "/type");
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
ffStrbufTrimRightSpace(&testBatteryBuffer);
ffStrbufSubstrBefore(dir, dirLength);
if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Battery") != 0)
@@ -22,6 +23,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
//scope may not exist or must not be "Device"
ffStrbufAppendS(dir, "/scope");
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
ffStrbufTrimRightSpace(&testBatteryBuffer);
ffStrbufSubstrBefore(dir, dirLength);
if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Device") == 0)
@@ -48,28 +50,37 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
ffStrbufInit(&result->manufacturer);
ffStrbufAppendS(dir, "/manufacturer");
ffReadFileBuffer(dir->chars, &result->manufacturer);
ffStrbufTrimRightSpace(&result->manufacturer);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->modelName);
ffStrbufAppendS(dir, "/model_name");
ffReadFileBuffer(dir->chars, &result->modelName);
ffStrbufTrimRightSpace(&result->modelName);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->technology);
ffStrbufAppendS(dir, "/technology");
ffReadFileBuffer(dir->chars, &result->technology);
ffStrbufTrimRightSpace(&result->technology);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->status);
ffStrbufAppendS(dir, "/status");
ffReadFileBuffer(dir->chars, &result->status);
ffStrbufTrimRightSpace(&result->status);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufAppendS(dir, "/cycle_count");
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
ffStrbufTrimRightSpace(&testBatteryBuffer);
ffStrbufSubstrBefore(dir, dirLength);
if(dir->length)
result->cycleCount = (uint32_t) ffStrbufToUInt(&testBatteryBuffer, 0);
if (dir->length)
{
int64_t cycleCount = 0;
cycleCount = (int64_t) strtoll(testBatteryBuffer.chars, NULL, 10);
result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount;
}
result->temperature = FF_BATTERY_TEMP_UNSET;
if (options->temp)
@@ -78,7 +89,7 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
FF_LIST_FOR_EACH(FFTempValue, value, *tempsResult)
{
if (ffStrbufEqualS(&value->name, id))
if (ffStrbufEqualS(&value->deviceName, id))
{
result->temperature = value->value;
break;
@@ -90,16 +101,8 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
{
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);
if(options->dir.length > 0)
{
ffStrbufAppend(&baseDir, &options->dir);
ffStrbufEnsureEndsWithC(&baseDir, '/');
}
else
{
ffStrbufAppendS(&baseDir, "/sys/class/power_supply/");
}
ffStrbufAppend(&baseDir, &options->dir);
ffStrbufEnsureEndsWithC(&baseDir, '/');
uint32_t baseDirLength = baseDir.length;
+1 -1
View File
@@ -150,7 +150,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->technology);
ffStrbufInit(&battery->status);
battery->temperature = 0.0/0.0;
battery->temperature = FF_BATTERY_TEMP_UNSET;
battery->cycleCount = 0;
battery->capacity = info.RemainingCapacity * 100.0 / info.MaxCapacity;
+5 -18
View File
@@ -4,25 +4,12 @@
#include <stdlib.h>
static void getSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
const char* ffDetectBios(FFBiosResult* bios)
{
ffReadFileBuffer(devicesPath, buffer);
if(ffIsSmbiosValueSet(buffer))
return;
ffReadFileBuffer(classPath, buffer);
if(ffIsSmbiosValueSet(buffer))
return;
ffStrbufClear(buffer);
}
const char* ffDetectBios(FFBiosResult* bios)
{
getSmbiosValue("/sys/devices/virtual/dmi/id/bios_date", "/sys/class/dmi/id/bios_date", &bios->date);
getSmbiosValue("/sys/devices/virtual/dmi/id/bios_release", "/sys/class/dmi/id/bios_release", &bios->release);
getSmbiosValue("/sys/devices/virtual/dmi/id/bios_vendor", "/sys/class/dmi/id/bios_vendor", &bios->vendor);
getSmbiosValue("/sys/devices/virtual/dmi/id/bios_version", "/sys/class/dmi/id/bios_version", &bios->version);
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 (ffPathExists("/sys/firmware/efi", FF_PATHTYPE_DIRECTORY) || ffPathExists("/sys/firmware/acpi/tables/UEFI", FF_PATHTYPE_FILE))
ffStrbufSetStatic(&bios->type, "UEFI");
else
+3 -16
View File
@@ -4,23 +4,10 @@
#include <stdlib.h>
static void getSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
{
ffReadFileBuffer(devicesPath, buffer);
if(ffIsSmbiosValueSet(buffer))
return;
ffReadFileBuffer(classPath, buffer);
if(ffIsSmbiosValueSet(buffer))
return;
ffStrbufClear(buffer);
}
const char* ffDetectBoard(FFBoardResult* board)
{
getSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name);
getSmbiosValue("/sys/devices/virtual/dmi/id/board_vendor", "/sys/class/dmi/id/board_vendor", &board->vendor);
getSmbiosValue("/sys/devices/virtual/dmi/id/board_version", "/sys/class/dmi/id/board_version", &board->version);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_vendor", "/sys/class/dmi/id/board_vendor", &board->vendor);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_version", "/sys/class/dmi/id/board_version", &board->version);
return NULL;
}
+2 -2
View File
@@ -58,9 +58,9 @@ static const char* detectWithBacklight(FFlist* result)
{
ffStrbufSubstrBeforeLastC(&brightness->name, '/'); // remove "/edid"
ffStrbufSubstrAfterLastC(&brightness->name, '/'); // try getting DRM connector name
if(ffStrbufStartsWithS(&brightness->name, "0000:"))
if(isdigit(brightness->name.chars[0]))
{
// PCI address, give up
// PCI address or some unknown path, give up
ffStrbufSetS(&brightness->name, entry->d_name);
}
else
+3 -16
View File
@@ -4,24 +4,11 @@
#include <stdlib.h>
static void getSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
{
ffReadFileBuffer(devicesPath, buffer);
if(ffIsSmbiosValueSet(buffer))
return;
ffReadFileBuffer(classPath, buffer);
if(ffIsSmbiosValueSet(buffer))
return;
ffStrbufClear(buffer);
}
const char* ffDetectChassis(FFChassisResult* result, FF_MAYBE_UNUSED FFChassisOptions* options)
{
getSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type);
getSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor);
getSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version);
if(result->type.length)
{
-1
View File
@@ -1,5 +1,4 @@
#include "cpu.h"
#include "detection/internal.h"
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu);
+2 -2
View File
@@ -13,8 +13,8 @@ typedef struct FFCPUResult
uint16_t coresLogical;
uint16_t coresOnline;
double frequencyMin;
double frequencyMax;
double frequencyMin; // GHz
double frequencyMax; // GHz
double temperature;
} FFCPUResult;
+4 -4
View File
@@ -11,14 +11,14 @@ static double detectCpuTemp(const FFstrbuf* cpuName)
{
switch (strtol(cpuName->chars + strlen("Apple M"), NULL, 10))
{
case 1: error = ffDetectCoreTemps(FF_TEMP_CPU_M1X, &result); break;
case 2: error = ffDetectCoreTemps(FF_TEMP_CPU_M2X, &result); break;
case 3: error = ffDetectCoreTemps(FF_TEMP_CPU_M3X, &result); break;
case 1: error = ffDetectSmcTemps(FF_TEMP_CPU_M1X, &result); break;
case 2: error = ffDetectSmcTemps(FF_TEMP_CPU_M2X, &result); break;
case 3: error = ffDetectSmcTemps(FF_TEMP_CPU_M3X, &result); break;
default: error = "Unsupported Apple Silicon CPU";
}
}
else // PPC?
error = ffDetectCoreTemps(FF_TEMP_CPU_X64, &result);
error = ffDetectSmcTemps(FF_TEMP_CPU_X64, &result);
if(error)
return FF_CPU_TEMP_UNSET;
+54 -7
View File
@@ -8,6 +8,7 @@
#include <sys/sysinfo.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#ifdef __ANDROID__
#include "common/settings.h"
@@ -132,10 +133,9 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
const char* error = parseCpuInfo(cpu, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch);
if (error) return error;
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, 1);
cpu->coresLogical = (uint16_t) get_nprocs_conf();
cpu->coresOnline = (uint16_t) get_nprocs();
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical);
#define BP "/sys/devices/system/cpu/cpufreq/policy0/"
if(ffPathExists(BP, FF_PATHTYPE_DIRECTORY))
@@ -167,17 +167,64 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
detectAndroid(cpu);
#endif
#ifdef __linux__
if (cpu->name.length == 0)
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
if (!ffProcessAppendStdOut(&buffer, (char *const[]) { "lscpu", NULL }))
if (ffProcessAppendStdOut(&buffer, (char *const[]) { "lscpu", NULL }) == NULL)
{
ffParsePropLines(buffer.chars, "Model name:", &cpu->name);
if (ffStrbufEqualS(&cpu->name, "-")) ffStrbufClear(&cpu->name);
char* pstart = buffer.chars;
if (cpu->vendor.length == 0)
{
pstart = strstr(pstart, "Vendor ID:");
if (pstart)
{
pstart += strlen("Vendor ID:");
while (isspace(*pstart)) ++pstart;
if (*pstart)
{
char* pend = strchr(pstart, '\n');
if (pend != NULL)
ffStrbufAppendNS(&cpu->vendor, (uint32_t) (pend - pstart), pstart);
else
{
ffStrbufAppendS(&cpu->vendor, pstart);
}
pstart = pend + 1;
}
}
}
while ((pstart = strstr(pstart, "Model name:")))
{
pstart += strlen("Model name:");
while (isspace(*pstart)) ++pstart;
if (*pstart == '\0')
break;
if (cpu->name.length > 0)
ffStrbufAppendS(&cpu->name, " + ");
if (*pstart == '-')
{
ffStrbufAppendS(&cpu->name, "Unknown");
++pstart;
continue;
}
char* pend = strchr(pstart, '\n');
if (pend != NULL)
ffStrbufAppendNS(&cpu->name, (uint32_t) (pend - pstart), pstart);
else
{
ffStrbufAppendS(&cpu->name, pstart);
break;
}
pstart = pend + 1;
}
}
}
#endif
return NULL;
}
+45 -6
View File
@@ -5,6 +5,43 @@
#include <sys/mount.h>
#ifdef __FreeBSD__
#include <libgeom.h>
static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
{
if (!ffStrStartsWith(fs->f_mntfromname, "/dev/"))
return "Only block devices are supported";
// Detect volume label in geom tree
static struct gmesh geomTree;
static struct gclass* cLabels;
if (!cLabels)
{
if (geomTree.lg_ident)
return "Previous geom_gettree() failed";
if (geom_gettree(&geomTree) < 0)
{
geomTree.lg_ident = (void*)(intptr_t)-1;
return "geom_gettree() failed";
}
for (cLabels = geomTree.lg_class.lh_first; !ffStrEquals(cLabels->lg_name, "LABEL"); cLabels = cLabels->lg_class.le_next);
if (!cLabels)
return "Class LABEL is not found";
}
for (struct ggeom* label = cLabels->lg_geom.lh_first; label; label = label->lg_geom.le_next)
{
struct gprovider* provider = label->lg_provider.lh_first;
if (!provider || !ffStrEquals(label->lg_name, fs->f_mntfromname + strlen("/dev/"))) continue;
const char* str = strchr(provider->lg_name, '/');
ffStrbufSetS(&disk->name, str ? str + 1 : provider->lg_name);
}
return NULL;
}
static void detectFsInfo(struct statfs* fs, FFDisk* disk)
{
if(ffStrbufEqualS(&disk->filesystem, "zfs"))
@@ -19,6 +56,8 @@ static void detectFsInfo(struct statfs* fs, FFDisk* disk)
disk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT;
else
disk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
detectFsLabel(fs, disk);
}
#elif __APPLE__
#include "util/apple/cf_helpers.h"
@@ -26,10 +65,10 @@ static void detectFsInfo(struct statfs* fs, FFDisk* disk)
#include <sys/attr.h>
#include <unistd.h>
struct VolAttrBuf {
struct CmnAttrBuf {
uint32_t length;
attrreference_t volNameRef;
char volNameSpace[MAXPATHLEN];
attrreference_t nameRef;
char nameSpace[NAME_MAX * 3 + 1];
} __attribute__((aligned(4), packed));
void detectFsInfo(struct statfs* fs, FFDisk* disk)
@@ -41,12 +80,12 @@ void detectFsInfo(struct statfs* fs, FFDisk* disk)
else
disk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
struct VolAttrBuf attrBuf;
struct CmnAttrBuf attrBuf;
if (getattrlist(disk->mountpoint.chars, &(struct attrlist) {
.bitmapcount = ATTR_BIT_MAP_COUNT,
.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME,
.commonattr = ATTR_CMN_NAME,
}, &attrBuf, sizeof(attrBuf), 0) == 0)
ffStrbufInitNS(&disk->name, attrBuf.volNameRef.attr_length - 1 /* excluding '\0' */, attrBuf.volNameSpace);
ffStrbufInitNS(&disk->name, attrBuf.nameRef.attr_length - 1 /* excluding '\0' */, attrBuf.nameSpace);
}
#endif
+15 -24
View File
@@ -26,8 +26,11 @@ static bool isPhysicalDevice(const struct mntent* device)
if(ffStrEquals(device->mnt_dir, "/"))
return true;
if(ffStrEquals(device->mnt_fsname, "none"))
return false;
//DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem.
if(ffStrEquals(device->mnt_fsname, "drvfs"))
if(ffStrEquals(device->mnt_type, "9p"))
return true;
//ZFS pool
@@ -189,41 +192,29 @@ static bool isSubvolume(const FFlist* disks, FFDisk* currentDisk)
static bool isRemovable(FFDisk* currentDisk)
{
FF_STRBUF_AUTO_DESTROY basePath = ffStrbufCreateS("/sys/block/");
FF_AUTO_CLOSE_DIR DIR* dir = opendir(basePath.chars);
if(dir == NULL)
if (!ffStrbufStartsWithS(&currentDisk->mountFrom, "/dev/"))
return false;
uint32_t index = ffStrbufLastIndexC(&currentDisk->mountFrom, '/');
const char* partitionName = index == currentDisk->mountFrom.length ? NULL : currentDisk->mountFrom.chars + index + 1;
if (!partitionName || !*partitionName) return false;
char sysBlockPartition[64];
snprintf(sysBlockPartition, sizeof(sysBlockPartition), "/sys/class/block/%s", currentDisk->mountFrom.chars + strlen("/dev/"));
struct dirent* entry;
while((entry = readdir(dir)) != NULL)
{
if(entry->d_name[0] == '.')
continue;
char sysBlockVolume[PATH_MAX]; // /sys/devices/pci0000:00/0000:00:14.0/usb4/4-3/4-3:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
if (realpath(sysBlockPartition, sysBlockVolume) == NULL)
return false;
strcpy(strrchr(sysBlockVolume, '/') + 1, "removable");
if (!ffStrStartsWith(partitionName, entry->d_name)) continue;
// /sys/block/sdx/device/delete
ffStrbufAppendS(&basePath, entry->d_name);
ffStrbufAppendS(&basePath, "/device/delete");
return ffPathExists(basePath.chars, FF_PATHTYPE_FILE);
}
return false;
char removableChar = '0';
return ffReadFileData(sysBlockVolume, 1, &removableChar) > 0 && removableChar == '1';
}
static void detectType(const FFlist* disks, FFDisk* currentDisk)
{
if(ffStrbufStartsWithS(&currentDisk->mountpoint, "/boot") || ffStrbufStartsWithS(&currentDisk->mountpoint, "/efi"))
currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
else if(isRemovable(currentDisk))
currentDisk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT;
else if(isSubvolume(disks, currentDisk))
currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
else if(isRemovable(currentDisk))
currentDisk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT;
else
currentDisk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
}
+25 -4
View File
@@ -41,16 +41,37 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
{
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/vendor", devName);
ffAppendFileBuffer(pathSysBlock, &device->name);
if (device->name.length > 0)
ffStrbufAppendC(&device->name, ' ');
if (ffAppendFileBuffer(pathSysBlock, &device->name))
{
ffStrbufTrimRightSpace(&device->name);
if (device->name.length > 0)
ffStrbufAppendC(&device->name, ' ');
}
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/model", devName);
ffAppendFileBuffer(pathSysBlock, &device->name);
ffStrbufTrim(&device->name, ' ');
ffStrbufTrimRightSpace(&device->name);
if (device->name.length == 0)
ffStrbufSetS(&device->name, devName);
else if (ffStrStartsWith(devName, "nvme"))
{
int devid, nsid;
if (sscanf(devName, "nvme%dn%d", &devid, &nsid) == 2)
{
bool multiNs = nsid > 1;
if (!multiNs)
{
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/nvme%dn2", devName, devid);
multiNs = ffPathExists(pathSysBlock, FF_PATHTYPE_DIRECTORY);
}
if (multiNs)
{
// In Asahi Linux, there are multiple namespaces for the same NVMe drive.
ffStrbufAppendF(&device->name, " - %d", nsid);
}
}
}
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
{
+86 -65
View File
@@ -5,78 +5,99 @@
#include <windows.h>
#include <winioctl.h>
static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFDiskIOOptions* options)
{
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
return false;
DWORD retSize;
char sddBuffer[4096];
if(!DeviceIoControl(
hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&(STORAGE_PROPERTY_QUERY) {
.PropertyId = StorageDeviceProperty,
.QueryType = PropertyStandardQuery,
},
sizeof(STORAGE_PROPERTY_QUERY),
&sddBuffer,
sizeof(sddBuffer),
&retSize,
NULL
) || retSize == 0)
return true;
FFDiskIOResult* device = (FFDiskIOResult*) ffListAdd(result);
STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
ffStrbufInit(&device->name);
if (sdd->VendorIdOffset != 0)
{
ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset);
ffStrbufTrim(&device->name, ' ');
}
if (sdd->ProductIdOffset != 0)
{
if (device->name.length)
ffStrbufAppendC(&device->name, ' ');
ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
ffStrbufTrimRight(&device->name, ' ');
}
if (!device->name.length)
ffStrbufSetWS(&device->name, szDevice);
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
{
ffStrbufDestroy(&device->name);
result->length--;
return true;
}
ffStrbufInitWS(&device->devPath, szDevice);
DISK_PERFORMANCE dp = {};
if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &dp, sizeof(dp), &retSize, NULL))
{
device->bytesRead = (uint64_t) dp.BytesRead.QuadPart;
device->readCount = (uint64_t) dp.ReadCount;
device->bytesWritten = (uint64_t) dp.BytesWritten.QuadPart;
device->writeCount = (uint64_t) dp.WriteCount;
}
else
{
ffStrbufDestroy(&device->name);
result->length--;
}
return true;
}
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
{
wchar_t szDevice[32] = L"\\\\.\\PhysicalDrive";
wchar_t* pNum = szDevice + strlen("\\\\.\\PhysicalDrive");
for (uint32_t idev = 0; ; ++idev)
{
_ultow(idev, pNum, 10);
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
break;
DWORD retSize;
char sddBuffer[4096];
if(!DeviceIoControl(
hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&(STORAGE_PROPERTY_QUERY) {
.PropertyId = StorageDeviceProperty,
.QueryType = PropertyStandardQuery,
},
sizeof(STORAGE_PROPERTY_QUERY),
&sddBuffer,
sizeof(sddBuffer),
&retSize,
NULL
) || retSize == 0)
continue;
FFDiskIOResult* device = (FFDiskIOResult*) ffListAdd(result);
STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
ffStrbufInit(&device->name);
if (sdd->VendorIdOffset != 0)
wchar_t szPhysicalDrive[32] = L"\\\\.\\PhysicalDrive";
wchar_t* pNum = szPhysicalDrive + strlen("\\\\.\\PhysicalDrive");
for (uint32_t idev = 0; ; ++idev)
{
ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset);
ffStrbufTrim(&device->name, ' ');
_ultow(idev, pNum, 10);
if (!detectPhysicalDisk(szPhysicalDrive, result, options))
break;
}
if (sdd->ProductIdOffset != 0)
}
{
wchar_t szCdrom[32] = L"\\\\.\\CDROM";
wchar_t* pNum = szCdrom + strlen("\\\\.\\CDROM");
for (uint32_t idev = 0; ; ++idev)
{
if (device->name.length)
ffStrbufAppendC(&device->name, ' ');
_ultow(idev, pNum, 10);
ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
ffStrbufTrimRight(&device->name, ' ');
}
if (!device->name.length)
ffStrbufAppendF(&device->name, "PhysicalDrive%u", (unsigned) idev);
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
{
ffStrbufDestroy(&device->name);
result->length--;
continue;
}
ffStrbufInitWS(&device->devPath, szDevice);
DISK_PERFORMANCE dp = {};
if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &dp, sizeof(dp), &retSize, NULL))
{
device->bytesRead = (uint64_t) dp.BytesRead.QuadPart;
device->readCount = (uint64_t) dp.ReadCount;
device->bytesWritten = (uint64_t) dp.BytesWritten.QuadPart;
device->writeCount = (uint64_t) dp.WriteCount;
}
else
{
ffStrbufDestroy(&device->name);
result->length--;
continue;
if (!detectPhysicalDisk(szCdrom, result, options))
break;
}
}
+11 -3
View File
@@ -1,5 +1,4 @@
#include "displayserver.h"
#include "detection/internal.h"
bool ffdsAppendDisplay(
FFDisplayServerResult* result,
@@ -36,7 +35,16 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds);
const FFDisplayServerResult* ffConnectDisplayServer()
{
FF_DETECTION_INTERNAL_GUARD(FFDisplayServerResult,
static FFDisplayServerResult result;
if (result.displays.elementSize == 0)
{
ffStrbufInit(&result.wmProcessName);
ffStrbufInit(&result.wmPrettyName);
ffStrbufInit(&result.wmProtocolName);
ffStrbufInit(&result.deProcessName);
ffStrbufInit(&result.dePrettyName);
ffListInit(&result.displays, sizeof(FFDisplayResult));
ffConnectDisplayServerImpl(&result);
);
}
return &result;
}
@@ -102,12 +102,8 @@ static bool detectWithGetprop(FFDisplayServerResult* ds)
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
{
ffStrbufInitStatic(&ds->wmProcessName, "WindowManager");
ffStrbufInitStatic(&ds->wmPrettyName, "Window Manager");
ffStrbufInit(&ds->wmProtocolName);
ffStrbufInit(&ds->deProcessName);
ffStrbufInit(&ds->dePrettyName);
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 0);
ffStrbufSetStatic(&ds->wmProcessName, "WindowManager");
ffStrbufSetStatic(&ds->wmPrettyName, "Window Manager");
if (!detectWithGetprop(ds))
detectWithDumpsys(ds);
@@ -73,20 +73,11 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
FF_CFTYPE_AUTO_RELEASE CFMachPortRef port = CGWindowServerCreateServerPort();
if (port)
{
ffStrbufInitStatic(&ds->wmProcessName, "WindowServer");
ffStrbufInitStatic(&ds->wmPrettyName, "Quartz Compositor");
}
else
{
ffStrbufInit(&ds->wmProcessName);
ffStrbufInit(&ds->wmPrettyName);
ffStrbufSetStatic(&ds->wmProcessName, "WindowServer");
ffStrbufSetStatic(&ds->wmPrettyName, "Quartz Compositor");
}
}
ffStrbufInit(&ds->wmProtocolName);
ffStrbufSetStatic(&ds->dePrettyName, "Aqua");
ffStrbufInit(&ds->deProcessName);
ffStrbufInitStatic(&ds->dePrettyName, "Aqua");
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 4);
detectDisplays(ds);
}
@@ -13,10 +13,10 @@ typedef struct FFMonitorInfo
} FFMonitorInfo;
static CALLBACK BOOL MonitorEnumProc(
HMONITOR hMonitor,
FF_MAYBE_UNUSED HDC hdc,
FF_MAYBE_UNUSED LPRECT lpRect,
LPARAM lParam
HMONITOR hMonitor,
FF_MAYBE_UNUSED HDC hdc,
FF_MAYBE_UNUSED LPRECT lpRect,
LPARAM lParam
)
{
FFlist* monitors = (FFlist*) lParam;
@@ -145,20 +145,16 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
BOOL enabled;
if(SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
{
ffStrbufInitStatic(&ds->wmProcessName, "dwm.exe");
ffStrbufInitStatic(&ds->wmPrettyName, "Desktop Window Manager");
ffStrbufSetStatic(&ds->wmProcessName, "dwm.exe");
ffStrbufSetStatic(&ds->wmPrettyName, "Desktop Window Manager");
}
else
{
// `explorer.exe` only provides a subset of WM functions, as well as the taskbar and desktop icons.
// While a window itself is drawn by kernel (GDI). Killing `explorer.exe` won't affect how windows are displayed generally.
ffStrbufInitStatic(&ds->wmProcessName, "explorer.exe");
ffStrbufInitStatic(&ds->wmPrettyName, "Internal");
ffStrbufSetStatic(&ds->wmProcessName, "explorer.exe");
ffStrbufSetStatic(&ds->wmPrettyName, "Internal");
}
ffStrbufInit(&ds->wmProtocolName);
ffStrbufInit(&ds->deProcessName);
ffStrbufInit(&ds->dePrettyName);
ffListInit(&ds->displays, sizeof(FFDisplayResult));
detectDisplays(ds);
@@ -3,13 +3,6 @@
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
{
ffStrbufInit(&ds->wmProcessName);
ffStrbufInit(&ds->wmPrettyName);
ffStrbufInit(&ds->wmProtocolName);
ffStrbufInit(&ds->deProcessName);
ffStrbufInit(&ds->dePrettyName);
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 4);
if (instance.config.general.dsForceDrm == FF_DS_FORCE_DRM_TYPE_FALSE)
{
//We try wayland as our preferred display server, as it supports the most features.
@@ -50,6 +50,7 @@ static void waylandDetectWM(int fd, FFDisplayServerResult* result)
FF_STRBUF_AUTO_DESTROY procPath = ffStrbufCreate();
ffStrbufAppendF(&procPath, "/proc/%d/cmdline", ucred.pid); //We check the cmdline for the process name, because it is not trimmed.
ffReadFileBuffer(procPath.chars, &result->wmProcessName);
ffStrbufTrimRightSpace(&result->wmProcessName);
ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments
ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path
}
+1
View File
@@ -326,6 +326,7 @@ static const char* getFromProcesses(FFDisplayServerResult* result)
//We check the cmdline for the process name, because it is not trimmed.
ffStrbufAppendS(&procPath, "/cmdline");
ffReadFileBuffer(procPath.chars, &processName);
ffStrbufTrimRightSpace(&processName);
ffStrbufSubstrBeforeFirstC(&processName, '\0'); //Trim the arguments
ffStrbufSubstrAfterLastC(&processName, '/');
-1
View File
@@ -1,5 +1,4 @@
#include "font.h"
#include "detection/internal.h"
const char* ffDetectFontImpl(FFFontResult* font);
+2 -1
View File
@@ -30,7 +30,8 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices);
ffStrbufInitS(&device->identifier, entry->d_name);
ffStrbufInit(&device->name);
ffAppendFileBuffer(path.chars, &device->name);
if (ffAppendFileBuffer(path.chars, &device->name))
ffStrbufTrimRightSpace(&device->name);
}
ffStrbufSubstrBefore(&path, baseLen);
+56 -6
View File
@@ -1,6 +1,6 @@
#include "gpu.h"
#include "detection/internal.h"
#include "detection/vulkan/vulkan.h"
#include "detection/opengl/opengl.h"
const char* FF_GPU_VENDOR_NAME_APPLE = "Apple";
const char* FF_GPU_VENDOR_NAME_AMD = "AMD";
@@ -46,17 +46,67 @@ const char* ffGetGPUVendorString(unsigned vendorId)
return NULL;
}
const char* detectByOpenGL(FFlist* gpus)
{
FFOpenGLResult result;
ffStrbufInit(&result.version);
ffStrbufInit(&result.renderer);
ffStrbufInit(&result.vendor);
ffStrbufInit(&result.slv);
const char* error = ffDetectOpenGL(&instance.config.modules.openGL, &result);
if (!error)
{
FFGPUResult* gpu = (FFGPUResult*) ffListAdd(gpus);
gpu->type = FF_GPU_TYPE_UNKNOWN;
ffStrbufInitMove(&gpu->vendor, &result.vendor);
ffStrbufInitMove(&gpu->name, &result.renderer);
ffStrbufInit(&gpu->driver);
ffStrbufInitF(&gpu->platformApi, "OpenGL %s", result.version.chars);
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->dedicated = gpu->shared = (FFGPUMemory){0, 0};
gpu->deviceId = 0;
if (ffStrbufIgnCaseEqualS(&gpu->vendor, "Mesa"))
ffStrbufClear(&gpu->vendor);
if (!gpu->vendor.length)
{
if (ffStrbufContainS(&result.renderer, "Apple"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
else if (ffStrbufContainS(&result.renderer, "Intel"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
else if (ffStrbufContainS(&result.renderer, "AMD") || ffStrbufContainS(&result.renderer, "ATI"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
else if (ffStrbufContainS(&result.renderer, "NVIDIA"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
}
}
ffStrbufDestroy(&result.version);
ffStrbufDestroy(&result.renderer);
ffStrbufDestroy(&result.vendor);
ffStrbufDestroy(&result.slv);
return error;
}
const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result)
{
if (!options->forceVulkan)
{
const char* error = ffDetectGPUImpl(options, result);
if (!error) return NULL;
if (!error && result->length > 0) return NULL;
}
FFVulkanResult* vulkan = ffDetectVulkan();
if (vulkan->error) return "GPU detection failed";
ffListDestroy(result);
ffListInitMove(result, &vulkan->gpus);
if (!vulkan->error && vulkan->gpus.length > 0)
{
ffListDestroy(result);
ffListInitMove(result, &vulkan->gpus);
return NULL;
}
if (detectByOpenGL(result) == NULL)
return NULL;
return NULL;
return "GPU detection failed";
}
+5 -2
View File
@@ -5,6 +5,7 @@
#define FF_GPU_TEMP_UNSET (0/0.0)
#define FF_GPU_CORE_COUNT_UNSET -1
#define FF_GPU_VMEM_SIZE_UNSET ((uint64_t)-1)
#define FF_GPU_FREQUENCY_UNSET (0/0.0)
extern const char* FF_GPU_VENDOR_NAME_APPLE;
extern const char* FF_GPU_VENDOR_NAME_AMD;
@@ -28,11 +29,13 @@ typedef struct FFGPUResult
FFstrbuf vendor;
FFstrbuf name;
FFstrbuf driver;
FFstrbuf platformApi;
double temperature;
int coreCount;
int32_t coreCount;
double frequency; // Real time clock frequency in GHz
FFGPUMemory dedicated;
FFGPUMemory shared;
uint32_t vulkanDeviceId; // Only used for vulkan
uint64_t deviceId; // Used internally, may be uninitialized
} FFGPUResult;
const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result);
+67
View File
@@ -0,0 +1,67 @@
#include "gpu_driver_specific.h"
// Everything detected in this file is static.
// The real time monitoring requires ADLX, whose interface is much more complicated than AGS
// Whoever has AMD graphic cards interested in this may contribute
// * ADLX (AMD Device Library eXtra): https://github.com/GPUOpen-LibrariesAndSDKs/ADLX
#include "3rdparty/ags/amd_ags.h"
#include "common/library.h"
#include "util/mallocHelper.h"
const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
{
static bool inited = false;
static AGSGPUInfo gpuInfo;
if (!inited)
{
inited = true;
FF_LIBRARY_LOAD(libags, NULL, "dlopen amd_ags failed", soName , 1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libags, agsInitialize)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libags, agsDeInitialize)
struct AGSContext* apiHandle;
if (ffagsInitialize(AGS_CURRENT_VERSION, NULL, &apiHandle, &gpuInfo) != AGS_SUCCESS)
return "loading ags library failed";
ffagsDeInitialize(apiHandle);
}
if (gpuInfo.numDevices == 0)
return "loading ags library failed or no AMD gpus found";
AGSDeviceInfo* device = NULL;
for (int iDev = 0; iDev < gpuInfo.numDevices; iDev++)
{
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID)
{
if (
cond->pciDeviceId.deviceId == (uint32_t) gpuInfo.devices[iDev].deviceId &&
cond->pciDeviceId.vendorId == (uint32_t) gpuInfo.devices[iDev].vendorId &&
cond->pciDeviceId.revId == (uint32_t) gpuInfo.devices[iDev].revisionId)
{
device = &gpuInfo.devices[iDev];
break;
}
}
}
if (!device)
return "Device not found";
if (result.coreCount)
*result.coreCount = (uint32_t) device->numCUs;
if (result.memory)
{
result.memory->total = device->localMemoryInBytes;
result.memory->used = FF_GPU_VMEM_SIZE_UNSET;
}
if (result.frequency)
*result.frequency = device->coreClock / 1000.; // Maximum frequency
return NULL;
}
+13 -6
View File
@@ -6,6 +6,8 @@
#include <IOKit/graphics/IOGraphicsLib.h>
const char* ffGpuDetectMetal(FFlist* gpus);
static double detectGpuTemp(const FFstrbuf* gpuName)
{
double result = 0;
@@ -15,18 +17,18 @@ static double detectGpuTemp(const FFstrbuf* gpuName)
{
switch (strtol(gpuName->chars + strlen("Apple M"), NULL, 10))
{
case 1: error = ffDetectCoreTemps(FF_TEMP_GPU_M1X, &result); break;
case 2: error = ffDetectCoreTemps(FF_TEMP_GPU_M2X, &result); break;
case 3: error = ffDetectCoreTemps(FF_TEMP_GPU_M3X, &result); break;
case 1: error = ffDetectSmcTemps(FF_TEMP_GPU_M1X, &result); break;
case 2: error = ffDetectSmcTemps(FF_TEMP_GPU_M2X, &result); break;
case 3: error = ffDetectSmcTemps(FF_TEMP_GPU_M3X, &result); break;
default: error = "Unsupported Apple Silicon GPU";
}
}
else if (ffStrbufStartsWithS(gpuName, "Intel"))
error = ffDetectCoreTemps(FF_TEMP_GPU_INTEL, &result);
error = ffDetectSmcTemps(FF_TEMP_GPU_INTEL, &result);
else if (ffStrbufStartsWithS(gpuName, "Radeon") || ffStrbufStartsWithS(gpuName, "AMD"))
error = ffDetectCoreTemps(FF_TEMP_GPU_AMD, &result);
error = ffDetectSmcTemps(FF_TEMP_GPU_AMD, &result);
else
error = ffDetectCoreTemps(FF_TEMP_GPU_UNKNOWN, &result);
error = ffDetectSmcTemps(FF_TEMP_GPU_UNKNOWN, &result);
if (error)
return FF_GPU_TEMP_UNSET;
@@ -54,6 +56,9 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
IORegistryEntryGetRegistryEntryID(registryEntry, &gpu->deviceId);
ffStrbufInitStatic(&gpu->platformApi, "Metal");
ffStrbufInit(&gpu->driver); // Ok for both Apple and Intel
ffCfDictGetString(properties, CFSTR("CFBundleIdentifier"), &gpu->driver);
@@ -102,5 +107,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
}
IOObjectRelease(iterator);
ffGpuDetectMetal(gpus);
return NULL;
}
+40
View File
@@ -0,0 +1,40 @@
#include "gpu.h"
#import <Metal/MTLDevice.h>
#ifndef MAC_OS_VERSION_13_0
#define MTLGPUFamilyMetal3 ((MTLGPUFamily) 5001)
#endif
const char* ffGpuDetectMetal(FFlist* gpus)
{
if (@available(macOS 10.15, *))
{
for (id<MTLDevice> device in MTLCopyAllDevices())
{
FFGPUResult* gpu = NULL;
FF_LIST_FOR_EACH(FFGPUResult, x, *gpus)
{
if (x->deviceId == device.registryID || ffStrbufEqualS(&x->name, device.name.UTF8String))
{
gpu = x;
break;
}
}
if (!gpu) continue;
if ([device supportsFamily:MTLGPUFamilyMetal3])
ffStrbufSetStatic(&gpu->platformApi, "Metal 3");
else if ([device supportsFamily:MTLGPUFamilyCommon3])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3");
else if ([device supportsFamily:MTLGPUFamilyCommon2])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 2");
else if ([device supportsFamily:MTLGPUFamilyCommon1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
return NULL;
}
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include "gpu.h"
typedef enum FFGpuDriverConditionType
{
FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID = 1 << 0,
FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID = 1 << 1,
FF_GPU_DRIVER_CONDITION_TYPE_LUID = 1 << 2,
} FFGpuDriverConditionType;
typedef struct FFGpuDriverPciBusId
{
uint32_t domain;
uint32_t bus;
uint32_t device;
uint32_t func;
} FFGpuDriverPciBusId;
typedef struct FFGpuDriverPciDeviceId
{
uint32_t deviceId;
uint32_t vendorId;
uint32_t subSystemId;
uint32_t revId;
} FFGpuDriverPciDeviceId;
// Use pciBusId if not NULL; use pciDeviceId otherwise
typedef struct FFGpuDriverCondition
{
FFGpuDriverConditionType type;
FFGpuDriverPciBusId pciBusId;
FFGpuDriverPciDeviceId pciDeviceId;
uint64_t luid;
} FFGpuDriverCondition;
// detect x if not NULL
typedef struct FFGpuDriverResult
{
double* temp;
FFGPUMemory* memory;
uint32_t* coreCount;
FFGPUType* type;
double* frequency;
} FFGpuDriverResult;
const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName);
const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName);
const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName);
+200
View File
@@ -0,0 +1,200 @@
#include "gpu_driver_specific.h"
#include "3rdparty/igcl/igcl_api.h"
#include "common/library.h"
#include "util/mallocHelper.h"
struct FFIgclData {
FF_LIBRARY_SYMBOL(ctlClose)
FF_LIBRARY_SYMBOL(ctlEnumerateDevices)
FF_LIBRARY_SYMBOL(ctlGetDeviceProperties)
FF_LIBRARY_SYMBOL(ctlEnumTemperatureSensors)
FF_LIBRARY_SYMBOL(ctlTemperatureGetState)
FF_LIBRARY_SYMBOL(ctlEnumMemoryModules)
FF_LIBRARY_SYMBOL(ctlMemoryGetState)
FF_LIBRARY_SYMBOL(ctlEnumFrequencyDomains)
FF_LIBRARY_SYMBOL(ctlFrequencyGetState)
bool inited;
ctl_api_handle_t apiHandle;
} igclData;
static void shutdownIgcl()
{
if (igclData.apiHandle)
{
igclData.ffctlClose(igclData.apiHandle);
igclData.apiHandle = NULL;
}
}
const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
{
if (!igclData.inited)
{
igclData.inited = true;
FF_LIBRARY_LOAD(libigcl, NULL, "dlopen igcl (ControlLib) failed", soName , 1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libigcl, ctlInit)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlClose)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumerateDevices)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlGetDeviceProperties)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumTemperatureSensors)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlTemperatureGetState)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumMemoryModules)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlMemoryGetState)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumFrequencyDomains)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlFrequencyGetState)
if (ffctlInit(&(ctl_init_args_t) {
.AppVersion = CTL_MAKE_VERSION(CTL_IMPL_MAJOR_VERSION, CTL_IMPL_MINOR_VERSION),
.flags = CTL_INIT_FLAG_USE_LEVEL_ZERO,
.Size = sizeof(ctl_init_args_t),
.Version = 0,
}, &igclData.apiHandle) != CTL_RESULT_SUCCESS)
return "loading igcl library failed";
atexit(shutdownIgcl);
libigcl = NULL; // don't close igcl
}
if (!igclData.apiHandle)
return "loading igcl library failed";
uint32_t deviceCount = 0;
if (igclData.ffctlEnumerateDevices(igclData.apiHandle, &deviceCount, NULL))
return "ctlEnumerateDevices(NULL) failed";
if (deviceCount == 0)
return "No Intel graphics adapter found";
FF_AUTO_FREE ctl_device_adapter_handle_t* devices = malloc(deviceCount * sizeof(*devices));
if (igclData.ffctlEnumerateDevices(igclData.apiHandle, &deviceCount, devices))
return "ctlEnumerateDevices(devices) failed";
ctl_device_adapter_handle_t device = NULL;
uint64_t /* LUID */ deviceId = 0;
ctl_device_adapter_properties_t properties = {
.Size = sizeof(properties),
.pDeviceID = &deviceId,
.device_id_size = sizeof(deviceId),
.Version = 2,
};
for (uint32_t iDev = 0; iDev < deviceCount; iDev++)
{
if (igclData.ffctlGetDeviceProperties(devices[iDev], &properties) != CTL_RESULT_SUCCESS)
continue;
if (properties.device_type != CTL_DEVICE_TYPE_GRAPHICS)
continue;
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_LUID)
{
if (cond->luid == deviceId)
{
device = devices[iDev];
break;
}
}
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
{
if (cond->pciBusId.bus == properties.adapter_bdf.bus &&
cond->pciBusId.device == properties.adapter_bdf.device &&
cond->pciBusId.func == properties.adapter_bdf.function)
{
device = devices[iDev];
break;
}
}
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID)
{
if (
cond->pciDeviceId.deviceId == properties.pci_device_id &&
cond->pciDeviceId.vendorId == properties.pci_vendor_id &&
cond->pciDeviceId.subSystemId == (uint32_t) ((properties.pci_subsys_id << 16u) | properties.pci_subsys_vendor_id) &&
cond->pciDeviceId.revId == properties.rev_id)
{
device = devices[iDev];
break;
}
}
}
if (!device)
return "Device not found";
if (result.coreCount)
*result.coreCount = properties.num_slices * properties.num_sub_slices_per_slice * properties.num_eus_per_sub_slice;
if (result.memory)
{
ctl_mem_handle_t memoryModules[16];
uint32_t memoryCount = sizeof(memoryModules) / sizeof(memoryModules[0]);
if (igclData.ffctlEnumMemoryModules(device, &memoryCount, memoryModules) == CTL_RESULT_SUCCESS && memoryCount > 0)
{
result.memory->used = 0;
result.memory->total = 0;
for (uint32_t iMem = 0; iMem < memoryCount; iMem++)
{
ctl_mem_state_t memoryState = {
.Size = sizeof(ctl_mem_state_t),
.Version = 0,
};
if (igclData.ffctlMemoryGetState(memoryModules[iMem], &memoryState) == CTL_RESULT_SUCCESS)
{
result.memory->total += memoryState.size;
result.memory->used += memoryState.size - memoryState.free;
}
}
}
}
if (result.type)
{
*result.type = properties.graphics_adapter_properties & CTL_ADAPTER_PROPERTIES_FLAG_INTEGRATED
? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
if (result.temp)
{
ctl_temp_handle_t sensors[16];
uint32_t sensorCount = sizeof(sensors) / sizeof(sensors[0]);
if (igclData.ffctlEnumTemperatureSensors(device, &sensorCount, sensors) == CTL_RESULT_SUCCESS && sensorCount > 0)
{
double sumValue = 0;
uint32_t availableCount = 0;
for (uint32_t iSensor = 0; iSensor < sensorCount; iSensor++)
{
double value;
if (igclData.ffctlTemperatureGetState(sensors[iSensor], &value) == CTL_RESULT_SUCCESS)
{
sumValue += value;
availableCount++;
}
}
*result.temp = sumValue / availableCount;
}
}
if (result.frequency)
{
ctl_freq_handle_t freqs[16];
uint32_t freqCount = sizeof(freqs) / sizeof(freqs[0]);
if (igclData.ffctlEnumFrequencyDomains(device, &freqCount, freqs) == CTL_RESULT_SUCCESS && freqCount > 0)
{
double sumValue = 0;
uint32_t availableCount = 0;
for (uint32_t iFreq = 0; iFreq < freqCount; iFreq++)
{
ctl_freq_state_t state = { .Size = sizeof(state), .Version = 0 };
if (igclData.ffctlFrequencyGetState(freqs[iFreq], &state) == CTL_RESULT_SUCCESS)
{
sumValue += state.actual;
availableCount++;
}
}
*result.frequency = (sumValue / availableCount) / 1000.;
}
}
return NULL;
}
+24 -12
View File
@@ -1,5 +1,5 @@
#include "detection/gpu/gpu.h"
#include "detection/gpu/gpu_nvidia.h"
#include "detection/gpu/gpu_driver_specific.h"
#include "detection/vulkan/vulkan.h"
#ifdef FF_HAVE_LIBPCI
@@ -46,12 +46,14 @@ static void pciDetectVendorName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
pci->ffpci_lookup_name(pci->access, gpu->vendor.chars, (int) gpu->vendor.allocated, PCI_LOOKUP_VENDOR, device->vendor_id);
ffStrbufRecalculateLength(&gpu->vendor);
if(ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
if(ffStrbufContainIgnCaseS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
else if(ffStrbufContainS(&gpu->vendor, "Intel"))
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "Intel"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
else if(ffStrbufContainS(&gpu->vendor, "NVIDIA"))
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "NVIDIA"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "Apple"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
}
static void drmDetectDeviceName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
@@ -133,7 +135,7 @@ static void pciDetectDriverName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
ffStrbufAppendC(&gpu->driver, ' ');
ffStrbufAppendS(&path, "/module/version");
ffAppendFileBuffer(path.chars, &gpu->driver);
ffStrbufTrimRight(&gpu->driver, ' ');
ffStrbufTrimRightSpace(&gpu->driver);
}
FF_MAYBE_UNUSED static void pciDetectTemp(FFGPUResult* gpu, struct pci_dev* device)
@@ -219,6 +221,8 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
FFGPUResult* gpu = ffListAdd(results);
ffStrbufInit(&gpu->platformApi);
ffStrbufInit(&gpu->vendor);
pciDetectVendorName(gpu, pci, device);
@@ -239,16 +243,24 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->useNvml))
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
{
char pciDeviceId[32];
snprintf(pciDeviceId, sizeof(pciDeviceId) - 1, "%04x:%02x:%02x.%d", device->domain, device->bus, device->dev, device->func);
ffDetectNvidiaGpuInfo((FFGpuNvidiaCondition) { .pciBusId = pciDeviceId }, (FFGpuNvidiaResult) {
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = {
.domain = (uint32_t) device->domain,
.bus = device->bus,
.device = device->dev,
.func = device->func,
},
}, (FFGpuDriverResult) {
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->useNvml ? &gpu->dedicated : NULL,
.coreCount = options->useNvml ? (uint32_t*) &gpu->coreCount : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.type = &gpu->type,
.frequency = &gpu->frequency,
}, "libnvidia-ml.so");
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
+19 -6
View File
@@ -1,4 +1,4 @@
#include "gpu_nvidia.h"
#include "gpu_driver_specific.h"
#include "3rdparty/nvml/nvml.h"
#include "common/library.h"
@@ -11,11 +11,12 @@ struct FFNvmlData {
FF_LIBRARY_SYMBOL(nvmlDeviceGetTemperature)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo_v2)
FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores)
FF_LIBRARY_SYMBOL(nvmlDeviceGetClockInfo)
bool inited;
} nvmlData;
const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult result, const char* soName)
const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName)
{
if (!nvmlData.inited)
{
@@ -30,6 +31,7 @@ const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult r
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetTemperature)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo_v2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetClockInfo)
if (ffnvmlInit_v2() != NVML_SUCCESS)
{
@@ -44,13 +46,16 @@ const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult r
return "loading nvml library failed";
nvmlDevice_t device = NULL;
if (cond.pciBusId)
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
{
nvmlReturn_t ret = nvmlData.ffnvmlDeviceGetHandleByPciBusId_v2(cond.pciBusId, &device);
char pciBusIdStr[32];
snprintf(pciBusIdStr, sizeof(pciBusIdStr) - 1, "%04x:%02x:%02x.%d", cond->pciBusId.domain, cond->pciBusId.bus, cond->pciBusId.device, cond->pciBusId.func);
nvmlReturn_t ret = nvmlData.ffnvmlDeviceGetHandleByPciBusId_v2(pciBusIdStr, &device);
if (ret != NVML_SUCCESS)
return "nvmlDeviceGetHandleByPciBusId_v2() failed";
}
else
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID)
{
uint32_t count;
if (nvmlData.ffnvmlDeviceGetCount_v2(&count) != NVML_SUCCESS)
@@ -65,7 +70,8 @@ const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult r
if (nvmlData.ffnvmlDeviceGetPciInfo_v3(device, &pciInfo) != NVML_SUCCESS)
continue;
if (pciInfo.pciDeviceId != cond.pciDeviceId || pciInfo.pciSubSystemId != cond.pciSubSystemId)
if (pciInfo.pciDeviceId != ((cond->pciDeviceId.deviceId << 16u) | cond->pciDeviceId.vendorId) ||
pciInfo.pciSubSystemId != cond->pciDeviceId.subSystemId)
continue;
break;
@@ -93,5 +99,12 @@ const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult r
if (result.coreCount)
nvmlData.ffnvmlDeviceGetNumGpuCores(device, result.coreCount);
if (result.frequency)
{
uint32_t clockMHz;
if (nvmlData.ffnvmlDeviceGetClockInfo(device, NVML_CLOCK_GRAPHICS, &clockMHz) == NVML_SUCCESS)
*result.frequency = clockMHz / 1000.;
}
return NULL;
}
-23
View File
@@ -1,23 +0,0 @@
#pragma once
#include "gpu.h"
// Use pciBusId if not NULL; use pciDeviceId and pciSubSystemId otherwise
typedef struct FFGpuNvidiaCondition
{
// "domain:bus:device.function"
const char* pciBusId;
// (deviceId << 16) | vendorId
uint32_t pciDeviceId;
uint32_t pciSubSystemId;
} FFGpuNvidiaCondition;
// detect x if not NULL
typedef struct FFGpuNvidiaResult
{
double* temp;
FFGPUMemory* memory;
uint32_t* coreCount;
} FFGpuNvidiaResult;
const char* ffDetectNvidiaGpuInfo(FFGpuNvidiaCondition cond, FFGpuNvidiaResult result, const char* soName);
+89 -23
View File
@@ -1,5 +1,5 @@
#include "gpu.h"
#include "detection/gpu/gpu_nvidia.h"
#include "detection/gpu/gpu_driver_specific.h"
#include "util/windows/unicode.h"
#include "util/windows/registry.h"
@@ -10,6 +10,41 @@ static int isGpuNameEqual(const FFGPUResult* gpu, const FFstrbuf* name)
return ffStrbufEqual(&gpu->name, name);
}
static inline bool getDriverSpecificDetectionFn(const char* vendor, __typeof__(&ffDetectNvidiaGpuInfo)* pDetectFn, const char** pDllName)
{
if (vendor == FF_GPU_VENDOR_NAME_NVIDIA)
{
*pDetectFn = ffDetectNvidiaGpuInfo;
*pDllName = "nvml.dll";
}
else if (vendor == FF_GPU_VENDOR_NAME_INTEL)
{
*pDetectFn = ffDetectIntelGpuInfo;
#ifdef _WIN64
*pDllName = "ControlLib.dll";
#else
*pDllName = "ControlLib32.dll";
#endif
}
else if (vendor == FF_GPU_VENDOR_NAME_AMD)
{
*pDetectFn = ffDetectAmdGpuInfo;
#ifdef _WIN64
*pDllName = "amd_ags_x64.dll";
#else
*pDllName = "amd_ags_x86.dll";
#endif
}
else
{
*pDetectFn = NULL;
*pDllName = NULL;
return false;
}
return true;
}
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
DISPLAY_DEVICEW displayDevice = { .cb = sizeof(displayDevice) };
@@ -35,14 +70,22 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (ffListContains(gpus, &gpuName, (void*) isGpuNameEqual)) continue;
}
// See: https://download.nvidia.com/XFree86/Linux-x86_64/545.23.06/README/supportedchips.html
// displayDevice.DeviceID = MatchingDeviceId "PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1"
uint32_t vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
swscanf(displayDevice.DeviceID, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId);
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString(vendorId));
ffStrbufInitWS(&gpu->name, displayDevice.DeviceString);
ffStrbufInit(&gpu->driver);
ffStrbufInitStatic(&gpu->platformApi, "Direct3D");
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = 0;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (deviceKeyLength == 100 && displayDevice.DeviceKey[deviceKeyPrefixLength - 1] == '{')
{
@@ -51,14 +94,6 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regControlVideoKey, &hKey, NULL)) continue;
ffRegReadStrbuf(hKey, L"DriverVersion", &gpu->driver, NULL);
ffRegReadStrbuf(hKey, L"ProviderName", &gpu->vendor, NULL);
if(ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
else if(ffStrbufContainS(&gpu->vendor, "Intel"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
else if(ffStrbufContainS(&gpu->vendor, "NVIDIA"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, displayDevice.DeviceKey + deviceKeyPrefixLength, strlen("00000000-0000-0000-0000-000000000000}"));
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
@@ -75,6 +110,14 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
gpu->dedicated.total = dedicatedVideoMemory + dedicatedSystemMemory;
gpu->shared.total = sharedSystemMemory;
}
ffRegReadUint64(hDirectxKey, L"AdapterLuid", &gpu->deviceId, NULL);
uint32_t featureLevel = 0;
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
}
else if (!ffRegReadUint64(hKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL))
{
@@ -83,23 +126,46 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
gpu->dedicated.total = vmem;
gpu->type = gpu->dedicated.total > 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
if (gpu->vendor.length == 0)
{
ffRegReadStrbuf(hKey, L"ProviderName", &gpu->vendor, NULL);
if (ffStrbufContainS(&gpu->vendor, "Intel"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
else if (ffStrbufContainS(&gpu->vendor, "NVIDIA"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
else if (ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
}
}
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->useNvml))
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
const char* dllName;
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName) && (options->temp || options->driverSpecific))
{
uint32_t vendorId, deviceId, subSystemId;
// See: https://download.nvidia.com/XFree86/Linux-x86_64/545.23.06/README/supportedchips.html
// displayDevice.DeviceID = MatchingDeviceId "PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1"
if (swscanf(displayDevice.DeviceID, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x", &vendorId, &deviceId, &subSystemId) == 3)
if (vendorId && deviceId && subSystemId && revId)
{
ffDetectNvidiaGpuInfo((FFGpuNvidiaCondition) {
.pciDeviceId = (deviceId << 16) | vendorId,
.pciSubSystemId = subSystemId,
}, (FFGpuNvidiaResult) {
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->useNvml ? &gpu->dedicated : NULL,
.coreCount = options->useNvml ? (uint32_t*) &gpu->coreCount : NULL,
}, "nvml.dll");
detectFn(
&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID | FF_GPU_DRIVER_CONDITION_TYPE_LUID,
.pciDeviceId = {
.deviceId = deviceId,
.vendorId = vendorId,
.subSystemId = subSystemId,
.revId = revId,
},
.luid = gpu->deviceId,
},
(FFGpuDriverResult) {
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.type = &gpu->type,
.frequency = &gpu->frequency,
},
dllName
);
}
}
}
+19 -9
View File
@@ -4,7 +4,7 @@
extern "C" {
#include "common/library.h"
#include "detection/gpu/gpu.h"
#include "detection/gpu/gpu_nvidia.h"
#include "detection/gpu/gpu_driver_specific.h"
}
#include <wsl/winadapter.h>
@@ -14,6 +14,8 @@ extern "C" {
#include <utility>
#include <cinttypes>
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
template <typename Fn>
struct on_scope_exit {
on_scope_exit(Fn &&fn): _fn(std::move(fn)) {}
@@ -65,6 +67,7 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
ffStrbufInitS(&gpu->name, desc);
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
ffStrbufInit(&gpu->driver);
uint64_t value = 0;
@@ -95,16 +98,23 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
const char* vendorStr = ffGetGPUVendorString((unsigned) hardwareId.vendorID);
ffStrbufSetStatic(&gpu->vendor, vendorStr);
if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && options->useNvml)
if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && (options->driverSpecific || options->temp))
{
ffDetectNvidiaGpuInfo((FFGpuNvidiaCondition) {
.pciBusId = nullptr,
.pciDeviceId = (hardwareId.deviceID << 16) | hardwareId.vendorID,
.pciSubSystemId = hardwareId.subSysID
}, (FFGpuNvidiaResult) {
FFGpuDriverCondition cond = {
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID,
.pciDeviceId = {
.deviceId = hardwareId.deviceID,
.vendorId = hardwareId.vendorID,
.subSystemId = hardwareId.subSysID,
.revId = hardwareId.revision,
},
};
ffDetectNvidiaGpuInfo(&cond, (FFGpuDriverResult) {
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->useNvml ? &gpu->dedicated : NULL,
.coreCount = options->useNvml ? (uint32_t*) &gpu->coreCount : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.type = &gpu->type,
.frequency = &gpu->frequency,
}, "/usr/lib/wsl/lib/libnvidia-ml.so");
}
}
+5 -18
View File
@@ -5,22 +5,9 @@
#include <stdlib.h>
static void getSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
{
ffReadFileBuffer(devicesPath, buffer);
if(ffIsSmbiosValueSet(buffer))
return;
ffReadFileBuffer(classPath, buffer);
if(ffIsSmbiosValueSet(buffer))
return;
ffStrbufClear(buffer);
}
static void getHostProductName(FFstrbuf* name)
{
getSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", name);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", name);
if(name->length > 0)
return;
@@ -42,11 +29,11 @@ static void getHostProductName(FFstrbuf* name)
const char* ffDetectHost(FFHostResult* host)
{
getSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->productFamily);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->productFamily);
getHostProductName(&host->productName);
getSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->productVersion);
getSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->productSku);
getSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->sysVendor);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->productVersion);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->productSku);
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->sysVendor);
//KVM/Qemu virtual machine
if(ffStrbufStartsWithS(&host->productName, "Standard PC"))
-12
View File
@@ -1,12 +0,0 @@
#pragma once
#include "common/thread.h"
#define FF_DETECTION_INTERNAL_GUARD(ResultType, ...) \
static ResultType result; \
static bool init = false; \
if(init) \
return &result; \
init = true; \
__VA_ARGS__; \
return &result;
+7 -4
View File
@@ -1,11 +1,13 @@
#include "media.h"
#include "detection/internal.h"
void ffDetectMediaImpl(FFMediaResult* media);
const FFMediaResult* ffDetectMedia(void)
{
FF_DETECTION_INTERNAL_GUARD(FFMediaResult,
static FFMediaResult result;
if (result.error.chars == NULL)
{
ffStrbufInit(&result.error);
ffStrbufInit(&result.playerId);
ffStrbufInit(&result.player);
@@ -14,10 +16,11 @@ const FFMediaResult* ffDetectMedia(void)
ffStrbufInit(&result.album);
ffStrbufInit(&result.url);
ffStrbufInit(&result.status);
ffDetectMediaImpl(&result);
if(result.song.length == 0 && result.error.length == 0)
ffStrbufAppendS(&result.error, "No media found");
);
}
return &result;
}
-1
View File
@@ -79,7 +79,6 @@ static const char* getMedia(FFMediaResult* result)
void ffDetectMediaImpl(FFMediaResult* media)
{
FF_UNUSED(instance)
const char* error = getMedia(media);
ffStrbufAppendS(&media->error, error);
}
+1 -1
View File
@@ -9,7 +9,7 @@
static void getData(FFstrbuf* buffer, const char* ifName, bool isDefaultRoute, FFstrbuf* path, FFlist* result)
{
ffStrbufSetF(path, "/sys/class/net/%s/operstate", ifName);
if(!ffReadFileBuffer(path->chars, buffer) || !ffStrbufEqualS(buffer, "up"))
if(!ffReadFileBuffer(path->chars, buffer) || !ffStrbufEqualS(buffer, "up\n"))
return;
FFNetIOResult* counters = (FFNetIOResult*) ffListAdd(result);
+16 -4
View File
@@ -1,11 +1,23 @@
#include "os.h"
#include "detection/internal.h"
void ffDetectOSImpl(FFOSResult* os);
const FFOSResult* ffDetectOS(void)
{
FF_DETECTION_INTERNAL_GUARD(FFOSResult,
ffDetectOSImpl(&result)
);
static FFOSResult result;
if (result.name.chars == NULL)
{
ffStrbufInit(&result.name);
ffStrbufInit(&result.prettyName);
ffStrbufInit(&result.id);
ffStrbufInit(&result.version);
ffStrbufInit(&result.versionID);
ffStrbufInit(&result.codename);
ffStrbufInit(&result.buildID);
ffStrbufInit(&result.idLike);
ffStrbufInit(&result.variant);
ffStrbufInit(&result.variantID);
ffDetectOSImpl(&result);
}
return &result;
}
+3 -11
View File
@@ -3,25 +3,17 @@
void ffDetectOSImpl(FFOSResult* os)
{
ffStrbufInitStatic(&os->name, "Android");
ffStrbufSetStatic(&os->name, "Android");
ffStrbufInitStatic(&os->prettyName, "Android");
ffStrbufSetStatic(&os->prettyName, "Android");
ffStrbufInitStatic(&os->id, "android");
ffStrbufSetStatic(&os->id, "android");
ffStrbufInit(&os->version);
ffSettingsGetAndroidProperty("ro.build.version.release", &os->version);
ffStrbufInit(&os->versionID);
ffSettingsGetAndroidProperty("ro.build.version.release", &os->versionID);
ffStrbufInit(&os->codename);
ffSettingsGetAndroidProperty("ro.build.version.codename", &os->codename);
ffStrbufInit(&os->buildID);
ffSettingsGetAndroidProperty("ro.build.id", &os->buildID);
ffStrbufInit(&os->idLike);
ffStrbufInit(&os->variant);
ffStrbufInit(&os->variantID);
}
-12
View File
@@ -98,18 +98,6 @@ static void parseOSXSoftwareLicense(FFOSResult* os)
void ffDetectOSImpl(FFOSResult* os)
{
ffStrbufInit(&os->name);
ffStrbufInit(&os->version);
ffStrbufInit(&os->buildID);
ffStrbufInit(&os->id);
ffStrbufInit(&os->prettyName);
ffStrbufInit(&os->versionID);
ffStrbufInit(&os->codename);
ffStrbufInit(&os->idLike);
ffStrbufInit(&os->variant);
ffStrbufInit(&os->variantID);
parseSystemVersion(os);
if(ffStrbufStartsWithIgnCaseS(&os->name, "MacOS"))
+1 -11
View File
@@ -126,6 +126,7 @@ static void getDebianVersion(FFOSResult* result)
{
FF_STRBUF_AUTO_DESTROY debianVersion = ffStrbufCreate();
ffAppendFileBuffer("/etc/debian_version", &debianVersion);
ffStrbufTrimRightSpace(&debianVersion);
if (!debianVersion.length) return;
ffStrbufSet(&result->version, &debianVersion);
ffStrbufSet(&result->versionID, &debianVersion);
@@ -166,17 +167,6 @@ static void detectOS(FFOSResult* os)
void ffDetectOSImpl(FFOSResult* os)
{
ffStrbufInit(&os->name);
ffStrbufInit(&os->prettyName);
ffStrbufInit(&os->id);
ffStrbufInit(&os->idLike);
ffStrbufInit(&os->variant);
ffStrbufInit(&os->variantID);
ffStrbufInit(&os->version);
ffStrbufInit(&os->versionID);
ffStrbufInit(&os->codename);
ffStrbufInit(&os->buildID);
detectOS(os);
if(ffStrbufIgnCaseEqualS(&os->id, "ubuntu"))
-11
View File
@@ -42,17 +42,6 @@ static const char* getOsNameByWinbrand(FFstrbuf* osName)
extern "C"
void ffDetectOSImpl(FFOSResult* os)
{
ffStrbufInit(&os->name);
ffStrbufInit(&os->prettyName);
ffStrbufInit(&os->id);
ffStrbufInit(&os->idLike);
ffStrbufInit(&os->variant);
ffStrbufInit(&os->variantID);
ffStrbufInit(&os->version);
ffStrbufInit(&os->versionID);
ffStrbufInit(&os->codename);
ffStrbufInit(&os->buildID);
if(getOsNameByWinbrand(&os->variant) && getOsNameByWmi(&os->variant))
return;
-1
View File
@@ -1,5 +1,4 @@
#include "packages.h"
#include "detection/internal.h"
#include <stddef.h>
@@ -1,5 +1,7 @@
#include "fastfetch.h"
#define FF_PHYSICALDISK_TEMP_UNSET (0/0.0)
typedef enum FFPhysicalDiskType
{
FF_PHYSICALDISK_TYPE_NONE = 0,
@@ -10,6 +12,9 @@ typedef enum FFPhysicalDiskType
FF_PHYSICALDISK_TYPE_FIXED = 1 << 2,
FF_PHYSICALDISK_TYPE_REMOVABLE = 1 << 3,
FF_PHYSICALDISK_TYPE_READWRITE = 1 << 4,
FF_PHYSICALDISK_TYPE_READONLY = 1 << 5,
} FFPhysicalDiskType;
typedef struct FFPhysicalDiskResult
@@ -18,8 +23,10 @@ typedef struct FFPhysicalDiskResult
FFstrbuf interconnect;
FFstrbuf serial;
FFstrbuf devPath;
FFstrbuf revision;
FFPhysicalDiskType type;
uint64_t size;
double temperature;
} FFPhysicalDiskResult;
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options);
@@ -7,6 +7,7 @@
#include <IOKit/storage/IOBlockStorageDriver.h>
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
#include <IOKit/storage/nvme/NVMeSMARTLibExternal.h>
static inline void wrapIoObjectRelease(io_service_t* service)
{
@@ -16,6 +17,35 @@ static inline void wrapIoObjectRelease(io_service_t* service)
}
#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease)))
static inline void wrapIoDestroyPlugInInterface(IOCFPlugInInterface*** pluginInf)
{
assert(pluginInf);
if (*pluginInf)
IODestroyPlugInInterface(*pluginInf);
}
static const char* detectSsdTemp(io_service_t entryPhysical, double* temp)
{
__attribute__((__cleanup__(wrapIoDestroyPlugInInterface))) IOCFPlugInInterface** pluginInf = NULL;
int32_t score;
if (IOCreatePlugInInterfaceForService(entryPhysical, kIONVMeSMARTUserClientTypeID, kIOCFPlugInInterfaceID, &pluginInf, &score) != kIOReturnSuccess)
return "IOCreatePlugInInterfaceForService() failed";
IONVMeSMARTInterface** smartInf = NULL;
if ((*pluginInf)->QueryInterface(pluginInf, CFUUIDGetUUIDBytes(kIONVMeSMARTInterfaceID), (LPVOID) &smartInf) != kIOReturnSuccess)
return "QueryInterface() failed";
NVMeSMARTData smartData;
const char* error = NULL;
if ((*smartInf)->SMARTReadData(smartInf, &smartData) == kIOReturnSuccess)
*temp = smartData.TEMPERATURE - 273;
else
error = "SMARTReadData() failed";
(*pluginInf)->Release(smartInf);
return error;
}
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
{
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0;
@@ -43,15 +73,20 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
ffStrbufInit(&device->serial);
ffStrbufInit(&device->revision);
ffStrbufInitS(&device->name, deviceName);
ffStrbufInit(&device->devPath);
ffStrbufInit(&device->interconnect);
device->type = FF_PHYSICALDISK_TYPE_NONE;
device->size = 0;
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
FF_CFTYPE_AUTO_RELEASE CFBooleanRef removable = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOMediaRemovableKey), kCFAllocatorDefault, kNilOptions);
device->type |= CFBooleanGetValue(removable) ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
FF_CFTYPE_AUTO_RELEASE CFBooleanRef writable = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOMediaWritableKey), kCFAllocatorDefault, kNilOptions);
device->type |= CFBooleanGetValue(writable) ? FF_PHYSICALDISK_TYPE_READWRITE : FF_PHYSICALDISK_TYPE_READONLY;
FF_CFTYPE_AUTO_RELEASE CFStringRef bsdName = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, kNilOptions);
if (bsdName)
{
@@ -76,6 +111,9 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
if (deviceCharacteristics)
{
ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductSerialNumberKey), &device->serial);
ffStrbufTrim(&device->serial, ' ');
ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductRevisionLevelKey), &device->revision);
ffStrbufTrim(&device->revision, ' ');
CFStringRef mediumType = (CFStringRef) CFDictionaryGetValue(deviceCharacteristics, CFSTR(kIOPropertyMediumTypeKey));
if (mediumType)
@@ -86,6 +124,13 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
device->type |= FF_PHYSICALDISK_TYPE_HDD;
}
}
if (options->temp)
{
FF_CFTYPE_AUTO_RELEASE CFBooleanRef nvmeSMARTCapable = IORegistryEntryCreateCFProperty(entryPhysical, CFSTR(kIOPropertyNVMeSMARTCapableKey), kCFAllocatorDefault, kNilOptions);
if (nvmeSMARTCapable && CFBooleanGetValue(nvmeSMARTCapable))
detectSsdTemp(entryPhysical, &device->temperature);
}
}
}
@@ -32,6 +32,10 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
if (provider->lg_geom->lg_rank != 1)
continue;
// Should memory disk (MD) be considered as physical disk?
//if (!ffStrEquals(provider->lg_geom->lg_class->lg_name, "DISK"))
// continue;
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateS(provider->lg_name);
FF_STRBUF_AUTO_DESTROY identifier = ffStrbufCreate();
FFPhysicalDiskType type = FF_PHYSICALDISK_TYPE_NONE;
@@ -43,6 +47,13 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
type |= ffStrEquals(ptr->lg_val, "0") ? FF_PHYSICALDISK_TYPE_SSD : FF_PHYSICALDISK_TYPE_HDD;
else if (ffStrEquals(ptr->lg_name, "ident"))
ffStrbufSetS(&identifier, ptr->lg_val);
else if (ffStrEquals(ptr->lg_name, "access"))
{
if (ffStrEquals(ptr->lg_val, "read-only"))
type |= FF_PHYSICALDISK_TYPE_READONLY;
else if (ffStrEquals(ptr->lg_val, "read-write"))
type |= FF_PHYSICALDISK_TYPE_READWRITE;
}
}
if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix))
@@ -51,16 +62,29 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
ffStrbufInitMove(&device->serial, &identifier);
ffStrbufInit(&device->revision);
ffStrbufInit(&device->interconnect);
switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK)
{
case DEVSTAT_TYPE_IF_SCSI: ffStrbufAppendS(&device->interconnect, "SCSI"); break;
case DEVSTAT_TYPE_IF_IDE: ffStrbufAppendS(&device->interconnect, "IDE"); break;
case DEVSTAT_TYPE_IF_OTHER: ffStrbufAppendS(&device->interconnect, "OTHER"); break;
// https://github.com/freebsd/freebsd-src/commit/d282baddb0b029ca8466d23ac51e95c918442535
case 0x040 /*DEVSTAT_TYPE_IF_NVME*/: ffStrbufAppendS(&device->interconnect, "NVMe"); break;
}
device->size = (uint64_t) provider->lg_mediasize;
ffStrbufInitMove(&device->name, &name);
if (!(device->type & FF_PHYSICALDISK_TYPE_READONLY) && !(device->type & FF_PHYSICALDISK_TYPE_READWRITE))
{
int acr = 1, acw = 1; // Number of partitions mounted for reading or writing
if (sscanf(provider->lg_mode, "r%dw%de%*d", &acr, &acw) == 2 && acr)
type |= acw ? FF_PHYSICALDISK_TYPE_READWRITE : FF_PHYSICALDISK_TYPE_READONLY;
}
device->type = type;
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
}
geom_stats_snapshot_free(snap);
+66 -12
View File
@@ -1,6 +1,7 @@
#include "physicaldisk.h"
#include "common/io/io.h"
#include "common/properties.h"
#include "detection/temps/temps_linux.h"
#include "util/stringUtils.h"
#include <ctype.h>
@@ -42,16 +43,37 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
{
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/vendor", devName);
ffAppendFileBuffer(pathSysBlock, &device->name);
if (device->name.length > 0)
ffStrbufAppendC(&device->name, ' ');
if (ffAppendFileBuffer(pathSysBlock, &device->name))
{
ffStrbufTrimRightSpace(&device->name);
if (device->name.length > 0)
ffStrbufAppendC(&device->name, ' ');
}
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/model", devName);
ffAppendFileBuffer(pathSysBlock, &device->name);
ffStrbufTrim(&device->name, ' ');
ffStrbufTrimRightSpace(&device->name);
if (device->name.length == 0)
ffStrbufSetS(&device->name, devName);
else if (ffStrStartsWith(devName, "nvme"))
{
int devid, nsid;
if (sscanf(devName, "nvme%dn%d", &devid, &nsid) == 2)
{
bool multiNs = nsid > 1;
if (!multiNs)
{
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/nvme%dn2", devName, devid);
multiNs = ffPathExists(pathSysBlock, FF_PATHTYPE_DIRECTORY);
}
if (multiNs)
{
// In Asahi Linux, there are multiple namespaces for the same NVMe drive.
ffStrbufAppendF(&device->name, " - %d", nsid);
}
}
}
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
{
@@ -66,16 +88,18 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
{
ffStrbufInit(&device->interconnect);
if (strstr(pathSysDeviceReal, "/usb") != NULL)
ffStrbufSetS(&device->interconnect, "usb");
ffStrbufSetS(&device->interconnect, "USB");
else if (strstr(pathSysDeviceReal, "/nvme") != NULL)
ffStrbufSetS(&device->interconnect, "NVMe");
else if (strstr(pathSysDeviceReal, "/ata") != NULL)
ffStrbufSetS(&device->interconnect, "ATA");
else if (strstr(pathSysDeviceReal, "/scsi") != NULL)
ffStrbufSetS(&device->interconnect, "SCSI");
else
{
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/transport", devName);
if (!ffAppendFileBuffer(pathSysBlock, &device->interconnect))
{
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/uevent", devName);
if (ffParsePropFile(pathSysBlock, "DEVTYPE=", &device->interconnect))
ffStrbufSubstrBeforeLastC(&device->interconnect, '_');
}
if (ffAppendFileBuffer(pathSysBlock, &device->interconnect))
ffStrbufTrimRightSpace(&device->interconnect);
}
}
@@ -106,10 +130,40 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
device->type |= removableChar == '1' ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
}
{
char roChar = '0';
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/ro", devName);
if (ffReadFileData(pathSysBlock, 1, &roChar) > 0)
device->type |= roChar == '1' ? FF_PHYSICALDISK_TYPE_READONLY : FF_PHYSICALDISK_TYPE_READWRITE;
}
{
ffStrbufInit(&device->serial);
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/serial", devName);
ffReadFileBuffer(pathSysBlock, &device->serial);
if (ffReadFileBuffer(pathSysBlock, &device->serial))
ffStrbufTrimRightSpace(&device->serial);
}
{
ffStrbufInit(&device->revision);
snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/firmware_rev", devName);
if (ffReadFileBuffer(pathSysBlock, &device->revision))
ffStrbufTrimRightSpace(&device->revision);
}
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
if (options->temp)
{
const FFlist* tempsResult = ffDetectTemps();
FF_LIST_FOR_EACH(FFTempValue, value, *tempsResult)
{
if (ffStrStartsWith(devName, value->deviceName.chars)) // nvme0 - nvme0n1
{
device->temperature = value->value;
break;
}
}
}
}
+173 -81
View File
@@ -5,97 +5,102 @@
#include <windows.h>
#include <winioctl.h>
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysicalDiskOptions* options)
{
wchar_t szDevice[32] = L"\\\\.\\PhysicalDrive";
wchar_t* pNum = szDevice + strlen("\\\\.\\PhysicalDrive");
for (uint32_t idev = 0; ; ++idev)
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
return false;
DWORD retSize;
char sddBuffer[4096];
if(!DeviceIoControl(
hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&(STORAGE_PROPERTY_QUERY) {
.PropertyId = StorageDeviceProperty,
.QueryType = PropertyStandardQuery,
},
sizeof(STORAGE_PROPERTY_QUERY),
&sddBuffer,
sizeof(sddBuffer),
&retSize,
NULL
) || retSize == 0)
return true;
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
device->type = FF_PHYSICALDISK_TYPE_NONE;
STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
ffStrbufInit(&device->name);
if (sdd->VendorIdOffset != 0)
{
_ultow(idev, pNum, 10);
ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset);
ffStrbufTrim(&device->name, ' ');
}
if (sdd->ProductIdOffset != 0)
{
if (device->name.length)
ffStrbufAppendC(&device->name, ' ');
FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
break;
ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
ffStrbufTrimRight(&device->name, ' ');
}
DWORD retSize;
char sddBuffer[4096];
if(!DeviceIoControl(
hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&(STORAGE_PROPERTY_QUERY) {
.PropertyId = StorageDeviceProperty,
.QueryType = PropertyStandardQuery,
},
sizeof(STORAGE_PROPERTY_QUERY),
&sddBuffer,
sizeof(sddBuffer),
&retSize,
NULL
) || retSize == 0)
continue;
if (!device->name.length)
ffStrbufSetWS(&device->name, szDevice);
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
device->type = FF_PHYSICALDISK_TYPE_NONE;
STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer;
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
{
ffStrbufDestroy(&device->name);
result->length--;
return true;
}
ffStrbufInit(&device->name);
if (sdd->VendorIdOffset != 0)
{
ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset);
ffStrbufTrim(&device->name, ' ');
}
if (sdd->ProductIdOffset != 0)
{
if (device->name.length)
ffStrbufAppendC(&device->name, ' ');
ffStrbufInitWS(&device->devPath, szDevice);
ffStrbufInit(&device->serial);
if (sdd->SerialNumberOffset != 0)
{
ffStrbufSetS(&device->serial, (const char*) sddBuffer + sdd->SerialNumberOffset);
ffStrbufTrim(&device->serial, ' ');
}
ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset);
ffStrbufTrimRight(&device->name, ' ');
}
ffStrbufInit(&device->revision);
if (sdd->ProductRevisionOffset != 0)
{
ffStrbufSetS(&device->revision, (const char*) sddBuffer + sdd->ProductRevisionOffset);
ffStrbufTrim(&device->revision, ' ');
}
if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix))
{
ffStrbufDestroy(&device->name);
result->length--;
continue;
}
device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
ffStrbufInitWS(&device->devPath, szDevice);
ffStrbufInit(&device->serial);
if (sdd->SerialNumberOffset != 0)
{
ffStrbufSetS(&device->serial, (const char*) sddBuffer + sdd->SerialNumberOffset);
ffStrbufTrim(&device->serial, ' ');
}
device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
ffStrbufInit(&device->interconnect);
switch (sdd->BusType)
{
case BusTypeUnknown: ffStrbufSetStatic(&device->interconnect, "Unknown"); break;
case BusTypeScsi: ffStrbufSetStatic(&device->interconnect, "Scsi"); break;
case BusTypeAtapi: ffStrbufSetStatic(&device->interconnect, "Atapi"); break;
case BusTypeAta: ffStrbufSetStatic(&device->interconnect, "Ata"); break;
case BusType1394: ffStrbufSetStatic(&device->interconnect, "1394"); break;
case BusTypeSsa: ffStrbufSetStatic(&device->interconnect, "Ssa"); break;
case BusTypeFibre: ffStrbufSetStatic(&device->interconnect, "Fibra"); break;
case BusTypeUsb: ffStrbufSetStatic(&device->interconnect, "Usb"); break;
case BusTypeRAID: ffStrbufSetStatic(&device->interconnect, "RAID"); break;
case BusTypeiScsi: ffStrbufSetStatic(&device->interconnect, "iScsi"); break;
case BusTypeSas: ffStrbufSetStatic(&device->interconnect, "Sas"); break;
case BusTypeSata: ffStrbufSetStatic(&device->interconnect, "Sata"); break;
case BusTypeSd: ffStrbufSetStatic(&device->interconnect, "Sd"); break;
case BusTypeMmc: ffStrbufSetStatic(&device->interconnect, "Mmc"); break;
case BusTypeVirtual: ffStrbufSetStatic(&device->interconnect, "Virtual"); break;
case BusTypeFileBackedVirtual: ffStrbufSetStatic(&device->interconnect, "FileBackedVirtual"); break;
case BusTypeSpaces: ffStrbufSetStatic(&device->interconnect, "Spaces"); break;
case BusTypeNvme: ffStrbufSetStatic(&device->interconnect, "Nvme"); break;
case BusTypeSCM: ffStrbufSetStatic(&device->interconnect, "SCM"); break;
case BusTypeUfs: ffStrbufSetStatic(&device->interconnect, "Ufs"); break;
default: ffStrbufSetF(&device->interconnect, "Unknown (%d)", (int) sdd->BusType); break;
}
ffStrbufInit(&device->interconnect);
switch (sdd->BusType)
{
case BusTypeUnknown: ffStrbufSetStatic(&device->interconnect, "Unknown"); break;
case BusTypeScsi: ffStrbufSetStatic(&device->interconnect, "SCSI"); break;
case BusTypeAtapi: ffStrbufSetStatic(&device->interconnect, "ATAPI"); break;
case BusTypeAta: ffStrbufSetStatic(&device->interconnect, "ATA"); break;
case BusType1394: ffStrbufSetStatic(&device->interconnect, "1394"); break;
case BusTypeSsa: ffStrbufSetStatic(&device->interconnect, "SSA"); break;
case BusTypeFibre: ffStrbufSetStatic(&device->interconnect, "Fibre"); break;
case BusTypeUsb: ffStrbufSetStatic(&device->interconnect, "USB"); break;
case BusTypeRAID: ffStrbufSetStatic(&device->interconnect, "RAID"); break;
case BusTypeiScsi: ffStrbufSetStatic(&device->interconnect, "iSCSI"); break;
case BusTypeSas: ffStrbufSetStatic(&device->interconnect, "SAS"); break;
case BusTypeSata: ffStrbufSetStatic(&device->interconnect, "SATA"); break;
case BusTypeSd: ffStrbufSetStatic(&device->interconnect, "SD"); break;
case BusTypeMmc: ffStrbufSetStatic(&device->interconnect, "MMC"); break;
case BusTypeVirtual: ffStrbufSetStatic(&device->interconnect, "Virtual"); break;
case BusTypeFileBackedVirtual: ffStrbufSetStatic(&device->interconnect, "File Backed Virtual"); break;
case BusTypeSpaces: ffStrbufSetStatic(&device->interconnect, "Spaces"); break;
case BusTypeNvme: ffStrbufSetStatic(&device->interconnect, "NVMe"); break;
case BusTypeSCM: ffStrbufSetStatic(&device->interconnect, "SCM"); break;
case BusTypeUfs: ffStrbufSetStatic(&device->interconnect, "UFS"); break;
default: ffStrbufSetF(&device->interconnect, "Unknown (%d)", (int) sdd->BusType); break;
}
{
DEVICE_SEEK_PENALTY_DESCRIPTOR dspd = {};
if(DeviceIoControl(
hDevice,
@@ -111,7 +116,9 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
NULL
) && retSize == sizeof(dspd))
device->type |= dspd.IncursSeekPenalty ? FF_PHYSICALDISK_TYPE_HDD : FF_PHYSICALDISK_TYPE_SSD;
}
{
DISK_GEOMETRY_EX dge = {};
if(DeviceIoControl(
hDevice,
@@ -127,5 +134,90 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
device->size = 0;
}
{
uint8_t buffer[sizeof(GET_MEDIA_TYPES) + sizeof(DEVICE_MEDIA_INFO) * 7] = "";
GET_MEDIA_TYPES* gmt = (GET_MEDIA_TYPES*) buffer;
if(DeviceIoControl(
hDevice,
IOCTL_STORAGE_GET_MEDIA_TYPES_EX,
NULL,
0,
gmt,
sizeof(buffer),
&retSize,
NULL) && gmt->MediaInfoCount > 0
)
{
// DiskInfo and RemovableDiskInfo have the same structures. TapeInfo doesn't.
if (gmt->DeviceType != FILE_DEVICE_TAPE)
{
__typeof__(gmt->MediaInfo[0].DeviceSpecific.DiskInfo)* diskInfo = &gmt->MediaInfo[0].DeviceSpecific.DiskInfo;
if (diskInfo->MediaCharacteristics & MEDIA_READ_ONLY)
device->type |= FF_PHYSICALDISK_TYPE_READONLY;
else if (diskInfo->MediaCharacteristics & MEDIA_READ_WRITE)
device->type |= FF_PHYSICALDISK_TYPE_READWRITE;
if (device->size == 0)
device->size = (uint64_t) diskInfo->NumberMediaSides * diskInfo->TracksPerCylinder * diskInfo->SectorsPerTrack * diskInfo->BytesPerSector;
}
else
{
__typeof__(gmt->MediaInfo[0].DeviceSpecific.TapeInfo)* tapeInfo = &gmt->MediaInfo[0].DeviceSpecific.TapeInfo;
if (tapeInfo->MediaCharacteristics & MEDIA_READ_ONLY)
device->type |= FF_PHYSICALDISK_TYPE_READONLY;
else if (tapeInfo->MediaCharacteristics & MEDIA_READ_WRITE)
device->type |= FF_PHYSICALDISK_TYPE_READWRITE;
}
}
}
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
if (options->temp)
{
STORAGE_TEMPERATURE_DATA_DESCRIPTOR stdd = {};
if(DeviceIoControl(
hDevice,
IOCTL_STORAGE_QUERY_PROPERTY,
&(STORAGE_PROPERTY_QUERY) {
.PropertyId = StorageDeviceTemperatureProperty,
.QueryType = PropertyStandardQuery,
},
sizeof(STORAGE_PROPERTY_QUERY),
&stdd,
sizeof(stdd),
&retSize,
NULL
) && retSize == sizeof(stdd))
device->temperature = stdd.TemperatureInfo[0].Temperature;
}
return true;
}
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
{
{
wchar_t szPhysicalDrive[32] = L"\\\\.\\PhysicalDrive";
wchar_t* pNum = szPhysicalDrive + strlen("\\\\.\\PhysicalDrive");
for (uint32_t idev = 0; ; ++idev)
{
_ultow(idev, pNum, 10);
if (!detectPhysicalDisk(szPhysicalDrive, result, options))
break;
}
}
{
wchar_t szCdrom[32] = L"\\\\.\\CDROM";
wchar_t* pNum = szCdrom + strlen("\\\\.\\CDROM");
for (uint32_t idev = 0; ; ++idev)
{
_ultow(idev, pNum, 10);
if (!detectPhysicalDisk(szCdrom, result, options))
break;
}
}
return NULL;
}
+14 -9
View File
@@ -287,7 +287,7 @@ static bool detectTemp(io_connect_t conn, const char *sensor, double* sum)
return true;
}
const char *ffDetectCoreTemps(enum FFTempType type, double *result)
const char *ffDetectSmcTemps(enum FFTempType type, double *result)
{
static io_connect_t conn;
static dispatch_once_t once_control;
@@ -323,14 +323,19 @@ const char *ffDetectCoreTemps(enum FFTempType type, double *result)
break;
case FF_TEMP_CPU_M2X:
count += detectTemp(conn, "Tp0A", result); // CPU core 1
count += detectTemp(conn, "Tp0D", result); // CPU core 2
count += detectTemp(conn, "Tp0E", result); // CPU core 3
count += detectTemp(conn, "Tp01", result); // CPU core 4
count += detectTemp(conn, "Tp02", result); // CPU core 5
count += detectTemp(conn, "Tp05", result); // CPU core 6
count += detectTemp(conn, "Tp06", result); // CPU core 7
count += detectTemp(conn, "Tp09", result); // CPU core 8
count += detectTemp(conn, "Tp1h", result); // CPU efficiency core 1
count += detectTemp(conn, "Tp1t", result); // CPU efficiency core 2
count += detectTemp(conn, "Tp1p", result); // CPU efficiency core 3
count += detectTemp(conn, "Tp1l", result); // CPU efficiency core 4
count += detectTemp(conn, "Tp01", result); // CPU performance core 1
count += detectTemp(conn, "Tp05", result); // CPU performance core 2
count += detectTemp(conn, "Tp09", result); // CPU performance core 3
count += detectTemp(conn, "Tp0D", result); // CPU performance core 4
count += detectTemp(conn, "Tp0X", result); // CPU performance core 5
count += detectTemp(conn, "Tp0b", result); // CPU performance core 6
count += detectTemp(conn, "Tp0f", result); // CPU performance core 7
count += detectTemp(conn, "Tp0j", result); // CPU performance core 8
break;
case FF_TEMP_CPU_M3X:
+1 -1
View File
@@ -29,4 +29,4 @@ enum FFTempType
FF_TEMP_MEMORY,
};
const char *ffDetectCoreTemps(enum FFTempType type, double* result);
const char *ffDetectSmcTemps(enum FFTempType type, double* result);
+17
View File
@@ -26,6 +26,7 @@ static bool parseHwmonDir(FFstrbuf* dir, FFTempValue* value)
ffStrbufAppendS(dir, "name");
ffReadFileBuffer(dir->chars, &value->name);
ffStrbufTrimRightSpace(&value->name);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufAppendS(dir, "device/class");
@@ -35,9 +36,25 @@ static bool parseHwmonDir(FFstrbuf* dir, FFTempValue* value)
ffStrbufAppendS(dir, "device/device/class");
ffReadFileBuffer(dir->chars, &valueBuffer);
}
ffStrbufTrimRightSpace(&valueBuffer);
ffStrbufSubstrBefore(dir, dirLength);
if(valueBuffer.length)
value->deviceClass = (uint32_t) strtoul(valueBuffer.chars, NULL, 16);
ffStrbufClear(&valueBuffer);
ffStrbufEnsureFree(&valueBuffer, 64);
ffStrbufAppendS(dir, "device");
ssize_t linkLen = readlink(dir->chars, valueBuffer.chars, valueBuffer.allocated - 1);
if (linkLen > 0)
{
valueBuffer.length = (uint32_t) linkLen;
valueBuffer.chars[linkLen] = 0;
ffStrbufSubstrAfterLastC(&valueBuffer, '/');
ffStrbufInitMove(&value->deviceName, &valueBuffer);
}
else
ffStrbufInit(&value->deviceName);
return value->name.length > 0 || value->deviceClass > 0;
}
+1
View File
@@ -5,6 +5,7 @@
typedef struct FFTempValue
{
FFstrbuf name;
FFstrbuf deviceName;
uint32_t deviceClass;
double value;
} FFTempValue;
@@ -1,7 +1,6 @@
#include "terminalfont.h"
#include "common/properties.h"
#include "common/processing.h"
#include "detection/internal.h"
#include "detection/terminalshell/terminalshell.h"
static void detectAlacritty(FFTerminalFontResult* terminalFont)
@@ -172,10 +172,9 @@ static void detectDeepinTerminal(FFTerminalFontResult* terminalFont)
{
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY profile = ffStrbufCreate();
ffStrbufAppend(&profile, &instance.state.platform.homeDir);
ffStrbufAppendS(&profile, ".config/deepin/deepin-terminal/config.conf"); //TODO: Use config dirs
FF_STRBUF_AUTO_DESTROY profile = ffStrbufCreateA(64);
ffSearchUserConfigFile(&instance.state.platform.configDirs, "deepin/deepin-terminal/config.conf", &profile);
FILE* file = fopen(profile.chars, "r");
if(file)
@@ -37,6 +37,7 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex
if(ffAppendFileBuffer(cmdlineFilePath, exe))
{
ffStrbufTrimRightSpace(exe);
ffStrbufSubstrBeforeFirstC(exe, '\0'); //Trim the arguments
ffStrbufTrimLeft(exe, '-'); //Happens in TTY
}
@@ -180,7 +181,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid)
#ifdef __APPLE__
// https://github.com/fastfetch-cli/fastfetch/discussions/501
if (ffStrEndsWith(name, " (figterm)"))
if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)"))
getProcessNameAndPpid(ppid, name, &ppid);
#endif
+21 -21
View File
@@ -141,10 +141,14 @@ static const char* detectVulkan(FFVulkanResult* result)
else
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties.properties);
//We don't want software rasterizers to show up as physical gpu
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
continue;
//If the device api version is higher than the current highest device api version, overwrite it
//In this case, also use the current device driver name as the shown driver name
FFVersion deviceAPIVersion = FF_VERSION_INIT;
applyVulkanVersion(physicalDeviceProperties.properties.apiVersion, &deviceAPIVersion);
if(ffVersionCompare(&deviceAPIVersion, &maxDeviceApiVersion) > 0)
@@ -168,20 +172,17 @@ static const char* detectVulkan(FFVulkanResult* result)
//Add the device to the list of devices shown by the GPU module
//We don't want software rasterizers to show up as physical gpu
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
continue;
// #456
FF_LIST_FOR_EACH(FFGPUResult, gpu, result->gpus)
{
if (gpu->vulkanDeviceId == physicalDeviceProperties.properties.deviceID)
if (gpu->deviceId == physicalDeviceProperties.properties.deviceID)
goto next;
}
FFGPUResult* gpu = ffListAdd(&result->gpus);
gpu->vulkanDeviceId = physicalDeviceProperties.properties.deviceID;
ffStrbufInitF(&gpu->platformApi, "Vulkan %u.%u.%u", deviceAPIVersion.major, deviceAPIVersion.minor, deviceAPIVersion.patch);
gpu->deviceId = physicalDeviceProperties.properties.deviceID;
ffStrbufInitS(&gpu->name, physicalDeviceProperties.properties.deviceName);
@@ -204,6 +205,7 @@ static const char* detectVulkan(FFVulkanResult* result)
//No way to detect those using vulkan
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
next:
continue;
@@ -228,22 +230,20 @@ static const char* detectVulkan(FFVulkanResult* result)
FFVulkanResult* ffDetectVulkan(void)
{
static FFVulkanResult result;
static bool init = false;
if(init)
return &result;
init = true;
if (result.gpus.elementSize == 0)
{
ffStrbufInit(&result.driver);
ffStrbufInit(&result.apiVersion);
ffStrbufInit(&result.conformanceVersion);
ffListInit(&result.gpus, sizeof(FFGPUResult));
ffStrbufInit(&result.driver);
ffStrbufInit(&result.apiVersion);
ffStrbufInit(&result.conformanceVersion);
ffListInit(&result.gpus, sizeof(FFGPUResult));
#ifdef FF_HAVE_VULKAN
result.error = detectVulkan(&result);
#else
result.error = "fastfetch was compiled without vulkan support";
#endif
#ifdef FF_HAVE_VULKAN
result.error = detectVulkan(&result);
#else
result.error = "fastfetch was compiled without vulkan support";
#endif
}
return &result;
}
+29 -5
View File
@@ -157,7 +157,7 @@ const char* ffDetectWifi(FFlist* result)
NSDictionary* authType = [apple valueForKey:@"AUTH_TYPE"];
if (authType)
{
if ([[authType valueForKey:@"AUTH_LOWER"] intValue] != 1) break; // APPLE80211_AUTH_TYPE_UNICAST?
// AUTH_LOWER seems useless. `airport` verifies if its value is between 1 and 3, and prints `unknown` if not
NSNumber* authUpper = [authType valueForKey:@"AUTH_UPPER"];
if (!authUpper)
@@ -167,14 +167,38 @@ const char* ffDetectWifi(FFlist* result)
int authUpperValue = [authUpper intValue];
switch (authUpperValue)
{
case 4096:
ffStrbufSetStatic(&item->conn.security, "WPA3-SAE");
case 1:
ffStrbufSetStatic(&item->conn.security, "WPA");
break;
case 2:
ffStrbufSetStatic(&item->conn.security, "WPA-PSK");
break;
case 4:
ffStrbufSetStatic(&item->conn.security, "WPA2");
break;
case 8:
ffStrbufSetStatic(&item->conn.security, "WPA2-PSK");
break;
case 4:
ffStrbufSetStatic(&item->conn.security, "WPA2");
case 16:
ffStrbufSetStatic(&item->conn.security, "FT-WPA2-PSK");
break;
case 32:
ffStrbufSetStatic(&item->conn.security, "LEAP");
break;
case 64:
ffStrbufSetStatic(&item->conn.security, "802.1X");
break;
case 128:
ffStrbufSetStatic(&item->conn.security, "FT-WPA2");
break;
case 256:
ffStrbufSetStatic(&item->conn.security, "WPS");
break;
case 4096:
ffStrbufSetStatic(&item->conn.security, "WPA3-SAE");
break;
case 8192:
ffStrbufSetStatic(&item->conn.security, "WPA3-FT-SAE");
break;
default: // TODO: support more auth types
ffStrbufAppendF(&item->conn.security, "To be supported (%d)", authUpperValue);
+1 -1
View File
@@ -248,7 +248,7 @@ static const char* detectWifiWithIoctls(FFlist* result)
item->conn.txRate = 0.0/0.0;
ffStrbufSetF(&path, "/sys/class/net/%s/operstate", i->if_name);
if(!ffAppendFileBuffer(path.chars, &item->inf.status) || !ffStrbufEqualS(&item->inf.status, "up"))
if (!ffAppendFileBuffer(path.chars, &item->inf.status) || !ffStrbufEqualS(&item->inf.status, "up\n"))
continue;
FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+37 -39
View File
@@ -1,4 +1,5 @@
#include "wmtheme.h"
#include "common/io/io.h"
#include "common/properties.h"
#include "common/parsing.h"
#include "common/settings.h"
@@ -132,60 +133,57 @@ static bool detectXFWM4(FFstrbuf* themeOrError)
static bool detectOpenbox(const FFstrbuf* dePrettyName, FFstrbuf* themeOrError)
{
FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA(64);
ffStrbufAppend(&absolutePath, &instance.state.platform.homeDir);
const char *configFileSubpath = "openbox/rc.xml";
if (ffStrbufIgnCaseCompS(dePrettyName, "LXQT") == 0)
configFileSubpath = "openbox/lxqt-rc.xml";
else if (ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0)
configFileSubpath = "openbox/lxde-rc.xml";
//TODO: use config dirs
if(ffStrbufIgnCaseCompS(dePrettyName, "LXQT") == 0)
ffStrbufAppendS(&absolutePath, ".config/openbox/lxqt-rc.xml");
else if(ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0)
ffStrbufAppendS(&absolutePath, ".config/openbox/lxde-rc.xml");
else
ffStrbufAppendS(&absolutePath, ".config/openbox/rc.xml");
char* line = NULL;
size_t len = 0;
FILE* file = fopen(absolutePath.chars, "r");
if(file == NULL)
if (!ffSearchUserConfigFile(&instance.state.platform.configDirs, configFileSubpath, &absolutePath))
{
ffStrbufAppendF(themeOrError, "Couldn't open \"%s\"", absolutePath.chars);
ffStrbufAppendF(themeOrError, "Couldn't find config file \"%s\"", configFileSubpath);
return false;
}
while(getline(&line, &len, file) != -1)
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
if (!ffReadFileBuffer(absolutePath.chars, &content))
{
if(strstr(line, "<theme>") != 0)
break;
ffStrbufAppendF(themeOrError, "Couldn't read \"%s\"", absolutePath.chars);
return false;
}
while(getline(&line, &len, file) != -1)
{
if(strstr(line, "<name>") != 0)
{
ffStrbufAppendS(themeOrError, line);
ffStrbufRemoveStrings(themeOrError, 2, (const char*[]) { "<name>", "</name>" });
ffStrbufTrimRight(themeOrError, '\n');
ffStrbufTrim(themeOrError, ' ');
break;
}
const char *themeStart = strstr(content.chars, "<theme>");
if (themeStart == NULL)
goto theme_not_found;
if(strstr(line, "</theme>") != 0) // sanity check
break;
}
const char *themeEnd = strstr(themeStart, "</theme>");
if (__builtin_expect(themeEnd == NULL, false)) // very rare case
goto theme_not_found;
if(line != NULL)
free(line);
const char *nameStart = strstr(themeStart, "<name>");
if (nameStart == NULL)
goto name_not_found;
fclose(file);
const char *nameEnd = strstr(nameStart, "</name>");
if (nameEnd == NULL || nameEnd > themeEnd) // (nameEnd > themeEnd) means name is not a theme's child
goto name_not_found;
nameStart += strlen("<name>");
ffStrbufAppendNS(themeOrError, (uint32_t)(nameEnd - nameStart), nameStart);
ffStrbufTrim(themeOrError, ' ');
if(themeOrError->length == 0)
{
ffStrbufAppendF(themeOrError, "Couldn't find theme name in \"%s\"", absolutePath.chars);
return false;
}
goto name_not_found;
return true;
theme_not_found:
ffStrbufAppendF(themeOrError, "Couldn't find theme node in \"%s\"", absolutePath.chars);
return false;
name_not_found:
ffStrbufAppendF(themeOrError, "Couldn't find theme name in \"%s\"", absolutePath.chars);
return false;
}
bool ffDetectWmTheme(FFstrbuf* themeOrError)
+11 -1
View File
@@ -267,7 +267,7 @@ static void listConfigPaths(void)
FF_LIST_FOR_EACH(FFstrbuf, folder, instance.state.platform.configDirs)
{
bool exists = false;
uint32_t length = folder->length + sizeof("fastfetch");
uint32_t length = folder->length + (uint32_t) strlen("fastfetch") + 1 /* trailing slash */;
ffStrbufAppendS(folder, "fastfetch/config.jsonc");
exists = ffPathExists(folder->chars, FF_PATHTYPE_FILE);
if (!exists)
@@ -501,6 +501,11 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val
ffStrbufAppendS(&absolutePath, value);
bool success = isJsonConfig ? parseJsoncFile(absolutePath.chars) : parseConfigFile(data, absolutePath.chars);
if (!success)
{
ffStrbufAppendS(&absolutePath, ".jsonc");
success = parseJsoncFile(absolutePath.chars);
}
if(success)
return;
@@ -514,6 +519,11 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val
ffStrbufAppendS(&absolutePath, value);
bool success = isJsonConfig ? parseJsoncFile(absolutePath.chars) : parseConfigFile(data, absolutePath.chars);
if (!success)
{
ffStrbufAppendS(&absolutePath, ".jsonc");
success = parseJsoncFile(absolutePath.chars);
}
if(success)
return;
+1 -1
View File
@@ -258,7 +258,7 @@ void ffInitBatteryOptions(FFBatteryOptions* options)
options->temp = false;
#ifdef __linux__
ffStrbufInit(&options->dir);
ffStrbufInitStatic(&options->dir, "/sys/class/power_supply/");
#elif defined(_WIN32)
options->useSetupApi = false;
#endif
+22 -8
View File
@@ -9,7 +9,7 @@
#include <stdlib.h>
#define FF_GPU_NUM_FORMAT_ARGS 10
#define FF_GPU_NUM_FORMAT_ARGS 12
static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResult* gpu)
{
@@ -38,6 +38,9 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu
if(gpu->coreCount != FF_GPU_CORE_COUNT_UNSET)
ffStrbufAppendF(&output, " (%d)", gpu->coreCount);
if(gpu->frequency == gpu->frequency && gpu->frequency > 0 /* Inactive? */)
ffStrbufAppendF(&output, " @ %.2f GHz", gpu->frequency);
if(gpu->temperature == gpu->temperature) //FF_GPU_TEMP_UNSET
{
ffStrbufAppendS(&output, " - ");
@@ -80,6 +83,8 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu
{FF_FORMAT_ARG_TYPE_UINT64, &gpu->dedicated.used},
{FF_FORMAT_ARG_TYPE_UINT64, &gpu->shared.total},
{FF_FORMAT_ARG_TYPE_UINT64, &gpu->shared.used},
{FF_FORMAT_ARG_TYPE_STRBUF, &gpu->platformApi},
{FF_FORMAT_ARG_TYPE_DOUBLE, &gpu->frequency},
});
}
}
@@ -129,9 +134,9 @@ bool ffParseGPUCommandOptions(FFGPUOptions* options, const char* key, const char
if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs))
return true;
if (ffStrEqualsIgnCase(subKey, "use-nvml"))
if (ffStrEqualsIgnCase(subKey, "driver-specific"))
{
options->useNvml = ffOptionParseBoolean(value);
options->driverSpecific = ffOptionParseBoolean(value);
return true;
}
@@ -179,9 +184,9 @@ void ffParseGPUJsonObject(FFGPUOptions* options, yyjson_val* module)
continue;
}
if (ffStrEqualsIgnCase(key, "useNvml"))
if (ffStrEqualsIgnCase(key, "driverSpecific"))
{
options->useNvml = yyjson_get_bool(val);
options->driverSpecific = yyjson_get_bool(val);
continue;
}
@@ -218,8 +223,8 @@ void ffGenerateGPUJsonConfig(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_
ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs);
if (options->useNvml != defaultOptions.useNvml)
yyjson_mut_obj_add_bool(doc, module, "useNvml", options->useNvml);
if (options->driverSpecific != defaultOptions.driverSpecific)
yyjson_mut_obj_add_bool(doc, module, "driverSpecific", options->driverSpecific);
if (options->forceVulkan != defaultOptions.forceVulkan)
yyjson_mut_obj_add_bool(doc, module, "forceVulkan", options->forceVulkan);
@@ -304,6 +309,13 @@ void ffGenerateGPUJsonResult(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_
yyjson_mut_obj_add_str(doc, obj, "type", type);
yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &gpu->vendor);
yyjson_mut_obj_add_strbuf(doc, obj, "platformApi", &gpu->platformApi);
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET)
yyjson_mut_obj_add_null(doc, obj, "frequency");
else
yyjson_mut_obj_add_real(doc, obj, "frequency", gpu->frequency);
}
FF_LIST_FOR_EACH(FFGPUResult, gpu, gpus)
@@ -327,6 +339,8 @@ void ffPrintGPUHelpFormat(void)
"GPU used dedicated memory",
"GPU total shared memory",
"GPU used shared memory",
"The platform API that GPU supports",
"Current frequency in GHz",
});
}
@@ -345,7 +359,7 @@ void ffInitGPUOptions(FFGPUOptions* options)
);
ffOptionInitModuleArg(&options->moduleArgs);
options->useNvml = false;
options->driverSpecific = false;
options->forceVulkan = false;
options->temp = false;
options->hideType = FF_GPU_TYPE_UNKNOWN;
+1 -1
View File
@@ -18,6 +18,6 @@ typedef struct FFGPUOptions
FFGPUType hideType;
bool temp;
bool useNvml;
bool driverSpecific;
bool forceVulkan;
} FFGPUOptions;
+1
View File
@@ -10,4 +10,5 @@ typedef struct FFPhysicalDiskOptions
FFModuleArgs moduleArgs;
FFstrbuf namePrefix;
bool temp;
} FFPhysicalDiskOptions;
+55 -3
View File
@@ -6,7 +6,7 @@
#include "util/stringUtils.h"
#define FF_PHYSICALDISK_DISPLAY_NAME "Physical Disk"
#define FF_PHYSICALDISK_NUM_FORMAT_ARGS 7
#define FF_PHYSICALDISK_NUM_FORMAT_ARGS 9
static int sortDevices(const FFPhysicalDiskResult* left, const FFPhysicalDiskResult* right)
{
@@ -63,28 +63,47 @@ void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options)
: dev->type & FF_PHYSICALDISK_TYPE_FIXED
? "Fixed"
: "";
const char* readOnlyType = dev->type & FF_PHYSICALDISK_TYPE_READONLY
? "Read-only"
: "";
if(options->moduleArgs.outputFormat.length == 0)
{
ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
if (physicalType[0] || removableType[0])
if (physicalType[0] || removableType[0] || readOnlyType[0])
{
ffStrbufAppendS(&buffer, " [");
if (physicalType[0])
ffStrbufAppendS(&buffer, physicalType);
if (removableType[0])
{
if (physicalType[0])
if (buffer.chars[buffer.length - 1] != '[')
ffStrbufAppendS(&buffer, ", ");
ffStrbufAppendS(&buffer, removableType);
}
if (readOnlyType[0])
{
if (buffer.chars[buffer.length - 1] != '[')
ffStrbufAppendS(&buffer, ", ");
ffStrbufAppendS(&buffer, readOnlyType);
}
ffStrbufAppendC(&buffer, ']');
}
if (dev->temperature == dev->temperature) //FF_PHYSICALDISK_TEMP_UNSET
{
if(buffer.length > 0)
ffStrbufAppendS(&buffer, " - ");
ffParseTemperature(dev->temperature, &buffer);
}
ffStrbufPutTo(&buffer, stdout);
}
else
{
if (dev->type & FF_PHYSICALDISK_TYPE_READWRITE)
readOnlyType = "Read-write";
ffParseSize(dev->size, &buffer);
ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_PHYSICALDISK_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &buffer},
@@ -94,6 +113,9 @@ void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options)
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->devPath},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->serial},
{FF_FORMAT_ARG_TYPE_STRING, removableType},
{FF_FORMAT_ARG_TYPE_STRING, readOnlyType},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->revision},
{FF_FORMAT_ARG_TYPE_DOUBLE, &dev->temperature},
});
}
++index;
@@ -121,6 +143,12 @@ bool ffParsePhysicalDiskCommandOptions(FFPhysicalDiskOptions* options, const cha
return true;
}
if (ffStrEqualsIgnCase(subKey, "temp"))
{
options->temp = ffOptionParseBoolean(value);
return true;
}
return false;
}
@@ -143,6 +171,12 @@ void ffParsePhysicalDiskJsonObject(FFPhysicalDiskOptions* options, yyjson_val* m
continue;
}
if (ffStrEqualsIgnCase(key, "temp"))
{
options->temp = yyjson_get_bool(val);
continue;
}
ffPrintError(FF_PHYSICALDISK_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
}
}
@@ -156,6 +190,9 @@ void ffGeneratePhysicalDiskJsonConfig(FFPhysicalDiskOptions* options, yyjson_mut
if (!ffStrbufEqual(&options->namePrefix, &defaultOptions.namePrefix))
yyjson_mut_obj_add_strbuf(doc, module, "namePrefix", &options->namePrefix);
if (options->temp != defaultOptions.temp)
yyjson_mut_obj_add_bool(doc, module, "temp", options->temp);
}
void ffGeneratePhysicalDiskJsonResult(FFPhysicalDiskOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -193,6 +230,17 @@ void ffGeneratePhysicalDiskJsonResult(FFPhysicalDiskOptions* options, yyjson_mut
yyjson_mut_obj_add_bool(doc, obj, "removable", false);
else
yyjson_mut_obj_add_null(doc, obj, "removable");
if (dev->type & FF_PHYSICALDISK_TYPE_READONLY)
yyjson_mut_obj_add_bool(doc, obj, "readOnly", true);
else if (dev->type & FF_PHYSICALDISK_TYPE_READWRITE)
yyjson_mut_obj_add_bool(doc, obj, "readOnly", false);
else
yyjson_mut_obj_add_null(doc, obj, "readOnly");
yyjson_mut_obj_add_strbuf(doc, obj, "revision", &dev->revision);
yyjson_mut_obj_add_real(doc, obj, "temperature", dev->temperature);
}
FF_LIST_FOR_EACH(FFPhysicalDiskResult, dev, result)
@@ -213,6 +261,9 @@ void ffPrintPhysicalDiskHelpFormat(void)
"Serial number",
"Device kind (SSD or HDD)",
"Device kind (Removable or Fixed)",
"Device kind (Read-only or Read-write)",
"Product revision",
"Device temperature",
});
}
@@ -232,6 +283,7 @@ void ffInitPhysicalDiskOptions(FFPhysicalDiskOptions* options)
ffOptionInitModuleArg(&options->moduleArgs);
ffStrbufInit(&options->namePrefix);
options->temp = false;
}
void ffDestroyPhysicalDiskOptions(FFPhysicalDiskOptions* options)
+1 -1
View File
@@ -130,7 +130,7 @@ void ffGenerateVulkanJsonResult(FF_MAYBE_UNUSED FFVulkanOptions* options, yyjson
yyjson_mut_obj_add_null(doc, sharedMemory, "used");
}
yyjson_mut_obj_add_uint(doc, gpuObj, "deviceId", vulkanGpu->vulkanDeviceId);
yyjson_mut_obj_add_uint(doc, gpuObj, "deviceId", vulkanGpu->deviceId);
}
}
+20 -17
View File
@@ -54,6 +54,7 @@ void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
strbuf->allocated = allocate;
}
// for an empty buffer, free + 1 length memory will be allocated(+1 for the NUL)
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free)
{
uint32_t oldFree = ffStrbufGetFree(strbuf);
@@ -64,7 +65,7 @@ void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free)
if(strbuf->allocated == 0)
{
newCap += strbuf->length + 1; // +1 for the NUL
newCap += strbuf->length + 1;
char* newbuf = malloc(sizeof(*strbuf->chars) * newCap);
if(strbuf->length == 0)
*newbuf = '\0';
@@ -118,22 +119,6 @@ void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value)
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufAppendNSExludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
{
if(value == NULL || length == 0)
return;
ffStrbufEnsureFree(strbuf, length);
for(uint32_t i = 0; i < length; i++)
{
if(value[i] != exclude)
strbuf->chars[strbuf->length++] = value[i];
}
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int))
{
if(value == NULL)
@@ -280,6 +265,24 @@ void ffStrbufTrimRight(FFstrbuf* strbuf, char c)
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufTrimRightSpace(FFstrbuf* strbuf)
{
if(strbuf->length == 0)
return;
while(ffStrbufEndsWithFn(strbuf, isspace))
--strbuf->length;
if(strbuf->allocated == 0)
{
//static string
ffStrbufInitNS(strbuf, strbuf->length, strbuf->chars);
return;
}
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endIndex)
{
if(startIndex > strbuf->length || startIndex >= endIndex)
+7 -1
View File
@@ -41,7 +41,6 @@ static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* _
void ffStrbufAppendC(FFstrbuf* strbuf, char c);
void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c);
void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value);
void ffStrbufAppendNSExludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude);
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int));
FF_C_PRINTF(2, 3) void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments);
@@ -55,6 +54,7 @@ FF_C_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
void ffStrbufTrimRight(FFstrbuf* strbuf, char c);
void ffStrbufTrimRightSpace(FFstrbuf* strbuf);
void ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endIndex);
void ffStrbufRemoveS(FFstrbuf* strbuf, const char* str);
@@ -454,6 +454,12 @@ static inline FF_C_NODISCARD bool ffStrbufEndsWithS(const FFstrbuf* strbuf, cons
return ffStrbufEndsWithNS(strbuf, (uint32_t) strlen(end), end);
}
static inline FF_C_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*fn)(int))
{
return strbuf->length == 0 ? false :
fn(strbuf->chars[strbuf->length - 1]);
}
static inline FF_C_NODISCARD bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end)
{
return ffStrbufEndsWithNS(strbuf, end->length, end->chars);
+22
View File
@@ -1,4 +1,5 @@
#include "smbiosHelper.h"
#include "common/io/io.h"
bool ffIsSmbiosValueSet(FFstrbuf* value)
{
@@ -26,3 +27,24 @@ bool ffIsSmbiosValueSet(FFstrbuf* value)
!ffStrbufIgnCaseEqualS(value, "N/A")
;
}
#ifdef __linux__
void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
{
if (ffReadFileBuffer(devicesPath, buffer))
{
ffStrbufTrimRightSpace(buffer);
if(ffIsSmbiosValueSet(buffer))
return;
}
if (ffReadFileBuffer(classPath, buffer))
{
ffStrbufTrimRightSpace(buffer);
if(ffIsSmbiosValueSet(buffer))
return;
}
ffStrbufClear(buffer);
}
#endif
+5 -1
View File
@@ -12,4 +12,8 @@ static inline void ffCleanUpSmbiosValue(FFstrbuf* value)
ffStrbufClear(value);
}
#endif
#ifdef __linux__
void ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer);
#endif
#endif
+7 -12
View File
@@ -2,7 +2,6 @@
#include "fastfetch.h"
#include <stdlib.h>
#include <synchapi.h>
//https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer
//https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/computer-system-hardware-classes
@@ -11,14 +10,11 @@ static void CoUninitializeWrap(void)
CoUninitialize();
}
static BOOL CALLBACK InitHandleFunction(FF_MAYBE_UNUSED PINIT_ONCE lpInitOnce, FF_MAYBE_UNUSED PVOID lpParameter, PVOID* lpContext)
static const char* doInitCom()
{
// Initialize COM
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
*lpContext = (PVOID) "CoInitializeEx() failed";
return FALSE;
}
return "CoInitializeEx() failed";
// Set general COM security levels
if (FAILED(CoInitializeSecurity(
@@ -34,18 +30,17 @@ static BOOL CALLBACK InitHandleFunction(FF_MAYBE_UNUSED PINIT_ONCE lpInitOnce, F
)))
{
CoUninitialize();
*lpContext = (PVOID) "CoInitializeSecurity() failed";
return FALSE;
return "CoInitializeSecurity() failed";
}
atexit(CoUninitializeWrap);
return TRUE;
return NULL;
}
const char* ffInitCom(void)
{
const char* error = NULL;
static INIT_ONCE s_InitOnce;
InitOnceExecuteOnce(&s_InitOnce, &InitHandleFunction, NULL, (void**)&error);
static const char* error = "";
if (error && error[0] == '\0')
error = doInitCom();
return error;
}
+5
View File
@@ -11,6 +11,11 @@ extern "C" {
#include <string_view>
static inline void ffStrbufInitWSV(FFstrbuf* result, const std::wstring_view source)
{
return ffStrbufInitNWS(result, (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());
+137
View File
@@ -0,0 +1,137 @@
#include <oaidl.h>
#include <type_traits>
#include <utility>
#include <string_view>
struct FFWmiVariant: VARIANT
{
explicit FFWmiVariant() { VariantInit(this); }
~FFWmiVariant() { VariantClear(this); }
FFWmiVariant(const FFWmiVariant&) = delete;
FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
bool hasValue() {
return this->vt != VT_EMPTY;
}
explicit operator bool() {
return this->hasValue();
}
template <typename T> T get()
{
// boolean
if constexpr (std::is_same_v<T, bool>) {
assert(this->vt == VT_BOOL);
return this->boolVal != VARIANT_FALSE;
}
// signed
else if constexpr (std::is_same_v<T, int8_t>) {
assert(this->vt == VT_I1);
return this->cVal;
}
else if constexpr (std::is_same_v<T, int16_t>) {
assert(vt == VT_I2);
return this->iVal;
}
else if constexpr (std::is_same_v<T, int32_t>) {
assert(this->vt == VT_I4 || vt == VT_INT);
return this->intVal;
}
else if constexpr (std::is_same_v<T, int64_t>) {
assert(this->vt == VT_I8);
return this->llVal;
}
// unsigned
else if constexpr (std::is_same_v<T, uint8_t>) {
assert(this->vt == VT_UI1);
return this->bVal;
}
else if constexpr (std::is_same_v<T, uint16_t>) {
assert(this->vt == VT_UI2);
return this->uiVal;
}
else if constexpr (std::is_same_v<T, uint32_t>) {
assert(this->vt == VT_UI4 || vt == VT_UINT);
return this->uintVal;
}
else if constexpr (std::is_same_v<T, uint64_t>) {
assert(this->vt == VT_UI8);
return this->ullVal;
}
// decimal
else if constexpr (std::is_same_v<T, float>) {
assert(this->vt == VT_R4);
return this->fltVal;
}
else if constexpr (std::is_same_v<T, double>) {
assert(this->vt == VT_R8);
return this->dblVal;
}
// string
else if constexpr (std::is_same_v<T, std::string_view>) {
assert(this->vt == VT_LPSTR);
return this->pcVal;
}
else if constexpr (std::is_same_v<T, std::wstring_view>) {
assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR);
if (this->vt == VT_LPWSTR)
return this->bstrVal;
else
return { this->bstrVal, SysStringLen(this->bstrVal) };
}
// array signed
else if constexpr (std::is_same_v<T, std::pair<const int8_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_I1);
return std::make_pair((int8_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const int16_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_I2);
return std::make_pair((int16_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const int32_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_I4);
return std::make_pair((int32_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const int64_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_I8);
return std::make_pair((int64_t*)this->parray->pvData, this->parray->cDims);
}
// array unsigned
else if constexpr (std::is_same_v<T, std::pair<const uint8_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_UI1);
return std::make_pair((uint8_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const uint16_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_UI2);
return std::make_pair((uint16_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const uint32_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_UI4);
return std::make_pair((uint32_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const uint64_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_UI8);
return std::make_pair((uint64_t*)this->parray->pvData, this->parray->cDims);
}
else {
assert(false && "unsupported type");
__builtin_unreachable();
}
}
};
+23 -28
View File
@@ -21,7 +21,7 @@ namespace
};
}
static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lpContext)
static const char* doInitService(const wchar_t* networkResource, IWbemServices** result)
{
HRESULT hres;
@@ -35,10 +35,7 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp
(LPVOID*) &pLoc);
if (FAILED(hres))
{
*((const char**)lpContext) = "Failed to create IWbemLocator object";
return FALSE;
}
return "Failed to create IWbemLocator object";
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices* pSvc = nullptr;
@@ -47,7 +44,7 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
bstr_t((const wchar_t*) lpParameter), // Object path of WMI namespace
bstr_t(networkResource), // Object path of WMI namespace
nullptr, // User name. nullptr = current user
nullptr, // User password. nullptr = current
0, // Locale. nullptr indicates current
@@ -60,10 +57,7 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp
pLoc = nullptr;
if (FAILED(hres))
{
*((const char**)lpContext) = "Could not connect WMI server";
return FALSE;
}
return "Could not connect WMI server";
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
@@ -80,39 +74,40 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp
if (FAILED(hres))
{
pSvc->Release();
*((const char**)lpContext) = "Could not set proxy blanket";
return FALSE;
return "Could not set proxy blanket";
}
*((IWbemServices**)lpContext) = pSvc;
return TRUE;
*result = pSvc;
return NULL;
}
FFWmiQuery::FFWmiQuery(const wchar_t* queryStr, FFstrbuf* error, FFWmiNamespace wmiNs)
: pEnumerator(nullptr)
{
const char* context = ffInitCom();
if (context)
const char* errStr;
if ((errStr = ffInitCom()))
{
if (error)
ffStrbufAppendS(error, context);
ffStrbufSetS(error, errStr);
return;
}
static INIT_ONCE s_InitOnce[(int) FFWmiNamespace::LAST] = {};
if (InitOnceExecuteOnce(
&s_InitOnce[(int)wmiNs],
&InitHandleFunction,
(PVOID) (wmiNs == FFWmiNamespace::CIMV2 ? L"ROOT\\CIMV2" : L"ROOT\\WMI"),
(void**)&context) == FALSE
) {
if(error)
ffStrbufAppendS(error, context);
return;
static IWbemServices* contexts[(int) FFWmiNamespace::LAST];
IWbemServices* context = contexts[(int)wmiNs];
if (!contexts[(int)wmiNs])
{
if ((errStr = doInitService(wmiNs == FFWmiNamespace::CIMV2 ? L"ROOT\\CIMV2" : L"ROOT\\WMI", &context)))
{
if (error)
ffStrbufSetS(error, errStr);
return;
}
contexts[(int)wmiNs] = context;
}
// Use the IWbemServices pointer to make requests of WMI
HRESULT hres = ((IWbemServices*)context)->ExecQuery(
HRESULT hres = context->ExecQuery(
bstr_t(L"WQL"),
bstr_t(queryStr),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+2 -135
View File
@@ -8,10 +8,9 @@ extern "C" {
#include <initguid.h>
#include <Wbemidl.h>
#include <utility>
#include <string_view>
#include <cassert>
#include <type_traits>
#include "variant.hpp"
enum class FFWmiNamespace {
CIMV2,
@@ -19,138 +18,6 @@ enum class FFWmiNamespace {
LAST,
};
struct FFWmiVariant: VARIANT {
explicit FFWmiVariant() { VariantInit(this); }
~FFWmiVariant() { VariantClear(this); }
FFWmiVariant(const FFWmiVariant&) = delete;
FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
bool hasValue() {
return this->vt != VT_EMPTY;
}
explicit operator bool() {
return this->hasValue();
}
template <typename T> T get()
{
// boolean
if constexpr (std::is_same_v<T, bool>) {
assert(this->vt == VT_BOOL);
return this->boolVal != VARIANT_FALSE;
}
// signed
else if constexpr (std::is_same_v<T, int8_t>) {
assert(this->vt == VT_I1);
return this->cVal;
}
else if constexpr (std::is_same_v<T, int16_t>) {
assert(vt == VT_I2);
return this->iVal;
}
else if constexpr (std::is_same_v<T, int32_t>) {
assert(this->vt == VT_I4 || vt == VT_INT);
return this->intVal;
}
else if constexpr (std::is_same_v<T, int64_t>) {
assert(this->vt == VT_I8);
return this->llVal;
}
// unsigned
else if constexpr (std::is_same_v<T, uint8_t>) {
assert(this->vt == VT_UI1);
return this->bVal;
}
else if constexpr (std::is_same_v<T, uint16_t>) {
assert(this->vt == VT_UI2);
return this->uiVal;
}
else if constexpr (std::is_same_v<T, uint32_t>) {
assert(this->vt == VT_UI4 || vt == VT_UINT);
return this->uintVal;
}
else if constexpr (std::is_same_v<T, uint64_t>) {
assert(this->vt == VT_UI8);
return this->ullVal;
}
// decimal
else if constexpr (std::is_same_v<T, float>) {
assert(this->vt == VT_R4);
return this->fltVal;
}
else if constexpr (std::is_same_v<T, double>) {
assert(this->vt == VT_R8);
return this->dblVal;
}
// string
else if constexpr (std::is_same_v<T, std::string_view>) {
assert(this->vt == VT_LPSTR);
return this->pcVal;
}
else if constexpr (std::is_same_v<T, std::wstring_view>) {
assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR);
if (this->vt == VT_LPWSTR)
return this->bstrVal;
else
return { this->bstrVal, SysStringLen(this->bstrVal) };
}
// array signed
else if constexpr (std::is_same_v<T, std::pair<const int8_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_I1);
return std::make_pair((int8_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const int16_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_I2);
return std::make_pair((int16_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const int32_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_I4);
return std::make_pair((int32_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const int64_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_I8);
return std::make_pair((int64_t*)this->parray->pvData, this->parray->cDims);
}
// array unsigned
else if constexpr (std::is_same_v<T, std::pair<const uint8_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_UI1);
return std::make_pair((uint8_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const uint16_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_UI2);
return std::make_pair((uint16_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const uint32_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_UI4);
return std::make_pair((uint32_t*)this->parray->pvData, this->parray->cDims);
}
else if constexpr (std::is_same_v<T, std::pair<const uint64_t*, uint32_t>>) {
assert(this->vt & VT_ARRAY);
assert((this->vt & ~VT_ARRAY) == VT_UI8);
return std::make_pair((uint64_t*)this->parray->pvData, this->parray->cDims);
}
else {
assert(false && "unsupported type");
__builtin_unreachable();
}
}
};
struct FFWmiRecord
{
IWbemClassObject* obj;