diff --git a/CMakeLists.txt b/CMakeLists.txt index 713ec814b..198283de0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,7 @@ cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF) cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR SunOS" OFF) cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF) cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF) +cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX" OFF) cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF) option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF) @@ -480,6 +481,7 @@ if(LINUX) src/detection/wmtheme/wmtheme_linux.c src/detection/camera/camera_linux.c src/util/platform/FFPlatform_unix.c + src/util/linux/elf.c ) elseif(ANDROID) list(APPEND LIBFASTFETCH_SRC @@ -1075,6 +1077,10 @@ ff_lib_enable(DDCUTIL "ddcutil" "Ddcutil" ) +ff_lib_enable(ELF + "libelf" + "libelf" +) ff_lib_enable(DIRECTX_HEADERS "DirectX-Headers" "DirectX-Headers" diff --git a/doc/json_schema.json b/doc/json_schema.json index 4af7a84df..a6e0bca2b 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -730,6 +730,10 @@ "ddcutil": { "description": "Used for brightness detection of external displays (Linux)", "type": "string" + }, + "elf": { + "description": "Used for st terminal font detection and systemd version detection (Linux)", + "type": "string" } } }, diff --git a/src/common/init.c b/src/common/init.c index 96d170291..b4d5c1721 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -248,6 +248,9 @@ void ffListFeatures(void) #if FF_HAVE_DDCUTIL "libddcutil\n" #endif + #if FF_HAVE_ELF + "libelf\n" + #endif #if FF_HAVE_DIRECTX_HEADERS "Directx Headers\n" #endif diff --git a/src/data/help.json b/src/data/help.json index 814409158..43d501209 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -935,6 +935,13 @@ "arg": { "type": "path" } + }, + { + "long": "lib-elf", + "desc": "Used for st terminal font detection and systemd version detection", + "arg": { + "type": "path" + } } ], "Module specific": [ diff --git a/src/options/library.c b/src/options/library.c index c718f6bbc..6ca05b573 100644 --- a/src/options/library.c +++ b/src/options/library.c @@ -66,6 +66,8 @@ const char* ffOptionsParseLibraryJsonConfig(FFOptionsLibrary* options, yyjson_va ffStrbufSetS(&options->libDdcutil, yyjson_get_str(val)); else if (ffStrEqualsIgnCase(key, "drm")) ffStrbufSetS(&options->libdrm, yyjson_get_str(val)); + else if (ffStrEqualsIgnCase(key, "elf")) + ffStrbufSetS(&options->libelf, yyjson_get_str(val)); #endif else @@ -131,6 +133,8 @@ bool ffOptionsParseLibraryCommandLine(FFOptionsLibrary* options, const char* key ffOptionParseString(key, value, &options->libDdcutil); else if(ffStrEqualsIgnCase(subkey, "drm")) ffOptionParseString(key, value, &options->libdrm); + else if(ffStrEqualsIgnCase(subkey, "elf")) + ffOptionParseString(key, value, &options->libelf); #endif else diff --git a/src/options/library.h b/src/options/library.h index 14d38a728..db96af2a5 100644 --- a/src/options/library.h +++ b/src/options/library.h @@ -32,6 +32,7 @@ typedef struct FFOptionsLibrary FFstrbuf libPulse; FFstrbuf libDdcutil; FFstrbuf libdrm; + FFstrbuf libelf; #endif } FFOptionsLibrary; diff --git a/src/util/linux/elf.c b/src/util/linux/elf.c new file mode 100644 index 000000000..4d210cc4b --- /dev/null +++ b/src/util/linux/elf.c @@ -0,0 +1,85 @@ +#include "elf.h" + +#ifdef FF_HAVE_ELF + +#include "common/io/io.h" +#include "common/library.h" +#include "util/stringUtils.h" + +#include +#include + +const char* ffElfExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata) +{ + FF_LIBRARY_LOAD(libelf, &instance.config.library.libelf, "dlopen libelf" FF_LIBRARY_EXTENSION " failed", "libelf" FF_LIBRARY_EXTENSION, 1); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_version) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_begin) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_getshdrstrndx) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_nextscn) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf64_getshdr) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf32_getshdr) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_getdata) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_strptr) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_end) + + if (ffelf_version(EV_CURRENT) == EV_NONE) return "elf_version() failed"; + + FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY, 0); + if (fd < 0) return "open() failed"; + + Elf* elf = ffelf_begin(fd, ELF_C_READ, NULL); + if (elf == NULL) return "elf_begin() failed"; + + size_t shstrndx = 0; + if (ffelf_getshdrstrndx(elf, &shstrndx) < 0) + { + ffelf_end(elf); + return "elf_getshdrstrndx() failed"; + } + + Elf_Scn* scn = NULL; + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + while ((scn = ffelf_nextscn(elf, scn)) != NULL) + { + Elf64_Shdr* shdr64 = ffelf64_getshdr(scn); + Elf32_Shdr* shdr32 = NULL; + if (shdr64 == NULL) + { + shdr32 = ffelf32_getshdr(scn); + if (shdr32 == NULL) continue; + } + + const char* name = ffelf_strptr(elf, shstrndx, shdr64 ? shdr64->sh_name : shdr32->sh_name); + if (name == NULL || !ffStrEquals(name, ".rodata")) continue; + + Elf_Data* data = ffelf_getdata(scn, NULL); + if (data == NULL) continue; + + for (size_t off = 0; off < data->d_size; ++off) + { + const char* p = (const char*) data->d_buf + off; + if (*p == '\0') continue; + uint32_t len = (uint32_t) strlen(p); + if (*p >= ' ' && *p <= '~') // Ignore control characters + { + if (!cb(p, len, userdata)) break; + } + off += len; + } + + break; + } + + ffelf_end(elf); + return NULL; +} + +#else + +const char* ffElfExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata) +{ + FF_UNUSED(elfFile, cb, userdata); + return "Fastfetch was built without libelf support"; +} + +#endif diff --git a/src/util/linux/elf.h b/src/util/linux/elf.h new file mode 100644 index 000000000..4cfdaeb45 --- /dev/null +++ b/src/util/linux/elf.h @@ -0,0 +1,5 @@ +#pragma once + +#include "fastfetch.h" + +const char* ffElfExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata);