Compare commits

..

215 Commits

Author SHA1 Message Date
Carter Li 469e21cce9 Merge pull request #1813 from fastfetch-cli/dev
Release: v2.46.0
2025-06-20 14:30:06 +08:00
李通洲 925e09c88a Doc: update changelog [ci skip] 2025-06-20 14:28:33 +08:00
李通洲 488454c1aa Logo (Builtin): simplify kali linux 2025-06-20 14:19:05 +08:00
李通洲 c67c52d606 Logo (Builtin): add Kalpa Desktop
Fix #1807
2025-06-20 14:18:21 +08:00
李通洲 e4e11ee509 Release: v2.46.0 2025-06-20 09:51:54 +08:00
李通洲 a3e2592555 Doc: update help.json 2025-06-20 09:51:40 +08:00
Carter Li e0e966dadf Logo (Builtin): rename hydra framework to hydrapwk
Fix #1812
2025-06-20 08:59:53 +08:00
李通洲 b079a8643b Chore: code cleanups 2025-06-19 22:41:30 +08:00
apocelipes 3291a9945f Global: add missing O_CLOEXEC to open() 2025-06-19 22:40:06 +08:00
李通洲 68fd21d0e4 GPU (Linux): fix an issue which vram_usage is bigger t han vram_visible 2025-06-19 22:00:48 +08:00
李通洲 0e1ef96992 GPU (Linux): detect shared vram usage of AMD GPU 2025-06-19 15:54:26 +08:00
李通洲 c377872438 GPU (Linux): correctly call radeon driver 2025-06-19 15:43:37 +08:00
李通洲 4f42d38e4d GPU (FreeBSD): fix mem leaks 2025-06-18 20:20:49 +08:00
李通洲 7b2243496b GPU (Windows): fix build 2025-06-18 18:53:29 +08:00
Carter Li 960a817d03 GPU (Linux): fix building without features 2025-06-18 18:37:30 +08:00
Carter Li 6917f9479e GPU (Linux / FreeBSD): add DRM detection support for old radeon driver
Ref: #1810
2025-06-18 16:41:02 +08:00
Carter Li 8559cc45eb GPU (Linux / FreeBSD): unifies DRM related code and code clean up 2025-06-18 10:01:32 +08:00
李通洲 40e33c676d GPU (FreeBSD): support detection by DRM [wip] 2025-06-17 20:58:09 +08:00
李通洲 d20371040e WM (FreeBSD): fix Hyprland version detection 2025-06-17 20:38:10 +08:00
李通洲 71faf1c7e3 GPU (macOS): detect Metal 4 support 2025-06-17 14:07:18 +08:00
李通洲 d182f3f743 OS (macOS): seems macOS 26 Beta 1 still reports itself as macOS 16. Honor it. 2025-06-17 14:01:22 +08:00
李通洲 39e009b945 CI: upgrade OpenBSD version 2025-06-17 09:30:14 +08:00
李通洲 a1873f3e9e CI: split amd64 and arm64 builds
So we can test both platforms in CI
2025-06-17 09:01:38 +08:00
李通洲 636bcaaaf9 Kmod: remove Chinese comments [ci skip] 2025-06-17 08:43:09 +08:00
李通洲 3fcbd80ef0 Board (macOS): detect board-id if available
Ref: https://github.com/GuillaumeGomez/sysinfo/pull/1545
2025-06-17 00:06:31 +08:00
李通洲 38887e7fbd Logo (Builtin): add GhostFreak
Fix #1801
2025-06-15 12:28:45 +08:00
AVSISP da958e11f9 Logo (Builtin): added AnushOS (#1806)
* Added AnushOS to builtin.c

Added AnushOS config to builtin.c

* Create anushos.txt

Added anushos.txt to ASCII logos

* Update builtin.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-15 12:23:27 +08:00
李通洲 c2ed71c4eb Global: set SetErrorMode(SEM_FAILCRITICALERRORS) globally
Fix #1805
2025-06-15 00:00:22 +08:00
ᡥᠠᡳᡤᡳᠶᠠ ᡥᠠᠯᠠ·ᠨᡝᡴᠣ 猫 2e1ddcf9f8 Logo (Builtin): Add HarmonyOS support (#1804)
* Logo (Builtin): add HarmonyOS

* OS (HarmonyOS): detect HarmonyOS

* Update src/detection/os/os_linux.c

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update os_linux.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-14 09:03:57 +08:00
Carter Li f1cc2d124c Packages (OpenBSD): fix counting by ignoring hidden folders 2025-06-13 20:38:51 +08:00
Techflash 1e32a95f83 CPU (NetBSD): properly support PowerPC (#1802)
Some devices store their CPU name in hw.model, so check that as well
before giving up.  Tested on NetBSD 10.1 evbppc/wii, and allows it to
detect the CPU as "750 (Revision 2.0)".

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-11 00:15:40 -05:00
CopticFelo 9e959bc57f WM (MacOS): Added Aerospace WM detection 2025-06-10 11:22:31 +08:00
李通洲 e68406ee22 DE (macOS): report Liquid Glass on macOS 26+ 2025-06-10 10:56:13 +08:00
李通洲 ba69e316b2 OS (MacOS): add macOS 26 Tahoe 2025-06-10 10:48:35 +08:00
李通洲 f3e8e8af52 Logo (Builtin): detect and add TrueNAS Scale 2025-06-10 10:22:13 +08:00
李通洲 c9adab3892 OS (Linux): detect Raspberry Pi OS
Fix #1773
2025-06-10 09:55:13 +08:00
李通洲 c8d1d29017 Disk (Linux): hide /boot/firmware by default 2025-06-10 09:54:11 +08:00
Carter Li 541acca7c0 Logo (Builtin): add xenia_old; update colors of xenia
#1797
2025-06-10 09:13:21 +08:00
Derek Passen ddf5099461 TerminalFont: support rio terminal emulator (#1789)
* Enable terminal font detection for rio terminal emulator

https://rioterm.com
https://rioterm.com/docs/config
https://rioterm.com/docs/config#fonts

* Update src/detection/terminalfont/terminalfont.c

Fix default rio font name

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-08 00:00:03 +08:00
李通洲 781a692b06 JsonSchema: document swap.separate 2025-06-07 19:23:25 +08:00
李通洲 9c37f1b370 CPU (Windows): use perflib.h instead of pdh.h for querying CPU temp
Fix #1787
2025-06-07 19:17:46 +08:00
Carter Li a66c26f4df Logo (Builtin): improve colors of bedrock_small
Fix #1790
2025-06-07 17:39:45 +08:00
Carter Li 3bd750bedf Host (Linux): detect Linux Binary Compatibility on FreeBSD
Fix #1786
2025-06-06 15:38:46 +08:00
Carter Li 4a1ada604c Host (Linux): more detailed info of WSL 2025-06-06 14:49:32 +08:00
Noah Michaels e5f57a34a2 Logo (Builtin): Add Fedora2_small (#1785)
* Add 1 more small Fedora logo

* Update builtin.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-05 20:12:44 -05:00
Carter Li 20a3737dce Packaging: update debian stuff [ci skip] 2025-06-05 10:59:16 +08:00
Carter Li e0452d9db5 Merge pull request #1784 from fastfetch-cli/dev
Release: v2.45.0
2025-06-05 10:47:05 +08:00
李通洲 d8e74ba84c Release: v2.45.0 2025-06-05 10:13:56 +08:00
Carter Li 04b13096ac Swap (Haiku): detect detailed info 2025-06-04 22:01:16 +08:00
李通洲 64d4035cae Chore (Haiku): don't use hard-coded page size 2025-06-04 21:26:37 +08:00
Carter Li 5e0ba57f53 Disk (BSD): silence compiler warnings 2025-06-05 04:55:12 +08:00
李通洲 d89263c218 Swap (DragonFly): add support 2025-06-04 20:51:21 +08:00
Carter Li 6a42588786 Swap (SunOS): detect detailed info 2025-06-04 19:36:22 +08:00
Carter Li 5883bf359c Swap (OpenBSD): detect detailed info 2025-06-04 19:05:02 +08:00
Carter Li 6a6b4070ca Swap (Linux): add fallback for Android 2025-06-04 18:35:53 +08:00
Carter Li 2c80cd6d29 Swap (Linux): support detailed info 2025-06-04 16:44:10 +08:00
Carter Li fa4b00b027 Swap (FreeBSD): detect detailed info 2025-06-04 15:30:03 +08:00
李通洲 5fdc924b5d Swap (macOS): detect detailed info 2025-06-04 15:07:05 +08:00
李通洲 3d4a117093 Swap: support separated output 2025-06-04 15:02:02 +08:00
李通洲 7ec0c664c5 Swap (Windows): detect detailed info 2025-06-04 15:01:37 +08:00
李通洲 9d2df589b5 Smbios (DragonFly): acquire SMBIOS info from /dev/mem 2025-06-04 14:22:33 +08:00
李通洲 7107d08e92 DE (DragonFly): fix build 2025-06-04 14:22:33 +08:00
Carter Li 4c34f99c12 Swap (Linux): use /proc/swaps
Preparing for detailed swap usage
2025-06-04 10:37:07 +08:00
Carter Li d7a8c92b46 CI (Linux): fix musl build 2025-06-04 09:05:04 +08:00
李通洲 bbb29ff766 CI (Linux): add missing deps for musl 2025-06-03 21:15:48 +08:00
amnexya 35235b9557 Logo (Builtin): Update logo for Xenia Linux (#1783)
* Update Xenia Linux logo

* Update builtin.c for xenia colours

* Update src/logo/builtin.c

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-03 21:11:50 +08:00
Carter Li 6b94605804 Disk (BSD): don't ignore sshfs 2025-06-03 18:58:38 +08:00
Carter Li 4b2fa07fdc Packages (Linux): fix dnf package count detection (v2) 2025-06-03 10:53:02 +08:00
Carter Li e203f4eeaf Packages (Linux): fix dnf package count detection
Fix #1777
2025-06-03 09:33:43 +08:00
李通洲 8db70b40e2 CI: add back disabled DFBSD 2025-06-02 22:00:32 +08:00
李通洲 1f967849e5 CMake: fix build of FreeBSD 2025-06-02 19:15:14 +08:00
李通洲 d60b2ddfd4 Disk (Linux): don't ignore sshfs
Fix #1776
2025-06-02 19:09:24 +08:00
李通洲 fb68d8a841 CI (Haiku): add build
Disabled due to https://github.com/cross-platform-actions/action/issues/104
2025-06-02 18:48:16 +08:00
李通洲 047411ba87 CMake: build FreeBSD pkg package 2025-06-02 15:56:18 +08:00
李通洲 08ed14b42a Logo: support "type": "command-raw"
Fix #1780
2025-06-02 11:46:43 +08:00
李通洲 d94a41cc1b Chore: tidy 2025-06-02 11:46:43 +08:00
Anshnk 81b7fb06c1 Fix typo, 15,2 isn't a real mac model number 2025-06-02 11:02:10 +08:00
李通洲 c8debccd16 DE (FreeBSD): support KDE version detection 2025-06-02 10:19:36 +08:00
Carter Li 2853bd15c0 Logo (Builtin): add void2
Ported from hyfetch
2025-05-31 23:28:16 +08:00
Carter Li 2f4146fde8 Logo (Builtin): update default colors of voidlinux
Fix  #1775
2025-05-31 23:18:43 +08:00
李通洲 eeceade14e Logo (Builtin): add rhel_small
Fix #1774
2025-05-31 13:39:40 +08:00
李通洲 1875c78e96 WM: support I3 version detection 2025-05-31 10:41:38 +08:00
李通洲 f389864e17 WM: support FVWM version detection 2025-05-31 10:16:26 +08:00
李通洲 b9317734b9 WM: support CTWM version detection 2025-05-31 10:02:45 +08:00
李通洲 4df4a1de78 Logo (Builtin): add Starry Linux
Fix #1771
2025-05-30 13:56:52 +08:00
李通洲 0cd8c6ead6 Chore: code cleanup 2025-05-30 10:33:37 +08:00
李通洲 f8479dae94 GPU: add more GPU vendors 2025-05-30 10:33:26 +08:00
李通洲 a7d623fa75 JsonSchema: update <module>Format [ci skip] 2025-05-29 10:13:57 +08:00
李通洲 7a8ffb27bd Packages: split code 2025-05-26 15:12:47 +08:00
Carter Li 73c0347469 Merge remote-tracking branch 'origin/dev' into dev 2025-05-26 15:00:58 +08:00
Carter Li fde5f3bd0f Packaging: update debian stuff [ci skip] 2025-05-26 15:00:06 +08:00
李通洲 9e1b1302fb Host (Android): add detection for OnePlus market name
Fix #1768
2025-05-26 14:22:47 +08:00
Carter Li 7e235b6be0 Merge pull request #1766 from fastfetch-cli/dev
Release: v2.44.0
2025-05-23 16:10:12 +08:00
李通洲 f43e1fd614 Release: v2.44.0 2025-05-23 15:41:22 +08:00
Carter Li c7b061eebd DisplayServer (Linux): fix errors on KDE beta
Fix #1765
2025-05-22 09:41:35 +08:00
Carter Li a0f579072f Disk: add --disk-hide-fs
Fix #1762
2025-05-21 16:40:42 +08:00
Carter Li d439ce8eb5 Disk: rename hiddenFolder to hideFolder; add docs 2025-05-21 15:09:19 +08:00
Carter Li e2a714732a Disk: add hiddenFolders (2) 2025-05-21 15:00:42 +08:00
asmeron a993a6f126 Logo (Builtin): Add UBLinux Logo (#1764)
* Logo (Builtin): Add UBLinux Logo

* Update builtin.c

---------

Co-authored-by: asmeron <asmeron@ublinux.com>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-05-20 21:50:34 -05:00
李通洲 8eb8f710d0 Disk: add option --disk-hidden-folders 2025-05-19 18:32:56 +08:00
李通洲 526868e355 Disk (Linux): don't hard code hidden mount points 2025-05-19 15:25:06 +08:00
李通洲 768238cb46 TerminalShell (Linux): ignore script
Fix #1761
2025-05-17 18:04:41 +08:00
Xavier Xiong 2d938042d0 Logo (Builtin): Add Kylin Logo (Remove ANSI codes) (#1760)
* Logo (Builtin): Add Kylin Logo

* Remove all ANSI escape codes from ASCII Logo

* Add color prefix to kylin logo
2025-05-16 01:05:42 -05:00
李通洲 9a54d92e9f Stat: use ESC 7/8 instead of CSI s/u
Fix Apple Terminal compatibility #1755
2025-05-16 10:33:58 +08:00
Collin 839abab744 Doc: Add information of where to find example config files (#1759) [ci skip] 2025-05-15 19:58:36 -05:00
Md. Iftakhar Awal Chowdhury c054570308 fish complete: add --logo-color-[1-9] completion (#1754)
* fish complete: add `--logo-color-[1-9]` completion

* reverted unnecessary changes
2025-05-15 03:18:19 -05:00
Carter Li ed69a7059b Packaging: update debian stuff [ci skip] 2025-05-14 09:51:44 +08:00
Carter Li 6b92659512 Merge pull request #1752 from fastfetch-cli/dev
Release: v2.43.0
2025-05-14 09:41:33 +08:00
Carter Li 7e04305d1c CI: silence spell check errors 2025-05-14 09:25:15 +08:00
Carter Li 87e13543da GPU (Linux): embed asahi_drm.h 2025-05-14 08:59:53 +08:00
Carter Li 7a2cbc060f 3rdparty (yyjson): upgrade to 0.11.1 2025-05-14 08:52:06 +08:00
Carter Li f22d73d473 PhysicalDisk: trim white spaces of serial 2025-05-13 18:29:46 +08:00
李通洲 e629126d73 Doc: update changelog 2025-05-13 15:52:30 +08:00
李通洲 9ac635e2e6 Media (Windows): detect player name (UMP apps only) 2025-05-13 15:46:33 +08:00
李通洲 1b1b0521f4 Doc: update changelog 2025-05-13 13:49:54 +08:00
李通洲 41d0f61ee0 GPU (AMD): remove usage of ADL2_Adapter_VRAMUsage_Get
It reports dedicated GPU memory usage too.

Ref: https://github.com/GPUOpen-LibrariesAndSDKs/display-library/issues/48
2025-05-13 13:39:42 +08:00
李通洲 9de5d9008b Release: v2.43.0 2025-05-13 10:37:52 +08:00
李通洲 576a9cc6fe Revert "Vulkan: use VK_API_VERSION_* instead of deprecated VK_VERSION_*"
Breaks building with old vulkan-headers

This reverts commit 36b0fdbcda.
2025-05-13 10:02:38 +08:00
李通洲 bd61d08afe Sound (macOS): report the volume of muted device as 0% 2025-05-13 09:35:13 +08:00
李通洲 4672b78481 Sound: don't show 255 in custom format
Fix #1750
2025-05-13 09:30:30 +08:00
李通洲 36b0fdbcda Vulkan: use VK_API_VERSION_* instead of deprecated VK_VERSION_* 2025-05-13 09:29:21 +08:00
Carter Li 7626ef6eaa GPU (Linux): fix CI errors
F**k Ubuntu
2025-05-10 21:40:33 +08:00
Carter Li 115108b3f1 GPU (Linux): detect core usage when libamdgpu is not available 2025-05-10 20:57:51 +08:00
Carter Li 154f9f462b GPU (Linux): detect VRAM type of AMD GPUs 2025-05-10 20:57:51 +08:00
Marvin Friedrich a96a9fc31d Smbios: fix transitive include for loff_t (#1746) 2025-05-10 10:49:22 +08:00
李通洲 23b43244c5 GPU (AMD): seems ADL2_Adapter_VRAMUsage_Get reports system mem usage only, not full memory usage
Because VRAMUsage reports a value which is smaller than DedicatedVRAMUsage
2025-05-09 22:46:31 +08:00
Carter Li 9dfb404a0d GPU (AMD): more verbose logs 2025-05-09 22:01:29 +08:00
Carter Li ff3028c656 GPU: don't hide unknown type of GPUs by default
Fix #1742
2025-05-09 21:58:41 +08:00
Carter Li 2f706ed494 Smbios: discard usless values 2025-05-09 21:55:31 +08:00
Carter Li 06427ee62b Media (Linux): fix duplicated playback status 2025-05-09 19:23:28 +08:00
李通洲 fe66eb3df0 GPU (Windows): fix incorrect used shared memory size 2025-05-08 23:20:53 +08:00
李通洲 6e1ab12399 Memory / Swap: always initialize local variables 2025-05-08 23:17:22 +08:00
Samuli Thomasson 484e05eae3 GPU: optionally hide unknown GPUs (#1742)
The current default behavior of not hiding any GPUs is retained. The new
feature of hiding unknown or unrecognized GPUs can be enabled with
hide-type = "unknown".
2025-05-07 22:06:47 +08:00
Joe_ 5d3fb98072 Logo (Builtin): add Hydra Framework logo (#1740)
* Added: Hydra Framework logo

* Remove extra line: hydra.txt
2025-05-07 03:02:36 -05:00
李通洲 0c30590088 Builtin (Logo): new AthenaOS logo
Fix #1741
2025-05-07 10:45:21 +08:00
李通洲 20cd4ce125 Logo (Builtin): sd '\$\{c(\d)\}' '$$$1' * 2025-05-07 10:44:05 +08:00
apocelipes 1c7aa89228 TerminalShell: use ffBinaryExtractStrings result as possible (#1739) 2025-05-06 18:49:29 +08:00
apocelipes f270255770 DisplayServer (Linux): fix xcb_connect error handling (#1735) 2025-05-06 03:18:53 -05:00
李通洲 4b62a3c75b 3rdparty: upgrade yyjson to 0.11.0 2025-05-06 16:12:58 +08:00
李通洲 1557f0c556 Media (macOS): support macOS 15.4
Fix #1737
2025-05-06 16:12:58 +08:00
Carter Li ef7f61309f GPU (Linux): fix asahi linux support again
Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
2025-05-06 09:27:54 +08:00
李通洲 f59491b25d Disk (Linux): fix possible bug on 32-bit platforms
Fix #1734
2025-05-05 22:05:22 +08:00
李通洲 e3592eb2c3 CPU (FreeBSD): simplify physical core count detection 2025-05-05 13:41:12 +08:00
Carter Li 305776eb94 CPU (SunOS): support physical core count and package count detection 2025-05-02 14:24:30 +08:00
Carter Li 599e0d393d Display: use height to calculate scale factor
Seems more accurate
2025-05-01 21:28:04 +08:00
李通洲 561574ae94 CPU (Windows): always use XxxW 2025-04-30 16:10:53 +08:00
李通洲 3dd78422eb Global: Improve ARRAY_SIZE macro using __is_array 2025-04-30 14:47:37 +08:00
李通洲 5c546ab8e7 Parsing: silence compiler warnings 2025-04-30 14:14:28 +08:00
Carter Li 3e9274040d Packaging: update debian stuff [ci skip] 2025-04-30 14:12:26 +08:00
Carter Li 630d876e2d Merge pull request #1722 from fastfetch-cli/dev
Release: v2.42.0
2025-04-29 14:05:36 +08:00
李通洲 1938be86ff Wifi (NetBSD): fix the ambiguous comment 2025-04-29 13:53:45 +08:00
李通洲 0980d5f0ad Wifi (BSD): correctly prioritize Wi-Fi protocol detection
by using an `if-else if` chain
2025-04-29 13:50:53 +08:00
李通洲 d8c1b3b61b Release: v2.42.0 2025-04-29 10:38:07 +08:00
李通洲 969523ae8a BIOS: normalize the module name
Fix #1721
2025-04-29 10:26:19 +08:00
李通洲 5d960ec744 Uptime: fix non-normalized time being shown
Fix #1720
2025-04-29 10:22:19 +08:00
apocelipes 3b36b8ca57 Global: use ARRAY_SIZE (#1718) 2025-04-28 21:22:04 -05:00
apocelipes 05f14764e6 Bluetooth (Linux): silence an unused variable warning (#1717) 2025-04-28 22:50:46 +08:00
apocelipes 3a180b24e3 Platform: fix a memory leak (#1716) 2025-04-28 22:49:31 +08:00
李通洲 02ab58e001 Doc: update changelog [ci skip] 2025-04-24 09:31:05 +08:00
Carter Li fd158b41e1 Logo (Chafa): fix setting chafa.symbols
Fix #1709
2025-04-24 09:02:45 +08:00
李通洲 89e0ede12f Camera (OpenBSD): add support 2025-04-23 20:09:08 +08:00
李通洲 4d7b2410ef CPU (OpenBSD): fix CPU temperature detection 2025-04-22 21:19:22 +08:00
李通洲 c1f6a2f755 Refactor: inline printError into ffPrintError and remove unused static helper 2025-04-22 14:30:39 +08:00
李通洲 9c455c3b0f Wifi (FreeBSD): fix possible mem leaks 2025-04-20 12:41:06 +08:00
Carter Li d4ea9dfd21 Wifi (NetBSD): add support
Untested
2025-04-20 12:40:47 +08:00
李通洲 08071e6e7e Wifi (OpenBSD): fix file name 2025-04-20 11:49:40 +08:00
李通洲 ec87174f30 CPU (NetBSD): add one more method to detect CPU frequency 2025-04-20 11:43:39 +08:00
李通洲 835e5b51c9 CPU (SunOS): detect CPU temp
Untested
2025-04-20 11:12:08 +08:00
Noa Himesaka 07c5ef255e Logo (Builtin): Add Codex Linux support (#1701)
* feat: add Codex Linux

* Codex.txt: remove empty lines

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-04-19 21:22:28 +08:00
李通洲 476b55c17d Logo (Builtin): remove GoralixOS
Ref: #1699
2025-04-19 21:18:13 +08:00
李通洲 4a53cfa312 Logo (Builtin): add Aurora
Fix #1700
2025-04-19 21:11:54 +08:00
李通洲 50ea515476 PhysicalDisk (Linux): don't detect disk type of virtual disks
Fix #1697
2025-04-18 16:10:01 +08:00
xzvf cbd9f72bc8 T2/SDE: upstreaming downstream's logo change (#1695)
* T2/SDE: upstreaming downstream's logo change

T2/SDE port of fastfetch applies two patches, improving the
distribution's logo and adding alternative names. I see no point not
having these upstream.

Downstream's patches are found here:
https://github.com/rxrbln/t2sde/tree/main/package/contrib/fastfetch

The old logo has been renamed to "T2_small".

* Fix ASCII art alignment in t2.txt

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-04-17 22:52:45 +08:00
李通洲 29eaa35f4c Color: support #RGB and #RRGGBB
Fix #1694
2025-04-17 10:48:18 +08:00
Carter Li 97c89c39d3 Packaging: update debian stuff [ci skip] 2025-04-16 13:51:09 +08:00
Carter Li 5769791185 Merge pull request #1691 from fastfetch-cli/dev
Release: v2.41.0
2025-04-16 13:29:07 +08:00
李通洲 894c66d793 Processing (Windows): fix macro name __aarch64__
Found by AI
2025-04-16 11:12:36 +08:00
李通洲 75290154b0 Chore: remove Chinese comments [ci skip] 2025-04-16 11:09:03 +08:00
李通洲 b08eea76b1 CI (Linux): enable chafa on Linux aarch64 2025-04-16 10:45:25 +08:00
李通洲 61d83af9ea CI (Linux): bump GH runner for linux-amd64
Ref: https://github.com/actions/runner-images/issues/11101
2025-04-16 10:45:02 +08:00
李通洲 2d497038eb Release: v2.41.0 2025-04-16 09:24:20 +08:00
李通洲 f8a5d5561a Bluetooth (NetBSD): add base implementation
Ref: #1690
2025-04-15 19:06:39 +08:00
李通洲 2e7e68ef23 Doc: add installation instructions for pkgsrc [ci skip]
Fix #1689
2025-04-15 19:04:19 +08:00
李通洲 b812f3ccde Uptime (Windows): use QueryUnbiasedInterruptTime
As suggested by MSDN
2025-04-15 16:41:38 +08:00
李通洲 6da8181bbe CMake: use mincore on WoA 2025-04-15 16:41:38 +08:00
李通洲 a51dd641c1 Processing (Windows): use GetOverlappedResultEx on WoA 2025-04-15 16:41:38 +08:00
李通洲 0d20164d40 CI (Windows): add WoA 2025-04-15 10:59:10 +08:00
李通洲 3320532668 GPU (Linux): add temp detection for Intel GPU
Untested
2025-04-14 18:57:15 +08:00
Carter Li bcc6492115 NetIO (Linux): use openat 2025-04-14 18:48:04 +08:00
naix c60bc8ee5b Logo (Builtin): Add 2 more Alpine logos (#1687)
* Logo (Builtin): Add 2 more Alpine logos

* Remove unnecessary $1 in ASCII logo file

* Add type field to Alpine2 logo configuration

---------

Co-authored-by: naix <naix@noreply.codeberg.org>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-04-14 00:50:45 -05:00
李通洲 4eefab8ccf CPU (Linux): fix build 2025-04-14 10:54:35 +08:00
李通洲 9cda7e20fb Chore: simplify fastfetch.h 2025-04-14 10:28:01 +08:00
李通洲 79d0197dcf Wifi (FreeBSD): remove unused sys headers 2025-04-14 10:04:11 +08:00
李通洲 ba01b1e4ce CPU (Linux): add new ARM part numbers 2025-04-14 09:27:01 +08:00
李通洲 58908f69ba Wifi (OpenBSD): add support
Completely untested.
2025-04-13 00:37:40 +08:00
李通洲 114088b845 Doc: add comments about displaying image logo on Windows [ci skip]
Fix  #1686
2025-04-12 20:38:42 +08:00
李通洲 6e77b592cb WM (FreeBSD): enable Hyprland version detection 2025-04-12 10:48:26 +08:00
李通洲 73bc71e922 CPU (Windows): use PDH to detect thermal temp
No Administrator privileges needed
2025-04-12 10:47:57 +08:00
Anduin Xue 090529ffef Logo (Builtin): Add support for anduinos (#1684)
* Add anduinos

* fix logo.

* Update anduinos.txt
2025-04-10 23:13:26 +08:00
李通洲 3c291f1af9 Platform: retrieve full user name 2025-04-09 16:15:23 +08:00
李通洲 fc31fe4aa4 Merge branch 'master' into dev 2025-04-09 14:39:51 +08:00
李通洲 563f9598be Release: v2.40.4 2025-04-09 14:24:27 +08:00
Carter Li 03bc2dade9 Fastfetch: fix loading presets in {exePath}/presets
Regression of v2.40.0
2025-04-09 14:15:06 +08:00
Carter Li 09d683b706 WM (Linux): remove v from Hyprland version 2025-04-09 14:14:56 +08:00
Carter Li 523a9590b8 Fastfetch: fix loading presets in {exePath}/presets
Regression of v2.40.0
2025-04-08 15:42:58 +08:00
李通洲 3c3188eb05 IO (Windows): support ~ expanding 2025-04-07 16:43:48 +08:00
李通洲 354062118f Chore: update comment 2025-04-07 16:43:48 +08:00
李通洲 85d7390fa8 Util (Windows): use native win32 functions 2025-04-07 16:38:54 +08:00
Carter Li 8509f97054 WM (Linux): remove v from Hyprland version 2025-04-06 17:21:32 +08:00
Rabindra Dhakal 8d5d8b4c90 Packages (Linux): add soar packages count (#1531)
* add soar packages count

* use || instead of concat for better compatibility with older SQLite versions

* convert package flags to 64-bit
2025-04-05 23:54:27 +08:00
李通洲 536ad9594e PhysicalDisk (Linux): add more disk types 2025-04-05 22:35:42 +08:00
李通洲 a57bbbadf4 PhysicalDisk (Linux): don't detect disk type for virtual disks
Fix #1669
2025-04-05 22:35:42 +08:00
李通洲 3def466ee0 Revert "CPU (FreeBSD): remove using of freq_levels"
This reverts commit ed2dd8f2ec.
2025-04-05 13:54:20 +08:00
李通洲 59868c66a0 CPU (FreeBSD): don't assume one SMT group has only two threads
Fix #1670
2025-04-05 13:48:18 +08:00
Carter Li e13eb05073 CPU (Linux): detect physical core count on non-x86 platforms 2025-04-05 12:08:35 +08:00
312 changed files with 10126 additions and 4407 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
[codespell]
check-filenames =
builtin = clear,rare,usage,informal
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu
+202 -12
View File
@@ -60,7 +60,7 @@ jobs:
linux-amd64:
name: Linux-amd64
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
permissions:
security-events: write
contents: read
@@ -80,12 +80,12 @@ jobs:
run: cat /proc/cpuinfo
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa ddcutil --ignore-dependencies
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
@@ -151,8 +151,13 @@ jobs:
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -378,7 +383,7 @@ jobs:
run: |
cat /etc/alpine-release
uname -a
apk add cmake samurai vulkan-loader-dev libxcb-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
shell: alpine.sh --root {0}
- name: build
@@ -403,9 +408,9 @@ jobs:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
macos-universal:
name: macOS-universal
runs-on: macos-latest
macos-amd64:
name: macOS-amd64
runs-on: macos-13
permissions:
security-events: write
contents: read
@@ -421,7 +426,7 @@ jobs:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' .
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -447,7 +452,54 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos-universal
name: fastfetch-macos-amd64
path: ./fastfetch-*.*
macos-aarch64:
name: macOS-aarch64
runs-on: macos-latest
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: uname -a
run: uname -a
- name: install required packages
run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: otool -L fastfetch
- name: run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos-aarch64
path: ./fastfetch-*.*
sunos-amd64:
@@ -537,7 +589,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '7.6'
version: '7.7'
run: |
uname -a
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa
@@ -592,6 +644,80 @@ jobs:
name: fastfetch-netbsd-amd64
path: ./fastfetch-*.*
dragonfly-amd64:
name: DragonFly-amd64
runs-on: ubuntu-latest
if: false
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: vmactions/dragonflybsd-vm@v1
with:
usesh: yes
prepare: |
uname -a
pkg update
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-dragonfly-amd64
path: ./fastfetch-*.*
haiku-amd64:
name: Haiku-amd64
runs-on: ubuntu-latest
if: false
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
architecture: x86-64
cpu_count: 4
shell: bash
version: 'r1beta5'
run: |
uname -a
ls -l
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-haiku-amd64
path: ./fastfetch-*.*
windows-amd64:
name: Windows-amd64
runs-on: windows-latest
@@ -654,6 +780,68 @@ jobs:
name: fastfetch-windows-amd64
path: ./fastfetch-windows-amd64.*
windows-aarch64:
name: Windows-aarch64
runs-on: windows-11-arm
permissions:
security-events: write
contents: read
defaults:
run:
shell: msys2 {0}
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: setup-msys2
uses: msys2/setup-msys2@v2
with:
msystem: CLANGARM64
update: true
install: git mingw-w64-clang-aarch64-7zip mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-vulkan-loader mingw-w64-clang-aarch64-vulkan-headers mingw-w64-clang-aarch64-opencl-icd mingw-w64-clang-aarch64-opencl-headers mingw-w64-clang-aarch64-cppwinrt mingw-w64-clang-aarch64-imagemagick
- name: print msys version
run: uname -a
- name: configure project
run: env PKG_CONFIG_PATH=/clangarm64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --verbose -j4
- name: copy necessary dlls
run: cp /clangarm64/bin/{OpenCL,vulkan-1}.dll .
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: ldd fastfetch
- name: run tests
run: ctest --output-on-failure
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-aarch64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-aarch64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-windows-aarch64
path: ./fastfetch-windows-aarch64.*
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
name: Release
@@ -667,12 +855,14 @@ jobs:
- linux-ppc64le
- linux-s390x
- musl-amd64
- macos-universal
- macos-amd64
- macos-aarch64
- freebsd-amd64
- openbsd-amd64
- netbsd-amd64
- sunos-amd64
- windows-amd64
- windows-aarch64
permissions:
contents: write
steps:
+161 -1
View File
@@ -1,3 +1,163 @@
# 2.46.0
Features:
* Support Rio terminal font detection (#1789, TerminalFont, Linux)
* Support GPU detection by DRM on FreeBSD (GPU, FreeBSD)
* Enable by `--gpu-detection-method auto`
* Require proper DRM drivers installed and loaded
* Support PowerPC CPU detection on NetBSD (#1802, CPU, NetBSD)
* Support Aerospace WM detection (#1796, WM, macOS)
* Improve Raspberry Pi OS for RPI5 detection (#1773, OS, Linux)
* Support Linux Binary Compatibility detection on FreeBSD (#1786, Host, Linux)
* Use `board-id` as board name if available (Board, macOS)
* Intel only
* Support shared VRAM usage detection for AMD GPUs (GPU, Linux)
* Use `perflib.h` instead of `pdh.h` for CPU temperature querying to get rid of pdh.dll (#1787, CPU, Windows)
* Support GPU info detection for old ATI radeon driver (#1810, GPU, Linux)
* Add macOS 26 Tahoe support (macOS)
* Report macOS 26 code name (OS)
* Report Liquid Glass DE on macOS 26+ (DE)
* Detect Metal 4 support (GPU)
Bugfixes:
* Fix packages counting by ignoring hidden folders (Packages, OpenBSD)
* Fix Hyprland version detection (WM, FreeBSD)
* Don't show `Please insert a disk into drive D:` error dialogs (#1805, Disk, Windows)
* Hide `/boot/firmware` by default (Disk, Linux)
Logos:
* Rename Hydra Framework to HydraPwk (#1812)
* Add AnushOS (#1806)
* Add HarmonyOS (#1804)
* Add GhostFreak (#1801)
* Add TrueNAS Scale (#1795)
* Add Fedora2_small (#1785)
* Add xenia_old; update colors of xenia (#1797)
* Improve colors of bedrock_small (#1790)
* Add Kalpa Desktop (#1807)
# 2.45.0
Features:
* Support OnePlus marketing name detection (#1768, Host, Android)
* Recognize additional GPU vendors (GPU, Linux)
* Support CTWM, FVWM and I3 window manager version detection (WM)
* Support KDE version detection on *BSD (DE, FreeBSD)
* Support `"logo": { "type": "command-raw" }` to run a command and display its output as logo (#1780, Logo)
* Useful for displaying custom logos generated by other programs such as `pokeget`: `{ "type": "command-raw", "source": "pokeget random --hide-name" }`
* Supported in JSONC config file only. `pokeget random --hide-name | fastfetch --file-raw -` should be used in shell.
* Acquire SMBIOS information on DragonFly BSD from `/dev/mem`; legacy BIOS only (PhysicalMemory, DragonFly)
* Support swap usage detection on DragonFly BSD (Swap, DragonFly)
* Support `--swap-separate` to display detailed swap devices on separate lines (Swap)
Bugfixes
* Fix MacBook Air model name (#1779, Host, macOS)
* Don't ignore sshfs mountpoints (#1776, Disk, Linux / FreeBSD)
* Fix dnf package count detection (#1777, Packages, Linux)
Logos:
* Add Starry Linux (#1771)
* Add rhel_small (#1774)
* Update color palette of voidlinux (#1775)
* Add void2
* Update Xenia Linux (#1783)
# 2.44.0
Features:
* Add option `--disk-hide-folders` and `--disk-hide-fs` to hide specific mountpoints and filesystems in Disk module (Disk)
* `--disk-hide-folders` defaults to `/efi:/boot:/boot/efi` on Linux and *BSD. Previously these EFI-related folders were hardcoded to be hidden on Linux.
Bugfixes:
* Fix Apple Terminal compatibility with `--stat` (macOS, #1755)
* Ignore `/usr/bin/script` when detecting shell and terminal (Terminal / Shell, #1761)
* Fix compatibility with KDE Plasma 6.4 which is in beta currently (Display, Linux, #1765)
Logos:
* Add Kylin (#1760)
* Add UBLinux (#1764)
# 2.43.0
Features:
* Support physical core count and package count detection on Solaris (CPU, SunOS)
* Improve physical core count detection on FreeBSD (CPU, FreeBSD)
* Add option to hide unknown GPUs (GPU)
* Detect VRAM type of AMD GPUs on Linux (GPU, Linux)
* Support playing media detection on macOS 15.4 (#1737, Media, macOS)
* Whether it works on newer versions is unknown
* Detect player name for Windows UMP apps (Media, Windows)
Bugfixes:
* Fix disk usage detection on 32-bit Linux (#1734, Disk, Linux)
* Fix compiling on Asahi Linux (GPU, Linux)
* Fix duplicated playback status (Media, Linux)
* Don't show 255 in custom format when muted on macOS (#1750, Sound, macOS)
* Remove shared memory detection for AMD GPUs, which doesn't work as expected (GPU, Windows)
Logos:
* new AthenaOS
* add Hydra Framework
# 2.42.0
Changes:
* Normalize the module name `Bios` to `BIOS` (#1721)
* No configuration file changes are required because fastfetch parses module names case-insensitively.
Bugfixes:
* Disable disk type detection for virtual disks (PhysicalDisk, Linux, #1669)
* Fix incorrect CPU temperature reporting (CPU, OpenBSD)
* Fix setting `logo.chafa.symbols` in JSON configuration (Logo, #1709)
* Fix non-normalized time display (Uptime, #1720)
* Miscellaneous minor fixes
Features:
* Add CPU temperature detection support (CPU, SunOS)
* Improve CPU frequency detection (CPU, NetBSD)
* Add Wi-Fi detection support (Wifi, NetBSD)
* Add Webcam detection support (Camera, OpenBSD)
* Requires root privileges
Logos:
* Remove GoralixOS logo (#1699)
* Add Aurora logo (#1700)
* Add Codex Linux logo (#1701)
# 2.41.0
Changes:
* Due to [the deprecation](https://github.com/actions/runner-images/issues/11101), Linux x86_64 binaries are now built with Ubuntu 22.04 (Glibc 2.35, Debian 12)
* You can always build fastfetch yourself on your own. Please don't report bugs related to this change.
Features:
* Support physical core count detection on non-x86 platforms (CPU, Linux / FreeBSD)
* Support CPU frequency detection on PPC64 (CPU, FreeBSD)
* Support soar packages count detection (Packages, Linux)
* Support `~` path expanding on Windows (Logo, Windows)
* Support retrieving full user name (Title)
* Exposed with `--title-format '{full-user-name}'`
* Improve CPU (thermal zone) temperature detection on Windows (CPU, Windows)
* Administrator privileges are no longer needed
* Support base Wifi info detection on OpenBSD (Wifi, OpenBSD)
* To be tested
* Support GPU temperature detection for Intel dGPU on Linux (GPU, Linux)
* To be tested
* Add new ARM CPU part numbers (CPU, Linux)
* Add base implementation of Bluetooth device detection (Bluetooth, NetBSD, #1690)
* Some small improvements
Logo:
* Add anduinos
* Add 2 more Alpine logos
# 2.40.4
Bugfixes:
* Fix loading presets config on Windows (Windows, #1682)
* Regression of v2.40.0
* Remove the prefix `v` of Hyprland version on Arch Linux (WM, Linux)
# 2.40.3
Bugfixes:
@@ -844,7 +1004,7 @@ Bugfixes:
* Fix some presets
* Better detection for XTerm terminal fonts (#1095, TerminalFont, Linux)
* Remove debug output (#1097, Windows)
* Fix command line option `--gpu-hide-type` doesn't work (#1098, GPU)
* Fix flag `--gpu-hide-type` doesn't work (#1098, GPU)
* Fix wrong date on Raspbian 10 (#1108, DateTime, Linux)
* Use `brightness` instead of `actuall_brightness` when detecting current brightness level (Brightness, Linux)
* Ref: https://bugzilla.kernel.org/show_bug.cgi?id=203905
+60 -26
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.40.3
VERSION 2.46.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -61,7 +61,7 @@ cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeB
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD" OFF)
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" OFF)
@@ -102,7 +102,7 @@ if(NOT BINARY_LINK_TYPE IN_LIST BINARY_LINK_TYPE_OPTIONS)
message(FATAL_ERROR "BINARY_LINK_TYPE must be one of ${BINARY_LINK_TYPE_OPTIONS}")
endif()
set(PACKAGE_MANAGERS AM APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SORCERY WINGET XBPS)
set(PACKAGE_MANAGERS AM APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SOAR SORCERY WINGET XBPS)
foreach(package_manager ${PACKAGE_MANAGERS})
if(package_manager STREQUAL "WINGET")
option(PACKAGES_DISABLE_${package_manager} "Disable ${package_manager} package manager detection by default" ON)
@@ -326,6 +326,11 @@ endif()
fastfetch_encode_c_string("${DATATEXT_JSON_HELP}" DATATEXT_JSON_HELP)
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
if(APPLE)
# See src/detection/media/media_apple.m
fastfetch_load_text(src/data/nowPlaying.scptd DATATEXT_NOWPLAYING)
endif()
configure_file(src/fastfetch_config.h.in fastfetch_config.h @ONLY)
configure_file(src/fastfetch_datatext.h.in fastfetch_datatext.h @ONLY)
if(APPLE)
@@ -342,7 +347,6 @@ foreach(file ${LOGO_FILES})
fastfetch_load_text("${file}" content)
get_filename_component(file "${file}" NAME_WE)
string(TOUPPER "${file}" file)
string(REGEX REPLACE "\\$\\{c([0-9]+)\\}" "$\\1" content "${content}")
set(LOGO_BUILTIN_H "${LOGO_BUILTIN_H}#define FASTFETCH_DATATEXT_LOGO_${file} ${content}\n")
endforeach()
file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
@@ -525,6 +529,7 @@ if(LINUX)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_linux.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_linux.c
@@ -672,6 +677,7 @@ elseif(FreeBSD)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_bsd.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_bsd.c
@@ -705,7 +711,7 @@ elseif(FreeBSD)
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wm/wm_nosupport.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
@@ -734,7 +740,7 @@ elseif(NetBSD)
src/common/sysctl.c
src/detection/battery/battery_nbsd.c
src/detection/bios/bios_nbsd.c
src/detection/bluetooth/bluetooth_nosupport.c
src/detection/bluetooth/bluetooth_bsd.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/board/board_nbsd.c
src/detection/bootmgr/bootmgr_bsd.c
@@ -783,7 +789,7 @@ elseif(NetBSD)
src/detection/netio/netio_bsd.c
src/detection/opengl/opengl_linux.c
src/detection/os/os_nbsd.c
src/detection/packages/packages_obsd.c
src/detection/packages/packages_nbsd.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_nbsd.c
src/detection/gtk_qt/qt.c
@@ -797,8 +803,8 @@ elseif(NetBSD)
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wm/wm_nosupport.c
src/detection/wifi/wifi_nbsd.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
@@ -879,8 +885,8 @@ elseif(OpenBSD)
src/detection/uptime/uptime_bsd.c
src/detection/users/users_obsd.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wm/wm_nosupport.c
src/detection/wifi/wifi_obsd.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
@@ -977,7 +983,6 @@ elseif(WIN32)
src/detection/btrfs/btrfs_nosupport.c
src/detection/chassis/chassis_windows.c
src/detection/cpu/cpu_windows.c
src/detection/cpu/cpu_windows.cpp
src/detection/cpucache/cpucache_windows.c
src/detection/cpuusage/cpuusage_windows.c
src/detection/cursor/cursor_windows.c
@@ -1589,7 +1594,14 @@ elseif(WIN32)
PRIVATE "cfgmgr32"
PRIVATE "winbrand"
PRIVATE "propsys"
PRIVATE "secur32"
)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
# WoA only works on Windows 10 or higher
target_link_libraries(libfastfetch
PRIVATE "mincore"
)
endif()
elseif(FreeBSD)
target_link_libraries(libfastfetch
PRIVATE "m"
@@ -1613,6 +1625,7 @@ elseif(OpenBSD)
)
elseif(NetBSD)
target_link_libraries(libfastfetch
PRIVATE "bluetooth"
PRIVATE "m"
PRIVATE "prop"
)
@@ -1826,10 +1839,26 @@ if (BUILD_TESTS)
PRIVATE libfastfetch
)
add_executable(fastfetch-test-color
tests/color.c
)
target_link_libraries(fastfetch-test-color
PRIVATE libfastfetch
)
add_executable(fastfetch-test-duration
tests/duration.c
)
target_link_libraries(fastfetch-test-duration
PRIVATE libfastfetch
)
enable_testing()
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
add_test(NAME test-list COMMAND fastfetch-test-list)
add_test(NAME test-format COMMAND fastfetch-test-format)
add_test(NAME test-color COMMAND fastfetch-test-color)
add_test(NAME test-duration COMMAND fastfetch-test-duration)
endif()
##################
@@ -1897,17 +1926,17 @@ install(
##################
set(CPACK_GENERATOR "TGZ;ZIP")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
endif()
if(APPLE)
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-universal" CPACK_PACKAGE_FILE_NAME)
else() # We don't use this in Windows
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
endif()
if(IS_MUSL)
string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
else()
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
endif()
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) # use macos instead of darwin
elseif(IS_MUSL)
string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
else()
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
endif()
if(LINUX)
@@ -1933,12 +1962,17 @@ if(LINUX)
endif()
endif()
find_program(HAVE_RPMBUILD "rpmbuild")
if(HAVE_RPMBUILD)
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
if(NOT IS_MUSL)
find_program(HAVE_RPMBUILD "rpmbuild")
if(HAVE_RPMBUILD)
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
endif()
endif()
elseif(FreeBSD)
set(CPACK_FREEBSD_PACKAGE_LICENSE "MIT")
set(CPACK_GENERATOR "${CPACK_GENERATOR};FREEBSD")
endif()
set(CPACK_SET_DESTDIR ON)
+56
View File
@@ -21,6 +21,8 @@ Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for
<img src="screenshots/example3.png" width="48%" align="top" />
<img src="screenshots/example5.png" height="15%" align="top" />
According configuration files for examples are located [here](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets/examples).
There are [screenshots on different platforms](https://github.com/fastfetch-cli/fastfetch/wiki).
## Installation
@@ -71,6 +73,10 @@ You may also download the program directly from [the GitHub releases page](https
* `pkg install fastfetch`
### NetBSD
* `pkgin in fastfetch`
### Android (Termux)
* `pkg install fastfetch`
@@ -230,6 +236,56 @@ Set the key to a white space.
}
```
### Q: How can I display images on Windows?
As of April 2025:
#### mintty and Wezterm
mintty (used by Bash on Windows and MSYS2) and Wezterm (nightly build only) support the iTerm image protocol on Windows.
In `config.jsonc`:
```json
{
"logo": {
"type": "iterm",
"source": "C:/path/to/image.png",
"width": <num-in-chars>
}
}
```
#### Windows Terminal
Windows Terminal supports the sixel image protocol only.
* If you installed fastfetch through MSYS2:
1. Install imagemagick: `pacman -S mingw-w64-<subsystem>-x86_64-imagemagick`
2. In `config.jsonc`:
```jsonc
{
"logo": {
"type": "sixel", // DO NOT USE "auto"
"source": "C:/path/to/image.png", // Do NOT use `~` as fastfetch is a native Windows program and doesn't apply cygwin path conversion
"width": <image-width-in-chars>, // Optional
"height": <image-height-in-chars> // Optional
}
}
```
* If you installed fastfetch via scoop or downloaded the binary directly from the GitHub Releases page:
1. Convert your image manually to sixel format using [any online image conversion service](https://www.google.com/search?q=convert+image+to+sixel)
2. In `config.jsonc`:
```jsonc
{
"logo": {
"type": "raw", // DO NOT USE "auto"
"source": "C:/path/to/image.sixel",
"width": <image-width-in-chars>, // Required
"height": <image-height-in-chars> // Required
}
}
```
### Q: I want feature A / B / C. Will fastfetch support it?
Fastfetch is a system information tool. We only accept hardware or system-level software feature requests. For most personal uses, I recommend using the `Command` module to implement custom functionality, which can be used to grab output from a custom shell script:
+8 -1
View File
@@ -62,11 +62,17 @@ end
echo '
import json, subprocess, sys
def main():
data: dict[str, list[dict]] = json.loads(subprocess.check_output(["fastfetch", "--help-raw"]))
for key in data:
for flag in data[key]:
if flag["long"] == "logo-color-[1-9]":
for i in range(1, 10):
print(f"""complete -c fastfetch -d "{flag["desc"]}" -l "logo-color-{i}" -x -a "(__fastfetch_complete_color)" """)
continue
if flag.get("pseudo", False):
continue
@@ -75,7 +81,7 @@ def main():
command_prefix += f""" -o {flag["short"]}"""
if "arg" in flag:
type: str = flag["arg"]["type"];
type: str = flag["arg"]["type"]
if type == "bool":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
elif type == "color":
@@ -98,6 +104,7 @@ def main():
else:
print(f"{command_prefix} -f")
if __name__ == "__main__":
try:
main()
+42
View File
@@ -1,3 +1,45 @@
fastfetch (2.45.0) jammy; urgency=medium
* Update to 2.45.0
-- Carter Li <zhangsongcui@live.cn> Thu, 05 Jun 2025 10:56:38 +0800
fastfetch (2.44.0) jammy; urgency=medium
* Update to 2.44.0
-- Carter Li <zhangsongcui@live.cn> Mon, 26 May 2025 14:59:01 +0800
fastfetch (2.43.0) jammy; urgency=medium
* Update to 2.43.0
-- Carter Li <zhangsongcui@live.cn> Wed, 14 May 2025 09:49:50 +0800
fastfetch (2.42.0) jammy; urgency=medium
* Update to 2.42.0
-- Carter Li <zhangsongcui@live.cn> Wed, 30 Apr 2025 14:08:57 +0800
fastfetch (2.41.0) jammy; urgency=medium
* Update to 2.41.0
-- Carter Li <zhangsongcui@live.cn> Wed, 16 Apr 2025 13:42:58 +0800
fastfetch (2.40.4) jammy; urgency=medium
* Update to 2.40.4
-- Carter Li <zhangsongcui@live.cn> Thu, 10 Apr 2025 15:38:21 +0800
fastfetch (2.40.3) jammy; urgency=medium
* Update to 2.40.3
-- Carter Li <zhangsongcui@live.cn> Mon, 07 Apr 2025 09:29:27 +0800
fastfetch (2.40.0) jammy; urgency=medium
* Update to 2.40.0
+1 -1
View File
@@ -1 +1 @@
fastfetch_2.40.0_source.buildinfo universe/utils optional
fastfetch_2.45.0_source.buildinfo universe/utils optional
+18 -3
View File
@@ -115,7 +115,7 @@
"type": "string"
},
"biosFormat": {
"description": "Output format of the module `Bios`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
"description": "Output format of the module `BIOS`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
"type": "string"
},
"bluetoothFormat": {
@@ -279,7 +279,7 @@
"type": "string"
},
"packagesFormat": {
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop}: Number of scoop packages\n 21. {choco}: Number of choco packages\n 22. {pkgtool}: Number of pkgtool packages\n 23. {paludis}: Number of paludis packages\n 24. {winget}: Number of winget packages\n 25. {opkg}: Number of opkg packages\n 26. {am-system}: Number of am-system packages\n 27. {sorcery}: Number of sorcery packages\n 28. {lpkg}: Number of lpkg packages\n 29. {lpkgbuild}: Number of lpkgbuild packages\n 30. {guix-system}: Number of guix-system packages\n 31. {guix-user}: Number of guix-user packages\n 32. {guix-home}: Number of guix-home packages\n 33. {linglong}: Number of linglong packages\n 34. {pacstall}: Number of pacstall packages\n 35. {mport}: Number of mport packages\n 36. {qi}: Number of qi packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {nix-all}: Total number of all nix packages\n 43. {flatpak-all}: Total number of all flatpak app packages\n 44. {brew-all}: Total number of all brew packages\n 45. {guix-all}: Total number of all guix packages\n 46. {hpkg-all}: Total number of all hpkg packages",
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop}: Number of scoop packages\n 21. {choco}: Number of choco packages\n 22. {pkgtool}: Number of pkgtool packages\n 23. {paludis}: Number of paludis packages\n 24. {winget}: Number of winget packages\n 25. {opkg}: Number of opkg packages\n 26. {am-system}: Number of am-system packages\n 27. {sorcery}: Number of sorcery packages\n 28. {lpkg}: Number of lpkg packages\n 29. {lpkgbuild}: Number of lpkgbuild packages\n 30. {guix-system}: Number of guix-system packages\n 31. {guix-user}: Number of guix-user packages\n 32. {guix-home}: Number of guix-home packages\n 33. {linglong}: Number of linglong packages\n 34. {pacstall}: Number of pacstall packages\n 35. {mport}: Number of mport packages\n 36. {qi}: Number of qi packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {nix-all}: Total number of all nix packages\n 44. {flatpak-all}: Total number of all flatpak app packages\n 45. {brew-all}: Total number of all brew packages\n 46. {guix-all}: Total number of all guix packages\n 47. {hpkg-all}: Total number of all hpkg packages",
"type": "string"
},
"physicaldiskFormat": {
@@ -339,7 +339,7 @@
"type": "string"
},
"titleFormat": {
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)",
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name",
"type": "string"
},
"themeFormat": {
@@ -429,6 +429,7 @@
"file-raw",
"data",
"data-raw",
"command-raw",
"sixel",
"kitty",
"kitty-direct",
@@ -1754,6 +1755,14 @@
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options"
},
"hideFolders": {
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output\nDefault: /efi:/boot:/boot/efi"
},
"hideFS": {
"type": "string",
"description": "A colon separated file systems to hide from the disk output"
},
"showExternal": {
"type": "boolean",
"description": "Set if external volume should be printed",
@@ -2053,6 +2062,7 @@
"enum": [
"integrated",
"discrete",
"unknown",
"none"
],
"default": "none"
@@ -2992,6 +3002,11 @@
"const": "swap",
"description": "Print swap (paging file) space usage"
},
"separate": {
"type": "boolean",
"description": "Set if detailed swap devices should be reported on separate lines instead of a summary",
"default": false
},
"percent": {
"$ref": "#/$defs/percent"
},
+4 -1
View File
@@ -52,7 +52,10 @@
},
"memory",
"physicalmemory",
"swap",
{
"type": "swap",
"separate": true
},
"disk",
"btrfs",
"zpool",
+4 -1
View File
@@ -54,7 +54,10 @@
},
"memory",
"physicalmemory",
"swap",
{
"type": "swap",
"separate": true
},
"disk",
"btrfs",
"zpool",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"home": "https://github.com/ibireme/yyjson",
"license": "MIT ( embed in source )",
"version": "0.10.0",
"version": "0.11.1",
"author": "ibireme"
}
+2508 -1264
View File
File diff suppressed because it is too large Load Diff
+800 -570
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -134,7 +134,7 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
int len = snprintf(str, sizeof str, "%.3fms", ms);
if (thres > 0)
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
}
}
+2
View File
@@ -1,4 +1,5 @@
#include "fastfetch.h"
#include "common/init.h"
#include "common/parsing.h"
#include "common/thread.h"
#include "detection/displayserver/displayserver.h"
@@ -104,6 +105,7 @@ void ffStart(void)
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
#ifdef _WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
if (instance.config.display.noBuffer)
setvbuf(stdout, NULL, _IONBF, 0);
else
+7
View File
@@ -0,0 +1,7 @@
#pragma once
void ffInitInstance(void);
void ffStart(void);
void ffFinish(void);
void ffDestroyInstance(void);
void ffListFeatures(void);
+1 -1
View File
@@ -290,7 +290,7 @@ bool ffSuppressIO(bool suppress)
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty)
{
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC);
if (dfd < 0)
return;
+8
View File
@@ -147,6 +147,14 @@ ssize_t ffReadFileDataRelative(HANDLE dfd, const char* fileName, size_t dataSize
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
{
if (in[0] == '~') {
if ((in[1] == '/' || in[1] == '\\' || in[1] == '\0') && !ffStrContainsC(in, '%')) {
ffStrbufSet(out, &instance.state.platform.homeDir);
ffStrbufAppendS(out, in + 1);
return true;
}
}
DWORD length = ExpandEnvironmentStringsA(in, NULL, 0);
if (length <= 1) return false;
+1 -1
View File
@@ -224,7 +224,7 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
int len = snprintf(str, sizeof str, "%.3fms", ms);
if (thres > 0)
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
}
}
+30
View File
@@ -177,6 +177,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
if (ffCharIsEnglishAlphabet(value[0]))
{
FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET)
else FF_APPEND_COLOR_CODE_COND(bold_, FF_COLOR_MODE_BOLD)
else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD)
else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM)
else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC)
@@ -212,6 +213,35 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
exit(479);
}
}
else if (value[0] == '#')
{
// RGB color
++value;
char* pend = NULL;
uint32_t rgb = (uint32_t) strtoul(value, &pend, 16);
if (pend == value) {
fprintf(stderr, "Error: invalid RGB color code found: %s\n", value);
exit(479);
}
if (pend - value > 6) {
fprintf(stderr, "Error: RGB color code too long: %s\n", value);
exit(479);
}
else if (pend - value == 3) {
rgb = ((rgb & 0xF00) >> 8) * 0x110000 +
((rgb & 0x0F0) >> 4) * 0x001100 +
((rgb & 0x00F) >> 0) * 0x000011;
}
else if (pend - value != 6) {
fprintf(stderr, "Error: invalid RGB color code length: %s\n", value);
exit(479);
}
uint32_t r = rgb >> 16, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
ffStrbufAppendF(buffer, FF_COLOR_FG_RGB "%u;%u;%u", r, g, b);
value = pend;
continue;
}
ffStrbufAppendC(buffer, *value);
++value;
+15 -8
View File
@@ -190,19 +190,26 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
}
}
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result)
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result)
{
if(days == 0 && hours == 0 && minutes == 0)
if(totalSeconds < 60)
{
ffStrbufAppendF(result, "%u seconds", seconds);
ffStrbufAppendF(result, "%u second", (unsigned) totalSeconds);
if (totalSeconds != 1)
ffStrbufAppendC(result, 's');
return;
}
if(seconds >= 30)
{
minutes++;
seconds = 0;
}
uint32_t seconds = (uint32_t) (totalSeconds % 60);
totalSeconds /= 60;
if (seconds >= 30)
totalSeconds++;
uint32_t minutes = (uint32_t) (totalSeconds % 60);
totalSeconds /= 60;
uint32_t hours = (uint32_t) (totalSeconds % 24);
totalSeconds /= 24;
uint32_t days = (uint32_t) totalSeconds;
if(days > 0)
{
+1 -1
View File
@@ -27,4 +27,4 @@ int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
void ffParseSize(uint64_t bytes, FFstrbuf* result);
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result);
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result);
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result);
+5 -9
View File
@@ -1,5 +1,6 @@
#include "fastfetch.h"
#include "common/printing.h"
#include "logo/logo.h"
#include "util/textModifier.h"
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType)
@@ -99,7 +100,7 @@ void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleAr
ffStrbufPutTo(&buffer, stdout);
}
static void printError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, va_list arguments)
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
{
if(!instance.config.display.showErrors)
return;
@@ -109,7 +110,10 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
if(!instance.config.display.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
va_list arguments;
va_start(arguments, message);
vprintf(message, arguments);
va_end(arguments);
if(!instance.config.display.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
@@ -117,14 +121,6 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
putchar('\n');
}
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
{
va_list arguments;
va_start(arguments, message);
printError(moduleName, moduleIndex, moduleArgs, printType, message, arguments);
va_end(arguments);
}
void ffPrintColor(const FFstrbuf* colorValue)
{
//If the color is not set, this would reset in \033[m, which resets everything.
+11 -2
View File
@@ -130,7 +130,11 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
switch (GetLastError())
{
case ERROR_IO_PENDING:
if (!timeout || WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
#if __aarch64__
if (!GetOverlappedResultEx(hChildPipeRead, &overlapped, &nRead, timeout < 0 ? INFINITE : (DWORD) timeout, FALSE))
#else
// To support Windows 7
if (timeout >= 0 && WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
{
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
@@ -138,13 +142,18 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
}
if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE))
#endif
{
if (GetLastError() == ERROR_BROKEN_PIPE)
return NULL;
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
return "GetOverlappedResult(hChildPipeRead) failed";
return "GetOverlappedResult"
#if __aarch64__
"Ex"
#endif
"(hChildPipeRead) failed";
}
break;
+20 -3
View File
@@ -840,6 +840,22 @@
"default": "Auto detection using mount-points"
}
},
{
"long": "disk-hide-folders",
"desc": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output",
"arg": {
"type": "path",
"default": "/efi:/boot:/boot/efi"
}
},
{
"long": "disk-hide-fs",
"desc": "A colon separated list of file systems to hide from the disk output",
"arg": {
"type": "string",
"default": ""
}
},
{
"long": "disk-show-regular",
"desc": "Specify whether regular volumes should be displayed",
@@ -1128,23 +1144,24 @@
"arg": {
"type": "enum",
"enum": {
"auto": "Query platform-specific graphics APIs. Requires proper GPU drivers to be installed. Not supported on BSDs",
"auto": "Query platform-specific graphics APIs. Requires proper GPU drivers to be installed. Supported on Linux, FreeBSD, Windows and macOS",
"pci": "Search PCI devices, which does not require GPU drivers to be installed. Not supported on Windows and macOS",
"vulkan": "Use Vulkan API. Slow and requires proper Vulkan drivers to be installed. Used for Android",
"opencl": "Use OpenCL API. Slow and requires proper OpenCL drivers to be installed",
"opengl": "Use OpenGL API. Slow and only detects one GPU"
"opengl": "Use OpenGL API. Slow and only detects one GPU. Used for OpenBSD"
},
"default": "auto"
}
},
{
"long": "gpu-hide-type",
"desc": "Specify which types of GPUs should not be displayed",
"desc": "Specify which types of GPUs should not be displayed (default: all GPUs are shown, regardless of recognition)",
"arg": {
"type": "enum",
"enum": {
"integrated": "Hide integrated GPUs",
"discrete": "Hide discrete GPUs",
"unknown": "Hide unknown (unrecognized) GPUs",
"none": "Do not hide any GPUs"
},
"default": "none"
+24
View File
@@ -0,0 +1,24 @@
use scripting additions
use framework "/System/Library/PrivateFrameworks/MediaRemote.framework"
set MRNowPlayingRequest to current application's NSClassFromString("MRNowPlayingRequest")
if MRNowPlayingRequest's localNowPlayingItem() is missing value then
return
end if
if MRNowPlayingRequest's localIsPlaying() then
set status to "Playing"
else
set status to "Paused"
end if
set infoDict to MRNowPlayingRequest's localNowPlayingItem()'s nowPlayingInfo()
set bundleObj to MRNowPlayingRequest's localNowPlayingPlayerPath()'s client()
return status & "
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoTitle" as text) & "
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoArtist" as text) & "
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoAlbum" as text) & "
" & (bundleObj's bundleIdentifier() as text) & "
" & (bundleObj's displayName() as text)
+2 -2
View File
@@ -16,8 +16,8 @@
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
{
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed";
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
prop_dictionary_t root = NULL;
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
+2 -2
View File
@@ -8,9 +8,9 @@
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* result)
{
FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY);
FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY | O_CLOEXEC);
if (devfd < 0) return "open(dev/apm, O_RDONLY) failed";
if (devfd < 0) return "open(dev/apm, O_RDONLY | O_CLOEXEC) failed";
struct apm_power_info info = {};
+7 -1
View File
@@ -6,7 +6,13 @@
static int enumDev(FF_MAYBE_UNUSED int sockfd, struct bt_devinfo const* dev, FFlist* devices)
{
FFBluetoothResult* device = ffListAdd(devices);
ffStrbufInitS(&device->name, bt_devremote_name_gen(dev->devname, &dev->bdaddr));
ffStrbufInitS(&device->name,
#if __FreeBSD__
bt_devremote_name_gen(dev->devname, &dev->bdaddr)
#else
dev->devname
#endif
);
ffStrbufInitS(&device->address, bt_ntoa(&dev->bdaddr, NULL));
ffStrbufUpperCase(&device->address);
ffStrbufInit(&device->type);
+1 -1
View File
@@ -232,7 +232,7 @@ static uint32_t connectedDevices(void)
#endif
const char* ffDetectBluetooth(FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
{
#ifdef FF_HAVE_DBUS
int32_t connectedCount = -1;
+13 -3
View File
@@ -9,9 +9,19 @@ const char* ffDetectBoard(FFBoardResult* result)
if (!service)
return "No IOPlatformExpertDevice found";
io_name_t name;
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess)
ffStrbufSetS(&result->name, name);
FF_CFTYPE_AUTO_RELEASE CFTypeRef boardId = IORegistryEntryCreateCFProperty(service, CFSTR("board-id"), kCFAllocatorDefault, kNilOptions);
if (boardId)
ffCfStrGetString(boardId, &result->name);
else
{
io_name_t name;
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess)
ffStrbufSetS(&result->name, name);
}
FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(service, CFSTR("version"), kCFAllocatorDefault, kNilOptions);
if (version)
ffCfStrGetString(version, &result->version);
FF_CFTYPE_AUTO_RELEASE CFTypeRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
if (manufacturer)
+1 -1
View File
@@ -20,7 +20,7 @@
const char* ffDetectBootmgr(FFBootmgrResult* result)
{
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR);
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR | O_CLOEXEC);
if (efifd < 0) return "open(/dev/efi) failed";
uint8_t buffer[2048];
+1 -1
View File
@@ -12,7 +12,7 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
for (char i = '0'; i <= '9'; ++i) {
path[strlen("/dev/ttyC")] = i;
FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY);
FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY | O_CLOEXEC);
if (devfd < 0) {
if (errno == EACCES && i == '0')
+11 -2
View File
@@ -7,6 +7,9 @@
#if FF_HAVE_LINUX_VIDEODEV2
#include <linux/videodev2.h>
#elif __has_include(<sys/videoio.h>) // OpenBSD
#include <sys/videoio.h>
#define FF_HAVE_LINUX_VIDEODEV2 1
#endif
const char* ffDetectCamera(FFlist* result)
@@ -17,9 +20,15 @@ const char* ffDetectCamera(FFlist* result)
for (uint32_t i = 0; i <= 9; ++i)
{
path[ARRAY_SIZE(path) - 2] = (char) (i + '0');
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0)
break;
{
if (errno == ENOENT)
break;
if (errno == ENXIO)
continue;
return "Failed to open /dev/videoN";
}
struct v4l2_capability cap = {};
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+6
View File
@@ -106,9 +106,14 @@ static const char* armPartId2name(uint32_t partId)
case 0xd80: return "Cortex-A520";
case 0xd81: return "Cortex-A720";
case 0xd82: return "Cortex-X4";
case 0xd83: return "Neoverse-V3AE";
case 0xd84: return "Neoverse-V3";
case 0xd85: return "Cortex-X925";
case 0xd87: return "Cortex-A725";
case 0xd88: return "Cortex-A520AE";
case 0xd89: return "Cortex-A720AE";
case 0xd8e: return "Neoverse-N3";
case 0xd8f: return "Cortex-A320";
default: return NULL;
}
}
@@ -314,6 +319,7 @@ static const char* fujitsuPartId2name(uint32_t partId)
switch (partId)
{
case 0x001: return "A64FX";
case 0x003: return "MONAKA";
default: return NULL;
}
}
+36 -23
View File
@@ -1,5 +1,6 @@
#include "cpu.h"
#include "common/sysctl.h"
#include "util/stringUtils.h"
#include <sys/param.h>
#if __has_include(<sys/cpuset.h>)
@@ -34,36 +35,30 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
if (ffSysctlGetString("hw.model", &cpu->name) != NULL)
return "sysctlbyname(hw.model) failed";
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
cpu->coresLogical = cpu->coresPhysical;
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("kern.smp.cores", 0);
cpu->coresOnline = (uint16_t) ffSysctlGetInt("kern.smp.cpus", cpu->coresLogical);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
if (ffSysctlGetString("kern.sched.topology_spec", &buffer) == NULL && buffer.length > 0)
{
// <groups>
// <group level="1" cache-level="3">
// <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
// <children>
// <group level="2" cache-level="2">
// <cpu count="2" mask="3,0,0,0">0, 1</cpu>
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
// </group>
// <group level="2" cache-level="2">
// <cpu count="2" mask="c,0,0,0">2, 3</cpu>
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
// </group>
// </children>
// </group>
// <group level="1" cache-level="3">
// <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
// <children>
// <group level="2" cache-level="2">
// <cpu count="2" mask="3,0,0,0">0, 1</cpu>
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
// </group>
// <group level="2" cache-level="2">
// <cpu count="2" mask="c,0,0,0">2, 3</cpu>
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
// </group>
// </children>
// </group>
// </groups>
uint32_t i = 0;
while (true)
{
i = ffStrbufNextIndexS(&buffer, i, "<flag name=\"THREAD\">THREAD group</flag>"); // Find physical core with hyper-threading enabled
if (i >= buffer.length) break;
cpu->coresPhysical--;
i += (uint32_t) strlen("<flag name=\"THREAD\">THREAD group</flag>");
}
for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p)
cpu->packages++;
}
#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
@@ -79,6 +74,24 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
uint32_t clockrate = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
if (clockrate > cpu->frequencyBase) cpu->frequencyBase = clockrate;
for (uint16_t i = 0; i < cpu->coresLogical; ++i)
{
ffStrbufClear(&buffer);
char key[32];
snprintf(key, sizeof(key), "dev.cpu.%u.freq_levels", i);
if (ffSysctlGetString(key, &buffer) == NULL)
{
if (buffer.length == 0) continue;
// MHz/Watts pairs like: 2501/32000 2187/27125 2000/24000
uint32_t fmax = (uint32_t) strtoul(buffer.chars, NULL, 10);
if (cpu->frequencyMax < fmax) cpu->frequencyMax = fmax;
}
else
break;
}
cpu->temperature = FF_CPU_TEMP_UNSET;
if (options->temp)
+85 -7
View File
@@ -9,6 +9,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#define FF_CPUINFO_PATH "/proc/cpuinfo"
@@ -432,11 +433,11 @@ FF_MAYBE_UNUSED static uint16_t getPackageCount(FFstrbuf* cpuinfo)
{
p += strlen("\nphysical id\t:");
char* pend;
unsigned long id = strtoul(p, &pend, 10);
unsigned long long id = strtoul(p, &pend, 10);
if (__builtin_expect(id > 64, false)) // Do 129-socket boards exist?
high |= 1 << (id - 64);
high |= 1ULL << (id - 64);
else
low |= 1 << id;
low |= 1ULL << id;
p = pend;
}
@@ -458,9 +459,7 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
cpu->coresOnline = (uint16_t) get_nprocs();
cpu->packages = getPackageCount(&cpuinfo);
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, 0); // physical cores in single package
if (cpu->coresPhysical == 0)
cpu->coresPhysical = cpu->coresLogical;
else if (cpu->packages > 1)
if (cpu->coresPhysical > 0 && cpu->packages > 1)
cpu->coresPhysical *= cpu->packages;
// Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252
@@ -473,6 +472,82 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
#else
static const char* detectPhysicalCores(FFCPUResult* cpu)
{
int dfd = open("/sys/devices/system/cpu/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (dfd < 0) return "open(\"/sys/devices/system/cpu/\") failed";
FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd);
if (!dir) return "fdopendir(dfd) failed";
uint64_t pkgLow = 0, pkgHigh = 0;
struct dirent* entry;
FF_LIST_AUTO_DESTROY cpuList = ffListCreate(sizeof(uint32_t));
while ((entry = readdir(dir)) != NULL)
{
if (entry->d_type != DT_DIR || !ffStrStartsWith(entry->d_name, "cpu") || !ffCharIsDigit(entry->d_name[strlen("cpu")]))
continue;
FF_AUTO_CLOSE_FD int cpuxfd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_DIRECTORY);
if (cpuxfd < 0)
continue;
char buf[128];
// Check if the directory contains a file named "topology/physical_package_id"
// that lists the physical package id of the CPU.
ssize_t len = ffReadFileDataRelative(cpuxfd, "topology/physical_package_id", sizeof(buf) - 1, buf);
if (len > 0)
{
buf[len] = '\0';
unsigned long long id = strtoul(buf, NULL, 10);
if (__builtin_expect(id > 64, false)) // Do 129-socket boards exist?
pkgHigh |= 1ULL << (id - 64);
else
pkgLow |= 1ULL << id;
}
// Check if the directory contains a file named "topology/core_cpus_list"
// that lists the physical cores in the package.
len = ffReadFileDataRelative(cpuxfd, "topology/core_cpus_list", sizeof(buf) - 1, buf);
if (len > 0)
{
buf[len] = '\0'; // low-high or low
for (const char* p = buf; *p;)
{
char* pend;
uint32_t coreId = (uint32_t) strtoul(p, &pend, 10);
if (pend == p) break;
bool found = false;
FF_LIST_FOR_EACH(uint32_t, id, cpuList)
{
if (*id == coreId)
{
// This core is already counted
found = true;
break;
}
}
if (!found)
*(uint32_t*) ffListAdd(&cpuList) = coreId;
p = strchr(pend, ',');
if (!p) break;
++p;
}
}
}
cpu->coresPhysical = (uint16_t) cpuList.length;
cpu->packages = (uint16_t) (__builtin_popcountll(pkgLow) + __builtin_popcountll(pkgHigh));
return NULL;
}
FF_MAYBE_UNUSED static void parseIsa(FFstrbuf* cpuIsa)
{
// Always use the last part of the ISA string. Ref: #590 #1204
@@ -601,7 +676,7 @@ FF_MAYBE_UNUSED static uint16_t getLoongarchPropCount(FFstrbuf* cpuinfo, const c
FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options, FFCPUResult* cpu)
{
cpu->coresPhysical = cpu->coresLogical = (uint16_t) get_nprocs_conf();
cpu->coresLogical = (uint16_t) get_nprocs_conf();
cpu->coresOnline = (uint16_t) get_nprocs();
#if __ANDROID__
@@ -663,6 +738,9 @@ FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options,
#endif
}
if (cpu->coresPhysical == 0)
detectPhysicalCores(cpu);
return NULL;
}
#endif
+5 -3
View File
@@ -18,8 +18,8 @@ static void freePropDict(prop_dictionary_t* pdict)
static const char* detectCpuTemp(double* current)
{
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed";
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
__attribute__((__cleanup__(freePropDict))) prop_dictionary_t root = NULL;
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
@@ -51,7 +51,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
{
if (ffSysctlGetString("machdep.cpu_brand", &cpu->name) != NULL &&
ffSysctlGetString("machdep.dmi.processor-version", &cpu->name) != NULL &&
ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL)
ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL &&
ffSysctlGetString("hw.model", &cpu->name) != NULL)
{
ffStrbufSetS(&cpu->name, "Unknown CPU");
}
@@ -67,6 +68,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
if (freq == 0) freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
if (freq == 0) freq = (uint32_t) ffSysctlGetInt("machdep.dmi.processor-frequency", 0);
if (freq > cpu->frequencyBase) cpu->frequencyBase = freq;
cpu->temperature = FF_CPU_TEMP_UNSET;
+45 -8
View File
@@ -1,10 +1,53 @@
#include "cpu.h"
#include "common/sysctl.h"
#include "util/stringUtils.h"
#include <errno.h>
#include <sys/time.h>
#include <sys/sensors.h>
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
static const char* detectCPUTemp(FFCPUResult* cpu)
{
int mib[5] = {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0};
for (mib[2] = 0; mib[2] < 1024; mib[2]++)
{
struct sensordev sensordev;
size_t sdlen = sizeof(struct sensordev);
if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) < 0)
{
if (errno == ENOENT)
break;
if (errno == ENXIO)
continue;
return "sysctl(sensordev) failed";
}
if (!ffStrStartsWith(sensordev.xname, "cpu"))
continue;
for (mib[4] = 0; mib[4] < sensordev.maxnumt[SENSOR_TEMP]; mib[4]++)
{
struct sensor sensor;
size_t slen = sizeof(struct sensor);
if (sysctl(mib, 5, &sensor, &slen, NULL, 0) < 0)
{
if (errno != ENOENT)
return "sysctl(sensor) failed";
continue;
}
if (sensor.flags & SENSOR_FINVALID)
continue;
cpu->temperature = (double)(sensor.value - 273150000) / 1E6;
return NULL;
}
}
return "No sensor for CPU temp found";
}
const char *ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
{
if (ffSysctlGetString(CTL_HW, HW_MODEL, &cpu->name))
return "sysctl(hw.model) failed";
@@ -19,13 +62,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
if (cpuspeed > cpu->frequencyBase) cpu->frequencyBase = cpuspeed;
cpu->temperature = FF_CPU_TEMP_UNSET;
if (options->temp)
{
struct sensor sensors;
size_t size = sizeof(sensors);
if (sysctl((int[]) {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0}, 5, &sensors, &size, NULL, 0) == 0)
cpu->temperature = (double) (sensors.value - 273150000) / 1E6;
}
if (options->temp) detectCPUTemp(cpu);
return NULL;
}
+104 -2
View File
@@ -1,6 +1,60 @@
#include "cpu.h"
#include "common/processing.h"
#include "util/stringUtils.h"
#include <kstat.h>
static const char* detectCPUTempByKstat(kstat_ctl_t* kc, FFCPUResult* cpu)
{
const char* possibleModules[] = {"temperature", "cpu_temp", "acpi_thermal", NULL};
for (int i = 0; possibleModules[i] != NULL; i++) {
kstat_t* ks = kstat_lookup(kc, possibleModules[i], -1, NULL);
if (ks && kstat_read(kc, ks, NULL) >= 0) {
kstat_named_t* kn = kstat_data_lookup(ks, "temperature");
if (kn) {
switch (kn->data_type) {
case KSTAT_DATA_INT32:
cpu->temperature = (float)kn->value.i32;
return NULL;
case KSTAT_DATA_UINT32:
cpu->temperature = (float)kn->value.ui32;
return NULL;
case KSTAT_DATA_FLOAT:
cpu->temperature = kn->value.f;
return NULL;
}
}
}
}
return "Failed to find CPU temperature using kstat";
}
static const char* detectCPUTempByIpmiTool(FFCPUResult* cpu)
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]){
"ipmitool",
"-c",
"sdr",
"list",
NULL
});
if (error)
return error;
char* line = NULL;
size_t len = 0;
while (ffStrbufGetline(&line, &len, &buffer))
{
if (sscanf(line, "CPU%*d Temp,%lf,degrees C,ok", &cpu->temperature) == 1)
return NULL;
}
return "ipmitool sdr list failed to find CPU temperature";
}
static inline void kstatFreeWrap(kstat_ctl_t** pkc)
{
assert(pkc);
@@ -8,7 +62,46 @@ static inline void kstatFreeWrap(kstat_ctl_t** pkc)
kstat_close(*pkc);
}
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPUResult* cpu)
static inline uint16_t countTypeId(kstat_ctl_t* kc, const char* type)
{
uint64_t low = 0, high = 0;
for (kstat_t* ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
{
if (ffStrStartsWith(ksp->ks_module, "cpu_info"))
{
if (kstat_read(kc, ksp, NULL) < 0)
continue;
kstat_named_t* stat = kstat_data_lookup(ksp, type);
if (!stat)
continue;
uint32_t id = 0;
switch (stat->data_type)
{
#ifdef _INT64_TYPE
case KSTAT_DATA_INT64:
case KSTAT_DATA_UINT64:
id = (uint32_t) stat->value.ui64;
break;
#endif
case KSTAT_DATA_INT32:
case KSTAT_DATA_UINT32:
id = stat->value.ui32;
break;
default:
continue;
}
if (__builtin_expect(id > 64, false))
high |= 1ULL << (id - 64);
else
low |= 1ULL << id;
}
}
return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high));
}
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
{
__attribute__((__cleanup__(kstatFreeWrap))) kstat_ctl_t* kc = kstat_open();
if (!kc)
@@ -40,7 +133,16 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe
if (ks && kstat_read(kc, ks, NULL) >= 0)
{
kstat_named_t* kn = kstat_data_lookup(ks, "ncpus");
if (kn) cpu->coresLogical = cpu->coresPhysical = cpu->coresOnline = (uint16_t) kn->value.ui32;
if (kn) cpu->coresLogical = cpu->coresOnline = (uint16_t) kn->value.ui32;
}
cpu->packages = countTypeId(kc, "chip_id");
cpu->coresPhysical = countTypeId(kc, "core_id");
if (options->temp)
{
if (detectCPUTempByKstat(kc, cpu) != NULL)
detectCPUTempByIpmiTool(cpu);
}
return NULL;
+116 -4
View File
@@ -4,6 +4,120 @@
#include "util/mallocHelper.h"
#include "util/smbiosHelper.h"
#include <windows.h>
#include "perflib_.h"
#include <wchar.h>
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery)
{
if (*phQuery != NULL)
{
PerfCloseQueryHandle(*phQuery);
*phQuery = NULL;
}
}
const char* detectThermalTemp(double* result)
{
struct FFPerfQuerySpec
{
PERF_COUNTER_IDENTIFIER Identifier;
WCHAR Name[16];
} querySpec = {
.Identifier = {
// Thermal Zone Information
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{52bc5412-dac2-449c-8bc2-96443888fe6b}
.CounterSetGuid = { 0x52bc5412, 0xdac2, 0x449c, {0x8b, 0xc2, 0x96, 0x44, 0x38, 0x88, 0xfe, 0x6b} },
.Size = sizeof(querySpec),
.CounterId = PERF_WILDCARD_COUNTER,
.InstanceId = PERF_WILDCARD_COUNTER,
},
.Name = L"\\_TZ.CPUZ", // The standard(?) instance name for CPU temperature in the thermal provider
};
DWORD dataSize = 0;
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
return "PerfEnumerateCounterSetInstances() failed";
if (dataSize <= sizeof(PERF_INSTANCE_HEADER))
return "No `Thermal Zone Information` instances found";
{
FF_AUTO_FREE PERF_INSTANCE_HEADER* const pHead = malloc(dataSize);
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, pHead, dataSize, &dataSize) != ERROR_SUCCESS)
return "PerfEnumerateCounterSetInstances() failed to get instance headers";
PERF_INSTANCE_HEADER* pInstanceHeader = pHead;
while (1)
{
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
if (wcscmp(instanceName, querySpec.Name) == 0)
break;
dataSize -= pInstanceHeader->Size;
if (dataSize == 0)
break;
pInstanceHeader = (PERF_INSTANCE_HEADER*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
}
if (dataSize == 0)
{
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pHead + sizeof(*pHead));
wcscpy(querySpec.Name, instanceName); // Use the first instance name if the specific one is not found
}
}
__attribute__((__cleanup__(ffPerfCloseQueryHandle)))
HANDLE hQuery = NULL;
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
return "PerfOpenQueryHandle() failed";
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
return "PerfAddCounters() failed";
if (querySpec.Identifier.Status != ERROR_SUCCESS)
return "PerfAddCounters() reports invalid identifier";
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
return "PerfQueryCounterData(NULL) failed";
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER)) // PERF_ERROR_RETURN, should not happen
return "instance doesn't exist";
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = malloc(dataSize);
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS)
return "PerfQueryCounterData(pDataHeader) failed";
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1);
if (pCounterHeader->dwType != PERF_MULTIPLE_COUNTERS)
return "Invalid counter type";
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
{
if (pCounterData->dwDataSize == sizeof(int32_t))
{
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
switch (pCounterIds[iCounter]) {
case 0: // Temperature
*result = *(int32_t*)(pCounterData + 1) - 273;
break;
case 3: // High Precision Temperature
*result = *(int32_t*)(pCounterData + 1) / 10.0 - 273;
break;
}
}
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
}
return NULL;
}
// 7.5
typedef struct FFSmbiosProcessorInfo
{
@@ -111,7 +225,7 @@ static const char* detectNCores(FFCPUResult* cpu)
else if (ptr->Relationship == RelationProcessorCore)
++cpu->coresPhysical;
else if (ptr->Relationship == RelationProcessorPackage)
cpu->packages++;
++cpu->packages;
}
return NULL;
@@ -165,8 +279,6 @@ static const char* detectCoreTypes(FFCPUResult* cpu)
return NULL;
}
const char* detectThermalTemp(double* current, double* critical);
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
{
detectNCores(cpu);
@@ -182,7 +294,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
detectMaxSpeedBySmbios(cpu);
if(options->temp)
detectThermalTemp(&cpu->temperature, NULL);
detectThermalTemp(&cpu->temperature);
return NULL;
}
-34
View File
@@ -1,34 +0,0 @@
#include "util/windows/wmi.hpp"
extern "C"
const char* detectThermalTemp(double* current, double* critical)
{
// Requires Administrator privileges
// https://wutils.com/wmi/root/wmi/msacpi_thermalzonetemperature/#properties
FFWmiQuery query(L"SELECT CurrentTemperature, CriticalTripPoint FROM MSAcpi_ThermalZoneTemperature WHERE Active = TRUE", nullptr, FFWmiNamespace::WMI);
if(!query)
return "Query WMI service failed";
if(FFWmiRecord record = query.next())
{
if (current)
{
if(auto vtCurrent = record.get(L"CurrentTemperature"))
*current = vtCurrent.get<int32_t>() / 10 - 273.15; // In tenth of degrees Kelvin
else
*current = 0.0/0.0;
}
if (critical)
{
if(auto vtCritical = record.get(L"CriticalTripPoint"))
*critical = vtCritical.get<int32_t>() / 10 - 273.15; // In tenth of degrees Kelvin
else
*critical = 0.0/0.0;
}
return NULL;
}
return "No WMI result returned";
}
+133
View File
@@ -0,0 +1,133 @@
#pragma once
#include <windows.h>
#include <perflib.h>
// Missing from <perflib.h> of MinGW-w64 SDK
#define PERF_WILDCARD_COUNTER 0xFFFFFFFF
#define PERF_WILDCARD_INSTANCE L"*"
#define PERF_AGGREGATE_INSTANCE L"_Total"
#define PERF_MAX_INSTANCE_NAME 1024
typedef struct _PERF_INSTANCE_HEADER {
ULONG Size; // = sizeof(PERF_INSTANCE_HEADER) + sizeof(InstanceName) + sizeof(Padding)
ULONG InstanceId; // Instance ID.
// Followed by:
// WCHAR InstanceName[]; // Nul-terminated.
// WCHAR Padding[]; // Pad to a multiple of 8 bytes
} PERF_INSTANCE_HEADER, *PPERF_INSTANCE_HEADER;
typedef struct _PERF_COUNTER_IDENTIFIER {
GUID CounterSetGuid; // The GUID of the counterset.
ULONG Status; // Win32 error code indicating success/failure of the add/delete operation.
ULONG Size; // sizeof(PERF_COUNTER_IDENTIFIER) + sizeof(InstanceName) + sizeof(Padding)
ULONG CounterId; // CounterId, or PERF_WILDCARD_COUNTER for all counters.
ULONG InstanceId; // InstanceId, or 0xFFFFFFFF to not filter on instance ID.
ULONG Index; // Set by PerfQueryCounterInfo to the position in which the corresponding counter data is returned.
ULONG Reserved; // Reserved.
// Followed by:
// WCHAR InstanceName[];
// WCHAR Padding[];
} PERF_COUNTER_IDENTIFIER, * PPERF_COUNTER_IDENTIFIER;
typedef struct _PERF_DATA_HEADER {
ULONG dwTotalSize; // = sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER blocks...)
ULONG dwNumCounters; // The number of PERF_COUNTER_HEADER blocks.
LONGLONG PerfTimeStamp; // Timestamp from a high-resolution clock.
LONGLONG PerfTime100NSec; // The number of 100 nanosecond intervals since January 1, 1601, in Coordinated Universal Time (UTC).
LONGLONG PerfFreq; // The frequency of a high-resolution clock.
SYSTEMTIME SystemTime; // The time at which data is collected on the provider side.
// Followed by:
// PERF_COUNTER_HEADER blocks...;
} PERF_DATA_HEADER, * PPERF_DATA_HEADER;
typedef enum _PerfCounterDataType {
PERF_ERROR_RETURN = 0, /* An error occurred when the performance counter value was queried. */
PERF_SINGLE_COUNTER = 1, /* Query returned a single counter from a single-instance. */
PERF_MULTIPLE_COUNTERS = 2, /* Query returned multiple counters from a single instance. */
PERF_MULTIPLE_INSTANCES = 4, /* Query returned a single counter from each of multiple instances. */
PERF_COUNTERSET = 6 /* Query returned multiple counters from each of multiple instances. */
} PerfCounterDataType;
typedef struct _PERF_COUNTER_HEADER {
ULONG dwStatus; // Win32 error code indicating success/failure of the query operation.
PerfCounterDataType dwType; // Result type - error, single/single, multi/single, single/multi, multi/multi.
ULONG dwSize; // = sizeof(PERF_COUNTER_HEADER) + sizeof(Additional data)
ULONG Reserved; // Reserved.
// Followed by additional data:
// If dwType == PERF_ERROR_RETURN: nothing.
// If dwType == PERF_SINGLE_COUNTER: PERF_COUNTER_DATA block.
// If dwType == PERF_MULTIPLE_COUNTERS: PERF_MULTI_COUNTERS block + PERF_COUNTER_DATA blocks.
// If dwType == PERF_MULTIPLE_INSTANCES: PERF_MULTI_INSTANCES block.
// If dwType == PERF_COUNTERSET: PERF_MULTI_COUNTERS block + PERF_MULTI_INSTANCES block.
} PERF_COUNTER_HEADER, * PPERF_COUNTER_HEADER;
typedef struct _PERF_MULTI_COUNTERS {
ULONG dwSize; // sizeof(PERF_MULTI_COUNTERS) + sizeof(CounterIds)
ULONG dwCounters; // Number of counter ids.
// Followed by:
// DWORD CounterIds[dwCounters];
} PERF_MULTI_COUNTERS, * PPERF_MULTI_COUNTERS;
typedef struct _PERF_COUNTER_DATA {
ULONG dwDataSize; // Size of the counter data, in bytes.
ULONG dwSize; // = sizeof(PERF_COUNTER_DATA) + sizeof(Data) + sizeof(Padding)
// Followed by:
// BYTE Data[dwDataSize];
// BYTE Padding[];
} PERF_COUNTER_DATA, * PPERF_COUNTER_DATA;
_Success_(return == ERROR_SUCCESS)
ULONG
WINAPI
PerfEnumerateCounterSetInstances(
_In_opt_z_ LPCWSTR szMachine,
_In_ LPCGUID pCounterSetId,
_Out_opt_bytecap_post_bytecount_(cbInstances, *pcbInstancesActual) PPERF_INSTANCE_HEADER pInstances,
DWORD cbInstances,
_Out_ LPDWORD pcbInstancesActual
);
_Success_(return == ERROR_SUCCESS)
ULONG
WINAPI
PerfOpenQueryHandle(
_In_opt_z_ LPCWSTR szMachine,
_Out_ HANDLE * phQuery
);
_Success_(return == ERROR_SUCCESS)
ULONG
WINAPI
PerfCloseQueryHandle(
_In_ HANDLE hQuery
);
_Success_(return == ERROR_SUCCESS)
ULONG
WINAPI
PerfAddCounters(
_In_ HANDLE hQuery,
_Inout_bytecount_(cbCounters) PPERF_COUNTER_IDENTIFIER pCounters,
DWORD cbCounters
);
_Success_(return == ERROR_SUCCESS)
ULONG
WINAPI
PerfDeleteCounters(
_In_ HANDLE hQuery,
_Inout_bytecount_(cbCounters) PPERF_COUNTER_IDENTIFIER pCounters,
DWORD cbCounters
);
_Success_(return == ERROR_SUCCESS)
ULONG
WINAPI
PerfQueryCounterData(
_In_ HANDLE hQuery,
_Out_opt_bytecap_post_bytecount_(cbCounterBlock, *pcbCounterBlockActual) PPERF_DATA_HEADER pCounterBlock,
DWORD cbCounterBlock,
_Out_ LPDWORD pcbCounterBlockActual
);
+19 -8
View File
@@ -10,18 +10,29 @@
#include "util/stringUtils.h"
#include <ctype.h>
#ifdef __FreeBSD__
#include <paths.h>
#ifndef _PATH_LOCALBASE
#define _PATH_LOCALBASE "/usr/local"
#endif
#elif __OpenBSD__
#define _PATH_LOCALBASE "/usr/local"
#elif __NetBSD__
#define _PATH_LOCALBASE "/usr/pkg"
#endif
static void getKDE(FFstrbuf* result, FFDEOptions* options)
{
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", 1, (FFpropquery[]) {
{"X-KDE-PluginInfo-Version =", result}
});
#ifdef _PATH_LOCALBASE
ffParsePropFile(_PATH_LOCALBASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
{
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", 1, (FFpropquery[]) {
{"X-KDE-PluginInfo-Version =", result}
});
}
ffParsePropFile(_PATH_LOCALBASE "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
#else
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
#endif
if(result->length == 0)
ffParsePropFileData("xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
+4 -4
View File
@@ -1,6 +1,6 @@
#include "disk.h"
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint)
{
#ifdef _WIN32
const char separator = ';';
@@ -11,12 +11,12 @@ bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
uint32_t mountpointLength = (uint32_t) strlen(mountpoint);
uint32_t startIndex = 0;
while(startIndex < options->folders.length)
while(startIndex < folders->length)
{
uint32_t colonIndex = ffStrbufNextIndexC(&options->folders, startIndex, separator);
uint32_t colonIndex = ffStrbufNextIndexC(folders, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == mountpointLength && memcmp(options->folders.chars + startIndex, mountpoint, mountpointLength) == 0)
if (folderLength == mountpointLength && memcmp(folders->chars + startIndex, mountpoint, mountpointLength) == 0)
return true;
startIndex = colonIndex + 1;
+1 -1
View File
@@ -28,4 +28,4 @@ typedef struct FFDisk
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint);
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint);
+7 -7
View File
@@ -52,7 +52,7 @@ static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
return NULL;
}
#else
static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
static const char* detectFsLabel(FF_MAYBE_UNUSED struct statfs* fs, FF_MAYBE_UNUSED FFDisk* disk)
{
return "Fastfetch was compiled without libgeom support";
}
@@ -145,10 +145,10 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if(__builtin_expect(options->folders.length > 0, 0))
{
if(!ffDiskMatchMountpoint(options, fs->f_mntonname))
if(!ffDiskMatchMountpoint(&options->folders, fs->f_mntonname))
continue;
}
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs"))
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs"))
continue;
#ifdef __FreeBSD__
@@ -159,13 +159,13 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
FFDisk* disk = ffListAdd(disks);
disk->bytesTotal = (uint64_t)fs->f_blocks * fs->f_bsize;
disk->bytesFree = (uint64_t)fs->f_bfree * fs->f_bsize;
disk->bytesAvailable = (uint64_t)fs->f_bavail * fs->f_bsize;
disk->bytesTotal = (uint64_t)fs->f_blocks * (uint64_t)fs->f_bsize;
disk->bytesFree = (uint64_t)fs->f_bfree * (uint64_t)fs->f_bsize;
disk->bytesAvailable = (uint64_t)fs->f_bavail * (uint64_t)fs->f_bsize;
disk->bytesUsed = 0; // To be filled in ./disk.c
disk->filesTotal = (uint32_t) fs->f_files;
disk->filesUsed = (uint32_t) (fs->f_files - fs->f_ffree);
disk->filesUsed = (uint32_t) fs->f_files - (uint32_t) fs->f_ffree;
ffStrbufInitS(&disk->mountFrom, fs->f_mntfromname);
ffStrbufInitS(&disk->mountpoint, fs->f_mntonname);
+1 -1
View File
@@ -23,7 +23,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, path.Path()))
if (!ffDiskMatchMountpoint(&options->folders, path.Path()))
continue;
}
+9 -5
View File
@@ -37,6 +37,10 @@ static bool isPhysicalDevice(const struct mntent* device)
if(ffStrEquals(device->mnt_type, "zfs"))
return true;
//sshfs
if(ffStrEquals(device->mnt_type, "fuse.sshfs"))
return true;
//Pseudo filesystems don't have a device in /dev
if(!ffStrStartsWith(device->mnt_fsname, "/dev/"))
return false;
@@ -220,7 +224,7 @@ static bool isRemovable(FFDisk* currentDisk)
static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mntent* device)
{
if(ffStrbufStartsWithS(&currentDisk->mountpoint, "/boot") || ffStrbufStartsWithS(&currentDisk->mountpoint, "/efi"))
if(hasmntopt(device, "x-gvfs-hide") || hasmntopt(device, "hidden"))
currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
else if(isSubvolume(disks, currentDisk))
currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
@@ -240,9 +244,9 @@ static void detectStats(FFDisk* disk)
if(statvfs(disk->mountpoint.chars, &fs) != 0)
memset(&fs, 0, sizeof(fs)); //Set all values to 0, so our values get initialized to 0 too
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
disk->bytesFree = fs.f_bfree * fs.f_frsize;
disk->bytesAvailable = fs.f_bavail * fs.f_frsize;
disk->bytesTotal = fs.f_blocks * (uint64_t) fs.f_frsize;
disk->bytesFree = fs.f_bfree * (uint64_t) fs.f_frsize;
disk->bytesAvailable = fs.f_bavail * (uint64_t) fs.f_frsize;
disk->bytesUsed = 0; // To be filled in ./disk.c
if (fs.f_files >= fs.f_ffree)
@@ -281,7 +285,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, device->mnt_dir))
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
continue;
}
else if(!isPhysicalDevice(device))
+1 -1
View File
@@ -113,7 +113,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, device.mnt_mountp))
if (!ffDiskMatchMountpoint(&options->folders, device.mnt_mountp))
continue;
}
else if(!isPhysicalDevice(&device))
+1 -5
View File
@@ -47,7 +47,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (__builtin_expect((long) options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, buffer.chars))
if (!ffDiskMatchMountpoint(&options->folders, buffer.chars))
continue;
}
else if(driveType == DRIVE_NO_ROOT_DIR)
@@ -99,9 +99,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
wchar_t diskName[MAX_PATH + 1], diskFileSystem[MAX_PATH + 1];
//https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa#remarks
UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
DWORD diskFlags;
BOOL result = GetVolumeInformationW(mountpoint,
diskName, ARRAY_SIZE(diskName), //Volume name
@@ -110,7 +107,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
&diskFlags, //File system flags
diskFileSystem, ARRAY_SIZE(diskFileSystem)
);
SetErrorMode(errorMode);
if(result)
{
@@ -2,6 +2,7 @@
#include "util/apple/cf_helpers.h"
#include "util/stringUtils.h"
#include "util/edidHelper.h"
#include "detection/os/os.h"
#include <stdlib.h>
#include <string.h>
@@ -194,7 +195,22 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
ffStrbufSetStatic(&ds->wmPrettyName, "Quartz Compositor");
}
}
ffStrbufSetStatic(&ds->dePrettyName, "Aqua");
const FFOSResult* os = ffDetectOS();
char* str_end;
const char* version = os->version.chars;
unsigned long osNum = strtoul(version, &str_end, 10);
if (str_end != version)
{
if (osNum > 15) { // Tahoe
ffStrbufSetStatic(&ds->dePrettyName, "Liquid Glass");
} else if (osNum < 10) {
ffStrbufSetStatic(&ds->dePrettyName, "Platinum");
} else {
ffStrbufSetStatic(&ds->dePrettyName, "Aqua");
}
}
detectDisplays(ds);
}
@@ -5,7 +5,7 @@
#include <stdint.h>
#include <stddef.h>
#include <wayland-util.h>
#include <wayland-client.h>
#ifdef __cplusplus
extern "C" {
@@ -214,6 +214,26 @@ enum kde_output_device_v2_capability {
* @since 9
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS = 0x80,
/**
* if this outputdevice supports the built-in color profile
* @since 12
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR = 0x100,
/**
* if this outputdevice supports DDC/CI
* @since 14
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI = 0x200,
/**
* if this outputdevice supports setting max bpc
* @since 15
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR = 0x400,
/**
* if this outputdevice supports EDR
* @since 16
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR = 0x800,
};
/**
* @ingroup iface_kde_output_device_v2
@@ -235,6 +255,22 @@ enum kde_output_device_v2_capability {
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS_SINCE_VERSION 9
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR_SINCE_VERSION 12
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI_SINCE_VERSION 14
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR_SINCE_VERSION 15
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR_SINCE_VERSION 16
#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */
#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM
@@ -316,6 +352,18 @@ enum kde_output_device_v2_color_power_tradeoff {
};
#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM */
#ifndef KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
/**
* @ingroup iface_kde_output_device_v2
* when the compositor may make use of EDR
*/
enum kde_output_device_v2_edr_policy {
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_NEVER = 0,
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ALWAYS = 1,
};
#endif /* KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM */
/**
* @ingroup iface_kde_output_device_v2
* @struct kde_output_device_v2_listener
@@ -658,6 +706,74 @@ struct kde_output_device_v2_listener {
void (*dimming)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t multiplier);
/**
* source output for mirroring
*
*
* @param source uuid of the source output
* @since 13
*/
void (*replication_source)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
const char *source);
/**
* if DDC/CI should be used to control brightness etc.
*
* If the ddc_ci capability is present, this determines if
* settings such as brightness, contrast or others should be set
* using DDC/CI.
* @param allowed 1 if allowed, 0 if disabled
* @since 14
*/
void (*ddc_ci_allowed)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t allowed);
/**
* override max bpc
*
* This limits the amount of bits per color that are sent to the
* display.
* @param max_bpc 0 for the default / automatic
* @since 15
*/
void (*max_bits_per_color)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t max_bpc);
/**
* range of max bits per color value
*
*
* @param min_value the minimum supported by the driver
* @param max_value the maximum supported by the driver
* @since 15
*/
void (*max_bits_per_color_range)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t min_value,
uint32_t max_value);
/**
* if and to what value automatic max bpc is limited
*
*
* @param max_bpc_limit which value automatic bpc gets limited to. 0 if not limited
* @since 15
*/
void (*automatic_max_bits_per_color_limit)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t max_bpc_limit);
/**
* when the compositor may apply EDR
*
* When EDR is enabled, the compositor may increase the backlight
* beyond the user-specified setting, in order to present HDR
* content on displays without native HDR support. This will
* usually result in better visuals, but also increases battery
* usage.
* @since 16
*/
void (*edr_policy)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t policy);
};
/**
@@ -779,6 +895,30 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_DIMMING_SINCE_VERSION 11
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_REPLICATION_SOURCE_SINCE_VERSION 13
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_DDC_CI_ALLOWED_SINCE_VERSION 14
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION 15
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_RANGE_SINCE_VERSION 15
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_AUTOMATIC_MAX_BITS_PER_COLOR_LIMIT_SINCE_VERSION 15
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_SINCE_VERSION 16
/** @ingroup iface_kde_output_device_v2 */
@@ -60,12 +60,18 @@ static const struct wl_message kde_output_device_v2_events[] = {
{ "brightness", "8u", kde_output_device_v2_types + 0 },
{ "color_power_tradeoff", "10u", kde_output_device_v2_types + 0 },
{ "dimming", "11u", kde_output_device_v2_types + 0 },
{ "replication_source", "13s", kde_output_device_v2_types + 0 },
{ "ddc_ci_allowed", "14u", kde_output_device_v2_types + 0 },
{ "max_bits_per_color", "15u", kde_output_device_v2_types + 0 },
{ "max_bits_per_color_range", "15uu", kde_output_device_v2_types + 0 },
{ "automatic_max_bits_per_color_limit", "15u", kde_output_device_v2_types + 0 },
{ "edr_policy", "16u", kde_output_device_v2_types + 0 },
};
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
"kde_output_device_v2", 11,
"kde_output_device_v2", 16,
0, NULL,
27, kde_output_device_v2_events,
33, kde_output_device_v2_events,
};
static const struct wl_message kde_output_device_mode_v2_events[] = {
@@ -137,6 +137,12 @@ static void waylandKdeHdrListener(void *data, FF_MAYBE_UNUSED struct kde_output_
display->hdrEnabled = !!hdr_enabled;
}
static void waylandKdeMaxBitsPerColorListener(void *data, FF_MAYBE_UNUSED struct kde_output_device_v2 *kde_output_device_v2, uint32_t max_bpc)
{
WaylandDisplay* display = data;
display->bitDepth = (uint8_t) max_bpc;
}
static struct kde_output_device_v2_listener outputListener = {
.geometry = waylandKdeGeometryListener,
.current_mode = waylandKdeCurrentModeListener,
@@ -165,6 +171,12 @@ static struct kde_output_device_v2_listener outputListener = {
.brightness = (void*) stubListener,
.color_power_tradeoff = (void*) stubListener,
.dimming = (void*) stubListener,
.replication_source = (void*) stubListener,
.ddc_ci_allowed = (void*) stubListener,
.max_bits_per_color = (void*) waylandKdeMaxBitsPerColorListener,
.max_bits_per_color_range = (void*) stubListener,
.automatic_max_bits_per_color_limit = (void*) stubListener,
.edr_policy = (void*) stubListener,
};
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
@@ -237,6 +249,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
item->manufactureYear = display.myear;
item->manufactureWeek = display.mweek;
item->serial = display.serial;
item->bitDepth = display.bitDepth;
}
ffStrbufDestroy(&display.description);
@@ -34,6 +34,7 @@ typedef struct WaylandData
typedef struct WaylandDisplay
{
WaylandData* parent;
void* internal;
int32_t width;
int32_t height;
int32_t refreshRate;
@@ -55,7 +56,7 @@ typedef struct WaylandDisplay
uint16_t myear;
uint16_t mweek;
uint32_t serial;
void* internal;
uint8_t bitDepth;
} WaylandDisplay;
inline static void stubListener(void* data, ...)
+5 -1
View File
@@ -335,6 +335,7 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(xcbRandr, "dlopen libxcb-randr failed", "libxcb-randr" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connect)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connection_has_error)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_get_setup)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_setup_roots_iterator)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_screen_next)
@@ -368,8 +369,11 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
data.connection = ffxcb_connect(NULL, NULL);
if(data.connection == NULL)
if(ffxcb_connection_has_error(data.connection) > 0)
{
ffxcb_disconnect(data.connection);
return "xcb_connect() failed";
}
data.result = result;
-3
View File
@@ -20,9 +20,6 @@ extern int ADL2_Adapter_Graphic_Core_Info_Get(ADL_CONTEXT_HANDLE context, int iA
// Function to retrieve memory information from the adapter. Version 2
extern int ADL2_Adapter_MemoryInfo2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLMemoryInfo2* lpMemoryInfo2);
// This function retrieves the VRAM usage of given adapter.
extern int ADL2_Adapter_VRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
// This function retrieves the Dedicated VRAM usage of given adapter.
extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
File diff suppressed because it is too large Load Diff
+12 -2
View File
@@ -15,6 +15,11 @@ const char* FF_GPU_VENDOR_NAME_PARALLEL = "Parallel";
const char* FF_GPU_VENDOR_NAME_MICROSOFT = "Microsoft";
const char* FF_GPU_VENDOR_NAME_REDHAT = "RedHat";
const char* FF_GPU_VENDOR_NAME_ORACLE = "Oracle";
const char* FF_GPU_VENDOR_NAME_BROADCOM = "Broadcom";
const char* FF_GPU_VENDOR_NAME_LOONGSON = "Loongson";
const char* FF_GPU_VENDOR_NAME_JINGJIA_MICRO = "Jingjia Micro";
const char* FF_GPU_VENDOR_NAME_HUAWEI = "Huawei";
const char* FF_GPU_VENDOR_NAME_ZHAOXIN = "Zhaoxin";
const char* ffGPUGetVendorString(unsigned vendorId)
{
@@ -22,17 +27,22 @@ const char* ffGPUGetVendorString(unsigned vendorId)
switch (vendorId)
{
case 0x106b: return FF_GPU_VENDOR_NAME_APPLE;
case 0x1002: case 0x1022: return FF_GPU_VENDOR_NAME_AMD;
case 0x1002: case 0x1022: case 0x1dd8: return FF_GPU_VENDOR_NAME_AMD;
case 0x8086: case 0x8087: case 0x03e7: return FF_GPU_VENDOR_NAME_INTEL;
case 0x0955: case 0x10de: case 0x12d2: return FF_GPU_VENDOR_NAME_NVIDIA;
case 0x1ed5: return FF_GPU_VENDOR_NAME_MTHREADS;
case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
case 0x17cb: case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
case 0x14c3: return FF_GPU_VENDOR_NAME_MTK;
case 0x15ad: return FF_GPU_VENDOR_NAME_VMWARE;
case 0x1af4: return FF_GPU_VENDOR_NAME_REDHAT;
case 0x1ab8: return FF_GPU_VENDOR_NAME_PARALLEL;
case 0x1414: return FF_GPU_VENDOR_NAME_MICROSOFT;
case 0x108e: return FF_GPU_VENDOR_NAME_ORACLE;
case 0x182f: case 0x14e4: return FF_GPU_VENDOR_NAME_BROADCOM;
case 0x0014: return FF_GPU_VENDOR_NAME_LOONGSON;
case 0x0731: return FF_GPU_VENDOR_NAME_JINGJIA_MICRO;
case 0x19e5: return FF_GPU_VENDOR_NAME_HUAWEI;
case 0x1d17: return FF_GPU_VENDOR_NAME_ZHAOXIN;
default: return NULL;
}
}
+19 -1
View File
@@ -49,7 +49,25 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus);
const char* ffGPUGetVendorString(unsigned vendorId);
typedef struct FFGpuDriverPciBusId
{
uint32_t domain;
uint32_t bus;
uint32_t device;
uint32_t func;
} FFGpuDriverPciBusId;
#if defined(__linux__) || defined(__FreeBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu);
void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu);
#endif
#if FF_HAVE_DRM
const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath);
const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath);
const char* ffDrmDetectI915(FFGPUResult* gpu, int fd);
const char* ffDrmDetectXe(FFGPUResult* gpu, int fd);
const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd);
#endif // FF_HAVE_DRM
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId);
#endif // defined(XXX)
+1 -20
View File
@@ -49,7 +49,6 @@ struct FFAdlData {
FF_LIBRARY_SYMBOL(ADL2_Adapter_Graphic_Core_Info_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_VRAMUsage_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get)
FF_LIBRARY_SYMBOL(ADL2_Overdrive_Caps)
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_CapabilitiesX2_Get)
@@ -91,7 +90,6 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_Graphic_Core_Info_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_VRAMUsage_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive_Caps)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_CapabilitiesX2_Get)
@@ -188,29 +186,12 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
FF_DEBUG("ADL2_Adapter_DedicatedVRAMUsage_Get returned %s (%d), usage: %d MB",
ffAdlStatusToString(status), status, vramUsage);
if (status == ADL_OK) {
if (status == ADL_OK && vramUsage >= 0) {
result.memory->used = (uint64_t) vramUsage * 1024 * 1024;
FF_DEBUG("Dedicated VRAM usage: %llu bytes (%d MB)", result.memory->used, vramUsage);
} else {
FF_DEBUG("Failed to get dedicated VRAM usage");
}
if (result.sharedMemory)
{
vramUsage = 0;
status = adlData.ffADL2_Adapter_VRAMUsage_Get(adlData.apiHandle, device->iAdapterIndex, &vramUsage);
FF_DEBUG("ADL2_Adapter_VRAMUsage_Get returned %s (%d), usage: %d MB",
ffAdlStatusToString(status), status, vramUsage);
if (status == ADL_OK) {
uint64_t totalUsage = (uint64_t) vramUsage * 1024 * 1024;
result.sharedMemory->used = totalUsage - result.memory->used;
FF_DEBUG("Total VRAM usage: %llu bytes, Shared VRAM usage: %llu bytes (%llu MB)",
totalUsage, result.sharedMemory->used, result.sharedMemory->used / (1024 * 1024));
} else {
FF_DEBUG("Failed to get total VRAM usage");
}
}
}
if (result.memoryType)
+6 -1
View File
@@ -3,6 +3,9 @@
#import <Metal/MTLDevice.h>
#import <IOKit/kext/KextManager.h>
#ifndef MAC_OS_VERSION_26_0
#define MTLGPUFamilyMetal4 ((MTLGPUFamily) 5002)
#endif
#ifndef MAC_OS_VERSION_13_0
#define MTLGPUFamilyMetal3 ((MTLGPUFamily) 5001)
#endif
@@ -57,7 +60,9 @@ const char* ffGpuDetectMetal(FFlist* gpus)
else if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 1");
#else // MAC_OS_X_VERSION_10_15
if ([device supportsFamily:MTLGPUFamilyMetal3])
if ([device supportsFamily:MTLGPUFamilyMetal4])
ffStrbufSetStatic(&gpu->platformApi, "Metal 4");
else if ([device supportsFamily:MTLGPUFamilyMetal3])
ffStrbufSetStatic(&gpu->platformApi, "Metal 3");
else if ([device supportsFamily:MTLGPUFamilyCommon3])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3");
-91
View File
@@ -1,91 +0,0 @@
#if __aarch64__ && FF_HAVE_DRM
#include <drm.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#if __has_include(<drm/asahi_drm.h>)
#include <drm/asahi_drm.h>
#else
// https://github.com/AsahiLinux/linux/blob/asahi/include/uapi/drm/asahi_drm.h
/* SPDX-License-Identifier: MIT */
/* Copyright (C) The Asahi Linux Contributors */
#define DRM_ASAHI_UNSTABLE_UABI_VERSION 10011
#define DRM_ASAHI_GET_PARAMS 0x00
#define DRM_ASAHI_MAX_CLUSTERS 32
struct drm_asahi_params_global
{
__u32 unstable_uabi_version;
__u32 pad0;
__u64 feat_compat;
__u64 feat_incompat;
__u32 gpu_generation;
__u32 gpu_variant;
__u32 gpu_revision;
__u32 chip_id;
__u32 num_dies;
__u32 num_clusters_total;
__u32 num_cores_per_cluster;
__u32 num_frags_per_cluster;
__u32 num_gps_per_cluster;
__u32 num_cores_total_active;
__u64 core_masks[DRM_ASAHI_MAX_CLUSTERS];
__u32 vm_page_size;
__u32 pad1;
__u64 vm_user_start;
__u64 vm_user_end;
__u64 vm_usc_start;
__u64 vm_usc_end;
__u64 vm_kernel_min_size;
__u32 max_syncs_per_submission;
__u32 max_commands_per_submission;
__u32 max_commands_in_flight;
__u32 max_attachments;
__u32 timer_frequency_hz;
__u32 min_frequency_khz;
__u32 max_frequency_khz;
__u32 max_power_mw;
__u32 result_render_size;
__u32 result_compute_size;
__u32 firmware_version[4];
};
struct drm_asahi_get_params
{
/** @extensions: Pointer to the first extension struct, if any */
__u64 extensions;
/** @param: Parameter group to fetch (MBZ) */
__u32 param_group;
/** @pad: MBZ */
__u32 pad;
/** @value: User pointer to write parameter struct */
__u64 pointer;
/** @value: Size of user buffer, max size supported on return */
__u64 size;
};
enum
{
DRM_IOCTL_ASAHI_GET_PARAMS = DRM_IOWR(DRM_COMMAND_BASE + DRM_ASAHI_GET_PARAMS, struct drm_asahi_get_params),
};
#endif // __has_include
#endif // FF_HAVE_DRM
+156 -44
View File
@@ -1,6 +1,7 @@
#include "gpu_driver_specific.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include <sys/pciio.h>
#include <fcntl.h>
@@ -10,11 +11,145 @@
#include <bus/pci/pcireg.h> // DragonFly
#endif
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
static void fillGPUTypeGeneric(FFGPUResult* gpu)
{
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY, 0);
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
}
#if FF_HAVE_DRM
#include "common/library.h"
#include "util/stringUtils.h"
#include <xf86drm.h>
static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus)
{
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm" FF_LIBRARY_EXTENSION " failed", "libdrm" FF_LIBRARY_EXTENSION, 2)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices)
drmDevicePtr devices[64];
int nDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices));
if (nDevices < 0)
return "drmGetDevices() failed";
for (int iDev = 0; iDev < nDevices; ++iDev)
{
drmDevice* dev = devices[iDev];
if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY)))
continue;
const char* path = dev->nodes[DRM_NODE_PRIMARY];
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitS(&gpu->platformApi, path);
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = 0;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
switch (dev->bustype)
{
case DRM_BUS_PCI:
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->deviceinfo.pci->vendor_id));
gpu->deviceId = (dev->businfo.pci->domain * 100000ull) + (dev->businfo.pci->bus * 1000ull) + (dev->businfo.pci->dev * 10ull) + dev->businfo.pci->func;
break;
case DRM_BUS_HOST1X:
ffStrbufSetS(&gpu->name, dev->deviceinfo.host1x->compatible[0]);
gpu->type = FF_GPU_TYPE_INTEGRATED;
break;
case DRM_BUS_PLATFORM:
ffStrbufSetS(&gpu->name, dev->deviceinfo.platform->compatible[0]);
gpu->type = FF_GPU_TYPE_INTEGRATED;
break;
case DRM_BUS_USB:
ffStrbufSetF(&gpu->name, "USB Device (%u-%u)", dev->deviceinfo.usb->vendor, dev->deviceinfo.usb->product);
gpu->type = FF_GPU_TYPE_DISCRETE;
break;
}
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) continue;
char driverName[64];
driverName[0] = '\0';
struct drm_version ver = {
.name = driverName,
.name_len = ARRAY_SIZE(driverName),
};
if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0)
ffStrbufSetF(&gpu->driver, "%*s %d.%d.%d", (int) ver.name_len, ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel);
if (ffStrStartsWith(driverName, "i915"))
ffDrmDetectI915(gpu, fd);
else if (ffStrStartsWith(driverName, "amdgpu"))
ffDrmDetectAmdgpu(options, gpu, dev->nodes[DRM_NODE_RENDER]);
else if (ffStrStartsWith(driverName, "radeon"))
ffDrmDetectRadeon(options, gpu, dev->nodes[DRM_NODE_RENDER]);
else if (ffStrStartsWith(driverName, "xe"))
ffDrmDetectXe(gpu, fd);
else if (ffStrStartsWith(driverName, "asahi"))
ffDrmDetectAsahi(gpu, fd);
else if (dev->bustype == DRM_BUS_PCI)
{
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
.domain = (uint32_t) dev->businfo.pci->domain,
.bus = dev->businfo.pci->bus,
.device = dev->businfo.pci->dev,
.func = dev->businfo.pci->func,
});
}
if (gpu->name.length == 0)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName(dev->deviceinfo.pci->device_id, dev->deviceinfo.pci->revision_id, gpu);
if (gpu->name.length == 0)
ffGPUFillVendorAndName(0, dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id, gpu);
}
fillGPUTypeGeneric(gpu);
}
ffdrmFreeDevices(devices, nDevices);
return NULL;
}
#endif
static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus)
{
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC);
if (fd < 0)
return "open(\"/dev/pci\", O_RDONLY, 0) failed";
return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed";
struct pci_conf confs[128];
struct pci_match_conf match = {
@@ -54,27 +189,12 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
gpu->deviceId = (pc->pc_sel.pc_domain * 100000ull) + (pc->pc_sel.pc_bus * 1000ull) + (pc->pc_sel.pc_dev * 10ull) + pc->pc_sel.pc_func;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
{
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = {
.domain = (uint32_t) pc->pc_sel.pc_domain,
.bus = pc->pc_sel.pc_bus,
.device = pc->pc_sel.pc_dev,
.func = pc->pc_sel.pc_func,
},
}, (FFGpuDriverResult) {
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.type = &gpu->type,
.frequency = &gpu->frequency,
.coreUsage = &gpu->coreUsage,
.name = &gpu->name,
}, "libnvidia-ml.so");
}
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
.domain = (uint32_t) pc->pc_sel.pc_domain,
.bus = pc->pc_sel.pc_bus,
.device = pc->pc_sel.pc_dev,
.func = pc->pc_sel.pc_func,
});
if (gpu->name.length == 0)
{
@@ -84,27 +204,19 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu);
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
fillGPUTypeGeneric(gpu);
}
return NULL;
}
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
{
if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO)
{
detectByDrm(options, gpus);
if (gpus->length > 0) return NULL;
}
return detectByPci(options, gpus);
}
-8
View File
@@ -10,14 +10,6 @@ typedef enum __attribute__((__packed__)) FFGpuDriverConditionType
FF_GPU_DRIVER_CONDITION_TYPE_FORCE_UNSIGNED = UINT8_MAX,
} FFGpuDriverConditionType;
typedef struct FFGpuDriverPciBusId
{
uint32_t domain;
uint32_t bus;
uint32_t device;
uint32_t func;
} FFGpuDriverPciBusId;
typedef struct FFGpuDriverPciDeviceId
{
uint32_t deviceId;
+372
View File
@@ -0,0 +1,372 @@
#include "gpu.h"
#if FF_HAVE_DRM
#include <drm.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "common/io/io.h"
#include "common/library.h"
#include "util/mallocHelper.h"
#include "util/stringUtils.h"
#include "intel_drm.h"
#include "asahi_drm.h"
#include <radeon_drm.h>
const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath)
{
FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "Failed to open DRM render device";
uint32_t value;
// https://github.com/torvalds/linux/blob/fb4d33ab452ea254e2c319bac5703d1b56d895bf/drivers/gpu/drm/radeon/radeon_kms.c#L231
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_ACTIVE_CU_COUNT,
.value = (uintptr_t) &value,
}) >= 0)
gpu->coreCount = (int32_t) value;
if (options->temp)
{
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_CURRENT_GPU_TEMP, // millidegrees C
.value = (uintptr_t) &value,
}) >= 0 && value != 0) // 0 means unavailable
gpu->temperature = (double) value / 1000.0;
}
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_MAX_SCLK, // MHz
.value = (uintptr_t) &value,
}) >= 0)
gpu->frequency = (uint32_t) (value / 1000u);
if (options->driverSpecific)
{
struct drm_radeon_gem_info gemInfo;
if (ioctl(fd, DRM_IOCTL_RADEON_GEM_INFO, &gemInfo) >= 0)
{
// vram_usage can be bigger than vram_usage, so we use vram_size here
gpu->dedicated.total = gemInfo.vram_size;
gpu->shared.total = gemInfo.gart_size;
uint64_t memSize;
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_VRAM_USAGE, // uint64_t
.value = (uintptr_t) &memSize,
}) >= 0)
gpu->dedicated.used = memSize;
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
.request = RADEON_INFO_GTT_USAGE, // uint64_t
.value = (uintptr_t) &memSize,
}) >= 0)
gpu->shared.used = memSize;
}
}
return NULL;
}
#ifdef FF_HAVE_DRM_AMDGPU
#include <amdgpu.h>
#include <amdgpu_drm.h>
const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath)
{
#if FF_HAVE_DRM_AMDGPU
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize)
FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "Failed to open DRM render device";
amdgpu_device_handle handle;
uint32_t majorVersion, minorVersion;
if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0)
return "Failed to initialize AMDGPU device";
uint32_t value;
if (options->temp)
{
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0)
gpu->temperature = value / 1000.;
}
ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle));
struct amdgpu_gpu_info gpuInfo;
if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0)
{
gpu->coreCount = (int32_t) gpuInfo.cu_active_number;
gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
#define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break
switch (gpuInfo.vram_type)
{
FF_VRAM_CASE(UNKNOWN, 0);
FF_VRAM_CASE(GDDR1, 1);
FF_VRAM_CASE(DDR2, 2);
FF_VRAM_CASE(GDDR3, 3);
FF_VRAM_CASE(GDDR4, 4);
FF_VRAM_CASE(GDDR5, 5);
FF_VRAM_CASE(HBM, 6);
FF_VRAM_CASE(DDR3, 7);
FF_VRAM_CASE(DDR4, 8);
FF_VRAM_CASE(GDDR6, 9);
FF_VRAM_CASE(DDR5, 10);
FF_VRAM_CASE(LPDDR4, 11);
FF_VRAM_CASE(LPDDR5, 12);
default:
ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type);
break;
}
struct amdgpu_heap_info heapInfo;
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0)
{
gpu->dedicated.total = heapInfo.heap_size;
gpu->dedicated.used = heapInfo.heap_usage;
}
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_GTT, 0, &heapInfo) >= 0)
{
gpu->shared.total = heapInfo.heap_size;
gpu->shared.used = heapInfo.heap_usage;
}
}
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0)
gpu->coreUsage = value;
ffamdgpu_device_deinitialize(handle);
return NULL;
#else
FF_UNUSED(gpu, renderPath);
return "Fastfetch is compiled without libdrm support";
#endif
}
#endif
const char* ffDrmDetectI915(FFGPUResult* gpu, int fd)
{
{
int value;
drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value };
if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0)
gpu->coreCount = value;
}
{
struct drm_i915_query_item queryItem = {
.query_id = DRM_I915_QUERY_MEMORY_REGIONS,
};
struct drm_i915_query query = {
.items_ptr = (uintptr_t) &queryItem,
.num_items = 1,
};
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 )
{
FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length);
queryItem.data_ptr = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0)
{
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
struct drm_i915_query_memory_regions* regionInfo = (void*) buffer;
for (uint32_t i = 0; i < regionInfo->num_regions; i++)
{
struct drm_i915_memory_region_info* region = regionInfo->regions + i;
switch (region->region.memory_class)
{
case I915_MEMORY_CLASS_SYSTEM:
gpu->shared.total += region->probed_size;
gpu->shared.used += region->probed_size - region->unallocated_size;
break;
case I915_MEMORY_CLASS_DEVICE:
gpu->dedicated.total += region->probed_size;
gpu->dedicated.used += region->probed_size - region->unallocated_size;
break;
}
}
}
}
}
return NULL;
}
static inline int popcountBytes(uint8_t* bytes, uint32_t length)
{
int count = 0;
while (length >= 8)
{
count += __builtin_popcountll(*(uint64_t*) bytes);
bytes += 8;
length -= 8;
}
if (length >= 4)
{
count += __builtin_popcountl(*(uint32_t*) bytes);
bytes += 4;
length -= 4;
}
if (length >= 2)
{
count += __builtin_popcountl(*(uint16_t*) bytes);
bytes += 2;
length -= 2;
}
if (length)
{
count += __builtin_popcountl(*(uint8_t*) bytes);
}
return count;
}
const char* ffDrmDetectXe(FFGPUResult* gpu, int fd)
{
bool flag = false;
{
struct drm_xe_device_query query = {
.query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
};
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
query.data = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
int dssCount = 0, euPerDssCount = 0;
for (struct drm_xe_query_topology_mask* topo = (void*) buffer;
(uint8_t*) topo < buffer + query.size;
topo = (void*) (topo->mask + topo->num_bytes)
) {
switch (topo->type)
{
case DRM_XE_TOPO_DSS_COMPUTE:
case DRM_XE_TOPO_DSS_GEOMETRY:
dssCount += popcountBytes(topo->mask, topo->num_bytes);
break;
case DRM_XE_TOPO_EU_PER_DSS:
euPerDssCount += popcountBytes(topo->mask, topo->num_bytes);
break;
}
}
gpu->coreCount = dssCount * euPerDssCount;
flag = true;
}
}
}
{
struct drm_xe_device_query query = {
.query = DRM_XE_DEVICE_QUERY_MEM_REGIONS,
};
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
query.data = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
struct drm_xe_query_mem_regions* regionInfo = (void*) buffer;
for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++)
{
struct drm_xe_mem_region* region = regionInfo->mem_regions + i;
switch (region->mem_class)
{
case DRM_XE_MEM_REGION_CLASS_SYSMEM:
gpu->shared.total += region->total_size;
gpu->shared.used += region->used;
break;
case DRM_XE_MEM_REGION_CLASS_VRAM:
gpu->dedicated.total += region->total_size;
gpu->dedicated.used += region->used;
break;
}
}
flag = true;
}
}
}
return flag ? NULL : "Failed to query Xe GPU information";
}
const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd)
{
struct drm_asahi_params_global paramsGlobal = {};
if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) {
.param_group = DRM_ASAHI_GET_PARAMS,
.pointer = (uint64_t) &paramsGlobal,
.size = sizeof(paramsGlobal),
}) >= 0)
{
// They removed `unstable_uabi_version` from the struct. Hopefully they won't introduce new ABI changes.
gpu->coreCount = (int32_t) (paramsGlobal.num_clusters_total * paramsGlobal.num_cores_per_cluster);
gpu->frequency = paramsGlobal.max_frequency_khz / 1000;
gpu->deviceId = paramsGlobal.chip_id;
if (!gpu->name.length)
{
const char* variant = " Unknown";
switch (paramsGlobal.gpu_variant) {
case 'G':
variant = "";
break;
case 'S':
variant = " Pro";
break;
case 'C':
variant = " Max";
break;
case 'D':
variant = " Ultra";
break;
}
ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)",
paramsGlobal.gpu_generation - 12, variant,
paramsGlobal.gpu_generation, paramsGlobal.gpu_variant,
paramsGlobal.gpu_revision + 0xA0);
}
return NULL;
}
return "Failed to query Asahi GPU information";
}
#endif // FF_HAVE_DRM
#include "gpu_driver_specific.h"
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId)
{
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
const char* soName;
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific))
{
return detectFn(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = pciBusId,
}, (FFGpuDriverResult) {
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
.type = &gpu->type,
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
.name = &gpu->name,
}, soName);
}
return "No driver-specific detection function found for the GPU vendor";
}
+1 -1
View File
@@ -5,7 +5,7 @@
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
FF_AUTO_CLOSE_FD int pokefd = open(POKE_DEVICE_FULLNAME, O_RDWR);
FF_AUTO_CLOSE_FD int pokefd = open(POKE_DEVICE_FULLNAME, O_RDWR | O_CLOEXEC);
if (pokefd < 0) return "open(POKE_DEVICE_FULLNAME) failed";
pci_info dev;
+100 -295
View File
@@ -21,10 +21,16 @@
#include <sys/ioctl.h>
#endif
#include "gpu_asahi.h"
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
#if defined(FF_HAVE_DRM) && defined(__aarch64__)
// https://github.com/alyssarosenzweig/linux/blob/agx-uapi-v7/include/uapi/drm/asahi_drm.h
// Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
#if __has_include(<drm/asahi_drm.h>)
#include <drm/asahi_drm.h>
#else
#include "asahi_drm.h"
#endif
#define FF_HAVE_DRM_ASAHI 1
#endif
static bool pciDetectDriver(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
{
@@ -99,73 +105,23 @@ FF_MAYBE_UNUSED static const char* drmFindRenderFromCard(const char* drmCardKey,
static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
{
#if FF_HAVE_DRM_AMDGPU
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize)
#if FF_HAVE_DRM
const char* error = drmFindRenderFromCard(drmKey, buffer);
if (error) return error;
if (ffStrbufEqualS(&gpu->driver, "radeon"))
return ffDrmDetectRadeon(options, gpu, buffer->chars);
else
{
const char* error = drmFindRenderFromCard(drmKey, buffer);
if (error) return error;
#if FF_HAVE_DRM_AMDGPU
return ffDrmDetectAmdgpu(options, gpu, buffer->chars);
#else
FF_UNUSED(options, gpu, drmKey, buffer);
return "Fastfetch is not compiled with libdrm_amdgpu support";
#endif
}
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
if (fd < 0) return "Failed to open DRM device";
amdgpu_device_handle handle;
uint32_t majorVersion, minorVersion;
if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0)
return "Failed to initialize AMDGPU device";
ffStrbufAppendF(&gpu->driver, " %u.%u", (unsigned) majorVersion, (unsigned) minorVersion);
uint32_t value;
if (options->temp)
{
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0)
gpu->temperature = value / 1000.;
}
ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle));
struct amdgpu_gpu_info gpuInfo;
if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0)
{
gpu->coreCount = (int32_t) gpuInfo.cu_active_number;
gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
struct amdgpu_heap_info heapInfo;
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0)
{
if (gpu->type == FF_GPU_TYPE_DISCRETE)
{
gpu->dedicated.total = heapInfo.heap_size;
gpu->dedicated.used = heapInfo.heap_usage;
}
else
{
gpu->shared.total = heapInfo.heap_size;
gpu->shared.used = heapInfo.heap_usage;
}
}
}
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0)
gpu->coreUsage = value;
ffamdgpu_device_deinitialize(handle);
return NULL;
#else
FF_UNUSED(options, gpu, drmKey, buffer);
return "Fastfetch is compiled without libdrm support";
FF_UNUSED(gpu, drmKey, buffer);
return "Fastfetch is not compiled with drm support";
#endif
}
@@ -189,46 +145,54 @@ static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu,
ffStrbufAppendC(pciDir, '/');
const uint32_t hwmonLen = pciDir->length;
ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only)
if (ffPathExists(pciDir->chars, FF_PATHTYPE_ANY))
gpu->type = FF_GPU_TYPE_INTEGRATED;
else
gpu->type = FF_GPU_TYPE_DISCRETE;
uint64_t value = 0;
if (options->temp)
{
ffStrbufSubstrBefore(pciDir, hwmonLen);
ffStrbufAppendS(pciDir, "temp1_input"); // The on die GPU temperature in millidegrees Celsius
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
gpu->temperature = (double) value / 1000;
}
if (options->driverSpecific)
if (ffStrbufEqualS(&gpu->driver, "amdgpu")) // Ancient radeon drivers don't have these files
{
ffStrbufSubstrBefore(pciDir, pciDirLen);
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
{
if (gpu->type == FF_GPU_TYPE_DISCRETE)
gpu->dedicated.total = value;
else
gpu->shared.total = value;
ffStrbufSubstrBefore(pciDir, hwmonLen);
ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only)
if (ffPathExists(pciDir->chars, FF_PATHTYPE_ANY))
gpu->type = FF_GPU_TYPE_INTEGRATED;
else
gpu->type = FF_GPU_TYPE_DISCRETE;
ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total"));
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used");
if (options->driverSpecific)
{
ffStrbufSubstrBefore(pciDir, pciDirLen);
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
{
if (gpu->type == FF_GPU_TYPE_DISCRETE)
gpu->dedicated.used = value;
gpu->dedicated.total = value;
else
gpu->shared.used = value;
gpu->shared.total = value;
ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total"));
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
{
if (gpu->type == FF_GPU_TYPE_DISCRETE)
gpu->dedicated.used = value;
else
gpu->shared.used = value;
}
}
ffStrbufSubstrBefore(pciDir, pciDirLen);
ffStrbufAppendS(pciDir, "/gpu_busy_percent");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
gpu->coreUsage = (double) value;
}
}
}
static void pciDetectIntelSpecific(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer, const char* drmKey)
static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer, const char* drmKey)
{
// Works for Intel GPUs
// https://patchwork.kernel.org/project/intel-gfx/patch/1422039866-11572-3-git-send-email-ville.syrjala@linux.intel.com/
@@ -238,40 +202,46 @@ static void pciDetectIntelSpecific(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf*
if (!drmKey) return;
if (ffStrbufEqualS(&gpu->driver, "xe"))
const uint32_t pciDirLen = pciDir->length;
bool isXE = ffStrbufEqualS(&gpu->driver, "xe");
if (isXE)
ffStrbufAppendS(pciDir, "/tile0/gt0/freq0/max_freq");
else
ffStrbufAppendF(pciDir, "/drm/%s/gt_max_freq_mhz", drmKey);
if (ffReadFileBuffer(pciDir->chars, buffer))
gpu->frequency = (uint32_t) ffStrbufToUInt(buffer, 0);
}
ffStrbufSubstrBefore(pciDir, pciDirLen);
static inline int popcountBytes(uint8_t* bytes, uint32_t length)
{
int count = 0;
while (length >= 8)
if (options->temp)
{
count += __builtin_popcountll(*(uint64_t*) bytes);
bytes += 8;
length -= 8;
ffStrbufAppendS(pciDir, "/hwmon/");
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pciDir->chars);
if (dirp)
{
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL)
{
if (entry->d_name[0] == '.') continue;
ffStrbufSubstrBefore(pciDir, pciDirLen + strlen("/hwmon/"));
ffStrbufAppendS(pciDir, entry->d_name);
// https://github.com/Syllo/nvtop/blob/73291884d926445e499d6b9b71cb7a9bdbc7c393/src/extract_gpuinfo_intel.c#L279-L281
ffStrbufAppendS(pciDir, isXE ? "/temp2_input" : "/temp1_input");
if (ffReadFileBuffer(pciDir->chars, buffer))
{
uint64_t value = ffStrbufToUInt(buffer, 0);
if (value > 0)
{
gpu->temperature = (double) value / 1000;
break;
}
}
}
}
ffStrbufSubstrBefore(pciDir, pciDirLen);
}
if (length >= 4)
{
count += __builtin_popcountl(*(uint32_t*) bytes);
bytes += 4;
length -= 4;
}
if (length >= 2)
{
count += __builtin_popcountl(*(uint16_t*) bytes);
bytes += 2;
length -= 2;
}
if (length)
{
count += __builtin_popcountl(*(uint8_t*) bytes);
}
return count;
}
static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
@@ -279,120 +249,14 @@ static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey,
#if FF_HAVE_DRM
ffStrbufSetS(buffer, "/dev/dri/");
ffStrbufAppendS(buffer, drmKey);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
if (fd < 0) return "Failed to open drm device";
if (ffStrbufEqualS(&gpu->driver, "xe"))
{
{
struct drm_xe_device_query query = {
.extensions = 0,
.query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
.size = 0,
.data = 0,
};
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
query.data = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
int dssCount = 0, euPerDssCount = 0;
for (struct drm_xe_query_topology_mask* topo = (void*) buffer;
(uint8_t*) topo < buffer + query.size;
topo = (void*) (topo->mask + topo->num_bytes)
) {
switch (topo->type)
{
case DRM_XE_TOPO_DSS_COMPUTE:
case DRM_XE_TOPO_DSS_GEOMETRY:
dssCount += popcountBytes(topo->mask, topo->num_bytes);
break;
case DRM_XE_TOPO_EU_PER_DSS:
euPerDssCount += popcountBytes(topo->mask, topo->num_bytes);
break;
}
}
gpu->coreCount = dssCount * euPerDssCount;
}
}
}
{
struct drm_xe_device_query query = {
.query = DRM_XE_DEVICE_QUERY_MEM_REGIONS,
};
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
query.data = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
{
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
struct drm_xe_query_mem_regions* regionInfo = (void*) buffer;
for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++)
{
struct drm_xe_mem_region* region = regionInfo->mem_regions + i;
switch (region->mem_class)
{
case DRM_XE_MEM_REGION_CLASS_SYSMEM:
gpu->shared.total += region->total_size;
gpu->shared.used += region->used;
break;
case DRM_XE_MEM_REGION_CLASS_VRAM:
gpu->dedicated.total += region->total_size;
gpu->dedicated.used += region->used;
break;
}
}
}
}
}
}
return ffDrmDetectXe(gpu, fd);
else if (ffStrbufEqualS(&gpu->driver, "i915"))
{
{
int value;
drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value };
if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0)
gpu->coreCount = value;
}
{
struct drm_i915_query_item queryItem = {
.query_id = DRM_I915_QUERY_MEMORY_REGIONS,
};
struct drm_i915_query query = {
.items_ptr = (uintptr_t) &queryItem,
.num_items = 1,
};
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 )
{
FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length);
queryItem.data_ptr = (uintptr_t) buffer;
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0)
{
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
struct drm_i915_query_memory_regions* regionInfo = (void*) buffer;
for (uint32_t i = 0; i < regionInfo->num_regions; i++)
{
struct drm_i915_memory_region_info* region = regionInfo->regions + i;
switch (region->region.memory_class)
{
case I915_MEMORY_CLASS_SYSTEM:
gpu->shared.total += region->probed_size;
gpu->shared.used += region->probed_size - region->unallocated_size;
break;
case I915_MEMORY_CLASS_DEVICE:
gpu->dedicated.total += region->probed_size;
gpu->dedicated.used += region->probed_size - region->unallocated_size;
break;
}
}
}
}
}
}
return NULL;
return ffDrmDetectI915(gpu, fd);
return "Unknown Intel GPU driver";
#else
FF_UNUSED(gpu, drmKey, buffer);
return "Fastfetch is not compiled with drm support";
@@ -500,36 +364,19 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
pciDetectIntelSpecific(gpu, deviceDir, buffer, drmKey);
pciDetectIntelSpecific(options, gpu, deviceDir, buffer, drmKey);
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
if (options->driverSpecific && drmKey)
drmDetectIntelSpecific(gpu, drmKey, buffer);
}
else
{
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
const char* soName;
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific))
{
detectFn(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = {
.domain = pciDomain,
.bus = pciBus,
.device = pciDevice,
.func = pciFunc,
},
}, (FFGpuDriverResult) {
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
.type = &gpu->type,
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
.name = &gpu->name,
}, soName);
}
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
.domain = pciDomain,
.bus = pciBus,
.device = pciDevice,
.func = pciFunc,
});
}
if (gpu->name.length == 0)
@@ -556,60 +403,18 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
#if __aarch64__
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FFstrbuf* buffer, const char* drmKey)
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FF_MAYBE_UNUSED FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
{
if (sscanf(name, "agx-t%lu", &gpu->deviceId) == 1)
ffStrbufSetStatic(&gpu->name, ffCPUAppleCodeToName((uint32_t) gpu->deviceId));
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
#if FF_HAVE_DRM
#if FF_HAVE_DRM_ASAHI
ffStrbufSetS(buffer, "/dev/dri/");
ffStrbufAppendS(buffer, drmKey);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
if (fd >= 0)
{
struct drm_asahi_params_global paramsGlobal = {};
if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) {
.param_group = DRM_ASAHI_GET_PARAMS,
.pointer = (uint64_t) &paramsGlobal,
.size = sizeof(paramsGlobal),
}) >= 0)
{
ffStrbufAppendF(&gpu->driver, " %u", paramsGlobal.unstable_uabi_version);
// FIXME: They will introduce ABI breaking changes. Always check the latest version
// https://www.reddit.com/r/AsahiLinux/comments/1ei2qiv/comment/lgm0v5s/
if (paramsGlobal.unstable_uabi_version == DRM_ASAHI_UNSTABLE_UABI_VERSION)
{
gpu->coreCount = (int) paramsGlobal.num_cores_total_active;
gpu->frequency = paramsGlobal.max_frequency_khz / 1000;
gpu->deviceId = paramsGlobal.chip_id;
if (!gpu->name.length)
{
const char* variant = " Unknown";
switch (paramsGlobal.gpu_variant) {
case 'G':
variant = "";
break;
case 'S':
variant = " Pro";
break;
case 'C':
variant = " Max";
break;
case 'D':
variant = " Ultra";
break;
}
ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)",
paramsGlobal.gpu_generation - 12, variant,
paramsGlobal.gpu_generation, paramsGlobal.gpu_variant,
paramsGlobal.gpu_revision + 0xA0);
}
}
}
}
return ffDrmDetectAsahi(gpu, fd);
#endif
return NULL;
+1
View File
@@ -12,6 +12,7 @@ const char* ffDetectHost(FFHostResult* host)
|| ffSettingsGetAndroidProperty("ro.vivo.market.name", &host->name)
|| ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->name)
|| ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->name)
|| ffSettingsGetAndroidProperty("ro.vendor.oplus.market.enname", &host->name)
|| ffSettingsGetAndroidProperty("ro.config.devicename", &host->name)
|| ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->name)
|| ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->name)
+4
View File
@@ -36,6 +36,10 @@ const char* getOthersByIokit(FFHostResult* host)
if (manufacturer)
ffCfStrGetString(manufacturer, &host->vendor);
FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("version"), kCFAllocatorDefault, kNilOptions);
if (version)
ffCfStrGetString(version, &host->version);
return NULL;
}
+14 -2
View File
@@ -77,10 +77,11 @@ const char* ffDetectHost(FFHostResult* host)
//On WSL, the real host can't be detected. Instead use WSL as host.
if(wslDistroName != NULL || getenv("WSL_DISTRO") != NULL || getenv("WSL_INTEROP") != NULL)
{
ffStrbufAppendS(&host->name, "Windows Subsystem for Linux");
ffStrbufSetStatic(&host->name, "Windows Subsystem for Linux");
if (wslDistroName)
ffStrbufAppendF(&host->name, " - %s", wslDistroName);
ffStrbufAppendS(&host->family, "WSL");
ffStrbufSetStatic(&host->family, "WSL");
ffStrbufSetStatic(&host->vendor, "Microsoft Corporation");
if (instance.config.general.detectVersion)
{
@@ -92,6 +93,17 @@ const char* ffDetectHost(FFHostResult* host)
}); // supported in 2.2.3 and later
}
}
else if (ffStrbufStartsWithS(&instance.state.platform.sysinfo.version, "FreeBSD "))
{
ffStrbufSetStatic(&host->name, "Linux Binary Compatibility on FreeBSD");
ffStrbufSetStatic(&host->family, "FreeBSD");
ffStrbufSetStatic(&host->vendor, "FreeBSD Foundation");
if (instance.config.general.detectVersion)
{
ffStrbufSetS(&host->version, instance.state.platform.sysinfo.version.chars + strlen("FreeBSD "));
ffStrbufSubstrBeforeFirstC(&host->version, ' ');
}
}
}
return NULL;
+1 -1
View File
@@ -121,7 +121,7 @@ const char* ffHostGetMacProductNameWithHwModel(const FFstrbuf* hwModel)
ffStrEquals(version, "16,5")) return "MacBook Pro (16-inch, 2024, Three Thunderbolt 5 ports)";
if(ffStrEquals(version, "15,14")) return "Mac Studio (M3 Ultra, 2025)";
if(ffStrEquals(version, "15,13")) return "MacBook Air (15-inch, M3, 2024)";
if(ffStrEquals(version, "15,2")) return "MacBook Air (13-inch, M3, 2024)";
if(ffStrEquals(version, "15,12")) return "MacBook Air (13-inch, M3, 2024)";
if(ffStrEquals(version, "15,3")) return "MacBook Pro (14-inch, Nov 2023, Two Thunderbolt / USB 4 ports)";
if(ffStrEquals(version, "15,4")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports)";
if(ffStrEquals(version, "15,5")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports, Two USB 3 ports)";
+31 -3
View File
@@ -1,8 +1,10 @@
#include "fastfetch.h"
#include "detection/media/media.h"
#include "common/library.h"
#include "common/processing.h"
#include "util/apple/cf_helpers.h"
#include "util/apple/osascript.h"
#include "fastfetch_datatext.h"
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
@@ -13,7 +15,7 @@ extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribu
extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import));
void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
static const char* getMedia(FFMediaResult* result)
static const char* getMediaByMediaRemote(FFMediaResult* result)
{
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
@@ -79,8 +81,34 @@ static const char* getMedia(FFMediaResult* result)
return error;
}
static const char* getMediaByOsascript(FFMediaResult* result)
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
// The script must be executed by `/usr/bin/osascript`. `ffOsascript` doesn't work here
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
"/usr/bin/osascript",
"-e",
FASTFETCH_DATATEXT_NOWPLAYING,
nil
});
if (error) return error;
if (buffer.length == 0) return "No media found";
// status\ntitle\nartist\nalbum\nbundleName\nappName
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player };
char* line = NULL;
size_t len = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i)
ffStrbufSetS(varList[i], line);
return NULL;
}
void ffDetectMediaImpl(FFMediaResult* media)
{
const char* error = getMedia(media);
ffStrbufAppendS(&media->error, error);
const char* error;
if (@available(macOS 15.4, *))
error = getMediaByOsascript(media);
else
error = getMediaByMediaRemote(media);
if (error) ffStrbufAppendS(&media->error, error);
}
+1
View File
@@ -142,6 +142,7 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul
ffStrbufClear(&result->artist);
ffStrbufClear(&result->album);
ffStrbufClear(&result->url);
ffStrbufClear(&result->status);
return false;
}
}
+9 -4
View File
@@ -19,11 +19,16 @@ static const char* getMedia(FFMediaResult* media)
}
ffStrbufSetWS(&media->playerId, result.playerId);
ffStrbufSet(&media->player, &media->playerId);
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
if (result.playerName[0])
{
ffStrbufSetWS(&media->player, result.playerName);
}
else
ffStrbufSubstrAfterFirstC(&media->player, '!'); // UWP ID
{
ffStrbufSet(&media->player, &media->playerId);
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
}
ffStrbufSetWS(&media->song, result.song);
ffStrbufSetWS(&media->artist, result.artist);
ffStrbufSetWS(&media->album, result.album);
@@ -1,5 +1,6 @@
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Media.Control.h>
#include <winrt/Windows.ApplicationModel.h>
#include <wchar.h>
extern "C"
@@ -11,6 +12,7 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
// C++/WinRT requires Windows 8.1+ and C++ runtime (std::string, exceptions and other stuff)
// Make it a separate dll in order not to break Windows 7 support
using namespace winrt::Windows::Media::Control;
using namespace winrt::Windows::ApplicationModel;
try
{
@@ -48,6 +50,11 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
::wcsncpy(result->song, mediaProps.Title().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
::wcsncpy(result->artist, mediaProps.Artist().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
::wcsncpy(result->album, mediaProps.AlbumTitle().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
try
{
// Only works for UWP apps
::wcsncpy(result->playerName, AppInfo::GetFromAppUserModelId(session.SourceAppUserModelId()).DisplayInfo().DisplayName().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
} catch (...) { }
return NULL;
}
+1
View File
@@ -5,6 +5,7 @@
typedef struct FFWinrtMediaResult
{
wchar_t playerId[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t playerName[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t song[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t artist[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t album[FF_MEDIA_WIN_RESULT_BUFLEN];
+3 -2
View File
@@ -8,8 +8,9 @@ const char* ffDetectMemory(FFMemoryResult* ram)
if (get_system_info(&info) != B_OK)
return "Error getting system info";
ram->bytesTotal = B_PAGE_SIZE * info.max_pages;
ram->bytesUsed = B_PAGE_SIZE * info.used_pages;
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
ram->bytesTotal = pageSize * info.max_pages;
ram->bytesUsed = pageSize * info.used_pages;
return NULL;
}
+18 -33
View File
@@ -4,60 +4,46 @@
#include "common/netif/netif.h"
#include "util/stringUtils.h"
#include <fcntl.h>
#include <net/if.h>
static void getData(FFstrbuf* buffer, const char* ifName, bool isDefaultRoute, FFstrbuf* path, FFlist* result)
static void getData(FFstrbuf* buffer, const char* ifName, bool isDefaultRoute, int basefd, FFlist* result)
{
ffStrbufSetF(path, "/sys/class/net/%s/operstate", ifName);
if(!ffReadFileBuffer(path->chars, buffer) || !ffStrbufEqualS(buffer, "up\n"))
FF_AUTO_CLOSE_FD int dfd = openat(basefd, ifName, O_RDONLY | O_DIRECTORY);
if (dfd < 0)
return;
char operstate;
if(!ffReadFileDataRelative(dfd, "operstate", 1, &operstate) || operstate != 'u' /* up or unknown */)
return;
FFNetIOResult* counters = (FFNetIOResult*) ffListAdd(result);
ffStrbufInitS(&counters->name, ifName);
counters->defaultRoute = isDefaultRoute;
ffStrbufSetF(path, "/sys/class/net/%s/statistics/", ifName);
uint32_t statLen = path->length;
ffStrbufAppendS(path, "rx_bytes");
if (ffReadFileBuffer(path->chars, buffer))
if (ffReadFileBufferRelative(dfd, "statistics/rx_bytes", buffer))
counters->rxBytes = ffStrbufToUInt(buffer, 0);
ffStrbufSubstrBefore(path, statLen);
ffStrbufAppendS(path, "tx_bytes");
if (ffReadFileBuffer(path->chars, buffer))
if (ffReadFileBufferRelative(dfd, "statistics/tx_bytes", buffer))
counters->txBytes = ffStrbufToUInt(buffer, 0);
ffStrbufSubstrBefore(path, statLen);
ffStrbufAppendS(path, "rx_packets");
if (ffReadFileBuffer(path->chars, buffer))
if (ffReadFileBufferRelative(dfd, "statistics/rx_packets", buffer))
counters->rxPackets = ffStrbufToUInt(buffer, 0);
ffStrbufSubstrBefore(path, statLen);
ffStrbufAppendS(path, "tx_packets");
if (ffReadFileBuffer(path->chars, buffer))
if (ffReadFileBufferRelative(dfd, "statistics/tx_packets", buffer))
counters->txPackets = ffStrbufToUInt(buffer, 0);
ffStrbufSubstrBefore(path, statLen);
ffStrbufAppendS(path, "rx_errors");
if (ffReadFileBuffer(path->chars, buffer))
if (ffReadFileBufferRelative(dfd, "statistics/rx_errors", buffer))
counters->rxErrors = ffStrbufToUInt(buffer, 0);
ffStrbufSubstrBefore(path, statLen);
ffStrbufAppendS(path, "tx_errors");
if (ffReadFileBuffer(path->chars, buffer))
if (ffReadFileBufferRelative(dfd, "statistics/tx_errors", buffer))
counters->txErrors = ffStrbufToUInt(buffer, 0);
ffStrbufSubstrBefore(path, statLen);
ffStrbufAppendS(path, "rx_dropped");
if (ffReadFileBuffer(path->chars, buffer))
if (ffReadFileBufferRelative(dfd, "statistics/rx_dropped", buffer))
counters->rxDrops = ffStrbufToUInt(buffer, 0);
ffStrbufSubstrBefore(path, statLen);
ffStrbufAppendS(path, "tx_dropped");
if (ffReadFileBuffer(path->chars, buffer))
if (ffReadFileBufferRelative(dfd, "statistics/tx_dropped", buffer))
counters->txDrops = ffStrbufToUInt(buffer, 0);
ffStrbufSubstrBefore(path, statLen);
}
const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
@@ -65,7 +51,6 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/net");
if (!dirp) return "opendir(\"/sys/class/net\") == NULL";
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateA(64);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName();
@@ -75,7 +60,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
if (options->namePrefix.length && strncmp(defaultRouteIfName, options->namePrefix.chars, options->namePrefix.length) != 0)
return NULL;
getData(&buffer, defaultRouteIfName, true, &path, result);
getData(&buffer, defaultRouteIfName, true, dirfd(dirp), result);
}
else
{
@@ -89,7 +74,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
if (options->namePrefix.length && strncmp(ifName, options->namePrefix.chars, options->namePrefix.length) != 0)
continue;
getData(&buffer, ifName, ffStrEquals(ifName, defaultRouteIfName), &path, result);
getData(&buffer, ifName, ffStrEquals(ifName, defaultRouteIfName), dirfd(dirp), result);
}
}
+2
View File
@@ -37,6 +37,8 @@ static bool detectOSCodeName(FFOSResult* os)
switch (num)
{
case 26:
case 16: ffStrbufSetStatic(&os->codename, "Tahoe"); return true;
case 15: ffStrbufSetStatic(&os->codename, "Sequoia"); return true;
case 14: ffStrbufSetStatic(&os->codename, "Sonoma"); return true;
case 13: ffStrbufSetStatic(&os->codename, "Ventura"); return true;
+30 -1
View File
@@ -231,6 +231,24 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
ffStrbufSetF(&result->prettyName, "Proxmox VE %s", result->versionID.chars);
return true;
}
else if (ffStrbufContainS(&instance.state.platform.sysinfo.release, "+rpt-rpi-"))
{
// Raspberry Pi OS
ffStrbufSetS(&result->id, "raspbian");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetS(&result->name, "Raspberry Pi OS");
ffStrbufSetS(&result->prettyName, "Raspberry Pi OS");
return true;
}
else if (ffStrbufEndsWithS(&instance.state.platform.sysinfo.release, "+truenas"))
{
// TrueNAS Scale
ffStrbufSetS(&result->id, "truenas-scale");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetS(&result->name, "TrueNAS Scale");
ffStrbufSetS(&result->prettyName, "TrueNAS Scale");
return true;
}
else
{
// Hack for MX Linux. See #847
@@ -286,8 +304,19 @@ static void detectOS(FFOSResult* os)
parseOsRelease(FASTFETCH_TARGET_DIR_ETC "/os-release", os);
if (os->id.length == 0 || os->version.length == 0 || os->prettyName.length == 0 || os->codename.length == 0)
parseLsbRelease(FASTFETCH_TARGET_DIR_ETC "/lsb-release", os);
if (os->id.length == 0 || os->name.length > 0 || os->prettyName.length > 0)
if (os->id.length == 0 || os->name.length == 0 || os->prettyName.length == 0)
parseOsRelease(FASTFETCH_TARGET_DIR_USR "/lib/os-release", os);
if (os->id.length == 0 && os->name.length == 0 && os->prettyName.length == 0)
{
// HarmonyOS has no os-release file
if (ffStrbufEqualS(&instance.state.platform.sysinfo.name, "HarmonyOS"))
{
ffStrbufSetS(&os->id, "harmonyos");
ffStrbufSetS(&os->idLike, "harmonyos");
ffStrbufSetS(&os->name, "HarmonyOS");
ffStrbufSetS(&os->prettyName, "HarmonyOS");
}
}
}
void ffDetectOSImpl(FFOSResult* os)
+11 -10
View File
@@ -100,22 +100,23 @@ uint32_t ffPackagesGetNumElements(const char* dirname, bool isdir)
{
bool ok = false;
#if !defined(__sun) && !defined(__HAIKU__)
if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK)
ok = entry->d_type == (isdir ? DT_DIR : DT_REG);
else
#endif
if (entry->d_name[0] != '.')
{
struct stat stbuf;
if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0)
ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode);
#if !defined(__sun) && !defined(__HAIKU__)
if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK)
ok = entry->d_type == (isdir ? DT_DIR : DT_REG);
else
#endif
{
struct stat stbuf;
if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0)
ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode);
}
}
if(ok) ++num_elements;
}
if(isdir && num_elements >= 2)
num_elements -= 2; // accounting for . and ..
return num_elements;
}
+1
View File
@@ -40,6 +40,7 @@ typedef struct FFPackagesResult
uint32_t rpm;
uint32_t scoop;
uint32_t snap;
uint32_t soar;
uint32_t sorcery;
uint32_t winget;
uint32_t xbps;
+8 -1
View File
@@ -554,7 +554,11 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", true);
if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false);
if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false);
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages", "rpm");
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT))
{
// `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey` package
packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Sigmd5", "rpm");
}
if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir);
if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
@@ -682,4 +686,7 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT))
result->amUser = getAMUser();
if (!(options->disabled & FF_PACKAGES_FLAG_SOAR_BIT))
result->soar += getSQLite3Int(&baseDir, ".local/share/soar/db/soar.db", "SELECT COUNT(DISTINCT pkg_id || pkg_name) FROM packages WHERE is_installed = true", "soar");
}
+9
View File
@@ -0,0 +1,9 @@
#include "packages.h"
#include "common/io/io.h"
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
}
-5
View File
@@ -4,11 +4,6 @@
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
#if __OpenBSD__
if (!(options->disabled & FF_PACKAGES_FLAG_PKG_BIT))
result->pkg = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg", true);
#elif __NetBSD__
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
#endif
}
@@ -65,6 +65,7 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
ffStrbufInitMove(&device->serial, &identifier);
ffStrbufTrim(&device->serial, ' ');
ffStrbufInit(&device->revision);
ffStrbufInit(&device->interconnect);
switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK)
@@ -10,7 +10,7 @@
static const char* detectDisk(FFstrbuf* path, const char* diskType, FFlist* result)
{
FF_AUTO_CLOSE_FD int rawfd = open(path->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int rawfd = open(path->chars, O_RDONLY | O_CLOEXEC);
if (rawfd < 0) return "detectDisk: open(rawfd) failed";
device_geometry geometry;
@@ -78,10 +78,18 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
ffStrbufInitMove(&device->name, &name);
ffStrbufInitF(&device->devPath, "/dev/%s", devName);
bool isVirtual = false;
{
ffStrbufInit(&device->interconnect);
if (ffStrStartsWith(devName, "nvme"))
ffStrbufSetStatic(&device->interconnect, "NVMe");
else if (ffStrStartsWith(devName, "mmcblk"))
ffStrbufSetStatic(&device->interconnect, "MMC");
else if (ffStrStartsWith(devName, "md"))
{
ffStrbufSetStatic(&device->interconnect, "RAID");
isVirtual = true;
}
else
{
char pathSysDeviceLink[64];
@@ -97,6 +105,11 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
ffStrbufSetStatic(&device->interconnect, "SCSI");
else if (strstr(pathSysDeviceReal, "/nvme") != NULL)
ffStrbufSetStatic(&device->interconnect, "NVMe");
else if (strstr(pathSysDeviceReal, "/virtio") != NULL)
{
ffStrbufSetStatic(&device->interconnect, "Virtual");
isVirtual = true;
}
else
{
if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect))
@@ -106,6 +119,7 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
}
}
if (!isVirtual)
{
char isRotationalChar = '1';
if (ffReadFileDataRelative(dfd, "queue/rotational", 1, &isRotationalChar) > 0)
@@ -139,7 +153,7 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
{
ffStrbufInit(&device->serial);
if (ffReadFileBufferRelative(devfd, "serial", &device->serial))
ffStrbufTrimRightSpace(&device->serial);
ffStrbufTrim(&device->serial, ' ');
}
{
+3 -1
View File
@@ -94,7 +94,9 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
}, 0, NULL, &dataSize, &active) == kAudioHardwareNoError)
device->active = !!active;
if (!muted)
if (muted)
device->volume = 0;
else
{
float volume;
dataSize = sizeof(volume);
+1 -1
View File
@@ -32,7 +32,7 @@ const char* ffDetectSound(FFlist* devices)
for (int idev = 0; idev <= info.nummixers; ++idev)
{
path[strlen("/dev/mixer")] = (char) ('0' + idev);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) break;
if (idev == 0)
+1 -1
View File
@@ -25,7 +25,7 @@ const char* ffDetectSound(FFlist* devices)
for (int idev = 0; idev < 9; ++idev)
{
path[strlen("/dev/audio")] = (char) ('0' + idev);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR);
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) break;
audio_device_t ad;
+2 -1
View File
@@ -4,8 +4,9 @@
typedef struct FFSwapResult
{
FFstrbuf name;
uint64_t bytesUsed;
uint64_t bytesTotal;
} FFSwapResult;
const char* ffDetectSwap(FFSwapResult* swap);
const char* ffDetectSwap(FFlist* result /* List of FFSwapResult */);
+3 -1
View File
@@ -3,13 +3,15 @@
#include <mach/mach.h>
#include <sys/sysctl.h>
const char* ffDetectSwap(FFSwapResult* swap)
const char* ffDetectSwap(FFlist* result)
{
struct xsw_usage xsw;
size_t size = sizeof(xsw);
if(sysctl((int[]){ CTL_VM, VM_SWAPUSAGE }, 2, &xsw, &size, NULL, 0) != 0)
return "Failed to read vm.swapusage";
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitStatic(&swap->name, xsw.xsu_encrypted ? "Encrypted" : "Normal");
swap->bytesTotal = xsw.xsu_total;
swap->bytesUsed = xsw.xsu_used;
return NULL;
+48 -7
View File
@@ -2,15 +2,57 @@
#include "common/sysctl.h"
#include <vm/vm_param.h>
#include <sys/stat.h>
#include <sys/param.h>
const char* ffDetectSwap(FFSwapResult* swap)
static void addSwapEntry(FFlist* result, struct xswdev* xsw, uint32_t pageSize)
{
if (xsw->xsw_nblks == 0) // DFBSD reports some /dev/wdog devices with nblks == 0
return;
FFSwapResult* swap = ffListAdd(result);
if (xsw->xsw_dev == NODEV)
ffStrbufInitStatic(&swap->name, "[NFS]");
else
ffStrbufInitF(&swap->name, "/dev/%s", devname(xsw->xsw_dev, S_IFCHR));
swap->bytesUsed = (uint64_t) xsw->xsw_used * pageSize;
swap->bytesTotal = (uint64_t) xsw->xsw_nblks * pageSize;
}
#if __DragonFly__
const char* ffDetectSwap(FFlist* result)
{
struct xswdev xsws[32];
size_t size = sizeof(xsws);
if (sysctlbyname("vm.swap_info_array", xsws, &size, NULL, 0) < 0)
return "sysctlbyname(\"vm.swap_info_array\") failed";
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
size_t count = size / sizeof(struct xswdev);
if (count == 0)
return NULL;
if (xsws->xsw_version != XSWDEV_VERSION)
return "xswdev version mismatch";
for (uint32_t i = 0; i < count; ++i)
addSwapEntry(result, &xsws[i], pageSize);
return NULL;
}
#elif __FreeBSD__
const char* ffDetectSwap(FFlist* result)
{
int mib[16];
size_t mibsize = ARRAY_SIZE(mib);
if (sysctlnametomib("vm.swap_info", mib, &mibsize) < 0)
return "sysctlnametomib(\"vm.swap_info\") failed";
swap->bytesUsed = swap->bytesTotal = 0;
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
for (int n = 0; ; ++n)
{
@@ -21,12 +63,11 @@ const char* ffDetectSwap(FFSwapResult* swap)
break;
if (xsw.xsw_version != XSWDEV_VERSION)
return "xswdev version mismatch";
swap->bytesUsed += (uint64_t) xsw.xsw_used;
swap->bytesTotal += (uint64_t) xsw.xsw_nblks;
}
swap->bytesUsed *= instance.state.platform.sysinfo.pageSize;
swap->bytesTotal *= instance.state.platform.sysinfo.pageSize;
addSwapEntry(result, &xsw, pageSize);
}
return NULL;
}
#endif
+15 -3
View File
@@ -1,15 +1,27 @@
#include "swap.h"
#include <OS.h>
#include <driver_settings.h>
const char* ffDetectSwap(FFSwapResult* swap)
const char* ffDetectSwap(FFlist* result)
{
system_info info;
if (get_system_info(&info) != B_OK)
return "Error getting system info";
swap->bytesTotal = B_PAGE_SIZE * (uint64_t) info.max_swap_pages;
swap->bytesUsed = B_PAGE_SIZE * (uint64_t) (info.max_swap_pages - info.free_swap_pages);
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitStatic(&swap->name, "System");
void* kvms = load_driver_settings("virtual_memory"); // /boot/home/config/settings/kernel/drivers/virtual_memory
if (kvms)
{
const char* swapAuto = get_driver_parameter(kvms, "swap_auto", NULL, NULL);
if (swapAuto)
ffStrbufSetStatic(&swap->name, swapAuto[0] == 'y' ? "Auto" : "Manual");
unload_driver_settings(kvms);
}
swap->bytesTotal = pageSize * (uint64_t) info.max_swap_pages;
swap->bytesUsed = pageSize * (uint64_t) (info.max_swap_pages - info.free_swap_pages);
return NULL;
}
+53 -1
View File
@@ -5,8 +5,9 @@
#include <inttypes.h>
const char* ffDetectSwap(FFSwapResult* swap)
static const char* detectByProcMeminfo(FFlist* result)
{
// For Android
// Ref: #620
char buf[PROC_FILE_BUFFSIZ];
ssize_t nRead = ffReadFileData("/proc/meminfo", ARRAY_SIZE(buf) - 1, buf);
@@ -23,8 +24,59 @@ const char* ffDetectSwap(FFSwapResult* swap)
if ((token = strstr(buf, "SwapFree:")) != NULL)
swapFree = strtoul(token + strlen("SwapFree:"), NULL, 10);
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitStatic(&swap->name, "Total");
swap->bytesTotal = swapTotal * 1024lu;
swap->bytesUsed = (swapTotal - swapFree) * 1024lu;
return NULL;
}
static const char* detectByProcSwaps(FFlist* result)
{
// Ref: #620
char buf[PROC_FILE_BUFFSIZ];
ssize_t nRead = ffReadFileData("/proc/swaps", ARRAY_SIZE(buf) - 1, buf);
if(nRead <= 0)
return "ffReadFileData(\"/proc/swaps\", ARRAY_SIZE(buf)-1, buf) failed";
buf[nRead] = '\0';
// Skip header
char* line = memchr(buf, '\n', (size_t) nRead);
while(line && *++line)
{
uint64_t total, used;
char name[256];
if(sscanf(line, "%255s %*[^\t]%" SCNu64 "%" SCNu64, name, &total, &used) != 3)
return "Invalid /proc/swaps format found";
uint32_t nameLen = (uint32_t) strnlen(name, sizeof(name));
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitA(&swap->name, nameLen);
for (size_t i = 0; i < nameLen; ++i)
{
if(name[i] == '\\')
{
char octal[4] = { name[i + 1], name[i + 2], name[i + 3], '\0' };
ffStrbufAppendC(&swap->name, (char) strtol(octal, NULL, 8));
i += 3;
}
else
ffStrbufAppendC(&swap->name, name[i]);
}
swap->bytesTotal = total * 1024u;
swap->bytesUsed = used * 1024u;
line = memchr(line, '\n', (size_t) (nRead - (line - buf)));
}
return NULL;
}
const char* ffDetectSwap(FFlist* result)
{
if (detectByProcSwaps(result) == NULL)
return NULL;
return detectByProcMeminfo(result);
}
+6 -6
View File
@@ -1,4 +1,5 @@
#include "swap.h"
#include "util/FFlist.h"
#include "util/mallocHelper.h"
#include <sys/types.h>
@@ -6,7 +7,7 @@
#include <sys/param.h>
#include <unistd.h>
const char* ffDetectSwap(FFSwapResult* swap)
const char* ffDetectSwap(FFlist* result)
{
int nswap = swapctl(SWAP_NSWAP, 0, 0);
if (nswap < 0) return "swapctl(SWAP_NSWAP) failed";
@@ -17,17 +18,16 @@ const char* ffDetectSwap(FFSwapResult* swap)
if (swapctl(SWAP_STATS, swdev, nswap) < 0)
return "swapctl(SWAP_STATS) failed";
uint64_t swapTotal = 0, swapUsed = 0;
for (int i = 0; i < nswap; i++)
{
if (swdev[i].se_flags & SWF_ENABLE)
{
swapUsed += (uint64_t) swdev[i].se_inuse;
swapTotal += (uint64_t) swdev[i].se_nblks;
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitS(&swap->name, swdev[i].se_path);
swap->bytesUsed = (uint64_t) swdev[i].se_inuse * DEV_BSIZE;
swap->bytesTotal = (uint64_t) swdev[i].se_nblks * DEV_BSIZE;
}
}
swap->bytesUsed = swapUsed * DEV_BSIZE;
swap->bytesTotal = swapTotal * DEV_BSIZE;
return NULL;
}

Some files were not shown because too many files have changed in this diff Show More