mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4dfba31cae | |||
| 3004f29c08 | |||
| b994ce5b55 | |||
| 6356f9d0e5 | |||
| 597c6f3dbc | |||
| 41cffac80c | |||
| c4cb6c65a9 | |||
| 46081a3e52 | |||
| a5fd671b92 | |||
| 8319512c83 | |||
| c1db692982 | |||
| aec2bfd2a4 | |||
| 7bacf20f72 | |||
| 1479de19ef | |||
| bb9ca73db1 | |||
| 81bac8bca4 | |||
| 56d22292b0 | |||
| 9a11ff8ddb | |||
| a99b6d602d | |||
| 40921156b8 | |||
| bc3703140b | |||
| bd5b385909 | |||
| 0fe3db419e | |||
| e80bb480c4 | |||
| d4773212b7 | |||
| 9ebff9fd22 | |||
| 5d8edc0c8b | |||
| 78530b4e34 | |||
| 61f2823903 | |||
| 7446828866 | |||
| 0b37acec5b | |||
| 53ecf57f19 | |||
| e1c4365c10 | |||
| ebc60ac66c | |||
| 4004501d0f | |||
| a0265c3204 | |||
| 3ef84834fc | |||
| 3276949663 | |||
| 1ec69d6838 | |||
| 7f1063d09b | |||
| 883923de4a | |||
| 146981009b | |||
| 060b69293c | |||
| 3345c1e9dd | |||
| 1c8e2e34ba | |||
| 5ab51c07d1 | |||
| eee98e54d0 | |||
| b0340d5581 | |||
| 1124342eda | |||
| 329cb229f8 | |||
| bedb5eb6c5 | |||
| f184f8dab5 | |||
| 7ee0e8726e | |||
| a7347130de | |||
| f3c82ad837 | |||
| 1bde2b31f9 | |||
| 1edc617b55 | |||
| 2bb451d9e4 | |||
| 4588644d39 | |||
| ed94b4c46c | |||
| f96ddb4c10 | |||
| 1b0a65ecf2 | |||
| 33983c5402 | |||
| 8cfee9d693 | |||
| 64568b31d1 | |||
| 02c999725c | |||
| be11013ae2 | |||
| a84c4dc1f4 | |||
| d9455adc7f | |||
| b20aea7ab8 | |||
| 5e770dc8b0 | |||
| 137d5dfe90 | |||
| 655d11c1cc | |||
| e32987c408 | |||
| fa4e11c73b | |||
| e753d4d3a4 | |||
| 75d2c668d0 | |||
| 559082806b | |||
| 6f8d276545 | |||
| 582268f44f | |||
| 9b68674c4f | |||
| badae2ba9d | |||
| dd4f006b5f | |||
| c491c9e8fc | |||
| 094d736d38 | |||
| 22bfaf3c69 | |||
| 980e552eba | |||
| 4a141c3f57 | |||
| 59289bef6c | |||
| 0b02543ef2 | |||
| 3cef51ec4a | |||
| 6d86813647 | |||
| fb267acac3 | |||
| ba3e26f2b4 | |||
| 4f8d8de749 | |||
| 54c5bc5110 | |||
| c6675f82f0 | |||
| afe2c85047 | |||
| 671b11157e | |||
| 78fb55c35c | |||
| 559905da60 | |||
| e093c8aa72 |
+24
-21
@@ -4,13 +4,16 @@ on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
|
||||
|
||||
jobs:
|
||||
spellcheck:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install codespell
|
||||
shell: bash
|
||||
@@ -29,7 +32,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -68,7 +71,7 @@ jobs:
|
||||
ffversion: ${{ steps.ffversion.outputs.ffversion }}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -137,7 +140,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -198,7 +201,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -237,7 +240,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -273,7 +276,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -308,7 +311,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -343,7 +346,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -374,7 +377,7 @@ jobs:
|
||||
name: Musl-amd64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: setup alpine linux
|
||||
uses: jirutka/setup-alpine@master
|
||||
@@ -416,7 +419,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -463,7 +466,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -507,7 +510,7 @@ jobs:
|
||||
name: SunOS-amd64
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/omnios-vm@v1
|
||||
@@ -543,7 +546,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -580,7 +583,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -616,7 +619,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -653,7 +656,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/dragonflybsd-vm@v1
|
||||
@@ -688,7 +691,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -700,7 +703,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
uname -a
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || 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
|
||||
@@ -726,7 +729,7 @@ jobs:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
@@ -788,7 +791,7 @@ jobs:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
|
||||
+61
-2
@@ -1,3 +1,62 @@
|
||||
# 2.50.2
|
||||
|
||||
Bugfixes:
|
||||
* Fixes linglong package detection V2 (#1903, Packages, Linux)
|
||||
* Fixes building with `-DENABLE_SYSTEM_YYJSON=ON` (#1904)
|
||||
* Fixes `showMac` does not honor `defaultRouteOnly` (#1902, LocalIP, Linux)
|
||||
* Fixes failing to acquire default route on Linux in certain cases (#1902, LocalIP, Linux)
|
||||
|
||||
# 2.50.1
|
||||
|
||||
Bugfixes:
|
||||
* Fixes percentage bar not displaying correctly in certain cases
|
||||
* Fixes linglong package detection on Debian 13 (#1899, Packages, Linux)
|
||||
|
||||
# 2.50.0
|
||||
|
||||
Changes:
|
||||
* Keys in JSON configuration files are now case-sensitive, as stated in v2.49.0.
|
||||
* This is a breaking change, but it should not affect most users as long as your config file passes JSON schema validation.
|
||||
* All module config flags have been removed, as stated in v2.49.0.
|
||||
* To configure modules via the command line, use: `echo '{"modules": [{"type":"custom","format":"Hello Fastfetch!"}]}' | fastfetch -c -`.
|
||||
* The percent bar config `display.bar.*` options have been replaced with a more organized, nested object structure.
|
||||
* `display.bar.charElapsed` has been renamed to `display.bar.char.elapsed`.
|
||||
* `display.bar.charTotal` has been renamed to `display.bar.char.total`.
|
||||
* `display.bar.borderLeft` has been renamed to `display.bar.border.left`.
|
||||
* `display.bar.borderRight` has been renamed to `display.bar.border.right`.
|
||||
* The undocumented flag `--load-config` has been removed.
|
||||
* Use `--config` or `-c` instead.
|
||||
* Flashfetch, a simplified fastfetch variant that used a hardcoded module list with direct function calls to reduce startup overhead, has been changed to a version that aims to match neofetch's behavior as closely as possible, for demonstration purposes.
|
||||
* Flashfetch is intended to be built from source (like [st](https://st.suckless.org/)). We do not provide prebuilt binaries in distributions.
|
||||
|
||||
Features:
|
||||
* Added support for reading JSON config from stdin using `--config -` or `-c -`.
|
||||
* Added `display.bar.border.{leftElapsed,rightElapsed}` for using the border as part of the bar content. (#1875)
|
||||
* `display.bar.border: null` has been added as a shorthand to disable bar borders.
|
||||
* Added `display.bar.color.{elapsed,total,border}` to customize the color of the elapsed, total, and border sections of the percent bar.
|
||||
* `display.bar.color: null` has been added as a shorthand to disable bar colors.
|
||||
* Improved Bedrock Linux detection (#1881, OS / Disk, Linux)
|
||||
* Added the command flag `--gen-config-full`, which generates a JSON config file containing all optional module options.
|
||||
* Improved the default IP address display when `localip.showAllIPs` is not set (LocalIP)
|
||||
* For IPv4, the preferred source address (if detected) is shown.
|
||||
* For IPv6, the first GUA or ULA that is not deprecated or temporary is shown.
|
||||
* Added support for interface speed detection on SunOS (LocalIP, SunOS)
|
||||
* Added detection support for Xlibre (#1888, WM, Linux)
|
||||
* Improved the accuracy of color detection (Cursor, macOS)
|
||||
* Improved the proformance of `Nix` package manager detection on macOS by porting optimizations form Linux port (#1893, Packages, macOS)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed custom object inheriting a key from the previous custom object if the key is blank (#1477)
|
||||
* Fixed a possible segfault when parsing color strings in the JSON config (#1878)
|
||||
* Fixed GPU driver detection when DRM is used (GPU, FreeBSD)
|
||||
* Fixed default route detection on DragonFly BSD (LocalIP, DFBSD)
|
||||
* Fixed lliurex detection (#1882, OS, Linux)
|
||||
* Fixed compatibility with `-ffast-math` (#1894)
|
||||
* Fixed physical GPU sometimes being ignored (#1896, GPU, Windows)
|
||||
|
||||
Logos:
|
||||
* Added ObsidianOS (#1890)
|
||||
|
||||
# 2.49.0
|
||||
|
||||
Deprecation Notice:
|
||||
@@ -26,8 +85,8 @@ Features:
|
||||
* Add `--{duration,percent,size,freq,temp}-space-before-unit [always|never]` options to add a space before the unit when printing duration, percent, size, frequency and temperature values
|
||||
* Add `--duration-abbreviation` to abbreviate duration values in custom format
|
||||
* For example: `1 day, 2 hours, 3 mins` will be displayed as `1d 2h 3m`
|
||||
* Add `--percent-with` to pad the percent value with spaces to a fixed width
|
||||
* For example: `--percent-with 3` will display ` 50%` instead of `50%`; useful for aligning percent values in custom format
|
||||
* Add `--percent-width` to pad the percent value with spaces to a fixed width
|
||||
* For example: `--percent-width 3` will display ` 50%` instead of `50%`; useful for aligning percent values in custom format
|
||||
|
||||
Bugfixes:
|
||||
* Improve accuracy of Flatpak count detection (#1856, Packages, Linux)
|
||||
|
||||
+6
-4
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.49.0
|
||||
VERSION 2.50.2
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -474,7 +474,6 @@ set(LIBFASTFETCH_SRC
|
||||
src/modules/wmtheme/wmtheme.c
|
||||
src/modules/zpool/zpool.c
|
||||
src/options/display.c
|
||||
src/options/modules.c
|
||||
src/options/logo.c
|
||||
src/options/general.c
|
||||
src/util/edidHelper.c
|
||||
@@ -548,6 +547,7 @@ if(LINUX)
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_linux.c
|
||||
src/detection/packages/packages_linux.c
|
||||
src/detection/packages/packages_nix.c
|
||||
src/detection/poweradapter/poweradapter_linux.c
|
||||
src/detection/processes/processes_linux.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
@@ -614,6 +614,7 @@ elseif(ANDROID)
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_android.c
|
||||
src/detection/packages/packages_linux.c
|
||||
src/detection/packages/packages_nix.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_linux.c
|
||||
src/detection/sound/sound_nosupport.c
|
||||
@@ -896,7 +897,7 @@ elseif(OpenBSD)
|
||||
elseif(APPLE)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/netif/netif_apple.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/common/sysctl.c
|
||||
@@ -940,6 +941,7 @@ elseif(APPLE)
|
||||
src/detection/opengl/opengl_apple.c
|
||||
src/detection/os/os_apple.m
|
||||
src/detection/packages/packages_apple.c
|
||||
src/detection/packages/packages_nix.c
|
||||
src/detection/poweradapter/poweradapter_apple.c
|
||||
src/detection/processes/processes_bsd.c
|
||||
src/detection/sound/sound_apple.c
|
||||
@@ -1042,7 +1044,7 @@ elseif(SunOS)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/netif/netif_apple.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/detection/battery/battery_nosupport.c
|
||||
|
||||
@@ -36,7 +36,6 @@ Some distributions package outdated versions of fastfetch. Older versions receiv
|
||||
<img src="https://repology.org/badge/vertical-allrepos/fastfetch.svg?columns=2" alt="Packaging status" align="right">
|
||||
</a>
|
||||
|
||||
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (for Ubuntu 22.04 or newer)
|
||||
* Debian: `apt install fastfetch` (for Debian 13 or newer)
|
||||
* Debian / Ubuntu: Download `fastfetch-linux-<proper architecture>.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and double-click it (for Ubuntu 20.04 or newer and Debian 11 or newer).
|
||||
* Arch Linux: `pacman -S fastfetch`
|
||||
@@ -58,7 +57,7 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
|
||||
|
||||
### macOS
|
||||
|
||||
* [HomeBrew](https://formulae.brew.sh/formula/fastfetch#default): `brew install fastfetch`
|
||||
* [Homebrew](https://formulae.brew.sh/formula/fastfetch#default): `brew install fastfetch`
|
||||
* [MacPorts](https://ports.macports.org/port/fastfetch/): `sudo port install fastfetch`
|
||||
|
||||
### Windows
|
||||
@@ -95,7 +94,8 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
|
||||
* 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 <module1>[:<module2>][:<module3>] --format json`
|
||||
* Display help messages: `fastfetch --help`
|
||||
* Generate a config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
|
||||
* Generate a minimal config file: `fastfetch [-s <module1>[:<module2>]] --gen-config [</path/to/config.jsonc>]`
|
||||
* Use: `--gen-config-full` to generate a full config file with all optional options
|
||||
|
||||
## Customization
|
||||
|
||||
|
||||
Vendored
+6
@@ -1,3 +1,9 @@
|
||||
fastfetch (2.49.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.49.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 31 Jul 2025 14:32:59 +0800
|
||||
|
||||
fastfetch (2.48.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.48.0
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
fastfetch_2.48.0_source.buildinfo universe/utils optional
|
||||
fastfetch_2.49.0_source.buildinfo universe/utils optional
|
||||
|
||||
+503
-173
@@ -2,33 +2,41 @@
|
||||
"$schema": "https://json-schema.org/draft-07/schema",
|
||||
"$defs": {
|
||||
"colors": {
|
||||
"type": "string",
|
||||
"description": "https://github.com/fastfetch-cli/fastfetch/wiki/Color-Format-Specification",
|
||||
"examples": [
|
||||
"reset_", "bright_", "dim_", "italic_", "underline_", "blink_", "inverse_", "hidden_", "strike_", "light_",
|
||||
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "default"
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"$comment": "https://github.com/fastfetch-cli/fastfetch/wiki/Color-Format-Specification",
|
||||
"examples": [
|
||||
"reset_", "bright_", "dim_", "italic_", "underline_", "blink_", "inverse_", "hidden_", "strike_", "light_",
|
||||
"black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"$comment": "Disable default color"
|
||||
}
|
||||
]
|
||||
},
|
||||
"key": {
|
||||
"description": "Key of the module",
|
||||
"type": "string"
|
||||
"description": "Key of the module\nOne whitespace character (` `) can be used to hide the key",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"keyColor": {
|
||||
"description": "Color of the module key. Left empty to use `display.color.keys`",
|
||||
"description": "Color of the module key to override the global setting `display.color.key`",
|
||||
"$ref": "#/$defs/colors"
|
||||
},
|
||||
"keyWidth": {
|
||||
"description": "Width of the module key. Use 0 to use `display.keyWidth`",
|
||||
"description": "Width of the module key to override the global setting `display.keyWidth`",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0
|
||||
"minimum": 1
|
||||
},
|
||||
"keyIcon": {
|
||||
"description": "Set the icon to be displayed by `display.keyType: \"icon\"`",
|
||||
"type": "string"
|
||||
},
|
||||
"outputColor": {
|
||||
"description": "Output color of the module. Left empty to use `display.color.output`",
|
||||
"description": "Output color of the module to override the global setting `display.color.output`",
|
||||
"$ref": "#/$defs/colors"
|
||||
},
|
||||
"percentType": {
|
||||
@@ -549,7 +557,7 @@
|
||||
"const": null
|
||||
},
|
||||
{
|
||||
"description": "Set the source file of the logo",
|
||||
"description": "Set the source file of the logo or built-in ASCII art name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
@@ -559,23 +567,67 @@
|
||||
"properties": {
|
||||
"type": {
|
||||
"description": "Set the type of the logo",
|
||||
"enum": [
|
||||
"auto",
|
||||
"builtin",
|
||||
"small",
|
||||
"file",
|
||||
"file-raw",
|
||||
"data",
|
||||
"data-raw",
|
||||
"command-raw",
|
||||
"sixel",
|
||||
"kitty",
|
||||
"kitty-direct",
|
||||
"kitty-icat",
|
||||
"iterm",
|
||||
"chafa",
|
||||
"raw",
|
||||
"none"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "auto",
|
||||
"description": "If something is given, first try built-in, then file. Otherwise detect logo"
|
||||
},
|
||||
{
|
||||
"const": "builtin",
|
||||
"description": "Built-in ASCII art"
|
||||
},
|
||||
{
|
||||
"const": "small",
|
||||
"description": "Built-in ASCII art, small version (not all logos support this option)"
|
||||
},
|
||||
{
|
||||
"const": "file",
|
||||
"description": "Text file, printed with color code replacement"
|
||||
},
|
||||
{
|
||||
"const": "file-raw",
|
||||
"description": "Text file, printed as is"
|
||||
},
|
||||
{
|
||||
"const": "data",
|
||||
"description": "Text data, printed with color code replacement"
|
||||
},
|
||||
{
|
||||
"const": "data-raw",
|
||||
"description": "Text data, printed as is"
|
||||
},
|
||||
{
|
||||
"const": "sixel",
|
||||
"description": "Image file, printed as sixel codes"
|
||||
},
|
||||
{
|
||||
"const": "kitty",
|
||||
"description": "Image file, printed using kitty graphics protocol"
|
||||
},
|
||||
{
|
||||
"const": "kitty-direct",
|
||||
"description": "Image file, tells the terminal emulator to read image data from the specified file"
|
||||
},
|
||||
{
|
||||
"const": "kitty-icat",
|
||||
"description": "Image file, uses `kitten icat` to display the image. Requires binary `kitten` to be installed"
|
||||
},
|
||||
{
|
||||
"const": "iterm",
|
||||
"description": "Image file, uses `iTerm` image protocol"
|
||||
},
|
||||
{
|
||||
"const": "chafa",
|
||||
"description": "Image file, prints `ASCII` art image generated by `libchafa`"
|
||||
},
|
||||
{
|
||||
"const": "raw",
|
||||
"description": "Image file, printed as `raw` binary string image"
|
||||
},
|
||||
{
|
||||
"const": "none",
|
||||
"description": "Disable logo printing"
|
||||
}
|
||||
],
|
||||
"default": "auto"
|
||||
},
|
||||
@@ -627,14 +679,30 @@
|
||||
}
|
||||
},
|
||||
"width": {
|
||||
"type": "integer",
|
||||
"description": "Set the width of the logo (in characters). Required for iTerm image protocol",
|
||||
"minimum": 1
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"description": "Auto detect width (default)"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Set the width of the logo (in characters). Required for some image protocols",
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"height": {
|
||||
"type": "integer",
|
||||
"description": "Set the height of the logo (in characters). Required for iTerm image protocol",
|
||||
"minimum": 1
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"description": "Auto detect width (default)"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Set the height of the logo (in characters). Required for some image protocols",
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"padding": {
|
||||
"type": "object",
|
||||
@@ -700,32 +768,71 @@
|
||||
"canvasMode": {
|
||||
"type": "string",
|
||||
"description": "Determine how colors are used in the output. This value maps to enum ChafaCanvasMode.",
|
||||
"enum": [
|
||||
"TRUECOLOR",
|
||||
"INDEXED_256",
|
||||
"INDEXED_240",
|
||||
"INDEXED_16",
|
||||
"FGBG_BGFG",
|
||||
"FGBG",
|
||||
"INDEXED_8",
|
||||
"INDEXED_16_8"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "TRUECOLOR",
|
||||
"description": "Use 24-bit true colors"
|
||||
},
|
||||
{
|
||||
"const": "INDEXED_256",
|
||||
"description": "Use 256 colors"
|
||||
},
|
||||
{
|
||||
"const": "INDEXED_240",
|
||||
"description": "Use 240 colors, but avoid using the lower 16 whose values vary between terminal environments"
|
||||
},
|
||||
{
|
||||
"const": "INDEXED_16",
|
||||
"description": "Use 16 colors using the aixterm ANSI extension"
|
||||
},
|
||||
{
|
||||
"const": "FGBG_BGFG",
|
||||
"description": "Use default foreground and background colors, plus inversion"
|
||||
},
|
||||
{
|
||||
"const": "FGBG",
|
||||
"description": "Use default foreground and background colors. No ANSI codes will be used"
|
||||
},
|
||||
{
|
||||
"const": "INDEXED_8",
|
||||
"description": "Use 8 colors, compatible with original ANSI X3.64"
|
||||
},
|
||||
{
|
||||
"const": "INDEXED_16_8",
|
||||
"description": "Use 16 FG colors (8 of which enabled with bold/bright) and 8 BG colors"
|
||||
}
|
||||
]
|
||||
},
|
||||
"colorSpace": {
|
||||
"type": "string",
|
||||
"description": "Set color space used for quantization. This value maps to enum ChafaColorSpace.",
|
||||
"enum": [
|
||||
"RGB",
|
||||
"DIN99D"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "RGB",
|
||||
"description": "RGB color space. Fast but imprecise"
|
||||
},
|
||||
{
|
||||
"const": "DIN99D",
|
||||
"description": "DIN99d color space. Slower, but good perceptual color precision"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ditherMode": {
|
||||
"type": "string",
|
||||
"description": "Set output dither mode (No effect with 24-bit color). This value maps to enum ChafaDitherMode.",
|
||||
"enum": [
|
||||
"NONE",
|
||||
"ORDERED",
|
||||
"DIFFUSION"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "NONE",
|
||||
"description": "No dithering"
|
||||
},
|
||||
{
|
||||
"const": "ORDERED",
|
||||
"description": "Ordered dithering (Bayer or similar)"
|
||||
},
|
||||
{
|
||||
"const": "DIFFUSION",
|
||||
"description": "Error diffusion dithering (Floyd-Steinberg or similar)"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -889,11 +996,23 @@
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Set whether to show icon before string keys",
|
||||
"enum": [
|
||||
"none",
|
||||
"string",
|
||||
"icon",
|
||||
"both"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "none",
|
||||
"description": "Disable keys"
|
||||
},
|
||||
{
|
||||
"const": "string",
|
||||
"description": "Show string keys"
|
||||
},
|
||||
{
|
||||
"const": "icon",
|
||||
"description": "Show icon keys (requires newest nerd font)"
|
||||
},
|
||||
{
|
||||
"const": "both",
|
||||
"description": "Show both icon and string keys"
|
||||
}
|
||||
],
|
||||
"default": "string"
|
||||
},
|
||||
@@ -955,7 +1074,24 @@
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"description": "Set the unit of temperature",
|
||||
"enum": ["D", "Default", "Celsius", "C", "Fahrenheit", "F", "Kelvin", "K"],
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "C",
|
||||
"description": "Celsius"
|
||||
},
|
||||
{
|
||||
"const": "F",
|
||||
"description": "Fahrenheit"
|
||||
},
|
||||
{
|
||||
"const": "K",
|
||||
"description": "Kelvin"
|
||||
},
|
||||
{
|
||||
"const": "D",
|
||||
"description": "Default (alias for Celsius)"
|
||||
}
|
||||
],
|
||||
"default": "D"
|
||||
},
|
||||
"ndigits": {
|
||||
@@ -997,25 +1133,87 @@
|
||||
"additionalProperties": false,
|
||||
"description": "Set the bar configuration",
|
||||
"properties": {
|
||||
"charElapsed": {
|
||||
"type": "string",
|
||||
"description": "Set the character to use in elapsed part",
|
||||
"default": "■"
|
||||
"char": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Set the characters used in the bar",
|
||||
"properties": {
|
||||
"elapsed": {
|
||||
"type": "string",
|
||||
"description": "Set the character to use in elapsed part",
|
||||
"default": "■"
|
||||
},
|
||||
"total": {
|
||||
"type": "string",
|
||||
"description": "Set the character to use in total part",
|
||||
"default": "-"
|
||||
}
|
||||
}
|
||||
},
|
||||
"charTotal": {
|
||||
"type": "string",
|
||||
"description": "Set the character to use in total part",
|
||||
"default": "-"
|
||||
"border": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"description": "Disable bar borders"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Set the string to use of borders of percentage bars",
|
||||
"properties": {
|
||||
"left": {
|
||||
"type": "string",
|
||||
"description": "Set the string to use at left border",
|
||||
"default": "[ "
|
||||
},
|
||||
"right": {
|
||||
"type": "string",
|
||||
"description": "Set the string to use at right border",
|
||||
"default": " ]"
|
||||
},
|
||||
"leftElapsed": {
|
||||
"type": "string",
|
||||
"description": "If both leftElapsed and rightElapsed are set, the border will be used as parts of bar content",
|
||||
"default": ""
|
||||
},
|
||||
"rightElapsed": {
|
||||
"type": "string",
|
||||
"description": "If both leftElapsed and rightElapsed are set, the border will be used as parts of bar content",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"borderLeft": {
|
||||
"type": "string",
|
||||
"description": "Set the string to use at left border",
|
||||
"default": "[ "
|
||||
},
|
||||
"borderRight": {
|
||||
"type": "string",
|
||||
"description": "Set the string to use at right border",
|
||||
"default": " ]"
|
||||
"color": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"description": "Disable color in percentage bars"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Set the color to use of percentage bars",
|
||||
"properties": {
|
||||
"elapsed": {
|
||||
"description": "Color to use in the elapsed part of percentage bars\nBy default, auto selected by percent.color.{green,yellow,red}",
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "auto"
|
||||
},
|
||||
"total": {
|
||||
"description": "Color to use in the total part of percentage bars",
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "light_white"
|
||||
},
|
||||
"border": {
|
||||
"description": "Color to use in the borders of percentage bars",
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "light_white"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"width": {
|
||||
"type": "integer",
|
||||
@@ -1739,14 +1937,35 @@
|
||||
"symbol": {
|
||||
"description": "Set the symbol to use",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"block",
|
||||
"background",
|
||||
"circle",
|
||||
"diamond",
|
||||
"triangle",
|
||||
"square",
|
||||
"star"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "block",
|
||||
"description": "\u2588\u2588\u2588"
|
||||
},
|
||||
{
|
||||
"const": "background",
|
||||
"description": "(whitespaces with background)"
|
||||
},
|
||||
{
|
||||
"const": "circle",
|
||||
"description": "\u25cf"
|
||||
},
|
||||
{
|
||||
"const": "diamond",
|
||||
"description": "\u25c6"
|
||||
},
|
||||
{
|
||||
"const": "triangle",
|
||||
"description": "\u25b2"
|
||||
},
|
||||
{
|
||||
"const": "square",
|
||||
"description": "\u25a0"
|
||||
},
|
||||
{
|
||||
"const": "star",
|
||||
"description": "\u2605"
|
||||
}
|
||||
],
|
||||
"default": "background"
|
||||
},
|
||||
@@ -1783,9 +2002,15 @@
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
},
|
||||
"keyColor": {
|
||||
"$ref": "#/$defs/keyColor"
|
||||
},
|
||||
"keyIcon": {
|
||||
"$ref": "#/$defs/keyIcon"
|
||||
},
|
||||
"keyWidth": {
|
||||
"$ref": "#/$defs/keyWidth"
|
||||
},
|
||||
"condition": {
|
||||
"$ref": "#/$defs/conditions"
|
||||
}
|
||||
@@ -1805,7 +2030,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"param": {
|
||||
"description": "Set the parameter used when starting the shell\nDefault: /c for Windows, -c for *nix",
|
||||
"description": "Set the parameter used when starting the shell\nIf set to an empty string, it will be ignored\nDefault: /c for Windows, -c for *nix",
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
@@ -1949,15 +2174,34 @@
|
||||
"const": "display"
|
||||
},
|
||||
"compactType": {
|
||||
"enum": [
|
||||
"none",
|
||||
"original",
|
||||
"scaled",
|
||||
"original-with-refresh-rate",
|
||||
"scaled-with-refresh-rate"
|
||||
],
|
||||
"description": "Set if all displays should be printed in one line",
|
||||
"default": "none"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": null,
|
||||
"description": "Disable compact mode"
|
||||
},
|
||||
{
|
||||
"const": "none",
|
||||
"description": "Disable compact mode (kept for compatibility)"
|
||||
},
|
||||
{
|
||||
"const": "original",
|
||||
"description": "Print original resolutions"
|
||||
},
|
||||
{
|
||||
"const": "scaled",
|
||||
"description": "Print scaled resolutions"
|
||||
},
|
||||
{
|
||||
"const": "original-with-refresh-rate",
|
||||
"description": "Print original resolutions with refresh rates"
|
||||
},
|
||||
{
|
||||
"const": "scaled-with-refresh-rate",
|
||||
"description": "Print scaled resolutions with refresh rates"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
},
|
||||
"preciseRefreshRate": {
|
||||
"description": "Set if decimal refresh rates should not be rounded into integers when printing",
|
||||
@@ -1966,12 +2210,25 @@
|
||||
},
|
||||
"order": {
|
||||
"description": "Set the order should be used when printing",
|
||||
"enum": [
|
||||
"none",
|
||||
"asc",
|
||||
"desc"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": null,
|
||||
"description": "Use the default order"
|
||||
},
|
||||
{
|
||||
"const": "none",
|
||||
"description": "Use the detected order (kept for compatibility)"
|
||||
},
|
||||
{
|
||||
"const": "asc",
|
||||
"description": "Sort by display name in ascending order"
|
||||
},
|
||||
{
|
||||
"const": "desc",
|
||||
"description": "Sort by display name in descending order"
|
||||
}
|
||||
],
|
||||
"default": "none"
|
||||
"default": null
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
@@ -2018,6 +2275,11 @@
|
||||
"type": "string",
|
||||
"description": "A colon separated file systems to hide from the disk output"
|
||||
},
|
||||
"showRegular": {
|
||||
"type": "boolean",
|
||||
"description": "Set if regular volume should be printed",
|
||||
"default": true
|
||||
},
|
||||
"showExternal": {
|
||||
"type": "boolean",
|
||||
"description": "Set if external volume should be printed",
|
||||
@@ -2045,7 +2307,7 @@
|
||||
},
|
||||
"useAvailable": {
|
||||
"type": "boolean",
|
||||
"description": "Use f_bavail (lpFreeBytesAvailableToCaller for Windows) instead of f_bfree to calculate used bytes",
|
||||
"description": "Use f_bavail (lpFreeBytesAvailableToCaller for Windows) instead of f_bfree to calculate used bytes\nMay be required for macOS to display correct results",
|
||||
"default": false
|
||||
},
|
||||
"percent": {
|
||||
@@ -2132,8 +2394,8 @@
|
||||
},
|
||||
"slowVersionDetection": {
|
||||
"type": "boolean",
|
||||
"description": "Set if DE version should be detected with slow operations.\nShould be unnecessary for most cases.",
|
||||
"default": "false"
|
||||
"description": "Set if DE version should be detected with slow operations.\nShould be unnecessary for most cases.\nThis is only used as a fallback method. Please file a bug report if you encounter any issues.",
|
||||
"default": false
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
@@ -2168,10 +2430,19 @@
|
||||
"description": "Print DNS servers"
|
||||
},
|
||||
"showType": {
|
||||
"enum": [
|
||||
"ipv4",
|
||||
"ipv6",
|
||||
"both"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "ipv4",
|
||||
"description": "Show IPv4 addresses only"
|
||||
},
|
||||
{
|
||||
"const": "ipv6",
|
||||
"description": "Show IPv6 addresses only"
|
||||
},
|
||||
{
|
||||
"const": "both",
|
||||
"description": "Show both IPv4 and IPv6 addresses"
|
||||
}
|
||||
],
|
||||
"default": "both",
|
||||
"description": "Specify the type of DNS servers should be detected"
|
||||
@@ -2317,31 +2588,65 @@
|
||||
"$ref": "#/$defs/temperature"
|
||||
},
|
||||
"driverSpecific": {
|
||||
"description": "Use driver specific method to detect more detailed GPU information (memory usage, core count, etc)",
|
||||
"description": "Use driver specific method to detect more detailed GPU information (memory usage, core count, etc)\nRequires the latest GPU drivers to be installed.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"detectionMethod": {
|
||||
"description": "Force using a specified method to detect GPUs",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"pci",
|
||||
"vulkan",
|
||||
"opencl",
|
||||
"opengl"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "auto",
|
||||
"description": "Query platform-specific graphics APIs.\nRequires proper GPU drivers to be installed.\nSupported on Linux, FreeBSD, Windows and macOS"
|
||||
},
|
||||
{
|
||||
"const": "pci",
|
||||
"description": "Search PCI devices, which does not require GPU drivers to be installed.\nNot supported on Windows and macOS"
|
||||
},
|
||||
{
|
||||
"const": "vulkan",
|
||||
"description": "Use Vulkan API.\nSlow and requires proper Vulkan drivers to be installed.\nUsed for Android"
|
||||
},
|
||||
{
|
||||
"const": "opencl",
|
||||
"description": "Use OpenCL API.\nSlow and requires proper OpenCL drivers to be installed"
|
||||
},
|
||||
{
|
||||
"const": "opengl",
|
||||
"description": "Use OpenGL API.\nSlow and only detects one GPU.\nUsed for OpenBSD"
|
||||
}
|
||||
],
|
||||
"default": "auto"
|
||||
"default": "<varies-by-platform>"
|
||||
},
|
||||
"hideType": {
|
||||
"description": "Specify the type of GPUs should not be printed",
|
||||
"enum": [
|
||||
"integrated",
|
||||
"discrete",
|
||||
"unknown",
|
||||
"none"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": null,
|
||||
"description": "Do not hide any GPUs"
|
||||
},
|
||||
{
|
||||
"const": "none",
|
||||
"description": "Do not hide any GPUs (kept for compatibility)"
|
||||
},
|
||||
{
|
||||
"const": "integrated",
|
||||
"description": "Hide integrated GPUs"
|
||||
},
|
||||
{
|
||||
"const": "discrete",
|
||||
"description": "Hide discrete GPUs"
|
||||
},
|
||||
{
|
||||
"const": "unknown",
|
||||
"description": "Hide unknown (unrecognized) GPUs"
|
||||
}
|
||||
],
|
||||
"default": "none"
|
||||
"default": null
|
||||
},
|
||||
"percent": {
|
||||
"$ref": "#/$defs/percent"
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
@@ -2600,7 +2905,7 @@
|
||||
"default": true
|
||||
},
|
||||
"showAllIps": {
|
||||
"description": "Show all IPs bound to the same interface.\nBy default only the first IP is shown",
|
||||
"description": "Show all IPs bound to the same interface.\nBy default only the firstly detected IP is shown",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
@@ -2619,7 +2924,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"defaultRouteOnly": {
|
||||
"description": "Show ips that are used for default routing only",
|
||||
"description": "Show ips that are used for default routing only\nDoesn't work on Android",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
@@ -2867,7 +3172,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"defaultRouteOnly": {
|
||||
"description": "Show ips that are used for default routing only",
|
||||
"description": "Show ips that are used for default routing only\nDoesn't work on Android",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
@@ -2878,7 +3183,7 @@
|
||||
},
|
||||
"waitTime": {
|
||||
"type": "integer",
|
||||
"description": "Wait time (in ms). Disk I/O = (totalBytesEnd - totalBytesStart) / waitTime",
|
||||
"description": "Wait time (in ms). Net I/O = (totalBytesEnd - totalBytesStart) / waitTime",
|
||||
"default": 200,
|
||||
"minimum": 1
|
||||
},
|
||||
@@ -2948,10 +3253,19 @@
|
||||
},
|
||||
"library": {
|
||||
"description": "Set the OpenGL context creation library to use",
|
||||
"enum": [
|
||||
"auto",
|
||||
"egl",
|
||||
"glx"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "auto",
|
||||
"description": "Prefer EGL on *nix; prefer platform-specific implementation on others"
|
||||
},
|
||||
{
|
||||
"const": "egl",
|
||||
"description": "Use EGL, which works on TTY"
|
||||
},
|
||||
{
|
||||
"const": "glx",
|
||||
"description": "Use GLX, requires X session (*nix only)"
|
||||
}
|
||||
],
|
||||
"default": "auto"
|
||||
},
|
||||
@@ -3020,44 +3334,51 @@
|
||||
"description": "List installed package managers and count of installed packages"
|
||||
},
|
||||
"disabled": {
|
||||
"description": "List of package managers to be disabled when detecting",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"am",
|
||||
"apk",
|
||||
"brew",
|
||||
"choco",
|
||||
"dpkg",
|
||||
"emerge",
|
||||
"eopkg",
|
||||
"flatpak",
|
||||
"guix",
|
||||
"hpkg",
|
||||
"linglong",
|
||||
"lpkg",
|
||||
"lpkgbuild",
|
||||
"macports",
|
||||
"mport",
|
||||
"nix",
|
||||
"opkg",
|
||||
"pacman",
|
||||
"pacstall",
|
||||
"paludis",
|
||||
"pisi",
|
||||
"pkg",
|
||||
"pkgtool",
|
||||
"qi",
|
||||
"rpm",
|
||||
"scoop",
|
||||
"snap",
|
||||
"sorcery",
|
||||
"winget",
|
||||
"xbps"
|
||||
],
|
||||
"uniqueItems": true
|
||||
},
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "List of package managers to be disabled when detecting\nWarning: Some detection methods can be very slow.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"am",
|
||||
"apk",
|
||||
"brew",
|
||||
"choco",
|
||||
"dpkg",
|
||||
"emerge",
|
||||
"eopkg",
|
||||
"flatpak",
|
||||
"guix",
|
||||
"hpkg",
|
||||
"linglong",
|
||||
"lpkg",
|
||||
"lpkgbuild",
|
||||
"macports",
|
||||
"mport",
|
||||
"nix",
|
||||
"opkg",
|
||||
"pacman",
|
||||
"pacstall",
|
||||
"paludis",
|
||||
"pisi",
|
||||
"pkg",
|
||||
"pkgtool",
|
||||
"rpm",
|
||||
"scoop",
|
||||
"snap",
|
||||
"sorcery",
|
||||
"winget",
|
||||
"xbps"
|
||||
],
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Enable all package managers",
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": ["winget"]
|
||||
},
|
||||
"combined": {
|
||||
@@ -3271,10 +3592,10 @@
|
||||
"default": "http://ipinfo.io/ip"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Time in milliseconds to wait for the public ip server to respond",
|
||||
"description": "Time in milliseconds to wait for the public ip server to respond.\n0 to disable timeout",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": "disabled (0)"
|
||||
"default": 0
|
||||
},
|
||||
"ipv6": {
|
||||
"description": "Whether to use IPv6 for public IP detection server",
|
||||
@@ -3377,10 +3698,19 @@
|
||||
"soundType": {
|
||||
"description": "Set what type of sound devices should be printed",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"main",
|
||||
"active",
|
||||
"all"
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "main",
|
||||
"description": "Print only main sound devices"
|
||||
},
|
||||
{
|
||||
"const": "active",
|
||||
"description": "Print only active sound devices"
|
||||
},
|
||||
{
|
||||
"const": "all",
|
||||
"description": "Print all sound devices"
|
||||
}
|
||||
],
|
||||
"default": "main"
|
||||
},
|
||||
@@ -3878,14 +4208,14 @@
|
||||
"const": "weather"
|
||||
},
|
||||
"location": {
|
||||
"description": "The location to display",
|
||||
"description": "The location to display\nMust be URI encoded (e.g., a whitespace must be encoded as \"+\")",
|
||||
"type": "string"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Time in milliseconds to wait for the weather server to respond",
|
||||
"description": "Time in milliseconds to wait for the weather server to respond.\n0 to disable timeout",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": "disabled (0)"
|
||||
"default": 0
|
||||
},
|
||||
"outputFormat": {
|
||||
"description": "The output weather format to be used (must be URI encoded)",
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
"type": ["bar", "hide-others"]
|
||||
},
|
||||
"bar": {
|
||||
"borderLeft": "",
|
||||
"borderRight": "",
|
||||
"charElapsed": "█",
|
||||
"charTotal": "░",
|
||||
"border": null,
|
||||
"char": {
|
||||
"elapsed": "█",
|
||||
"total": "░"
|
||||
},
|
||||
"width": 40
|
||||
},
|
||||
"constants": [
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"type": "small"
|
||||
},
|
||||
"display": {
|
||||
"separator": " ",
|
||||
"key": {
|
||||
"type": "both"
|
||||
},
|
||||
"bar": {
|
||||
"border": {
|
||||
"left": "\uee00",
|
||||
"leftElapsed": "\uee03",
|
||||
"right": "\uee02",
|
||||
"rightElapsed": "\uee05"
|
||||
},
|
||||
"char": {
|
||||
"total": "\uee01",
|
||||
"elapsed": "\uee04"
|
||||
},
|
||||
"color": {
|
||||
"total": null
|
||||
}
|
||||
},
|
||||
"percent": {
|
||||
"type": [
|
||||
"bar",
|
||||
"bar-monochrome"
|
||||
]
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"title",
|
||||
"separator",
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "MEM"
|
||||
},
|
||||
{
|
||||
"type": "swap",
|
||||
"key": "SWP"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "DSK"
|
||||
},
|
||||
{
|
||||
"type": "battery",
|
||||
"key": "BAT"
|
||||
},
|
||||
{
|
||||
"type": "brightness",
|
||||
"key": "BGT"
|
||||
},
|
||||
{
|
||||
"type": "colors",
|
||||
"paddingLeft": 6,
|
||||
"symbol": "circle"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// #1887
|
||||
{
|
||||
"$schema": "file:///Users/carter/fastfetch/doc/json_schema.json",
|
||||
"logo": null,
|
||||
"display": {
|
||||
"constants": [
|
||||
"\u001b[s\u001b[33C│\u001b[u",
|
||||
" » "
|
||||
],
|
||||
"separator": "",
|
||||
"percent": {
|
||||
"type": ["num", "bar"]
|
||||
},
|
||||
"brightColor": false,
|
||||
"bar": {
|
||||
"border": {
|
||||
"left": "[",
|
||||
"leftElapsed": "[",
|
||||
"right": "]",
|
||||
"rightElapsed": "]"
|
||||
},
|
||||
"char": {
|
||||
"elapsed": "─",
|
||||
"total": "─"
|
||||
},
|
||||
"color": {
|
||||
"elapsed": "default",
|
||||
"total": "light_black"
|
||||
},
|
||||
"width": 16
|
||||
},
|
||||
"color": {
|
||||
"separator": "default",
|
||||
"keys": "default",
|
||||
"output": "default"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"title",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}OS{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "│ {$1}",
|
||||
"format": "{size-percentage-bar} {size-percentage}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "│ {$1}",
|
||||
"format": "{size-used} / {size-total}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}UI{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "wmtheme",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "display",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{width}x{height} @ {refresh-rate} Hz"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}HW{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "cpu",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{percentage-bar} {percentage}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│ {$1}",
|
||||
"format": "{used} / {total}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -8,8 +8,10 @@
|
||||
"width": 11
|
||||
},
|
||||
"bar": {
|
||||
"charElapsed": "=",
|
||||
"charTotal": "-",
|
||||
"char": {
|
||||
"elapsed": "=",
|
||||
"total": "-"
|
||||
},
|
||||
"width": 13
|
||||
},
|
||||
"percent": {
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
"display": {
|
||||
"size": {
|
||||
"maxPrefix": "MB",
|
||||
"ndigits": 0
|
||||
"ndigits": 0,
|
||||
"spaceBeforeUnit": "never"
|
||||
},
|
||||
"freq": {
|
||||
"ndigits": 3,
|
||||
"spaceBeforeUnit": "never"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
@@ -39,11 +44,12 @@
|
||||
"cpu",
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "GPU"
|
||||
"key": "GPU",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"format": "{} / {}"
|
||||
"format": "{used} / {total}"
|
||||
},
|
||||
"break",
|
||||
"colors"
|
||||
|
||||
+43
-29
@@ -10,21 +10,8 @@
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffParseModuleOptions(const char* key, const char* value)
|
||||
{
|
||||
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
|
||||
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (baseInfo->parseCommandOptions(baseInfo, key, value)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffPrepareCommandOption(FFdata* data)
|
||||
{
|
||||
FFOptionsModules* const options = &instance.config.modules;
|
||||
//If we don't have a custom structure, use the default one
|
||||
if(data->structure.length == 0)
|
||||
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
|
||||
@@ -33,54 +20,78 @@ void ffPrepareCommandOption(FFdata* data)
|
||||
ffPrepareCPUUsage();
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME))
|
||||
ffPrepareDiskIO(&options->diskIo);
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME))
|
||||
ffPrepareNetIO(&options->netIo);
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
|
||||
if(instance.config.general.multithreading)
|
||||
{
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
|
||||
ffPreparePublicIp(&options->publicIP);
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
|
||||
ffPrepareWeather(&options->weather);
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonConfig(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
|
||||
static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
|
||||
{
|
||||
yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules");
|
||||
if (!modules)
|
||||
modules = yyjson_mut_obj_add_arr(doc, doc->root, "modules");
|
||||
|
||||
yyjson_mut_val* module = yyjson_mut_obj(doc);
|
||||
FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
|
||||
ffStrbufLowerCase(&type);
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
|
||||
|
||||
if (baseInfo->generateJsonConfig)
|
||||
baseInfo->generateJsonConfig(baseInfo, doc, module);
|
||||
if (instance.state.fullConfig)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_obj(doc);
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
|
||||
|
||||
if (yyjson_mut_obj_size(module) > 1)
|
||||
yyjson_mut_arr_add_val(modules, module);
|
||||
if (baseInfo->generateJsonConfig)
|
||||
baseInfo->generateJsonConfig(options, doc, module);
|
||||
|
||||
if (yyjson_mut_obj_size(module) > 1)
|
||||
yyjson_mut_arr_add_val(modules, module);
|
||||
else
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
else
|
||||
{
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
|
||||
static void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
baseInfo->generateJsonResult(baseInfo, doc, module);
|
||||
baseInfo->generateJsonResult(options, doc, module);
|
||||
else
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
}
|
||||
|
||||
static void parseStructureCommand(
|
||||
const char* line,
|
||||
void (*fn)(FFModuleBaseInfo *baseInfo, yyjson_mut_doc* jsonDoc),
|
||||
void (*fn)(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* jsonDoc),
|
||||
yyjson_mut_doc* jsonDoc
|
||||
)
|
||||
{
|
||||
@@ -91,10 +102,13 @@ static void parseStructureCommand(
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(line, baseInfo->name))
|
||||
{
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (__builtin_expect(jsonDoc != NULL, false))
|
||||
fn(baseInfo, jsonDoc);
|
||||
fn(baseInfo, optionBuf, jsonDoc);
|
||||
else
|
||||
baseInfo->printModule(baseInfo);
|
||||
baseInfo->printModule(optionBuf);
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ typedef struct FFdata
|
||||
bool configLoaded;
|
||||
} FFdata;
|
||||
|
||||
bool ffParseModuleOptions(const char* key, const char* value);
|
||||
void ffPrepareCommandOption(FFdata* data);
|
||||
void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc);
|
||||
void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc);
|
||||
|
||||
+2
-2
@@ -113,8 +113,8 @@ static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start,
|
||||
static inline bool formatArgSet(const FFformatarg* arg)
|
||||
{
|
||||
return arg->value != NULL && (
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) || //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_DOUBLE && *(double*)arg->value > 0.0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
|
||||
|
||||
+2
-8
@@ -25,6 +25,7 @@ static void initState(FFstate* state)
|
||||
state->logoHeight = 0;
|
||||
state->keysHeight = 0;
|
||||
state->terminalLightTheme = false;
|
||||
state->titleFqdn = false;
|
||||
|
||||
ffPlatformInit(&state->platform);
|
||||
state->configDoc = NULL;
|
||||
@@ -42,14 +43,13 @@ static void defaultConfig(void)
|
||||
{
|
||||
ffOptionsInitLogo(&instance.config.logo);
|
||||
ffOptionsInitGeneral(&instance.config.general);
|
||||
ffOptionsInitModules(&instance.config.modules);
|
||||
ffOptionsInitDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
void ffInitInstance(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
//https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendations&view=msvc-170#utf-8-support
|
||||
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
|
||||
setlocale(LC_ALL, ".UTF8");
|
||||
#else
|
||||
// Never use `setlocale(LC_ALL, "")`
|
||||
@@ -96,11 +96,6 @@ static void chldSignalHandler(FF_MAYBE_UNUSED int signal)
|
||||
|
||||
void ffStart(void)
|
||||
{
|
||||
#ifdef FF_START_DETECTION_THREADS
|
||||
if(instance.config.general.multithreading)
|
||||
startDetectionThreads();
|
||||
#endif
|
||||
|
||||
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe && !instance.state.resultDoc;
|
||||
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
|
||||
|
||||
@@ -150,7 +145,6 @@ static void destroyConfig(void)
|
||||
{
|
||||
ffOptionsDestroyLogo(&instance.config.logo);
|
||||
ffOptionsDestroyGeneral(&instance.config.general);
|
||||
ffOptionsDestroyModules(&instance.config.modules);
|
||||
ffOptionsDestroyDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
|
||||
+45
-30
@@ -12,52 +12,57 @@
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffJsonConfigParseModuleArgs(const char* key, yyjson_val* val, FFModuleArgs* moduleArgs)
|
||||
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs)
|
||||
{
|
||||
if(ffStrEqualsIgnCase(key, "key"))
|
||||
if (unsafe_yyjson_equals_str(key, "type") || unsafe_yyjson_equals_str(key, "condition"))
|
||||
return true;
|
||||
|
||||
if (unsafe_yyjson_equals_str(key, "key"))
|
||||
{
|
||||
ffStrbufSetNS(&moduleArgs->key, (uint32_t) yyjson_get_len(val), yyjson_get_str(val));
|
||||
ffStrbufSetJsonVal(&moduleArgs->key, val);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "format"))
|
||||
else if (unsafe_yyjson_equals_str(key, "format"))
|
||||
{
|
||||
ffStrbufSetNS(&moduleArgs->outputFormat, (uint32_t) yyjson_get_len(val), yyjson_get_str(val));
|
||||
ffStrbufSetJsonVal(&moduleArgs->outputFormat, val);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "outputColor"))
|
||||
else if (unsafe_yyjson_equals_str(key, "outputColor"))
|
||||
{
|
||||
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->outputColor);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "keyColor"))
|
||||
else if (unsafe_yyjson_equals_str(key, "keyColor"))
|
||||
{
|
||||
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->keyColor);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "keyWidth"))
|
||||
else if (unsafe_yyjson_equals_str(key, "keyWidth"))
|
||||
{
|
||||
moduleArgs->keyWidth = (uint32_t) yyjson_get_uint(val);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "keyIcon"))
|
||||
else if (unsafe_yyjson_equals_str(key, "keyIcon"))
|
||||
{
|
||||
ffStrbufSetS(&moduleArgs->keyIcon, yyjson_get_str(val));
|
||||
ffStrbufSetJsonVal(&moduleArgs->keyIcon, val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* defaultModuleArgs, FFModuleArgs* moduleArgs)
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs)
|
||||
{
|
||||
if (!ffStrbufEqual(&defaultModuleArgs->key, &moduleArgs->key))
|
||||
if (moduleArgs->key.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "key", &moduleArgs->key);
|
||||
if (!ffStrbufEqual(&defaultModuleArgs->outputFormat, &moduleArgs->outputFormat))
|
||||
if (moduleArgs->outputFormat.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "format", &moduleArgs->outputFormat);
|
||||
if (!ffStrbufEqual(&defaultModuleArgs->keyColor, &moduleArgs->keyColor))
|
||||
if (moduleArgs->outputColor.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "outputColor", &moduleArgs->outputColor);
|
||||
if (moduleArgs->keyColor.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "keyColor", &moduleArgs->keyColor);
|
||||
if (moduleArgs->keyWidth != defaultModuleArgs->keyWidth)
|
||||
if (moduleArgs->keyWidth > 0)
|
||||
yyjson_mut_obj_add_uint(doc, module, "keyWidth", moduleArgs->keyWidth);
|
||||
if (!ffStrbufEqual(&defaultModuleArgs->keyIcon, &moduleArgs->keyIcon))
|
||||
if (moduleArgs->keyIcon.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "keyIcon", &moduleArgs->keyIcon);
|
||||
}
|
||||
|
||||
@@ -96,12 +101,12 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p
|
||||
return "Invalid enum value type; must be a string or integer";
|
||||
}
|
||||
|
||||
static inline void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
|
||||
static inline void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
baseInfo->generateJsonResult(baseInfo, doc, module);
|
||||
baseInfo->generateJsonResult(options, doc, module);
|
||||
else
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
}
|
||||
@@ -115,11 +120,14 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(type, baseInfo->name))
|
||||
{
|
||||
if (jsonVal) baseInfo->parseJsonObject(baseInfo, jsonVal);
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (jsonVal) baseInfo->parseJsonObject(optionBuf, jsonVal);
|
||||
if (__builtin_expect(jsonDoc != NULL, false))
|
||||
genJsonResult(baseInfo, jsonDoc);
|
||||
genJsonResult(baseInfo, optionBuf, jsonDoc);
|
||||
else
|
||||
baseInfo->printModule(baseInfo);
|
||||
baseInfo->printModule(optionBuf);
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -128,7 +136,6 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
|
||||
|
||||
static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
{
|
||||
FFconfig* cfg = &instance.config;
|
||||
switch (type[0])
|
||||
{
|
||||
case 'b': case 'B': {
|
||||
@@ -139,32 +146,40 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
case 'd': case 'D': {
|
||||
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME))
|
||||
{
|
||||
if (module) cfg->modules.diskIo.moduleInfo.parseJsonObject(&cfg->modules.diskIo, module);
|
||||
ffPrepareDiskIO(&cfg->modules.diskIo);
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
if (module) ffDiskIOModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'n': case 'N': {
|
||||
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME))
|
||||
{
|
||||
if (module) cfg->modules.netIo.moduleInfo.parseJsonObject(&cfg->modules.netIo, module);
|
||||
ffPrepareNetIO(&cfg->modules.netIo);
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
if (module) ffNetIOModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': case 'P': {
|
||||
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME))
|
||||
{
|
||||
if (module) cfg->modules.publicIP.moduleInfo.parseJsonObject(&cfg->modules.publicIP, module);
|
||||
ffPreparePublicIp(&cfg->modules.publicIP);
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
if (module) ffPublicIPModuleInfo.parseJsonObject(&options, module);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'w': case 'W': {
|
||||
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME))
|
||||
{
|
||||
if (module) cfg->modules.weather.moduleInfo.parseJsonObject(&cfg->modules.weather, module);
|
||||
ffPrepareWeather(&cfg->modules.weather);
|
||||
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
if (module) ffWeatherModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
bool ffJsonConfigParseModuleArgs(const char* key, yyjson_val* val, FFModuleArgs* moduleArgs);
|
||||
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs);
|
||||
const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[]);
|
||||
void ffPrintJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc);
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* defaultModuleArgs, FFModuleArgs* moduleArgs);
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs);
|
||||
|
||||
yyjson_api_inline yyjson_mut_val* yyjson_mut_strbuf(yyjson_mut_doc *doc, const FFstrbuf* buf) {
|
||||
return yyjson_mut_strncpy(doc, buf->chars, buf->length);
|
||||
|
||||
+74
-74
@@ -1,69 +1,69 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/modules.h"
|
||||
|
||||
static FFModuleBaseInfo* A[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* B[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.battery,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.bios,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.bluetooth,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.bluetoothRadio,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.board,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.bootmgr,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.break_,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.brightness,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.btrfs,
|
||||
&ffBatteryModuleInfo,
|
||||
&ffBiosModuleInfo,
|
||||
&ffBluetoothModuleInfo,
|
||||
&ffBluetoothRadioModuleInfo,
|
||||
&ffBoardModuleInfo,
|
||||
&ffBootmgrModuleInfo,
|
||||
&ffBreakModuleInfo,
|
||||
&ffBrightnessModuleInfo,
|
||||
&ffBtrfsModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* C[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.camera,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.chassis,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.command,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.colors,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.cpu,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.cpuCache,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.cpuUsage,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.cursor,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.custom,
|
||||
&ffCameraModuleInfo,
|
||||
&ffChassisModuleInfo,
|
||||
&ffCommandModuleInfo,
|
||||
&ffColorsModuleInfo,
|
||||
&ffCPUModuleInfo,
|
||||
&ffCPUCacheModuleInfo,
|
||||
&ffCPUUsageModuleInfo,
|
||||
&ffCursorModuleInfo,
|
||||
&ffCustomModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* D[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.dateTime,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.de,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.display,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.disk,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.diskIo,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.dns,
|
||||
&ffDateTimeModuleInfo,
|
||||
&ffDEModuleInfo,
|
||||
&ffDisplayModuleInfo,
|
||||
&ffDiskModuleInfo,
|
||||
&ffDiskIOModuleInfo,
|
||||
&ffDNSModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* E[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.editor,
|
||||
&ffEditorModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* F[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.font,
|
||||
&ffFontModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* G[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.gamepad,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.gpu,
|
||||
&ffGamepadModuleInfo,
|
||||
&ffGPUModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* H[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.host,
|
||||
&ffHostModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* I[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.icons,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.initSystem,
|
||||
&ffIconsModuleInfo,
|
||||
&ffInitSystemModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -72,47 +72,47 @@ static FFModuleBaseInfo* J[] = {
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* K[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.kernel,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.keyboard,
|
||||
&ffKernelModuleInfo,
|
||||
&ffKeyboardModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* L[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.lm,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.loadavg,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.locale,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.localIP,
|
||||
&ffLMModuleInfo,
|
||||
&ffLoadavgModuleInfo,
|
||||
&ffLocaleModuleInfo,
|
||||
&ffLocalIPModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* M[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.media,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.memory,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.monitor,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.mouse,
|
||||
&ffMediaModuleInfo,
|
||||
&ffMemoryModuleInfo,
|
||||
&ffMonitorModuleInfo,
|
||||
&ffMouseModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* N[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.netIo,
|
||||
&ffNetIOModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* O[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.openCL,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.openGL,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.os,
|
||||
&ffOpenCLModuleInfo,
|
||||
&ffOpenGLModuleInfo,
|
||||
&ffOSModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* P[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.packages,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.physicalDisk,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.physicalMemory,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.player,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.powerAdapter,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.processes,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.publicIP,
|
||||
&ffPackagesModuleInfo,
|
||||
&ffPhysicalDiskModuleInfo,
|
||||
&ffPhysicalMemoryModuleInfo,
|
||||
&ffPlayerModuleInfo,
|
||||
&ffPowerAdapterModuleInfo,
|
||||
&ffProcessesModuleInfo,
|
||||
&ffPublicIPModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -125,42 +125,42 @@ static FFModuleBaseInfo* R[] = {
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* S[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.separator,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.shell,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.sound,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.swap,
|
||||
&ffSeparatorModuleInfo,
|
||||
&ffShellModuleInfo,
|
||||
&ffSoundModuleInfo,
|
||||
&ffSwapModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* T[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.terminal,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.terminalFont,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.terminalSize,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.terminalTheme,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.title,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.theme,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.tpm,
|
||||
&ffTerminalModuleInfo,
|
||||
&ffTerminalFontModuleInfo,
|
||||
&ffTerminalSizeModuleInfo,
|
||||
&ffTerminalThemeModuleInfo,
|
||||
&ffTitleModuleInfo,
|
||||
&ffThemeModuleInfo,
|
||||
&ffTPMModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* U[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.uptime,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.users,
|
||||
&ffUptimeModuleInfo,
|
||||
&ffUsersModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* V[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.version,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.vulkan,
|
||||
&ffVersionModuleInfo,
|
||||
&ffVulkanModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* W[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.wallpaper,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.weather,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.wm,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.wifi,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.wmTheme,
|
||||
&ffWallpaperModuleInfo,
|
||||
&ffWeatherModuleInfo,
|
||||
&ffWMModuleInfo,
|
||||
&ffWifiModuleInfo,
|
||||
&ffWMThemeModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -173,7 +173,7 @@ static FFModuleBaseInfo* Y[] = {
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* Z[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.zpool,
|
||||
&ffZpoolModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
+13
-20
@@ -2,30 +2,23 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#else
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex);
|
||||
enum { IF_INDEX_UNINITIALIZED = (uint32_t) -1, IF_INDEX_INVALID = (uint32_t) -2 };
|
||||
static uint32_t ifIndex = IF_INDEX_UNINITIALIZED;
|
||||
static char ifName[IF_NAMESIZE + 1];
|
||||
|
||||
static inline void init()
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void)
|
||||
{
|
||||
if (ifIndex == (uint32_t) IF_INDEX_UNINITIALIZED && !ffNetifGetDefaultRouteImpl(ifName, &ifIndex))
|
||||
ifIndex = (uint32_t) IF_INDEX_INVALID;
|
||||
static FFNetifDefaultRouteResult result;
|
||||
if (result.status == FF_NETIF_UNINITIALIZED) {
|
||||
result.status = ffNetifGetDefaultRouteImplV4(&result) ? FF_NETIF_OK : FF_NETIF_INVALID;
|
||||
}
|
||||
return &result;
|
||||
}
|
||||
|
||||
const char* ffNetifGetDefaultRouteIfName()
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void)
|
||||
{
|
||||
init();
|
||||
return ifName;
|
||||
}
|
||||
|
||||
uint32_t ffNetifGetDefaultRouteIfIndex()
|
||||
{
|
||||
init();
|
||||
return ifIndex;
|
||||
static FFNetifDefaultRouteResult result;
|
||||
if (result.status == FF_NETIF_UNINITIALIZED) {
|
||||
result.status = ffNetifGetDefaultRouteImplV6(&result) ? FF_NETIF_OK : FF_NETIF_INVALID;
|
||||
}
|
||||
return &result;
|
||||
}
|
||||
|
||||
@@ -2,5 +2,29 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
const char* ffNetifGetDefaultRouteIfName();
|
||||
uint32_t ffNetifGetDefaultRouteIfIndex();
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFNetifDefaultRouteResultStatus {
|
||||
FF_NETIF_UNINITIALIZED,
|
||||
FF_NETIF_INVALID,
|
||||
FF_NETIF_OK
|
||||
} FFNetifDefaultRouteResultStatus;
|
||||
|
||||
typedef struct FFNetifDefaultRouteResult {
|
||||
uint32_t ifIndex;
|
||||
|
||||
#ifndef _WIN32
|
||||
char ifName[IF_NAMESIZE + 1];
|
||||
uint32_t preferredSourceAddrV4;
|
||||
#endif
|
||||
enum FFNetifDefaultRouteResultStatus status;
|
||||
} FFNetifDefaultRouteResult;
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result);
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result);
|
||||
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void);
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void);
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#include "netif.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
|
||||
#if __APPLE__
|
||||
// https://github.com/apple-oss-distributions/network_cmds/blob/8f38231438e6a4d16ef8015e97e12c2c05105644/rtsol.tproj/if.c#L243
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(uint32_t))
|
||||
#elif __sun
|
||||
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L339
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#else
|
||||
#error unknown platform
|
||||
#endif
|
||||
|
||||
static struct sockaddr *
|
||||
get_rt_address(struct rt_msghdr *rtm, int desired)
|
||||
{
|
||||
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
|
||||
|
||||
for (int i = 0; i < RTAX_MAX; i++)
|
||||
{
|
||||
if (rtm->rtm_addrs & (1 << i))
|
||||
{
|
||||
if ((1 << i) == desired)
|
||||
return sa;
|
||||
|
||||
#ifndef __sun
|
||||
uint32_t salen = sa->sa_len;
|
||||
#else
|
||||
uint32_t salen;
|
||||
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L2941
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
salen = sizeof (struct sockaddr_in);
|
||||
break;
|
||||
case AF_LINK:
|
||||
salen = sizeof (struct sockaddr_dl);
|
||||
break;
|
||||
case AF_INET6:
|
||||
salen = sizeof (struct sockaddr_in6);
|
||||
break;
|
||||
default:
|
||||
salen = sizeof (struct sockaddr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
sa = (struct sockaddr *)(ROUNDUP(salen) + (char *)sa);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET);
|
||||
if (pfRoute < 0)
|
||||
return false;
|
||||
|
||||
{
|
||||
struct timeval timeout = {1, 0};
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
int pid = getpid();
|
||||
|
||||
struct {
|
||||
struct rt_msghdr hdr;
|
||||
struct sockaddr_in dst;
|
||||
uint8_t data[512];
|
||||
} rtmsg = {
|
||||
.hdr = {
|
||||
.rtm_type = RTM_GET,
|
||||
.rtm_flags = RTF_UP | RTF_GATEWAY,
|
||||
.rtm_version = RTM_VERSION,
|
||||
.rtm_addrs = RTA_DST | RTA_IFP | RTA_IFA,
|
||||
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
|
||||
.rtm_pid = pid,
|
||||
.rtm_seq = 1,
|
||||
},
|
||||
.dst = {
|
||||
.sin_family = AF_INET,
|
||||
#ifndef __sun
|
||||
.sin_len = sizeof(rtmsg.dst),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
|
||||
return false;
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid))
|
||||
;
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
if (sdl
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
// Get the preferred source address
|
||||
struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(&rtmsg.hdr, RTA_IFA);
|
||||
if (src && src->sin_family == AF_INET)
|
||||
result->preferredSourceAddrV4 = src->sin_addr.s_addr;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
|
||||
if (pfRoute < 0)
|
||||
return false;
|
||||
|
||||
{
|
||||
struct timeval timeout = {1, 0};
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
int pid = getpid();
|
||||
|
||||
struct {
|
||||
struct rt_msghdr hdr;
|
||||
struct sockaddr_in6 dst;
|
||||
uint8_t data[512];
|
||||
} rtmsg = {
|
||||
.hdr = {
|
||||
.rtm_type = RTM_GET,
|
||||
.rtm_flags = RTF_UP | RTF_GATEWAY,
|
||||
.rtm_version = RTM_VERSION,
|
||||
.rtm_addrs = RTA_DST | RTA_IFP,
|
||||
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
|
||||
.rtm_pid = pid,
|
||||
.rtm_seq = 2,
|
||||
},
|
||||
.dst = {
|
||||
.sin6_family = AF_INET6,
|
||||
#ifndef __sun
|
||||
.sin6_len = sizeof(rtmsg.dst),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
|
||||
return false;
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == pid))
|
||||
;
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
if (sdl
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -8,25 +8,24 @@
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
#elif defined(__NetBSD__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
#elif defined(__OpenBSD__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
#elif defined(__sun)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), _SS_ALIGNSIZE)
|
||||
#if __DragonFly__
|
||||
// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/cf0aa2f1e47a3f0a6055fe427563cb3f3e627064/sys/net/route.h#L315C9-L315C19
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#elif __FreeBSD__
|
||||
// https://github.com/freebsd/freebsd-src/blob/e4c0ecba44b20ebb2e4d80978c2cb6d16b730cb9/sys/net/route.h#L368C9-L368C16
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#elif __NetBSD__
|
||||
// https://github.com/NetBSD/src/blob/29beb637d057520c0ed37ac2cde966f7cc0cadf4/sys/net/route.h#L330
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
|
||||
#elif __OpenBSD__
|
||||
// https://github.com/openbsd/src/blob/ca647cfa4ec3ccb8360714bc0ebc32a394f7fb6a/regress/sys/netinet/bindconnect/bindconnect.c#L250
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#else
|
||||
# error unknown platform
|
||||
#error unknown platform
|
||||
#endif
|
||||
|
||||
static struct sockaddr *
|
||||
@@ -40,23 +39,18 @@ get_rt_address(struct rt_msghdr *rtm, int desired)
|
||||
{
|
||||
if ((1 << i) == desired)
|
||||
return sa;
|
||||
#ifdef __sun
|
||||
sa = (struct sockaddr *)(ROUNDUP(sizeof(struct sockaddr)) + (char *)sa);
|
||||
#else
|
||||
sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY};
|
||||
size_t needed;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0)
|
||||
return false;
|
||||
|
||||
FF_AUTO_FREE char* buf = malloc(needed);
|
||||
@@ -71,80 +65,62 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
|
||||
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && (sa->sa_family == AF_INET))
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET))
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl->sdl_family == AF_LINK)
|
||||
if (sdl && sdl->sdl_family == AF_LINK)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(iface, sdl->sdl_data, sdl->sdl_nlen);
|
||||
iface[sdl->sdl_nlen] = '\0';
|
||||
*ifIndex = sdl->sdl_index;
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
// Get the preferred source address
|
||||
struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(rtm, RTA_IFA);
|
||||
if (src && src->sin_family == AF_INET)
|
||||
result->preferredSourceAddrV4 = src->sin_addr.s_addr;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET);
|
||||
if (pfRoute < 0)
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY};
|
||||
size_t needed;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0)
|
||||
return false;
|
||||
|
||||
{
|
||||
struct timeval timeout = {1, 0};
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
FF_AUTO_FREE char* buf = malloc(needed);
|
||||
|
||||
int pid = getpid();
|
||||
|
||||
struct {
|
||||
struct rt_msghdr hdr;
|
||||
struct sockaddr_in dst;
|
||||
uint8_t data[512];
|
||||
} rtmsg = {
|
||||
.hdr = {
|
||||
.rtm_type = RTM_GET,
|
||||
.rtm_flags = RTF_UP | RTF_GATEWAY,
|
||||
.rtm_version = RTM_VERSION,
|
||||
.rtm_addrs = RTA_DST | RTA_IFP,
|
||||
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
|
||||
.rtm_pid = pid,
|
||||
.rtm_seq = 1,
|
||||
},
|
||||
.dst = {
|
||||
.sin_family = AF_INET,
|
||||
#ifndef __sun
|
||||
.sin_len = sizeof(rtmsg.dst),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
if (write(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen) != rtmsg.hdr.rtm_msglen)
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
|
||||
return false;
|
||||
|
||||
while (read(pfRoute, &rtmsg, sizeof(rtmsg)) > 0)
|
||||
char* lim = buf + needed;
|
||||
struct rt_msghdr* rtm;
|
||||
for (char* next = buf; next < lim; next += rtm->rtm_msglen)
|
||||
{
|
||||
if (rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid)
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
|
||||
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET6))
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
if (sdl
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
)
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl && sdl->sdl_family == AF_LINK)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(iface, sdl->sdl_data, sdl->sdl_nlen);
|
||||
iface[sdl->sdl_nlen] = '\0';
|
||||
*ifIndex = sdl->sdl_index;
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
|
||||
// loosely based on Haiku's src/bin/network/route/route.cpp
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
// TODO: AF_INET6
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET);
|
||||
if (pfRoute < 0)
|
||||
return false;
|
||||
@@ -42,8 +41,11 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
|
||||
while (interface < end) {
|
||||
if (interface->ifr_route.flags & RTF_DEFAULT) {
|
||||
strlcpy(iface, interface->ifr_name, IF_NAMESIZE);
|
||||
*ifIndex = if_nametoindex(interface->ifr_name);
|
||||
// interface->ifr_metric?
|
||||
strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
|
||||
result->ifIndex = if_nametoindex(interface->ifr_name);
|
||||
if (interface->ifr_route.source)
|
||||
result->preferredSourceAddrV4 = ((struct sockaddr_in*)interface->ifr_route.source)->sin_addr.s_addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,9 +57,56 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
if (interface->ifr_route.gateway != NULL)
|
||||
addressSize += interface->ifr_route.gateway->sa_len;
|
||||
|
||||
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE
|
||||
+ sizeof(struct route_entry) + addressSize);
|
||||
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET6);
|
||||
if (pfRoute < 0)
|
||||
return false;
|
||||
|
||||
struct ifconf config;
|
||||
config.ifc_len = sizeof(config.ifc_value);
|
||||
if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0)
|
||||
return false;
|
||||
|
||||
int size = config.ifc_value;
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
FF_AUTO_FREE void *buffer = malloc((size_t) size);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.ifc_len = size;
|
||||
config.ifc_buf = buffer;
|
||||
if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
|
||||
return false;
|
||||
|
||||
struct ifreq *interface = (struct ifreq*)buffer;
|
||||
struct ifreq *end = (struct ifreq*)((uint8_t*)buffer + size);
|
||||
|
||||
while (interface < end) {
|
||||
if (interface->ifr_route.flags & RTF_DEFAULT) {
|
||||
strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
|
||||
result->ifIndex = if_nametoindex(interface->ifr_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t addressSize = 0;
|
||||
if (interface->ifr_route.destination != NULL)
|
||||
addressSize += interface->ifr_route.destination->sa_len;
|
||||
if (interface->ifr_route.mask != NULL)
|
||||
addressSize += interface->ifr_route.mask->sa_len;
|
||||
if (interface->ifr_route.gateway != NULL)
|
||||
addressSize += interface->ifr_route.gateway->sa_len;
|
||||
|
||||
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+383
-32
@@ -1,52 +1,403 @@
|
||||
#include "netif.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
|
||||
static bool getDefaultRouteIPv4(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/route", "r");
|
||||
if (!netRoute) return false;
|
||||
FF_DEBUG("Starting IPv4 default route detection");
|
||||
|
||||
// skip first line
|
||||
FF_UNUSED(fscanf(netRoute, "%*[^\n]\n"));
|
||||
|
||||
unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu, ...
|
||||
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", iface, &destination) == 2)
|
||||
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
if (destination != 0) continue;
|
||||
*ifIndex = if_nametoindex(iface);
|
||||
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
|
||||
|
||||
unsigned pid = (unsigned) getpid();
|
||||
FF_DEBUG("Process PID: %u", pid);
|
||||
|
||||
// Bind socket
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Let kernel choose PID
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Successfully bound socket");
|
||||
|
||||
struct __attribute__((__packed__)) {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtmsg rtm;
|
||||
struct rtattr rta;
|
||||
uint32_t table;
|
||||
} req = {
|
||||
// Netlink message header
|
||||
.nlh = {
|
||||
.nlmsg_len = sizeof(req),
|
||||
.nlmsg_type = RTM_GETROUTE,
|
||||
.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
|
||||
.nlmsg_seq = 1,
|
||||
.nlmsg_pid = pid,
|
||||
},
|
||||
// Route message
|
||||
.rtm = {
|
||||
.rtm_family = AF_INET,
|
||||
.rtm_dst_len = 0, // Match all destinations
|
||||
.rtm_src_len = 0, // Match all sources
|
||||
.rtm_tos = 0,
|
||||
.rtm_table = RT_TABLE_UNSPEC,
|
||||
.rtm_protocol = RTPROT_UNSPEC,
|
||||
.rtm_scope = RT_SCOPE_UNIVERSE,
|
||||
.rtm_type = RTN_UNSPEC,
|
||||
.rtm_flags = 0,
|
||||
},
|
||||
// Route attribute for main table
|
||||
.rta = {
|
||||
.rta_len = RTA_LENGTH(sizeof(uint32_t)),
|
||||
.rta_type = RTA_TABLE,
|
||||
},
|
||||
.table = RT_TABLE_MAIN,
|
||||
};
|
||||
|
||||
struct sockaddr_nl dest_addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Kernel
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0,
|
||||
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
|
||||
|
||||
if (sent != sizeof(req)) {
|
||||
FF_DEBUG("Failed to send netlink request: sent=%zd, expected=%zu", sent, sizeof(req));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Sent netlink request: %zd bytes", sent);
|
||||
|
||||
struct sockaddr_nl src_addr = {};
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
|
||||
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
|
||||
|
||||
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr*)&src_addr, &src_addr_len);
|
||||
|
||||
if (received < 0) {
|
||||
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (received >= (ssize_t)sizeof(buffer)) {
|
||||
FF_DEBUG("Failed to receive complete message (possible truncation)");
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Received netlink response: %zd bytes", received);
|
||||
|
||||
struct {
|
||||
uint32_t metric;
|
||||
uint32_t ifindex;
|
||||
uint32_t prefsrc;
|
||||
} entry;
|
||||
uint32_t minMetric = UINT32_MAX;
|
||||
int routeCount = 0;
|
||||
|
||||
for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
|
||||
NLMSG_OK(nlh, received);
|
||||
nlh = NLMSG_NEXT(nlh, received)) {
|
||||
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid)
|
||||
continue;
|
||||
if (nlh->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
FF_DEBUG("Received NLMSG_DONE, processed %d routes", routeCount);
|
||||
break;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(nlh);
|
||||
FF_DEBUG("Netlink reports error: %s", strerror(-err->error));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type != RTM_NEWROUTE)
|
||||
continue;
|
||||
|
||||
routeCount++;
|
||||
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
|
||||
if (rtm->rtm_family != AF_INET)
|
||||
continue;
|
||||
|
||||
if (rtm->rtm_dst_len != 0)
|
||||
continue;
|
||||
|
||||
FF_DEBUG("Processing IPv4 default route candidate #%d", routeCount);
|
||||
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
|
||||
|
||||
// Parse route attributes
|
||||
size_t rtm_len = RTM_PAYLOAD(nlh);
|
||||
for (struct rtattr* rta = RTM_RTA(rtm);
|
||||
RTA_OK(rta, rtm_len);
|
||||
rta = RTA_NEXT(rta, rtm_len))
|
||||
{
|
||||
if (RTA_PAYLOAD(rta) < sizeof(uint32_t))
|
||||
continue; // Skip invalid attributes
|
||||
|
||||
uint32_t rta_data = *(uint32_t*) RTA_DATA(rta);
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
FF_DEBUG("Unexpected RTA_DST: %s (len=%u)", inet_ntoa((struct in_addr) { .s_addr = rta_data }), rtm->rtm_dst_len);
|
||||
goto next;
|
||||
case RTA_OIF:
|
||||
entry.ifindex = rta_data;
|
||||
FF_DEBUG("Found interface index: %u", entry.ifindex);
|
||||
break;
|
||||
case RTA_GATEWAY:
|
||||
FF_DEBUG("Found gateway: %s", inet_ntoa(*(struct in_addr*)&rta_data));
|
||||
if (rta_data == 0) goto next;
|
||||
break;
|
||||
case RTA_PRIORITY:
|
||||
FF_DEBUG("Found metric: %u", rta_data);
|
||||
if (rta_data >= minMetric) goto next;
|
||||
entry.metric = rta_data;
|
||||
break;
|
||||
case RTA_PREFSRC:
|
||||
entry.prefsrc = rta_data;
|
||||
FF_DEBUG("Found preferred source: %s", inet_ntoa(*(struct in_addr*)&rta_data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.ifindex == 0 || entry.metric >= minMetric)
|
||||
{
|
||||
next:
|
||||
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
continue;
|
||||
}
|
||||
minMetric = entry.metric;
|
||||
result->ifIndex = entry.ifindex;
|
||||
FF_DEBUG("Updated best route: ifindex=%u, metric=%u, prefsrc=%x", entry.ifindex, entry.metric, entry.prefsrc);
|
||||
result->preferredSourceAddrV4 = entry.prefsrc;
|
||||
if (minMetric == 0)
|
||||
{
|
||||
FF_DEBUG("Found zero metric route, stopping further processing");
|
||||
break; // Stop processing if we found a zero metric route
|
||||
}
|
||||
}
|
||||
|
||||
if (minMetric < UINT32_MAX)
|
||||
{
|
||||
if_indextoname(result->ifIndex, result->ifName);
|
||||
FF_DEBUG("Found default IPv4 route: interface=%s, index=%u, metric=%u", result->ifName, result->ifIndex, minMetric);
|
||||
return true;
|
||||
}
|
||||
iface[0] = '\0';
|
||||
FF_DEBUG("No IPv4 default route found");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool getDefaultRouteIPv6(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/ipv6_route", "r");
|
||||
if (!netRoute) return false;
|
||||
FF_DEBUG("Starting IPv6 default route detection");
|
||||
|
||||
uint32_t prefixLen;
|
||||
//destination, dest_prefix_len, source, src_prefix_len, next hop, metric, ref counter, use counter, flags, iface
|
||||
while (fscanf(netRoute, "%*s %x %*s %*s %*s %*s %*s %*s %*s %" FF_STR(IF_NAMESIZE) "s", &prefixLen, iface) == 2)
|
||||
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
if (prefixLen != 0) continue;
|
||||
*ifIndex = if_nametoindex(iface);
|
||||
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
|
||||
|
||||
unsigned pid = (unsigned) getpid();
|
||||
FF_DEBUG("Process PID: %u", pid);
|
||||
|
||||
// Bind socket
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Let kernel choose PID
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Successfully bound socket");
|
||||
|
||||
struct __attribute__((__packed__)) {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtmsg rtm;
|
||||
struct rtattr rta;
|
||||
uint32_t table;
|
||||
} req = {
|
||||
// Netlink message header
|
||||
.nlh = {
|
||||
.nlmsg_len = sizeof(req),
|
||||
.nlmsg_type = RTM_GETROUTE,
|
||||
.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
|
||||
.nlmsg_seq = 1,
|
||||
.nlmsg_pid = pid,
|
||||
},
|
||||
// Route message
|
||||
.rtm = {
|
||||
.rtm_family = AF_INET6, // IPv6 instead of IPv4
|
||||
.rtm_dst_len = 0, // Match all destinations
|
||||
.rtm_src_len = 0, // Match all sources
|
||||
.rtm_tos = 0,
|
||||
.rtm_table = RT_TABLE_UNSPEC,
|
||||
.rtm_protocol = RTPROT_UNSPEC,
|
||||
.rtm_scope = RT_SCOPE_UNIVERSE,
|
||||
.rtm_type = RTN_UNSPEC,
|
||||
.rtm_flags = 0,
|
||||
},
|
||||
// Route attribute for main table
|
||||
.rta = {
|
||||
.rta_len = RTA_LENGTH(sizeof(uint32_t)),
|
||||
.rta_type = RTA_TABLE,
|
||||
},
|
||||
.table = RT_TABLE_MAIN,
|
||||
};
|
||||
|
||||
struct sockaddr_nl dest_addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Kernel
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0,
|
||||
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
|
||||
|
||||
if (sent != sizeof(req)) {
|
||||
FF_DEBUG("Failed to send netlink request: sent=%zd, expected=%zu", sent, sizeof(req));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Sent netlink request: %zd bytes", sent);
|
||||
|
||||
struct sockaddr_nl src_addr = {};
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
|
||||
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
|
||||
|
||||
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr*)&src_addr, &src_addr_len);
|
||||
|
||||
if (received < 0) {
|
||||
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (received >= (ssize_t)sizeof(buffer)) {
|
||||
FF_DEBUG("Failed to receive complete message (possible truncation)");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t metric;
|
||||
uint32_t ifindex;
|
||||
} entry;
|
||||
uint32_t minMetric = UINT32_MAX;
|
||||
int routeCount = 0;
|
||||
|
||||
for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
|
||||
NLMSG_OK(nlh, received);
|
||||
nlh = NLMSG_NEXT(nlh, received)) {
|
||||
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid)
|
||||
continue;
|
||||
if (nlh->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
FF_DEBUG("Received NLMSG_DONE, processed %d routes", routeCount);
|
||||
break;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(nlh);
|
||||
FF_DEBUG("Netlink reports error: %s", strerror(-err->error));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type != RTM_NEWROUTE)
|
||||
continue;
|
||||
|
||||
routeCount++;
|
||||
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
|
||||
if (rtm->rtm_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
if (rtm->rtm_dst_len != 0)
|
||||
continue;
|
||||
|
||||
FF_DEBUG("Processing IPv6 default route candidate #%d", routeCount);
|
||||
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
|
||||
|
||||
// Parse route attributes
|
||||
size_t rtm_len = RTM_PAYLOAD(nlh);
|
||||
for (struct rtattr* rta = RTM_RTA(rtm);
|
||||
RTA_OK(rta, rtm_len);
|
||||
rta = RTA_NEXT(rta, rtm_len))
|
||||
{
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
|
||||
FF_MAYBE_UNUSED char str[INET6_ADDRSTRLEN];
|
||||
FF_DEBUG("Unexpected RTA_DST: %s", inet_ntop(AF_INET6, RTA_DATA(rta), str, sizeof(str)));
|
||||
goto next;
|
||||
}
|
||||
break;
|
||||
case RTA_OIF:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) {
|
||||
entry.ifindex = *(uint32_t*) RTA_DATA(rta);
|
||||
FF_DEBUG("Found interface index: %u", entry.ifindex);
|
||||
}
|
||||
break;
|
||||
case RTA_GATEWAY:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
|
||||
struct in6_addr* gw = (struct in6_addr*) RTA_DATA(rta);
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(gw)) goto next;
|
||||
FF_MAYBE_UNUSED char str[INET6_ADDRSTRLEN];
|
||||
FF_DEBUG("Found gateway: %s", inet_ntop(AF_INET6, gw, str, sizeof(str)));
|
||||
}
|
||||
break;
|
||||
case RTA_PRIORITY:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) {
|
||||
uint32_t metric = *(uint32_t*) RTA_DATA(rta);
|
||||
FF_DEBUG("Found metric: %u", metric);
|
||||
if (metric >= minMetric) goto next;
|
||||
entry.metric = metric;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.ifindex == 0 || entry.metric >= minMetric)
|
||||
{
|
||||
next:
|
||||
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
continue;
|
||||
}
|
||||
minMetric = entry.metric;
|
||||
result->ifIndex = entry.ifindex;
|
||||
FF_DEBUG("Updated best route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
|
||||
if (minMetric == 0)
|
||||
{
|
||||
FF_DEBUG("Found zero metric route, stopping further processing");
|
||||
break; // Stop processing if we found a zero metric route
|
||||
}
|
||||
}
|
||||
|
||||
if (minMetric < UINT32_MAX)
|
||||
{
|
||||
if_indextoname(result->ifIndex, result->ifName);
|
||||
FF_DEBUG("Found default IPv6 route: interface=%s, index=%u, metric=%u", result->ifName, result->ifIndex, minMetric);
|
||||
return true;
|
||||
}
|
||||
iface[0] = '\0';
|
||||
FF_DEBUG("No IPv6 default route found");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
if (getDefaultRouteIPv4(iface, ifIndex))
|
||||
return true;
|
||||
|
||||
return getDefaultRouteIPv6(iface, ifIndex);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
|
||||
#include <iphlpapi.h>
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
|
||||
@@ -18,20 +18,17 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if ((row->DestinationPrefix.PrefixLength == 0) &&
|
||||
((row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0) ||
|
||||
(row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr))))
|
||||
if (row->DestinationPrefix.PrefixLength == 0 &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0)
|
||||
{
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) &&
|
||||
ifRow.OperStatus == IfOperStatusUp)
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp)
|
||||
{
|
||||
MIB_IPINTERFACE_ROW ipInterfaceRow = {
|
||||
.Family = (row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET) ? AF_INET : AF_INET6,
|
||||
.Family = AF_INET,
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
|
||||
@@ -43,9 +40,57 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
if (realMetric < smallestMetric)
|
||||
{
|
||||
smallestMetric = realMetric;
|
||||
*ifIndex = row->InterfaceIndex;
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, ifRow.Alias, -1, iface, IF_NAMESIZE, NULL, NULL) > 0)
|
||||
iface[IF_NAMESIZE] = '\0';
|
||||
result->ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeMibTable(pIpForwardTable);
|
||||
|
||||
return foundDefault;
|
||||
}
|
||||
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable)))
|
||||
return false;
|
||||
|
||||
bool foundDefault = false;
|
||||
uint32_t smallestMetric = UINT32_MAX;
|
||||
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
|
||||
{
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if (row->DestinationPrefix.PrefixLength == 0 &&
|
||||
row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr))
|
||||
{
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp)
|
||||
{
|
||||
MIB_IPINTERFACE_ROW ipInterfaceRow = {
|
||||
.Family = AF_INET6,
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
|
||||
uint32_t realMetric = row->Metric /* Metric offset */;
|
||||
|
||||
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow)))
|
||||
realMetric += ipInterfaceRow.Metric /* Interface metric */;
|
||||
|
||||
if (realMetric < smallestMetric)
|
||||
{
|
||||
smallestMetric = realMetric;
|
||||
result->ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
FF_DEBUG("Multithreading mode enabled, creating connection thread");
|
||||
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
|
||||
if (state->thread) {
|
||||
FF_DEBUG("Thread creation successful: thread=%p", (void*)state->thread);
|
||||
FF_DEBUG("Thread creation successful: thread=%p", (void*)(uintptr_t)state->thread);
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Thread creation failed");
|
||||
|
||||
+2
-49
@@ -28,55 +28,6 @@ const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName)
|
||||
return subKey;
|
||||
}
|
||||
|
||||
bool ffOptionParseModuleArgs(const char* argumentKey, const char* subKey, const char* value, FFModuleArgs* result)
|
||||
{
|
||||
if(ffStrEqualsIgnCase(subKey, "key"))
|
||||
{
|
||||
ffOptionParseString(argumentKey, value, &result->key);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(subKey, "format"))
|
||||
{
|
||||
ffOptionParseString(argumentKey, value, &result->outputFormat);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(subKey, "output-color"))
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <str>\n", argumentKey);
|
||||
exit(477);
|
||||
}
|
||||
ffOptionParseColor(value, &result->outputColor);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrStartsWithIgnCase(subKey, "key-"))
|
||||
{
|
||||
const char* subKey2 = subKey + strlen("key-");
|
||||
if(ffStrEqualsIgnCase(subKey2, "color"))
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <str>\n", argumentKey);
|
||||
exit(477);
|
||||
}
|
||||
ffOptionParseColor(value, &result->keyColor);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(subKey2, "width"))
|
||||
{
|
||||
result->keyWidth = ffOptionParseUInt32(argumentKey, value);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(subKey2, "icon"))
|
||||
{
|
||||
ffOptionParseString(argumentKey, value, &result->keyIcon);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer)
|
||||
{
|
||||
if(value == NULL)
|
||||
@@ -157,6 +108,8 @@ bool ffOptionParseBoolean(const char* str)
|
||||
|
||||
void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
{
|
||||
if (!value || value[0] == '\0') return;
|
||||
|
||||
// If value is already an ANSI escape code, use it
|
||||
if (value[0] == '\e' && value[1] == '[')
|
||||
{
|
||||
|
||||
+4
-2
@@ -29,7 +29,8 @@ typedef struct FFModuleBaseInfo
|
||||
// This is UB, because `void*` is not compatible with `FF*Options*`.
|
||||
// However we can't do it better unless we move to C++, so that `option` becomes a `this` pointer
|
||||
// https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type
|
||||
bool (*parseCommandOptions)(void* options, const char* key, const char* value);
|
||||
void (*initOptions)(void* options);
|
||||
void (*destroyOptions)(void* options);
|
||||
void (*parseJsonObject)(void* options, struct yyjson_val *module);
|
||||
void (*printModule)(void* options);
|
||||
void (*generateJsonResult)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* module);
|
||||
@@ -63,7 +64,6 @@ typedef struct FFKeyValuePair
|
||||
} FFKeyValuePair;
|
||||
|
||||
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName);
|
||||
bool ffOptionParseModuleArgs(const char* argumentKey, const char* pkey, const char* value, FFModuleArgs* result);
|
||||
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer);
|
||||
FF_C_NODISCARD uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value);
|
||||
FF_C_NODISCARD int32_t ffOptionParseInt32(const char* argumentKey, const char* value);
|
||||
@@ -94,3 +94,5 @@ static inline void ffOptionDestroyModuleArg(FFModuleArgs* args)
|
||||
ffStrbufDestroy(&args->outputFormat);
|
||||
ffStrbufDestroy(&args->outputColor);
|
||||
}
|
||||
|
||||
enum { FF_OPTION_MAX_SIZE = 1 << 8 }; // Maximum size of a single option value, used for static allocation
|
||||
|
||||
+76
-62
@@ -60,23 +60,32 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
|
||||
uint32_t blocksPercent = (uint32_t) (percent / 100.0 * options->barWidth + 0.5);
|
||||
const bool borderAsValue = options->barBorderLeftElapsed.length && options->barBorderRightElapsed.length;
|
||||
|
||||
uint8_t blocksPercent = (uint8_t) (percent / 100.0 * options->barWidth + 0.5);
|
||||
assert(blocksPercent <= options->barWidth);
|
||||
|
||||
if(options->barBorderLeft.length)
|
||||
if(!borderAsValue && options->barBorderLeft.length)
|
||||
{
|
||||
if(!options->pipe)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
|
||||
if(!options->pipe && options->barColorBorder.length > 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
|
||||
ffStrbufAppend(buffer, &options->barBorderLeft);
|
||||
}
|
||||
|
||||
if (percent != percent)
|
||||
if (percent == -DBL_MAX)
|
||||
{
|
||||
if(!options->pipe)
|
||||
// Use total color for simplification
|
||||
if(!options->pipe && options->barColorTotal.length > 0)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
|
||||
|
||||
for (uint32_t i = 0; i < options->barWidth; ++i)
|
||||
ffStrbufAppend(buffer, &options->barCharElapsed);
|
||||
for (uint8_t i = 0; i < options->barWidth; ++i)
|
||||
{
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeft
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRight
|
||||
: &options->barCharTotal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -85,61 +94,72 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
const char* colorRed = options->percentColorRed.chars;
|
||||
|
||||
FFPercentageTypeFlags percentType = config.type == 0 ? options->percentType : config.type;
|
||||
bool monochrome = !!(percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT);
|
||||
|
||||
for (uint32_t i = 0; i < blocksPercent; ++i)
|
||||
bool autoColorElapsed = ffStrbufIgnCaseEqualS(&options->barColorElapsed, "auto");
|
||||
|
||||
bool monochrome = (percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT) || !autoColorElapsed;
|
||||
if (!options->pipe && options->barColorElapsed.length > 0 && monochrome)
|
||||
{
|
||||
if(!options->pipe)
|
||||
const char* color = NULL;
|
||||
if (!autoColorElapsed)
|
||||
color = options->barColorElapsed.chars;
|
||||
else if (green <= yellow)
|
||||
{
|
||||
if (monochrome)
|
||||
{
|
||||
const char* color = NULL;
|
||||
if (green <= yellow)
|
||||
{
|
||||
if (percent < green) color = colorGreen;
|
||||
else if (percent < yellow) color = colorYellow;
|
||||
else color = colorRed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (percent < yellow) color = colorRed;
|
||||
else if (percent < green) color = colorYellow;
|
||||
else color = colorGreen;
|
||||
}
|
||||
ffStrbufAppendF(buffer, "\e[%sm", color);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
if (i == section2Begin)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed));
|
||||
else if (i == section1Begin)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else if (i == 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed));
|
||||
}
|
||||
if (percent < green) color = colorGreen;
|
||||
else if (percent < yellow) color = colorYellow;
|
||||
else color = colorRed;
|
||||
}
|
||||
ffStrbufAppend(buffer, &options->barCharElapsed);
|
||||
else
|
||||
{
|
||||
if (percent < yellow) color = colorRed;
|
||||
else if (percent < green) color = colorYellow;
|
||||
else color = colorGreen;
|
||||
}
|
||||
ffStrbufAppendF(buffer, "\e[%sm", color);
|
||||
}
|
||||
for (uint8_t i = 0; i < blocksPercent; ++i)
|
||||
{
|
||||
if (!options->pipe && options->barColorElapsed.length > 0 && !monochrome)
|
||||
{
|
||||
uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
if (i == section2Begin)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed));
|
||||
else if (i == section1Begin)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else if (i == 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed));
|
||||
}
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeftElapsed
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRightElapsed
|
||||
: &options->barCharElapsed);
|
||||
}
|
||||
|
||||
if (blocksPercent < options->barWidth)
|
||||
{
|
||||
if(!options->pipe)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
|
||||
for (uint32_t i = blocksPercent; i < options->barWidth; ++i)
|
||||
ffStrbufAppend(buffer, &options->barCharTotal);
|
||||
if(!options->pipe && options->barColorTotal.length > 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorTotal.chars);
|
||||
for (uint8_t i = blocksPercent; i < options->barWidth; ++i)
|
||||
{
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeft
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRight
|
||||
: &options->barCharTotal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(options->barBorderRight.length)
|
||||
if(!borderAsValue && options->barBorderRight.length)
|
||||
{
|
||||
if(!options->pipe)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
|
||||
if(!options->pipe && options->barColorBorder.length > 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
|
||||
ffStrbufAppend(buffer, &options->barBorderRight);
|
||||
}
|
||||
|
||||
if(!options->pipe)
|
||||
if(!options->pipe && (options->barColorElapsed.length > 0 || options->barColorTotal.length > 0 || options->barColorBorder.length > 0))
|
||||
{
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
appendOutputColor(buffer, module);
|
||||
@@ -165,7 +185,7 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
const char* colorYellow = options->percentColorYellow.chars;
|
||||
const char* colorRed = options->percentColorRed.chars;
|
||||
|
||||
if(percent != percent)
|
||||
if(percent == -DBL_MAX)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
|
||||
else if(green <= yellow)
|
||||
{
|
||||
@@ -239,14 +259,14 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageModuleConfig* config)
|
||||
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config)
|
||||
{
|
||||
if (!ffStrEqualsIgnCase(key, "percent"))
|
||||
if (!unsafe_yyjson_equals_str(key, "percent"))
|
||||
return false;
|
||||
|
||||
if (!yyjson_is_obj(value))
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s must be an object\n", key);
|
||||
fprintf(stderr, "Error: usage: %s must be an object\n", unsafe_yyjson_get_str(key));
|
||||
exit(480);
|
||||
}
|
||||
|
||||
@@ -288,16 +308,10 @@ bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageMo
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig defaultConfig, FFPercentageModuleConfig config)
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config)
|
||||
{
|
||||
if (config.green == defaultConfig.green && config.yellow == defaultConfig.yellow)
|
||||
return;
|
||||
|
||||
yyjson_mut_val* percent = yyjson_mut_obj_add_obj(doc, module, "percent");
|
||||
if (config.green != defaultConfig.green)
|
||||
yyjson_mut_obj_add_uint(doc, percent, "green", config.green);
|
||||
if (config.yellow != defaultConfig.yellow)
|
||||
yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow);
|
||||
if (config.type != defaultConfig.type)
|
||||
yyjson_mut_obj_add_uint(doc, percent, "type", config.type);
|
||||
yyjson_mut_obj_add_uint(doc, percent, "green", config.green);
|
||||
yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow);
|
||||
yyjson_mut_obj_add_uint(doc, percent, "type", config.type);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ typedef enum __attribute__((__packed__)) FFPercentageTypeFlags
|
||||
FF_PERCENTAGE_TYPE_BAR_BIT = 1 << 1,
|
||||
FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT = 1 << 2,
|
||||
FF_PERCENTAGE_TYPE_NUM_COLOR_BIT = 1 << 3,
|
||||
FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT = FF_PERCENTAGE_TYPE_NUM_COLOR_BIT,
|
||||
FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT = 1 << 4,
|
||||
FF_PERCENTAGE_TYPE_FORCE_UNSIGNED_ = UINT8_MAX,
|
||||
} FFPercentageTypeFlags;
|
||||
static_assert(sizeof(FFPercentageTypeFlags) == 1, "");
|
||||
@@ -40,6 +40,6 @@ typedef struct yyjson_val yyjson_val;
|
||||
typedef struct yyjson_mut_doc yyjson_mut_doc;
|
||||
typedef struct yyjson_mut_val yyjson_mut_val;
|
||||
bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentageModuleConfig* config);
|
||||
bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageModuleConfig* config);
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig defaultConfig, FFPercentageModuleConfig config);
|
||||
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config);
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config);
|
||||
const char* ffPercentParseTypeJsonConfig(yyjson_val* value, FFPercentageTypeFlags* result);
|
||||
|
||||
+9
-18
@@ -5,7 +5,7 @@
|
||||
|
||||
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module)
|
||||
{
|
||||
if (celsius != celsius) // ignores NaN
|
||||
if (celsius == -DBL_MAX) // ignores invalid value
|
||||
return;
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
@@ -107,9 +107,9 @@ bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char*
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config)
|
||||
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config)
|
||||
{
|
||||
if (!ffStrEqualsIgnCase(key, "temp"))
|
||||
if (!unsafe_yyjson_equals_str(key, "temp"))
|
||||
return false;
|
||||
|
||||
if (yyjson_is_bool(value))
|
||||
@@ -126,7 +126,7 @@ bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, F
|
||||
|
||||
if (!yyjson_is_obj(value))
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s must be an object or a boolean\n", key);
|
||||
fprintf(stderr, "Error: usage: %s must be an object or a boolean\n", unsafe_yyjson_get_str(key));
|
||||
exit(480);
|
||||
}
|
||||
|
||||
@@ -159,23 +159,14 @@ bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, F
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FF_MAYBE_UNUSED bool defaultTemp, FFColorRangeConfig defaultConfig, bool temp, FFColorRangeConfig config)
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config)
|
||||
{
|
||||
assert(defaultTemp == false); // assume defaultTemp is always false
|
||||
|
||||
if (!temp)
|
||||
return;
|
||||
|
||||
if (config.green != defaultConfig.green || config.yellow != defaultConfig.yellow)
|
||||
{
|
||||
yyjson_mut_val* temp = yyjson_mut_obj_add_obj(doc, module, "temp");
|
||||
if (config.green != defaultConfig.green)
|
||||
yyjson_mut_obj_add_uint(doc, temp, "green", config.green);
|
||||
if (config.yellow != defaultConfig.yellow)
|
||||
yyjson_mut_obj_add_uint(doc, temp, "yellow", config.yellow);
|
||||
}
|
||||
yyjson_mut_obj_add_bool(doc, module, "temp", false);
|
||||
else
|
||||
{
|
||||
yyjson_mut_obj_add_bool(doc, module, "temp", true);
|
||||
yyjson_mut_val* temp = yyjson_mut_obj_add_obj(doc, module, "temp");
|
||||
yyjson_mut_obj_add_uint(doc, temp, "green", config.green);
|
||||
yyjson_mut_obj_add_uint(doc, temp, "yellow", config.yellow);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -5,5 +5,5 @@
|
||||
|
||||
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module);
|
||||
bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* value, bool* useTemp, FFColorRangeConfig* config);
|
||||
bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config);
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FF_MAYBE_UNUSED bool defaultTemp, FFColorRangeConfig defaultConfig, bool temp, FFColorRangeConfig config);
|
||||
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config);
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config);
|
||||
|
||||
+51
-902
@@ -77,7 +77,16 @@
|
||||
},
|
||||
{
|
||||
"long": "gen-config",
|
||||
"desc": "Generate a config file at the specified path with options from the command line (if any)",
|
||||
"desc": "Generate a minimal config file at the specified path",
|
||||
"remark": "Defaults to \"~/.config/fastfetch/config.jsonc\". Will print the generated config if <path> is \"-\"",
|
||||
"arg": {
|
||||
"type": "path",
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "gen-config-full",
|
||||
"desc": "Generate a full config file with all optional options at the specified path",
|
||||
"remark": "Defaults to \"~/.config/fastfetch/config.jsonc\". Will print the generated config if <path> is \"-\"",
|
||||
"arg": {
|
||||
"type": "path",
|
||||
@@ -699,6 +708,47 @@
|
||||
"default": " ]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bar-border-left-elapsed",
|
||||
"desc": "If both bar-border-left-elapsed and bar-border-right-elapsed are set, the border will be used as parts of bar content",
|
||||
"arg": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bar-border-right-elapsed",
|
||||
"desc": "If both bar-border-left-elapsed and bar-border-right-elapsed are set, the border will be used as parts of bar content",
|
||||
"arg": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bar-color-elapsed",
|
||||
"desc": "Set the color to use in the elapsed part of percentage bars",
|
||||
"remark": "By default, auto selected by percent-color-{green,yellow,red}",
|
||||
"arg": {
|
||||
"type": "color",
|
||||
"default": "<auto>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bar-color-total",
|
||||
"desc": "Set the color to use in the total part of percentage bars",
|
||||
"arg": {
|
||||
"type": "color",
|
||||
"default": "light_white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bar-color-border",
|
||||
"desc": "Set the color to use in the borders of percentage bars",
|
||||
"arg": {
|
||||
"type": "color",
|
||||
"default": "light_white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bar-width",
|
||||
"desc": "Set the width of percentage bars in characters",
|
||||
@@ -857,906 +907,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Module specific": [
|
||||
{
|
||||
"long": "title-fqdn",
|
||||
"desc": "Specify whether the title should use fully qualified domain name",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "title-color-user",
|
||||
"desc": "Set the color of the user name (left part)",
|
||||
"remark": "See `-h color` for the list of available colors",
|
||||
"arg": {
|
||||
"type": "color",
|
||||
"default": "Use color of \"--color-title\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "title-color-at",
|
||||
"desc": "Set the color of the @ symbol (middle part)",
|
||||
"remark": "See `-h color` for the list of available colors",
|
||||
"arg": {
|
||||
"type": "color",
|
||||
"default": "Use color of \"--color-title\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "title-color-host",
|
||||
"desc": "Set the color of the host name (right part)",
|
||||
"remark": "See `-h color` for the list of available colors",
|
||||
"arg": {
|
||||
"type": "color",
|
||||
"default": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "separator-string",
|
||||
"desc": "Set the string to be printed by the separator line",
|
||||
"arg": {
|
||||
"type": "str",
|
||||
"default": "-"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "separator-output-color",
|
||||
"desc": "Set the color of the separator line",
|
||||
"arg": {
|
||||
"type": "color",
|
||||
"default": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "separator-length",
|
||||
"desc": "Set the length of the separator line",
|
||||
"remark": "Set to 0 to automatically calculate it based on the title length",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-folders",
|
||||
"desc": "A colon (semicolon on Windows) separated list of folder paths to detect",
|
||||
"remark": "On Windows, a drive letter must be upper-cased and end with \"\\\". \"/\" is used as an alias of the system drive. This option overrides other disk-show-* options",
|
||||
"arg": {
|
||||
"type": "path",
|
||||
"default": "Auto detection using mount-points"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-hide-folders",
|
||||
"desc": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output",
|
||||
"arg": {
|
||||
"type": "path",
|
||||
"default": "/efi:/boot:/boot/efi:/boot/firmware"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-hide-fs",
|
||||
"desc": "A colon separated list of file systems to hide from the disk output",
|
||||
"arg": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-regular",
|
||||
"desc": "Specify whether regular volumes should be displayed",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-external",
|
||||
"desc": "Specify whether external volumes should be displayed",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-hidden",
|
||||
"desc": "Specify whether hidden volumes should be displayed",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-subvolumes",
|
||||
"desc": "Specify whether subvolumes should be displayed",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-readonly",
|
||||
"desc": "Specify whether read-only volumes should be displayed",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-unknown",
|
||||
"desc": "Specify whether unknown volumes (unable to detect sizes) should be displayed",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-use-available",
|
||||
"desc": "Use f_bavail (lpFreeBytesAvailableToCaller for Windows) instead of f_bfree to calculate used bytes",
|
||||
"remark": "May be required for macOS to display correct results",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "diskio-detect-total",
|
||||
"desc": "Detect total bytes instead of current rate",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "diskio-name-prefix",
|
||||
"desc": "Show only disks with the given name prefix",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "diskio-wait-time",
|
||||
"desc": "Set the wait time (in ms) when detecting disk usage",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "physicaldisk-name-prefix",
|
||||
"desc": "Show only disks with the given name prefix",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "physicaldisk-temp",
|
||||
"desc": "Detect and display SSD temperature if supported",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bluetooth-show-disconnected",
|
||||
"desc": "Specify whether disconnected Bluetooth devices should be displayed",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "packages-disabled",
|
||||
"desc": "A colon-separated list of package managers to disable when detecting",
|
||||
"remark": [
|
||||
"Some detection methods can be very slow.",
|
||||
"You may need to increase the value of '--processing-timeout' to make it work properly.",
|
||||
"Use `--packages-disabled none` to enable all."
|
||||
],
|
||||
"arg": {
|
||||
"type": "string",
|
||||
"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",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"none": "Disable this compact mode",
|
||||
"original": "Print original resolutions",
|
||||
"scaled": "Print scaled resolutions",
|
||||
"original-with-refresh-rate": "Print original resolutions with refresh rate",
|
||||
"scaled-with-refresh-rate": "Print scaled resolutions with refresh rate"
|
||||
},
|
||||
"default": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "display-precise-refresh-rate",
|
||||
"desc": "Specify whether decimal refresh rates should not be rounded to integers when printing",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "display-order",
|
||||
"desc": "Set the order to use when printing displays",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"none": "Use the detected order",
|
||||
"asc": "Sort by display name in ascending order",
|
||||
"desc": "Sort by display name in descending order"
|
||||
},
|
||||
"default": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "brightness-ddcci-sleep",
|
||||
"desc": "Set the sleep time (in ms) when sending DDC/CI requests",
|
||||
"remark": "See <https://www.ddcutil.com/performance_options/#option-sleep-multiplier> for details",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "brightness-compact",
|
||||
"desc": "Specify whether multiple results should be printed in one line",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "sound-type",
|
||||
"desc": "Set which types of sound devices should be displayed",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"main": "Print only main sound devices",
|
||||
"active": "Print only active sound devices",
|
||||
"all": "Print all sound devices"
|
||||
},
|
||||
"default": "main"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "battery-use-setup-api",
|
||||
"desc": "Specify whether \"SetupAPI\" should be used on Windows to detect battery info",
|
||||
"remark": [
|
||||
"SetupAPI supports multiple batteries, but is slower.",
|
||||
"Windows only"
|
||||
],
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "cpu-temp",
|
||||
"desc": "Detect and display CPU temperature if supported",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "cpu-show-pe-core-count",
|
||||
"desc": "Detect and display CPU frequency of different core types (e.g., P-cores and E-cores) if supported",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "cpucache-compact",
|
||||
"desc": "Show all CPU caches in one line",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "cpuusage-separate",
|
||||
"desc": "Display CPU usage per logical core, instead of an average result",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "cpuusage-wait-time",
|
||||
"desc": "Set the wait time (in ms) when detecting CPU usage",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "de-slow-version-detection",
|
||||
"desc": "Specify whether DE version should be detected with slower operations",
|
||||
"remark": [
|
||||
"This is only used as a fallback method. Please file a bug report if you encounter any issues.",
|
||||
"Linux only"
|
||||
],
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "gpu-temp",
|
||||
"desc": "Detect and display GPU temperature if supported",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "gpu-driver-specific",
|
||||
"desc": "Use driver-specific methods to detect more detailed GPU information (memory usage, core count, etc.)",
|
||||
"remark": "Requires the latest GPU drivers to be installed.",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "gpu-detection-method",
|
||||
"desc": "Force using a specified method to detect GPUs",
|
||||
"remark": "Will fall back to other methods if the specified method fails",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"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. Used for OpenBSD"
|
||||
},
|
||||
"default": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "gpu-hide-type",
|
||||
"desc": "Specify which types of GPUs should not be displayed (default: all GPUs are shown, regardless of recognition)",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"integrated": "Hide integrated GPUs",
|
||||
"discrete": "Hide discrete GPUs",
|
||||
"unknown": "Hide unknown (unrecognized) GPUs",
|
||||
"none": "Do not hide any GPUs"
|
||||
},
|
||||
"default": "none"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "battery-temp",
|
||||
"desc": "Detect and display battery temperature if supported",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "loadavg-ndigits",
|
||||
"desc": "Set the number of digits to keep after the decimal point when printing load average",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "loadavg-compact",
|
||||
"desc": "Show load average values in one line",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-ipv4",
|
||||
"desc": "Show IPv4 addresses in the local IP module",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-ipv6",
|
||||
"desc": "Show IPv6 addresses in the local IP module",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-mac",
|
||||
"desc": "Show MAC addresses in the local IP module",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-loop",
|
||||
"desc": "Show loopback addresses (127.0.0.1) in the local IP module",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-mtu",
|
||||
"desc": "Show network interface MTU (Maximum Transmission Unit) size in bytes",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-speed",
|
||||
"desc": "Show network interface link speed in human-readable format (or as a 1Mb units integer in JSON format)",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-prefix-len",
|
||||
"desc": "Show network prefix length (/N) in the local IP module",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-name-prefix",
|
||||
"desc": "Show only interfaces with the given interface name prefix",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-default-route-only",
|
||||
"desc": "Show only the interface that is used for default routing",
|
||||
"remark": "Doesn't work on Android",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-all-ips",
|
||||
"desc": "Show all IPs bound to the same interface. By default, only the first IP is shown",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-show-flags",
|
||||
"desc": "Show network interface flags in the local IP module",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "localip-compact",
|
||||
"desc": "Show all IPs in one line",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "dns-show-type",
|
||||
"desc": "Specify which types of DNS servers should be detected",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"ipv4": "Show IPv4 addresses only",
|
||||
"ipv6": "Show IPv6 addresses only",
|
||||
"both": "Show both IPv4 and IPv6 addresses"
|
||||
},
|
||||
"default": "both"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "netio-name-prefix",
|
||||
"desc": "Show only interfaces with the given name prefix",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "netio-default-route-only",
|
||||
"desc": "Show only the interface that is used for default routing",
|
||||
"remark": "Doesn't work on Android",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "netio-detect-total",
|
||||
"desc": "Detect total bytes instead of current rate",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "netio-wait-time",
|
||||
"desc": "Set the wait time (in ms) when detecting network usage",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "publicip-timeout",
|
||||
"desc": "Time in milliseconds to wait for the public IP server to respond",
|
||||
"remark": "0 to disable timeout",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "publicip-url",
|
||||
"desc": "The URL of the public IP detection server to use",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "publicip-ipv6",
|
||||
"desc": "Specify whether to use IPv6 for the public IP detection server",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "weather-location",
|
||||
"desc": "Set the location to use",
|
||||
"remark": "Must be URI encoded (e.g., a whitespace must be encoded as \"+\")",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "weather-timeout",
|
||||
"desc": "Time in milliseconds to wait for the weather server to respond",
|
||||
"remark": "0 to disable timeout",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "weather-output-format",
|
||||
"desc": "The output weather format to use",
|
||||
"remark": "Must be URI encoded",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "wm-detect-plugin",
|
||||
"desc": "Specify whether window manager plugins should be detected on supported platforms",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "users-compact",
|
||||
"desc": "Show all active users in one line",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "users-myself-only",
|
||||
"desc": "Show only the current user",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "player-name",
|
||||
"desc": "The name of the player to use for the Media and Player modules",
|
||||
"remark": "Linux only",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "opengl-library",
|
||||
"desc": "Set the OpenGL context creation library to use",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"auto": "Prefer EGL on *nix; prefer platform-specific implementation on others",
|
||||
"egl": "EGL",
|
||||
"glx": "GLX (*nix only)"
|
||||
},
|
||||
"default": "auto"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "command-shell",
|
||||
"desc": "Set the shell program to execute the command text",
|
||||
"arg": {
|
||||
"type": "str",
|
||||
"default": "\"cmd\" for Windows; \"/bin/sh\" for *nix"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "command-param",
|
||||
"desc": "Set the parameter to use when starting the shell",
|
||||
"remark": "If set to an empty string, it will be ignored",
|
||||
"arg": {
|
||||
"type": "str",
|
||||
"default": "\"/c\" for Windows; \"-c\" for *nix"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "command-key",
|
||||
"desc": "Set the module key to display",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "command-text",
|
||||
"desc": "Set the command text to execute",
|
||||
"arg": {
|
||||
"type": "str"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "colors-symbol",
|
||||
"desc": "Set the symbol to be printed by the Colors module",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"block": "\u2588\u2588\u2588",
|
||||
"background": "(whitespaces with background)",
|
||||
"circle": "\u25cf",
|
||||
"diamond": "\u25c6",
|
||||
"triangle": "\u25b2",
|
||||
"square": "\u25a0",
|
||||
"star": "\u2605"
|
||||
},
|
||||
"default": "background"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "colors-padding-left",
|
||||
"desc": "Set the number of white spaces to print before the symbol",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "colors-block-width",
|
||||
"desc": "Set the block width in spaces",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "colors-block-range-start",
|
||||
"desc": "Set the start range of colors in the blocks to print",
|
||||
"remark": [
|
||||
"Display colors 0-15 in the blocks. (16 colors)",
|
||||
"Display colors 0-7 in the blocks. (8 colors)",
|
||||
"Only works for `--colors-symbol block`.",
|
||||
"Must be in range 0-15",
|
||||
"See also `--colors-range-end`"
|
||||
],
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "colors-block-range-end",
|
||||
"desc": "Set the end range of colors in the blocks to print",
|
||||
"remark": [
|
||||
"Display colors 0-15 in the blocks. (16 colors)",
|
||||
"Display colors 0-7 in the blocks. (8 colors)",
|
||||
"Only works for `--colors-symbol block`.",
|
||||
"Must be in range 0-15",
|
||||
"See also `--colors-range-start`"
|
||||
],
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 15
|
||||
}
|
||||
}
|
||||
],
|
||||
"General module": [
|
||||
{
|
||||
"long": "<module>-format",
|
||||
"desc": [
|
||||
"Set the format string to use for a specific module",
|
||||
"See <https://github.com/fastfetch-cli/fastfetch/wiki/Format-String-Guide>",
|
||||
"For help about a specific format string, use \"fastfetch -h <module>-format\""
|
||||
],
|
||||
"arg": {
|
||||
"type": "format"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-key",
|
||||
"desc": [
|
||||
"Set the key to use for a specific module.",
|
||||
"For modules that print multiple lines, the string is parsed",
|
||||
"as a format string with the index as the first character"
|
||||
],
|
||||
"arg": {
|
||||
"type": "key"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-key-color",
|
||||
"desc": "Override the global \"--color-keys\" option for a specific module",
|
||||
"arg": {
|
||||
"type": "color"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-key-icon",
|
||||
"desc": "Set the icon to be displayed by \"--key-type icon\"",
|
||||
"arg": {
|
||||
"type": "string"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-output-color",
|
||||
"desc": "Override the global \"--color-output\" option for a specific module",
|
||||
"arg": {
|
||||
"type": "color"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-key-width",
|
||||
"desc": "Override the global \"--key-width\" option for a specific module",
|
||||
"arg": {
|
||||
"type": "num"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-percent-green",
|
||||
"desc": [
|
||||
"Threshold for percentage color ranges",
|
||||
"Values less than percent-green will be shown in green"
|
||||
],
|
||||
"arg": {
|
||||
"type": "num"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-percent-yellow",
|
||||
"desc": [
|
||||
"Threshold for percentage color ranges",
|
||||
"Values greater than percent-green and less than percent-yellow will be shown in yellow",
|
||||
"Values greater than percent-yellow will be shown in red"
|
||||
],
|
||||
"arg": {
|
||||
"type": "num"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-percent-type",
|
||||
"desc": "Set the percentage output type",
|
||||
"remark": [
|
||||
"0 to use global `--percent-type` value",
|
||||
"1 for percentage number",
|
||||
"2 for multi-color bar",
|
||||
"3 for both",
|
||||
"6 for bar only",
|
||||
"9 for colored number",
|
||||
"10 for monochrome bar"
|
||||
],
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 0
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-temp-green",
|
||||
"desc": [
|
||||
"Threshold for temperature color ranges",
|
||||
"Values less than temp-green will be shown in green"
|
||||
],
|
||||
"arg": {
|
||||
"type": "num"
|
||||
},
|
||||
"pseudo": true
|
||||
},
|
||||
{
|
||||
"long": "<module>-temp-yellow",
|
||||
"desc": [
|
||||
"Threshold for temperature color ranges",
|
||||
"Values greater than temp-green and less than temp-yellow will be shown in yellow",
|
||||
"Values greater than temp-yellow will be shown in red"
|
||||
],
|
||||
"arg": {
|
||||
"type": "num"
|
||||
},
|
||||
"pseudo": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/battery/option.h"
|
||||
|
||||
#define FF_BATTERY_TEMP_UNSET (0/0.0)
|
||||
#define FF_BATTERY_TEMP_UNSET (-DBL_MAX)
|
||||
|
||||
typedef struct FFBatteryResult
|
||||
{
|
||||
|
||||
@@ -96,6 +96,7 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
battery->cycleCount = 0;
|
||||
battery->timeRemaining = -1;
|
||||
battery->capacity = 0;
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->status);
|
||||
@@ -124,11 +125,11 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
double level = 0, scale = 0;
|
||||
if (ffParsePropLines(start, "level: ", &temp))
|
||||
level = ffStrbufToDouble(&temp);
|
||||
level = ffStrbufToDouble(&temp, -DBL_MAX);
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
if (ffParsePropLines(start, "scale: ", &temp))
|
||||
scale = ffStrbufToDouble(&temp);
|
||||
scale = ffStrbufToDouble(&temp, -DBL_MAX);
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
if (level > 0 && scale > 0)
|
||||
@@ -138,7 +139,7 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
if(options->temp)
|
||||
{
|
||||
if (ffParsePropLines(start, "temperature: ", &temp))
|
||||
battery->temperature = ffStrbufToDouble(&temp);
|
||||
battery->temperature = ffStrbufToDouble(&temp, FF_BATTERY_TEMP_UNSET);
|
||||
ffStrbufClear(&temp);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFl
|
||||
return;
|
||||
|
||||
FFBatteryResult* result = ffListAdd(results);
|
||||
result->capacity = ffStrbufToDouble(&tmpBuffer);
|
||||
result->capacity = ffStrbufToDouble(&tmpBuffer, 0);
|
||||
|
||||
//At this point, we have a battery. Try to get as much values as possible.
|
||||
|
||||
@@ -154,7 +154,11 @@ static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFl
|
||||
if (options->temp)
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "temp", &tmpBuffer))
|
||||
result->temperature = ffStrbufToDouble(&tmpBuffer) / 10;
|
||||
{
|
||||
result->temperature = ffStrbufToDouble(&tmpBuffer, FF_BATTERY_TEMP_UNSET);
|
||||
if (result->temperature != FF_BATTERY_TEMP_UNSET)
|
||||
result->temperature /= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results)
|
||||
|
||||
battery->cycleCount = bi.CycleCount;
|
||||
|
||||
battery->temperature = 0.0/0.0;
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
if(options->temp)
|
||||
{
|
||||
bqi.InformationLevel = BatteryTemperature;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bios/option.h"
|
||||
|
||||
typedef struct FFBiosResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bluetooth/option.h"
|
||||
|
||||
typedef struct FFBluetoothResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bluetoothradio/option.h"
|
||||
|
||||
typedef struct FFBluetoothRadioResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/board/option.h"
|
||||
|
||||
typedef struct FFBoardResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bootmgr/option.h"
|
||||
|
||||
typedef struct FFBootmgrResult
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "util/FFlist.h"
|
||||
#include "modules/brightness/option.h"
|
||||
|
||||
typedef struct FFBrightnessResult
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ static const char* detectWithBacklight(FFlist* result)
|
||||
ffStrbufAppendS(&backlightDir, "/brightness");
|
||||
if(ffReadFileBuffer(backlightDir.chars, &buffer))
|
||||
{
|
||||
double actualBrightness = ffStrbufToDouble(&buffer);
|
||||
double actualBrightness = ffStrbufToDouble(&buffer, 0);
|
||||
ffStrbufSubstrBefore(&backlightDir, backlightDirLength);
|
||||
ffStrbufAppendS(&backlightDir, entry->d_name);
|
||||
ffStrbufAppendS(&backlightDir, "/max_brightness");
|
||||
@@ -71,7 +71,7 @@ static const char* detectWithBacklight(FFlist* result)
|
||||
}
|
||||
else
|
||||
ffStrbufInitS(&brightness->name, entry->d_name);
|
||||
brightness->max = ffStrbufToDouble(&buffer);
|
||||
brightness->max = ffStrbufToDouble(&buffer, 0);
|
||||
brightness->min = 0;
|
||||
brightness->current = actualBrightness;
|
||||
brightness->builtin = true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/btrfs/option.h"
|
||||
|
||||
typedef struct FFBtrfsDiskUsage
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/camera/option.h"
|
||||
|
||||
typedef struct FFCameraResult
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@ const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
ffStrbufInitStatic(&camera->name, "Unknown");
|
||||
}
|
||||
ffStrbufInit(&camera->vendor);
|
||||
ffStrbufInitS(&camera->id, yyjson_get_str(yyjson_obj_get(device, "id")));
|
||||
ffStrbufInitJsonVal(&camera->id, yyjson_obj_get(device, "id"));
|
||||
yyjson_val* sizes = yyjson_arr_get_first(yyjson_obj_get(device, "jpeg_output_sizes"));
|
||||
if (yyjson_is_obj(sizes))
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/chassis/option.h"
|
||||
|
||||
typedef struct FFChassisResult
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cpu/option.h"
|
||||
|
||||
#define FF_CPU_TEMP_UNSET (0/0.0)
|
||||
#define FF_CPU_TEMP_UNSET (-DBL_MAX)
|
||||
|
||||
typedef struct FFCPUCore
|
||||
{
|
||||
|
||||
@@ -28,19 +28,19 @@ static double parseHwmonDir(FFstrbuf* dir, FFstrbuf* buffer)
|
||||
ffStrbufAppendS(dir, "temp1_input");
|
||||
|
||||
if(!ffReadFileBuffer(dir->chars, buffer))
|
||||
return 0.0/0.0;
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
double value = ffStrbufToDouble(buffer);// millidegree Celsius
|
||||
double value = ffStrbufToDouble(buffer, FF_CPU_TEMP_UNSET);// millidegree Celsius
|
||||
|
||||
if(value != value)
|
||||
return 0.0/0.0;
|
||||
if(value == FF_CPU_TEMP_UNSET)
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
ffStrbufAppendS(dir, "name");
|
||||
if (!ffReadFileBuffer(dir->chars, buffer))
|
||||
return 0.0/0.0;
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
|
||||
@@ -51,14 +51,17 @@ static double parseHwmonDir(FFstrbuf* dir, FFstrbuf* buffer)
|
||||
ffStrbufEqualS(buffer, "coretemp") // Intel
|
||||
) return value / 1000.;
|
||||
|
||||
return 0.0/0.0;
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
}
|
||||
|
||||
static double detectTZTemp(FFstrbuf* buffer)
|
||||
{
|
||||
if (ffReadFileBuffer("/sys/class/thermal/thermal_zone0/temp", buffer))
|
||||
return ffStrbufToDouble(buffer) / 1000.;
|
||||
return 0.0/0.0;
|
||||
{
|
||||
double value = ffStrbufToDouble(buffer, FF_CPU_TEMP_UNSET);// millidegree Celsius
|
||||
return value != FF_CPU_TEMP_UNSET ? value / 1000. : FF_CPU_TEMP_UNSET;
|
||||
}
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
}
|
||||
|
||||
static double detectCPUTemp(void)
|
||||
@@ -72,7 +75,7 @@ static double detectCPUTemp(void)
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars);
|
||||
if(dirp == NULL)
|
||||
return 0.0/0.0;
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
@@ -84,7 +87,7 @@ static double detectCPUTemp(void)
|
||||
ffStrbufAppendC(&baseDir, '/');
|
||||
|
||||
double result = parseHwmonDir(&baseDir, &buffer);
|
||||
if (result == result)
|
||||
if (result != FF_CPU_TEMP_UNSET)
|
||||
return result;
|
||||
|
||||
ffStrbufSubstrBefore(&baseDir, baseDirLength);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cpucache/option.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFCPUCacheType
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cpuusage/option.h"
|
||||
|
||||
typedef struct FFCpuUsageInfo {
|
||||
uint64_t inUseAll;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cursor/option.h"
|
||||
|
||||
typedef struct FFCursorResult
|
||||
{
|
||||
|
||||
@@ -2,19 +2,30 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
static void appendColor(FFstrbuf* str, NSDictionary* color)
|
||||
static void appendColor(FFstrbuf* str, NSDictionary* dict)
|
||||
{
|
||||
int r = (int) (((NSNumber*) color[@"red"]).doubleValue * 255);
|
||||
int g = (int) (((NSNumber*) color[@"green"]).doubleValue * 255);
|
||||
int b = (int) (((NSNumber*) color[@"blue"]).doubleValue * 255);
|
||||
int a = (int) (((NSNumber*) color[@"alpha"]).doubleValue * 255);
|
||||
uint32_t r = (uint32_t) (((NSNumber*) dict[@"red"]).doubleValue * 255 + .5);
|
||||
uint32_t g = (uint32_t) (((NSNumber*) dict[@"green"]).doubleValue * 255 + .5);
|
||||
uint32_t b = (uint32_t) (((NSNumber*) dict[@"blue"]).doubleValue * 255 + .5);
|
||||
uint32_t a = (uint32_t) (((NSNumber*) dict[@"alpha"]).doubleValue * 255 + .5);
|
||||
uint32_t color = (r << 24) | (g << 16) | (b << 8) | a;
|
||||
|
||||
if (r == 255 && g == 255 && b == 255 && a == 255)
|
||||
ffStrbufAppendS(str, "White");
|
||||
else if (r == 0 && g == 0 && b == 0 && a == 255)
|
||||
ffStrbufAppendS(str, "Black");
|
||||
else
|
||||
ffStrbufAppendF(str, "#%02X%02X%02X%02X", r, g, b, a);
|
||||
switch (color)
|
||||
{
|
||||
case 0x000000FF: ffStrbufAppendS(str, "Black"); return;
|
||||
case 0x0433FFFF: ffStrbufAppendS(str, "Blue"); return;
|
||||
case 0xAA7942FF: ffStrbufAppendS(str, "Brown"); return;
|
||||
case 0x00FDFFFF: ffStrbufAppendS(str, "Cyan"); return;
|
||||
case 0x00F900FF: ffStrbufAppendS(str, "Green"); return;
|
||||
case 0xFF40FFFF: ffStrbufAppendS(str, "Magenta"); return;
|
||||
case 0xFF9300FF: ffStrbufAppendS(str, "Orange"); return;
|
||||
case 0x942192FF: ffStrbufAppendS(str, "Purple"); return;
|
||||
case 0xFF2600FF: ffStrbufAppendS(str, "Red"); return;
|
||||
case 0xFFFB00FF: ffStrbufAppendS(str, "Yellow"); return;
|
||||
case 0xFFFFFFFF: ffStrbufAppendS(str, "White"); return;
|
||||
case 0x00000000: ffStrbufAppendS(str, "Transparent"); return;
|
||||
default: ffStrbufAppendF(str, "#%08X", color); return;
|
||||
}
|
||||
}
|
||||
|
||||
void ffDetectCursor(FFCursorResult* result)
|
||||
@@ -46,7 +57,7 @@ void ffDetectCursor(FFCursorResult* result)
|
||||
|
||||
NSNumber* mouseDriverCursorSize = dict[@"mouseDriverCursorSize"];
|
||||
if (mouseDriverCursorSize)
|
||||
ffStrbufAppendF(&result->size, "%d", (int) (mouseDriverCursorSize.doubleValue * 32));
|
||||
ffStrbufAppendF(&result->size, "%d", (int) (mouseDriverCursorSize.doubleValue * 32 + 0.5));
|
||||
else
|
||||
ffStrbufAppendS(&result->size, "32");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/de/option.h"
|
||||
|
||||
const char* ffDetectDEVersion(const FFstrbuf* deName, FFstrbuf* result, FFDEOptions* options);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/disk/option.h"
|
||||
|
||||
typedef struct FFDisk
|
||||
{
|
||||
|
||||
@@ -55,6 +55,9 @@ static bool isPhysicalDevice(const struct mntent* device)
|
||||
ffStrStartsWith(device->mnt_fsname + 5, "fd") //Ignore fd devices
|
||||
) return false;
|
||||
|
||||
if (ffStrStartsWith(device->mnt_dir, "/bedrock/")) // Ignore Bedrock Linux subvolumes
|
||||
return false;
|
||||
|
||||
struct stat deviceStat;
|
||||
if(stat(device->mnt_fsname, &deviceStat) != 0)
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/diskio/option.h"
|
||||
|
||||
typedef struct FFDiskIOResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/display/option.h"
|
||||
|
||||
#define FF_DE_PRETTY_PLASMA "KDE Plasma"
|
||||
#define FF_DE_PRETTY_GNOME "GNOME"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/time.h"
|
||||
#include "util/edidHelper.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -24,6 +25,9 @@ typedef struct XcbPropertyData
|
||||
FF_LIBRARY_SYMBOL(xcb_get_atom_name_name)
|
||||
FF_LIBRARY_SYMBOL(xcb_get_atom_name_name_length)
|
||||
FF_LIBRARY_SYMBOL(xcb_get_atom_name_reply)
|
||||
FF_LIBRARY_SYMBOL(xcb_get_setup)
|
||||
FF_LIBRARY_SYMBOL(xcb_setup_vendor)
|
||||
FF_LIBRARY_SYMBOL(xcb_setup_vendor_length)
|
||||
} XcbPropertyData;
|
||||
|
||||
static bool xcbInitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, XcbPropertyData* propertyData)
|
||||
@@ -38,6 +42,9 @@ static bool xcbInitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, XcbProperty
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_name, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_name_length, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_reply, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_setup, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_setup_vendor, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_setup_vendor_length, false)
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -86,6 +93,23 @@ static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connect
|
||||
ffStrbufSetS(&result->wmProcessName, wmName);
|
||||
}
|
||||
|
||||
static void xcbFetchServerVendor(XcbPropertyData* data, xcb_connection_t* connection, FFDisplayServerResult* result)
|
||||
{
|
||||
const xcb_setup_t* setup = data->ffxcb_get_setup(connection);
|
||||
|
||||
int length = data->ffxcb_setup_vendor_length(setup);
|
||||
if(length <= 0)
|
||||
return;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY serverVendor = ffStrbufCreateNS((uint32_t) length, data->ffxcb_setup_vendor(setup));
|
||||
|
||||
if (!ffStrbufEqualS(&serverVendor, "The X.Org Foundation")) // Original
|
||||
{
|
||||
ffStrbufDestroy(&result->wmProtocolName);
|
||||
ffStrbufInitMove(&result->wmProtocolName, &serverVendor);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct XcbRandrData
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources_current)
|
||||
@@ -381,8 +405,10 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(data.connection));
|
||||
|
||||
|
||||
if(iterator.rem > 0 && propertyDataInitialized)
|
||||
if(iterator.rem > 0 && propertyDataInitialized) {
|
||||
xcbDetectWMfromEWMH(&data.propData, data.connection, iterator.data->root, result);
|
||||
xcbFetchServerVendor(&data.propData, data.connection, result);
|
||||
}
|
||||
|
||||
|
||||
while(iterator.rem > 0)
|
||||
|
||||
@@ -14,6 +14,7 @@ typedef struct X11PropertyData
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(XInternAtom)
|
||||
FF_LIBRARY_SYMBOL(XGetWindowProperty)
|
||||
FF_LIBRARY_SYMBOL(XServerVendor)
|
||||
FF_LIBRARY_SYMBOL(XFree)
|
||||
} X11PropertyData;
|
||||
|
||||
@@ -21,6 +22,7 @@ static bool x11InitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, X11Property
|
||||
{
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XInternAtom, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XGetWindowProperty, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XServerVendor, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XFree, false)
|
||||
|
||||
return true;
|
||||
@@ -62,6 +64,16 @@ static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDispl
|
||||
data->ffXFree(wmWindow);
|
||||
}
|
||||
|
||||
static void x11FetchServerVendor(X11PropertyData* data, Display* display, FFDisplayServerResult* result)
|
||||
{
|
||||
const char* serverVendor = data->ffXServerVendor(display);
|
||||
if (serverVendor && !ffStrEquals(serverVendor, "The X.Org Foundation")) {
|
||||
ffStrbufSetS(&result->wmProtocolName, serverVendor);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
typedef struct XrandrData
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(XInternAtom)
|
||||
@@ -305,8 +317,10 @@ const char* ffdsConnectXrandr(FFDisplayServerResult* result)
|
||||
if(data.display == NULL)
|
||||
return "XOpenDisplay() failed";
|
||||
|
||||
if(propertyDataInitialized && ScreenCount(data.display) > 0)
|
||||
if(propertyDataInitialized && ScreenCount(data.display) > 0) {
|
||||
x11DetectWMFromEWMH(&propertyData, data.display, result);
|
||||
x11FetchServerVendor(&propertyData, data.display, result);
|
||||
}
|
||||
|
||||
data.result = result;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/dns/option.h"
|
||||
|
||||
const char* ffDetectDNS(FFDNSOptions* options, FFlist* results /* list of FFstrbuf */);
|
||||
|
||||
@@ -37,7 +37,7 @@ const char* ffDetectDNS(FFDNSOptions* options, FFlist* results)
|
||||
return "GetAdaptersAddresses() failed";
|
||||
}
|
||||
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex();
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex;
|
||||
// Iterate through all of the adapters
|
||||
for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/editor/option.h"
|
||||
|
||||
typedef struct FFEditorResult
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/font/option.h"
|
||||
|
||||
#define FF_DETECT_FONT_NUM_FONTS 4
|
||||
enum { FF_DETECT_FONT_NUM_FONTS = 4 };
|
||||
|
||||
typedef struct FFFontResult
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "detection/vulkan/vulkan.h"
|
||||
#include "detection/opencl/opencl.h"
|
||||
#include "detection/opengl/opengl.h"
|
||||
#include "modules/opengl/opengl.h"
|
||||
|
||||
const char* FF_GPU_VENDOR_NAME_APPLE = "Apple";
|
||||
const char* FF_GPU_VENDOR_NAME_AMD = "AMD";
|
||||
@@ -56,7 +57,10 @@ const char* detectByOpenGL(FFlist* gpus)
|
||||
ffStrbufInit(&result.slv);
|
||||
ffStrbufInit(&result.library);
|
||||
|
||||
const char* error = ffDetectOpenGL(&instance.config.modules.openGL, &result);
|
||||
__attribute__((__cleanup__(ffDestroyOpenGLOptions))) FFOpenGLOptions options;
|
||||
ffInitOpenGLOptions(&options);
|
||||
const char* error = ffDetectOpenGL(&options, &result);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
FFGPUResult* gpu = (FFGPUResult*) ffListAdd(gpus);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/gpu/option.h"
|
||||
|
||||
#define FF_GPU_TEMP_UNSET (0/0.0)
|
||||
#define FF_GPU_TEMP_UNSET (-DBL_MAX)
|
||||
#define FF_GPU_CORE_COUNT_UNSET -1
|
||||
#define FF_GPU_VMEM_SIZE_UNSET ((uint64_t)-1)
|
||||
#define FF_GPU_FREQUENCY_UNSET 0
|
||||
#define FF_GPU_CORE_USAGE_UNSET (0/0.0)
|
||||
#define FF_GPU_CORE_USAGE_UNSET (-DBL_MAX)
|
||||
#define FF_GPU_INDEX_UNSET ((uint32_t)-1)
|
||||
|
||||
extern const char* FF_GPU_VENDOR_NAME_APPLE;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "gpu.h"
|
||||
#include "common/library.h"
|
||||
#include "detection/cpu/cpu.h"
|
||||
#include "util/apple/cf_helpers.h"
|
||||
#include "util/apple/smc_temps.h"
|
||||
|
||||
@@ -109,7 +107,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
gpu->type = FF_GPU_TYPE_UNKNOWN;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
IORegistryEntryGetRegistryEntryID(registryEntry, &gpu->deviceId);
|
||||
ffStrbufInitStatic(&gpu->platformApi, "Metal");
|
||||
ffStrbufInitStatic(&gpu->platformApi, "IOKit");
|
||||
|
||||
ffStrbufInit(&gpu->driver); // Ok for both Apple and Intel
|
||||
ffCfDictGetString(properties, CFSTR("CFBundleIdentifier"), &gpu->driver);
|
||||
|
||||
@@ -106,7 +106,10 @@ static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus)
|
||||
.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);
|
||||
{
|
||||
driverName[ver.name_len] = '\0';
|
||||
ffStrbufSetF(&gpu->driver, "%s %d.%d.%d", ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel);
|
||||
}
|
||||
|
||||
if (ffStrStartsWith(driverName, "i915"))
|
||||
ffDrmDetectI915(gpu, fd);
|
||||
|
||||
+194
-32
@@ -4,13 +4,11 @@
|
||||
#include "util/windows/unicode.h"
|
||||
#include "util/windows/registry.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#define INITGUID
|
||||
#include <cfgmgr32.h>
|
||||
#include <ntddvdeo.h>
|
||||
#include <devpkey.h>
|
||||
#include "util/debug.h"
|
||||
#include "util/windows/nt.h"
|
||||
|
||||
#include <cfgmgr32.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 };
|
||||
|
||||
@@ -19,35 +17,55 @@ const uint32_t regDirectxKeyPrefixLength = (uint32_t) __builtin_strlen("SOFTWARE
|
||||
wchar_t regDriverKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Class\\" FF_EMPTY_GUID_STR L"\\0000";
|
||||
const uint32_t regDriverKeyPrefixLength = (uint32_t) __builtin_strlen("SYSTEM\\CurrentControlSet\\Control\\Class\\");
|
||||
|
||||
#define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in <devguid.h>
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
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";
|
||||
FF_DEBUG("Starting GPU detection");
|
||||
|
||||
FF_AUTO_FREE DEVINSTID_W devInfList = malloc(devInfListSize * sizeof(*devInfList));
|
||||
|
||||
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)
|
||||
ULONG devIdListSize = 0;
|
||||
if (CM_Get_Device_ID_List_SizeW(&devIdListSize, GUID_DEVCLASS_DISPLAY_STRING, CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT) != CR_SUCCESS || devIdListSize <= 1)
|
||||
{
|
||||
if (wcsncmp(devInf, L"\\\\?\\ROOT#BasicDisplay#", 22) == 0)
|
||||
continue; // Skip Microsoft Basic Display Adapter
|
||||
FF_DEBUG("No display devices found, list size: %lu", devIdListSize);
|
||||
return "No display devices found";
|
||||
}
|
||||
|
||||
FF_DEBUG("Found device ID list size: %lu", devIdListSize);
|
||||
|
||||
FF_AUTO_FREE DEVINSTID_W devIdList = malloc(devIdListSize * sizeof(*devIdList));
|
||||
|
||||
if (CM_Get_Device_ID_ListW(GUID_DEVCLASS_DISPLAY_STRING, devIdList, devIdListSize, CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT) != CR_SUCCESS)
|
||||
{
|
||||
FF_DEBUG("CM_Get_Device_ID_ListW failed");
|
||||
return "CM_Get_Device_ID_ListW failed";
|
||||
}
|
||||
|
||||
int deviceCount = 0;
|
||||
for (wchar_t* devId = devIdList; *devId; devId += wcslen(devId) + 1)
|
||||
{
|
||||
FF_DEBUG("Processing device ID: %ls", devId);
|
||||
|
||||
if (wcsncmp(devId, L"SWD\\", 4) == 0)
|
||||
{
|
||||
FF_DEBUG("Skipping SWD device interface to avoid duplicates");
|
||||
continue;
|
||||
}
|
||||
|
||||
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)
|
||||
if (CM_Locate_DevNodeW(&devInst, devId, CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS)
|
||||
{
|
||||
FF_DEBUG("Failed to get device instance ID or locate device node");
|
||||
continue;
|
||||
}
|
||||
FF_DEBUG("Device instance ID: %lu", devInst);
|
||||
}
|
||||
|
||||
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
|
||||
deviceCount++;
|
||||
FF_DEBUG("Added GPU #%d to list", deviceCount);
|
||||
|
||||
ffStrbufInit(&gpu->vendor);
|
||||
ffStrbufInit(&gpu->name);
|
||||
ffStrbufInit(&gpu->driver);
|
||||
@@ -63,8 +81,15 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
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)
|
||||
if (swscanf(devId, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId) == 4)
|
||||
{
|
||||
FF_DEBUG("Parsed PCI IDs - Vendor: 0x%x, Device: 0x%x, SubSystem: 0x%x, Rev: 0x%x", vendorId, deviceId, subSystemId, revId);
|
||||
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to parse PCI device information from instance ID");
|
||||
}
|
||||
|
||||
uint32_t pciBus = 0, pciAddr = 0, pciDev = 0, pciFunc = 0;
|
||||
|
||||
@@ -78,53 +103,87 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
pciFunc = pciAddr & 0xFFFF;
|
||||
gpu->deviceId = (pciBus * 1000ull) + (pciDev * 10ull) + pciFunc;
|
||||
pciAddr = 1; // Set to 1 to indicate that the device is a PCI device
|
||||
FF_DEBUG("PCI location - Bus: %u, Device: %u, Function: %u, DeviceID: %llu", pciBus, pciDev, pciFunc, gpu->deviceId);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get PCI address");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get PCI bus number");
|
||||
}
|
||||
|
||||
uint64_t adapterLuid = 0;
|
||||
|
||||
FF_HKEY_AUTO_DESTROY hVideoIdKey = NULL;
|
||||
|
||||
wchar_t buffer[256];
|
||||
ULONG bufferLen = 0;
|
||||
if (CM_Open_DevNode_Key(devInst, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hVideoIdKey, CM_REGISTRY_HARDWARE) == CR_SUCCESS)
|
||||
{
|
||||
FF_DEBUG("Opened device node registry key");
|
||||
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_DEBUG("Found VideoID: %ls", buffer);
|
||||
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
|
||||
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
|
||||
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
|
||||
{
|
||||
FF_DEBUG("Opened DirectX registry key");
|
||||
|
||||
if (gpu->vendor.length == 0)
|
||||
{
|
||||
uint32_t vendorId = 0;
|
||||
if(ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId)
|
||||
{
|
||||
FF_DEBUG("Found vendor ID from DirectX registry: 0x%x", vendorId);
|
||||
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
|
||||
}
|
||||
}
|
||||
|
||||
ffRegReadStrbuf(hDirectxKey, L"Description", &gpu->name, NULL);
|
||||
if (ffRegReadStrbuf(hDirectxKey, L"Description", &gpu->name, NULL))
|
||||
FF_DEBUG("Found GPU description: %s", gpu->name.chars);
|
||||
|
||||
if (ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &gpu->dedicated.total, NULL))
|
||||
FF_DEBUG("Found dedicated video memory: %llu bytes", gpu->dedicated.total);
|
||||
|
||||
ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &gpu->dedicated.total, NULL);
|
||||
if (ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &gpu->shared.total, NULL))
|
||||
{
|
||||
FF_DEBUG("Found dedicated system memory: %llu bytes", gpu->shared.total);
|
||||
uint64_t sharedSystemMemory = 0;
|
||||
if (ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL))
|
||||
{
|
||||
gpu->shared.total += sharedSystemMemory;
|
||||
FF_DEBUG("Added shared system memory: %llu bytes, total shared: %llu bytes", sharedSystemMemory, gpu->shared.total);
|
||||
}
|
||||
}
|
||||
|
||||
if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL))
|
||||
{
|
||||
FF_DEBUG("Found adapter LUID: %llu", adapterLuid);
|
||||
if (!gpu->deviceId) gpu->deviceId = adapterLuid;
|
||||
}
|
||||
|
||||
uint32_t featureLevel = 0;
|
||||
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
|
||||
{
|
||||
FF_DEBUG("Found D3D12 feature level: 0x%x", featureLevel);
|
||||
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
|
||||
}
|
||||
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
|
||||
{
|
||||
FF_DEBUG("Found D3D11 feature level: 0x%x", featureLevel);
|
||||
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
|
||||
}
|
||||
|
||||
uint64_t driverVersion = 0;
|
||||
if(ffRegReadUint64(hDirectxKey, L"DriverVersion", &driverVersion, NULL) && driverVersion)
|
||||
{
|
||||
FF_DEBUG("Found driver version: %llu", driverVersion);
|
||||
ffStrbufSetF(&gpu->driver, "%u.%u.%u.%u",
|
||||
(unsigned) (driverVersion >> 48) & 0xFFFF,
|
||||
(unsigned) (driverVersion >> 32) & 0xFFFF,
|
||||
@@ -133,21 +192,38 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to open DirectX registry key");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get VideoID or invalid buffer length");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to open device node registry key");
|
||||
}
|
||||
|
||||
if (gpu->vendor.length == 0 || gpu->name.length == 0)
|
||||
{
|
||||
FF_DEBUG("Trying fallback registry method for vendor/name");
|
||||
bufferLen = sizeof(buffer);
|
||||
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DRIVER, NULL, buffer, &bufferLen, 0) == CR_SUCCESS &&
|
||||
bufferLen == (FF_GUID_STRLEN + strlen("\\0000") + 1) * 2)
|
||||
{
|
||||
FF_DEBUG("Found driver GUID: %ls", buffer);
|
||||
wmemcpy(regDriverKey + regDriverKeyPrefixLength, buffer, FF_GUID_STRLEN + strlen("\\0000"));
|
||||
FF_HKEY_AUTO_DESTROY hRegDriverKey = NULL;
|
||||
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDriverKey, &hRegDriverKey, NULL))
|
||||
{
|
||||
FF_DEBUG("Opened driver registry key");
|
||||
|
||||
if (gpu->vendor.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"ProviderName", &gpu->vendor, NULL))
|
||||
{
|
||||
FF_DEBUG("Found provider name: %s", gpu->vendor.chars);
|
||||
if (ffStrbufContainS(&gpu->vendor, "Intel"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
|
||||
else if (ffStrbufContainS(&gpu->vendor, "NVIDIA"))
|
||||
@@ -155,20 +231,35 @@ 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->name.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"DriverDesc", &gpu->name, NULL))
|
||||
FF_DEBUG("Found driver description: %s", gpu->name.chars);
|
||||
if (gpu->driver.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"DriverVersion", &gpu->driver, NULL))
|
||||
FF_DEBUG("Found driver version: %s", gpu->driver.chars);
|
||||
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;
|
||||
FF_DEBUG("Found memory size from hardware info: %u bytes", memorySize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Found qwMemorySize from hardware info: %llu bytes", gpu->dedicated.total);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to open driver registry key");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get driver GUID or invalid buffer length");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +268,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
|
||||
if (options->driverSpecific && getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName))
|
||||
{
|
||||
FF_DEBUG("Calling driver-specific detection function for vendor: %s, DLL: %s", gpu->vendor.chars, dllName);
|
||||
detectFn(
|
||||
&(FFGpuDriverCondition) {
|
||||
.type = (deviceId > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID : 0)
|
||||
@@ -210,17 +302,31 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
},
|
||||
dllName
|
||||
);
|
||||
FF_DEBUG("Driver-specific detection completed");
|
||||
}
|
||||
else if (options->driverSpecific)
|
||||
{
|
||||
FF_DEBUG("No driver-specific detection function found for vendor: %s", gpu->vendor.chars);
|
||||
}
|
||||
|
||||
if (!gpu->name.length)
|
||||
{
|
||||
FF_DEBUG("Trying to get device description as fallback");
|
||||
bufferLen = sizeof(buffer);
|
||||
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DEVICEDESC, NULL, buffer, &bufferLen, 0) == CR_SUCCESS)
|
||||
{
|
||||
ffStrbufSetWS(&gpu->name, buffer);
|
||||
FF_DEBUG("Found device description: %s", gpu->name.chars);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get device description");
|
||||
}
|
||||
}
|
||||
|
||||
if (gpu->type == FF_GPU_TYPE_UNKNOWN && adapterLuid > 0)
|
||||
{
|
||||
FF_DEBUG("Trying to determine GPU type using D3DKMT APIs");
|
||||
HMODULE hgdi32 = GetModuleHandleW(L"gdi32.dll");
|
||||
if (hgdi32)
|
||||
{
|
||||
@@ -230,6 +336,8 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
D3DKMT_OPENADAPTERFROMLUID openAdapterFromLuid = { .AdapterLuid = *(LUID*)&adapterLuid };
|
||||
if (NT_SUCCESS(ffD3DKMTOpenAdapterFromLuid(&openAdapterFromLuid)))
|
||||
{
|
||||
FF_DEBUG("Successfully opened adapter from LUID");
|
||||
|
||||
D3DKMT_ADAPTERTYPE adapterType = {};
|
||||
D3DKMT_QUERYADAPTERINFO queryAdapterInfo = {
|
||||
.hAdapter = openAdapterFromLuid.hAdapter,
|
||||
@@ -239,14 +347,20 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
};
|
||||
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) // Vista and later
|
||||
{
|
||||
FF_DEBUG("Queried adapter type - HybridDiscrete: %d, HybridIntegrated: %d", adapterType.HybridDiscrete, adapterType.HybridIntegrated);
|
||||
if (adapterType.HybridDiscrete)
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
else if (adapterType.HybridIntegrated)
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to query adapter type");
|
||||
}
|
||||
|
||||
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET)
|
||||
{
|
||||
FF_DEBUG("Trying to get GPU frequency information");
|
||||
for (ULONG nodeIdx = 0; ; nodeIdx++)
|
||||
{
|
||||
D3DKMT_NODEMETADATA nodeMetadata = {
|
||||
@@ -258,8 +372,16 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
.pPrivateDriverData = &nodeMetadata,
|
||||
.PrivateDriverDataSize = sizeof(nodeMetadata),
|
||||
};
|
||||
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) break; // Windows 10 and later
|
||||
if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D) continue;
|
||||
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo)))
|
||||
{
|
||||
FF_DEBUG("No more nodes to query (index %lu)", nodeIdx);
|
||||
break; // Windows 10 and later
|
||||
}
|
||||
if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D)
|
||||
{
|
||||
FF_DEBUG("Skipping node %lu (not 3D engine)", nodeIdx);
|
||||
continue;
|
||||
}
|
||||
|
||||
D3DKMT_QUERYSTATISTICS queryStatistics = {
|
||||
.Type = D3DKMT_QUERYSTATISTICS_NODE2,
|
||||
@@ -269,18 +391,29 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) // Windows 11 (22H2) and later
|
||||
{
|
||||
gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000);
|
||||
FF_DEBUG("Found GPU frequency: %u MHz", gpu->frequency);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to query node statistics for node %lu", nodeIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter };
|
||||
(void) D3DKMTCloseAdapter(&closeAdapter);
|
||||
openAdapterFromLuid.hAdapter = 0;
|
||||
FF_DEBUG("Closed adapter handle");
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to open adapter from LUID");
|
||||
}
|
||||
|
||||
if (options->temp && gpu->temperature != gpu->temperature)
|
||||
if (options->temp && gpu->temperature == FF_GPU_TEMP_UNSET)
|
||||
{
|
||||
FF_DEBUG("Trying to get GPU temperature");
|
||||
D3DKMT_QUERYSTATISTICS queryStatistics = {
|
||||
.Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER,
|
||||
.AdapterLuid = *(LUID*)&adapterLuid,
|
||||
@@ -288,20 +421,49 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
};
|
||||
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)) &&
|
||||
queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0)
|
||||
{
|
||||
gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0;
|
||||
FF_DEBUG("Found GPU temperature: %.1f°C", gpu->temperature);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get GPU temperature or temperature is 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("D3DKMTOpenAdapterFromLuid not available");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get gdi32.dll module handle");
|
||||
}
|
||||
}
|
||||
|
||||
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
|
||||
{
|
||||
FF_DEBUG("Using fallback GPU type detection");
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
|
||||
{
|
||||
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
FF_DEBUG("Intel GPU type determined: %s", gpu->type == FF_GPU_TYPE_INTEGRATED ? "Integrated" : "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;
|
||||
FF_DEBUG("GPU type determined by memory size (%llu bytes): %s", gpu->dedicated.total, gpu->type == FF_GPU_TYPE_DISCRETE ? "Discrete" : "Integrated");
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Unable to determine GPU type");
|
||||
}
|
||||
}
|
||||
|
||||
FF_DEBUG("Completed processing GPU #%d - Vendor: %s, Name: %s, Type: %d", deviceCount, gpu->vendor.chars, gpu->name.chars, gpu->type);
|
||||
}
|
||||
|
||||
FF_DEBUG("GPU detection completed, found %d devices", deviceCount);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/host/option.h"
|
||||
|
||||
typedef struct FFHostResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/icons/option.h"
|
||||
|
||||
typedef struct FFIconsResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/initsystem/option.h"
|
||||
|
||||
typedef struct FFInitSystemResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/lm/option.h"
|
||||
|
||||
typedef struct FFLMResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/localip/option.h"
|
||||
|
||||
typedef struct FFLocalIpResult
|
||||
{
|
||||
@@ -11,7 +12,7 @@ typedef struct FFLocalIpResult
|
||||
FFstrbuf flags;
|
||||
int32_t mtu;
|
||||
int32_t speed; // in Mbps
|
||||
bool defaultRoute;
|
||||
FFLocalIpType defaultRoute;
|
||||
} FFLocalIpResult;
|
||||
|
||||
typedef struct FFLocalIpNIFlag
|
||||
@@ -20,7 +21,7 @@ typedef struct FFLocalIpNIFlag
|
||||
const char *name;
|
||||
} FFLocalIpNIFlag;
|
||||
|
||||
static inline void ffLocalIpFillNIFlags(FFstrbuf *buf, uint32_t flag, const FFLocalIpNIFlag names[])
|
||||
static inline void ffLocalIpFillNIFlags(FFstrbuf *buf, uint64_t flag, const FFLocalIpNIFlag names[])
|
||||
{
|
||||
for (const FFLocalIpNIFlag *nf = names; flag && nf->name; ++nf)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "common/io/io.h"
|
||||
#include "common/netif/netif.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
@@ -11,11 +12,18 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_addr.h>
|
||||
#endif
|
||||
|
||||
#if __has_include(<netinet6/in6_var.h>)
|
||||
#include <netinet6/in6_var.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined(__HAIKU__)
|
||||
@@ -27,212 +35,550 @@
|
||||
#if defined(__sun) || defined(__HAIKU__)
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
#if defined(__sun)
|
||||
#include <kstat.h>
|
||||
|
||||
static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
{
|
||||
assert(pkc);
|
||||
if (*pkc)
|
||||
kstat_close(*pkc);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define FF_LOCALIP_NIFLAG(name) { IFF_##name, #name }
|
||||
|
||||
static const FFLocalIpNIFlag niFlagOptions[] = {
|
||||
{ IFF_UP, "UP" },
|
||||
{ IFF_BROADCAST, "BROADCAST" },
|
||||
FF_LOCALIP_NIFLAG(UP),
|
||||
FF_LOCALIP_NIFLAG(BROADCAST),
|
||||
#ifdef IFF_DEBUG
|
||||
{ IFF_DEBUG, "DEBUG" },
|
||||
FF_LOCALIP_NIFLAG(DEBUG),
|
||||
#endif
|
||||
{ IFF_LOOPBACK, "LOOPBACK" },
|
||||
{ IFF_POINTOPOINT, "POINTOPOINT" },
|
||||
FF_LOCALIP_NIFLAG(LOOPBACK),
|
||||
FF_LOCALIP_NIFLAG(POINTOPOINT),
|
||||
#ifdef IFF_RUNNING
|
||||
{ IFF_RUNNING, "RUNNING" },
|
||||
FF_LOCALIP_NIFLAG(RUNNING),
|
||||
#endif
|
||||
{ IFF_NOARP, "NOARP" },
|
||||
{ IFF_PROMISC, "PROMISC" },
|
||||
{ IFF_ALLMULTI, "ALLMULTI" },
|
||||
{ IFF_MULTICAST, "MULTICAST" },
|
||||
FF_LOCALIP_NIFLAG(NOARP),
|
||||
FF_LOCALIP_NIFLAG(PROMISC),
|
||||
FF_LOCALIP_NIFLAG(ALLMULTI),
|
||||
#ifdef IFF_INTELLIGENT
|
||||
FF_LOCALIP_NIFLAG(INTELLIGENT),
|
||||
#endif
|
||||
FF_LOCALIP_NIFLAG(MULTICAST),
|
||||
#ifdef IFF_NOTRAILERS
|
||||
{ IFF_NOTRAILERS, "NOTRAILERS" },
|
||||
FF_LOCALIP_NIFLAG(NOTRAILERS),
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
{ IFF_MASTER, "MASTER" },
|
||||
{ IFF_SLAVE, "SLAVE" },
|
||||
{ IFF_PORTSEL, "PORTSEL" },
|
||||
{ IFF_AUTOMEDIA, "AUTOMEDIA" },
|
||||
{ IFF_DYNAMIC, "DYNAMIC" },
|
||||
{ IFF_LOWER_UP, "LOWER_UP" },
|
||||
{ IFF_DORMANT, "DORMANT" },
|
||||
{ IFF_ECHO, "ECHO" },
|
||||
FF_LOCALIP_NIFLAG(MASTER),
|
||||
FF_LOCALIP_NIFLAG(SLAVE),
|
||||
FF_LOCALIP_NIFLAG(PORTSEL),
|
||||
FF_LOCALIP_NIFLAG(AUTOMEDIA),
|
||||
FF_LOCALIP_NIFLAG(DYNAMIC),
|
||||
FF_LOCALIP_NIFLAG(LOWER_UP),
|
||||
FF_LOCALIP_NIFLAG(DORMANT),
|
||||
FF_LOCALIP_NIFLAG(ECHO),
|
||||
#endif
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
{ IFF_OACTIVE, "OACTIVE" },
|
||||
{ IFF_SIMPLEX, "SIMPLEX" },
|
||||
{ IFF_LINK0, "LINK0" },
|
||||
{ IFF_LINK1, "LINK1" },
|
||||
{ IFF_LINK2, "LINK2" },
|
||||
FF_LOCALIP_NIFLAG(OACTIVE),
|
||||
FF_LOCALIP_NIFLAG(SIMPLEX),
|
||||
FF_LOCALIP_NIFLAG(LINK0),
|
||||
FF_LOCALIP_NIFLAG(LINK1),
|
||||
FF_LOCALIP_NIFLAG(LINK2),
|
||||
#endif
|
||||
#ifdef IFF_ALTPHYS
|
||||
{ IFF_ALTPHYS, "ALTPHYS" },
|
||||
FF_LOCALIP_NIFLAG(ALTPHYS),
|
||||
#endif
|
||||
#ifdef IFF_CANTCONFIG
|
||||
{ IFF_CANTCONFIG, "CANTCONFIG" },
|
||||
FF_LOCALIP_NIFLAG(CANTCONFIG),
|
||||
#endif
|
||||
#ifdef __HAIKU__
|
||||
{ IFF_AUTOUP, "IAUTOUP" },
|
||||
{ IFF_SIMPLEX, "SIMPLEX" },
|
||||
{ IFF_LINK, "LINK" },
|
||||
{ IFF_AUTO_CONFIGURED, "AUTO_CONFIGURED" },
|
||||
{ IFF_CONFIGURING, "CONFIGURING" },
|
||||
FF_LOCALIP_NIFLAG(AUTOUP),
|
||||
FF_LOCALIP_NIFLAG(SIMPLEX),
|
||||
FF_LOCALIP_NIFLAG(LINK),
|
||||
FF_LOCALIP_NIFLAG(AUTO_CONFIGURED),
|
||||
FF_LOCALIP_NIFLAG(CONFIGURING),
|
||||
#endif
|
||||
#ifdef __sun
|
||||
FF_LOCALIP_NIFLAG(MULTI_BCAST),
|
||||
FF_LOCALIP_NIFLAG(UNNUMBERED),
|
||||
FF_LOCALIP_NIFLAG(DHCPRUNNING),
|
||||
FF_LOCALIP_NIFLAG(PRIVATE),
|
||||
#endif
|
||||
// sentinel
|
||||
{},
|
||||
};
|
||||
|
||||
static void addNewIp(FFlist* list, const char* name, const char* addr, int type, bool defaultRoute, uint32_t flags, bool firstOnly)
|
||||
typedef enum __attribute__((__packed__)) FFIPv6Type
|
||||
{
|
||||
FFLocalIpResult* ip = NULL;
|
||||
FF_IPV6_Other,
|
||||
FF_IPV6_GUA = 0b0001,
|
||||
FF_IPV6_GUA_SECONDARY = 0b0101,
|
||||
FF_IPV6_ULA = 0b0010,
|
||||
FF_IPV6_ULA_SECONDARY = 0b0110,
|
||||
FF_IPV6_TYPE_MASK = 0b0011,
|
||||
FF_IPV6_SECONDARY_FLAG = 0b1100,
|
||||
FF_IPV6_PREFERRED = UINT8_MAX,
|
||||
} FFIPv6Type;
|
||||
|
||||
FF_LIST_FOR_EACH(FFLocalIpResult, temp, *list)
|
||||
static FFIPv6Type getIpType(struct ifaddrs* ifa)
|
||||
{
|
||||
struct sockaddr_in6* addr = (struct sockaddr_in6*) ifa->ifa_addr;
|
||||
|
||||
FF_DEBUG("Checking IPv6 type for interface %s", ifa->ifa_name);
|
||||
|
||||
#ifndef IN6_IS_ADDR_GLOBAL
|
||||
#define IN6_IS_ADDR_GLOBAL(a) \
|
||||
((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000))
|
||||
#endif
|
||||
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
|
||||
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) \
|
||||
((((const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl(0xfc000000))
|
||||
#endif
|
||||
FFIPv6Type result = FF_IPV6_Other;
|
||||
if (IN6_IS_ADDR_GLOBAL(&addr->sin6_addr))
|
||||
{
|
||||
if (!ffStrbufEqualS(&temp->name, name)) continue;
|
||||
ip = temp;
|
||||
break;
|
||||
result = FF_IPV6_GUA;
|
||||
FF_DEBUG("Interface %s has Global Unicast Address", ifa->ifa_name);
|
||||
}
|
||||
if (!ip)
|
||||
else if (IN6_IS_ADDR_UNIQUE_LOCAL(&addr->sin6_addr))
|
||||
{
|
||||
ip = (FFLocalIpResult*) ffListAdd(list);
|
||||
ffStrbufInitS(&ip->name, name);
|
||||
ffStrbufInit(&ip->ipv4);
|
||||
ffStrbufInit(&ip->ipv6);
|
||||
ffStrbufInit(&ip->mac);
|
||||
ffStrbufInit(&ip->flags);
|
||||
ip->defaultRoute = defaultRoute;
|
||||
ip->mtu = -1;
|
||||
ip->speed = -1;
|
||||
|
||||
ffLocalIpFillNIFlags(&ip->flags, flags, niFlagOptions);
|
||||
result = FF_IPV6_ULA;
|
||||
FF_DEBUG("Interface %s has Unique Local Address", ifa->ifa_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Interface %s has other IPv6 address type", ifa->ifa_name);
|
||||
return FF_IPV6_Other;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
#ifdef SIOCGIFAFLAG_IN6
|
||||
static int sockfd = 0;
|
||||
if (sockfd == 0)
|
||||
{
|
||||
case AF_INET:
|
||||
if (ip->ipv4.length)
|
||||
{
|
||||
if (firstOnly) return;
|
||||
ffStrbufAppendC(&ip->ipv4, ',');
|
||||
}
|
||||
ffStrbufAppendS(&ip->ipv4, addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (ip->ipv6.length)
|
||||
{
|
||||
if (firstOnly) return;
|
||||
ffStrbufAppendC(&ip->ipv6, ',');
|
||||
}
|
||||
ffStrbufAppendS(&ip->ipv6, addr);
|
||||
break;
|
||||
case -1:
|
||||
ffStrbufSetS(&ip->mac, addr);
|
||||
break;
|
||||
sockfd = socket(AF_INET6, SOCK_DGRAM
|
||||
#ifdef SOCK_CLOEXEC
|
||||
| SOCK_CLOEXEC
|
||||
#endif
|
||||
, 0);
|
||||
#ifndef SOCK_CLOEXEC
|
||||
if (sockfd > 0) fcntl(sockfd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
}
|
||||
if (sockfd < 0) return result;
|
||||
|
||||
struct in6_ifreq ifr6 = {};
|
||||
ffStrCopy(ifr6.ifr_name, ifa->ifa_name, IFNAMSIZ);
|
||||
ifr6.ifr_addr = *addr;
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFAFLAG_IN6, &ifr6) != 0)
|
||||
return result;
|
||||
|
||||
#ifdef IN6_IFF_PREFER_SOURCE
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_PREFER_SOURCE)
|
||||
return FF_IPV6_PREFERRED;
|
||||
#endif
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY | IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED
|
||||
#ifdef IN6_IFF_OPTIMISTIC
|
||||
| IN6_IFF_OPTIMISTIC
|
||||
#endif
|
||||
)) result |= FF_IPV6_SECONDARY_FLAG;
|
||||
return result;
|
||||
#elif __linux__
|
||||
static FFlist addresses = {};
|
||||
if (addresses.elementSize == 0)
|
||||
{
|
||||
ffListInit(&addresses, sizeof(struct in6_addr));
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
if (!ffReadFileBuffer("/proc/net/if_inet6", &buffer))
|
||||
return result;
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
while (ffStrbufGetline(&line, &len, &buffer))
|
||||
{
|
||||
struct in6_addr* entry = (struct in6_addr*) ffListAdd(&addresses);
|
||||
uint8_t flags;
|
||||
if (sscanf(line, "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 "%2" SCNx8 " %*s %*s %*s %" SCNx8 " %*s",
|
||||
&entry->s6_addr[0], &entry->s6_addr[1], &entry->s6_addr[2], &entry->s6_addr[3],
|
||||
&entry->s6_addr[4], &entry->s6_addr[5], &entry->s6_addr[6], &entry->s6_addr[7],
|
||||
&entry->s6_addr[8], &entry->s6_addr[9], &entry->s6_addr[10], &entry->s6_addr[11],
|
||||
&entry->s6_addr[12], &entry->s6_addr[13], &entry->s6_addr[14], &entry->s6_addr[15],
|
||||
&flags) != 17 ||
|
||||
(!IN6_IS_ADDR_GLOBAL(entry) && !IN6_IS_ADDR_UNIQUE_LOCAL(entry)) ||
|
||||
(flags & (IFA_F_DEPRECATED | IFA_F_TEMPORARY | IFA_F_TENTATIVE | IFA_F_DADFAILED | IFA_F_OPTIMISTIC))
|
||||
)
|
||||
--addresses.length;
|
||||
}
|
||||
}
|
||||
if (addresses.capacity == 0) return result;
|
||||
|
||||
FF_LIST_FOR_EACH(struct in6_addr, entry, addresses)
|
||||
{
|
||||
if (memcmp(&addr->sin6_addr, entry, sizeof(struct in6_addr)) == 0)
|
||||
return result;
|
||||
}
|
||||
result |= FF_IPV6_SECONDARY_FLAG;
|
||||
return result;
|
||||
#elif __sun
|
||||
if (ifa->ifa_flags & IFF_PREFERRED)
|
||||
return FF_IPV6_PREFERRED;
|
||||
if (ifa->ifa_flags & (IFF_DEPRECATED | IFF_TEMPORARY | IFF_DUPLICATE))
|
||||
result |= FF_IPV6_SECONDARY_FLAG;
|
||||
return result;
|
||||
#else
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct ifaddrs* mac;
|
||||
FFlist /*<struct ifaddrs*>*/ ipv4;
|
||||
FFlist /*<struct ifaddrs*>*/ ipv6;
|
||||
} FFAdapter;
|
||||
|
||||
static void appendIpv4(const FFLocalIpOptions* options, FFstrbuf* buffer, const struct ifaddrs* ifa)
|
||||
{
|
||||
struct sockaddr_in* ipv4 = (struct sockaddr_in*) ifa->ifa_addr;
|
||||
|
||||
char addressBuffer[INET_ADDRSTRLEN + 16];
|
||||
inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN);
|
||||
|
||||
FF_DEBUG("Adding IPv4 address %s for interface %s", addressBuffer, ifa->ifa_name);
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_PREFIX_LEN_BIT)
|
||||
{
|
||||
struct sockaddr_in* netmask = (struct sockaddr_in*) ifa->ifa_netmask;
|
||||
int cidr = __builtin_popcount(netmask->sin_addr.s_addr);
|
||||
if (cidr != 0)
|
||||
{
|
||||
size_t len = strlen(addressBuffer);
|
||||
snprintf(addressBuffer + len, 16, "/%d", cidr);
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer->length) ffStrbufAppendC(buffer, ',');
|
||||
ffStrbufAppendS(buffer, addressBuffer);
|
||||
}
|
||||
|
||||
static void appendIpv6(const FFLocalIpOptions* options, FFstrbuf* buffer, const struct ifaddrs* ifa)
|
||||
{
|
||||
struct sockaddr_in6* ipv6 = (struct sockaddr_in6*) ifa->ifa_addr;
|
||||
|
||||
char addressBuffer[INET6_ADDRSTRLEN + 16];
|
||||
inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN);
|
||||
|
||||
FF_DEBUG("Adding IPv6 address %s for interface %s", addressBuffer, ifa->ifa_name);
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_PREFIX_LEN_BIT)
|
||||
{
|
||||
struct sockaddr_in6* netmask = (struct sockaddr_in6*) ifa->ifa_netmask;
|
||||
int cidr = 0;
|
||||
static_assert(sizeof(netmask->sin6_addr) % sizeof(uint64_t) == 0, "");
|
||||
for (uint32_t i = 0; i < sizeof(netmask->sin6_addr) / sizeof(uint64_t); ++i)
|
||||
cidr += __builtin_popcountll(((uint64_t*) &netmask->sin6_addr)[i]);
|
||||
if (cidr != 0)
|
||||
{
|
||||
size_t len = strlen(addressBuffer);
|
||||
snprintf(addressBuffer + len, 16, "/%d", cidr);
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer->length) ffStrbufAppendC(buffer, ',');
|
||||
ffStrbufAppendS(buffer, addressBuffer);
|
||||
}
|
||||
|
||||
const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
{
|
||||
FF_DEBUG("Starting local IP detection with showType=0x%x, namePrefix='%s'",
|
||||
options->showType, options->namePrefix.chars);
|
||||
|
||||
struct ifaddrs* ifAddrStruct = NULL;
|
||||
if(getifaddrs(&ifAddrStruct) < 0)
|
||||
{
|
||||
FF_DEBUG("getifaddrs() failed");
|
||||
return "getifaddrs(&ifAddrStruct) failed";
|
||||
}
|
||||
|
||||
const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName();
|
||||
FF_DEBUG("Successfully retrieved interface addresses");
|
||||
|
||||
FF_LIST_AUTO_DESTROY adapters = ffListCreate(sizeof(FFAdapter));
|
||||
|
||||
for (struct ifaddrs* ifa = ifAddrStruct; ifa; ifa = ifa->ifa_next)
|
||||
{
|
||||
if (!ifa->ifa_addr)
|
||||
{
|
||||
FF_DEBUG("Skipping interface %s (no address)", ifa->ifa_name);
|
||||
continue;
|
||||
#ifdef IFF_RUNNING
|
||||
if (!(ifa->ifa_flags & IFF_RUNNING))
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isDefaultRoute = ffStrEquals(defaultRouteIfName, ifa->ifa_name);
|
||||
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
|
||||
#ifdef IFF_RUNNING
|
||||
if (!(ifa->ifa_flags & IFF_RUNNING))
|
||||
{
|
||||
FF_DEBUG("Skipping interface %s (not running)", ifa->ifa_name);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((ifa->ifa_flags & IFF_LOOPBACK) && !(options->showType & FF_LOCALIP_TYPE_LOOP_BIT))
|
||||
{
|
||||
FF_DEBUG("Skipping loopback interface %s", ifa->ifa_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options->namePrefix.length && strncmp(ifa->ifa_name, options->namePrefix.chars, options->namePrefix.length) != 0)
|
||||
{
|
||||
FF_DEBUG("Skipping interface %s (doesn't match prefix '%s')",
|
||||
ifa->ifa_name, options->namePrefix.chars);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t flags = options->showType & FF_LOCALIP_TYPE_FLAGS_BIT ? ifa->ifa_flags : 0;
|
||||
|
||||
if (ifa->ifa_addr->sa_family == AF_INET)
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_MAC_BIT) &&
|
||||
ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
|
||||
{
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_IPV4_BIT))
|
||||
continue;
|
||||
FF_DEBUG("Skipping interface %s (unsupported address family %d)",
|
||||
ifa->ifa_name, ifa->ifa_addr->sa_family);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct sockaddr_in* ipv4 = (struct sockaddr_in*) ifa->ifa_addr;
|
||||
char addressBuffer[INET_ADDRSTRLEN + 16];
|
||||
inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN);
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_PREFIX_LEN_BIT)
|
||||
if (options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT)
|
||||
{
|
||||
// If the interface is not the default route for either IPv4 or IPv6, skip it
|
||||
if (!((options->showType & FF_LOCALIP_TYPE_IPV4_BIT) && ffStrEquals(ffNetifGetDefaultRouteV4()->ifName, ifa->ifa_name)) &&
|
||||
!((options->showType & FF_LOCALIP_TYPE_IPV6_BIT) && ffStrEquals(ffNetifGetDefaultRouteV6()->ifName, ifa->ifa_name)))
|
||||
{
|
||||
struct sockaddr_in* netmask = (struct sockaddr_in*) ifa->ifa_netmask;
|
||||
int cidr = __builtin_popcount(netmask->sin_addr.s_addr);
|
||||
if (cidr != 0)
|
||||
FF_DEBUG("Skipping interface %s (not default route interface)", ifa->ifa_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
FF_DEBUG("Processing interface %s (family=%d, flags=0x%x)",
|
||||
ifa->ifa_name, ifa->ifa_addr->sa_family, ifa->ifa_flags);
|
||||
|
||||
FFAdapter* adapter = NULL;
|
||||
FF_LIST_FOR_EACH(FFAdapter, x, adapters)
|
||||
{
|
||||
if (ffStrEquals(x->mac->ifa_name, ifa->ifa_name))
|
||||
{
|
||||
adapter = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!adapter)
|
||||
{
|
||||
adapter = ffListAdd(&adapters);
|
||||
*adapter = (FFAdapter) {
|
||||
.mac = ifa,
|
||||
.ipv4 = ffListCreate(sizeof(struct ifaddrs*)),
|
||||
.ipv6 = ffListCreate(sizeof(struct ifaddrs*)),
|
||||
};
|
||||
FF_DEBUG("Created new adapter entry for interface %s", ifa->ifa_name);
|
||||
}
|
||||
|
||||
switch (ifa->ifa_addr->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
if (options->showType & FF_LOCALIP_TYPE_IPV4_BIT)
|
||||
{
|
||||
size_t len = strlen(addressBuffer);
|
||||
snprintf(addressBuffer + len, 16, "/%d", cidr);
|
||||
*FF_LIST_ADD(struct ifaddrs*, adapter->ipv4) = ifa;
|
||||
FF_DEBUG("Added IPv4 entry for interface %s", ifa->ifa_name);
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (options->showType & FF_LOCALIP_TYPE_IPV6_BIT)
|
||||
{
|
||||
*FF_LIST_ADD(struct ifaddrs*, adapter->ipv6) = ifa;
|
||||
FF_DEBUG("Added IPv6 entry for interface %s", ifa->ifa_name);
|
||||
}
|
||||
break;
|
||||
#if __FreeBSD__ || __OpenBSD__ || __APPLE__ || __NetBSD__ || __HAIKU__
|
||||
case AF_LINK:
|
||||
adapter->mac = ifa;
|
||||
FF_DEBUG("Updated MAC entry for interface %s", ifa->ifa_name);
|
||||
break;
|
||||
#elif !__sun
|
||||
case AF_PACKET:
|
||||
adapter->mac = ifa;
|
||||
FF_DEBUG("Updated MAC entry for interface %s", ifa->ifa_name);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
FF_DEBUG("Found %u network adapters", adapters.length);
|
||||
|
||||
FF_LIST_FOR_EACH(FFAdapter, adapter, adapters)
|
||||
{
|
||||
FF_DEBUG("Processing adapter %s (IPv4 entries: %u, IPv6 entries: %u)",
|
||||
adapter->mac->ifa_name, adapter->ipv4.length, adapter->ipv6.length);
|
||||
|
||||
FFLocalIpResult* item = FF_LIST_ADD(FFLocalIpResult, *results);
|
||||
ffStrbufInitS(&item->name, adapter->mac->ifa_name);
|
||||
ffStrbufInit(&item->ipv4);
|
||||
ffStrbufInit(&item->ipv6);
|
||||
ffStrbufInit(&item->mac);
|
||||
ffStrbufInit(&item->flags);
|
||||
item->defaultRoute = FF_LOCALIP_TYPE_NONE;
|
||||
item->mtu = -1;
|
||||
item->speed = -1;
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_FLAGS_BIT)
|
||||
{
|
||||
ffLocalIpFillNIFlags(&item->flags, adapter->mac->ifa_flags, niFlagOptions);
|
||||
FF_DEBUG("Added flags for interface %s: %s", adapter->mac->ifa_name, item->flags.chars);
|
||||
}
|
||||
|
||||
if ((options->showType & FF_LOCALIP_TYPE_IPV4_BIT))
|
||||
{
|
||||
const FFNetifDefaultRouteResult* defaultRouteV4 = ffNetifGetDefaultRouteV4();
|
||||
bool isDefaultRouteIf = ffStrEquals(defaultRouteV4->ifName, adapter->mac->ifa_name);
|
||||
|
||||
if (isDefaultRouteIf)
|
||||
{
|
||||
item->defaultRoute |= FF_LOCALIP_TYPE_IPV4_BIT;
|
||||
FF_DEBUG("Interface %s is IPv4 default route", adapter->mac->ifa_name);
|
||||
}
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT)
|
||||
{
|
||||
if (!isDefaultRouteIf)
|
||||
{
|
||||
FF_DEBUG("Skipping IPv4 for interface %s (not default route)", adapter->mac->ifa_name);
|
||||
goto v6;
|
||||
}
|
||||
}
|
||||
|
||||
addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET, isDefaultRoute, flags, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT));
|
||||
}
|
||||
else if (ifa->ifa_addr->sa_family == AF_INET6)
|
||||
{
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_IPV6_BIT))
|
||||
continue;
|
||||
|
||||
struct sockaddr_in6* ipv6 = (struct sockaddr_in6 *)ifa->ifa_addr;
|
||||
char addressBuffer[INET6_ADDRSTRLEN + 16];
|
||||
inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN);
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_PREFIX_LEN_BIT)
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
|
||||
{
|
||||
struct sockaddr_in6* netmask = (struct sockaddr_in6*) ifa->ifa_netmask;
|
||||
int cidr = 0;
|
||||
static_assert(sizeof(netmask->sin6_addr) % sizeof(uint64_t) == 0, "");
|
||||
for (uint32_t i = 0; i < sizeof(netmask->sin6_addr) / sizeof(uint64_t); ++i)
|
||||
cidr += __builtin_popcountll(((uint64_t*) &netmask->sin6_addr)[i]);
|
||||
if (cidr != 0)
|
||||
struct ifaddrs* ifa = NULL;
|
||||
if (isDefaultRouteIf && defaultRouteV4->preferredSourceAddrV4 != 0)
|
||||
{
|
||||
size_t len = strlen(addressBuffer);
|
||||
snprintf(addressBuffer + len, 16, "/%d", cidr);
|
||||
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv4)
|
||||
{
|
||||
struct sockaddr_in* ipv4 = (struct sockaddr_in*) (*pifa)->ifa_addr;
|
||||
if (ipv4->sin_addr.s_addr == defaultRouteV4->preferredSourceAddrV4)
|
||||
{
|
||||
ifa = *pifa;
|
||||
FF_DEBUG("Found preferred IPv4 source address for interface %s", adapter->mac->ifa_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ifa)
|
||||
appendIpv4(options, &item->ipv4, ifa);
|
||||
else if (adapter->ipv4.length > 0)
|
||||
{
|
||||
appendIpv4(options, &item->ipv4, *FF_LIST_GET(struct ifaddrs*, adapter->ipv4, 0));
|
||||
FF_DEBUG("Using first IPv4 address for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Adding all IPv4 addresses for interface %s", adapter->mac->ifa_name);
|
||||
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv4)
|
||||
appendIpv4(options, &item->ipv4, *pifa);
|
||||
}
|
||||
}
|
||||
v6:
|
||||
if ((options->showType & FF_LOCALIP_TYPE_IPV6_BIT))
|
||||
{
|
||||
const FFNetifDefaultRouteResult* defaultRouteV6 = ffNetifGetDefaultRouteV6();
|
||||
bool isDefaultRouteIf = ffStrEquals(defaultRouteV6->ifName, adapter->mac->ifa_name);
|
||||
|
||||
if (isDefaultRouteIf)
|
||||
{
|
||||
item->defaultRoute |= FF_LOCALIP_TYPE_IPV6_BIT;
|
||||
FF_DEBUG("Interface %s is IPv6 default route", adapter->mac->ifa_name);
|
||||
}
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT)
|
||||
{
|
||||
if (!isDefaultRouteIf)
|
||||
{
|
||||
FF_DEBUG("Skipping IPv6 for interface %s (not default route)", adapter->mac->ifa_name);
|
||||
goto mac;
|
||||
}
|
||||
}
|
||||
|
||||
addNewIp(results, ifa->ifa_name, addressBuffer, AF_INET6, isDefaultRoute, flags, !(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT));
|
||||
}
|
||||
#if __FreeBSD__ || __OpenBSD__ || __APPLE__ || __NetBSD__ || __HAIKU__
|
||||
else if (ifa->ifa_addr->sa_family == AF_LINK)
|
||||
{
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_MAC_BIT))
|
||||
continue;
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
|
||||
{
|
||||
struct ifaddrs* selected = NULL;
|
||||
struct ifaddrs* secondary = NULL;
|
||||
|
||||
char addressBuffer[32];
|
||||
uint8_t* ptr = (uint8_t*) LLADDR((struct sockaddr_dl *)ifa->ifa_addr);
|
||||
snprintf(addressBuffer, ARRAY_SIZE(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
|
||||
addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute, flags, false);
|
||||
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
|
||||
{
|
||||
FFIPv6Type type = getIpType(*pifa);
|
||||
if (type == FF_IPV6_PREFERRED)
|
||||
{
|
||||
selected = *pifa;
|
||||
FF_DEBUG("Found preferred IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
break;
|
||||
}
|
||||
else if (type == FF_IPV6_GUA && !selected)
|
||||
{
|
||||
selected = *pifa;
|
||||
FF_DEBUG("Found GUA IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
else if (type == FF_IPV6_ULA && !secondary)
|
||||
{
|
||||
secondary = *pifa;
|
||||
FF_DEBUG("Found ULA IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
}
|
||||
if (!selected) selected = secondary;
|
||||
|
||||
if (selected)
|
||||
appendIpv6(options, &item->ipv6, selected);
|
||||
else if (adapter->ipv6.length > 0)
|
||||
{
|
||||
appendIpv6(options, &item->ipv6, *FF_LIST_GET(struct ifaddrs*, adapter->ipv6, 0));
|
||||
FF_DEBUG("Using first IPv6 address for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Adding all IPv6 addresses for interface %s", adapter->mac->ifa_name);
|
||||
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
|
||||
appendIpv6(options, &item->ipv6, *pifa);
|
||||
}
|
||||
}
|
||||
mac:
|
||||
#ifndef __sun
|
||||
if (options->showType & FF_LOCALIP_TYPE_MAC_BIT)
|
||||
{
|
||||
if (adapter->mac->ifa_addr)
|
||||
{
|
||||
#if __FreeBSD__ || __OpenBSD__ || __APPLE__ || __NetBSD__ || __HAIKU__
|
||||
uint8_t* ptr = (uint8_t*) LLADDR((struct sockaddr_dl *)adapter->mac->ifa_addr);
|
||||
#else
|
||||
uint8_t* ptr = ((struct sockaddr_ll *)adapter->mac->ifa_addr)->sll_addr;
|
||||
#endif
|
||||
ffStrbufSetF(&item->mac, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
|
||||
FF_DEBUG("Added MAC address %s for interface %s", item->mac.chars, adapter->mac->ifa_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("No MAC address available for interface %s", adapter->mac->ifa_name);
|
||||
}
|
||||
}
|
||||
#else
|
||||
else if (ifa->ifa_addr->sa_family == AF_PACKET)
|
||||
{
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_MAC_BIT))
|
||||
continue;
|
||||
|
||||
char addressBuffer[32];
|
||||
uint8_t* ptr = ((struct sockaddr_ll *)ifa->ifa_addr)->sll_addr;
|
||||
snprintf(addressBuffer, ARRAY_SIZE(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
|
||||
addNewIp(results, ifa->ifa_name, addressBuffer, -1, isDefaultRoute, flags, false);
|
||||
}
|
||||
(void) adapter;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ifAddrStruct) freeifaddrs(ifAddrStruct);
|
||||
FF_LIST_FOR_EACH(FFAdapter, adapter, adapters)
|
||||
{
|
||||
ffListDestroy(&adapter->ipv4);
|
||||
ffListDestroy(&adapter->ipv6);
|
||||
}
|
||||
|
||||
if (ifAddrStruct)
|
||||
{
|
||||
freeifaddrs(ifAddrStruct);
|
||||
ifAddrStruct = NULL;
|
||||
FF_DEBUG("Cleaned up interface address structures");
|
||||
}
|
||||
|
||||
if ((options->showType & FF_LOCALIP_TYPE_MTU_BIT) || (options->showType & FF_LOCALIP_TYPE_SPEED_BIT)
|
||||
#ifdef __sun
|
||||
@@ -240,18 +586,26 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
FF_DEBUG("Retrieving additional interface properties (MTU/Speed/MAC)");
|
||||
FF_AUTO_CLOSE_FD int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd > 0)
|
||||
{
|
||||
FF_LIST_FOR_EACH(FFLocalIpResult, iface, *results)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct ifreq ifr = {};
|
||||
ffStrCopy(ifr.ifr_name, iface->name.chars, IFNAMSIZ);
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_MTU_BIT)
|
||||
{
|
||||
if (ioctl(sockfd, SIOCGIFMTU, &ifr) == 0)
|
||||
{
|
||||
iface->mtu = (int32_t) ifr.ifr_mtu;
|
||||
FF_DEBUG("Interface %s MTU: %d", iface->name.chars, iface->mtu);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get MTU for interface %s", iface->name.chars);
|
||||
}
|
||||
}
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_SPEED_BIT)
|
||||
@@ -260,12 +614,21 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
struct ethtool_cmd edata = { .cmd = ETHTOOL_GSET };
|
||||
ifr.ifr_data = (void*) &edata;
|
||||
if (ioctl(sockfd, SIOCETHTOOL, &ifr) == 0)
|
||||
iface->speed = (edata.speed_hi << 16) | edata.speed; // ethtool_cmd_speed is not available on Android
|
||||
{
|
||||
iface->speed = (edata.speed_hi << 16) | edata.speed;
|
||||
FF_DEBUG("Interface %s speed: %d Mbps", iface->name.chars, iface->speed);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ethtool_cmd_speed is not available on Android
|
||||
FF_DEBUG("Failed to get speed for interface %s via ethtool", iface->name.chars);
|
||||
}
|
||||
#elif __FreeBSD__ || __APPLE__ || __OpenBSD__ || __NetBSD__
|
||||
struct ifmediareq ifmr = {};
|
||||
ffStrCopy(ifmr.ifm_name, iface->name.chars, IFNAMSIZ);
|
||||
if (ioctl(sockfd, SIOCGIFMEDIA, &ifmr) == 0 && (IFM_TYPE(ifmr.ifm_active) & IFM_ETHER))
|
||||
{
|
||||
FF_DEBUG("Interface %s media type: 0x%x", iface->name.chars, IFM_SUBTYPE(ifmr.ifm_active));
|
||||
switch (IFM_SUBTYPE(ifmr.ifm_active))
|
||||
{
|
||||
#ifdef IFM_HPNA_1
|
||||
@@ -630,7 +993,15 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
iface->speed = 56000; break;
|
||||
default:
|
||||
iface->speed = -1;
|
||||
FF_DEBUG("Unknown media subtype for interface %s", iface->name.chars);
|
||||
break;
|
||||
}
|
||||
if (iface->speed > 0)
|
||||
FF_DEBUG("Interface %s speed: %d Mbps", iface->name.chars, iface->speed);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to get media info for interface %s", iface->name.chars);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -641,11 +1012,38 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
const uint8_t* ptr = (uint8_t*) ifr.ifr_addr.sa_data; // NOT ifr_enaddr
|
||||
ffStrbufSetF(&iface->mac, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
|
||||
FF_DEBUG("Added MAC address %s for interface %s (Solaris)", iface->mac.chars, iface->name.chars);
|
||||
}
|
||||
if (options->showType & FF_LOCALIP_TYPE_SPEED_BIT)
|
||||
{
|
||||
__attribute__((__cleanup__(kstatFreeWrap))) kstat_ctl_t* kc = kstat_open();
|
||||
for (kstat_t* ks = kc->kc_chain; ks; ks = ks->ks_next)
|
||||
{
|
||||
if (!ffStrEquals(ks->ks_class, "net") || !ffStrEquals(ks->ks_module, "link")) continue;
|
||||
if (ffStrbufEqualS(&iface->name, ks->ks_name))
|
||||
{
|
||||
if (kstat_read(kc, ks, NULL) >= 0)
|
||||
{
|
||||
kstat_named_t* ifspeed = (kstat_named_t*) kstat_data_lookup(ks, "ifspeed");
|
||||
if (ifspeed)
|
||||
{
|
||||
iface->speed = (int32_t) (ifspeed->value.ui64 / 1000 / 1000);
|
||||
FF_DEBUG("Interface %s speed: %d Mbps (kstat)", iface->name.chars, iface->speed);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Failed to create socket for interface property retrieval");
|
||||
}
|
||||
}
|
||||
|
||||
FF_DEBUG("Local IP detection completed, found %u interfaces", results->length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -4,62 +4,31 @@
|
||||
#include "common/netif/netif.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/windows/unicode.h"
|
||||
#include "util/debug.h"
|
||||
#include "localip.h"
|
||||
|
||||
#define FF_LOCALIP_NIFLAG(name) { IP_ADAPTER_##name, #name }
|
||||
|
||||
static const FFLocalIpNIFlag niFlagOptions[] = {
|
||||
{ IP_ADAPTER_DDNS_ENABLED, "DDNS_ENABLED" },
|
||||
{ IP_ADAPTER_REGISTER_ADAPTER_SUFFIX, "REGISTER_ADAPTER_SUFFIX" },
|
||||
{ IP_ADAPTER_DHCP_ENABLED, "DHCP_ENABLED" },
|
||||
{ IP_ADAPTER_RECEIVE_ONLY, "RECEIVE_ONLY" },
|
||||
{ IP_ADAPTER_NO_MULTICAST, "NO_MULTICAST" },
|
||||
{ IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG, "IPV6_OTHER_STATEFUL_CONFIG" },
|
||||
{ IP_ADAPTER_NETBIOS_OVER_TCPIP_ENABLED, "NETBIOS_OVER_TCPIP_ENABLED" },
|
||||
{ IP_ADAPTER_IPV4_ENABLED, "IPV4_ENABLED" },
|
||||
{ IP_ADAPTER_IPV6_ENABLED, "IPV6_ENABLED" },
|
||||
{ IP_ADAPTER_IPV6_MANAGE_ADDRESS_CONFIG, "IPV6_MANAGE_ADDRESS_CONFIG" },
|
||||
FF_LOCALIP_NIFLAG(DDNS_ENABLED),
|
||||
FF_LOCALIP_NIFLAG(REGISTER_ADAPTER_SUFFIX),
|
||||
FF_LOCALIP_NIFLAG(DHCP_ENABLED),
|
||||
FF_LOCALIP_NIFLAG(RECEIVE_ONLY),
|
||||
FF_LOCALIP_NIFLAG(NO_MULTICAST),
|
||||
FF_LOCALIP_NIFLAG(IPV6_OTHER_STATEFUL_CONFIG),
|
||||
FF_LOCALIP_NIFLAG(NETBIOS_OVER_TCPIP_ENABLED),
|
||||
FF_LOCALIP_NIFLAG(IPV4_ENABLED),
|
||||
FF_LOCALIP_NIFLAG(IPV6_ENABLED),
|
||||
FF_LOCALIP_NIFLAG(IPV6_MANAGE_ADDRESS_CONFIG),
|
||||
// sentinel
|
||||
{},
|
||||
};
|
||||
|
||||
static void addNewIp(FFlist* list, const char* name, const char* addr, int type, bool newIp, bool defaultRoute)
|
||||
{
|
||||
FFLocalIpResult* ip = NULL;
|
||||
|
||||
if (newIp)
|
||||
{
|
||||
ip = (FFLocalIpResult*) ffListAdd(list);
|
||||
ffStrbufInitS(&ip->name, name);
|
||||
ffStrbufInit(&ip->ipv4);
|
||||
ffStrbufInit(&ip->ipv6);
|
||||
ffStrbufInit(&ip->mac);
|
||||
ffStrbufInit(&ip->flags);
|
||||
ip->defaultRoute = defaultRoute;
|
||||
ip->speed = -1;
|
||||
ip->mtu = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ip = FF_LIST_GET(FFLocalIpResult, *list, list->length - 1);
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case AF_INET:
|
||||
if (ip->ipv4.length) ffStrbufAppendC(&ip->ipv4, ',');
|
||||
ffStrbufAppendS(&ip->ipv4, addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (ip->ipv6.length) ffStrbufAppendC(&ip->ipv6, ',');
|
||||
ffStrbufAppendS(&ip->ipv6, addr);
|
||||
break;
|
||||
case -1:
|
||||
ffStrbufSetS(&ip->mac, addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
{
|
||||
FF_DEBUG("Starting local IP detection with showType=0x%X, namePrefix='%.*s'",
|
||||
options->showType, (int)options->namePrefix.length, options->namePrefix.chars);
|
||||
|
||||
IP_ADAPTER_ADDRESSES* FF_AUTO_FREE adapter_addresses = NULL;
|
||||
|
||||
// Multiple attempts in case interfaces change while
|
||||
@@ -67,69 +36,134 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
DWORD adapter_addresses_buffer_size = 0;
|
||||
for (int attempts = 0;; ++attempts)
|
||||
{
|
||||
FF_DEBUG("Attempt %d to get adapter addresses, buffer size: %lu", attempts + 1, adapter_addresses_buffer_size);
|
||||
|
||||
if (adapter_addresses_buffer_size)
|
||||
{
|
||||
adapter_addresses = (IP_ADAPTER_ADDRESSES*)realloc(adapter_addresses, adapter_addresses_buffer_size);
|
||||
assert(adapter_addresses);
|
||||
}
|
||||
|
||||
DWORD family = options->showType & FF_LOCALIP_TYPE_IPV4_BIT
|
||||
? options->showType & FF_LOCALIP_TYPE_IPV6_BIT ? AF_UNSPEC : AF_INET
|
||||
: AF_INET6;
|
||||
FF_DEBUG("Calling GetAdaptersAddresses with family=%u, flags=0x%X", (unsigned)family,
|
||||
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER);
|
||||
|
||||
DWORD error = GetAdaptersAddresses(
|
||||
options->showType & FF_LOCALIP_TYPE_IPV4_BIT
|
||||
? options->showType & FF_LOCALIP_TYPE_IPV6_BIT ? AF_UNSPEC : AF_INET
|
||||
: AF_INET6,
|
||||
family,
|
||||
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER,
|
||||
NULL,
|
||||
adapter_addresses,
|
||||
&adapter_addresses_buffer_size);
|
||||
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
FF_DEBUG("GetAdaptersAddresses succeeded on attempt %d", attempts + 1);
|
||||
break;
|
||||
}
|
||||
else if (ERROR_BUFFER_OVERFLOW == error && attempts < 4)
|
||||
{
|
||||
FF_DEBUG("Buffer overflow, need %lu bytes, retrying", adapter_addresses_buffer_size);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("GetAdaptersAddresses failed with error %lu after %d attempts", error, attempts + 1);
|
||||
return "GetAdaptersAddresses() failed";
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex();
|
||||
int adapterCount = 0;
|
||||
int processedCount = 0;
|
||||
|
||||
// Iterate through all of the adapters
|
||||
for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next)
|
||||
{
|
||||
if (adapter->OperStatus != IfOperStatusUp)
|
||||
continue;
|
||||
adapterCount++;
|
||||
|
||||
bool isDefaultRoute = adapter->IfIndex == defaultRouteIfIndex;
|
||||
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
|
||||
FF_DEBUG("Processing adapter %d: IfIndex=%u, IfType=%u, OperStatus=%u",
|
||||
adapterCount, (unsigned)adapter->IfIndex, (unsigned)adapter->IfType, (unsigned)adapter->OperStatus);
|
||||
|
||||
if (adapter->OperStatus != IfOperStatusUp)
|
||||
{
|
||||
FF_DEBUG("Skipping adapter %u (not operational, status=%d)", (unsigned)adapter->IfIndex, adapter->OperStatus);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isLoop = adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK;
|
||||
if (isLoop && !(options->showType & FF_LOCALIP_TYPE_LOOP_BIT))
|
||||
continue;
|
||||
FF_DEBUG("Adapter %u: isLoopback=%s", (unsigned)adapter->IfIndex, isLoop ? "true" : "false");
|
||||
|
||||
bool newIp = true;
|
||||
if (isLoop && !(options->showType & FF_LOCALIP_TYPE_LOOP_BIT))
|
||||
{
|
||||
FF_DEBUG("Skipping loopback adapter %u (loopback not requested)", (unsigned)adapter->IfIndex);
|
||||
continue;
|
||||
}
|
||||
|
||||
char name[128];
|
||||
WideCharToMultiByte(CP_UTF8, 0, adapter->FriendlyName, -1, name, ARRAY_SIZE(name), NULL, NULL);
|
||||
if (options->namePrefix.length && strncmp(name, options->namePrefix.chars, options->namePrefix.length) != 0)
|
||||
continue;
|
||||
FF_DEBUG("Adapter %u name: '%s'", (unsigned)adapter->IfIndex, name);
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_MAC_BIT && adapter->PhysicalAddressLength == 6)
|
||||
if (options->namePrefix.length && strncmp(name, options->namePrefix.chars, options->namePrefix.length) != 0)
|
||||
{
|
||||
char addressBuffer[32];
|
||||
uint8_t* ptr = adapter->PhysicalAddress;
|
||||
snprintf(addressBuffer, ARRAY_SIZE(addressBuffer), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
|
||||
addNewIp(results, name, addressBuffer, -1, newIp, isDefaultRoute);
|
||||
newIp = false;
|
||||
FF_DEBUG("Skipping adapter %u (name doesn't match prefix '%.*s')",
|
||||
(unsigned)adapter->IfIndex, (int)options->namePrefix.length, options->namePrefix.chars);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT)
|
||||
{
|
||||
if (!((options->showType & FF_LOCALIP_TYPE_IPV4_BIT) && ffNetifGetDefaultRouteV4()->ifIndex == adapter->IfIndex) &&
|
||||
!((options->showType & FF_LOCALIP_TYPE_IPV6_BIT) && ffNetifGetDefaultRouteV6()->ifIndex == adapter->IfIndex))
|
||||
{
|
||||
FF_DEBUG("Skipping interface %u (not default route interface)", (unsigned)adapter->IfIndex);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
processedCount++;
|
||||
FF_DEBUG("Creating result item for adapter %u ('%s')", (unsigned)adapter->IfIndex, name);
|
||||
|
||||
FFLocalIpResult* item = (FFLocalIpResult*) ffListAdd(results);
|
||||
ffStrbufInitS(&item->name, name);
|
||||
ffStrbufInit(&item->ipv4);
|
||||
ffStrbufInit(&item->ipv6);
|
||||
ffStrbufInit(&item->mac);
|
||||
ffStrbufInit(&item->flags);
|
||||
item->defaultRoute = FF_LOCALIP_TYPE_NONE;
|
||||
item->speed = -1;
|
||||
item->mtu = -1;
|
||||
|
||||
uint32_t typesToAdd = options->showType & (FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_IPV6_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT);
|
||||
FF_DEBUG("Types to add for adapter %u: 0x%X", (unsigned)adapter->IfIndex, typesToAdd);
|
||||
|
||||
int ipv4Count = 0, ipv6Count = 0;
|
||||
|
||||
for (IP_ADAPTER_UNICAST_ADDRESS* ifa = adapter->FirstUnicastAddress; ifa; ifa = ifa->Next)
|
||||
{
|
||||
FF_DEBUG("Processing unicast address: family=%d, DadState=%d",
|
||||
ifa->Address.lpSockaddr->sa_family, ifa->DadState);
|
||||
|
||||
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) && ifa->DadState != IpDadStatePreferred)
|
||||
{
|
||||
FF_DEBUG("Skipping address (DadState=%d, not preferred)", ifa->DadState);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifa->Address.lpSockaddr->sa_family == AF_INET)
|
||||
{
|
||||
if (!(typesToAdd & (FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT))) continue;
|
||||
if (!(typesToAdd & (FF_LOCALIP_TYPE_IPV4_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT)))
|
||||
{
|
||||
FF_DEBUG("Skipping IPv4 address (not requested in typesToAdd=0x%X)", typesToAdd);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isDefaultRoute = ((options->showType & FF_LOCALIP_TYPE_IPV4_BIT) && ffNetifGetDefaultRouteV4()->ifIndex == adapter->IfIndex);
|
||||
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
|
||||
{
|
||||
FF_DEBUG("Skipping IPv4 address (not on default route interface)");
|
||||
continue;
|
||||
}
|
||||
|
||||
SOCKADDR_IN* ipv4 = (SOCKADDR_IN*) ifa->Address.lpSockaddr;
|
||||
char addressBuffer[INET_ADDRSTRLEN + 6];
|
||||
@@ -141,15 +175,30 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
snprintf(addressBuffer + len, 6, "/%u", (unsigned) ifa->OnLinkPrefixLength);
|
||||
}
|
||||
|
||||
addNewIp(results, name, addressBuffer, AF_INET, newIp, isDefaultRoute);
|
||||
newIp = false;
|
||||
FF_DEBUG("Adding IPv4 address: %s (isDefaultRoute=%s)", addressBuffer, isDefaultRoute ? "true" : "false");
|
||||
|
||||
if (item->ipv4.length) ffStrbufAppendC(&item->ipv4, ',');
|
||||
ffStrbufAppendS(&item->ipv4, addressBuffer);
|
||||
if (isDefaultRoute) item->defaultRoute |= FF_LOCALIP_TYPE_IPV4_BIT;
|
||||
|
||||
ipv4Count++;
|
||||
typesToAdd &= ~(unsigned) FF_LOCALIP_TYPE_IPV4_BIT;
|
||||
if (typesToAdd == 0) break;
|
||||
}
|
||||
else if (ifa->Address.lpSockaddr->sa_family == AF_INET6)
|
||||
{
|
||||
if (!(typesToAdd & (FF_LOCALIP_TYPE_IPV6_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT))) continue;
|
||||
if (!(typesToAdd & (FF_LOCALIP_TYPE_IPV6_BIT | FF_LOCALIP_TYPE_ALL_IPS_BIT)))
|
||||
{
|
||||
FF_DEBUG("Skipping IPv6 address (not requested in typesToAdd=0x%X)", typesToAdd);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isDefaultRoute = ((options->showType & FF_LOCALIP_TYPE_IPV6_BIT) && ffNetifGetDefaultRouteV6()->ifIndex == adapter->IfIndex);
|
||||
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
|
||||
{
|
||||
FF_DEBUG("Skipping IPv6 address (not on default route interface)");
|
||||
continue;
|
||||
}
|
||||
|
||||
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
|
||||
char addressBuffer[INET6_ADDRSTRLEN + 6];
|
||||
@@ -161,25 +210,45 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
snprintf(addressBuffer + len, 6, "/%u", (unsigned) ifa->OnLinkPrefixLength);
|
||||
}
|
||||
|
||||
addNewIp(results, name, addressBuffer, AF_INET6, newIp, isDefaultRoute);
|
||||
newIp = false;
|
||||
FF_DEBUG("Adding IPv6 address: %s (isDefaultRoute=%s)", addressBuffer, isDefaultRoute ? "true" : "false");
|
||||
|
||||
if (item->ipv6.length) ffStrbufAppendC(&item->ipv6, ',');
|
||||
ffStrbufAppendS(&item->ipv6, addressBuffer);
|
||||
if (isDefaultRoute) item->defaultRoute |= FF_LOCALIP_TYPE_IPV6_BIT;
|
||||
|
||||
ipv6Count++;
|
||||
typesToAdd &= ~(unsigned) FF_LOCALIP_TYPE_IPV6_BIT;
|
||||
if (typesToAdd == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!newIp)
|
||||
FF_DEBUG("Adapter %u: collected %d IPv4 and %d IPv6 addresses", (unsigned)adapter->IfIndex, ipv4Count, ipv6Count);
|
||||
|
||||
if (options->showType & FF_LOCALIP_TYPE_SPEED_BIT)
|
||||
{
|
||||
FFLocalIpResult* result = FF_LIST_GET(FFLocalIpResult, *results, results->length - 1);
|
||||
if (options->showType & FF_LOCALIP_TYPE_SPEED_BIT)
|
||||
result->speed = (int32_t) (adapter->ReceiveLinkSpeed / 1000000);
|
||||
if (options->showType & FF_LOCALIP_TYPE_MTU_BIT)
|
||||
result->mtu = (int32_t) adapter->Mtu;
|
||||
if (options->showType & FF_LOCALIP_TYPE_FLAGS_BIT)
|
||||
ffLocalIpFillNIFlags(&result->flags, adapter->Flags, niFlagOptions);
|
||||
item->speed = (int32_t) (adapter->ReceiveLinkSpeed / 1000000);
|
||||
FF_DEBUG("Adapter %u speed: %d Mbps (raw: %llu)", (unsigned)adapter->IfIndex, item->speed, adapter->ReceiveLinkSpeed);
|
||||
}
|
||||
if (options->showType & FF_LOCALIP_TYPE_MTU_BIT)
|
||||
{
|
||||
item->mtu = (int32_t) adapter->Mtu;
|
||||
FF_DEBUG("Adapter %u MTU: %d", (unsigned)adapter->IfIndex, item->mtu);
|
||||
}
|
||||
if (options->showType & FF_LOCALIP_TYPE_FLAGS_BIT)
|
||||
{
|
||||
ffLocalIpFillNIFlags(&item->flags, adapter->Flags, niFlagOptions);
|
||||
FF_DEBUG("Adapter %u flags: 0x%lX -> '%s'", (unsigned)adapter->IfIndex, adapter->Flags, item->flags.chars);
|
||||
}
|
||||
if (options->showType & FF_LOCALIP_TYPE_MAC_BIT && adapter->PhysicalAddressLength == 6)
|
||||
{
|
||||
uint8_t* ptr = adapter->PhysicalAddress;
|
||||
ffStrbufSetF(&item->mac, "%02x:%02x:%02x:%02x:%02x:%02x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
|
||||
FF_DEBUG("Adapter %u MAC: %s", (unsigned)adapter->IfIndex, item->mac.chars);
|
||||
}
|
||||
}
|
||||
|
||||
FF_DEBUG("Local IP detection completed: scanned %d adapters, processed %d, results count: %u",
|
||||
adapterCount, processedCount, results->length);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/media/option.h"
|
||||
|
||||
typedef struct FFMediaResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/memory/option.h"
|
||||
|
||||
typedef struct FFMemoryResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/netio/option.h"
|
||||
|
||||
typedef struct FFNetIOResult
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
{
|
||||
int mib[] = {CTL_NET, PF_LINK, NETLINK_GENERIC,
|
||||
options->defaultRouteOnly ? IFMIB_IFDATA : IFMIB_IFALLDATA,
|
||||
options->defaultRouteOnly ? (int) ffNetifGetDefaultRouteIfIndex() : 0,
|
||||
options->defaultRouteOnly ? (int) ffNetifGetDefaultRouteV4()->ifIndex : 0,
|
||||
IFDATA_GENERAL};
|
||||
|
||||
size_t bufSize = 0;
|
||||
@@ -26,7 +26,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
|
||||
size_t ifCount = bufSize / sizeof(struct ifmibdata);
|
||||
|
||||
const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName();
|
||||
const char* defaultRouteIfName = ffNetifGetDefaultRouteV4()->ifName;
|
||||
|
||||
for (size_t i = 0; i < ifCount; i++)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
{
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex();
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex;
|
||||
|
||||
size_t bufSize = 0;
|
||||
if (sysctl((int[]) { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, (options->defaultRouteOnly ? (int) defaultRouteIfIndex : 0) }, 6, NULL, &bufSize, 0, 0) < 0)
|
||||
|
||||
@@ -13,7 +13,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
BNetworkInterface interface;
|
||||
uint32 cookie = 0;
|
||||
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex();
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex;
|
||||
|
||||
while (roster.GetNextInterface(&cookie, interface) == B_OK)
|
||||
{
|
||||
|
||||
@@ -53,7 +53,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
const char* defaultRouteIfName = ffNetifGetDefaultRouteIfName();
|
||||
const char* defaultRouteIfName = ffNetifGetDefaultRouteV4()->ifName;
|
||||
|
||||
if (options->defaultRouteOnly)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
if (!kc)
|
||||
return "kstat_open() failed";
|
||||
|
||||
const char* defaultRoute = ffNetifGetDefaultRouteIfName();
|
||||
const char* defaultRouteIfName = ffNetifGetDefaultRouteV4()->ifName;
|
||||
|
||||
for (kstat_t* ks = kc->kc_chain; ks; ks = ks->ks_next)
|
||||
{
|
||||
@@ -25,7 +25,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
if (options->namePrefix.length && strncmp(ks->ks_name, options->namePrefix.chars, options->namePrefix.length) != 0)
|
||||
continue;
|
||||
|
||||
bool isDefaultRoute = ffStrEquals(ks->ks_name, defaultRoute);
|
||||
bool isDefaultRoute = ffStrEquals(ks->ks_name, defaultRouteIfName);
|
||||
if (options->defaultRouteOnly && !isDefaultRoute)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options)
|
||||
return "GetAdaptersAddresses() failed";
|
||||
}
|
||||
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex();
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex;
|
||||
|
||||
// Iterate through all of the adapters
|
||||
for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/opencl/option.h"
|
||||
|
||||
typedef struct FFOpenCLResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/opengl/option.h"
|
||||
|
||||
typedef struct FFOpenGLResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/os/option.h"
|
||||
|
||||
typedef struct FFOSResult
|
||||
{
|
||||
|
||||
+34
-19
@@ -89,6 +89,21 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
}
|
||||
|
||||
if (ffPathExists("/usr/bin/lliurex-version", FF_PATHTYPE_FILE))
|
||||
{
|
||||
ffStrbufSetStatic(&result->name, "LliureX");
|
||||
ffStrbufSetStatic(&result->id, "lliurex");
|
||||
ffStrbufClear(&result->version);
|
||||
if (ffProcessAppendStdOut(&result->version, (char* const[]) {
|
||||
"/usr/bin/lliurex-version",
|
||||
NULL,
|
||||
}) == NULL) // 8.2.2
|
||||
ffStrbufTrimRightSpace(&result->version);
|
||||
ffStrbufSetF(&result->prettyName, "LliureX %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
|
||||
{
|
||||
ffStrbufSetStatic(&result->name, "Kubuntu");
|
||||
@@ -169,15 +184,6 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "lliurex"))
|
||||
{
|
||||
ffStrbufSetStatic(&result->name, "LliureX");
|
||||
ffStrbufSetF(&result->prettyName, "LliureX %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "lliurex");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FF_MAYBE_UNUSED static void getDebianVersion(FFOSResult* result)
|
||||
@@ -306,16 +312,10 @@ FF_MAYBE_UNUSED static bool detectFedoraVariant(FFOSResult* result)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void detectOS(FFOSResult* os)
|
||||
static bool detectBedrock(FFOSResult* os)
|
||||
{
|
||||
#ifdef FF_CUSTOM_OS_RELEASE_PATH
|
||||
parseOsRelease(FF_STR(FF_CUSTOM_OS_RELEASE_PATH), os);
|
||||
#ifdef FF_CUSTOM_LSB_RELEASE_PATH
|
||||
parseLsbRelease(FF_STR(FF_CUSTOM_LSB_RELEASE_PATH), os);
|
||||
#endif
|
||||
return;
|
||||
#endif
|
||||
|
||||
const char* bedrockRestrict = getenv("BEDROCK_RESTRICT");
|
||||
if(bedrockRestrict && bedrockRestrict[0] == '1') return false;
|
||||
if(parseOsRelease(FASTFETCH_TARGET_DIR_ROOT "/bedrock" FASTFETCH_TARGET_DIR_ETC "/bedrock-release", os))
|
||||
{
|
||||
if(os->id.length == 0)
|
||||
@@ -328,8 +328,23 @@ static void detectOS(FFOSResult* os)
|
||||
ffStrbufAppendS(&os->prettyName, "Bedrock Linux");
|
||||
|
||||
parseOsRelease("/bedrock" FASTFETCH_TARGET_DIR_ETC "/os-release", os);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void detectOS(FFOSResult* os)
|
||||
{
|
||||
#ifdef FF_CUSTOM_OS_RELEASE_PATH
|
||||
parseOsRelease(FF_STR(FF_CUSTOM_OS_RELEASE_PATH), os);
|
||||
#ifdef FF_CUSTOM_LSB_RELEASE_PATH
|
||||
parseLsbRelease(FF_STR(FF_CUSTOM_LSB_RELEASE_PATH), os);
|
||||
#endif
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (detectBedrock(os))
|
||||
return;
|
||||
|
||||
// Refer: https://gist.github.com/natefoo/814c5bf936922dad97ff
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/packages/option.h"
|
||||
|
||||
typedef struct FFPackagesResult
|
||||
{
|
||||
@@ -54,6 +55,9 @@ const char* ffDetectPackages(FFPackagesResult* result, FFPackagesOptions* option
|
||||
bool ffPackagesReadCache(FFstrbuf* cacheDir, FFstrbuf* cacheContent, const char* filePath, const char* packageId, uint32_t* result);
|
||||
bool ffPackagesWriteCache(FFstrbuf* cacheDir, FFstrbuf* cacheContent, uint32_t num_elements);
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
uint32_t ffPackagesGetNix(FFstrbuf* baseDir, const char* dirname);
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
uint32_t ffPackagesGetNumElements(const char* dirname, bool isdir);
|
||||
#endif
|
||||
|
||||
@@ -4,91 +4,66 @@
|
||||
#include "common/processing.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
static void countBrewPackages(const char* dirname, FFPackagesResult* result)
|
||||
static void countBrewPackages(FFstrbuf* baseDir, FFPackagesResult* result)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(dirname);
|
||||
|
||||
uint32_t baseDirLength = baseDir.length;
|
||||
|
||||
ffStrbufAppendS(&baseDir, "/Caskroom");
|
||||
result->brewCask += ffPackagesGetNumElements(baseDir.chars, true);
|
||||
ffStrbufSubstrBefore(&baseDir, baseDirLength);
|
||||
|
||||
ffStrbufAppendS(&baseDir, "/Cellar");
|
||||
result->brew += ffPackagesGetNumElements(baseDir.chars, true);
|
||||
ffStrbufSubstrBefore(&baseDir, baseDirLength);
|
||||
}
|
||||
|
||||
static void getBrewPackages(FFPackagesResult* result)
|
||||
{
|
||||
const char* prefix = getenv("HOMEBREW_PREFIX");
|
||||
if(ffStrSet(prefix))
|
||||
return countBrewPackages(prefix, result);
|
||||
|
||||
countBrewPackages(FASTFETCH_TARGET_DIR_ROOT "/opt/homebrew", result);
|
||||
countBrewPackages(FASTFETCH_TARGET_DIR_USR "/local", result);
|
||||
}
|
||||
|
||||
static uint32_t countMacPortsPackages(const char* dirname)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(dirname);
|
||||
ffStrbufAppendS(&baseDir, "/var/macports/software");
|
||||
|
||||
return ffPackagesGetNumElements(baseDir.chars, true);
|
||||
}
|
||||
|
||||
static uint32_t getMacPortsPackages()
|
||||
{
|
||||
const char* prefix = getenv("MACPORTS_PREFIX");
|
||||
if(ffStrSet(prefix))
|
||||
return countMacPortsPackages(prefix);
|
||||
|
||||
return countMacPortsPackages(FASTFETCH_TARGET_DIR_ROOT "/opt/local");
|
||||
}
|
||||
|
||||
static uint32_t getNixPackagesImpl(const char* path)
|
||||
{
|
||||
//Nix detection is kinda slow, so we only do it if the dir exists
|
||||
if(!ffPathExists(path, FF_PATHTYPE_DIRECTORY))
|
||||
return 0;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreateA(128);
|
||||
|
||||
//https://github.com/fastfetch-cli/fastfetch/issues/195#issuecomment-1191748222
|
||||
FF_STRBUF_AUTO_DESTROY command = ffStrbufCreateA(255);
|
||||
ffStrbufAppendS(&command, "for x in $(nix-store --query --requisites ");
|
||||
ffStrbufAppendS(&command, path);
|
||||
ffStrbufAppendS(&command, "); do if [ -d $x ]; then echo $x ; fi ; done | cut -d- -f2- | egrep '([0-9]{1,}\\.)+[0-9]{1,}' | egrep -v '\\-doc$|\\-man$|\\-info$|\\-dev$|\\-bin$|^nixos-system-nixos-' | uniq | wc -l");
|
||||
|
||||
ffProcessAppendStdOut(&output, (char* const[]) {
|
||||
FASTFETCH_TARGET_DIR_ROOT "/bin/sh",
|
||||
"-c",
|
||||
command.chars,
|
||||
NULL
|
||||
});
|
||||
|
||||
return (uint32_t) strtoul(output.chars, NULL, 10);
|
||||
}
|
||||
|
||||
static uint32_t getNixPackages(FFstrbuf* baseDir, const char* dirname)
|
||||
{
|
||||
uint32_t baseDirLength = baseDir->length;
|
||||
ffStrbufAppendS(baseDir, dirname);
|
||||
uint32_t num_elements = getNixPackagesImpl(baseDir->chars);
|
||||
|
||||
ffStrbufAppendS(baseDir, "/Caskroom");
|
||||
result->brewCask += ffPackagesGetNumElements(baseDir->chars, true);
|
||||
ffStrbufSubstrBefore(baseDir, baseDirLength);
|
||||
return num_elements;
|
||||
|
||||
ffStrbufAppendS(baseDir, "/Cellar");
|
||||
result->brew += ffPackagesGetNumElements(baseDir->chars, true);
|
||||
ffStrbufSubstrBefore(baseDir, baseDirLength);
|
||||
}
|
||||
|
||||
static uint32_t getMacPortsPackages(FFstrbuf* baseDir)
|
||||
{
|
||||
ffStrbufAppendS(baseDir, "/var/macports/software");
|
||||
return ffPackagesGetNumElements(baseDir->chars, true);
|
||||
}
|
||||
|
||||
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
{
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT)) getBrewPackages(result);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_MACPORTS_BIT)) result->macports = getMacPortsPackages();
|
||||
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreate();
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
|
||||
{
|
||||
const char* prefix = getenv("HOMEBREW_PREFIX");
|
||||
if (ffStrSet(prefix))
|
||||
{
|
||||
ffStrbufSetS(&baseDir, prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __aarch64__
|
||||
ffStrbufSetS(&baseDir, FASTFETCH_TARGET_DIR_ROOT "/opt/homebrew");
|
||||
#else
|
||||
ffStrbufSetS(&baseDir, FASTFETCH_TARGET_DIR_USR "/local");
|
||||
#endif
|
||||
}
|
||||
countBrewPackages(&baseDir, result);
|
||||
}
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_MACPORTS_BIT))
|
||||
{
|
||||
const char* prefix = getenv("MACPORTS_PREFIX");
|
||||
if (ffStrSet(prefix))
|
||||
{
|
||||
ffStrbufSetS(&baseDir, prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufSetS(&baseDir, FASTFETCH_TARGET_DIR_ROOT "/opt/local");
|
||||
}
|
||||
|
||||
result->macports = getMacPortsPackages(&baseDir);
|
||||
}
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(FASTFETCH_TARGET_DIR_ROOT);
|
||||
result->nixDefault += getNixPackages(&baseDir, "/nix/var/nix/profiles/default");
|
||||
result->nixSystem += getNixPackages(&baseDir, "/run/current-system");
|
||||
ffStrbufSetS(&baseDir, FASTFETCH_TARGET_DIR_ROOT);
|
||||
result->nixDefault += ffPackagesGetNix(&baseDir, "/nix/var/nix/profiles/default");
|
||||
result->nixSystem += ffPackagesGetNix(&baseDir, "/run/current-system");
|
||||
ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
|
||||
result->nixUser = getNixPackages(&baseDir, "/.nix-profile");
|
||||
result->nixUser = ffPackagesGetNix(&baseDir, "/.nix-profile");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "packages.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/parsing.h"
|
||||
#include "common/processing.h"
|
||||
#include "common/properties.h"
|
||||
#include "common/settings.h"
|
||||
#include "detection/os/os.h"
|
||||
@@ -124,157 +123,6 @@ static uint32_t countFilesRecursive(FFstrbuf* baseDir, const char* dirname, cons
|
||||
return sum;
|
||||
}
|
||||
|
||||
static bool isValidNixPkg(FFstrbuf* pkg)
|
||||
{
|
||||
if (!ffPathExists(pkg->chars, FF_PATHTYPE_DIRECTORY))
|
||||
return false;
|
||||
|
||||
ffStrbufSubstrAfterLastC(pkg, '/');
|
||||
if (
|
||||
ffStrbufStartsWithS(pkg, "nixos-system-nixos-") ||
|
||||
ffStrbufEndsWithS(pkg, "-doc") ||
|
||||
ffStrbufEndsWithS(pkg, "-man") ||
|
||||
ffStrbufEndsWithS(pkg, "-info") ||
|
||||
ffStrbufEndsWithS(pkg, "-dev") ||
|
||||
ffStrbufEndsWithS(pkg, "-bin")
|
||||
) return false;
|
||||
|
||||
enum { START, DIGIT, DOT, MATCH } state = START;
|
||||
|
||||
for (uint32_t i = 0; i < pkg->length; i++)
|
||||
{
|
||||
char c = pkg->chars[i];
|
||||
switch (state)
|
||||
{
|
||||
case START:
|
||||
if (ffCharIsDigit(c))
|
||||
state = DIGIT;
|
||||
break;
|
||||
case DIGIT:
|
||||
if (ffCharIsDigit(c))
|
||||
continue;
|
||||
if (c == '.')
|
||||
state = DOT;
|
||||
else
|
||||
state = START;
|
||||
break;
|
||||
case DOT:
|
||||
if (ffCharIsDigit(c))
|
||||
state = MATCH;
|
||||
else
|
||||
state = START;
|
||||
break;
|
||||
case MATCH:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return state == MATCH;
|
||||
}
|
||||
|
||||
static bool checkNixCache(FFstrbuf* cacheDir, FFstrbuf* hash, uint32_t* count)
|
||||
{
|
||||
if (!ffPathExists(cacheDir->chars, FF_PATHTYPE_FILE))
|
||||
return false;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreate();
|
||||
if (!ffReadFileBuffer(cacheDir->chars, &cacheContent))
|
||||
return false;
|
||||
|
||||
// Format: <hash>\n<count>
|
||||
uint32_t split = ffStrbufFirstIndexC(&cacheContent, '\n');
|
||||
if (split == cacheContent.length)
|
||||
return false;
|
||||
|
||||
ffStrbufSetNS(hash, split, cacheContent.chars);
|
||||
*count = (uint32_t)atoi(cacheContent.chars + split + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeNixCache(FFstrbuf* cacheDir, FFstrbuf* hash, uint32_t count)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreateCopy(hash);
|
||||
ffStrbufAppendF(&cacheContent, "\n%u", count);
|
||||
return ffWriteFileBuffer(cacheDir->chars, &cacheContent);
|
||||
}
|
||||
|
||||
static uint32_t getNixPackagesImpl(char* path)
|
||||
{
|
||||
//Nix detection is kinda slow, so we only do it if the dir exists
|
||||
if(!ffPathExists(path, FF_PATHTYPE_DIRECTORY))
|
||||
return 0;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cacheDir = ffStrbufCreateCopy(&instance.state.platform.cacheDir);
|
||||
ffStrbufEnsureEndsWithC(&cacheDir, '/');
|
||||
ffStrbufAppendS(&cacheDir, "fastfetch/packages/nix");
|
||||
ffStrbufAppendS(&cacheDir, path);
|
||||
|
||||
//Check the hash first to determine if we need to recompute the count
|
||||
FF_STRBUF_AUTO_DESTROY hash = ffStrbufCreateA(64);
|
||||
FF_STRBUF_AUTO_DESTROY cacheHash = ffStrbufCreateA(64);
|
||||
uint32_t count = 0;
|
||||
|
||||
ffProcessAppendStdOut(&hash, (char* const[]) {
|
||||
"nix-store",
|
||||
"--query",
|
||||
"--hash",
|
||||
path,
|
||||
NULL
|
||||
});
|
||||
|
||||
if (checkNixCache(&cacheDir, &cacheHash, &count) && ffStrbufEqual(&hash, &cacheHash))
|
||||
return count;
|
||||
|
||||
//Cache is invalid, recompute the count
|
||||
count = 0;
|
||||
|
||||
//Implementation based on bash script from here:
|
||||
//https://github.com/fastfetch-cli/fastfetch/issues/195#issuecomment-1191748222
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreateA(1024);
|
||||
|
||||
ffProcessAppendStdOut(&output, (char* const[]) {
|
||||
"nix-store",
|
||||
"--query",
|
||||
"--requisites",
|
||||
path,
|
||||
NULL
|
||||
});
|
||||
|
||||
uint32_t lineLength = 0;
|
||||
for (uint32_t i = 0; i < output.length; i++)
|
||||
{
|
||||
if (output.chars[i] != '\n')
|
||||
{
|
||||
lineLength++;
|
||||
continue;
|
||||
}
|
||||
|
||||
output.chars[i] = '\0';
|
||||
FFstrbuf line = {
|
||||
.allocated = 0,
|
||||
.length = lineLength,
|
||||
.chars = output.chars + i - lineLength
|
||||
};
|
||||
if (isValidNixPkg(&line))
|
||||
count++;
|
||||
lineLength = 0;
|
||||
}
|
||||
|
||||
writeNixCache(&cacheDir, &hash, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static uint32_t getNixPackages(FFstrbuf* baseDir, const char* dirname)
|
||||
{
|
||||
uint32_t baseDirLength = baseDir->length;
|
||||
ffStrbufAppendS(baseDir, dirname);
|
||||
uint32_t num_elements = getNixPackagesImpl(baseDir->chars);
|
||||
ffStrbufSubstrBefore(baseDir, baseDirLength);
|
||||
return num_elements;
|
||||
}
|
||||
|
||||
static uint32_t getXBPSImpl(FFstrbuf* baseDir)
|
||||
{
|
||||
DIR* dir = opendir(baseDir->chars);
|
||||
@@ -572,8 +420,8 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT)) packageCounts->flatpakSystem += getFlatpakPackages(baseDir, "/var/lib");
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
|
||||
{
|
||||
packageCounts->nixDefault += getNixPackages(baseDir, "/nix/var/nix/profiles/default");
|
||||
packageCounts->nixSystem += getNixPackages(baseDir, "/run/current-system");
|
||||
packageCounts->nixDefault += ffPackagesGetNix(baseDir, "/nix/var/nix/profiles/default");
|
||||
packageCounts->nixSystem += ffPackagesGetNix(baseDir, "/run/current-system");
|
||||
}
|
||||
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);
|
||||
@@ -598,7 +446,7 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
|
||||
{
|
||||
packageCounts->guixSystem += getGuixPackages(baseDir, "/run/current-system/profile");
|
||||
}
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_LINGLONG_BIT)) packageCounts->linglong += getNumElements(baseDir, "/var/lib/linglong/repo/refs/heads/main", true);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_LINGLONG_BIT)) packageCounts->linglong += getNumElements(baseDir, "/var/lib/linglong/layers", true);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PACSTALL_BIT)) packageCounts->pacstall += getNumElements(baseDir, "/var/lib/pacstall/metadata", false);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PISI_BIT)) packageCounts->pisi += getNumElements(baseDir, "/var/lib/pisi/package", true);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT)) packageCounts->pkgsrc += getNumElements(baseDir, "/usr/pkg/pkgdb", DT_DIR);
|
||||
@@ -673,7 +521,7 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
|
||||
{
|
||||
// Count packages from $HOME/.nix-profile
|
||||
result->nixUser += getNixPackages(&baseDir, ".nix-profile");
|
||||
result->nixUser += ffPackagesGetNix(&baseDir, ".nix-profile");
|
||||
|
||||
// Check in $XDG_STATE_HOME/nix/profile
|
||||
FF_STRBUF_AUTO_DESTROY stateHome = ffStrbufCreate();
|
||||
@@ -688,11 +536,11 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
ffStrbufSet(&stateHome, &instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(&stateHome, ".local/state/");
|
||||
}
|
||||
result->nixUser += getNixPackages(&stateHome, "nix/profile");
|
||||
result->nixUser += ffPackagesGetNix(&stateHome, "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);
|
||||
result->nixUser += ffPackagesGetNix(&userPkgsDir, instance.state.platform.userName.chars);
|
||||
}
|
||||
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT))
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#include "packages.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
static bool isValidNixPkg(FFstrbuf* pkg)
|
||||
{
|
||||
if (!ffPathExists(pkg->chars, FF_PATHTYPE_DIRECTORY))
|
||||
return false;
|
||||
|
||||
ffStrbufSubstrAfterLastC(pkg, '/');
|
||||
if (
|
||||
ffStrbufStartsWithS(pkg, "nixos-system-nixos-") ||
|
||||
ffStrbufEndsWithS(pkg, "-doc") ||
|
||||
ffStrbufEndsWithS(pkg, "-man") ||
|
||||
ffStrbufEndsWithS(pkg, "-info") ||
|
||||
ffStrbufEndsWithS(pkg, "-dev") ||
|
||||
ffStrbufEndsWithS(pkg, "-bin")
|
||||
) return false;
|
||||
|
||||
enum { START, DIGIT, DOT, MATCH } state = START;
|
||||
|
||||
for (uint32_t i = 0; i < pkg->length; i++)
|
||||
{
|
||||
char c = pkg->chars[i];
|
||||
switch (state)
|
||||
{
|
||||
case START:
|
||||
if (ffCharIsDigit(c))
|
||||
state = DIGIT;
|
||||
break;
|
||||
case DIGIT:
|
||||
if (ffCharIsDigit(c))
|
||||
continue;
|
||||
if (c == '.')
|
||||
state = DOT;
|
||||
else
|
||||
state = START;
|
||||
break;
|
||||
case DOT:
|
||||
if (ffCharIsDigit(c))
|
||||
state = MATCH;
|
||||
else
|
||||
state = START;
|
||||
break;
|
||||
case MATCH:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return state == MATCH;
|
||||
}
|
||||
|
||||
static bool checkNixCache(FFstrbuf* cacheDir, FFstrbuf* hash, uint32_t* count)
|
||||
{
|
||||
if (!ffPathExists(cacheDir->chars, FF_PATHTYPE_FILE))
|
||||
return false;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreate();
|
||||
if (!ffReadFileBuffer(cacheDir->chars, &cacheContent))
|
||||
return false;
|
||||
|
||||
// Format: <hash>\n<count>
|
||||
uint32_t split = ffStrbufFirstIndexC(&cacheContent, '\n');
|
||||
if (split == cacheContent.length)
|
||||
return false;
|
||||
|
||||
ffStrbufSetNS(hash, split, cacheContent.chars);
|
||||
*count = (uint32_t)atoi(cacheContent.chars + split + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeNixCache(FFstrbuf* cacheDir, FFstrbuf* hash, uint32_t count)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreateCopy(hash);
|
||||
ffStrbufAppendF(&cacheContent, "\n%u", count);
|
||||
return ffWriteFileBuffer(cacheDir->chars, &cacheContent);
|
||||
}
|
||||
|
||||
static uint32_t getNixPackagesImpl(char* path)
|
||||
{
|
||||
//Nix detection is kinda slow, so we only do it if the dir exists
|
||||
if(!ffPathExists(path, FF_PATHTYPE_DIRECTORY))
|
||||
return 0;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cacheDir = ffStrbufCreateCopy(&instance.state.platform.cacheDir);
|
||||
ffStrbufEnsureEndsWithC(&cacheDir, '/');
|
||||
ffStrbufAppendS(&cacheDir, "fastfetch/packages/nix");
|
||||
ffStrbufAppendS(&cacheDir, path);
|
||||
|
||||
//Check the hash first to determine if we need to recompute the count
|
||||
FF_STRBUF_AUTO_DESTROY hash = ffStrbufCreateA(64);
|
||||
FF_STRBUF_AUTO_DESTROY cacheHash = ffStrbufCreateA(64);
|
||||
uint32_t count = 0;
|
||||
|
||||
ffProcessAppendStdOut(&hash, (char* const[]) {
|
||||
"nix-store",
|
||||
"--query",
|
||||
"--hash",
|
||||
path,
|
||||
NULL
|
||||
});
|
||||
|
||||
if (checkNixCache(&cacheDir, &cacheHash, &count) && ffStrbufEqual(&hash, &cacheHash))
|
||||
return count;
|
||||
|
||||
//Cache is invalid, recompute the count
|
||||
count = 0;
|
||||
|
||||
//Implementation based on bash script from here:
|
||||
//https://github.com/fastfetch-cli/fastfetch/issues/195#issuecomment-1191748222
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreateA(1024);
|
||||
|
||||
ffProcessAppendStdOut(&output, (char* const[]) {
|
||||
"nix-store",
|
||||
"--query",
|
||||
"--requisites",
|
||||
path,
|
||||
NULL
|
||||
});
|
||||
|
||||
uint32_t lineLength = 0;
|
||||
for (uint32_t i = 0; i < output.length; i++)
|
||||
{
|
||||
if (output.chars[i] != '\n')
|
||||
{
|
||||
lineLength++;
|
||||
continue;
|
||||
}
|
||||
|
||||
output.chars[i] = '\0';
|
||||
FFstrbuf line = {
|
||||
.allocated = 0,
|
||||
.length = lineLength,
|
||||
.chars = output.chars + i - lineLength
|
||||
};
|
||||
if (isValidNixPkg(&line))
|
||||
count++;
|
||||
lineLength = 0;
|
||||
}
|
||||
|
||||
writeNixCache(&cacheDir, &hash, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t ffPackagesGetNix(FFstrbuf* baseDir, const char* dirname)
|
||||
{
|
||||
uint32_t baseDirLength = baseDir->length;
|
||||
ffStrbufAppendS(baseDir, dirname);
|
||||
uint32_t num_elements = getNixPackagesImpl(baseDir->chars);
|
||||
ffStrbufSubstrBefore(baseDir, baseDirLength);
|
||||
return num_elements;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ static void detectScoop(FFPackagesResult* result)
|
||||
{
|
||||
ffStrbufClear(&scoopPath);
|
||||
if (root)
|
||||
ffStrbufSetS(&scoopPath, yyjson_get_str(yyjson_obj_get(root, "root_path")));
|
||||
ffStrbufSetJsonVal(&scoopPath, yyjson_obj_get(root, "root_path"));
|
||||
if (scoopPath.length == 0)
|
||||
{
|
||||
ffStrbufSet(&scoopPath, &instance.state.platform.homeDir);
|
||||
@@ -72,7 +72,7 @@ static void detectScoop(FFPackagesResult* result)
|
||||
{
|
||||
ffStrbufClear(&scoopPath);
|
||||
if (root)
|
||||
ffStrbufSetS(&scoopPath, yyjson_get_str(yyjson_obj_get(root, "global_path")));
|
||||
ffStrbufSetJsonVal(&scoopPath, yyjson_obj_get(root, "global_path"));
|
||||
if (scoopPath.length == 0)
|
||||
{
|
||||
ffStrbufSetS(&scoopPath, getenv("ProgramData"));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/physicaldisk/option.h"
|
||||
|
||||
#define FF_PHYSICALDISK_TEMP_UNSET (0/0.0)
|
||||
#define FF_PHYSICALDISK_TEMP_UNSET (-DBL_MAX)
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFPhysicalDiskType
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/physicalmemory/option.h"
|
||||
|
||||
typedef struct FFPhysicalMemoryResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/poweradapter/option.h"
|
||||
|
||||
typedef struct FFPowerAdapterResult
|
||||
{
|
||||
|
||||
@@ -31,13 +31,13 @@ static void parsePowerAdapter(int dfd, FF_MAYBE_UNUSED const char* id, FFlist* r
|
||||
return;
|
||||
|
||||
//input_power_limit must exist and be not empty
|
||||
if (!ffReadFileBufferRelative(dfd, "input_power_limit", &tmpBuffer))
|
||||
if (!ffReadFileBufferRelative(dfd, "input_power_limit", &tmpBuffer) || tmpBuffer.length == 0)
|
||||
return;
|
||||
|
||||
FFPowerAdapterResult* result = ffListAdd(results);
|
||||
ffStrbufInit(&result->name);
|
||||
ffStrbufInit(&result->description);
|
||||
result->watts = (int) (ffStrbufToDouble(&tmpBuffer) / 1e6 + 0.5);
|
||||
result->watts = (int) (ffStrbufToDouble(&tmpBuffer, 0) / 1e6 + 0.5);
|
||||
ffStrbufInit(&result->manufacturer);
|
||||
ffStrbufInit(&result->modelName);
|
||||
ffStrbufInit(&result->serial);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user