Compare commits

..

199 Commits

Author SHA1 Message Date
Carter Li 02aafbd7f4 Merge pull request #1852 from fastfetch-cli/dev
Release: v2.48.1
2025-07-18 19:28:54 +08:00
Carter Li 72da8150bd Release: v2.48.1 2025-07-18 18:50:30 +08:00
Carter Li aca2b5336d WM (Linux): fix a copy-paste error 2025-07-18 18:04:00 +08:00
李通洲 c79b67efc1 Modules: don't report errors when condition key is set 2025-07-18 16:16:38 +08:00
李通洲 30af91ce8e Packages: add new option --packages-combined 2025-07-18 15:55:33 +08:00
李通洲 6c56348e54 JsonConfig: add modules[n].condition to run modules conditionally on different platforms 2025-07-18 15:45:25 +08:00
李通洲 531b25dc2f Version: replace WIN32 with Windows and Darwin with macOS 2025-07-18 15:08:40 +08:00
李通洲 8c6dc34654 Processing (*nix): fix compiling on Android 7 2025-07-18 13:27:17 +08:00
李通洲 cf2034b93e Processing (Windows): redirect unused std handles to NUL to avoid potential errors 2025-07-18 10:39:11 +08:00
李通洲 f7db03b8c4 Processing (*nix): use traditional fork-exec on Android and OpenBSD
Fix https://github.com/termux/termux-packages/issues/25369
2025-07-18 10:37:52 +08:00
Carter Li 8647e366f9 Packaging: update debian stuff [ci skip] 2025-07-17 16:27:07 +08:00
李通洲 1bf41d68f9 WM (Linux): add Openbox version detection 2025-07-17 14:15:35 +08:00
Carter Li 1ac1f1f889 Chore: silense compiler warnings 2025-07-16 15:19:48 +08:00
Carter Li 14f1278485 Release: v2.48.0 (#1848)
Co-authored-by: Dariqq <77271900+Dariqq@users.noreply.github.com>
Co-authored-by: Robert Nilson <109800336+ZBookCMD@users.noreply.github.com>
Co-authored-by: Juan Llamas <38849891+xoltia@users.noreply.github.com>
Co-authored-by: Angel Gustavo Lopez <143856402+Xray-OS@users.noreply.github.com>
2025-07-16 15:09:29 +08:00
李通洲 c2c6856159 Doc: optimize README; fix typo 2025-07-16 14:45:56 +08:00
李通洲 c89f3d2896 Release: v2.48.0 2025-07-16 14:33:22 +08:00
李通洲 8e773470df Logo: partially revert c5c0e54 2025-07-16 14:29:41 +08:00
李通洲 ea4fc7bdda Separator: remove formatArgs
It makes no sense.
2025-07-16 10:46:47 +08:00
李通洲 468d1e0903 Display: add option --fraction-ndigits
to control number of digits to print when formatting ordinary fraction numbers
2025-07-16 10:33:20 +08:00
李通洲 6851e7b082 Uptime / Users: add years, days-of-year and year-fraction
Like what `Disk` has
2025-07-16 09:53:09 +08:00
Carter Li a734f18fd5 Chore (Linux): silience compiler warnings 2025-07-15 23:33:26 +08:00
李通洲 30b1e29785 JsonSchema: update xxxFormat [ci skip] 2025-07-15 22:44:56 +08:00
李通洲 dde0c22195 Disk: add keys years, days-of-year and years-fraction
Fix #1847
2025-07-15 22:38:31 +08:00
Angel Gustavo Lopez 1311a809db Logo (Builtin): rename ada to xray_os (#1845)
* going back to xray_os

* going back to xray_os

---------

Co-authored-by: xray_os <xray_os>
2025-07-15 17:52:09 +08:00
李通洲 60a54f4880 CMake: reconfigure after adding / removing logos 2025-07-15 11:02:31 +08:00
李通洲 b4e65e7e48 README: document how to run multiple modules on command line [ci skip] 2025-07-15 10:48:37 +08:00
李通洲 6f3ed4a7b4 Processing (Linux): cache the index of $LANG 2025-07-15 10:22:56 +08:00
李通洲 cc8f8ff0f7 README: add DeepWiki badge [ci skip]
An interesting website
2025-07-15 08:51:15 +08:00
李通洲 8a00f2d901 GPU (Windows): fix compiling on x86-32 2025-07-15 00:04:43 +08:00
李通洲 c5c0e543e4 Logo: don't print builtin logo if the provided logo source cannot be found 2025-07-13 20:32:31 +08:00
李通洲 97255f37da Logo: load .raw files as raw image file 2025-07-13 20:32:31 +08:00
李通洲 fb8a04f97a Logo: don't load text files as image file
Fix #1843
2025-07-13 20:32:13 +08:00
李通洲 c3ce5ac947 Logo: don't parse file paths as builtin logo name 2025-07-13 20:15:10 +08:00
李通洲 eae69049b2 GPU (Windows): more method to detect device name 2025-07-13 01:39:38 +08:00
李通洲 102e8fcc72 GPU (Windows): detect GPU frequency by default
Supported on Windows 11 only
2025-07-13 01:16:46 +08:00
李通洲 8372708f98 GPU (Intel): prefer matching GPU with bus id 2025-07-13 01:16:46 +08:00
Juan Llamas 5011edc9d9 Packages (Linux): clean up nix user package detection 2025-07-12 23:57:51 +08:00
Juan Llamas 94a5228ffc Packages (Linux): add /etc/profiles/per-user detection for nix user packages 2025-07-12 23:57:51 +08:00
李通洲 382c0cd7c3 GPU (Windows): ignore invalid temps 2025-07-12 15:16:36 +08:00
李通洲 ab496b23b7 GPU (Windows): greatly improve performance of GPU temp detection
... when `--gpu-driver-specific` is not set. Supported on Windows 10 and later
2025-07-12 01:26:33 +08:00
李通洲 939f428da7 Logo (Builtin): add AxOS
Fix #1841
2025-07-11 14:01:30 +08:00
Robert Nilson 2d496c91e1 Logo (Builtin): add the Minimal System logo (#1837)
* Added logo of Minimal System

* Changed to spaces instead of tabs

* Removed paddings for minimal.txt

* Changed

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

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-07-10 03:31:49 -05:00
李通洲 442d58b646 Revert "GPU (macOS): update how integrated GPUs are detected"
This reverts commit 5381395c54.
2025-07-10 16:16:45 +08:00
李通洲 4d377b94b7 CI (Haiku): Apply work-around for work directory
From <cross-platform-actions/action#104 (comment)>
2025-07-10 14:40:25 +08:00
李通洲 7248868e33 Sound (macOS): improve device id detection 2025-07-10 10:42:23 +08:00
Carter Li 2eda6464ad Processing (Linux): use posix_spawnp for better performance 2025-07-09 23:56:02 +08:00
Carter Li 2622fc12a6 Chore (Linux): silence compiler warnings 2025-07-09 20:23:28 +08:00
李通洲 b178e43428 GPU (Windows): use nvapi to detect GPU type 2025-07-09 00:28:16 +08:00
李通洲 d00fca26c5 GPU (Windows): clean up 2025-07-09 00:08:13 +08:00
李通洲 23e4d1c4aa Chore (Windows): tidy 2025-07-07 22:34:23 +08:00
李通洲 6871c8bb73 GPU (Windows): fix Win7 compatibility 2025-07-07 22:34:04 +08:00
李通洲 61adc7cf64 GPU (Windows): new method to detect device type 2025-07-07 22:03:30 +08:00
李通洲 9ba30adcba GPU (Windows): add driver version fall back 2025-07-06 18:23:14 +08:00
李通洲 010b2c6262 CMake (Windows): remove setupapi dependency 2025-07-06 17:48:39 +08:00
李通洲 c65fb1a868 Battery (Windows): use CMAPI instead of SetupAPI 2025-07-06 17:04:51 +08:00
李通洲 2029679ea5 GPU (Windows): use CMAPI instead of SetupAPI
Improve performance
2025-07-06 17:04:31 +08:00
Carter Li 817f70c2cd Presets: add a new example
Fix #1832
2025-07-05 08:33:55 +08:00
Carter Li 3a1f0485f4 PhysicalDisk: unifying white space trimming 2025-07-05 08:31:21 +08:00
李通洲 64910d0781 OS (Linux): detect fedora variants
Fix #1830
2025-07-04 10:31:59 +08:00
Dariqq 821462e152 Chore: Add a missing semicolon (#1828)
Followup to a9f021ccb9
2025-07-03 20:16:14 -05:00
Carter Li b015fd579c Packaging: update debian stuff [ci skip] 2025-07-03 14:53:14 +08:00
Carter Li 8b40a81e22 Merge pull request #1826 from fastfetch-cli/dev
Release: v2.47.0
2025-07-03 14:05:23 +08:00
李通洲 8be64714ba OS (Linux): remove duplicated code 2025-07-03 11:03:14 +08:00
李通洲 fe5d739cba Doc: update README [ci skip] 2025-07-03 10:51:42 +08:00
李通洲 dba0672a11 CMake: remove the unused option ENABLE_CPUUSAGE_PERFLIB 2025-07-03 10:47:44 +08:00
李通洲 3ed6acf3ca Release: v2.47.0 2025-07-03 10:45:41 +08:00
李通洲 8c74c54bb0 README 2025-07-03 10:27:44 +08:00
Carter Li 818473102c Logo (Builtin): always use FG_DEFAULT on title and keys 2025-07-03 09:39:32 +08:00
Carter Li f1cc4a7805 Logo (Builtin): fix colors of raw Linux logo 2025-07-03 09:36:39 +08:00
Carter Li c574af97a4 Logo (Builtin): fix colors of DragonFly 2025-07-03 09:33:04 +08:00
Carter Li 74ae84e719 Revert "Logo (Builtin): :%s/FG_WHITE/FG_DEFAULT/g"
This reverts commit bdbc885811.
2025-07-03 09:03:23 +08:00
李通洲 98738b6920 CPUUsage (Windows): detect perflib support dynamically based on OS version 2025-07-02 19:40:22 +08:00
李通洲 2e5769def2 OS (Linux): add support of Xubuntu
Fix #1825
2025-07-02 09:41:07 +08:00
李通洲 18a6929662 CPUUsage (Windows): disable ENABLE_CPUUSAGE_PERFLIB by default
Because Windows 7 doesn't support it
2025-07-01 22:08:08 +08:00
李通洲 0e61d1134d CMake: fix typo 2025-07-01 21:05:37 +08:00
李通洲 4abb183735 CPUUsage(Windows): add new method using Windows Performance Library 2025-07-01 20:53:46 +08:00
李通洲 d5b56be4ff CMake (SunOS): drop pciaccess dependency 2025-07-01 20:32:45 +08:00
李通洲 1854953d8c Chore (Windows): move perflib_.h to somewhere global 2025-07-01 14:57:40 +08:00
李通洲 2406015c81 Terminal (Linux): ignore init and systemd 2025-06-30 19:41:59 +08:00
李通洲 ec7f14ab96 CpuUsage (Windows): refine KernelTime calculation by removing unused DPC and interrupt time 2025-06-30 19:37:04 +08:00
李通洲 d94cdf4424 CpuUsage (Linux / BSD): include interrupt and softirq times in CPU usage calculations 2025-06-30 19:36:46 +08:00
李通洲 40e57b7698 IO: increase PROC_FILE_BUFFSIZ to avoid possible short reads 2025-06-30 19:16:08 +08:00
李通洲 974c658fff README: add the OpenBSD and DragonFly installation method [ci skip]
Fix https://github.com/fastfetch-cli/fastfetch/issues/1819#issuecomment-3015070008
2025-06-28 23:39:01 +08:00
李通洲 ad0ddfd7f1 Media (macOS): support old macOS version 2025-06-27 16:00:27 +08:00
李通洲 1da8367f55 Media (macOS): simplify now playing handling
Also improve performance
2025-06-27 14:28:45 +08:00
李通洲 bdbc885811 Logo (Builtin): :%s/FG_WHITE/FG_DEFAULT/g
To improve visibility on white background
2025-06-26 22:36:15 +08:00
李通洲 86e5a5997b Display (FreeBSD): silence a compiler warning 2025-06-26 21:44:06 +08:00
李通洲 9832a0e45b GPU (FreeBSD): fix compiling when libdrm is not available
Fix #1820
2025-06-26 21:34:34 +08:00
李通洲 addf674621 OS (Linux): append version string for Ubuntu variants 2025-06-26 21:31:16 +08:00
李通洲 863c5583ef GPU (OpenBSD): fix pci.ids file location
Fix #1819

Signed-off-by: kevlo <kevlo@openbsd.org>
2025-06-25 13:45:49 +08:00
李通洲 45cbc6de83 OS (macOS): force reporting 26 on macOS Tahoe
Fix #1809
2025-06-25 09:19:08 +08:00
李通洲 e68f766b4d OS (Linux): improve RPIOS detection
Ref: https://github.com/fastfetch-cli/fastfetch/issues/1816#issuecomment-2996316164
2025-06-23 22:10:50 +08:00
李通洲 29d7a1acac OS (Linux): use ffStrbufSetStatic where applicatable 2025-06-23 19:41:57 +08:00
李通洲 8d59d14b80 OS (Linux): clean up dietpi related code 2025-06-23 19:41:31 +08:00
Carter Li ed1883909a OS (Linux): detect DietPi
Fix #1816
2025-06-23 18:30:04 +08:00
李通洲 049701a8a9 CI (FreeBSD): run with 14.3 2025-06-23 16:13:40 +08:00
Carter Li 13b7bc89eb Sound (SunOS): rework; drop pulseaudio dependency 2025-06-22 20:35:29 +08:00
Carter Li 92fe44183d Shell (SunOS): ignore leading - 2025-06-22 12:12:49 +08:00
Carter Li 8ebc980c17 GPU (SunOS): simplify 2025-06-22 11:20:19 +08:00
Carter Li dbeb338bda PhysicalDisk (SunOS): rework; support more device types 2025-06-22 11:14:29 +08:00
Carter Li 65ff11a8d0 PhysicalDisk (SunOS): add support 2025-06-22 01:16:50 +08:00
Carter Li 7a73211484 Logo (Builtin): use FG_DEFAULT instead of FG_WHITE 2025-06-21 23:51:40 +08:00
Carter Li ca049997b1 GPU (SunOS): rework GPU detection 2025-06-21 23:22:37 +08:00
李通洲 a9f021ccb9 Chore: remove useless semicolons 2025-06-21 20:46:51 +08:00
Carter Li 55249c2294 BIOS (SunOS): detect BIOS type 2025-06-21 20:46:51 +08:00
李通洲 c13da56959 OS (macOS): remove useless code 2025-06-20 19:28:03 +08:00
Carter Li 665c7cd5d3 Packaging: update debian stuff [ci skip] 2025-06-20 15:02:23 +08:00
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
207 changed files with 5574 additions and 1415 deletions
+158 -9
View File
@@ -383,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
@@ -408,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
@@ -426,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
@@ -452,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:
@@ -505,7 +552,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '14.2'
version: '14.3'
run: |
uname -a
sudo pkg update
@@ -542,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
@@ -597,6 +644,106 @@ 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
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: Fixup VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
version: 'r1beta5'
architecture: x86-64
cpu_count: 4
shell: bash
sync_files: false
shutdown_vm: false
run: |
mv '/home/runner/work' '/boot/home/work'
ln -sf '/boot/home/work' '/home/runner/work'
- name: Sync files to VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
version: 'r1beta5'
architecture: x86-64
cpu_count: 4
shell: bash
sync_files: runner-to-vm
shutdown_vm: false
run: |
chown -R $(id -u):$(id -g) $(pwd)
ls -l
- name: run VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
version: 'r1beta5'
architecture: x86-64
cpu_count: 4
shell: bash
sync_files: vm-to-runner
run: |
uname -a
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
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
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
@@ -734,11 +881,13 @@ jobs:
- linux-ppc64le
- linux-s390x
- musl-amd64
- macos-universal
- macos-amd64
- macos-aarch64
- freebsd-amd64
- openbsd-amd64
- netbsd-amd64
- sunos-amd64
- haiku-amd64
- windows-amd64
- windows-aarch64
permissions:
+151
View File
@@ -1,3 +1,154 @@
# 2.48.1
Features:
* Add support for detecting Openbox WM version (WM, Linux)
* Improve reliability of child process spawning on Windows (Windows)
* Add a new option `--packages-combined`, which combines related package managers into single counts (#1851, Packages)
* For example: if you have both `flatpak-system` and `flatpak-user` packages installed, they will be combined into a single `flatpak` count with `--packages-combined` enabled.
* Add `modules[n].condition` to conditionally enable modules on different platforms
* Useful when sharing configuration files across platforms
* For example:
```jsonc
{
"type": "custom",
"format": "This string will be printed on Intel macOS only",
"condition": {
"system": "macOS", // Can be an array, optional
"arch": "x86_64" // Can be an array, optional too
}
}
```
Bugfixes:
* Revert the change of `posix_spawn` in v2.48.0 for Android and OpenBSD (Android / OpenBSD)
* Fix completion for Android 7 (Required by Termux)
# 2.48.0
Features:
* Add support for detecting Fedora variants (#1830, OS, Linux)
* Currently supported variants: CoreOS, Kinoite, Sericea, Silverblue
* Optimize GPU detection on Windows when `--gpu-driver-specific` is not used (GPU, Windows)
* Improve accuracy of GPU type detection. Previously it was guessed based on the dedicated vmem size, which causes issues on newer AMD integrated GPUs such as 9000 HX and AI 9 HX series. Supported on Windows 8.1 or later.
* Add support for generic frequency detection of GPU 3D engine on Windows 11 22H2 or later.
* Improve performance. GPU temperature detection is significantly improved when `--gpu-driver-specific` is not used.
* Improve performance and security when spawning child processes by replacing `fork-exec` with `posix_spawn` (*nix)
* Improve accuracy of sound device detection on macOS (Sound, macOS)
* Trim leading and trailing whitespaces in disk serial numbers (PhysicalDisk)
* Add `/etc/profiles/per-user` detection for Nix user packages (#1782, Packages, Linux)
* Introduce `years` (whole years as integer), `days-of-year` (days since the last anniversary) and `years-fraction` (years as fraction, e.g. 1.5 means 1 year and 6 months) formatting placeholder to `Disk` (since disk creation), `Users` (since user login) and `Uptime` (since system boot) modules
* For example: `fastfetch -s disk --disk-key 'OS Installation' --disk-format '{years} years {days-of-year} days'`
* Add `--fraction-ndigits` option to specify the number of digits after the decimal point when displaying ordinary fractional values
* Typically used with `{years-fraction}` above
* This option does not affect percentage values, sizes, etc, which are controlled by individual options.
Bugfixes:
* Fix compilation issues when not using `-DBINARY_LINK_TYPE=dlopen`
* Regression from v2.47.0
* Note: this option was added for debugging purposes only and is not recommended for production use
* Replace `MTLDevice::hasUnifiedMemory` with `MTLDevice::location` for GPU type Detection (GPU, macOS)
* This should resolve the issue where discrete GPUs were detected as integrated GPUs on Intel MacBooks with multi-GPU configurations.
* Prevent text files from being loaded as image files (#1843, Logo)
Logos:
* Add Minimal System
* Add AxOS
* Rename Ada to Xray OS
# 2.47.0
Features:
* Various improvements for Solaris / OpenIndiana support
* Support BIOS (UEFI or legacy) type detection (BIOS)
* Support physical disk detection (PhysicalDisk)
* Remove leading `-` from login shells (Shell)
* Improve GPU detection performance (GPU)
* Drop `libpciaccess` dependency
* Use native API to detect sound devices (Sound)
* Drop `PulseAudio` dependency
* Improve DietPi OS and Raspberry Pi OS detection (#1816, OS, Linux)
* Force reporting version 26 on macOS Tahoe (OS, macOS)
* Append version string to Ubuntu variants (OS, Linux)
* Improve performance of media detection for macOS 15.4+ (Media, macOS)
* Increase `PROC_FILE_BUFFSIZ` to avoid possible short reads (Linux)
* Fix potential bugs in `DiskIO`, `NetIO` and `CPUUsage` modules
* Improve accuracy of CPU usage calculations by including interrupt and softirq times (CPUUsage, Linux / *BSD)
* Ignore `init` and `systemd` processes when detecting terminals (Terminal, Linux)
* Improve accuracy of CPU usage detection on Windows 10+ with perflib, which matches values reported by Task Manager (CPUUsage, Windows)
Bugfixes:
* Fix `pci.ids` file location (#1819, GPU, OpenBSD)
* Fix compiling on FreeBSD when `libdrm` support is disabled (#1820, GPU, FreeBSD)
Logos:
* Improve visibility on white-background terminals for some logos by replacing white with the default foreground color
* According to Wikipedia, the default foreground color is implementation-defined. It's usually black for white themes and white for dark themes. However, some terminals, notably Konsole with the default theme, use a different color, which may cause issues with some logos.
* Add Xubuntu
# 2.46.0
Features:
* Support Rio terminal font detection (#1789, TerminalFont, Linux)
* Support GPU detection by DRM on FreeBSD (GPU, FreeBSD)
* Enable by `--gpu-detection-method auto`
* Require proper DRM drivers installed and loaded
* Support PowerPC CPU detection on NetBSD (#1802, CPU, NetBSD)
* Support Aerospace WM detection (#1796, WM, macOS)
* Improve Raspberry Pi OS for RPI5 detection (#1773, OS, Linux)
* Support Linux Binary Compatibility detection on FreeBSD (#1786, Host, Linux)
* Use `board-id` as board name if available (Board, macOS)
* Intel only
* Support shared VRAM usage detection for AMD GPUs (GPU, Linux)
* Use `perflib.h` instead of `pdh.h` for CPU temperature querying to get rid of `pdh.dll` dependency (#1787, CPU, Windows)
* Support GPU info detection for old ATI radeon driver (#1810, GPU, Linux)
* Add macOS 26 Tahoe support (macOS)
* Report macOS 26 code name (OS)
* Report Liquid Glass DE on macOS 26+ (DE)
* Detect Metal 4 support (GPU)
Bugfixes:
* Fix packages counting by ignoring hidden folders (Packages, OpenBSD)
* Fix Hyprland version detection (WM, FreeBSD)
* Don't show `Please insert a disk into drive D:` error dialogs (#1805, Disk, Windows)
* Hide `/boot/firmware` by default (Disk, Linux)
Logos:
* Rename Hydra Framework to HydraPwk (#1812)
* Add AnushOS (#1806)
* Add HarmonyOS (#1804)
* Add GhostFreak (#1801)
* Add TrueNAS Scale (#1795)
* Add Fedora2_small (#1785)
* Add xenia_old; update colors of xenia (#1797)
* Improve colors of bedrock_small (#1790)
* Add Kalpa Desktop (#1807)
# 2.45.0
Features:
* Support OnePlus marketing name detection (#1768, Host, Android)
* Recognize additional GPU vendors (GPU, Linux)
* Support CTWM, FVWM and I3 window manager version detection (WM)
* Support KDE version detection on *BSD (DE, FreeBSD)
* Support `"logo": { "type": "command-raw" }` to run a command and display its output as logo (#1780, Logo)
* Useful for displaying custom logos generated by other programs such as `pokeget`: `{ "type": "command-raw", "source": "pokeget random --hide-name" }`
* Supported in JSONC config file only. `pokeget random --hide-name | fastfetch --file-raw -` should be used in shell.
* Acquire SMBIOS information on DragonFly BSD from `/dev/mem`; legacy BIOS only (PhysicalMemory, DragonFly)
* Support swap usage detection on DragonFly BSD (Swap, DragonFly)
* Support `--swap-separate` to display detailed swap devices on separate lines (Swap)
Bugfixes
* Fix MacBook Air model name (#1779, Host, macOS)
* Don't ignore sshfs mountpoints (#1776, Disk, Linux / FreeBSD)
* Fix dnf package count detection (#1777, Packages, Linux)
Logos:
* Add Starry Linux (#1771)
* Add rhel_small (#1774)
* Update color palette of voidlinux (#1775)
* Add void2
* Update Xenia Linux (#1783)
# 2.44.0
Features:
+32 -31
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.44.0
VERSION 2.48.1
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -61,7 +61,7 @@ cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeB
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD" OFF)
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" OFF)
@@ -76,13 +76,13 @@ cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD O
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS" OFF)
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku" OFF)
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR SunOS" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku" OFF)
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
cmake_dependent_option(ENABLE_LIBZFS "Enable libzfs" ON "LINUX OR FreeBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD" OFF)
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
@@ -326,11 +326,6 @@ 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)
@@ -341,7 +336,7 @@ endif()
# Ascii image data #
####################
file(GLOB LOGO_FILES "src/logo/ascii/*.txt")
file(GLOB LOGO_FILES CONFIGURE_DEPENDS "src/logo/ascii/*.txt")
set(LOGO_BUILTIN_H "#pragma once\n#pragma GCC diagnostic ignored \"-Wtrigraphs\"\n\n")
foreach(file ${LOGO_FILES})
fastfetch_load_text("${file}" content)
@@ -529,6 +524,7 @@ if(LINUX)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_linux.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_linux.c
@@ -676,6 +672,7 @@ elseif(FreeBSD)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_bsd.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_bsd.c
@@ -787,7 +784,7 @@ elseif(NetBSD)
src/detection/netio/netio_bsd.c
src/detection/opengl/opengl_linux.c
src/detection/os/os_nbsd.c
src/detection/packages/packages_obsd.c
src/detection/packages/packages_nbsd.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_nbsd.c
src/detection/gtk_qt/qt.c
@@ -802,7 +799,7 @@ elseif(NetBSD)
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nbsd.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
@@ -884,7 +881,7 @@ elseif(OpenBSD)
src/detection/users/users_obsd.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_obsd.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
@@ -1060,7 +1057,7 @@ elseif(SunOS)
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/disk/disk_sunos.c
src/detection/dns/dns_linux.c
src/detection/physicaldisk/physicaldisk_nosupport.c
src/detection/physicaldisk/physicaldisk_sunos.c
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_sunos.c
src/detection/displayserver/linux/displayserver_linux.c
@@ -1100,7 +1097,7 @@ elseif(SunOS)
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_linux.c
src/detection/gtk_qt/qt.c
src/detection/sound/sound_linux.c
src/detection/sound/sound_sunos.c
src/detection/swap/swap_sunos.c
src/detection/terminalfont/terminalfont_linux.c
src/detection/terminalshell/terminalshell_linux.c
@@ -1585,7 +1582,6 @@ elseif(WIN32)
PRIVATE "ws2_32"
PRIVATE "ntdll"
PRIVATE "version"
PRIVATE "setupapi"
PRIVATE "hid"
PRIVATE "wtsapi32"
PRIVATE "imagehlp"
@@ -1593,7 +1589,6 @@ elseif(WIN32)
PRIVATE "winbrand"
PRIVATE "propsys"
PRIVATE "secur32"
PRIVATE "pdh"
)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
# WoA only works on Windows 10 or higher
@@ -1636,6 +1631,7 @@ elseif(SunOS)
PRIVATE "proc"
PRIVATE "zfs"
PRIVATE "nvpair"
PRIVATE "devinfo"
)
elseif(ANDROID)
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
@@ -1925,17 +1921,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)
@@ -1961,12 +1957,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)
+7 -7
View File
@@ -10,6 +10,7 @@
[![GitHub release (with filter)](https://img.shields.io/github/v/release/fastfetch-cli/fastfetch?logo=github)](https://github.com/fastfetch-cli/fastfetch/releases)
[![latest packaged version(s)](https://repology.org/badge/latest-versions/fastfetch.svg)](https://repology.org/project/fastfetch/versions)
[![Packaging status](https://repology.org/badge/tiny-repos/fastfetch.svg)](https://repology.org/project/fastfetch/versions)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/fastfetch-cli/fastfetch)
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and SunOS.
@@ -69,13 +70,12 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
You may also download the program directly from [the GitHub releases page](https://github.com/fastfetch-cli/fastfetch/releases/latest) in the form of an archive file.
### FreeBSD
### BSD systems
* `pkg install fastfetch`
### NetBSD
* `pkgin in fastfetch`
* FreeBSD: `pkg install fastfetch`
* NetBSD: `pkgin in fastfetch`
* OpenBSD: `pkg_add fastfetch` (Snapshots only)
* DragonFly BSD: `pkg install fastfetch` (Snapshots only)
### Android (Termux)
@@ -93,7 +93,7 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
* Run with default configuration: `fastfetch`
* Run with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) to find what interests you: `fastfetch -c all.jsonc`
* View all data that fastfetch detects: `fastfetch -s <module> --format json`
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
* Display help messages: `fastfetch --help`
* Generate a config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
+30
View File
@@ -1,3 +1,33 @@
fastfetch (2.48.0) jammy; urgency=medium
* Update to 2.48.0
-- Carter Li <zhangsongcui@live.cn> Thu, 17 Jul 2025 16:16:52 +0800
fastfetch (2.47.0) jammy; urgency=medium
* Update to 2.47.0
-- Carter Li <zhangsongcui@live.cn> Thu, 03 Jul 2025 14:51:45 +0800
fastfetch (2.46.0) jammy; urgency=medium
* Update to 2.46.0
-- Carter Li <zhangsongcui@live.cn> Fri, 20 Jun 2025 15:01:21 +0800
fastfetch (2.45.0) jammy; urgency=medium
* Update to 2.45.0
-- Carter Li <zhangsongcui@live.cn> Thu, 05 Jun 2025 10:56:38 +0800
fastfetch (2.44.0) jammy; urgency=medium
* Update to 2.44.0
-- Carter Li <zhangsongcui@live.cn> Mon, 26 May 2025 14:59:01 +0800
fastfetch (2.43.0) jammy; urgency=medium
* Update to 2.43.0
+1 -1
View File
@@ -1 +1 @@
fastfetch_2.43.0_source.buildinfo universe/utils optional
fastfetch_2.48.0_source.buildinfo universe/utils optional
+434 -10
View File
@@ -108,6 +108,128 @@
}
]
},
"systems": {
"type": "string",
"enum": [
"Android",
"Linux",
"DragonFly",
"MidnightBSD",
"FreeBSD",
"macOS",
"Windows",
"SunOS",
"OpenBSD",
"NetBSD",
"Haiku"
]
},
"architectures": {
"type": "string",
"enum": [
"x86_64",
"i386",
"ia64",
"aarch64",
"arm",
"mips",
"powerpc",
"riscv",
"s390x",
"loongarch",
"sparc",
"alpha",
"hppa",
"m68k"
]
},
"conditions": {
"description": "Only show the module if conditions are met",
"type": "object",
"additionalProperties": false,
"properties": {
"system": {
"description": "System name to match",
"type": "string",
"oneOf": [
{
"$ref": "#/$defs/systems"
},
{
"type": "array",
"items": {
"$ref": "#/$defs/systems"
},
"description": "Array of system names to match"
},
{
"type": "null",
"description": "Null to disable this condition"
}
]
},
"!system": {
"description": "System name to not match",
"type": "string",
"oneOf": [
{
"$ref": "#/$defs/systems"
},
{
"type": "array",
"items": {
"$ref": "#/$defs/systems"
},
"description": "Array of system names to not match"
},
{
"type": "null",
"description": "Null to disable this condition"
}
]
},
"arch": {
"description": "Architecture to match",
"type": "string",
"oneOf": [
{
"$ref": "#/$defs/architectures"
},
{
"type": "array",
"items": {
"$ref": "#/$defs/architectures"
},
"description": "Array of architectures to match"
},
{
"type": "null",
"description": "Null to disable this condition"
}
]
},
"!arch": {
"description": "Architecture to not match",
"type": "string",
"oneOf": [
{
"$ref": "#/$defs/architectures"
},
{
"type": "array",
"items": {
"$ref": "#/$defs/architectures"
},
"description": "Array of architectures to not match"
},
{
"type": "null",
"description": "Null to disable this condition"
}
]
}
}
},
"batteryFormat": {
@@ -115,7 +237,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": {
@@ -183,7 +305,7 @@
"type": "string"
},
"diskFormat": {
"description": "Output format of the module `Disk`. See Wiki for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter\n 21. {mount-from}: Mount from (device path)",
"description": "Output format of the module `Disk`. See Wiki for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter\n 21. {mount-from}: Mount from (device path)\n 22. {years}: Years integer after creation\n 23. {days-of-year}: Days of year after creation\n 24. {years-fraction}: Years fraction after creation",
"type": "string"
},
"diskioFormat": {
@@ -306,10 +428,6 @@
"description": "Output format of the module `PublicIp`. See Wiki for formatting syntax\n 1. {ip}: Public IP address\n 2. {location}: Location",
"type": "string"
},
"separatorFormat": {
"description": "Output format of the module `Separator`. See Wiki for formatting syntax\n 1. {string}: Separator string\n 2. {outputColor}: Output color\n 3. {length}: Length",
"type": "string"
},
"shellFormat": {
"description": "Output format of the module `Shell`. See Wiki for formatting syntax\n 1. {process-name}: Shell process name\n 2. {exe}: The first argument of the command line when running the shell\n 3. {exe-name}: Shell base name of arg0\n 4. {version}: Shell version\n 5. {pid}: Shell pid\n 6. {pretty-name}: Shell pretty name\n 7. {exe-path}: Shell full exe path\n 8. {tty}: Shell tty used",
"type": "string"
@@ -319,7 +437,7 @@
"type": "string"
},
"swapFormat": {
"description": "Output format of the module `Swap`. See Wiki for formatting syntax\n 1. {used}: Used size\n 2. {total}: Total size\n 3. {percentage}: Percentage used (num)\n 4. {percentage-bar}: Percentage used (bar)",
"description": "Output format of the module `Swap`. See Wiki for formatting syntax\n 1. {used}: Used size\n 2. {total}: Total size\n 3. {percentage}: Percentage used (num)\n 4. {percentage-bar}: Percentage used (bar)\n 5. {name}: Name",
"type": "string"
},
"terminalFormat": {
@@ -339,7 +457,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": {
@@ -351,11 +469,11 @@
"type": "string"
},
"uptimeFormat": {
"description": "Output format of the module `Uptime`. See Wiki for formatting syntax\n 1. {days}: Days\n 2. {hours}: Hours\n 3. {minutes}: Minutes\n 4. {seconds}: Seconds\n 5. {milliseconds}: Milliseconds\n 6. {boot-time}: Boot time in local timezone",
"description": "Output format of the module `Uptime`. See Wiki for formatting syntax\n 1. {days}: Days after boot\n 2. {hours}: Hours after boot\n 3. {minutes}: Minutes after boot\n 4. {seconds}: Seconds after boot\n 5. {milliseconds}: Milliseconds after boot\n 6. {boot-time}: Boot time in local timezone\n 7. {years}: Years integer after boot\n 8. {days-of-year}: Days of year after boot\n 9. {years-fraction}: Years fraction after boot",
"type": "string"
},
"usersFormat": {
"description": "Output format of the module `Users`. See Wiki for formatting syntax\n 1. {name}: User name\n 2. {host-name}: Host name\n 3. {session}: Session name\n 4. {client-ip}: Client IP\n 5. {login-time}: Login Time in local timezone\n 6. {days}: Days after login\n 7. {hours}: Hours after login\n 8. {minutes}: Minutes after login\n 9. {seconds}: Seconds after login\n 10. {milliseconds}: Milliseconds after login",
"description": "Output format of the module `Users`. See Wiki for formatting syntax\n 1. {name}: User name\n 2. {host-name}: Host name\n 3. {session}: Session name\n 4. {client-ip}: Client IP\n 5. {login-time}: Login Time in local timezone\n 6. {days}: Days after login\n 7. {hours}: Hours after login\n 8. {minutes}: Minutes after login\n 9. {seconds}: Seconds after login\n 10. {milliseconds}: Milliseconds after login\n 11. {years}: Years integer after login\n 12. {days-of-year}: Days of year after login\n 13. {years-fraction}: Years fraction after login",
"type": "string"
},
"versionFormat": {
@@ -429,6 +547,7 @@
"file-raw",
"data",
"data-raw",
"command-raw",
"sixel",
"kitty",
"kitty-direct",
@@ -933,6 +1052,28 @@
}
}
},
"fraction": {
"type": "object",
"additionalProperties": false,
"description": "Set how ordinary fraction numbers should be displayed",
"properties": {
"ndigits": {
"oneOf": [
{
"type": "number",
"description": "Set the number of digits to keep after the decimal point when formatting ordinary fraction numbers",
"minimum": 0,
"maximum": 9
},
{
"type": "null",
"description": "The number of digits will be automatically determined based on the value"
}
],
"default": null
}
}
},
"noBuffer": {
"type": "boolean",
"description": "Whether to disable the stdout application buffer",
@@ -986,6 +1127,7 @@
"host",
"icons",
"initsystem",
"keyboard",
"kernel",
"lm",
"loadavg",
@@ -994,6 +1136,7 @@
"media",
"memory",
"monitor",
"mouse",
"netio",
"opencl",
"opengl",
@@ -1048,6 +1191,9 @@
"type": {
"const": "break",
"description": "Print a empty line"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1088,6 +1234,9 @@
},
"format": {
"$ref": "#/$defs/batteryFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1117,6 +1266,9 @@
},
"format": {
"$ref": "#/$defs/biosFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1154,6 +1306,9 @@
},
"format": {
"$ref": "#/$defs/bluetoothFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1183,6 +1338,9 @@
},
"format": {
"$ref": "#/$defs/bluetoothradioFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1212,6 +1370,9 @@
},
"format": {
"$ref": "#/$defs/boardFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1241,6 +1402,9 @@
},
"format": {
"$ref": "#/$defs/bootmgrFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1285,6 +1449,9 @@
},
"format": {
"$ref": "#/$defs/brightnessFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1317,6 +1484,9 @@
},
"format": {
"$ref": "#/$defs/btrfsFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1346,6 +1516,9 @@
},
"format": {
"$ref": "#/$defs/cameraFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1375,6 +1548,9 @@
},
"format": {
"$ref": "#/$defs/chassisFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1412,6 +1588,9 @@
},
"format": {
"$ref": "#/$defs/cpuFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1444,6 +1623,9 @@
},
"format": {
"$ref": "#/$defs/cpucacheFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1487,6 +1669,9 @@
},
"format": {
"$ref": "#/$defs/cpuusageFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1548,6 +1733,9 @@
},
"keyIcon": {
"$ref": "#/$defs/keyIcon"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1589,6 +1777,9 @@
},
"format": {
"$ref": "#/$defs/commandFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1621,6 +1812,9 @@
},
"format": {
"$ref": "#/$defs/cursorFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1652,6 +1846,9 @@
"format": {
"description": "Text to print",
"type": "string"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1684,6 +1881,9 @@
},
"format": {
"$ref": "#/$defs/datetimeFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1738,6 +1938,9 @@
},
"format": {
"$ref": "#/$defs/displayFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1812,6 +2015,9 @@
},
"format": {
"$ref": "#/$defs/diskFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1856,6 +2062,9 @@
},
"format": {
"$ref": "#/$defs/diskioFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1890,6 +2099,9 @@
},
"format": {
"$ref": "#/$defs/deFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1928,6 +2140,9 @@
},
"format": {
"$ref": "#/$defs/dnsFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1960,6 +2175,9 @@
},
"format": {
"$ref": "#/$defs/editorFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -1992,6 +2210,9 @@
},
"format": {
"$ref": "#/$defs/fontFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2024,6 +2245,9 @@
},
"format": {
"$ref": "#/$defs/gamepadFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2083,6 +2307,9 @@
},
"format": {
"$ref": "#/$defs/gpuFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2112,6 +2339,9 @@
},
"format": {
"$ref": "#/$defs/hostFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2141,6 +2371,9 @@
},
"format": {
"$ref": "#/$defs/iconsFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2170,6 +2403,9 @@
},
"format": {
"$ref": "#/$defs/initsystemFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2199,6 +2435,38 @@
},
"format": {
"$ref": "#/$defs/kernelFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
{
"title": "Keyboard",
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"const": "keyboard",
"description": "List (connected) keyboards"
},
"key": {
"$ref": "#/$defs/key"
},
"keyColor": {
"$ref": "#/$defs/keyColor"
},
"keyIcon": {
"$ref": "#/$defs/keyIcon"
},
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"format": {
"$ref": "#/$defs/memoryFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2228,6 +2496,9 @@
},
"format": {
"$ref": "#/$defs/lmFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2316,6 +2587,9 @@
},
"format": {
"$ref": "#/$defs/localipFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2360,6 +2634,9 @@
},
"format": {
"$ref": "#/$defs/loadavgFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2389,6 +2666,9 @@
},
"format": {
"$ref": "#/$defs/localeFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2418,6 +2698,9 @@
},
"format": {
"$ref": "#/$defs/mediaFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2450,6 +2733,38 @@
},
"format": {
"$ref": "#/$defs/memoryFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
{
"title": "Mouse",
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"const": "mouse",
"description": "List connected mouses"
},
"key": {
"$ref": "#/$defs/key"
},
"keyColor": {
"$ref": "#/$defs/keyColor"
},
"keyIcon": {
"$ref": "#/$defs/keyIcon"
},
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"format": {
"$ref": "#/$defs/memoryFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2479,6 +2794,9 @@
},
"format": {
"$ref": "#/$defs/monitorFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2528,6 +2846,9 @@
},
"format": {
"$ref": "#/$defs/netioFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2557,6 +2878,9 @@
},
"format": {
"$ref": "#/$defs/openclFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2595,6 +2919,9 @@
},
"format": {
"$ref": "#/$defs/openglFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2624,6 +2951,9 @@
},
"format": {
"$ref": "#/$defs/osFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2677,6 +3007,11 @@
},
"default": ["winget"]
},
"combined": {
"description": "Whether to combine related package managers into single counts (e.g., nix-system + nix-user = nix)",
"type": "boolean",
"default": false
},
"key": {
"$ref": "#/$defs/key"
},
@@ -2694,6 +3029,9 @@
},
"format": {
"$ref": "#/$defs/packagesFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2730,6 +3068,9 @@
},
"format": {
"$ref": "#/$defs/physicaldiskFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2759,6 +3100,9 @@
},
"format": {
"$ref": "#/$defs/physicalmemoryFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2788,6 +3132,9 @@
},
"format": {
"$ref": "#/$defs/playerFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2817,6 +3164,9 @@
},
"format": {
"$ref": "#/$defs/poweradapterFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2846,6 +3196,9 @@
},
"format": {
"$ref": "#/$defs/processesFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2892,6 +3245,9 @@
},
"format": {
"$ref": "#/$defs/publicipFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2918,6 +3274,9 @@
"type": "integer",
"minimum": 0,
"default": 0
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2947,6 +3306,9 @@
},
"format": {
"$ref": "#/$defs/shellFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -2989,6 +3351,9 @@
},
"format": {
"$ref": "#/$defs/soundFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3001,6 +3366,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"
},
@@ -3021,6 +3391,9 @@
},
"format": {
"$ref": "#/$defs/swapFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3050,6 +3423,9 @@
},
"format": {
"$ref": "#/$defs/terminalFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3079,6 +3455,9 @@
},
"format": {
"$ref": "#/$defs/terminalfontFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3108,6 +3487,9 @@
},
"format": {
"$ref": "#/$defs/terminalsizeFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3137,6 +3519,9 @@
},
"format": {
"$ref": "#/$defs/terminalthemeFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3166,6 +3551,9 @@
},
"format": {
"$ref": "#/$defs/themeFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3219,6 +3607,9 @@
},
"format": {
"$ref": "#/$defs/titleFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3248,6 +3639,9 @@
},
"format": {
"$ref": "#/$defs/tpmFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3287,6 +3681,9 @@
},
"format": {
"$ref": "#/$defs/usersFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3316,6 +3713,9 @@
},
"format": {
"$ref": "#/$defs/uptimeFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3345,6 +3745,9 @@
},
"format": {
"$ref": "#/$defs/versionFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3374,6 +3777,9 @@
},
"format": {
"$ref": "#/$defs/vulkanFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3403,6 +3809,9 @@
},
"format": {
"$ref": "#/$defs/wallpaperFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3447,6 +3856,9 @@
},
"format": {
"$ref": "#/$defs/weatherFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3476,6 +3888,9 @@
},
"format": {
"$ref": "#/$defs/wifiFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3510,6 +3925,9 @@
},
"format": {
"$ref": "#/$defs/wmFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3539,6 +3957,9 @@
},
"format": {
"$ref": "#/$defs/wmthemeFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
@@ -3571,6 +3992,9 @@
},
"format": {
"$ref": "#/$defs/zpoolFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
}
+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",
+14 -1
View File
@@ -217,10 +217,23 @@
"key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}"
},
{
"condition": {
"!system": "macOS"
},
"type": "disk",
"keyIcon": "",
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
"folders": "/", // On macOS, "/System/Volumes/VM" works for me
"folders": "/",
"format": "{create-time:10} [{days} days]"
},
{
"condition": {
"system": "macOS"
},
"type": "disk",
"keyIcon": "",
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
"folders": "/System/Volumes/VM",
"format": "{create-time:10} [{days} days]"
},
{
+49
View File
@@ -0,0 +1,49 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "small",
"padding": {
"top": 1
}
},
"display": {
"separator": " "
},
"modules": [
"break",
"title",
{
"type": "os",
"key": "os ",
"keyColor": "red"
},
{
"type": "kernel",
"key": "kernel",
"keyColor": "green"
},
{
"type": "host",
"format": "{vendor} {family}",
"key": "host ",
"keyColor": "yellow"
},
{
"type": "packages",
"key": "pkgs ",
"keyColor": "blue"
},
{
"type": "uptime",
"format": "{?days}{days}d {?}{hours}h {minutes}m",
"key": "uptime",
"keyColor": "magenta"
},
{
"type": "memory",
"key": "memory",
"keyColor": "cyan"
},
"break"
]
}
+4 -1
View File
@@ -16,7 +16,10 @@
"format": "{release}"
},
"uptime",
"packages",
{
"type": "packages",
"combined": true
},
"shell",
{
"type": "display",
+9 -2
View File
@@ -32,10 +32,16 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_FLOAT:
ffStrbufAppendF(buffer, "%f", *(float*)formatarg->value);
if (instance.config.display.fractionNdigits >= 0)
ffStrbufAppendF(buffer, "%.*f", instance.config.display.fractionNdigits, *(float*)formatarg->value);
else
ffStrbufAppendF(buffer, "%g", *(float*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_DOUBLE:
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
if (instance.config.display.fractionNdigits >= 0)
ffStrbufAppendF(buffer, "%.*f", instance.config.display.fractionNdigits, *(double*)formatarg->value);
else
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_BOOL:
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
@@ -108,6 +114,7 @@ static inline bool formatArgSet(const FFformatarg* arg)
{
return arg->value != NULL && (
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) || //Also is false for NaN
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) || //Also is false for NaN
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
+1
View File
@@ -105,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
+3 -2
View File
@@ -19,8 +19,7 @@
#define FF_INVALID_FD (-1)
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
// one safe way to read correct data is reading the whole file in a single read syscall
// 8192 comes from procps-ng: https://gitlab.com/procps-ng/procps/-/blob/master/library/meminfo.c?ref_type=heads#L39
#define PROC_FILE_BUFFSIZ 8192
#define PROC_FILE_BUFFSIZ (32 * 1024)
#endif
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
@@ -223,6 +222,8 @@ static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char*
return false;
}
FFNativeFD ffGetNullFD(void);
#ifdef _WIN32
// Only O_RDONLY is supported
HANDLE openat(HANDLE dfd, const char* fileName, bool directory);
+10 -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;
@@ -358,3 +358,12 @@ void ffListFilesRecursively(const char* path, bool pretty)
ffStrbufEnsureEndsWithC(&folder, '/');
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
}
FFNativeFD ffGetNullFD(void)
{
static FFNativeFD hNullFile = -1;
if (hNullFile != -1)
return hNullFile;
hNullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
return hNullFile;
}
+21 -2
View File
@@ -175,7 +175,7 @@ bool ffSuppressIO(bool suppress)
static bool init = false;
static HANDLE hOrigOut = INVALID_HANDLE_VALUE;
static HANDLE hOrigErr = INVALID_HANDLE_VALUE;
static HANDLE hNullFile = INVALID_HANDLE_VALUE;
HANDLE hNullFile = ffGetNullFD();
static int fOrigOut = -1;
static int fOrigErr = -1;
static int fNullFile = -1;
@@ -187,7 +187,6 @@ bool ffSuppressIO(bool suppress)
hOrigOut = GetStdHandle(STD_OUTPUT_HANDLE);
hOrigErr = GetStdHandle(STD_ERROR_HANDLE);
hNullFile = CreateFileW(L"NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
fOrigOut = _dup(STDOUT_FILENO);
fOrigErr = _dup(STDERR_FILENO);
fNullFile = _open_osfhandle((intptr_t) hNullFile, 0);
@@ -352,3 +351,23 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
return NULL;
}
FFNativeFD ffGetNullFD(void)
{
static FFNativeFD hNullFile = INVALID_HANDLE_VALUE;
if (hNullFile != INVALID_HANDLE_VALUE)
return hNullFile;
hNullFile = CreateFileW(
L"NUL",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
0,
&(SECURITY_ATTRIBUTES){
.nLength = sizeof(SECURITY_ATTRIBUTES),
.lpSecurityDescriptor = NULL,
.bInheritHandle = TRUE,
});
return hNullFile;
}
+43
View File
@@ -4,6 +4,7 @@
#include "common/printing.h"
#include "common/io/io.h"
#include "common/time.h"
#include "detection/version/version.h"
#include "modules/modules.h"
#include "util/stringUtils.h"
@@ -170,6 +171,25 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
}
}
static bool matchesJsonArray(const char* str, yyjson_val* val)
{
assert(val);
if (unsafe_yyjson_is_str(val))
return ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(val));
if (!unsafe_yyjson_is_arr(val)) return false;
size_t idx, max;
yyjson_val* item;
yyjson_arr_foreach(val, idx, max, item)
{
if (yyjson_is_str(item) && ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(item)))
return true;
}
return false;
}
static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
{
yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc);
@@ -197,6 +217,29 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
module = NULL;
else if (yyjson_is_obj(module))
{
yyjson_val* conditions = yyjson_obj_get(module, "condition");
if (conditions)
{
if (!yyjson_is_obj(conditions))
return "Property 'conditions' must be an object";
yyjson_val* system = yyjson_obj_get(conditions, "system");
if (system && !matchesJsonArray(ffVersionResult.sysName, system))
continue;
system = yyjson_obj_get(conditions, "!system");
if (system && matchesJsonArray(ffVersionResult.sysName, system))
continue;
yyjson_val* arch = yyjson_obj_get(conditions, "arch");
if (arch && !matchesJsonArray(ffVersionResult.architecture, arch))
continue;
arch = yyjson_obj_get(conditions, "!arch");
if (arch && matchesJsonArray(ffVersionResult.architecture, arch))
continue;
}
type = yyjson_get_str(yyjson_obj_get(module, "type"));
if (!type) return "module object must contain a \"type\" key ( case sensitive )";
if (yyjson_obj_size(module) == 1) // contains only Property type
+1 -1
View File
@@ -74,7 +74,7 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...);
FF_MAYBE_UNUSED void* libraryObjectName = NULL; // Placeholder
#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
symbolMapping = (__typeof__(&symbolName)) &symbolName
symbolMapping = (__typeof__(&symbolName)) &symbolName;
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
FF_MAYBE_UNUSED __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
+1 -1
View File
@@ -7,7 +7,7 @@
#include "util/debug.h"
#include <unistd.h>
#include <sys/poll.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
+106 -14
View File
@@ -12,6 +12,10 @@
#include <errno.h>
#include <sys/wait.h>
#if !(__ANDROID__ || __OpenBSD__)
#include <spawn.h>
#endif
#if defined(__FreeBSD__) || defined(__APPLE__)
#include <sys/types.h>
#include <sys/user.h>
@@ -33,6 +37,10 @@
#include <image.h>
#endif
#ifndef environ
extern char** environ;
#endif
enum { FF_PIPE_BUFSIZ = 8192 };
static inline int ffPipe2(int* fds, int flags)
@@ -48,6 +56,8 @@ static inline int ffPipe2(int* fds, int flags)
#endif
}
// Not thread-safe
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
{
int pipes[2];
@@ -56,7 +66,77 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if(ffPipe2(pipes, O_CLOEXEC) == -1)
return "pipe() failed";
pid_t childPid = fork();
pid_t childPid = -1;
int nullFile = ffGetNullFD();
#if !(__ANDROID__ || __OpenBSD__)
// NetBSD / Darwin: native syscall
// Linux (glibc): clone3-execve
// FreeBSD: vfork-execve
// illumos: vforkx-execve
// OpenBSD / Android (bionic): fork-execve
posix_spawn_file_actions_t file_actions;
posix_spawn_file_actions_init(&file_actions);
posix_spawn_file_actions_adddup2(&file_actions, pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
posix_spawn_file_actions_adddup2(&file_actions, nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
static char* oldLang = NULL;
static int langIndex = -1;
if (langIndex >= 0)
{
// Found before
if (oldLang) // oldLang was set only if it needed to be changed
{
if (environ[langIndex] != oldLang)
{
// environ is changed outside of this function
langIndex = -1;
}
else
environ[langIndex] = (char*) "LANG=C.UTF-8";
}
}
if (langIndex < 0)
{
for (int i = 0; environ[i] != NULL; i++)
{
if (ffStrStartsWith(environ[i], "LANG="))
{
langIndex = i;
const char* langValue = environ[i] + 5; // Skip "LANG="
if (ffStrEqualsIgnCase(langValue, "C") ||
ffStrStartsWithIgnCase(environ[i], "C.") ||
ffStrEqualsIgnCase(langValue, "en_US") ||
ffStrStartsWithIgnCase(langValue, "en_US."))
break; // No need to change LANG
oldLang = environ[i];
environ[i] = (char*) "LANG=C.UTF-8"; // Set LANG to C.UTF-8 for consistent output
break;
}
}
}
int ret = posix_spawnp(&childPid, argv[0], &file_actions, NULL, argv, environ);
if (oldLang)
environ[langIndex] = oldLang;
posix_spawn_file_actions_destroy(&file_actions);
if (ret != 0)
{
close(pipes[0]);
close(pipes[1]);
return "posix_spawnp() failed";
}
#else
// https://github.com/termux/termux-packages/issues/25369
childPid = fork();
if(childPid == -1)
{
close(pipes[0]);
@@ -64,18 +144,18 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
return "fork() failed";
}
//Child
if(childPid == 0)
{
int nullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
//Child
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
setenv("LANG", "C", 1);
putenv("LANG=C.UTF-8");
execvp(argv[0], argv);
_exit(127);
}
//Parent
#endif
close(pipes[1]);
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
@@ -86,20 +166,30 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if (timeout >= 0)
{
struct pollfd pollfd = { childPipeFd, POLLIN, 0 };
if (poll(&pollfd, 1, timeout) == 0)
int pollret = poll(&pollfd, 1, timeout);
if (pollret == 0)
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
}
else if (errno == EINTR)
else if (pollret < 0)
{
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
if (waitpid(childPid, NULL, WNOHANG) == childPid)
if (errno == EINTR)
{
// Read remaining data from the pipe
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
childPid = -1;
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
if (waitpid(childPid, NULL, WNOHANG) == childPid)
{
// Read remaining data from the pipe
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
childPid = -1;
}
}
else
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) error";
}
}
else if (pollfd.revents & POLLERR)
@@ -279,8 +369,10 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
psinfo_t proc;
if (ffReadFileData(filePath, sizeof(proc), &proc) == sizeof(proc))
{
ffStrbufSetS(exe, proc.pr_psargs);
ffStrbufSubstrBeforeFirstC(exe, ' ');
const char* args = proc.pr_psargs;
if (args[0] == '-') ++args;
const char* end = strchr(args, ' ');
ffStrbufSetNS(exe, end ? (uint32_t) (end - args) : (uint32_t) strlen(args), args);
}
if (exePath)
+7 -1
View File
@@ -81,7 +81,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if (hChildPipeWrite == INVALID_HANDLE_VALUE)
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
PROCESS_INFORMATION piProcInfo = {0};
PROCESS_INFORMATION piProcInfo = {};
BOOL success;
@@ -91,9 +91,15 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
.dwFlags = STARTF_USESTDHANDLES,
};
if (useStdErr)
{
siStartInfo.hStdOutput = ffGetNullFD();
siStartInfo.hStdError = hChildPipeWrite;
}
else
{
siStartInfo.hStdOutput = hChildPipeWrite;
siStartInfo.hStdError = ffGetNullFD();
}
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
argvToCmdline(argv, &cmdline);
+44
View File
@@ -97,3 +97,47 @@ static inline const char* ffTimeToTimeStr(uint64_t msec)
#ifdef _WIN32
#pragma GCC diagnostic pop
#endif
typedef struct FFTimeGetAgeResult
{
uint32_t years;
uint32_t daysOfYear;
double yearsFraction;
} FFTimeGetAgeResult;
static inline FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs)
{
FFTimeGetAgeResult result = {};
if (__builtin_expect(birthMs == 0 || nowMs < birthMs, 0))
return result;
time_t birth_s = (time_t) (birthMs / 1000);
struct tm birth_tm;
#ifdef _WIN32
localtime_s(&birth_tm, &birth_s);
#else
localtime_r(&birth_s, &birth_tm);
#endif
time_t now_s = (time_t) (nowMs / 1000);
struct tm now_tm;
#ifdef _WIN32
localtime_s(&now_tm, &now_s);
#else
localtime_r(&now_s, &now_tm);
#endif
result.years = (uint32_t) (now_tm.tm_year - birth_tm.tm_year);
if (now_tm.tm_yday < birth_tm.tm_yday)
result.years--;
birth_tm.tm_year += (int) result.years;
birth_s = mktime(&birth_tm);
uint32_t diff_s = (uint32_t) (now_s - birth_s);
result.daysOfYear = diff_s / (24 * 60 * 60);
birth_tm.tm_year += 1;
result.yearsFraction = (double) diff_s / (double) (mktime(&birth_tm) - birth_s) + result.years;
return result;
}
+21 -2
View File
@@ -719,6 +719,15 @@
"default": 2
}
},
{
"long": "fraction-ndigits",
"desc": "Set the number of digits to keep after the decimal point when printing ordinary fraction numbers",
"remark": "If negative, the number of digits will be automatically determined based on the value",
"arg": {
"type": "num",
"default": -1
}
},
{
"long": "temp-unit",
"desc": "Set the temperature unit",
@@ -981,6 +990,16 @@
"default": "winget"
}
},
{
"long": "packages-combined",
"desc": "Whether to combine related package managers into single counts",
"remark": "e.g., nix-system + nix-user = nix",
"arg": {
"type": "bool",
"optional": true,
"default": false
}
},
{
"long": "display-compact-type",
"desc": "Specify whether all displays should be printed in one line",
@@ -1144,11 +1163,11 @@
"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"
}
-24
View File
@@ -1,24 +0,0 @@
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 = {};
+19 -28
View File
@@ -8,40 +8,31 @@
#undef WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <setupapi.h>
#include <batclass.h>
#include <devguid.h>
#include <cfgmgr32.h>
#include <winternl.h>
static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results)
{
if(*hdev)
SetupDiDestroyDeviceInfoList(*hdev);
}
//https://learn.microsoft.com/en-us/windows-hardware/drivers/install/using-device-interfaces
ULONG cchDeviceInterfaces = 0;
CONFIGRET cr = CM_Get_Device_Interface_List_SizeW(&cchDeviceInterfaces, (LPGUID)&GUID_DEVCLASS_BATTERY, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS)
return "CM_Get_Device_Interface_List_SizeW() failed";
static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results)
{
//https://learn.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices
HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) =
SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(hdev == INVALID_HANDLE_VALUE)
return "SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY) failed";
if (cchDeviceInterfaces <= 1)
return NULL; // Not found
SP_DEVICE_INTERFACE_DATA did = { .cbSize = sizeof(did) };
for(DWORD idev = 0; SetupDiEnumDeviceInterfaces(hdev, NULL, &GUID_DEVCLASS_BATTERY, idev, &did); idev++)
wchar_t* FF_AUTO_FREE mszDeviceInterfaces = (wchar_t*)malloc(cchDeviceInterfaces * sizeof(wchar_t));
cr = CM_Get_Device_Interface_ListW((LPGUID)&GUID_DEVCLASS_BATTERY, NULL, mszDeviceInterfaces, cchDeviceInterfaces, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS)
return "CM_Get_Device_Interface_ListW() failed";
for (const wchar_t* pDeviceInterface = mszDeviceInterfaces; *pDeviceInterface; pDeviceInterface += wcslen(pDeviceInterface) + 1)
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetailW(hdev, &did, NULL, 0, &cbRequired, NULL); //Fail with not enough buffer
SP_DEVICE_INTERFACE_DETAIL_DATA_W* FF_AUTO_FREE pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)malloc(cbRequired);
if(!pdidd)
break; //Out of memory
pdidd->cbSize = sizeof(*pdidd);
if(!SetupDiGetDeviceInterfaceDetailW(hdev, &did, pdidd, cbRequired, &cbRequired, NULL))
continue;
HANDLE FF_AUTO_CLOSE_FD hBattery =
CreateFileW(pdidd->DevicePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
CreateFileW(pDeviceInterface, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hBattery == INVALID_HANDLE_VALUE)
continue;
@@ -99,7 +90,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
bqi.InformationLevel = BatteryManufactureDate;
BATTERY_MANUFACTURE_DATE date;
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL))
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day);
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year < 1000 ? date.Year + 1900 : date.Year, date.Month, date.Day);
}
{
@@ -131,7 +122,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
{
BATTERY_STATUS bs;
BATTERY_WAIT_STATUS bws = { .BatteryTag = bqi.BatteryTag };
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY)
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY && bi.FullChargedCapacity != 0)
battery->capacity = bs.Capacity * 100.0 / bi.FullChargedCapacity;
else
battery->capacity = 0;
@@ -271,6 +262,6 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
{
return options->useSetupApi
? detectWithSetupApi(options, results)
? detectWithCmApi(options, results)
: detectWithNtApi(options, results);
}
+16
View File
@@ -32,6 +32,10 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
#include <fcntl.h>
#include <unistd.h>
#elif __sun
#include <libdevinfo.h>
#include <sys/sunddi.h>
#endif
typedef struct FFSmbiosBios
@@ -59,6 +63,7 @@ typedef struct FFSmbiosBios
static_assert(offsetof(FFSmbiosBios, ExtendedBiosRomSize) == 0x18,
"FFSmbiosBios: Wrong struct alignment");
const char* ffDetectBios(FFBiosResult* bios)
{
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
@@ -94,6 +99,17 @@ const char* ffDetectBios(FFBiosResult* bios)
default: break;
}
}
#elif __sun
di_node_t rootNode = di_init("/", DINFOPROP);
if (rootNode != DI_NODE_NIL)
{
char* efiVersion = NULL;
if (di_prop_lookup_strings(DDI_DEV_T_ANY, rootNode, "efi-version", &efiVersion) > 0)
ffStrbufSetStatic(&bios->type, "UEFI");
else
ffStrbufSetStatic(&bios->type, "BIOS");
}
di_fini(rootNode);
#elif __HAIKU__ || __OpenBSD__
// Currently SMBIOS detection is supported in legancy BIOS only
ffStrbufSetStatic(&bios->type, "BIOS");
+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')
+1 -1
View File
@@ -20,7 +20,7 @@ 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)
{
if (errno == ENOENT)
+1 -1
View File
@@ -474,7 +474,7 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
static const char* detectPhysicalCores(FFCPUResult* cpu)
{
int dfd = open("/sys/devices/system/cpu/", O_RDONLY | O_DIRECTORY);
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);
+4 -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");
}
+98 -24
View File
@@ -4,42 +4,116 @@
#include "util/mallocHelper.h"
#include "util/smbiosHelper.h"
#include <pdh.h>
#include <windows.h>
#include "util/windows/perflib_.h"
#include <wchar.h>
static void ffPdhOpenCloseQuery(HQUERY* query)
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery)
{
assert(query);
if (*query)
if (*phQuery != NULL)
{
PdhCloseQuery(*query);
*query = NULL;
PerfCloseQueryHandle(*phQuery);
*phQuery = NULL;
}
}
static const char* detectThermalTemp(double* result)
const char* detectThermalTemp(double* result)
{
// typeperf.exe -sc 1 "\Thermal Zone Information(*)\Temperature"
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
};
__attribute__((__cleanup__(ffPdhOpenCloseQuery))) HQUERY query = NULL;
DWORD dataSize = 0;
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
return "PerfEnumerateCounterSetInstances() failed";
if (PdhOpenQueryW(NULL, 0, &query) != ERROR_SUCCESS)
return "Failed to open PDH query";
if (dataSize <= sizeof(PERF_INSTANCE_HEADER))
return "No `Thermal Zone Information` instances found";
HCOUNTER counter = NULL;
if (PdhAddEnglishCounterW(query,
L"\\Thermal Zone Information(*)\\Temperature",
0,
&counter) != ERROR_SUCCESS)
return "Failed to add TZI temperature counter";
{
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";
if (PdhCollectQueryData(query) != ERROR_SUCCESS)
return "Failed to collect query data";
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;
PDH_FMT_COUNTERVALUE value;
if (PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, NULL, &value) != ERROR_SUCCESS)
return "Failed to format counter value";
dataSize -= pInstanceHeader->Size;
if (dataSize == 0)
break;
pInstanceHeader = (PERF_INSTANCE_HEADER*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
}
*result = value.doubleValue - 273;
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;
}
@@ -151,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;
+9
View File
@@ -5,12 +5,14 @@
#include <stdint.h>
static FFlist cpuTimes1;
static uint64_t startTime;
void ffPrepareCPUUsage(void)
{
assert(cpuTimes1.elementSize == 0);
ffListInit(&cpuTimes1, sizeof(FFCpuUsageInfo));
ffGetCpuUsageInfo(&cpuTimes1);
startTime = ffTimeGetNow();
}
const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
@@ -23,6 +25,12 @@ const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
if(error) return error;
ffTimeSleep(options->waitTime);
}
else
{
uint64_t elapsedTime = ffTimeGetNow() - startTime;
if (elapsedTime < options->waitTime)
ffTimeSleep(options->waitTime - (uint32_t)elapsedTime);
}
if(cpuTimes1.length == 0) return "No CPU cores found";
@@ -57,5 +65,6 @@ retry:
cpuTime1->inUseAll = cpuTime2->inUseAll;
cpuTime1->totalAll = cpuTime2->totalAll;
}
startTime = ffTimeGetNow();
return NULL;
}
+2 -2
View File
@@ -42,8 +42,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
for (uint32_t i = 0; i < coreCount; ++i)
{
uint64_t* cpTime = cpTimes[i];
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS];
uint64_t total = inUse + cpTime[CP_INTR] + cpTime[CP_IDLE];
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS] + cpTime[CP_INTR];
uint64_t total = inUse + cpTime[CP_IDLE];
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
*info = (FFCpuUsageInfo) {
+2 -2
View File
@@ -31,8 +31,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
{
if(sscanf(start, "cpu%*d%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%*[^\n]\n", &user, &nice, &system, &idle, &iowait, &irq, &softirq) == 7)
{
uint64_t inUse = user + nice + system;
uint64_t total = inUse + idle + iowait + irq + softirq;
uint64_t inUse = user + nice + system + irq + softirq;
uint64_t total = inUse + idle + iowait;
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
*info = (FFCpuUsageInfo) {
+139 -5
View File
@@ -5,8 +5,11 @@
#include <ntstatus.h>
#include <winternl.h>
#include <windows.h>
#include <wchar.h>
#include "util/windows/perflib_.h"
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
static const char* getInfoByNqsi(FFlist* cpuTimes)
{
ULONG size = 0;
if(NtQuerySystemInformation(SystemProcessorPerformanceInformation, NULL, 0, &size) != STATUS_INFO_LENGTH_MISMATCH)
@@ -20,11 +23,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
{
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* coreInfo = pinfo + i;
// KernelTime includes idle time.
LONGLONG dpcTime = coreInfo->Reserved1[0].QuadPart;
LONGLONG interruptTime = coreInfo->Reserved1[1].QuadPart;
// KernelTime includes IdleTime and DpcTime.
coreInfo->KernelTime.QuadPart -= coreInfo->IdleTime.QuadPart;
coreInfo->KernelTime.QuadPart += dpcTime + interruptTime;
uint64_t inUse = (uint64_t) (coreInfo->UserTime.QuadPart + coreInfo->KernelTime.QuadPart);
uint64_t total = inUse + (uint64_t)coreInfo->IdleTime.QuadPart;
@@ -38,3 +38,137 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
return NULL;
}
static const char* getInfoByPerflib(FFlist* cpuTimes)
{
static HANDLE hQuery = NULL;
if (hQuery == NULL)
{
struct FFPerfQuerySpec
{
PERF_COUNTER_IDENTIFIER Identifier;
WCHAR Name[16];
} querySpec = {
.Identifier = {
// Processor Information GUID
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{b4fc721a-0378-476f-89ba-a5a79f810b36}
.CounterSetGuid = { 0xb4fc721a, 0x0378, 0x476f, {0x89, 0xba, 0xa5, 0xa7, 0x9f, 0x81, 0x0b, 0x36} },
.Size = sizeof(querySpec),
.CounterId = PERF_WILDCARD_COUNTER, // https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
.InstanceId = PERF_WILDCARD_COUNTER,
},
.Name = PERF_WILDCARD_INSTANCE,
};
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
{
PerfCloseQueryHandle(hQuery);
hQuery = INVALID_HANDLE_VALUE;
return "PerfOpenQueryHandle() failed";
}
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
{
PerfCloseQueryHandle(hQuery);
hQuery = INVALID_HANDLE_VALUE;
return "PerfAddCounters() failed";
}
if (querySpec.Identifier.Status != ERROR_SUCCESS)
{
PerfCloseQueryHandle(hQuery);
hQuery = INVALID_HANDLE_VALUE;
return "PerfAddCounters() reports invalid identifier";
}
}
if (hQuery == INVALID_HANDLE_VALUE)
return "Init hQuery failed";
DWORD dataSize = 0;
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
return "PerfQueryCounterData(NULL) failed";
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER))
return "instance doesn't exist";
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = (PERF_DATA_HEADER*)malloc(dataSize);
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS)
return "PerfQueryCounterData(pDataHeader) failed";
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1);
if (pCounterHeader->dwType != PERF_COUNTERSET)
return "Invalid counter type";
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
if (pMultiCounters->dwCounters == 0)
return "No CPU counters found";
PERF_MULTI_INSTANCES* pMultiInstances = (PERF_MULTI_INSTANCES*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
if (pMultiInstances->dwInstances == 0)
return "No CPU instances found";
PERF_INSTANCE_HEADER* pInstanceHeader = (PERF_INSTANCE_HEADER*)(pMultiInstances + 1);
for (DWORD iInstance = 0; iInstance < pMultiInstances->dwInstances; ++iInstance)
{
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
uint64_t processorUtility = UINT64_MAX, utilityBase = UINT64_MAX;
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
{
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
// https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
switch (pCounterIds[iCounter]) {
case 26: // % Processor Utility (#26, Type=PERF_AVERAGE_BULK)
assert(pCounterData->dwDataSize == sizeof(uint64_t));
processorUtility = *(uint64_t*)(pCounterData + 1);
break;
case 27: // % Utility Base (#27, Type=PERF_AVERAGE_BASE)
assert(pCounterData->dwDataSize == sizeof(uint32_t));
utilityBase = *(uint32_t*)(pCounterData + 1) * 100LLU;
break;
}
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
}
if (wcschr(instanceName, L'_') == NULL /* ignore `_Total` */)
{
if (processorUtility == UINT64_MAX)
return "Counter \"% Processor Utility\" are not supported";
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
*info = (FFCpuUsageInfo) {
.inUseAll = processorUtility,
.totalAll = utilityBase,
};
}
pInstanceHeader = (PERF_INSTANCE_HEADER*)pCounterData;
}
return NULL;
}
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
{
#if __aarch64__
static uint8_t winver = 10; // Assume Windows 10 or later for WoA
#else
static uint8_t winver = 0;
if (winver == 0)
winver = (uint8_t) ffStrbufToUInt(&instance.state.platform.sysinfo.release, 1);
#endif
if (winver >= 10)
{
if (getInfoByPerflib(cpuTimes) == NULL) return NULL;
ffListClear(cpuTimes);
winver = 1; // Fall back to NQSI
}
return getInfoByNqsi(cpuTimes);
}
+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)
+6 -6
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";
}
@@ -148,7 +148,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
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);
+5 -1
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;
@@ -279,7 +283,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
while((device = getmntent(mountsFile)))
{
if (__builtin_expect(options->folders.length, 0))
if (__builtin_expect(options->folders.length > 0, false))
{
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
continue;
-4
View File
@@ -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);
}
+1 -1
View File
@@ -440,7 +440,7 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result)
#endif
const char* ffdsConnectDrm(FFDisplayServerResult* result)
const char* ffdsConnectDrm(FF_MAYBE_UNUSED FFDisplayServerResult* result)
{
#ifdef FF_HAVE_DRM
if (instance.config.general.dsForceDrm != FF_DS_FORCE_DRM_TYPE_SYSFS_ONLY)
+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)
+7 -2
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");
@@ -66,7 +71,7 @@ const char* ffGpuDetectMetal(FFlist* gpus)
else if ([device supportsFamily:MTLGPUFamilyCommon1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
gpu->type = device.location == MTLDeviceLocationBuiltIn ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->index = (uint32_t) device.locationNumber;
if (device.hasUnifiedMemory && device.recommendedMaxWorkingSetSize > 0)
+158 -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,21 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu);
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
fillGPUTypeGeneric(gpu);
}
return NULL;
}
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
{
#if FF_HAVE_DRM
if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO)
{
detectByDrm(options, gpus);
if (gpus->length > 0) return NULL;
}
#endif
return detectByPci(options, gpus);
}
-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 = (uintptr_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;
+6 -6
View File
@@ -89,19 +89,19 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
if (properties.device_type != CTL_DEVICE_TYPE_GRAPHICS)
continue;
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_LUID)
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
{
if (cond->luid == deviceId)
if (cond->pciBusId.bus == properties.adapter_bdf.bus &&
cond->pciBusId.device == properties.adapter_bdf.device &&
cond->pciBusId.func == properties.adapter_bdf.function)
{
device = devices[iDev];
break;
}
}
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_LUID)
{
if (cond->pciBusId.bus == properties.adapter_bdf.bus &&
cond->pciBusId.device == properties.adapter_bdf.device &&
cond->pciBusId.func == properties.adapter_bdf.function)
if (cond->luid == deviceId)
{
device = devices[iDev];
break;
+55 -309
View File
@@ -105,93 +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;
#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)
{
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
}
@@ -215,47 +145,50 @@ 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, pciDirLen);
ffStrbufAppendS(pciDir, "/gpu_busy_percent");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
gpu->coreUsage = (double) 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;
}
}
}
@@ -311,153 +244,19 @@ static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu
}
}
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;
}
static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
{
#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";
@@ -572,29 +371,12 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
}
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)
@@ -630,45 +412,9 @@ FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, cons
#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)
{
// 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 ffDrmDetectAsahi(gpu, fd);
#endif
return NULL;
+51 -31
View File
@@ -29,11 +29,12 @@ struct FFNvapiData {
FF_LIBRARY_SYMBOL(nvapi_Unload)
FF_LIBRARY_SYMBOL(nvapi_EnumPhysicalGPUs)
FF_LIBRARY_SYMBOL(nvapi_GPU_GetRamType)
FF_LIBRARY_SYMBOL(nvapi_GPU_GetGPUType)
bool inited;
} nvapiData;
static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
static const char* detectMoreByNvapi(FFGpuDriverResult* result)
{
if (!nvapiData.inited)
{
@@ -55,6 +56,7 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
FF_NVAPI_INTERFACE(nvapi_Unload, NVAPI_INTERFACE_OFFSET_UNLOAD)
FF_NVAPI_INTERFACE(nvapi_EnumPhysicalGPUs, NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS)
FF_NVAPI_INTERFACE(nvapi_GPU_GetRamType, NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE)
FF_NVAPI_INTERFACE(nvapi_GPU_GetGPUType, NVAPI_INTERFACE_OFFSET_GPU_GET_GPU_TYPE)
#undef FF_NVAPI_INTERFACE
if (ffnvapi_Initialize() < 0)
@@ -62,6 +64,7 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
nvapiData.ffnvapi_EnumPhysicalGPUs = ffnvapi_EnumPhysicalGPUs;
nvapiData.ffnvapi_GPU_GetRamType = ffnvapi_GPU_GetRamType;
nvapiData.ffnvapi_GPU_GetGPUType = ffnvapi_GPU_GetGPUType;
nvapiData.ffnvapi_Unload = ffnvapi_Unload;
atexit((void*) ffnvapi_Unload);
@@ -86,36 +89,53 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
NvPhysicalGpuHandle gpuHandle = handles[gpuIndex];
NvApiGPUMemoryType memType;
if (nvapiData.ffnvapi_GPU_GetRamType(gpuHandle, &memType) < 0)
return "NvAPI_GPU_GetRamType() failed";
switch (memType)
if (result->memoryType && nvapiData.ffnvapi_GPU_GetRamType(gpuHandle, &memType) == 0)
{
#define FF_NVAPI_MEMORY_TYPE(type) \
case NVAPI_GPU_MEMORY_TYPE_##type: \
ffStrbufSetStatic(result->memoryType, #type); \
switch (memType)
{
#define FF_NVAPI_MEMORY_TYPE(type) \
case NVAPI_GPU_MEMORY_TYPE_##type: \
ffStrbufSetStatic(result->memoryType, #type); \
break;
FF_NVAPI_MEMORY_TYPE(UNKNOWN)
FF_NVAPI_MEMORY_TYPE(SDRAM)
FF_NVAPI_MEMORY_TYPE(DDR1)
FF_NVAPI_MEMORY_TYPE(DDR2)
FF_NVAPI_MEMORY_TYPE(GDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR3)
FF_NVAPI_MEMORY_TYPE(GDDR4)
FF_NVAPI_MEMORY_TYPE(DDR3)
FF_NVAPI_MEMORY_TYPE(GDDR5)
FF_NVAPI_MEMORY_TYPE(LPDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR5X)
FF_NVAPI_MEMORY_TYPE(LPDDR3)
FF_NVAPI_MEMORY_TYPE(LPDDR4)
FF_NVAPI_MEMORY_TYPE(LPDDR5)
FF_NVAPI_MEMORY_TYPE(GDDR6)
FF_NVAPI_MEMORY_TYPE(GDDR6X)
FF_NVAPI_MEMORY_TYPE(GDDR7)
#undef FF_NVAPI_MEMORY_TYPE
default:
ffStrbufSetF(result->memoryType, "Unknown (%d)", memType);
break;
FF_NVAPI_MEMORY_TYPE(UNKNOWN)
FF_NVAPI_MEMORY_TYPE(SDRAM)
FF_NVAPI_MEMORY_TYPE(DDR1)
FF_NVAPI_MEMORY_TYPE(DDR2)
FF_NVAPI_MEMORY_TYPE(GDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR3)
FF_NVAPI_MEMORY_TYPE(GDDR4)
FF_NVAPI_MEMORY_TYPE(DDR3)
FF_NVAPI_MEMORY_TYPE(GDDR5)
FF_NVAPI_MEMORY_TYPE(LPDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR5X)
FF_NVAPI_MEMORY_TYPE(LPDDR3)
FF_NVAPI_MEMORY_TYPE(LPDDR4)
FF_NVAPI_MEMORY_TYPE(LPDDR5)
FF_NVAPI_MEMORY_TYPE(GDDR6)
FF_NVAPI_MEMORY_TYPE(GDDR6X)
FF_NVAPI_MEMORY_TYPE(GDDR7)
#undef FF_NVAPI_MEMORY_TYPE
default:
ffStrbufSetF(result->memoryType, "Unknown (%d)", memType);
break;
}
}
NvApiGPUType gpuType;
if (result->type && nvapiData.ffnvapi_GPU_GetGPUType(gpuHandle, &gpuType) == 0)
{
switch (gpuType)
{
case NV_SYSTEM_TYPE_IGPU:
*result->type = FF_GPU_TYPE_INTEGRATED;
break;
case NV_SYSTEM_TYPE_DGPU:
*result->type = FF_GPU_TYPE_DISCRETE;
break;
default:
*result->type = FF_GPU_TYPE_UNKNOWN;
break;
}
}
return NULL;
@@ -222,13 +242,13 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
{
*result.index = value;
#ifdef _WIN32
// Don't bother loading nvapi for GPU type detection only
if (result.memoryType)
detectMemTypeByNvapi(&result);
detectMoreByNvapi(&result);
#endif
}
}
if (result.temp)
{
uint32_t value;
+3 -1
View File
@@ -45,8 +45,10 @@ static const FFstrbuf* loadPciIds()
if (pciids.length == 0)
ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/local/share/hwdata/pci.ids", &pciids);
}
#elif __FreeBSD__ || __OpenBSD__ || __NetBSD__
#elif __FreeBSD__ || __NetBSD__
ffReadFileBuffer(_PATH_LOCALBASE "/share/pciids/pci.ids", &pciids);
#elif __OpenBSD__
ffReadFileBuffer(_PATH_LOCALBASE "/share/hwdata/pci.ids", &pciids);
#elif __sun
ffReadFileBuffer(FASTFETCH_TARGET_DIR_ROOT "/usr/share/hwdata/pci.ids", &pciids);
#elif __HAIKU__
+34 -60
View File
@@ -1,83 +1,57 @@
#include "gpu.h"
#include "common/io/io.h"
#include "common/processing.h"
#include "util/stringUtils.h"
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
#include <libdevinfo.h>
static int walkDevTree(di_node_t node, FF_MAYBE_UNUSED di_minor_t minor, FFlist* gpus)
{
// SunOS requires root permission to query PCI device list, except `/usr/bin/scanpci`
// Same behavior can be observed with `cp $(which scanpci) /tmp/ && /tmp/scanpci`
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
"/usr/bin/scanpci",
"-v",
NULL,
});
if (error)
return error;
if (!ffStrbufStartsWithS(&buffer, "\npci "))
return "Invalid scanpci result";
// pci bus 0x0000 cardnum 0x00 function 0x00: vendor 0x1414 device 0x008e
// Device unknown
// CardVendor 0x0000 card 0x0000 (Card unknown)
// STATUS 0x0010 COMMAND 0x0007
// CLASS 0x03 0x02 0x00 REVISION 0x00
// BIST 0x00 HEADER 0x00 LATENCY 0x00 CACHE 0x00
// MAX_LAT 0x00 MIN_GNT 0x00 INT_PIN 0x00 INT_LINE 0x00
for (
const char* pclass = strstr(buffer.chars, "\n CLASS 0x03 ");
pclass;
pclass = strstr(pclass, "\n CLASS 0x03 ")
)
int* vendorId;
int* deviceId;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id", &vendorId) > 0
&& di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id", &deviceId) > 0)
{
// find the start of device entry
const char* pstart = memrchr(buffer.chars, '\n', (size_t) (pclass - buffer.chars));
if (pstart == NULL)
return "PCI info not found, invalid scanpci result";
while (pstart[1] != 'p')
{
pstart = memrchr(buffer.chars, '\n', (size_t) (pstart - buffer.chars - 1));
if (pstart == NULL)
return "PCI info not found, invalid scanpci result";
}
++pstart;
uint32_t vendorId, deviceId;
if (sscanf(pstart, "pci %*[^:]: vendor %x device %x",
&vendorId, &deviceId) != 2)
return "PCI info not found, invalid scanpci result";
pclass += strlen("\n CLASS 0x03 ");
uint32_t subclass = (uint32_t) strtoul(pclass, NULL, 16);
pclass += strlen("0x02 0x00 REVISION ");
uint32_t revision = (uint32_t) strtoul(pclass, NULL, 16);
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
ffStrbufInit(&gpu->memoryType);
ffStrbufInitS(&gpu->vendor, ffGPUGetVendorString((uint16_t) *vendorId));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitStatic(&gpu->platformApi, "/usr/bin/scanpci");
ffStrbufInitS(&gpu->driver, di_driver_name(node));
ffStrbufInitStatic(&gpu->platformApi, "libdevinfo");
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = 0;
gpu->deviceId = strtoul(di_bus_addr(node), NULL, 16);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName((uint16_t) deviceId, (uint8_t) revision, gpu);
{
int* revId;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "revision-id", &revId) > 0)
ffGPUQueryAmdGpuName((uint16_t) *deviceId, (uint8_t) *revId, gpu);
}
if (gpu->name.length == 0)
{
ffGPUFillVendorAndName((uint8_t) subclass, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
uint8_t subclass = 0; // assume VGA
int* classCode;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "class-code", &classCode) > 0)
subclass = (uint8_t) (*classCode & 0xFFFF);
ffGPUFillVendorAndName(subclass, (uint16_t) *vendorId, (uint16_t) *deviceId, gpu);
}
}
return DI_WALK_CONTINUE;
}
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
di_node_t rootNode = di_init("/", DINFOCPYALL);
if (rootNode == DI_NODE_NIL)
return "di_init() failed";
di_walk_minor(rootNode, DDI_NT_DISPLAY, DI_WALK_CLDFIRST, gpus, (void*) walkDevTree);
di_fini(rootNode);
return NULL;
}
+193 -84
View File
@@ -1,18 +1,15 @@
#include "gpu.h"
#include "common/library.h"
#include "detection/gpu/gpu_driver_specific.h"
#include "util/windows/unicode.h"
#include "util/windows/registry.h"
#include "util/mallocHelper.h"
#define INITGUID
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
{
if(*hdev)
SetupDiDestroyDeviceInfoList(*hdev);
}
#include <cfgmgr32.h>
#include <ntddvdeo.h>
#include <devpkey.h>
#include "util/windows/nt.h"
#define FF_EMPTY_GUID_STR L"{00000000-0000-0000-0000-000000000000}"
enum { FF_GUID_STRLEN = sizeof(FF_EMPTY_GUID_STR) / sizeof(wchar_t) - 1 };
@@ -24,21 +21,38 @@ const uint32_t regDriverKeyPrefixLength = (uint32_t) __builtin_strlen("SYSTEM\\C
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) =
SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, DIGCF_PRESENT);
ULONG devInfListSize = 0;
if (CM_Get_Device_Interface_List_SizeW(&devInfListSize, (LPGUID)&GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS || devInfListSize <= 1)
return "No display devices found";
if(hdev == INVALID_HANDLE_VALUE)
return "SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY) failed";
FF_AUTO_FREE DEVINSTID_W devInfList = malloc(devInfListSize * sizeof(*devInfList));
SP_DEVINFO_DATA did = { .cbSize = sizeof(did) };
for (DWORD idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); ++idev)
if (CM_Get_Device_Interface_ListW((LPGUID)&GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, devInfList, devInfListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS)
return "CM_Get_Device_Interface_ListW failed";
for (wchar_t* devInf = devInfList; *devInf; devInf += wcslen(devInf) + 1)
{
if (wcsncmp(devInf, L"\\\\?\\ROOT#BasicDisplay#", 22) == 0)
continue; // Skip Microsoft Basic Display Adapter
DEVINST devInst = 0;
wchar_t buffer[256];
ULONG bufferLen = 0;
{
DEVPROPTYPE propertyType;
bufferLen = sizeof(buffer);
if (CM_Get_Device_Interface_PropertyW(devInf, &DEVPKEY_Device_InstanceId, &propertyType, (PBYTE) buffer, &bufferLen, 0) != CR_SUCCESS ||
CM_Locate_DevNodeW(&devInst, buffer, CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS)
continue;
}
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->memoryType);
ffStrbufInitStatic(&gpu->platformApi, "SetupAPI");
ffStrbufInitStatic(&gpu->platformApi, "CM API");
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
@@ -48,86 +62,91 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
gpu->deviceId = 0;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
uint32_t pciBus = 0, pciAddr = 0, pciDev = 0, pciFunc = 0;
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_BUSNUMBER, NULL, (PBYTE) &pciBus, sizeof(pciBus), NULL) &&
SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_ADDRESS, NULL, (PBYTE) &pciAddr, sizeof(pciAddr), NULL))
{
pciDev = (pciAddr >> 16) & 0xFFFF;
pciFunc = pciAddr & 0xFFFF;
gpu->deviceId = (pciBus * 1000ull) + (pciDev * 10ull) + pciFunc;
pciAddr = 1; // Set to 1 to indicate that the device is a PCI device
}
unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
if (swscanf(buffer, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId) == 4)
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
wchar_t buffer[256];
uint32_t pciBus = 0, pciAddr = 0, pciDev = 0, pciFunc = 0;
ULONG pciBufLen = sizeof(pciBus);
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, NULL, &pciBus, &pciBufLen, 0) == CR_SUCCESS)
{
pciBufLen = sizeof(pciAddr);
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, NULL, &pciAddr, &pciBufLen, 0) == CR_SUCCESS)
{
pciDev = (pciAddr >> 16) & 0xFFFF;
pciFunc = pciAddr & 0xFFFF;
gpu->deviceId = (pciBus * 1000ull) + (pciDev * 10ull) + pciFunc;
pciAddr = 1; // Set to 1 to indicate that the device is a PCI device
}
}
uint64_t adapterLuid = 0;
FF_HKEY_AUTO_DESTROY hVideoIdKey = SetupDiOpenDevRegKey(hdev, &did, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (!hVideoIdKey) continue;
DWORD bufferLen = sizeof(buffer);
if (RegGetValueW(hVideoIdKey, NULL, L"VideoID", RRF_RT_REG_SZ, NULL, buffer, &bufferLen) == ERROR_SUCCESS &&
bufferLen == (FF_GUID_STRLEN + 1) * sizeof(wchar_t))
FF_HKEY_AUTO_DESTROY hVideoIdKey = NULL;
if (CM_Open_DevNode_Key(devInst, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hVideoIdKey, CM_REGISTRY_HARDWARE) == CR_SUCCESS)
{
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
bufferLen = sizeof(buffer);
if (RegGetValueW(hVideoIdKey, NULL, L"VideoID", RRF_RT_REG_SZ, NULL, buffer, &bufferLen) == ERROR_SUCCESS &&
bufferLen == (FF_GUID_STRLEN + 1) * sizeof(wchar_t))
{
uint32_t vendorId = 0;
if(ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId)
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
uint64_t dedicatedVideoMemory = 0;
if(ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &dedicatedVideoMemory, NULL))
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
{
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
gpu->type = dedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
if (gpu->vendor.length == 0)
{
uint32_t vendorId = 0;
if(ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId)
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
}
uint64_t dedicatedSystemMemory, sharedSystemMemory;
if(ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &dedicatedSystemMemory, NULL) &&
ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL))
{
gpu->dedicated.total = dedicatedVideoMemory + dedicatedSystemMemory;
gpu->shared.total = sharedSystemMemory;
}
ffRegReadStrbuf(hDirectxKey, L"Description", &gpu->name, NULL);
if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL))
{
if (!gpu->deviceId) gpu->deviceId = adapterLuid;
}
ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &gpu->dedicated.total, NULL);
if (ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &gpu->shared.total, NULL))
{
uint64_t sharedSystemMemory = 0;
if (ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL))
gpu->shared.total += sharedSystemMemory;
}
uint32_t featureLevel = 0;
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL))
{
if (!gpu->deviceId) gpu->deviceId = adapterLuid;
}
uint64_t driverVersion = 0;
if(ffRegReadUint64(hDirectxKey, L"DriverVersion", &driverVersion, NULL) && driverVersion)
{
ffStrbufSetF(&gpu->driver, "%u.%u.%u.%u",
(unsigned) (driverVersion >> 48) & 0xFFFF,
(unsigned) (driverVersion >> 32) & 0xFFFF,
(unsigned) (driverVersion >> 16) & 0xFFFF,
(unsigned) (driverVersion >> 0) & 0xFFFF
);
uint32_t featureLevel = 0;
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
uint64_t driverVersion = 0;
if(ffRegReadUint64(hDirectxKey, L"DriverVersion", &driverVersion, NULL) && driverVersion)
{
ffStrbufSetF(&gpu->driver, "%u.%u.%u.%u",
(unsigned) (driverVersion >> 48) & 0xFFFF,
(unsigned) (driverVersion >> 32) & 0xFFFF,
(unsigned) (driverVersion >> 16) & 0xFFFF,
(unsigned) (driverVersion >> 0) & 0xFFFF
);
}
}
}
}
if (gpu->vendor.length == 0)
if (gpu->vendor.length == 0 || gpu->name.length == 0)
{
bufferLen = sizeof(buffer);
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_DRIVER, NULL, (PBYTE) buffer, sizeof(buffer), &bufferLen) && bufferLen == (FF_GUID_STRLEN + strlen("\\0000") + 1) * 2)
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DRIVER, NULL, buffer, &bufferLen, 0) == CR_SUCCESS &&
bufferLen == (FF_GUID_STRLEN + strlen("\\0000") + 1) * 2)
{
wmemcpy(regDriverKey + regDriverKeyPrefixLength, buffer, FF_GUID_STRLEN + strlen("\\0000"));
FF_HKEY_AUTO_DESTROY hRegDriverKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDriverKey, &hRegDriverKey, NULL))
{
if (ffRegReadStrbuf(hRegDriverKey, L"ProviderName", &gpu->vendor, NULL))
if (gpu->vendor.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"ProviderName", &gpu->vendor, NULL))
{
if (ffStrbufContainS(&gpu->vendor, "Intel"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
@@ -136,6 +155,19 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
else if (ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
}
if (gpu->name.length == 0)
ffRegReadStrbuf(hRegDriverKey, L"DriverDesc", &gpu->name, NULL);
if (gpu->driver.length == 0)
ffRegReadStrbuf(hRegDriverKey, L"DriverVersion", &gpu->driver, NULL);
if (gpu->dedicated.total == FF_GPU_VMEM_SIZE_UNSET)
{
if (!ffRegReadUint64(hRegDriverKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL))
{
uint32_t memorySize = 0;
if (ffRegReadUint(hRegDriverKey, L"HardwareInformation.MemorySize", &memorySize, NULL))
gpu->dedicated.total = memorySize;
}
}
}
}
}
@@ -143,18 +175,11 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
const char* dllName;
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName) && (options->temp || options->driverSpecific))
if (options->driverSpecific && getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName))
{
unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_HARDWAREID, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
{
swscanf(buffer, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId);
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
}
detectFn(
&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID
.type = (deviceId > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID : 0)
| (adapterLuid > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_LUID : 0)
| (pciAddr > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID : 0),
.pciDeviceId = {
@@ -189,9 +214,93 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (!gpu->name.length)
{
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_DEVICEDESC, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
bufferLen = sizeof(buffer);
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DEVICEDESC, NULL, buffer, &bufferLen, 0) == CR_SUCCESS)
ffStrbufSetWS(&gpu->name, buffer);
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN && adapterLuid > 0)
{
HMODULE hgdi32 = GetModuleHandleW(L"gdi32.dll");
if (hgdi32)
{
FF_LIBRARY_LOAD_SYMBOL_LAZY(hgdi32, D3DKMTOpenAdapterFromLuid);
if (ffD3DKMTOpenAdapterFromLuid) // Windows 8 and later
{
D3DKMT_OPENADAPTERFROMLUID openAdapterFromLuid = { .AdapterLuid = *(LUID*)&adapterLuid };
if (NT_SUCCESS(ffD3DKMTOpenAdapterFromLuid(&openAdapterFromLuid)))
{
D3DKMT_ADAPTERTYPE adapterType = {};
D3DKMT_QUERYADAPTERINFO queryAdapterInfo = {
.hAdapter = openAdapterFromLuid.hAdapter,
.Type = KMTQAITYPE_ADAPTERTYPE,
.pPrivateDriverData = &adapterType,
.PrivateDriverDataSize = sizeof(adapterType),
};
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) // Vista and later
{
if (adapterType.HybridDiscrete)
gpu->type = FF_GPU_TYPE_DISCRETE;
else if (adapterType.HybridIntegrated)
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET)
{
for (ULONG nodeIdx = 0; ; nodeIdx++)
{
D3DKMT_NODEMETADATA nodeMetadata = {
.NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx,
};
queryAdapterInfo = (D3DKMT_QUERYADAPTERINFO) {
.hAdapter = openAdapterFromLuid.hAdapter,
.Type = KMTQAITYPE_NODEMETADATA,
.pPrivateDriverData = &nodeMetadata,
.PrivateDriverDataSize = sizeof(nodeMetadata),
};
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) break; // Windows 10 and later
if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D) continue;
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_NODE2,
.AdapterLuid = *(LUID*)&adapterLuid,
.QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) // Windows 11 (22H2) and later
{
gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000);
break;
}
}
}
D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter };
(void) D3DKMTCloseAdapter(&closeAdapter);
openAdapterFromLuid.hAdapter = 0;
}
if (options->temp && gpu->temperature != gpu->temperature)
{
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER,
.AdapterLuid = *(LUID*)&adapterLuid,
.QueryPhysAdapter = { .PhysicalAdapterIndex = 0 },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)) &&
queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0)
gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0;
}
}
}
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
else if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
gpu->type = gpu->dedicated.total >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
}
return NULL;
+9
View File
@@ -23,6 +23,13 @@ typedef enum NvApiGPUMemoryType
NVAPI_GPU_MEMORY_TYPE_GDDR7,
} NvApiGPUMemoryType;
typedef enum
{
NV_SYSTEM_TYPE_GPU_UNKNOWN = 0,
NV_SYSTEM_TYPE_IGPU = 1, // Integrated
NV_SYSTEM_TYPE_DGPU = 2, // Discrete
} NvApiGPUType;
typedef int NvAPI_Status; // 0 = success; < 0 = error
typedef struct NvPhysicalGpuHandle* NvPhysicalGpuHandle;
@@ -32,6 +39,7 @@ typedef enum
NVAPI_INTERFACE_OFFSET_UNLOAD = 0xD22BDD7E,
NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS = 0xE5AC921F,
NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE = 0x57F7CAAC,
NVAPI_INTERFACE_OFFSET_GPU_GET_GPU_TYPE = 0xC33BAEB1,
NVAPI_INTERFACE_OFFSET_FORCE_UINT32 = 0xFFFFFFFF
} NvApiInterfaceOffsets;
@@ -42,3 +50,4 @@ extern NvAPI_Status nvapi_Initialize(void);
extern NvAPI_Status nvapi_Unload(void);
extern NvAPI_Status nvapi_EnumPhysicalGPUs(NvPhysicalGpuHandle* handles, int* count);
extern NvAPI_Status nvapi_GPU_GetRamType(NvPhysicalGpuHandle handle, NvApiGPUMemoryType* memtype);
extern NvAPI_Status nvapi_GPU_GetGPUType(NvPhysicalGpuHandle handle, NvApiGPUType* gpuType);
+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)";
+72 -45
View File
@@ -1,50 +1,35 @@
#include "fastfetch.h"
#include "detection/media/media.h"
#include "common/library.h"
#include "common/processing.h"
#include "util/apple/cf_helpers.h"
#include "util/apple/osascript.h"
#include "fastfetch_datatext.h"
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
// https://github.com/andrewwiik/iOS-Blocks/blob/master/Widgets/Music/MediaRemote.h
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingClient(dispatch_queue_t dispatcher, void (^callback)(_Nullable id clientObj)) __attribute__((weak_import));
extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribute__((weak_import));
extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import));
void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingApplicationDisplayID(dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef displayID)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingApplicationDisplayName(int unknown, dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef name)) __attribute__((weak_import));
static const char* getMediaByMediaRemote(FFMediaResult* result)
{
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingClient);
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetBundleIdentifier);
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetParentAppBundleIdentifier);
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingApplicationIsPlaying);
#undef FF_TEST_FN_EXISTANCE
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
ffStrbufSetStatic(&result->status, playing ? "Playing" : "Paused");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
__block const char* error = NULL;
MRMediaRemoteGetNowPlayingInfo(queue, ^(_Nullable CFDictionaryRef info) {
if(info != nil)
{
error = ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
if(!error)
{
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
}
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
}
else
error = "MRMediaRemoteGetNowPlayingInfo() failed";
@@ -53,42 +38,76 @@ static const char* getMediaByMediaRemote(FFMediaResult* result)
});
dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingClient(queue, ^(_Nullable id clientObj) {
if (clientObj != nil)
{
CFStringRef identifier = MRNowPlayingClientGetBundleIdentifier(clientObj);
if (identifier == nil)
identifier = MRNowPlayingClientGetParentAppBundleIdentifier(clientObj);
if (identifier != nil)
ffCfStrGetString(identifier, &result->playerId);
}
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
ffStrbufSetStatic(&result->status, playing ? "Playing" : "Paused");
dispatch_group_leave(group);
});
if (MRMediaRemoteGetNowPlayingApplicationDisplayID)
{
dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingApplicationDisplayID(queue, ^(_Nullable CFStringRef displayID) {
ffCfStrGetString(displayID, &result->playerId);
dispatch_group_leave(group);
});
}
if (MRMediaRemoteGetNowPlayingApplicationDisplayName)
{
dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingApplicationDisplayName(0, queue, ^(_Nullable CFStringRef name) {
ffCfStrGetString(name, &result->player);
dispatch_group_leave(group);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
// Don't dispatch_release because we are using ARC
if(result->playerId.length > 0)
{
char buf[128];
snprintf(buf, ARRAY_SIZE(buf), "name of app id \"%s\"", result->playerId.chars);
ffOsascript(buf, &result->player);
}
if(result->song.length > 0)
return NULL;
return error;
}
static const char* getMediaByOsascript(FFMediaResult* result)
__attribute__((visibility("default"), used))
int ffPrintMediaByMediaRemote(void)
{
FFMediaResult media = {
.status = ffStrbufCreate(),
.song = ffStrbufCreate(),
.artist = ffStrbufCreate(),
.album = ffStrbufCreate(),
.playerId = ffStrbufCreate(),
.player = ffStrbufCreate(),
};
if (getMediaByMediaRemote(&media) != NULL)
return 1;
ffStrbufPutTo(&media.status, stdout);
ffStrbufPutTo(&media.song, stdout);
ffStrbufPutTo(&media.artist, stdout);
ffStrbufPutTo(&media.album, stdout);
ffStrbufPutTo(&media.playerId, stdout);
ffStrbufPutTo(&media.player, stdout);
ffStrbufDestroy(&media.status);
ffStrbufDestroy(&media.song);
ffStrbufDestroy(&media.artist);
ffStrbufDestroy(&media.album);
ffStrbufDestroy(&media.playerId);
ffStrbufDestroy(&media.player);
return 0;
}
static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
{
// #1737
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote()", instance.state.platform.exePath.chars);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
// 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,
"/usr/bin/python3", // Must be signed by Apple. Homebrew python doesn't work
"-c",
script.chars,
nil
});
if (error) return error;
@@ -107,8 +126,16 @@ void ffDetectMediaImpl(FFMediaResult* media)
{
const char* error;
if (@available(macOS 15.4, *))
error = getMediaByOsascript(media);
error = getMediaByAuthorizedProcess(media);
else
error = getMediaByMediaRemote(media);
if (error) ffStrbufAppendS(&media->error, error);
if (error)
ffStrbufAppendS(&media->error, error);
else if (media->player.length == 0 && media->playerId.length > 0)
{
ffStrbufSet(&media->player, &media->playerId);
if (ffStrbufStartsWithIgnCaseS(&media->player, "com."))
ffStrbufSubstrAfter(&media->player, strlen("com.") - 1);
ffStrbufReplaceAllC(&media->player, '.', ' ');
}
}
+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;
}
+8 -1
View File
@@ -25,6 +25,11 @@ static void parseSystemVersion(FFOSResult* os)
ffStrbufInitS(&os->version, value.UTF8String);
if((value = dict[@"ProductBuildVersion"]))
ffStrbufInitS(&os->buildID, value.UTF8String);
if (ffStrbufStartsWithS(&os->version, "16."))
{
// macOS 26 Tahoe. #1809
os->version.chars[0] = '2';
}
}
static bool detectOSCodeName(FFOSResult* os)
@@ -37,6 +42,8 @@ static bool detectOSCodeName(FFOSResult* os)
switch (num)
{
case 26:
case 16: ffStrbufSetStatic(&os->codename, "Tahoe"); return true;
case 15: ffStrbufSetStatic(&os->codename, "Sequoia"); return true;
case 14: ffStrbufSetStatic(&os->codename, "Sonoma"); return true;
case 13: ffStrbufSetStatic(&os->codename, "Ventura"); return true;
@@ -62,7 +69,7 @@ static bool detectOSCodeName(FFOSResult* os)
case 6: ffStrbufSetStatic(&os->codename, "Snow Leopard"); return true;
case 5: ffStrbufSetStatic(&os->codename, "Leopard"); return true;
case 4: ffStrbufSetStatic(&os->codename, "Tiger"); return true;
case 3: ffStrbufSetStatic(&os->codename, "Panther"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 3: ffStrbufSetStatic(&os->codename, "Panther"); return true;
case 2: ffStrbufSetStatic(&os->codename, "Jaguar"); return true;
case 1: ffStrbufSetStatic(&os->codename, "Puma"); return true;
case 0: ffStrbufSetStatic(&os->codename, "Cheetah"); return true;
+125 -62
View File
@@ -47,7 +47,7 @@ FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result)
// - `Armbian_Security` for images with kali repo added
// - `Armbian-unofficial` for an unofficial image built from source, e.g. during development and testing
if (ffStrbufStartsWithS(&result->prettyName, "Armbian"))
ffStrbufSetS(&result->name, "Armbian");
ffStrbufSetStatic(&result->name, "Armbian");
else
return false;
ffStrbufSet(&result->idLike, &result->id);
@@ -69,113 +69,113 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
return;
else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
{
ffStrbufSetS(&result->name, "Linux Lite");
ffStrbufSetS(&result->id, "linuxlite");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Linux Lite");
ffStrbufSetStatic(&result->id, "linuxlite");
ffStrbufSetStatic(&result->idLike, "ubuntu");
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Linux Lite "));
return;
}
else if(ffStrbufStartsWithS(&result->prettyName, "Rhino Linux "))
{
ffStrbufSetS(&result->name, "Rhino Linux");
ffStrbufSetS(&result->id, "rhinolinux");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Rhino Linux");
ffStrbufSetStatic(&result->id, "rhinolinux");
ffStrbufSetStatic(&result->idLike, "ubuntu");
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Rhino Linux "));
return;
}
else if(ffStrbufStartsWithS(&result->prettyName, "VanillaOS "))
{
ffStrbufSetS(&result->id, "vanilla");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->id, "vanilla");
ffStrbufSetStatic(&result->idLike, "ubuntu");
}
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
{
ffStrbufSetS(&result->name, "Kubuntu");
ffStrbufSetS(&result->prettyName, "Kubuntu");
ffStrbufSetS(&result->id, "kubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Kubuntu");
ffStrbufSetF(&result->prettyName, "Kubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "kubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "xfce") || ffStrContains(xdgConfigDirs, "xubuntu"))
{
ffStrbufSetS(&result->name, "Xubuntu");
ffStrbufSetS(&result->prettyName, "Xubuntu");
ffStrbufSetS(&result->id, "xubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Xubuntu");
ffStrbufSetF(&result->prettyName, "Xubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "xubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "lxqt") || ffStrContains(xdgConfigDirs, "lubuntu"))
{
ffStrbufSetS(&result->name, "Lubuntu");
ffStrbufSetS(&result->prettyName, "Lubuntu");
ffStrbufSetS(&result->id, "lubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Lubuntu");
ffStrbufSetF(&result->prettyName, "Lubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "lubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "budgie"))
{
ffStrbufSetS(&result->name, "Ubuntu Budgie");
ffStrbufSetS(&result->prettyName, "Ubuntu Budgie");
ffStrbufSetS(&result->id, "ubuntu-budgie");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Budgie");
ffStrbufSetF(&result->prettyName, "Ubuntu Budgie %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-budgie");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "cinnamon"))
{
ffStrbufSetS(&result->name, "Ubuntu Cinnamon");
ffStrbufSetS(&result->prettyName, "Ubuntu Cinnamon");
ffStrbufSetS(&result->id, "ubuntu-cinnamon");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Cinnamon");
ffStrbufSetF(&result->prettyName, "Ubuntu Cinnamon %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-cinnamon");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "mate"))
{
ffStrbufSetS(&result->name, "Ubuntu MATE");
ffStrbufSetS(&result->prettyName, "Ubuntu MATE");
ffStrbufSetS(&result->id, "ubuntu-mate");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu MATE");
ffStrbufSetF(&result->prettyName, "Ubuntu MATE %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-mate");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "studio"))
{
ffStrbufSetS(&result->name, "Ubuntu Studio");
ffStrbufSetS(&result->prettyName, "Ubuntu Studio");
ffStrbufSetS(&result->id, "ubuntu-studio");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Studio");
ffStrbufSetF(&result->prettyName, "Ubuntu Studio %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-studio");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "sway"))
{
ffStrbufSetS(&result->name, "Ubuntu Sway");
ffStrbufSetS(&result->prettyName, "Ubuntu Sway");
ffStrbufSetS(&result->id, "ubuntu-sway");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Sway");
ffStrbufSetF(&result->prettyName, "Ubuntu Sway %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-sway");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "touch"))
{
ffStrbufSetS(&result->name, "Ubuntu Touch");
ffStrbufSetS(&result->prettyName, "Ubuntu Touch");
ffStrbufSetS(&result->id, "ubuntu-touch");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "Ubuntu Touch");
ffStrbufSetF(&result->prettyName, "Ubuntu Touch %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-touch");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
if(ffStrContains(xdgConfigDirs, "lliurex"))
{
ffStrbufSetS(&result->name, "LliureX");
ffStrbufSetS(&result->prettyName, "LliureX");
ffStrbufSetS(&result->id, "lliurex");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetStatic(&result->name, "LliureX");
ffStrbufSetF(&result->prettyName, "LliureX %s", result->version.chars);
ffStrbufSetStatic(&result->id, "lliurex");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
}
}
@@ -196,8 +196,8 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
return true;
else if (ffStrbufStartsWithS(&result->name, "Loc-OS"))
{
ffStrbufSetS(&result->id, "locos");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetStatic(&result->id, "locos");
ffStrbufSetStatic(&result->idLike, "debian");
return true;
}
else if (ffStrbufEqualS(&result->name, "Parrot Security"))
@@ -210,15 +210,15 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
else if (ffStrbufStartsWithS(&result->name, "Lilidog GNU/Linux"))
{
// https://github.com/fastfetch-cli/fastfetch/issues/1373
ffStrbufSetS(&result->id, "lilidog");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetStatic(&result->id, "lilidog");
ffStrbufSetStatic(&result->idLike, "debian");
return true;
}
else if (access("/usr/bin/pveversion", X_OK) == 0)
{
ffStrbufSetS(&result->id, "pve");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetS(&result->name, "Proxmox VE");
ffStrbufSetStatic(&result->id, "pve");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "Proxmox VE");
ffStrbufClear(&result->versionID);
if (ffProcessAppendStdOut(&result->versionID, (char* const[]) {
"/usr/bin/dpkg-query",
@@ -231,15 +231,50 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
ffStrbufSetF(&result->prettyName, "Proxmox VE %s", result->versionID.chars);
return true;
}
else if (ffPathExists("/etc/rpi-issue", FF_PATHTYPE_FILE))
{
// Raspberry Pi OS
ffStrbufSetStatic(&result->id, "raspbian");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "Raspberry Pi OS");
ffStrbufSetStatic(&result->prettyName, "Raspberry Pi OS");
return true;
}
else if (ffPathExists("/boot/dietpi/.version", FF_PATHTYPE_FILE))
{
// DietPi
ffStrbufSetStatic(&result->id, "dietpi");
ffStrbufSetStatic(&result->name, "DietPi");
ffStrbufSetStatic(&result->prettyName, "DietPi");
ffStrbufSetStatic(&result->idLike, "debian");
FF_STRBUF_AUTO_DESTROY core = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY sub = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY rc = ffStrbufCreate();
if (ffParsePropFileValues("/boot/dietpi/.version", 3, (FFpropquery[]) {
{"G_DIETPI_VERSION_CORE=", &core},
{"G_DIETPI_VERSION_SUB=", &sub},
{"G_DIETPI_VERSION_RC=", &rc},
})) ffStrbufAppendF(&result->prettyName, " %s.%s.%s", core.chars, sub.chars, rc.chars);
return true;
}
else if (ffStrbufEndsWithS(&instance.state.platform.sysinfo.release, "+truenas"))
{
// TrueNAS Scale
ffStrbufSetStatic(&result->id, "truenas-scale");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "TrueNAS Scale");
ffStrbufSetStatic(&result->prettyName, "TrueNAS Scale");
return true;
}
else
{
// Hack for MX Linux. See #847
FF_STRBUF_AUTO_DESTROY lsbRelease = ffStrbufCreate();
if (ffAppendFileBuffer("/etc/lsb-release", &lsbRelease) && ffStrbufContainS(&lsbRelease, "DISTRIB_ID=MX"))
{
ffStrbufSetS(&result->id, "mx");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetS(&result->name, "MX");
ffStrbufSetStatic(&result->id, "mx");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "MX");
ffStrbufClear(&result->version);
ffParsePropLines(lsbRelease.chars, "DISTRIB_RELEASE=", &result->version);
@@ -256,6 +291,21 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
return false;
}
FF_MAYBE_UNUSED static bool detectFedoraVariant(FFOSResult* result)
{
if (ffStrbufEqualS(&result->variantID, "coreos")
|| ffStrbufEqualS(&result->variantID, "kinoite")
|| ffStrbufEqualS(&result->variantID, "sericea")
|| ffStrbufEqualS(&result->variantID, "silverblue"))
{
ffStrbufAppendC(&result->id, '-');
ffStrbufAppend(&result->id, &result->variantID);
ffStrbufSetStatic(&result->idLike, "fedora");
return true;
}
return false;
}
static void detectOS(FFOSResult* os)
{
#ifdef FF_CUSTOM_OS_RELEASE_PATH
@@ -286,8 +336,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)
@@ -295,13 +356,15 @@ void ffDetectOSImpl(FFOSResult* os)
detectOS(os);
#ifdef __linux__
if(ffStrbufIgnCaseEqualS(&os->id, "ubuntu"))
if(ffStrbufEqualS(&os->id, "ubuntu"))
getUbuntuFlavour(os);
else if(ffStrbufIgnCaseEqualS(&os->id, "debian"))
else if(ffStrbufEqualS(&os->id, "debian"))
{
if (!detectDebianDerived(os))
getDebianVersion(os);
}
else if(ffStrbufEqualS(&os->id, "fedora"))
detectFedoraVariant(os);
else if(ffStrbufEqualS(&os->id, "linuxmint"))
{
if (ffStrbufEqualS(&os->name, "LMDE"))
+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;
}
+20 -19
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))
@@ -642,33 +646,30 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
#endif
ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
{
// check if ~/.nix-profile exists
FF_STRBUF_AUTO_DESTROY profilePath = ffStrbufCreateCopy(&baseDir);
ffStrbufAppendS(&profilePath, ".nix-profile");
if (ffPathExists(profilePath.chars, FF_PATHTYPE_DIRECTORY))
{
result->nixUser += getNixPackages(&baseDir, ".nix-profile");
}
// Count packages from $HOME/.nix-profile
result->nixUser += getNixPackages(&baseDir, ".nix-profile");
// check if $XDG_STATE_HOME/nix/profile exists
FF_STRBUF_AUTO_DESTROY stateDir = ffStrbufCreate();
const char* stateHome = getenv("XDG_STATE_HOME");
if(ffStrSet(stateHome))
// Check in $XDG_STATE_HOME/nix/profile
FF_STRBUF_AUTO_DESTROY stateHome = ffStrbufCreate();
const char* stateHomeEnv = getenv("XDG_STATE_HOME");
if (ffStrSet(stateHomeEnv))
{
ffStrbufSetS(&stateDir, stateHome);
ffStrbufEnsureEndsWithC(&stateDir, '/');
ffStrbufSetS(&stateHome, stateHomeEnv);
ffStrbufEnsureEndsWithC(&stateHome, '/');
}
else
{
ffStrbufSet(&stateDir, &instance.state.platform.homeDir);
ffStrbufAppendS(&stateDir, ".local/state/");
ffStrbufSet(&stateHome, &instance.state.platform.homeDir);
ffStrbufAppendS(&stateHome, ".local/state/");
}
result->nixUser += getNixPackages(&stateHome, "nix/profile");
ffStrbufSet(&profilePath, &stateDir);
ffStrbufAppendS(&profilePath, "nix/profile");
result->nixUser += getNixPackages(&stateDir, "nix/profile");
// Check in /etc/profiles/per-user/$USER
FF_STRBUF_AUTO_DESTROY userPkgsDir = ffStrbufCreateStatic("/etc/profiles/per-user/");
result->nixUser += getNixPackages(&userPkgsDir, instance.state.platform.userName.chars);
}
if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT))
+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
}
@@ -113,9 +113,9 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
if (deviceCharacteristics)
{
ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductSerialNumberKey), &device->serial);
ffStrbufTrim(&device->serial, ' ');
ffStrbufTrimSpace(&device->serial);
ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductRevisionLevelKey), &device->revision);
ffStrbufTrim(&device->revision, ' ');
ffStrbufTrimRightSpace(&device->revision);
CFStringRef mediumType = (CFStringRef) CFDictionaryGetValue(deviceCharacteristics, CFSTR(kIOPropertyMediumTypeKey));
if (mediumType)
@@ -65,7 +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, ' ');
ffStrbufTrimSpace(&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;
@@ -153,7 +153,7 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
{
ffStrbufInit(&device->serial);
if (ffReadFileBufferRelative(devfd, "serial", &device->serial))
ffStrbufTrim(&device->serial, ' ');
ffStrbufTrimSpace(&device->serial);
}
{
@@ -0,0 +1,77 @@
#include "physicaldisk.h"
#include "util/stringUtils.h"
#include "sys/scsi/generic/inquiry.h"
#include <libdevinfo.h>
#include <sys/stat.h>
struct FFWalkTreeBundle
{
FFPhysicalDiskOptions* options;
FFlist* disks;
};
static int walkDevTree(di_node_t node, di_minor_t minor, struct FFWalkTreeBundle* bundle)
{
if (di_minor_spectype(minor) != S_IFCHR || !ffStrEquals(di_minor_name(minor), "a,raw")) return DI_WALK_CONTINUE;
char* productId;
char* vendorId;
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-product-id", &productId) > 0
&& di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-vendor-id", &vendorId) > 0)
{
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateF("%s %s", vendorId, productId);
if (bundle->options->namePrefix.length && !ffStrbufStartsWithIgnCase(&name, &bundle->options->namePrefix))
return DI_WALK_CONTINUE;
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(bundle->disks);
ffStrbufInitMove(&device->name, &name);
ffStrbufInitF(&device->devPath, "/devices%s", di_devfs_path(node));
ffStrbufInit(&device->serial);
ffStrbufInit(&device->revision);
ffStrbufInit(&device->interconnect);
device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
device->type = FF_PHYSICALDISK_TYPE_NONE;
device->size = 0;
char* buf;
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-serial-no", &buf) > 0)
{
ffStrbufSetS(&device->serial, buf);
ffStrbufTrimSpace(&device->serial);
}
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-revision-id", &buf) > 0)
{
ffStrbufSetS(&device->revision, buf);
ffStrbufTrimRightSpace(&device->revision);
}
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "class", &buf) > 0)
ffStrbufSetS(&device->interconnect, buf);
device->type |= di_prop_find(DDI_DEV_T_ANY, node, "removable-media") ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
int* value;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-solid-state", &value) > 0)
device->type |= *value ? FF_PHYSICALDISK_TYPE_SSD : FF_PHYSICALDISK_TYPE_HDD;
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type", &value) > 0)
device->type |= *value == DTYPE_DIRECT ? FF_PHYSICALDISK_TYPE_READWRITE : *value == DTYPE_RODIRECT ? FF_PHYSICALDISK_TYPE_READONLY : 0;
int64_t* nblocks;
if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "device-nblocks", &nblocks) > 0
&& di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-blksize", &value) > 0)
device->size = (uint64_t) ((uint64_t) *nblocks * (uint64_t) *value);
}
return DI_WALK_CONTINUE;
}
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
{
di_node_t rootNode = di_init("/", DINFOCPYALL);
if (rootNode == DI_NODE_NIL)
return "di_init() failed";
di_walk_minor(rootNode, DDI_NT_BLOCK, DI_WALK_CLDFIRST, &(struct FFWalkTreeBundle) { options, result }, (void*) walkDevTree);
di_fini(rootNode);
return NULL;
}
@@ -62,14 +62,14 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysic
if (sdd->SerialNumberOffset != 0)
{
ffStrbufSetS(&device->serial, (const char*) sddBuffer + sdd->SerialNumberOffset);
ffStrbufTrim(&device->serial, ' ');
ffStrbufTrimSpace(&device->serial);
}
ffStrbufInit(&device->revision);
if (sdd->ProductRevisionOffset != 0)
{
ffStrbufSetS(&device->revision, (const char*) sddBuffer + sdd->ProductRevisionOffset);
ffStrbufTrim(&device->revision, ' ');
ffStrbufTrimRightSpace(&device->revision);
}
device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
+909
View File
@@ -0,0 +1,909 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (C) 4Front Technologies 1996-2008.
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_AUDIO_OSS_H
#define _SYS_AUDIO_OSS_H
#include <sys/types.h>
#include <sys/time.h>
/*
* These are the ioctl calls for all Solaris /dev/dsp and /dev/mixer audio
* devices.
*
* Note that the contents of this file include definitions which exist
* primarily for compatibility. Many of the defines here are not
* actually implemented, but exist solely to facilitate compilation of
* programs from other operating systems. Other definitions here may
* not be fully supported or may otherwise be obsolete. There are many
* things in this file which should not be used on SunOS.
*
* Please read the documentation to determine which portions of the
* API are fully supported and recommended for use in new
* applications.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Buffer status queries.
* SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE
*/
typedef struct audio_buf_info {
int fragments; /* # of available fragments */
int fragstotal; /* Total # of fragments allocated */
int fragsize; /* Size of a fragment in bytes */
int bytes; /* Available space in bytes */
/* Note! 'bytes' could be more than fragments*fragsize */
} audio_buf_info;
/*
* Sync groups for audio devices.
* SNDCTL_DSP_SYNCGROUP and SNDCTL_DSP_SYNCSTART
*/
typedef struct oss_syncgroup {
int id;
int mode;
int filler[16];
} oss_syncgroup;
/*
* SNDCTL_DSP_GETERROR
*/
typedef struct audio_errinfo {
int play_underruns;
int rec_overruns;
unsigned int play_ptradjust;
unsigned int rec_ptradjust;
int play_errorcount;
int rec_errorcount;
int play_lasterror;
int rec_lasterror;
int play_errorparm;
int rec_errorparm;
int filler[16];
} audio_errinfo;
/*
* SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR
*/
typedef struct count_info {
unsigned int bytes; /* Total # of bytes processed */
int blocks; /* # of fragment transitions since last time */
int ptr; /* Current DMA pointer value */
} count_info;
/*
* SNDCTL_DSP_CURENT_IPTR and SNDCTL_DSP_CURRENT_OPTR
*/
typedef struct {
long long samples; /* Total # of samples */
int fifo_samples; /* Samples in device FIFO */
int filler[32]; /* For future use */
} oss_count_t;
/*
* SNDCTL_DSP_GET_RECSRC_NAMES and SNDCTL_DSP_GET_PLAYTGT_NAMES
*/
#define OSS_ENUM_MAXVALUE 255
typedef struct oss_mixer_enuminfo {
int dev;
int ctrl;
int nvalues;
int version;
short strindex[OSS_ENUM_MAXVALUE];
char strings[3000];
} oss_mixer_enuminfo;
/*
* Digital interface (S/PDIF) control interface
* SNDCTL_DSP_READCTL and SNDCTL_DSP_WRITECTL
*/
typedef struct oss_digital_control {
unsigned int caps;
#define DIG_CBITIN_NONE 0x00000000
#define DIG_CBITIN_LIMITED 0x00000001
#define DIG_CBITIN_DATA 0x00000002
#define DIG_CBITIN_BYTE0 0x00000004
#define DIG_CBITIN_FULL 0x00000008
#define DIG_CBITIN_MASK 0x0000000f
#define DIG_CBITOUT_NONE 0x00000000
#define DIG_CBITOUT_LIMITED 0x00000010
#define DIG_CBITOUT_BYTE0 0x00000020
#define DIG_CBITOUT_FULL 0x00000040
#define DIG_CBITOUT_DATA 0x00000080
#define DIG_CBITOUT_MASK 0x000000f0
#define DIG_UBITIN 0x00000100
#define DIG_UBITOUT 0x00000200
#define DIG_VBITOUT 0x00000400
#define DIG_OUTRATE 0x00000800
#define DIG_INRATE 0x00001000
#define DIG_INBITS 0x00002000
#define DIG_OUTBITS 0x00004000
#define DIG_EXACT 0x00010000
#define DIG_PRO 0x00020000
#define DIG_CONSUMER 0x00040000
#define DIG_PASSTHROUGH 0x00080000
#define DIG_OUTSEL 0x00100000
unsigned int valid;
#define VAL_CBITIN 0x00000001
#define VAL_UBITIN 0x00000002
#define VAL_CBITOUT 0x00000004
#define VAL_UBITOUT 0x00000008
#define VAL_ISTATUS 0x00000010
#define VAL_IRATE 0x00000020
#define VAL_ORATE 0x00000040
#define VAL_INBITS 0x00000080
#define VAL_OUTBITS 0x00000100
#define VAL_REQUEST 0x00000200
#define VAL_OUTSEL 0x00000400
#define VAL_OUTMASK (VAL_CBITOUT|VAL_UBITOUT|VAL_ORATE|VAL_OUTBITS|VAL_OUTSEL)
unsigned int request;
unsigned int param;
#define SPD_RQ_PASSTHROUGH 1
unsigned char cbitin[24];
unsigned char ubitin[24];
unsigned char cbitout[24];
unsigned char ubitout[24];
unsigned int outsel;
#define OUTSEL_DIGITAL 1
#define OUTSEL_ANALOG 2
#define OUTSEL_BOTH (OUTSEL_DIGITAL|OUTSEL_ANALOG)
int in_data; /* Audio/data if autodetectable by receiver */
#define IND_UNKNOWN 0
#define IND_AUDIO 1
#define IND_DATA 2
int in_locked; /* Receiver locked */
#define LOCK_NOT_INDICATED 0
#define LOCK_UNLOCKED 1
#define LOCK_LOCKED 2
int in_quality; /* Input signal quality */
#define IN_QUAL_NOT_INDICATED 0
#define IN_QUAL_POOR 1
#define IN_QUAL_GOOD 2
int in_vbit;
int out_vbit; /* V bits */
#define VBIT_NOT_INDICATED 0
#define VBIT_OFF 1
#define VBIT_ON 2
unsigned int in_errors; /* Various input error conditions */
#define INERR_CRC 0x0001
#define INERR_QCODE_CRC 0x0002
#define INERR_PARITY 0x0004
#define INERR_BIPHASE 0x0008
int srate_in;
int srate_out;
int bits_in;
int bits_out;
int filler[32];
} oss_digital_control;
/*
* The "new" mixer API.
*
* This improved mixer API makes it possible to access every possible feature
* of every possible device. However you should read the mixer programming
* section of the OSS API Developer's Manual. There is no chance that you
* could use this interface correctly just by examining this header.
*/
#define OSS_VERSION 0x040003
#define SOUND_VERSION OSS_VERSION
typedef struct oss_sysinfo {
char product[32]; /* E.g. SunOS Audio */
char version[32]; /* E.g. 4.0a */
int versionnum; /* See OSS_GETVERSION */
char options[128]; /* NOT SUPPORTED */
int numaudios; /* # of audio/dsp devices */
int openedaudio[8]; /* Mask of audio devices are busy */
int numsynths; /* NOT SUPPORTED, always 0 */
int nummidis; /* NOT SUPPORTED, always 0 */
int numtimers; /* NOT SUPPORTED, always 0 */
int nummixers; /* # of mixer devices */
int openedmidi[8]; /* Mask of midi devices are busy */
int numcards; /* Number of sound cards in the system */
int numaudioengines; /* Number of audio engines in the system */
char license[16]; /* E.g. "GPL" or "CDDL" */
char revision_info[256]; /* For internal use */
int filler[172]; /* For future expansion */
} oss_sysinfo;
typedef struct oss_mixext {
int dev; /* Mixer device number */
int ctrl; /* Extension number */
int type; /* Entry type */
#define MIXT_DEVROOT 0 /* Device root entry */
#define MIXT_GROUP 1 /* Controller group */
#define MIXT_ONOFF 2 /* OFF (0) or ON (1) */
#define MIXT_ENUM 3 /* Enumerated (0 to maxvalue) */
#define MIXT_MONOSLIDER 4 /* Mono slider (0 to 255) */
#define MIXT_STEREOSLIDER 5 /* Stereo slider (dual 0 to 255) */
#define MIXT_MESSAGE 6 /* (Readable) textual message */
#define MIXT_MONOVU 7 /* VU meter value (mono) */
#define MIXT_STEREOVU 8 /* VU meter value (stereo) */
#define MIXT_MONOPEAK 9 /* VU meter peak value (mono) */
#define MIXT_STEREOPEAK 10 /* VU meter peak value (stereo) */
#define MIXT_RADIOGROUP 11 /* Radio button group */
#define MIXT_MARKER 12 /* Separator between entries */
#define MIXT_VALUE 13 /* Decimal value entry */
#define MIXT_HEXVALUE 14 /* Hexadecimal value entry */
#define MIXT_MONODB 15 /* OBSOLETE */
#define MIXT_STEREODB 16 /* OBSOLETE */
#define MIXT_SLIDER 17 /* Slider (mono, 31 bit int range) */
#define MIXT_3D 18
#define MIXT_MONOSLIDER16 19 /* Mono slider (0-32767) */
#define MIXT_STEREOSLIDER16 20 /* Stereo slider (dual 0-32767) */
#define MIXT_MUTE 21 /* Mute=1, unmute=0 */
/* Possible value range (minvalue to maxvalue) */
/* Note that maxvalue may also be smaller than minvalue */
int maxvalue;
int minvalue;
int flags;
#define MIXF_READABLE 0x00000001 /* Has readable value */
#define MIXF_WRITEABLE 0x00000002 /* Has writeable value */
#define MIXF_POLL 0x00000004 /* May change itself */
#define MIXF_HZ 0x00000008 /* Hertz scale */
#define MIXF_STRING 0x00000010 /* Use dynamic extensions for value */
#define MIXF_DYNAMIC 0x00000010 /* Supports dynamic extensions */
#define MIXF_OKFAIL 0x00000020 /* Interpret value as 1=OK, 0=FAIL */
#define MIXF_FLAT 0x00000040 /* NOT SUPPORTED */
#define MIXF_LEGACY 0x00000080 /* NOT SUPPORTED */
#define MIXF_CENTIBEL 0x00000100 /* Centibel (0.1 dB) step size */
#define MIXF_DECIBEL 0x00000200 /* Step size of 1 dB */
#define MIXF_MAINVOL 0x00000400 /* Main volume control */
#define MIXF_PCMVOL 0x00000800 /* PCM output volume control */
#define MIXF_RECVOL 0x00001000 /* PCM recording volume control */
#define MIXF_MONVOL 0x00002000 /* Input->output monitor volume */
#define MIXF_WIDE 0x00004000 /* NOT SUPPORTED */
#define MIXF_DESCR 0x00008000 /* NOT SUPPORTED */
#define MIXF_DISABLE 0x00010000 /* Control has been disabled */
char id[16]; /* Mnemonic ID (internal use) */
int parent; /* Entry# of parent (-1 if root) */
int dummy; /* NOT SUPPORTED */
int timestamp;
char data[64]; /* Misc data (entry type dependent) */
unsigned char enum_present[32]; /* Mask of allowed enum values */
int control_no; /* NOT SUPPORTED, always -1 */
unsigned int desc; /* Scope flags, etc */
#define MIXEXT_SCOPE_MASK 0x0000003f
#define MIXEXT_SCOPE_OTHER 0x00000000
#define MIXEXT_SCOPE_INPUT 0x00000001
#define MIXEXT_SCOPE_OUTPUT 0x00000002
#define MIXEXT_SCOPE_MONITOR 0x00000003
#define MIXEXT_SCOPE_RECSWITCH 0x00000004
char extname[32];
int update_counter;
#ifdef _KERNEL
int filler[6];
int enumbit;
#else
int filler[7];
#endif
} oss_mixext;
typedef struct oss_mixext_root {
char id[16];
char name[48];
} oss_mixext_root;
typedef struct oss_mixer_value {
int dev;
int ctrl;
int value;
int flags; /* Reserved for future use. Initialize to 0 */
int timestamp; /* Must be set to oss_mixext.timestamp */
int filler[8]; /* Reserved for future use. Initialize to 0 */
} oss_mixer_value;
#define OSS_LONGNAME_SIZE 64
#define OSS_LABEL_SIZE 16
#define OSS_DEVNODE_SIZE 32
typedef char oss_longname_t[OSS_LONGNAME_SIZE];
typedef char oss_label_t[OSS_LABEL_SIZE];
typedef char oss_devnode_t[OSS_DEVNODE_SIZE];
typedef struct oss_audioinfo {
int dev; /* Audio device number */
char name[64];
int busy; /* 0, OPEN_READ, OPEN_WRITE, OPEN_READWRITE */
int pid; /* Process ID, not used in SunOS */
int caps; /* PCM_CAP_INPUT, PCM_CAP_OUTPUT */
int iformats; /* Supported input formats */
int oformats; /* Supported output formats */
int magic; /* Internal use only */
char cmd[64]; /* Command using the device (if known) */
int card_number;
int port_number;
int mixer_dev;
int legacy_device; /* Obsolete field. Replaced by devnode */
int enabled; /* 1=enabled, 0=device not ready */
int flags; /* internal use only - no practical meaning */
int min_rate; /* Minimum sample rate */
int max_rate; /* Maximum sample rate */
int min_channels; /* Minimum number of channels */
int max_channels; /* Maximum number of channels */
int binding; /* DSP_BIND_FRONT, etc. 0 means undefined */
int rate_source;
char handle[32];
#define OSS_MAX_SAMPLE_RATES 20 /* Cannot be changed */
unsigned int nrates; /* Array of supported sample rates */
unsigned int rates[OSS_MAX_SAMPLE_RATES];
oss_longname_t song_name; /* Song name (if given) */
oss_label_t label; /* Device label (if given) */
int latency; /* In usecs, -1=unknown */
oss_devnode_t devnode; /* Device special file name (absolute path) */
int next_play_engine;
int next_rec_engine;
int filler[184];
} oss_audioinfo;
typedef struct oss_mixerinfo {
int dev;
char id[16];
char name[32];
int modify_counter;
int card_number;
int port_number;
char handle[32];
int magic; /* Reserved */
int enabled; /* Reserved */
int caps;
#define MIXER_CAP_VIRTUAL 0x00000001
#define MIXER_CAP_LAYOUT_B 0x00000002 /* For internal use only */
#define MIXER_CAP_NARROW 0x00000004 /* Conserve horiz space */
int flags; /* Reserved */
int nrext;
/*
* The priority field can be used to select the default
* (motherboard) mixer device. The mixer with the highest
* priority is the most preferred one. -2 or less means that
* this device cannot be used as the default mixer.
*/
int priority;
oss_devnode_t devnode; /* Device special file name (absolute path) */
int legacy_device;
int filler[245]; /* Reserved */
} oss_mixerinfo;
typedef struct oss_card_info {
int card;
char shortname[16];
char longname[128];
int flags;
char hw_info[400];
int intr_count;
int ack_count;
int filler[154];
} oss_card_info;
typedef struct mixer_info { /* OBSOLETE */
char id[16];
char name[32];
int modify_counter;
int card_number;
int port_number;
char handle[32];
} mixer_info;
#define MAX_PEAK_CHANNELS 128
typedef unsigned short oss_peaks_t[MAX_PEAK_CHANNELS];
/* For use with SNDCTL_DSP_GET_CHNORDER */
#define CHID_UNDEF 0
#define CHID_L 1
#define CHID_R 2
#define CHID_C 3
#define CHID_LFE 4
#define CHID_LS 5
#define CHID_RS 6
#define CHID_LR 7
#define CHID_RR 8
#define CHNORDER_UNDEF 0x0000000000000000ULL
#define CHNORDER_NORMAL 0x0000000087654321ULL
#define OSSIOCPARM_MASK 0x1fff /* parameters must be < 8192 bytes */
#define OSSIOC_VOID 0x00000000 /* no parameters */
#define OSSIOC_OUT 0x20000000 /* copy out parameters */
#define OSSIOC_IN 0x40000000 /* copy in parameters */
#define OSSIOC_INOUT (OSSIOC_IN|OSSIOC_OUT)
#define OSSIOC_SZ(t) ((sizeof (t) & OSSIOCPARM_MASK) << 16)
#define OSSIOC_GETSZ(x) (((x) >> 16) & OSSIOCPARM_MASK)
#define __OSSIO(x, y) ((int)(OSSIOC_VOID|(x<<8)|y))
#define __OSSIOR(x, y, t) ((int)(OSSIOC_OUT|OSSIOC_SZ(t)|(x<<8)|y))
#define __OSSIOW(x, y, t) ((int)(OSSIOC_IN|OSSIOC_SZ(t)|(x<<8)|y))
#define __OSSIOWR(x, y, t) ((int)(OSSIOC_INOUT|OSSIOC_SZ(t)|(x<<8)|y))
#define SNDCTL_SYSINFO __OSSIOR('X', 1, oss_sysinfo)
#define OSS_SYSINFO SNDCTL_SYSINFO /* Old name */
#define SNDCTL_MIX_NRMIX __OSSIOR('X', 2, int)
#define SNDCTL_MIX_NREXT __OSSIOWR('X', 3, int)
#define SNDCTL_MIX_EXTINFO __OSSIOWR('X', 4, oss_mixext)
#define SNDCTL_MIX_READ __OSSIOWR('X', 5, oss_mixer_value)
#define SNDCTL_MIX_WRITE __OSSIOWR('X', 6, oss_mixer_value)
#define SNDCTL_AUDIOINFO __OSSIOWR('X', 7, oss_audioinfo)
#define SNDCTL_MIX_ENUMINFO __OSSIOWR('X', 8, oss_mixer_enuminfo)
#define SNDCTL_MIDIINFO __OSSIO('X', 9)
#define SNDCTL_MIXERINFO __OSSIOWR('X', 10, oss_mixerinfo)
#define SNDCTL_CARDINFO __OSSIOWR('X', 11, oss_card_info)
#define SNDCTL_ENGINEINFO __OSSIOWR('X', 12, oss_audioinfo)
#define SNDCTL_AUDIOINFO_EX __OSSIOWR('X', 13, oss_audioinfo)
#define SNDCTL_MIX_DESCRIPTION __OSSIOWR('X', 14, oss_mixer_enuminfo)
/* ioctl codes 'X', 200-255 are reserved for internal use */
/*
* Few more "globally" available ioctl calls.
*/
#define SNDCTL_SETSONG __OSSIOW('Y', 2, oss_longname_t)
#define SNDCTL_GETSONG __OSSIOR('Y', 2, oss_longname_t)
#define SNDCTL_SETNAME __OSSIOW('Y', 3, oss_longname_t)
#define SNDCTL_SETLABEL __OSSIOW('Y', 4, oss_label_t)
#define SNDCTL_GETLABEL __OSSIOR('Y', 4, oss_label_t)
/*
* IOCTL commands for /dev/dsp
*/
#define SNDCTL_DSP_HALT __OSSIO('P', 0)
#define SNDCTL_DSP_RESET SNDCTL_DSP_HALT /* Old name */
#define SNDCTL_DSP_SYNC __OSSIO('P', 1)
#define SNDCTL_DSP_SPEED __OSSIOWR('P', 2, int)
#define SNDCTL_DSP_STEREO __OSSIOWR('P', 3, int) /* OBSOLETE */
#define SNDCTL_DSP_GETBLKSIZE __OSSIOWR('P', 4, int)
#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT
#define SNDCTL_DSP_CHANNELS __OSSIOWR('P', 6, int)
#define SNDCTL_DSP_POST __OSSIO('P', 8)
#define SNDCTL_DSP_SUBDIVIDE __OSSIOWR('P', 9, int)
#define SNDCTL_DSP_SETFRAGMENT __OSSIOWR('P', 10, int)
#define SNDCTL_DSP_GETFMTS __OSSIOR('P', 11, int) /* Returns a mask */
#define SNDCTL_DSP_SETFMT __OSSIOWR('P', 5, int) /* Selects ONE fmt */
#define SNDCTL_DSP_GETOSPACE __OSSIOR('P', 12, audio_buf_info)
#define SNDCTL_DSP_GETISPACE __OSSIOR('P', 13, audio_buf_info)
#define SNDCTL_DSP_NONBLOCK __OSSIO('P', 14) /* Obsolete */
#define SNDCTL_DSP_GETCAPS __OSSIOR('P', 15, int)
#define SNDCTL_DSP_GETTRIGGER __OSSIOR('P', 16, int)
#define SNDCTL_DSP_SETTRIGGER __OSSIOW('P', 16, int)
#define SNDCTL_DSP_GETIPTR __OSSIOR('P', 17, count_info)
#define SNDCTL_DSP_GETOPTR __OSSIOR('P', 18, count_info)
#define SNDCTL_DSP_SETSYNCRO __OSSIO('P', 21)
#define SNDCTL_DSP_SETDUPLEX __OSSIO('P', 22)
#define SNDCTL_DSP_PROFILE __OSSIOW('P', 23, int) /* OBSOLETE */
#define APF_NORMAL 0 /* Normal applications */
#define APF_NETWORK 1 /* Underruns caused by "external" delay */
#define APF_CPUINTENS 2 /* Underruns caused by "overheating" the CPU */
#define SNDCTL_DSP_GETODELAY __OSSIOR('P', 23, int)
#define SNDCTL_DSP_GETPLAYVOL __OSSIOR('P', 24, int)
#define SNDCTL_DSP_SETPLAYVOL __OSSIOWR('P', 24, int)
#define SNDCTL_DSP_GETERROR __OSSIOR('P', 25, audio_errinfo)
#define SNDCTL_DSP_READCTL __OSSIOWR('P', 26, oss_digital_control)
#define SNDCTL_DSP_WRITECTL __OSSIOWR('P', 27, oss_digital_control)
#define SNDCTL_DSP_SYNCGROUP __OSSIOWR('P', 28, oss_syncgroup)
#define SNDCTL_DSP_SYNCSTART __OSSIOW('P', 29, int)
#define SNDCTL_DSP_COOKEDMODE __OSSIOW('P', 30, int)
#define SNDCTL_DSP_SILENCE __OSSIO('P', 31)
#define SNDCTL_DSP_SKIP __OSSIO('P', 32)
#define SNDCTL_DSP_HALT_INPUT __OSSIO('P', 33)
#define SNDCTL_DSP_RESET_INPUT SNDCTL_DSP_HALT_INPUT /* Old name */
#define SNDCTL_DSP_HALT_OUTPUT __OSSIO('P', 34)
#define SNDCTL_DSP_RESET_OUTPUT SNDCTL_DSP_HALT_OUTPUT /* Old name */
#define SNDCTL_DSP_LOW_WATER __OSSIOW('P', 34, int)
#define SNDCTL_DSP_CURRENT_IPTR __OSSIOR('P', 35, oss_count_t)
#define SNDCTL_DSP_CURRENT_OPTR __OSSIOR('P', 36, oss_count_t)
#define SNDCTL_DSP_GET_RECSRC_NAMES __OSSIOR('P', 37, oss_mixer_enuminfo)
#define SNDCTL_DSP_GET_RECSRC __OSSIOR('P', 38, int)
#define SNDCTL_DSP_SET_RECSRC __OSSIOWR('P', 38, int)
#define SNDCTL_DSP_GET_PLAYTGT_NAMES __OSSIOR('P', 39, oss_mixer_enuminfo)
#define SNDCTL_DSP_GET_PLAYTGT __OSSIOR('P', 40, int)
#define SNDCTL_DSP_SET_PLAYTGT __OSSIOWR('P', 40, int)
#define SNDCTL_DSP_GETRECVOL __OSSIOR('P', 41, int)
#define SNDCTL_DSP_SETRECVOL __OSSIOWR('P', 41, int)
#define SNDCTL_DSP_GET_CHNORDER __OSSIOR('P', 42, unsigned long long)
#define SNDCTL_DSP_SET_CHNORDER __OSSIOWR('P', 42, unsigned long long)
#define SNDCTL_DSP_GETIPEAKS __OSSIOR('P', 43, oss_peaks_t)
#define SNDCTL_DSP_GETOPEAKS __OSSIOR('P', 44, oss_peaks_t)
#define SNDCTL_DSP_POLICY __OSSIOW('P', 45, int) /* See the manual */
#define SNDCTL_DSP_GETCHANNELMASK __OSSIOWR('P', 64, int)
#define SNDCTL_DSP_BIND_CHANNEL __OSSIOWR('P', 65, int)
/*
* These definitions are here for the benefit of compiling application
* code. Most of these are NOT implemented in the Solaris code,
* however. This is the older 3.x OSS API, and only the master input and
* output levels are actually supported.
*/
#define SOUND_MIXER_NRDEVICES 28
#define SOUND_MIXER_VOLUME 0
#define SOUND_MIXER_BASS 1
#define SOUND_MIXER_TREBLE 2
#define SOUND_MIXER_SYNTH 3
#define SOUND_MIXER_PCM 4
#define SOUND_MIXER_SPEAKER 5
#define SOUND_MIXER_LINE 6
#define SOUND_MIXER_MIC 7
#define SOUND_MIXER_CD 8
#define SOUND_MIXER_IMIX 9 /* Recording monitor */
#define SOUND_MIXER_ALTPCM 10
#define SOUND_MIXER_RECLEV 11 /* Recording level */
#define SOUND_MIXER_IGAIN 12 /* Input gain */
#define SOUND_MIXER_OGAIN 13 /* Output gain */
#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */
#define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */
#define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */
#define SOUND_MIXER_DIGITAL1 17 /* Digital I/O 1 */
#define SOUND_MIXER_DIGITAL2 18 /* Digital I/O 2 */
#define SOUND_MIXER_DIGITAL3 19 /* Digital I/O 3 */
#define SOUND_MIXER_PHONE 20 /* Phone */
#define SOUND_MIXER_MONO 21 /* Mono Output */
#define SOUND_MIXER_VIDEO 22 /* Video/TV (audio) in */
#define SOUND_MIXER_RADIO 23 /* Radio in */
#define SOUND_MIXER_DEPTH 24 /* Surround depth */
#define SOUND_MIXER_REARVOL 25 /* Rear/Surround speaker vol */
#define SOUND_MIXER_CENTERVOL 26 /* Center/LFE speaker vol */
#define SOUND_MIXER_SIDEVOL 27 /* Side-Surround (8speaker) vol */
#define SOUND_MIXER_SURRVOL SOUND_MIXER_SIDEVOL
#define SOUND_ONOFF_MIN 28
#define SOUND_ONOFF_MAX 30
#define SOUND_MIXER_NONE 31
#define SOUND_MIXER_RECSRC 0xff /* Recording sources */
#define SOUND_MIXER_DEVMASK 0xfe /* Supported devices */
#define SOUND_MIXER_RECMASK 0xfd /* Recording sources */
#define SOUND_MIXER_CAPS 0xfc /* Mixer capabilities (do not use) */
#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
#define SOUND_MIXER_OUTSRC 0xfa
#define SOUND_MIXER_OUTMASK 0xf9
#define SOUND_MIXER_ENHANCE SOUND_MIXER_NONE
#define SOUND_MIXER_MUTE SOUND_MIXER_NONE
#define SOUND_MIXER_LOUD SOUND_MIXER_NONE
#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME)
#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS)
#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE)
#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH)
#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM)
#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER)
#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE)
#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC)
#define SOUND_MASK_CD (1 << SOUND_MIXER_CD)
#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX)
#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM)
#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV)
#define SOUND_MASK_IGAIN (1 << SOUND_MIXER_IGAIN)
#define SOUND_MASK_OGAIN (1 << SOUND_MIXER_OGAIN)
#define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1)
#define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2)
#define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3)
#define SOUND_MASK_DIGITAL1 (1 << SOUND_MIXER_DIGITAL1)
#define SOUND_MASK_DIGITAL2 (1 << SOUND_MIXER_DIGITAL2)
#define SOUND_MASK_DIGITAL3 (1 << SOUND_MIXER_DIGITAL3)
#define SOUND_MASK_MONO (1 << SOUND_MIXER_MONO)
#define SOUND_MASK_PHONE (1 << SOUND_MIXER_PHONE)
#define SOUND_MASK_RADIO (1 << SOUND_MIXER_RADIO)
#define SOUND_MASK_VIDEO (1 << SOUND_MIXER_VIDEO)
#define SOUND_MASK_DEPTH (1 << SOUND_MIXER_DEPTH)
#define SOUND_MASK_REARVOL (1 << SOUND_MIXER_REARVOL)
#define SOUND_MASK_CENTERVOL (1 << SOUND_MIXER_CENTERVOL)
#define SOUND_MASK_SIDEVOL (1 << SOUND_MIXER_SIDEVOL)
#define SOUND_MASK_SURRVOL SOUND_MASK_SIDEVOL
#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE)
#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE)
#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD)
/*
* Again, DO NOT USE the following two macros. They are here for SOURCE
* COMPATIBILITY ONLY.
*/
#define SOUND_DEVICE_LABELS { \
"Vol ", "Bass ", "Treble", "Synth", "Pcm ", "Speaker ", "Line ", \
"Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \
"Aux1", "Aux2", "Aux3", "Digital1", "Digital2", "Digital3", \
"Phone", "Mono", "Video", "Radio", "Depth", \
"Rear", "Center", "Side" }
#define SOUND_DEVICE_NAMES { \
"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
"mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
"aux1", "aux2", "aux3", "dig1", "dig2", "dig3", \
"phone", "mono", "video", "radio", "depth", \
"rear", "center", "side" }
#define MIXER_READ(dev) __OSSIOR('M', dev, int)
#define MIXER_WRITE(dev) __OSSIOWR('M', dev, int)
#define SOUND_MIXER_INFO __OSSIOR('M', 101, mixer_info)
#define OSS_GETVERSION __OSSIOR('M', 118, int)
/*
* These macros are useful for some applications. They are implemented
* as soft values for the application, and do not affect real hardware.
*/
#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME)
#define SOUND_MIXER_READ_OGAIN MIXER_READ(SOUND_MIXER_OGAIN)
#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM)
#define SOUND_MIXER_READ_IGAIN MIXER_READ(SOUND_MIXER_IGAIN)
#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV)
#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC)
#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK)
#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK)
#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
#define SOUND_MIXER_READ_RECGAIN __OSSIOR('M', 119, int)
#define SOUND_MIXER_READ_MONGAIN __OSSIOR('M', 120, int)
#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
#define SOUND_MIXER_WRITE_OGAIN MIXER_WRITE(SOUND_MIXER_OGAIN)
#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM)
#define SOUND_MIXER_WRITE_IGAIN MIXER_WRITE(SOUND_MIXER_IGAIN)
#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV)
#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC)
#define SOUND_MIXER_WRITE_RECGAIN __OSSIOWR('M', 119, int)
#define SOUND_MIXER_WRITE_MONGAIN __OSSIOWR('M', 120, int)
/*
* These macros are here for source compatibility. They intentionally don't
* map to any real hardware. NOT SUPPORTED!
*/
#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS)
#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE)
#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH)
#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER)
#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE)
#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC)
#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD)
#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX)
#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM)
#define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1)
#define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2)
#define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3)
#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS)
#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE)
#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH)
#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER)
#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE)
#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC)
#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD)
#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX)
#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM)
#define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1)
#define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2)
#define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3)
/*
* Audio encoding types (Note! U8=8 and S16_LE=16 for compatibility)
*/
#define AFMT_QUERY 0x00000000 /* Return current fmt */
#define AFMT_MU_LAW 0x00000001
#define AFMT_A_LAW 0x00000002
#define AFMT_IMA_ADPCM 0x00000004
#define AFMT_U8 0x00000008
#define AFMT_S16_LE 0x00000010
#define AFMT_S16_BE 0x00000020
#define AFMT_S8 0x00000040
#define AFMT_U16_LE 0x00000080
#define AFMT_U16_BE 0x00000100
#define AFMT_MPEG 0x00000200 /* NOT SUPPORTED: MPEG (2) audio */
#define AFMT_AC3 0x00000400 /* NOT SUPPORTED: AC3 compressed */
#define AFMT_VORBIS 0x00000800 /* NOT SUPPORTED: Ogg Vorbis */
#define AFMT_S32_LE 0x00001000
#define AFMT_S32_BE 0x00002000
#define AFMT_FLOAT 0x00004000 /* NOT SUPPORTED: IEEE double float */
#define AFMT_S24_LE 0x00008000 /* LSB aligned in 32 bit word */
#define AFMT_S24_BE 0x00010000 /* LSB aligned in 32 bit word */
#define AFMT_SPDIF_RAW 0x00020000 /* NOT SUPPORTED: Raw S/PDIF frames */
#define AFMT_S24_PACKED 0x00040000 /* 24 bit packed little endian */
/*
* Some big endian/little endian handling macros (native endian and
* opposite endian formats).
*/
#if defined(_BIG_ENDIAN)
#define AFMT_S16_NE AFMT_S16_BE
#define AFMT_U16_NE AFMT_U16_BE
#define AFMT_S32_NE AFMT_S32_BE
#define AFMT_S24_NE AFMT_S24_BE
#define AFMT_S16_OE AFMT_S16_LE
#define AFMT_S32_OE AFMT_S32_LE
#define AFMT_S24_OE AFMT_S24_LE
#else
#define AFMT_S16_NE AFMT_S16_LE
#define AFMT_U16_NE AFMT_U16_LE
#define AFMT_S32_NE AFMT_S32_LE
#define AFMT_S24_NE AFMT_S24_LE
#define AFMT_S16_OE AFMT_S16_BE
#define AFMT_S32_OE AFMT_S32_BE
#define AFMT_S24_OE AFMT_S24_BE
#endif
/*
* SNDCTL_DSP_GETCAPS bits
*/
#define PCM_CAP_REVISION 0x000000ff /* Revision level (0 to 255) */
#define PCM_CAP_DUPLEX 0x00000100 /* Full duplex rec/play */
#define PCM_CAP_REALTIME 0x00000200 /* NOT SUPPORTED */
#define PCM_CAP_BATCH 0x00000400 /* NOT SUPPORTED */
#define PCM_CAP_COPROC 0x00000800 /* NOT SUPPORTED */
#define PCM_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */
#define PCM_CAP_MMAP 0x00002000 /* Supports mmap() */
#define PCM_CAP_MULTI 0x00004000 /* Supports multiple open */
#define PCM_CAP_BIND 0x00008000 /* Supports channel binding */
#define PCM_CAP_INPUT 0x00010000 /* Supports recording */
#define PCM_CAP_OUTPUT 0x00020000 /* Supports playback */
#define PCM_CAP_VIRTUAL 0x00040000 /* Virtual device */
#define PCM_CAP_ANALOGOUT 0x00100000 /* NOT SUPPORTED */
#define PCM_CAP_ANALOGIN 0x00200000 /* NOT SUPPORTED */
#define PCM_CAP_DIGITALOUT 0x00400000 /* NOT SUPPORTED */
#define PCM_CAP_DIGITALIN 0x00800000 /* NOT SUPPORTED */
#define PCM_CAP_ADMASK 0x00f00000 /* NOT SUPPORTED */
#define PCM_CAP_SHADOW 0x01000000 /* "Shadow" device */
#define PCM_CAP_CH_MASK 0x06000000 /* See DSP_CH_MASK below */
#define PCM_CAP_HIDDEN 0x08000000 /* NOT SUPPORTED */
#define PCM_CAP_FREERATE 0x10000000
#define PCM_CAP_MODEM 0x20000000 /* NOT SUPPORTED */
#define PCM_CAP_DEFAULT 0x40000000 /* "Default" device */
/*
* Preferred channel usage. These bits can be used to give
* recommendations to the application. Used by few drivers. For
* example if ((caps & DSP_CH_MASK) == DSP_CH_MONO) means that the
* device works best in mono mode. However it doesn't necessarily mean
* that the device cannot be used in stereo. These bits should only be
* used by special applications such as multi track hard disk
* recorders to find out the initial setup. However the user should be
* able to override this selection.
*
* To find out which modes are actually supported the application
* should try to select them using SNDCTL_DSP_CHANNELS.
*/
#define DSP_CH_MASK 0x06000000 /* Mask */
#define DSP_CH_ANY 0x00000000 /* No preferred mode */
#define DSP_CH_MONO 0x02000000
#define DSP_CH_STEREO 0x04000000
#define DSP_CH_MULTI 0x06000000 /* More than two channels */
/*
* The PCM_CAP_* capability names used to be known as DSP_CAP_*, so
* it's necessary to define the older names too.
*/
#define DSP_CAP_ADMASK PCM_CAP_ADMASK
#define DSP_CAP_ANALOGIN PCM_CAP_ANALOGIN
#define DSP_CAP_ANALOGOUT PCM_CAP_ANALOGOUT
#define DSP_CAP_BATCH PCM_CAP_BATCH
#define DSP_CAP_BIND PCM_CAP_BIND
#define DSP_CAP_COPROC PCM_CAP_COPROC
#define DSP_CAP_DEFAULT PCM_CAP_DEFAULT
#define DSP_CAP_DIGITALIN PCM_CAP_DIGITALIN
#define DSP_CAP_DIGITALOUT PCM_CAP_DIGITALOUT
#define DSP_CAP_DUPLEX PCM_CAP_DUPLEX
#define DSP_CAP_FREERATE PCM_CAP_FREERATE
#define DSP_CAP_HIDDEN PCM_CAP_HIDDEN
#define DSP_CAP_INPUT PCM_CAP_INPUT
#define DSP_CAP_MMAP PCM_CAP_MMAP
#define DSP_CAP_MODEM PCM_CAP_MODEM
#define DSP_CAP_MULTI PCM_CAP_MULTI
#define DSP_CAP_OUTPUT PCM_CAP_OUTPUT
#define DSP_CAP_REALTIME PCM_CAP_REALTIME
#define DSP_CAP_REVISION PCM_CAP_REVISION
#define DSP_CAP_SHADOW PCM_CAP_SHADOW
#define DSP_CAP_TRIGGER PCM_CAP_TRIGGER
#define DSP_CAP_VIRTUAL PCM_CAP_VIRTUAL
/*
* SNDCTL_DSP_GETTRIGGER and SNDCTL_DSP_SETTRIGGER
*/
#define PCM_ENABLE_INPUT 0x00000001
#define PCM_ENABLE_OUTPUT 0x00000002
/*
* SNDCTL_DSP_BIND_CHANNEL
*/
#define DSP_BIND_QUERY 0x00000000
#define DSP_BIND_FRONT 0x00000001
#define DSP_BIND_SURR 0x00000002
#define DSP_BIND_CENTER_LFE 0x00000004
#define DSP_BIND_HANDSET 0x00000008
#define DSP_BIND_MIC 0x00000010
#define DSP_BIND_MODEM1 0x00000020
#define DSP_BIND_MODEM2 0x00000040
#define DSP_BIND_I2S 0x00000080
#define DSP_BIND_SPDIF 0x00000100
#define DSP_BIND_REAR 0x00000200
/*
* SOUND_MIXER_READ_CAPS
*/
#define SOUND_CAP_EXCL_INPUT 0x00000001
#define SOUND_CAP_NOLEGACY 0x00000004
#define SOUND_CAP_NORECSRC 0x00000008
/*
* The following ioctl is for internal use only -- it is used to
* coordinate /dev/sndstat numbering with file names in /dev/sound.
* Applications must not use it. (This is duplicated in sys/audioio.h
* as well.)
*/
#define SNDCTL_SUN_SEND_NUMBER __OSSIOW('X', 200, int)
#ifdef __cplusplus
}
#endif
#endif /* _SYS_AUDIO_OSS_H */
+23 -11
View File
@@ -32,15 +32,6 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
{
AudioDeviceID deviceId = deviceIds[index];
FF_CFTYPE_AUTO_RELEASE CFStringRef name = NULL;
dataSize = sizeof(name);
if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress){
kAudioObjectPropertyName,
kAudioObjectPropertyScopeOutput,
kAudioObjectPropertyElementMain
}, 0, NULL, &dataSize, &name) != kAudioHardwareNoError)
continue;
// Ignore input devices
if(AudioObjectGetPropertyDataSize(deviceId, &(AudioObjectPropertyAddress){
kAudioDevicePropertyStreams,
@@ -71,10 +62,31 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
device->main = deviceId == mainDeviceId;
device->active = false;
device->volume = FF_SOUND_VOLUME_UNKNOWN;
ffStrbufInitF(&device->identifier, "%u", (unsigned) deviceId);
ffStrbufInit(&device->identifier);
ffStrbufInit(&device->name);
ffStrbufInitStatic(&device->platformApi, "Core Audio");
ffCfStrGetString(name, &device->name);
FF_CFTYPE_AUTO_RELEASE CFStringRef uid = NULL;
dataSize = sizeof(uid);
if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress) {
kAudioDevicePropertyDeviceUID,
kAudioObjectPropertyScopeOutput,
kAudioObjectPropertyElementMain
}, 0, NULL, &dataSize, &uid) == kAudioHardwareNoError)
ffCfStrGetString(uid, &device->identifier);
else
ffStrbufAppendF(&device->identifier, "ID-%u", (unsigned) deviceId);
FF_CFTYPE_AUTO_RELEASE CFStringRef name = NULL;
dataSize = sizeof(name);
if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress){
kAudioObjectPropertyName,
kAudioObjectPropertyScopeOutput,
kAudioObjectPropertyElementMain
}, 0, NULL, &dataSize, &name) == kAudioHardwareNoError)
ffCfStrGetString(name, &device->name);
else
ffStrbufSet(&device->name, &device->identifier);
uint32_t muted;
dataSize = sizeof(muted);
+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;
+95
View File
@@ -0,0 +1,95 @@
#include "sound.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include <fcntl.h>
#include <unistd.h>
#if __has_include(<sys/soundcard.h>)
#include <sys/soundcard.h>
#else
// Strangely, they don't provide this file on default installation
#include "audio_oss_sunos.h"
#endif
const char* ffDetectSound(FFlist* devices)
{
int defaultDev;
{
char mixerp[12];
ssize_t plen = readlink("/dev/audio", mixerp, ARRAY_SIZE(mixerp));
if (plen < 6)
return "readlink(/dev/audio) failed";
defaultDev = mixerp[plen - 1] - '0';
if (defaultDev < 0 || defaultDev > 9)
return "Invalid mixer device";
}
char path[] = "/dev/mixer0";
FF_STRBUF_AUTO_DESTROY sndstat = ffStrbufCreate();
struct oss_sysinfo info = { .nummixers = 9 };
// The implementation is very different from *BSD's. They call it OSS4
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 | O_CLOEXEC);
if (fd < 0) break;
if (idev == 0)
{
if (ioctl(fd, SNDCTL_SYSINFO, &info) != 0)
return "ioctl(SNDCTL_SYSINFO) failed";
if (ffAppendFDBuffer(fd, &sndstat))
ffStrbufSubstrAfterFirstS(&sndstat, "\nMixers:");
}
struct oss_mixerinfo mi = {};
if (ioctl(fd, SNDCTL_MIXERINFO, &mi) < 0)
continue;
int volume = -1;
for (int iext = 0; iext < mi.nrext; ++iext)
{
struct oss_mixext me = { .dev = mi.dev, .ctrl = iext };
if (ioctl(fd, SNDCTL_MIX_EXTINFO, &me) < 0)
continue;
if (me.flags & MIXF_PCMVOL)
{
struct oss_mixer_value mv = { .dev = mi.dev, .ctrl = iext, .timestamp = me.timestamp };
if (ioctl(fd, SNDCTL_MIX_READ, &mv) >= 0)
{
mv.value -= me.minvalue;
me.maxvalue -= me.minvalue;
volume = (uint8_t) ((mv.value * 100 + me.maxvalue / 2) / me.maxvalue);
}
break;
}
}
if (volume == -1) continue;
FFSoundDevice* device = ffListAdd(devices);
ffStrbufInitS(&device->identifier, path);
char buf[16];
int bufLen = snprintf(buf, ARRAY_SIZE(buf), "\n%d: ", mi.dev);
assert(bufLen > 3);
const char* pLine = memmem(sndstat.chars, sndstat.length, buf, (size_t) bufLen);
if (pLine)
{
pLine += bufLen;
const char* pEnd = strchr(pLine, '\n');
if (!pEnd) pEnd = sndstat.chars + sndstat.length;
ffStrbufInitNS(&device->name, (uint32_t) (pEnd - pLine), pLine);
}
else
ffStrbufInitS(&device->name, mi.name);
ffStrbufTrimRightSpace(&device->name);
ffStrbufInitF(&device->platformApi, "%s %s", info.product, info.version);
device->volume = (uint8_t) volume;
device->active = !!mi.enabled;
device->main = defaultDev == idev;
}
return NULL;
}
+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;
}
+6 -8
View File
@@ -5,7 +5,7 @@
enum { FFMaxNSwap = 8 };
const char* ffDetectSwap(FFSwapResult* swap)
const char* ffDetectSwap(FFlist* result)
{
char strings[FFMaxNSwap][PATH_MAX];
uint8_t buffer[sizeof(swaptbl_t) + sizeof(swapent_t) * (FFMaxNSwap - 1)] = {};
@@ -18,16 +18,14 @@ const char* ffDetectSwap(FFSwapResult* swap)
if (size < 0)
return "swapctl() failed";
swap->bytesTotal = swap->bytesUsed = 0;
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
for (int i = 0; i < size; ++i)
{
swap->bytesTotal += (uint64_t) table->swt_ent[i].ste_pages;
swap->bytesUsed += (uint64_t) table->swt_ent[i].ste_free;
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitS(&swap->name, table->swt_ent[i].ste_path);
swap->bytesTotal = (uint64_t) table->swt_ent[i].ste_pages * pageSize;
swap->bytesUsed = swap->bytesTotal - (uint64_t) table->swt_ent[i].ste_free * pageSize;
}
swap->bytesUsed = swap->bytesTotal - swap->bytesUsed;
swap->bytesTotal *= instance.state.platform.sysinfo.pageSize;
swap->bytesUsed *= instance.state.platform.sysinfo.pageSize;
return NULL;
}
+9 -6
View File
@@ -1,11 +1,12 @@
#include "swap.h"
#include "util/mallocHelper.h"
#include "util/windows/unicode.h"
#include <winternl.h>
#include <ntstatus.h>
#include <windows.h>
const char* ffDetectSwap(FFSwapResult* swap)
const char* ffDetectSwap(FFlist* result)
{
uint8_t buffer[4096];
ULONG size = sizeof(buffer);
@@ -13,16 +14,18 @@ const char* ffDetectSwap(FFSwapResult* swap)
if(!NT_SUCCESS(NtQuerySystemInformation(SystemPagefileInformation, pstart, size, &size)))
return "NtQuerySystemInformation(SystemPagefileInformation, size) failed";
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
for (SYSTEM_PAGEFILE_INFORMATION* current = pstart; ; current = (SYSTEM_PAGEFILE_INFORMATION*)((uint8_t*) current + current->NextEntryOffset))
{
swap->bytesUsed += current->TotalUsed;
swap->bytesTotal += current->CurrentSize;
FFSwapResult* swap = ffListAdd(result);
ffStrbufInitNWS(&swap->name, current->FileName.Length / sizeof(wchar_t), current->FileName.Buffer);
if (ffStrbufStartsWithS(&swap->name, "\\??\\"))
ffStrbufSubstrAfter(&swap->name, strlen("\\??\\") - 1);
swap->bytesUsed = current->TotalUsed * pageSize;
swap->bytesTotal = current->CurrentSize * pageSize;
if (current->NextEntryOffset == 0)
break;
}
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
swap->bytesUsed *= pageSize;
swap->bytesTotal *= pageSize;
return NULL;
}
+25
View File
@@ -243,6 +243,29 @@ static bool detectContour(const FFstrbuf* exe, FFTerminalFontResult* result)
return true;
}
static bool detectRio(FFTerminalFontResult* terminalFont)
{
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();
FFpropquery fontQueryToml[] = {
{"family =", &fontName},
{"size =", &fontSize},
};
ffParsePropFileConfigValues("rio/config.toml", 2, fontQueryToml);
if(fontName.length == 0)
ffStrbufAppendS(&fontName, "Cascadia Code");
if(fontSize.length == 0)
ffStrbufAppendS(&fontSize, "18");
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
return true;
}
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont);
static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
@@ -257,6 +280,8 @@ static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTermina
detectContour(&terminal->exe, terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "ghostty"))
detectGhostty(terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "rio"))
detectRio(terminalFont);
#ifndef _WIN32
else if(ffStrbufStartsWithIgnCaseS(&terminal->exe, "/dev/pts/"))
@@ -109,6 +109,8 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
ffStrbufEqualS(&result->processName, "chezmoi") || // #762
ffStrbufEqualS(&result->processName, "proot") ||
ffStrbufEqualS(&result->processName, "script") ||
ffStrbufEqualS(&result->processName, "init") ||
ffStrbufEqualS(&result->processName, "systemd") ||
#ifdef __linux__
ffStrbufStartsWithS(&result->processName, "flatpak-") || // #707
#endif
+2 -2
View File
@@ -43,9 +43,9 @@
#elif defined(__FreeBSD__)
#define FF_SYSNAME "FreeBSD"
#elif defined(__APPLE__)
#define FF_SYSNAME "Darwin"
#define FF_SYSNAME "macOS"
#elif defined(_WIN32)
#define FF_SYSNAME "WIN32"
#define FF_SYSNAME "Windows"
#elif defined(__sun)
#define FF_SYSNAME "SunOS"
#elif defined(__OpenBSD__)
+1
View File
@@ -30,6 +30,7 @@ const char* ffDetectWMPlugin(FFstrbuf* pluginName)
!ffStrEqualsIgnCase(comm, "kwm") &&
!ffStrEqualsIgnCase(comm, "chunkwm") &&
!ffStrEqualsIgnCase(comm, "yabai") &&
!ffStrEqualsIgnCase(comm, "aerospace") &&
!ffStrEqualsIgnCase(comm, "rectangle")
) continue;
+125 -1
View File
@@ -128,6 +128,39 @@ static const char* getSway(FFstrbuf* result)
return "Failed to run command `sway --version`";
}
static bool extractI3Version(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
{
int count = 0;
sscanf(line, "%*d.%*d%n", &count);
if (count == 0) return true;
ffStrbufSetNS((FFstrbuf*) userdata, len, line);
return false;
}
static const char* getI3(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("i3", &path);
if (error) return "Failed to find i3 executable path";
ffBinaryExtractStrings(path.chars, extractI3Version, result, (uint32_t) strlen("0.0"));
if (result->length > 0) return NULL;
if (ffProcessAppendStdOut(result, (char* const[]){
path.chars,
"--version",
NULL
}) == NULL)
{ // i3 version 1.10 C 2009...
ffStrbufSubstrAfterFirstS(result, "version ");
ffStrbufSubstrBeforeFirstC(result, ' ');
return NULL;
}
return "Failed to run command `i3 --version`";
}
static const char* getWslg(FFstrbuf* result)
{
if (!ffAppendFileBuffer("/mnt/wslg/versions.txt", result))
@@ -143,19 +176,110 @@ static const char* getWslg(FFstrbuf* result)
return NULL;
}
static bool extractCommonWmVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
{
int count = 0;
sscanf(line, "%*d.%*d.%*d%n", &count);
if (count == 0) return true;
ffStrbufSetNS((FFstrbuf*) userdata, len, line);
return false;
}
static const char* getCtwm(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("ctwm", &path);
if (error) return "Failed to find ctwm executable path";
ffBinaryExtractStrings(path.chars, extractCommonWmVersion, result, (uint32_t) strlen("0.0.0"));
if (result->length > 0) return NULL;
if (ffProcessAppendStdOut(result, (char* const[]){
path.chars,
"--version",
NULL
}) == NULL)
{ // ctwm version 4.0.1\n...
ffStrbufSubstrBeforeFirstC(result, '\n');
ffStrbufSubstrAfterLastC(result, ' ');
return NULL;
}
return "Failed to run command `ctwm --version`";
}
static const char* getFvwm(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("fvwm", &path);
if (error) return "Failed to find fvwm executable path";
ffBinaryExtractStrings(path.chars, extractCommonWmVersion, result, (uint32_t) strlen("0.0.0"));
if (result->length > 0) return NULL;
if (ffProcessAppendStdOut(result, (char* const[]){
path.chars,
"-version",
NULL
}) == NULL)
{ // [FVWM][main]: fvwm Version 2.2.5\n...
ffStrbufSubstrBeforeFirstC(result, '\n');
ffStrbufSubstrAfterLastC(result, ' ');
return NULL;
}
return "Failed to run command `fvwm -version`";
}
static const char* getOpenbox(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("openbox", &path);
if (error) return "Failed to find openbox executable path";
ffBinaryExtractStrings(path.chars, extractCommonWmVersion, result, (uint32_t) strlen("0.0.0"));
if (result->length > 0) return NULL;
if (ffProcessAppendStdOut(result, (char* const[]){
path.chars,
"--version",
NULL
}) == NULL)
{ // Openbox 3.6.1\n...
ffStrbufSubstrBeforeFirstC(result, '\n');
ffStrbufSubstrAfterLastC(result, ' ');
return NULL;
}
return "Failed to run command `openbox --version`";
}
const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options)
{
if (!wmName)
return "No WM detected";
if (ffStrbufEqualS(wmName, "Hyprland"))
if (ffStrbufIgnCaseEqualS(wmName, "Hyprland"))
return getHyprland(result);
if (ffStrbufEqualS(wmName, "sway"))
return getSway(result);
if (ffStrbufEqualS(wmName, "i3"))
return getI3(result);
if (ffStrbufEqualS(wmName, "WSLg"))
return getWslg(result);
if (ffStrbufEqualS(wmName, "ctwm"))
return getCtwm(result);
if (ffStrbufEqualS(wmName, "fvwm"))
return getFvwm(result);
if (ffStrbufEqualS(wmName, "Openbox"))
return getOpenbox(result);
return "Unsupported WM";
}
-4
View File
@@ -2,7 +2,3 @@
#define FASTFETCH_DATATEXT_JSON_HELP @DATATEXT_JSON_HELP@
#define FASTFETCH_DATATEXT_STRUCTURE @DATATEXT_STRUCTURE@
#ifdef __APPLE__
#define FASTFETCH_DATATEXT_NOWPLAYING @DATATEXT_NOWPLAYING@
#endif
+20
View File
@@ -0,0 +1,20 @@
$4#######################
$4# $2##### $4#
$4# $2####### $4#
$4# $2##$5O$2#$5O$2## $4#
$4# $2#$3#####$2# $4#
$4# $2##$1##$3###$1##$2## $4#
$4# $2#$1##########$2## $4#
$4# $2#$1############$2## $4#
$4# $2#$1######$5A_O$1####$2### $4#
$4# $3##$2#$1############$2##$3## $4#
$4#$3######$2#$1#######$2#$3######$4#
$4#$3#######$2#$1#####$2#$3#######$4#
$4# $3#####$2#######$3##### $4#
$4#######################
$4#$5╔═╗╔╗╔╦ ╦╔═╗╦ ╦╔═╗╔═╗$4#
$4#$5╠═╣║║║║ ║╚═╗╠═╣║ ║╚═╗$4#
$4#$5╩ ╩╝╚╝╚═╝╚═╝╩ ╩╚═╝╚═╝$4#
$4#######################
$4# $3WWW.ANUSHOS.ORG $4#
$4#######################
+16
View File
@@ -0,0 +1,16 @@
▂🬭𜴧⎻𜷗𜴗𜴦𜵎⎻𜴧🬭▂
▁▂𜴧━𜵼𜵶𜶮▂🬭🬭𜴐🭗 🬁𜴜🬭🬭▂𜶮▁𜵁━𜴧▂▁
𜷓𜵐🬂🬂🮂𜶮𜴸𜴪━𜴆🮂▔ ▔🮂𜴆━𜴩𜵳𜴸🮂🬂🬂𜶚🬿
🭄🬨▍ 🬜🮂▔ ▁▂▂🬭🬭▂▂▁ ▔🮂🬪 🮈🬕𜶿
🭄🭙▐▎𜵫 🭃██████████🭎 🭢𜶡🮇▌🭤𜶿
🭄🭙 ▐🭄🭙 🭋█████🭜𜴦█████🭀 🭤🭏▌ 🭤🭏
𜵫🭗 🮉🭛 🭃███🭝🭙 🭥🭒███🭎 🭦▋ 🭢𜶡
▟🬮𜴧━🭷🭘 🭋████▄▂ ▂▄████🭀 🭣𜴇━𜴧🬯🭏
🭕𜴸𜴆╾🭺🬽 🭃██🭡 🭖██🭐 🭈𜵡╼𜴆🬡🭠
𜴤🬼 🮉🭀 🭋███΄ 🭤███🭀 🭋▊ 🭇𜵐
𜴠🬾 ▐𜴢🬾▁▁ 🭃██𜴍 𜶘██🭐 ▁▁🭉🭫▌ 🭉🭠
𜴠🬾🮈▎𜶚 ▔🮂🬂▀🬎🬎 🮅🬎▀🬂🮂▔ 𜵐🮇▌🭉𜴏
𜴢🭿▍ 𜴬▂▁ ▁▂🬜΄🮈🬲𜴏
🭥𜶡🬭🬭▂𜶭▁𜵁━𜴧▂▁ ▁▂𜴧━𜶷𜶭𜶮▂🬭🬭𜵫🭚
▔⎺𜴆━𜴩▔𜶮🮂🬂🬂𜴜🬼 🭇𜴐🬂🬂🮂𜶮▔𜴨━𜴆⎺▔
⠈🮂🭷𜴆╾𜶦𜷞🭄𜴬╼𜴆🬂🮂΄
+5 -5
View File
@@ -1,6 +1,6 @@
_________
| __ |
| \ \___ |
| \ _ \ |
| \___/ |
_________
| $2__ $1 |
| $2\ \___ $1 |
| $2 \ _ \$1 |
| $2 \___/$1 |
|_________|

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