From 9bb5fa05da6d6b7dc935180d820245c1522f9ba1 Mon Sep 17 00:00:00 2001 From: WANG Xuerui Date: Fri, 30 Aug 2024 21:07:50 +0800 Subject: [PATCH] abi: new module Support probing LoongArch ABI features at first. --- CMakeLists.txt | 7 ++ presets/all.jsonc | 1 + presets/ci.jsonc | 1 + src/common/modules.c | 1 + src/detection/abi/abi.h | 35 +++++++ src/detection/abi/abi_linux.c | 108 +++++++++++++++++++++ src/detection/abi/abi_nosupport.c | 8 ++ src/modules/abi/abi.c | 154 ++++++++++++++++++++++++++++++ src/modules/abi/abi.h | 9 ++ src/modules/abi/option.h | 11 +++ src/modules/modules.h | 1 + src/modules/options.h | 1 + src/options/modules.c | 2 + src/options/modules.h | 1 + 14 files changed, 340 insertions(+) create mode 100644 src/detection/abi/abi.h create mode 100644 src/detection/abi/abi_linux.c create mode 100644 src/detection/abi/abi_nosupport.c create mode 100644 src/modules/abi/abi.c create mode 100644 src/modules/abi/abi.h create mode 100644 src/modules/abi/option.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 52a0e17e66..241275c3dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,6 +324,7 @@ set(LIBFASTFETCH_SRC src/logo/image/im7.c src/logo/image/image.c src/logo/logo.c + src/modules/abi/abi.c src/modules/battery/battery.c src/modules/bios/bios.c src/modules/bluetooth/bluetooth.c @@ -414,6 +415,7 @@ if(LINUX) src/common/netif/netif_linux.c src/common/networking_linux.c src/common/processing_linux.c + src/detection/abi/abi_linux.c src/detection/battery/battery_linux.c src/detection/bios/bios_linux.c src/detection/board/board_linux.c @@ -492,6 +494,7 @@ elseif(ANDROID) src/common/netif/netif_linux.c src/common/networking_linux.c src/common/processing_linux.c + src/detection/abi/abi_linux.c src/detection/battery/battery_android.c src/detection/bios/bios_android.c src/detection/bluetooth/bluetooth_nosupport.c @@ -557,6 +560,7 @@ elseif(FreeBSD) src/common/networking_linux.c src/common/processing_linux.c src/common/sysctl.c + src/detection/abi/abi_nosupport.c src/detection/battery/battery_bsd.c src/detection/bios/bios_bsd.c src/detection/bluetooth/bluetooth_linux.c @@ -636,6 +640,7 @@ elseif(APPLE) src/common/networking_linux.c src/common/processing_linux.c src/common/sysctl.c + src/detection/abi/abi_nosupport.c src/detection/battery/battery_apple.c src/detection/bios/bios_apple.c src/detection/bluetooth/bluetooth_apple.m @@ -702,6 +707,7 @@ elseif(WIN32) src/common/netif/netif_windows.c src/common/networking_windows.c src/common/processing_windows.c + src/detection/abi/abi_nosupport.c src/detection/battery/battery_windows.c src/detection/bios/bios_windows.c src/detection/bluetooth/bluetooth_windows.c @@ -771,6 +777,7 @@ elseif(SunOS) src/common/netif/netif_bsd.c src/common/networking_linux.c src/common/processing_linux.c + src/detection/abi/abi_nosupport.c src/detection/battery/battery_nosupport.c src/detection/bios/bios_windows.c src/detection/board/board_windows.c diff --git a/presets/all.jsonc b/presets/all.jsonc index efcec55dd5..bc692cc20d 100644 --- a/presets/all.jsonc +++ b/presets/all.jsonc @@ -15,6 +15,7 @@ "board", "chassis", "kernel", + "abi", "initsystem", "uptime", "loadavg", diff --git a/presets/ci.jsonc b/presets/ci.jsonc index 565e28b6ea..d4b338c103 100644 --- a/presets/ci.jsonc +++ b/presets/ci.jsonc @@ -17,6 +17,7 @@ "board", "chassis", "kernel", + "abi", "initsystem", "uptime", "loadavg", diff --git a/src/common/modules.c b/src/common/modules.c index 28f270165e..6ac4ca0c04 100644 --- a/src/common/modules.c +++ b/src/common/modules.c @@ -1,6 +1,7 @@ #include "fastfetch.h" static FFModuleBaseInfo* A[] = { + (void*) &instance.config.modules.abi, NULL, }; diff --git a/src/detection/abi/abi.h b/src/detection/abi/abi.h new file mode 100644 index 0000000000..f5e3c3e14a --- /dev/null +++ b/src/detection/abi/abi.h @@ -0,0 +1,35 @@ +#pragma once + +#include "fastfetch.h" + +typedef struct FFABIFeature +{ + const char* name; + bool supported; +} FFABIFeature; + +typedef struct FFABICompat +{ + const char* name; + const char* desc; +} FFABICompat; + +typedef struct FFABIResult +{ + FFlist compats; // List of FFABICompat + FFlist features; // List of FFABIFeature +} FFABIResult; + +const char* ffDetectABI(const FFABIOptions* options, FFABIResult* result); + +static inline void ffABIAddFeature( + FFABIResult* result, + const char* name, + bool supported) +{ + FFABIFeature* item = (FFABIFeature*) ffListAdd(&result->features); + *item = (FFABIFeature) { + .name = name, + .supported = supported, + }; +} diff --git a/src/detection/abi/abi_linux.c b/src/detection/abi/abi_linux.c new file mode 100644 index 0000000000..474f458d23 --- /dev/null +++ b/src/detection/abi/abi_linux.c @@ -0,0 +1,108 @@ +#include "abi.h" + +#ifdef __loongarch__ + +// Detect the running kernel's ABI flavor and compatibility. +// +// Reference: https://areweloongyet.com/docs/world-compat-details/ + +#include +#include +#include +#include +#include + +#ifndef __NR_fstat +#define __NR_fstat 80 +#endif + +#ifndef __NR_getrlimit +#define __NR_getrlimit 163 +#endif + +#define NSIG_NEW_WORLD 65 +#define NSIG_BYTES_NEW_WORLD 8 +#define NSIG_BYTES_OLD_WORLD 16 + +const char* ffDetectABI( + FF_MAYBE_UNUSED const FFABIOptions* options, + FFABIResult* result) +{ + // record the ABI used at build-time + bool builtOnNewWorld = NSIG == NSIG_NEW_WORLD; + + FFABICompat* buildTimeItem = (FFABICompat*) ffListAdd(&result->compats); + *buildTimeItem = (FFABICompat) { + .name = FASTFETCH_PROJECT_NAME " program", + .desc = builtOnNewWorld ? "New world (ABI2.0)" : "Old world (ABI1.0)", + }; + + // probe the running kernel + bool hasNewWorldSignals = syscall(__NR_rt_sigaction, SIGUSR1, NULL, NULL, NSIG_BYTES_NEW_WORLD) == 0; + bool hasOldWorldSignals = syscall(__NR_rt_sigaction, SIGUSR1, NULL, NULL, NSIG_BYTES_OLD_WORLD) == 0; + + bool hasFstatSyscalls = true; + if (syscall(__NR_fstat, 0, NULL) == -1) + { + hasFstatSyscalls = errno != ENOSYS; + } + + bool hasOldRlimitSyscalls = true; + if (syscall(__NR_getrlimit, RLIMIT_NOFILE, NULL) == -1) + { + hasOldRlimitSyscalls = errno != ENOSYS; + } + + ffABIAddFeature(result, "new-world signals", hasNewWorldSignals); + ffABIAddFeature(result, "old-world signals", hasOldWorldSignals); + ffABIAddFeature(result, "fstat & newfstatat", hasFstatSyscalls); + ffABIAddFeature(result, "getrlimit & setrlimit", hasOldRlimitSyscalls); + + // now classify the system + bool fullyOldWorld = hasOldWorldSignals && hasFstatSyscalls && hasOldRlimitSyscalls; + bool fullyNewWorld = hasNewWorldSignals; + bool isNewWorldPast611 = fullyNewWorld && hasFstatSyscalls; + + FFABICompat* newWorldItem = (FFABICompat*) ffListAdd(&result->compats); + *newWorldItem = (FFABICompat) { + .name = "LoongArch new world", + .desc = NULL, + }; + + FFABICompat* oldWorldItem = (FFABICompat*) ffListAdd(&result->compats); + *oldWorldItem = (FFABICompat) { + .name = "LoongArch old world", + .desc = NULL, + }; + + if (fullyNewWorld) + { + if (isNewWorldPast611) + newWorldItem->desc = "Supported (Linux 6.11)"; + else + newWorldItem->desc = "Supported (Linux 5.19)"; + + if (fullyOldWorld) + oldWorldItem->desc = "Supported (compatible)"; + else + oldWorldItem->desc = "Unsupported"; + } + else + { + newWorldItem->desc = "Unsupported"; + oldWorldItem->desc = "Supported (native)"; + } + + return NULL; +} + +#else + +const char* ffDetectABI( + FF_MAYBE_UNUSED const FFABIOptions* options, + FF_MAYBE_UNUSED FFABIResult* result) +{ + return "Not supported on this architecture"; +} + +#endif diff --git a/src/detection/abi/abi_nosupport.c b/src/detection/abi/abi_nosupport.c new file mode 100644 index 0000000000..de6a1acfae --- /dev/null +++ b/src/detection/abi/abi_nosupport.c @@ -0,0 +1,8 @@ +#include "abi.h" + +const char* ffDetectABI( + FF_MAYBE_UNUSED const FFABIOptions* options, + FF_MAYBE_UNUSED FFABIResult* result) +{ + return "Not supported on this platform"; +} diff --git a/src/modules/abi/abi.c b/src/modules/abi/abi.c new file mode 100644 index 0000000000..2fe50890bb --- /dev/null +++ b/src/modules/abi/abi.c @@ -0,0 +1,154 @@ +#include "common/printing.h" +#include "common/jsonconfig.h" +#include "common/parsing.h" +#include "common/temps.h" +#include "detection/abi/abi.h" +#include "modules/abi/abi.h" +#include "util/stringUtils.h" + +#define FF_ABI_NUM_FORMAT_ARGS 1 + +void ffPrintABI(FFABIOptions* options) +{ + FFABIResult result; + ffListInit(&result.compats, sizeof(FFABICompat)); + ffListInit(&result.features, sizeof(FFABIFeature)); + + const char* error = ffDetectABI(options, &result); + if (error) + { + ffPrintError(FF_ABI_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error); + goto out; + } + + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + + FF_LIST_FOR_EACH(FFABICompat, compat, result.compats) + { + if (options->moduleArgs.key.length == 0) + { + ffStrbufSetF(&buffer, FF_ABI_MODULE_NAME " (%s)", compat->name); + } + else + { + ffStrbufClear(&buffer); + FF_PARSE_FORMAT_STRING_CHECKED(&buffer, &options->moduleArgs.key, 2, ((FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_STRING, compat->name, "name"}, + {FF_FORMAT_ARG_TYPE_STRBUF, &options->moduleArgs.keyIcon, "icon"}, + })); + } + + if (options->moduleArgs.outputFormat.length == 0) + { + ffPrintLogoAndKey(buffer.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY); + printf("%s\n", compat->desc); + } + else + { + FF_PRINT_FORMAT_CHECKED(FF_ABI_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_ABI_NUM_FORMAT_ARGS, ((FFformatarg[]) { + {FF_FORMAT_ARG_TYPE_STRING, compat->desc, "desc"}, + })); + } + } + +out: + ffListDestroy(&result.compats); + ffListDestroy(&result.features); +} + +bool ffParseABICommandOptions(FFABIOptions* options, const char* key, const char* value) +{ + const char* subKey = ffOptionTestPrefix(key, FF_ABI_MODULE_NAME); + if (!subKey) return false; + return ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs); +} + +void ffParseABIJsonObject(FFABIOptions* options, yyjson_val* module) +{ + yyjson_val *key_, *val; + size_t idx, max; + yyjson_obj_foreach(module, idx, max, key_, val) + { + const char* key = yyjson_get_str(key_); + if(ffStrEqualsIgnCase(key, "type")) + continue; + + if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) + continue; + + ffPrintError(FF_ABI_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", key); + } +} + +void ffGenerateABIJsonConfig(FFABIOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + __attribute__((__cleanup__(ffDestroyABIOptions))) FFABIOptions defaultOptions; + ffInitABIOptions(&defaultOptions); + + ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); +} + +void ffGenerateABIJsonResult(FFABIOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + FFABIResult result; + ffListInit(&result.compats, sizeof(FFABICompat)); + ffListInit(&result.features, sizeof(FFABIFeature)); + + const char* error = ffDetectABI(options, &result); + + if (error) + { + yyjson_mut_obj_add_str(doc, module, "error", error); + goto out; + } + + yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); + + yyjson_mut_val* compats = yyjson_mut_obj_add_arr(doc, obj, "compats"); + FF_LIST_FOR_EACH(FFABICompat, compat, result.compats) + { + yyjson_mut_val* compatObj = yyjson_mut_arr_add_obj(doc, compats); + yyjson_mut_obj_add_str(doc, compatObj, "name", compat->name); + yyjson_mut_obj_add_str(doc, compatObj, "desc", compat->desc); + } + + yyjson_mut_val* features = yyjson_mut_obj_add_arr(doc, obj, "features"); + FF_LIST_FOR_EACH(FFABIFeature, feat, result.features) + { + yyjson_mut_val* featObj = yyjson_mut_arr_add_obj(doc, features); + yyjson_mut_obj_add_str(doc, featObj, "name", feat->name); + yyjson_mut_obj_add_bool(doc, featObj, "supported", feat->supported); + } + +out: + ffListDestroy(&result.compats); + ffListDestroy(&result.features); +} + +void ffPrintABIHelpFormat(void) +{ + FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_ABI_MODULE_NAME, "{1}", FF_ABI_NUM_FORMAT_ARGS, ((const char* []) { + "ABI Description - desc", + })); +} + +void ffInitABIOptions(FFABIOptions* options) +{ + ffOptionInitModuleBaseInfo( + &options->moduleInfo, + FF_ABI_MODULE_NAME, + "Print kernel ABI features and compatibility", + ffParseABICommandOptions, + ffParseABIJsonObject, + ffPrintABI, + ffGenerateABIJsonResult, + ffPrintABIHelpFormat, + ffGenerateABIJsonConfig + ); + ffOptionInitModuleArg(&options->moduleArgs, ""); +} + +void ffDestroyABIOptions(FFABIOptions* options) +{ + ffOptionDestroyModuleArg(&options->moduleArgs); +} diff --git a/src/modules/abi/abi.h b/src/modules/abi/abi.h new file mode 100644 index 0000000000..822b1af4c9 --- /dev/null +++ b/src/modules/abi/abi.h @@ -0,0 +1,9 @@ +#pragma once + +#include "fastfetch.h" + +#define FF_ABI_MODULE_NAME "ABI" + +void ffPrintABI(FFABIOptions* options); +void ffInitABIOptions(FFABIOptions* options); +void ffDestroyABIOptions(FFABIOptions* options); diff --git a/src/modules/abi/option.h b/src/modules/abi/option.h new file mode 100644 index 0000000000..bd573def7f --- /dev/null +++ b/src/modules/abi/option.h @@ -0,0 +1,11 @@ +#pragma once + +// This file will be included in "fastfetch.h", do NOT put unnecessary things here + +#include "common/option.h" + +typedef struct FFABIOptions +{ + FFModuleBaseInfo moduleInfo; + FFModuleArgs moduleArgs; +} FFABIOptions; diff --git a/src/modules/modules.h b/src/modules/modules.h index d6e6f5c14c..3ba809359a 100644 --- a/src/modules/modules.h +++ b/src/modules/modules.h @@ -2,6 +2,7 @@ // For "fastfetch.c" and "flashfetch.c" +#include "modules/abi/abi.h" #include "modules/battery/battery.h" #include "modules/bios/bios.h" #include "modules/bluetooth/bluetooth.h" diff --git a/src/modules/options.h b/src/modules/options.h index 74ad4c0b49..b5a1d19688 100644 --- a/src/modules/options.h +++ b/src/modules/options.h @@ -2,6 +2,7 @@ // For "fastfetch.h" +#include "modules/abi/option.h" #include "modules/battery/option.h" #include "modules/bios/option.h" #include "modules/bluetooth/option.h" diff --git a/src/options/modules.c b/src/options/modules.c index 22c6fcf5b1..858917817d 100644 --- a/src/options/modules.c +++ b/src/options/modules.c @@ -3,6 +3,7 @@ void ffOptionsInitModules(FFOptionsModules* options) { + ffInitABIOptions(&options->abi); ffInitBatteryOptions(&options->battery); ffInitBiosOptions(&options->bios); ffInitBluetoothOptions(&options->bluetooth); @@ -76,6 +77,7 @@ void ffOptionsInitModules(FFOptionsModules* options) void ffOptionsDestroyModules(FFOptionsModules* options) { + ffDestroyABIOptions(&options->abi); ffDestroyBatteryOptions(&options->battery); ffDestroyBiosOptions(&options->bios); ffDestroyBluetoothOptions(&options->bluetooth); diff --git a/src/options/modules.h b/src/options/modules.h index 27ec92dc4d..397a32b458 100644 --- a/src/options/modules.h +++ b/src/options/modules.h @@ -4,6 +4,7 @@ typedef struct FFOptionsModules { + FFABIOptions abi; FFBatteryOptions battery; FFBiosOptions bios; FFBluetoothOptions bluetooth;