Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

abi: new module #1231

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions presets/all.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"board",
"chassis",
"kernel",
"abi",
"initsystem",
"uptime",
"loadavg",
Expand Down
1 change: 1 addition & 0 deletions presets/ci.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"board",
"chassis",
"kernel",
"abi",
"initsystem",
"uptime",
"loadavg",
Expand Down
1 change: 1 addition & 0 deletions src/common/modules.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "fastfetch.h"

static FFModuleBaseInfo* A[] = {
(void*) &instance.config.modules.abi,
NULL,
};

Expand Down
35 changes: 35 additions & 0 deletions src/detection/abi/abi.h
Original file line number Diff line number Diff line change
@@ -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,
};
}
108 changes: 108 additions & 0 deletions src/detection/abi/abi_linux.c
Original file line number Diff line number Diff line change
@@ -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 <errno.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <unistd.h>

#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
8 changes: 8 additions & 0 deletions src/detection/abi/abi_nosupport.c
Original file line number Diff line number Diff line change
@@ -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";
}
154 changes: 154 additions & 0 deletions src/modules/abi/abi.c
Original file line number Diff line number Diff line change
@@ -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);
}
9 changes: 9 additions & 0 deletions src/modules/abi/abi.h
Original file line number Diff line number Diff line change
@@ -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);
Loading