diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a8495dc6b..ab2341eebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,34 @@ +# 2.33.0 + +Changes: +* Introduce a new CMake flag `-DBUILD_FLASHFETCH=OFF` to disable building flashfetch binaries + * Package managers are encouraged to enable it. See for detail + +Bugfixes: +* Fix interconnect type detection (#1453, PhysicalDisk, Linux) + * Regression of v2.28 +* Don't report `proot` as terminal (Terminal, Android) +* Remove a debug output (DiskIO, OpenBSD) +* Fix media detection for some players (#1461, Media, Linux) + * Regression of v2.32 + +Features: +* Use `$POWERSHELL_VERSION` as PowerShell version if available (Shell, Windows) + * Fetching Windows PowerShell version can be very slow. Add `$env:POWERSHELL_VERSION = $PSVersionTable.PSVersion.ToString()` in `$PROFILE` before running `fastfetch` to improve the performance of `Shell` module +* Add support for ubuntu-based armbian detection (#1447, OS, Linux) +* Improve performance of Bluetooth detection (Bluetooth) + * We no longer report disconnected bluetooth devices in `--format json` when `--bluetooth-show-disconnected` isn't specified +* Support brightness level detection for builtin displays (Brightness, OpenBSD / NetBSD) + * Requires root permission on OpenBSD +* Support battery level detection (Battery, OpenBSD / NetBSD) +* Support CPU temperature detection in NetBSD (CPU, NetBSD) +* Hard code path of `libvulkan.so` for Android + * So that users don't need to install the vulkan-loader wrapper of termux + +Logo: +* Add NurOS +* Add GoralixOS + # 2.32.1 A hotfix for OpenBSD. No changes to other platforms. diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ab90fcb31..71c0e886ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.32.1 + VERSION 2.33.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" @@ -86,6 +86,7 @@ cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR Open option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF) option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF) option(ENABLE_LTO "Enable link-time optimization in release mode if supported" ON) +option(BUILD_FLASHFETCH "Build flashfetch" ON) # Also build the flashfetch binary option(BUILD_TESTS "Build tests" OFF) # Also create test executables option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds option(IS_MUSL "Build with musl libc" OFF) # Used by Github Actions @@ -616,8 +617,8 @@ elseif(FreeBSD) src/common/sysctl.c src/detection/battery/battery_bsd.c src/detection/bios/bios_bsd.c - src/detection/bluetooth/bluetooth_linux.c - src/detection/bluetoothradio/bluetoothradio_linux.c + src/detection/bluetooth/bluetooth_nosupport.c + src/detection/bluetoothradio/bluetoothradio_nosupport.c src/detection/board/board_bsd.c src/detection/bootmgr/bootmgr_bsd.c src/detection/brightness/brightness_bsd.c @@ -697,13 +698,13 @@ elseif(NetBSD) src/common/networking_linux.c src/common/processing_linux.c src/common/sysctl.c - src/detection/battery/battery_nosupport.c + src/detection/battery/battery_nbsd.c src/detection/bios/bios_nbsd.c - src/detection/bluetooth/bluetooth_linux.c - src/detection/bluetoothradio/bluetoothradio_linux.c + src/detection/bluetooth/bluetooth_nosupport.c + src/detection/bluetoothradio/bluetoothradio_nosupport.c src/detection/board/board_nbsd.c src/detection/bootmgr/bootmgr_nosupport.c - src/detection/brightness/brightness_nosupport.c + src/detection/brightness/brightness_nbsd.c src/detection/btrfs/btrfs_nosupport.c src/detection/chassis/chassis_nbsd.c src/detection/cpu/cpu_nbsd.c @@ -779,13 +780,13 @@ elseif(OpenBSD) src/common/networking_linux.c src/common/processing_linux.c src/common/sysctl.c - src/detection/battery/battery_nosupport.c + src/detection/battery/battery_obsd.c src/detection/bios/bios_nosupport.c - src/detection/bluetooth/bluetooth_linux.c - src/detection/bluetoothradio/bluetoothradio_linux.c + src/detection/bluetooth/bluetooth_nosupport.c + src/detection/bluetoothradio/bluetoothradio_nosupport.c src/detection/board/board_nosupport.c src/detection/bootmgr/bootmgr_nosupport.c - src/detection/brightness/brightness_nosupport.c + src/detection/brightness/brightness_obsd.c src/detection/btrfs/btrfs_nosupport.c src/detection/chassis/chassis_nosupport.c src/detection/cpu/cpu_obsd.c @@ -1485,6 +1486,7 @@ elseif(OpenBSD) elseif(NetBSD) target_link_libraries(libfastfetch PRIVATE "m" + PRIVATE "prop" ) elseif(SunOS) target_link_libraries(libfastfetch @@ -1611,41 +1613,52 @@ target_link_libraries(fastfetch PRIVATE libfastfetch ) -add_executable(flashfetch - src/flashfetch.c -) -target_compile_definitions(flashfetch - PRIVATE FASTFETCH_TARGET_BINARY_NAME=flashfetch -) -target_link_libraries(flashfetch - PRIVATE libfastfetch -) - # Prevent fastfetch from linking to libstdc++ set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "") set_target_properties(fastfetch PROPERTIES LINKER_LANGUAGE C) -set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C) if(WIN32) target_sources(fastfetch PRIVATE src/util/windows/version.rc ) - target_sources(flashfetch - PRIVATE src/util/windows/version.rc - ) elseif(APPLE) target_link_options(fastfetch PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,Info.plist ) - target_link_options(flashfetch - PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,Info.plist - ) endif() if(BINARY_LINK_TYPE STREQUAL "static") target_link_options(fastfetch PRIVATE "-static") - target_link_options(flashfetch PRIVATE "-static") +endif() + +# Apply all above parameters to flashfetch if it is built +if (BUILD_FLASHFETCH) + add_executable(flashfetch + src/flashfetch.c + ) + target_compile_definitions(flashfetch + PRIVATE FASTFETCH_TARGET_BINARY_NAME=flashfetch + ) + target_link_libraries(flashfetch + PRIVATE libfastfetch + ) + + set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C) + + if(WIN32) + target_sources(flashfetch + PRIVATE src/util/windows/version.rc + ) + elseif(APPLE) + target_link_options(flashfetch + PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,Info.plist + ) + endif() + + if(BINARY_LINK_TYPE STREQUAL "static") + target_link_options(flashfetch PRIVATE "-static") + endif() endif() ################### @@ -1687,10 +1700,17 @@ endif() include(GNUInstallDirs) install( - TARGETS fastfetch flashfetch + TARGETS fastfetch DESTINATION "${CMAKE_INSTALL_BINDIR}" ) +if (TARGET flashfetch) + install( + TARGETS flashfetch + DESTINATION "${CMAKE_INSTALL_BINDIR}" + ) +endif() + if (TARGET ffwinrt) install( TARGETS ffwinrt diff --git a/README.md b/README.md index 01f9d44bf3..3563d39f8f 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,10 @@ Try upgrading `pci.ids`: Download and over Alternatively, you may try to use `fastfetch --gpu-driver-specific`, so that `fastfetch` will try to ask the driver for GPU name if supported. +### Q: I get error `Authorization required, but no authorization protocol specified` when running fastfetch in root + +Try `export XAUTHORITY=$HOME/.Xauthority` + ### Q: Fastfetch cannot detect my awesome 3rd-party macOS window manager! Try `fastfetch --wm-detect-plugin`. See also [#984](https://github.com/fastfetch-cli/fastfetch/issues/984) diff --git a/src/detection/battery/battery_nbsd.c b/src/detection/battery/battery_nbsd.c new file mode 100644 index 0000000000..682bfbfd28 --- /dev/null +++ b/src/detection/battery/battery_nbsd.c @@ -0,0 +1,107 @@ +#include "battery.h" +#include "common/io/io.h" +#include "util/FFstrbuf.h" +#include "util/stringUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results) +{ + FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY); + if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed"; + + prop_dictionary_t root = NULL; + if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0) + return "prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed"; + + bool acConnected = false; + { + prop_array_t acad = prop_dictionary_get(root, "acpiacad0"); + if (acad) + { + prop_dictionary_t dict = prop_array_get(acad, 0); + prop_dictionary_get_uint8(dict, "cur-value", (uint8_t*) &acConnected); + } + } + + prop_object_iterator_t itKey = prop_dictionary_iterator(root); + for (prop_dictionary_keysym_t key; (key = prop_object_iterator_next(itKey)) != NULL; ) + { + if (!ffStrStartsWith(prop_dictionary_keysym_value(key), "acpibat")) continue; + + prop_array_t bat = prop_dictionary_get_keysym(root, key); + uint32_t max = 0, curr = 0, dischargeRate = 0; + bool charging = false, critical = false; + prop_object_iterator_t iter = prop_array_iterator(bat); + for (prop_dictionary_t dict; (dict = prop_object_iterator_next(iter)) != NULL;) + { + if (prop_object_type(dict) != PROP_TYPE_DICTIONARY) + continue; + + const char* desc = NULL; + if (!prop_dictionary_get_string(dict, "description", &desc)) + continue; + + if (ffStrEquals(desc, "present")) + { + int value = 0; + if (prop_dictionary_get_int(dict, "cur-value", &value) && value == 0) + continue; + } + else if (ffStrEquals(desc, "charging")) + { + prop_dictionary_get_uint8(dict, "cur-value", (uint8_t*) &charging); + } + else if (ffStrEquals(desc, "charge")) + { + prop_dictionary_get_uint32(dict, "max-value", &max); + prop_dictionary_get_uint32(dict, "cur-value", &curr); + const char* state = NULL; + if (prop_dictionary_get_string(dict, "state", &state) && ffStrEquals(state, "critical")) + critical = true; + } + else if (ffStrEquals(desc, "discharge rate")) + { + prop_dictionary_get_uint(dict, "cur-value", &dischargeRate); + } + } + + if (max > 0) + { + FFBatteryResult* battery = ffListAdd(results); + battery->temperature = FF_BATTERY_TEMP_UNSET; + battery->cycleCount = 0; + ffStrbufInit(&battery->manufacturer); + ffStrbufInit(&battery->modelName); + ffStrbufInit(&battery->status); + ffStrbufInit(&battery->technology); + ffStrbufInit(&battery->serial); + ffStrbufInit(&battery->manufactureDate); + battery->timeRemaining = -1; + + battery->capacity = (double) curr / max; + if (charging) + ffStrbufAppendS(&battery->status, "Charging, "); + else if (dischargeRate) + ffStrbufAppendS(&battery->status, "Discharging, "); + if (critical) + ffStrbufAppendS(&battery->status, "Critical, "); + if (acConnected) + ffStrbufAppendS(&battery->status, "AC Connected"); + ffStrbufTrimRight(&battery->status, ' '); + ffStrbufTrimRight(&battery->status, ','); + } + } + prop_object_iterator_release(itKey); + + return NULL; +} diff --git a/src/detection/battery/battery_obsd.c b/src/detection/battery/battery_obsd.c new file mode 100644 index 0000000000..ea4f731489 --- /dev/null +++ b/src/detection/battery/battery_obsd.c @@ -0,0 +1,52 @@ +#include "battery.h" +#include "common/io/io.h" + +#include +#include +#include +#include + +const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* result) +{ + FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY); + + if (devfd < 0) return "open(dev/apm, O_RDONLY) failed"; + + struct apm_power_info info = {}; + + if (ioctl(devfd, APM_IOC_GETPOWER, &info) < 0) + return "ioctl(APM_IOC_GETPOWER) failed"; + + if (info.battery_state == APM_BATTERY_ABSENT) + return NULL; + + FFBatteryResult* battery = (FFBatteryResult*) ffListAdd(result); + battery->temperature = FF_BATTERY_TEMP_UNSET; + battery->cycleCount = 0; + battery->timeRemaining = -1; + battery->capacity = info.battery_life; + ffStrbufInit(&battery->manufacturer); + ffStrbufInit(&battery->modelName); + ffStrbufInit(&battery->status); + ffStrbufInit(&battery->technology); + ffStrbufInit(&battery->serial); + ffStrbufInit(&battery->manufactureDate); + + if (info.ac_state == APM_AC_ON) + ffStrbufAppendS(&battery->status, "AC Connected"); + else if (info.ac_state == APM_AC_BACKUP) + ffStrbufAppendS(&battery->status, "Backup In Use"); + else if (info.ac_state == APM_AC_OFF) + { + battery->timeRemaining = (int) info.minutes_left * 60; + ffStrbufAppendS(&battery->status, "Discharging"); + } + + if (info.battery_state == APM_BATT_CRITICAL || info.battery_state == APM_BATT_CHARGING) + { + if (battery->status.length) ffStrbufAppendS(&battery->status, ", "); + ffStrbufAppendS(&battery->status, info.battery_state == APM_BATT_CRITICAL ? "Critical" : "Charging"); + } + + return NULL; +} diff --git a/src/detection/bluetooth/bluetooth.h b/src/detection/bluetooth/bluetooth.h index 0702abbdb7..57bf9ef3ac 100644 --- a/src/detection/bluetooth/bluetooth.h +++ b/src/detection/bluetooth/bluetooth.h @@ -11,4 +11,4 @@ typedef struct FFBluetoothResult bool connected; } FFBluetoothResult; -const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */); +const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */); diff --git a/src/detection/bluetooth/bluetooth_apple.m b/src/detection/bluetooth/bluetooth_apple.m index 4f29deb56d..e7d3abd391 100644 --- a/src/detection/bluetooth/bluetooth_apple.m +++ b/src/detection/bluetooth/bluetooth_apple.m @@ -10,7 +10,7 @@ @interface IOBluetoothDevice() @property (nonatomic) uint8_t batteryPercentSingle; @end -const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */) +const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */) { NSArray* ioDevices = IOBluetoothDevice.pairedDevices; if(!ioDevices) @@ -18,6 +18,9 @@ @interface IOBluetoothDevice() for(IOBluetoothDevice* ioDevice in ioDevices) { + if (!options->showDisconnected && !ioDevice.isConnected) + continue; + FFBluetoothResult* device = ffListAdd(devices); ffStrbufInitS(&device->name, ioDevice.name.UTF8String); ffStrbufInitS(&device->address, ioDevice.addressString.UTF8String); diff --git a/src/detection/bluetooth/bluetooth_linux.c b/src/detection/bluetooth/bluetooth_linux.c index b7ae5a8394..beaaba9b13 100644 --- a/src/detection/bluetooth/bluetooth_linux.c +++ b/src/detection/bluetooth/bluetooth_linux.c @@ -3,6 +3,7 @@ #ifdef FF_HAVE_DBUS #include "common/dbus.h" +#include "common/io/io.h" /* Example dbus reply, striped to only the relevant parts: array [ //root @@ -44,16 +45,16 @@ array [ //root ] */ -static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device) +static bool detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device) { if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) - return; + return true; DBusMessageIter dictIter; dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter); if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) - return; + return true; const char* deviceProperty; dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty); @@ -74,6 +75,13 @@ static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBlue } else if(ffStrEquals(deviceProperty, "Connected")) ffDBusGetBool(dbus, &dictIter, &device->connected); + else if(ffStrEquals(deviceProperty, "Paired")) + { + bool paired = true; + ffDBusGetBool(dbus, &dictIter, &paired); + if (!paired) return false; + } + return true; } static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device) @@ -103,32 +111,37 @@ static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFB do { - detectBluetoothValue(dbus, &arrayIter, device); + bool shouldContinue = detectBluetoothValue(dbus, &arrayIter, device); + if (!shouldContinue) + { + ffStrbufClear(&device->name); + break; + } } while (dbus->lib->ffdbus_message_iter_next(&arrayIter)); } -static void detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter) +static FFBluetoothResult* detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter) { if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) - return; + return NULL; DBusMessageIter dictIter; dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter); if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH) - return; + return NULL; const char* objectPath; dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &objectPath); // We don't want adapter objects if(!ffStrContains(objectPath, "/dev_")) - return; + return NULL; dbus->lib->ffdbus_message_iter_next(&dictIter); if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY) - return; + return NULL; DBusMessageIter arrayIter; dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter); @@ -145,16 +158,10 @@ static void detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessage detectBluetoothProperty(dbus, &arrayIter, device); } while (dbus->lib->ffdbus_message_iter_next(&arrayIter)); - if(device->name.length == 0) - { - ffStrbufDestroy(&device->name); - ffStrbufDestroy(&device->address); - ffStrbufDestroy(&device->type); - --devices->length; - } + return device; } -static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter) +static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter, int32_t connectedCount) { if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) return; @@ -164,11 +171,25 @@ static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIt do { - detectBluetoothObject(devices, dbus, &arrayIter); + FFBluetoothResult* device = detectBluetoothObject(devices, dbus, &arrayIter); + + if (device) + { + if(device->name.length == 0 || (connectedCount > 0 && !device->connected)) + { + ffStrbufDestroy(&device->name); + ffStrbufDestroy(&device->address); + ffStrbufDestroy(&device->type); + --devices->length; + } + + if (device->connected && --connectedCount == 0) + break; + } } while (dbus->lib->ffdbus_message_iter_next(&arrayIter)); } -static const char* detectBluetooth(FFlist* devices) +static const char* detectBluetooth(FFlist* devices, int32_t connectedCount) { FFDBusData dbus; const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus); @@ -186,18 +207,43 @@ static const char* detectBluetooth(FFlist* devices) return "Failed to get root iterator of GetManagedObjects"; } - detectBluetoothRoot(devices, &dbus, &rootIter); + detectBluetoothRoot(devices, &dbus, &rootIter, connectedCount); dbus.lib->ffdbus_message_unref(managedObjects); return NULL; } +static uint32_t connectedDevices(void) +{ + FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/bluetooth"); + if(dirp == NULL) + return 0; + + uint32_t result = 0; + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) + { + if (strchr(entry->d_name, ':') != NULL) + ++result; + } + + return result; +} + #endif -const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */) +const char* ffDetectBluetooth(FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */) { #ifdef FF_HAVE_DBUS - return detectBluetooth(devices); + int32_t connectedCount = -1; + if (!options->showDisconnected) + { + connectedCount = (int32_t) connectedDevices(); + if (connectedCount == 0) + return NULL; + } + + return detectBluetooth(devices, connectedCount); #else return "Fastfetch was compiled without DBus support"; #endif diff --git a/src/detection/bluetooth/bluetooth_nosupport.c b/src/detection/bluetooth/bluetooth_nosupport.c index 8db5a465cb..c119ecb954 100644 --- a/src/detection/bluetooth/bluetooth_nosupport.c +++ b/src/detection/bluetooth/bluetooth_nosupport.c @@ -1,6 +1,6 @@ #include "bluetooth.h" -const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */) +const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */) { return "Not supported on this platform"; } diff --git a/src/detection/bluetooth/bluetooth_windows.c b/src/detection/bluetooth/bluetooth_windows.c index 80b83837ae..5da75fc839 100644 --- a/src/detection/bluetooth/bluetooth_windows.c +++ b/src/detection/bluetooth/bluetooth_windows.c @@ -7,7 +7,7 @@ #pragma GCC diagnostic ignored "-Wpointer-sign" -const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */) +const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */) { // Actually bluetoothapis.dll, but it's missing on Windows 7 FF_LIBRARY_LOAD(bluetoothapis, "dlopen bthprops.cpl failed", "bthprops.cpl", 1) @@ -20,13 +20,14 @@ const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */) }; HBLUETOOTH_DEVICE_FIND hFind = ffBluetoothFindFirstDevice(&(BLUETOOTH_DEVICE_SEARCH_PARAMS) { .fReturnConnected = TRUE, - .fReturnRemembered = TRUE, - .fReturnAuthenticated = TRUE, - .fReturnUnknown = TRUE, + .fReturnRemembered = options->showDisconnected, + .fReturnAuthenticated = options->showDisconnected, .dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS) }, &btdi); if(!hFind) { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + return NULL; return "BluetoothFindFirstDevice() failed"; } diff --git a/src/detection/bluetooth/bluetooth_windows.cpp b/src/detection/bluetooth/bluetooth_windows.cpp index 70fc1de187..e995d23765 100644 --- a/src/detection/bluetooth/bluetooth_windows.cpp +++ b/src/detection/bluetooth/bluetooth_windows.cpp @@ -55,7 +55,7 @@ const char* ffBluetoothDetectBattery(FFlist* devices) on_scope_exit releaseCallResult([&] { pCallResult && pCallResult->Release(); }); IWbemClassObject* pResultObject = nullptr; - if (FAILED(pCallResult->GetResultObject(WBEM_INFINITE, &pResultObject))) + if (FAILED(pCallResult->GetResultObject((LONG) WBEM_INFINITE, &pResultObject))) continue; on_scope_exit releaseResultObject([&] { pResultObject && pResultObject->Release(); }); diff --git a/src/detection/bluetoothradio/bluetoothradio_linux.c b/src/detection/bluetoothradio/bluetoothradio_linux.c index 05b77523cc..50427e57ff 100644 --- a/src/detection/bluetoothradio/bluetoothradio_linux.c +++ b/src/detection/bluetoothradio/bluetoothradio_linux.c @@ -3,56 +3,47 @@ #ifdef FF_HAVE_DBUS #include "common/dbus.h" +#include "common/io/io.h" -/* Example dbus reply, striped to only the relevant parts: -array [ //root +/* Example dbus reply: +array [ dict entry( - object path "/org/bluez/hci0" - array [ - dict entry( - string "org.bluez.Adapter1" - array [ - dict entry( - string "Address" - variant string "XX:XX:XX:XX:XX:XX" - ) - dict entry( - string "Name" - variant string "xxxxxxxx" - ) - dict entry( - string "Powered" - variant boolean true - ) - dict entry( - string "PowerState" - variant string "on" - ) - dict entry( - string "Manufacturer" - variant uint16 2 - ) - dict entry( - string "Version" - variant byte 12 - ) - ] - ) - ] + string "Address" + variant string "XX:XX:XX:XX:XX:XX" + ) + dict entry( + string "Name" + variant string "xxxxxxxx" + ) + dict entry( + string "Powered" + variant boolean true + ) + dict entry( + string "PowerState" + variant string "on" + ) + dict entry( + string "Manufacturer" + variant uint16 2 + ) + dict entry( + string "Version" + variant byte 12 ) ] */ -static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothRadioResult* device) +static const char* detectBluetoothProperty(FFBluetoothRadioResult* device, FFDBusData* dbus, DBusMessageIter* iter) { if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) - return; + return "Expected dict entry"; DBusMessageIter dictIter; dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter); if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) - return; + return "Expected dict entry key to be a string"; const char* deviceProperty; dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty); @@ -77,121 +68,73 @@ static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBlue ffDBusGetBool(dbus, &dictIter, &device->discoverable); else if(ffStrEquals(deviceProperty, "Pairable")) ffDBusGetBool(dbus, &dictIter, &device->connectable); -} - -static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothRadioResult* device) -{ - if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) - return; - DBusMessageIter dictIter; - dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter); - - if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) - return; - - const char* propertyType; - dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &propertyType); - - if(!ffStrContains(propertyType, ".Adapter")) - return; //We don't care about other properties - - dbus->lib->ffdbus_message_iter_next(&dictIter); - - if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY) - return; - - DBusMessageIter arrayIter; - dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter); - - do - { - detectBluetoothValue(dbus, &arrayIter, device); - } while (dbus->lib->ffdbus_message_iter_next(&arrayIter)); + return NULL; } -static void detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter) +static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const char* hciName, FFDBusData* dbus) { - if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) - return; - - DBusMessageIter dictIter; - dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter); - - if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH) - return; - - const char* objectPath; - dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &objectPath); - - //We want adapter objects - if(!ffStrStartsWith(objectPath, "/org/bluez/hci") || ffStrContains(objectPath, "/dev_")) - return; - - dbus->lib->ffdbus_message_iter_next(&dictIter); - - if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY) - return; - - DBusMessageIter arrayIter; - dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter); + char objPath[300]; + snprintf(objPath, sizeof(objPath), "/org/bluez/%s", hciName); - FFBluetoothRadioResult* device = ffListAdd(devices); - ffStrbufInit(&device->name); - ffStrbufInit(&device->address); - ffStrbufInitStatic(&device->vendor, "Unknown"); - device->lmpVersion = INT_MIN; - device->lmpSubversion = INT_MIN; - device->enabled = false; + DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1"); + if(!properties) + return "Failed to call org.freedesktop.DBus.Properties.GetAll"; - do + DBusMessageIter rootIter; + if(!dbus->lib->ffdbus_message_iter_init(properties, &rootIter)) { - detectBluetoothProperty(dbus, &arrayIter, device); - } while (dbus->lib->ffdbus_message_iter_next(&arrayIter)); + dbus->lib->ffdbus_message_unref(properties); + return "Failed to get root iterator of org.freedesktop.DBus.Properties.GetAll"; + } - if(device->name.length == 0) + if(dbus->lib->ffdbus_message_iter_get_arg_type(&rootIter) != DBUS_TYPE_ARRAY) { - ffStrbufDestroy(&device->name); - ffStrbufDestroy(&device->address); - --devices->length; + dbus->lib->ffdbus_message_unref(properties); + return "Expected array"; } -} - -static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter) -{ - if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) - return; DBusMessageIter arrayIter; - dbus->lib->ffdbus_message_iter_recurse(iter, &arrayIter); + dbus->lib->ffdbus_message_iter_recurse(&rootIter, &arrayIter); do { - detectBluetoothObject(devices, dbus, &arrayIter); + detectBluetoothProperty(device, dbus, &arrayIter); } while (dbus->lib->ffdbus_message_iter_next(&arrayIter)); + + dbus->lib->ffdbus_message_unref(properties); + return NULL; } static const char* detectBluetooth(FFlist* devices) { + FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/bluetooth"); + if(dirp == NULL) + return "Failed to open /sys/class/bluetooth"; + FFDBusData dbus; const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus); if(error) return error; - DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL); - if(!managedObjects) - return "Failed to call GetManagedObjects"; - - DBusMessageIter rootIter; - if(!dbus.lib->ffdbus_message_iter_init(managedObjects, &rootIter)) + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) { - dbus.lib->ffdbus_message_unref(managedObjects); - return "Failed to get root iterator of GetManagedObjects"; + if (entry->d_name[0] == '.') + continue; + + if (strchr(entry->d_name, ':') != NULL) // ignore connected devices + continue; + + FFBluetoothRadioResult* device = ffListAdd(devices); + ffStrbufInit(&device->name); + ffStrbufInit(&device->address); + ffStrbufInitStatic(&device->vendor, "Unknown"); + device->lmpVersion = INT_MIN; + device->lmpSubversion = INT_MIN; + device->enabled = false; + detectBluetoothRoot(device, entry->d_name, &dbus); } - - detectBluetoothRoot(devices, &dbus, &rootIter); - - dbus.lib->ffdbus_message_unref(managedObjects); return NULL; } @@ -202,7 +145,7 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */) #ifdef FF_HAVE_DBUS return detectBluetooth(devices); #else - FF_UNUSED(devices) + FF_UNUSED(devices) return "Fastfetch was compiled without DBus support"; #endif } diff --git a/src/detection/board/board_nbsd.c b/src/detection/board/board_nbsd.c index 9557cc3398..cc89149aae 100644 --- a/src/detection/board/board_nbsd.c +++ b/src/detection/board/board_nbsd.c @@ -10,6 +10,8 @@ const char* ffDetectBoard(FFBoardResult* board) ffCleanUpSmbiosValue(&board->version); if (ffSysctlGetString("machdep.dmi.board-vendor", &board->vendor) == NULL) ffCleanUpSmbiosValue(&board->vendor); + if (ffSysctlGetString("machdep.dmi.board-serial", &board->serial) == NULL) + ffCleanUpSmbiosValue(&board->serial); return NULL; } diff --git a/src/detection/brightness/brightness_nbsd.c b/src/detection/brightness/brightness_nbsd.c new file mode 100644 index 0000000000..1fd7773b0e --- /dev/null +++ b/src/detection/brightness/brightness_nbsd.c @@ -0,0 +1,25 @@ +#include "brightness.h" + +#include "common/sysctl.h" + +const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) +{ + // https://man.netbsd.org/NetBSD-10.1/acpiout.4#DESCRIPTION + char key[] = "hw.acpi.acpiout0.brightness"; + char* pn = key + strlen("hw.acpi.acpiout"); + + for (uint32_t i = 0; i <= 9; ++i) + { + *pn = (char) ('0' + i); + int value = ffSysctlGetInt(key, -1); + if (value == -1) continue; + + FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result); + ffStrbufInitF(&brightness->name, "acpiout%d", i); + + brightness->max = 100; + brightness->min = 0; + brightness->current = value; + } + return NULL; +} diff --git a/src/detection/brightness/brightness_obsd.c b/src/detection/brightness/brightness_obsd.c new file mode 100644 index 0000000000..ea5d7334cc --- /dev/null +++ b/src/detection/brightness/brightness_obsd.c @@ -0,0 +1,30 @@ +#include "brightness.h" +#include "common/io/io.h" + +#include +#include +#include +#include + +const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) +{ + FF_AUTO_CLOSE_FD int devfd = open("/dev/ttyC0", O_RDONLY); + + if (devfd < 0) return "open(dev/ttyC0, O_RDONLY) failed"; + + struct wsdisplay_param param = { + .param = WSDISPLAYIO_PARAM_BRIGHTNESS, + }; + + if (ioctl(devfd, WSDISPLAYIO_GETPARAM, ¶m) < 0) + return "ioctl(WSDISPLAYIO_GETPARAM) failed"; + + FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result); + ffStrbufInitStatic(&brightness->name, "wsdisplay"); + + brightness->max = param.max; + brightness->min = param.min; + brightness->current = param.curval; + + return NULL; +} diff --git a/src/detection/chassis/chassis_nbsd.c b/src/detection/chassis/chassis_nbsd.c index 796c241a9d..c2593bf85c 100644 --- a/src/detection/chassis/chassis_nbsd.c +++ b/src/detection/chassis/chassis_nbsd.c @@ -10,6 +10,8 @@ const char* ffDetectChassis(FFChassisResult* chassis) ffCleanUpSmbiosValue(&chassis->version); if (ffSysctlGetString("machdep.dmi.chassis-vendor", &chassis->vendor) == NULL) ffCleanUpSmbiosValue(&chassis->vendor); + if (ffSysctlGetString("machdep.dmi.chassis-serial", &chassis->serial) == NULL) + ffCleanUpSmbiosValue(&chassis->serial); return NULL; } diff --git a/src/detection/cpu/cpu_nbsd.c b/src/detection/cpu/cpu_nbsd.c index 0a78ed146b..12e6bb4cd1 100644 --- a/src/detection/cpu/cpu_nbsd.c +++ b/src/detection/cpu/cpu_nbsd.c @@ -1,26 +1,42 @@ #include "cpu.h" #include "common/sysctl.h" -#include +#include "common/io/io.h" + +#include +#include +#include +#include +#include +#include static const char* detectCpuTemp(double* current) { - int temp = ffSysctlGetInt("dev.cpu.0.temperature", -999999); - if (temp == -999999) - return "ffSysctlGetInt(\"dev.cpu.0.temperature\") failed"; + FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY); + if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed"; - // In tenth of degrees Kelvin - *current = (double) temp / 10 - 273.15; - return NULL; -} + prop_dictionary_t root = NULL; + if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0) + return "prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed"; -static const char* detectThermalTemp(double* current) -{ - int temp = ffSysctlGetInt("hw.acpi.thermal.tz0.temperature", -999999); - if (temp == -999999) - return "ffSysctlGetInt(\"hw.acpi.thermal.tz0.temperature\") failed"; + prop_array_t array = prop_dictionary_get(root, "coretemp0"); + if (!array) array = prop_dictionary_get(root, "amdzentemp0"); + if (!array) array = prop_dictionary_get(root, "viac7temp0"); + if (!array) array = prop_dictionary_get(root, "acpitz0"); // Thermal Zones + if (!array) return "No temp data found in root dictionary"; + + if (prop_array_count(array) != 2) + return "Unexpected `xtemp0` data"; + + prop_dictionary_t dict = prop_array_get(array, 0); + if (prop_object_type(dict) != PROP_TYPE_DICTIONARY) + return "Unexpected `xtemp0[0]`"; + + int temp = 0; // in µK + if (!prop_dictionary_get_int(dict, "cur-value", &temp)) + return "Failed to get temperature"; + + *current = temp / 1e6 - 273.15; - // In tenth of degrees Kelvin - *current = (double) temp / 10 - 273.15; return NULL; } @@ -32,26 +48,22 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) return "sysctlbyname(machdep.cpu_brand) failed"; } + if (ffSysctlGetString("machdep.dmi.processor-vendor", &cpu->vendor) == NULL) + ffStrbufTrimRightSpace(&cpu->vendor); + cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1); cpu->coresLogical = cpu->coresPhysical; cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.ncpuonline", cpu->coresLogical); ffCPUDetectSpeedByCpuid(cpu); - { - struct clockinfo info; - size_t length = sizeof(info); - if (sysctl((int[]) {CTL_KERN, KERN_CLOCKRATE}, 2, &info, &length, NULL, 0) == 0) - cpu->frequencyBase = (uint32_t) info.hz / 1000; - } + uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0); + if (freq > cpu->frequencyBase) + cpu->frequencyBase = freq; cpu->temperature = FF_CPU_TEMP_UNSET; - if (options->temp) - { - if (detectCpuTemp(&cpu->temperature) != NULL) - detectThermalTemp(&cpu->temperature); - } + if (options->temp) detectCpuTemp(&cpu->temperature); return NULL; } diff --git a/src/detection/diskio/diskio_obsd.c b/src/detection/diskio/diskio_obsd.c index b00b733a22..437d93caf1 100644 --- a/src/detection/diskio/diskio_obsd.c +++ b/src/detection/diskio/diskio_obsd.c @@ -13,8 +13,6 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options) return "sysctl({HW_DISKSTATS}, NULL) failed"; uint32_t nDrive = (uint32_t) (len / sizeof(struct diskstats)); - printf("C: %d\n", nDrive); - struct diskstats* stats = malloc(len); if (sysctl(mib, ARRAY_SIZE(mib), stats, &len, NULL, 0) < 0) diff --git a/src/detection/host/host_nbsd.c b/src/detection/host/host_nbsd.c index 947198cb6e..8fd61abf29 100644 --- a/src/detection/host/host_nbsd.c +++ b/src/detection/host/host_nbsd.c @@ -12,6 +12,10 @@ const char* ffDetectHost(FFHostResult* host) ffCleanUpSmbiosValue(&host->vendor); if (ffSysctlGetString("machdep.dmi.system-version", &host->version) == NULL) ffCleanUpSmbiosValue(&host->version); + if (ffSysctlGetString("machdep.dmi.system-serial", &host->serial) == NULL) + ffCleanUpSmbiosValue(&host->serial); + if (ffSysctlGetString("machdep.dmi.system-uuid", &host->uuid) == NULL) + ffCleanUpSmbiosValue(&host->uuid); return NULL; } diff --git a/src/detection/media/media_linux.c b/src/detection/media/media_linux.c index a4953de500..4434f317eb 100644 --- a/src/detection/media/media_linux.c +++ b/src/detection/media/media_linux.c @@ -78,7 +78,7 @@ static bool parseMprisMetadata(FFDBusData* data, DBusMessageIter* rootIterator, static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResult* result) { // Get all properties at once to reduce the number of IPCs - DBusMessage* reply = ffDBusGetAllProperties(data, busName, "/org/mpris/MediaPlayer2", ""); + DBusMessage* reply = ffDBusGetAllProperties(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player"); if(reply == NULL) return false; @@ -112,10 +112,6 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul parseMprisMetadata(data, &dictIterator, result); else if(ffStrEquals(key, "PlaybackStatus")) ffDBusGetString(data, &dictIterator, &result->status); - else if(ffStrEquals(key, "Identity")) - ffDBusGetString(data, &dictIterator, &result->player); - else if(ffStrEquals(key, "DesktopEntry")) - ffDBusGetString(data, &dictIterator, &desktopIdentity); FF_DBUS_ITER_CONTINUE(data, &arrayIterator) } @@ -128,17 +124,22 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul return false; } - if (result->player.length == 0) + //Set short bus name + ffStrbufAppendS(&result->playerId, busName + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); + + //We found a song, get the player name + if (ffStrbufStartsWithS(&result->playerId, "musikcube.instance")) + { + // dbus calls are EXTREMELY slow on musikcube, so we set the player name manually + ffStrbufSetStatic(&result->player, "musikcube"); + } + else { - if (desktopIdentity.length > 0) - { - ffStrbufDestroy(&result->player); - ffStrbufInitMove(&result->player, &desktopIdentity); - } - else - { + ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player); + if(result->player.length == 0) + ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player); + if(result->player.length == 0) ffStrbufAppend(&result->player, &result->playerId); - } } data->lib->ffdbus_message_unref(reply); diff --git a/src/detection/os/os_linux.c b/src/detection/os/os_linux.c index d4ec8b0be6..f293d5f0ef 100644 --- a/src/detection/os/os_linux.c +++ b/src/detection/os/os_linux.c @@ -46,13 +46,33 @@ static bool parseOsRelease(const char* fileName, FFOSResult* result) }); } +// Common logic for detecting Armbian image version +FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result) +{ + if (ffStrbufStartsWithS(&result->prettyName, "Armbian ")) // Official Armbian release images + ffStrbufSetS(&result->name, "Armbian"); + else if (ffStrbufStartsWithS(&result->prettyName, "Armbian-unofficial ")) // Unofficial Armbian image built from source + ffStrbufSetS(&result->name, "Armbian (custom build)"); + else + return false; + ffStrbufSet(&result->idLike, &result->id); + ffStrbufSetS(&result->id, "armbian"); + ffStrbufClear(&result->versionID); + uint32_t versionStart = ffStrbufFirstIndexC(&result->prettyName, ' ') + 1; + uint32_t versionEnd = ffStrbufNextIndexC(&result->prettyName, versionStart, ' '); + ffStrbufSetNS(&result->versionID, versionEnd - versionStart, result->prettyName.chars + versionStart); + return true; +} + FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result) { const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS"); if(!ffStrSet(xdgConfigDirs)) return; - if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite ")) + if (detectArmbianVersion(result)) + return; + else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite ")) { ffStrbufSetS(&result->name, "Linux Lite"); ffStrbufSetS(&result->id, "linuxlite"); @@ -164,28 +184,8 @@ FF_MAYBE_UNUSED static void getDebianVersion(FFOSResult* result) FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result) { - if (ffStrbufStartsWithS(&result->prettyName, "Armbian ")) // Armbian 24.2.1 bookworm - { - ffStrbufSetS(&result->name, "Armbian"); - ffStrbufSetS(&result->id, "armbian"); - ffStrbufSetS(&result->idLike, "debian"); - ffStrbufClear(&result->versionID); - uint32_t versionStart = ffStrbufFirstIndexC(&result->prettyName, ' ') + 1; - uint32_t versionEnd = ffStrbufNextIndexC(&result->prettyName, versionStart, ' '); - ffStrbufSetNS(&result->versionID, versionEnd - versionStart, result->prettyName.chars + versionStart); - return true; - } - else if (ffStrbufStartsWithS(&result->prettyName, "Armbian-unofficial ")) // Unofficial Armbian image built from source - { - ffStrbufSetS(&result->name, "Armbian (custom build)"); - ffStrbufSetS(&result->id, "armbian"); - ffStrbufSetS(&result->idLike, "debian"); - ffStrbufClear(&result->versionID); - uint32_t versionStart = ffStrbufFirstIndexC(&result->prettyName, ' ') + 1; - uint32_t versionEnd = ffStrbufNextIndexC(&result->prettyName, versionStart, ' '); - ffStrbufSetNS(&result->versionID, versionEnd - versionStart, result->prettyName.chars + versionStart); + if (detectArmbianVersion(result)) return true; - } else if (ffStrbufStartsWithS(&result->name, "Loc-OS")) { ffStrbufSetS(&result->id, "locos"); diff --git a/src/detection/physicaldisk/physicaldisk_linux.c b/src/detection/physicaldisk/physicaldisk_linux.c index 6a41ada243..ed1fa87bef 100644 --- a/src/detection/physicaldisk/physicaldisk_linux.c +++ b/src/detection/physicaldisk/physicaldisk_linux.c @@ -80,24 +80,28 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption { ffStrbufInit(&device->interconnect); - char pathSysDeviceReal[PATH_MAX]; - ssize_t pathLength = readlinkat(dfd, "device", pathSysDeviceReal, ARRAY_SIZE(pathSysDeviceReal) - 1); - if (pathLength > 0) + if (ffStrStartsWith(devName, "nvme")) + ffStrbufSetStatic(&device->interconnect, "NVMe"); + else { - pathSysDeviceReal[pathLength] = '\0'; - - if (strstr(pathSysDeviceReal, "/usb") != NULL) - ffStrbufSetS(&device->interconnect, "USB"); - else if (strstr(pathSysDeviceReal, "/nvme") != NULL) - ffStrbufSetS(&device->interconnect, "NVMe"); - else if (strstr(pathSysDeviceReal, "/ata") != NULL) - ffStrbufSetS(&device->interconnect, "ATA"); - else if (strstr(pathSysDeviceReal, "/scsi") != NULL) - ffStrbufSetS(&device->interconnect, "SCSI"); - else + char pathSysDeviceLink[64]; + snprintf(pathSysDeviceLink, ARRAY_SIZE(pathSysDeviceLink), "/sys/block/%s/device", devName); + char pathSysDeviceReal[PATH_MAX]; + if (realpath(pathSysDeviceLink, pathSysDeviceReal)) { - if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect)) - ffStrbufTrimRightSpace(&device->interconnect); + if (strstr(pathSysDeviceReal, "/usb") != NULL) + ffStrbufSetStatic(&device->interconnect, "USB"); + else if (strstr(pathSysDeviceReal, "/ata") != NULL) + ffStrbufSetStatic(&device->interconnect, "ATA"); + else if (strstr(pathSysDeviceReal, "/scsi") != NULL) + ffStrbufSetStatic(&device->interconnect, "SCSI"); + else if (strstr(pathSysDeviceReal, "/nvme") != NULL) + ffStrbufSetStatic(&device->interconnect, "NVMe"); + else + { + if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect)) + ffStrbufTrimRightSpace(&device->interconnect); + } } } } diff --git a/src/detection/physicalmemory/physicalmemory.c b/src/detection/physicalmemory/physicalmemory.c index c5df181f38..70e111b087 100644 --- a/src/detection/physicalmemory/physicalmemory.c +++ b/src/detection/physicalmemory/physicalmemory.c @@ -23,6 +23,7 @@ static inline const char* getVendorString(unsigned vendorId) void FFPhysicalMemoryUpdateVendorString(FFPhysicalMemoryResult* device) { + if (device->vendor.length == 0) return; if (ffStrbufEqualS(&device->vendor, "Unknown")) { ffStrbufClear(&device->vendor); diff --git a/src/detection/physicalmemory/physicalmemory_linux.c b/src/detection/physicalmemory/physicalmemory_linux.c index fc83f92a31..cfc18fe300 100644 --- a/src/detection/physicalmemory/physicalmemory_linux.c +++ b/src/detection/physicalmemory/physicalmemory_linux.c @@ -191,6 +191,7 @@ const char* ffDetectPhysicalMemory(FFlist* result) device->maxSpeed = data->Speed == 0xFFFF ? data->ExtendedSpeed : data->Speed; ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer)); + ffCleanUpSmbiosValue(&device->vendor); FFPhysicalMemoryUpdateVendorString(device); ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber)); diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index ebacb444f0..a591829a2a 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -109,6 +109,15 @@ static bool getShellVersionFish(FFstrbuf* exe, FFstrbuf* version) static bool getShellVersionPwsh(FFstrbuf* exe, FFstrbuf* version) { + // Requires manually setting $POWERSHELL_VERSION + // $env:POWERSHELL_VERSION = $PSVersionTable.PSVersion.ToString(); fastfetch.exe + const char* env = getenv("POWERSHELL_VERSION"); + if (env) + { + ffStrbufSetS(version, env); + return true; + } + #ifdef _WIN32 if(getFileVersion(exe->chars, version)) { @@ -249,6 +258,13 @@ static bool getShellVersionZsh(FFstrbuf* exe, FFstrbuf* exePath, FFstrbuf* versi #ifdef _WIN32 static bool getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version) { + const char* env = getenv("POWERSHELL_VERSION"); + if (env) + { + ffStrbufSetS(version, env); + return true; + } + return ffProcessAppendStdOut(version, (char* const[]) { exe->chars, "-NoLogo", diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 5d63236f83..91160f3d39 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -57,6 +57,9 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid) ffStrbufEqualS(&result->processName, "flashfetch") || ffStrbufContainS(&result->processName, "debug") || ffStrbufContainS(&result->processName, "not-found") || + #ifdef __ANDROID__ + ffStrbufEqualS(&result->processName, "proot") || + #endif ffStrbufEndsWithS(&result->processName, ".sh") ) { @@ -105,6 +108,9 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) ffStrbufEqualS(&result->processName, "login") || ffStrbufEqualS(&result->processName, "clifm") || // https://github.com/leo-arch/clifm/issues/289 ffStrbufEqualS(&result->processName, "chezmoi") || // #762 + #ifdef __ANDROID__ + ffStrbufEqualS(&result->processName, "proot") || + #endif #ifdef __linux__ ffStrbufStartsWithS(&result->processName, "flatpak-") || // #707 #endif diff --git a/src/detection/version/version.c b/src/detection/version/version.c index 1f1deb3485..a979bde5f5 100644 --- a/src/detection/version/version.c +++ b/src/detection/version/version.c @@ -40,6 +40,8 @@ #define FF_SYSNAME "SunOS" #elif defined(__OpenBSD__) #define FF_SYSNAME "OpenBSD" +#elif defined(__NetBSD__) + #define FF_SYSNAME "NetBSD" #else #define FF_SYSNAME "unknown" #endif diff --git a/src/detection/vulkan/vulkan.c b/src/detection/vulkan/vulkan.c index 3f26b747e6..571ab50d41 100644 --- a/src/detection/vulkan/vulkan.c +++ b/src/detection/vulkan/vulkan.c @@ -39,13 +39,20 @@ static void applyDriverName(VkPhysicalDeviceDriverPropertiesKHR* properties, FFs static const char* detectVulkan(FFVulkanResult* result) { - FF_LIBRARY_LOAD(vulkan, "dlopen libvulkan"FF_LIBRARY_EXTENSION " failed", - #ifdef __APPLE__ - "libMoltenVK"FF_LIBRARY_EXTENSION, -1 - #elif defined(_WIN32) - "vulkan-1"FF_LIBRARY_EXTENSION, -1 + FF_LIBRARY_LOAD(vulkan, "dlopen libvulkan" FF_LIBRARY_EXTENSION " failed", + #if __ANDROID__ + #if UINTPTR_MAX == UINT32_MAX + "/system/lib/" + #else + "/system/lib64/" + #endif + "libvulkan" FF_LIBRARY_EXTENSION, -1 + #elif __APPLE__ + "libMoltenVK" FF_LIBRARY_EXTENSION, -1 + #elif _WIN32 + "vulkan-1" FF_LIBRARY_EXTENSION, -1 #else - "libvulkan"FF_LIBRARY_EXTENSION, 2 + "libvulkan" FF_LIBRARY_EXTENSION, 2 #endif ) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkGetInstanceProcAddr) diff --git a/src/logo/ascii/goralixos.txt b/src/logo/ascii/goralixos.txt new file mode 100644 index 0000000000..907afc1f2f --- /dev/null +++ b/src/logo/ascii/goralixos.txt @@ -0,0 +1,11 @@ + .7J~ + ~G@^ .^. + :5&&&&##B?. !B&G7 + 7B##&&B##BBP~ ^P&@&##P~ + $2^YGP5PBPPP5YY55?: .7GGGB#BPPP7. + .?PPPPPPPPPP55YYY5Y!.^YPPPPPP5YYY5J~ + !PPPPPPPPPPPPPP5YYYY5JY5PPPPPPP55YY55?: + ^YPPPPPPPPPPPPPPPPYYYYYYYYY5PPPPPPP5YYY5Y!. + .7PPPPPPPPPPPPPPPPPP5YYYYYYYYY55PPPPP5YYYYY5J~ +!5GPPPPPPPPPPPPPPPPPPPP55555555YY5PPPPPP5555555?: +7777777777777777777777777!!!!!!!!!77777777!!!!!7!: \ No newline at end of file diff --git a/src/logo/ascii/nuros.txt b/src/logo/ascii/nuros.txt new file mode 100644 index 0000000000..577b9c4d57 --- /dev/null +++ b/src/logo/ascii/nuros.txt @@ -0,0 +1,12 @@ + ___╓╓___ + _▄▄▓▓▀▀╜╜╨▀▓▓▓╗_ + ╓▓▓▀² `╙▓▓╖ + ╣▓▀ _▄▓▓▓▓▓▓W_ ╙▓▓ + ╣▓╜ ,▓▓▓▓▓▓▓▓▓▓▓▓_ ²▓▓ +╒▓▌ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ║▓m +╞▓▓ í▓▓▓▓▓▓▓▓▓▓▓▓▓▓h ╞▓╡ +²▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ║▓h + ║▓▄ ╙▓▓▓▓▓▓▓▓▓▓╜ ƒ▓▓ + ╙▓▓_ ⁿ╙╨╝╝╝╜² _╢▓╜ + ╙▓▓╗__ _╗▓▓╜ + `╙╝▓▓▓▓▓▓▓▓╝╙ \ No newline at end of file diff --git a/src/logo/builtin.c b/src/logo/builtin.c index a8271d6f53..b062be144f 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -1912,6 +1912,15 @@ static const FFlogo G[] = { .colorKeys = FF_COLOR_FG_MAGENTA, .colorTitle = FF_COLOR_FG_WHITE, }, + // GoralixOS + { + .names = {"GoralixOS"}, + .lines = FASTFETCH_DATATEXT_LOGO_GORALIXOS, + .colors = { + FF_COLOR_FG_WHITE, + FF_COLOR_FG_LIGHT_BLACK, + }, + }, // GrapheneOS { .names = {"GrapheneOS"}, @@ -3086,6 +3095,15 @@ static const FFlogo N[] = { .colorKeys = FF_COLOR_FG_BLUE, .colorTitle = FF_COLOR_FG_WHITE, }, + // NurOS + { + .names = {"NurOS"}, + .lines = FASTFETCH_DATATEXT_LOGO_NUROS, + .colors = { + FF_COLOR_FG_BLUE, + FF_COLOR_FG_WHITE, + }, + }, // Nurunner { .names = {"Nurunner"}, diff --git a/src/modules/bluetooth/bluetooth.c b/src/modules/bluetooth/bluetooth.c index fe3357d4fd..7563b1d54a 100644 --- a/src/modules/bluetooth/bluetooth.c +++ b/src/modules/bluetooth/bluetooth.c @@ -59,7 +59,7 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de void ffPrintBluetooth(FFBluetoothOptions* options) { FF_LIST_AUTO_DESTROY devices = ffListCreate(sizeof (FFBluetoothResult)); - const char* error = ffDetectBluetooth(&devices); + const char* error = ffDetectBluetooth(options, &devices); if(error) { @@ -155,11 +155,11 @@ void ffGenerateBluetoothJsonConfig(FFBluetoothOptions* options, yyjson_mut_doc* ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent); } -void ffGenerateBluetoothJsonResult(FF_MAYBE_UNUSED FFBluetoothOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +void ffGenerateBluetoothJsonResult(FFBluetoothOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { FF_LIST_AUTO_DESTROY results = ffListCreate(sizeof(FFBluetoothResult)); - const char* error = ffDetectBluetooth(&results); + const char* error = ffDetectBluetooth(options, &results); if (error) { yyjson_mut_obj_add_str(doc, module, "error", error); diff --git a/src/modules/media/media.c b/src/modules/media/media.c index 8bdf13889c..98e6aef45d 100644 --- a/src/modules/media/media.c +++ b/src/modules/media/media.c @@ -99,6 +99,9 @@ void ffPrintMedia(FFMediaOptions* options) FF_FORMAT_ARG(media->artist, "artist"), FF_FORMAT_ARG(media->album, "album"), FF_FORMAT_ARG(media->status, "status"), + FF_FORMAT_ARG(media->player, "player-name"), + FF_FORMAT_ARG(media->playerId, "player-id"), + FF_FORMAT_ARG(media->url, "url"), })); } } @@ -149,10 +152,17 @@ void ffGenerateMediaJsonResult(FF_MAYBE_UNUSED FFMediaOptions* options, yyjson_m } yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); - yyjson_mut_obj_add_strbuf(doc, obj, "song", &media->song); - yyjson_mut_obj_add_strbuf(doc, obj, "artist", &media->artist); - yyjson_mut_obj_add_strbuf(doc, obj, "album", &media->album); - yyjson_mut_obj_add_strbuf(doc, obj, "status", &media->status); + + yyjson_mut_val* song = yyjson_mut_obj_add_obj(doc, obj, "song"); + yyjson_mut_obj_add_strbuf(doc, song, "name", &media->song); + yyjson_mut_obj_add_strbuf(doc, song, "artist", &media->artist); + yyjson_mut_obj_add_strbuf(doc, song, "album", &media->album); + yyjson_mut_obj_add_strbuf(doc, song, "status", &media->status); + + yyjson_mut_val* player = yyjson_mut_obj_add_obj(doc, obj, "player"); + yyjson_mut_obj_add_strbuf(doc, player, "name", &media->player); + yyjson_mut_obj_add_strbuf(doc, player, "id", &media->playerId); + yyjson_mut_obj_add_strbuf(doc, player, "url", &media->url); } static FFModuleBaseInfo ffModuleInfo = { diff --git a/src/modules/player/player.c b/src/modules/player/player.c index c462b3e2a7..56f1601497 100644 --- a/src/modules/player/player.c +++ b/src/modules/player/player.c @@ -118,18 +118,7 @@ void ffGeneratePlayerJsonConfig(FFPlayerOptions* options, yyjson_mut_doc* doc, y void ffGeneratePlayerJsonResult(FF_MAYBE_UNUSED FFMediaOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) { - const FFMediaResult* media = ffDetectMedia(); - - if(media->error.length > 0) - { - yyjson_mut_obj_add_strbuf(doc, module, "error", &media->error); - return; - } - - yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); - yyjson_mut_obj_add_strbuf(doc, obj, "player", &media->player); - yyjson_mut_obj_add_strbuf(doc, obj, "playerId", &media->playerId); - yyjson_mut_obj_add_strbuf(doc, obj, "url", &media->url); + yyjson_mut_obj_add_str(doc, module, "error", "Player module is an alias of Media module"); } static FFModuleBaseInfo ffModuleInfo = { diff --git a/src/util/FFlist.c b/src/util/FFlist.c index e640f507e7..c1af330d59 100644 --- a/src/util/FFlist.c +++ b/src/util/FFlist.c @@ -34,5 +34,5 @@ bool ffListPop(FFlist* list, void* result) memcpy(result, ffListGet(list, list->length - 1), list->elementSize); --list->length; - return result; + return true; }