diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 2b74fc955..584849735 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v2 - name: install required packages - run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev + run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev - name: Initialize CodeQL uses: github/codeql-action/init@v1 diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 63f85d43a..745e8b176 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v2 - name: install required packages - run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev + run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev - name: Initialize CodeQL uses: github/codeql-action/init@v1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6295f7dfc..651c94d49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ OPTION(ENABLE_DCONF "Enable dconf" ON) OPTION(ENABLE_DBUS "Enable dbus-1" ON) OPTION(ENABLE_XFCONF "Enable libxfconf-0" ON) OPTION(ENABLE_SQLITE3 "Enable sqlite3" ON) +OPTION(ENABLE_RPM "Enable rpm" ON) OPTION(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON) OPTION(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON) OPTION(ENABLE_ZLIB "Enable zlib" ON) @@ -275,6 +276,15 @@ if(ENABLE_SQLITE3) endif() endif() +if(ENABLE_RPM) + pkg_check_modules(RPM rpm) + if(RPM_FOUND) + target_compile_definitions(libfastfetch PRIVATE FF_HAVE_RPM=1) + else() + message(WARNING "Package rpm not found. Building without support.") + endif() +endif() + if(ENABLE_IMAGEMAGICK7) pkg_check_modules(IMAGEMAGICK7 MagickCore-7.Q16HDRI) if(NOT IMAGEMAGICK7_FOUND) @@ -347,6 +357,7 @@ target_include_directories(libfastfetch PRIVATE ${DBUS_INCLUDE_DIRS} PRIVATE ${XFCONF_INCLUDE_DIRS} PRIVATE ${SQLITE3_INCLUDE_DIRS} + PRIVATE ${RPM_INCLUDE_DIRS} PRIVATE ${IMAGEMAGICK7_INCLUDE_DIRS} PRIVATE ${IMAGEMAGICK6_INCLUDE_DIRS} PRIVATE ${ZLIB_INCLUDE_DIRS} diff --git a/README.md b/README.md index df710d7d1..66b8827c8 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ The following libraries are used if present at runtime: * [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song. * [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font. * [`libsqlite3`](https://www.sqlite.org/index.html): Needed for rpm package count. +* [`librpm`](http://rpm.org/): Slower fallback for rpm package count. Needed on openSUSE. ## Support status All categories not listed here should work without needing a specific implementation. diff --git a/completions/bash b/completions/bash index ac7b58ddd..06bb1f784 100644 --- a/completions/bash +++ b/completions/bash @@ -232,6 +232,7 @@ __fastfetch_completion() "--lib-DBus" "--lib-XFConf" "--lib-sqlite3" + "--lib-rpm" "--lib-imagemagick" "--lib-z" "--lib-chafa" diff --git a/src/common/init.c b/src/common/init.c index b18f477b6..10f9bd5ba 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -200,6 +200,7 @@ static void defaultConfig(FFinstance* instance) ffStrbufInitA(&instance->config.libDBus, 0); ffStrbufInitA(&instance->config.libXFConf, 0); ffStrbufInitA(&instance->config.libSQLite3, 0); + ffStrbufInitA(&instance->config.librpm, 0); ffStrbufInitA(&instance->config.libImageMagick, 0); ffStrbufInitA(&instance->config.libZ, 0); ffStrbufInitA(&instance->config.libChafa, 0); @@ -331,6 +332,9 @@ void ffListFeatures() #ifdef FF_HAVE_SQLITE3 "sqlite3\n" #endif + #ifdef FF_HAVE_RPM + "rpm\n" + #endif "" , stdout); } diff --git a/src/common/settings.c b/src/common/settings.c index 56c4bf4c2..17be91f5c 100644 --- a/src/common/settings.c +++ b/src/common/settings.c @@ -297,7 +297,7 @@ static const SQLiteData* getSQLiteData(const FFinstance* instance) FF_LIBRARY_DATA_LOAD_RETURN } -int ffSettingsGetSQLite3Int(FFinstance* instance, const char* dbPath, const char* query) +int ffSettingsGetSQLite3Int(const FFinstance* instance, const char* dbPath, const char* query) { const SQLiteData* data = getSQLiteData(instance); if(data == NULL) @@ -329,7 +329,7 @@ int ffSettingsGetSQLite3Int(FFinstance* instance, const char* dbPath, const char return result; } #else //FF_HAVE_SQLITE3 -int ffSettingsGetSQLite3Int(FFinstance* instance, const char* dbPath, const char* query) +int ffSettingsGetSQLite3Int(const FFinstance* instance, const char* dbPath, const char* query) { FF_UNUSED(instance, dbPath, query) return 0; diff --git a/src/data/config.txt b/src/data/config.txt index fcce09164..48ae0e8f5 100644 --- a/src/data/config.txt +++ b/src/data/config.txt @@ -234,6 +234,7 @@ #--lib-DBus /usr/lib/libdbus-1.so #--lib-XFConf /usr/lib/libxfconf-0.so #--lib-sqlite3 /usr/lib/libsqlite3.so +#--lib-rpm /usr/lib/librpm.so #--lib-imagemagick /usr/lib/libMagickCore-7.Q16HDRI.so #--lib-z /usr/lib/libz.so #--lib-chafa /usr/lib/libchafa.so diff --git a/src/data/help.txt b/src/data/help.txt index c1b445433..240783588 100644 --- a/src/data/help.txt +++ b/src/data/help.txt @@ -123,6 +123,7 @@ Library options: Set the path of a library to load --lib-DBus --lib-XFConf --lib-sqlite3 + --lib-rpm --lib-imagemagick --lib-z --lib-chafa diff --git a/src/fastfetch.c b/src/fastfetch.c index a1a8f3543..0937bbbb0 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -993,6 +993,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con optionParseString(key, value, &instance->config.libXFConf); else if(strcasecmp(key, "--lib-sqlite") == 0 || strcasecmp(key, "--lib-sqlite3") == 0) optionParseString(key, value, &instance->config.libSQLite3); + else if(strcasecmp(key, "--lib-rpm") == 0) + optionParseString(key, value, &instance->config.librpm); else if(strcasecmp(key, "--lib-imagemagick") == 0) optionParseString(key, value, &instance->config.libImageMagick); else if(strcasecmp(key, "--lib-z") == 0) diff --git a/src/fastfetch.h b/src/fastfetch.h index 923092837..ff6b4e503 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -138,6 +138,7 @@ typedef struct FFconfig FFstrbuf libDBus; FFstrbuf libXFConf; FFstrbuf libSQLite3; + FFstrbuf librpm; FFstrbuf libImageMagick; FFstrbuf libZ; FFstrbuf libChafa; @@ -466,7 +467,7 @@ FFvariant ffSettingsGetGSettings(FFinstance* instance, const char* schemaName, c FFvariant ffSettingsGet(FFinstance* instance, const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type); FFvariant ffSettingsGetXFConf(FFinstance* instance, const char* channelName, const char* propertyName, FFvarianttype type); -int ffSettingsGetSQLite3Int(FFinstance* instance, const char* dbPath, const char* query); +int ffSettingsGetSQLite3Int(const FFinstance* instance, const char* dbPath, const char* query); #ifdef __ANDROID__ bool ffSettingsGetAndroidProperty(const char* propName, FFstrbuf* result); diff --git a/src/modules/packages.c b/src/modules/packages.c index f15e0afd4..1acc51ed6 100644 --- a/src/modules/packages.c +++ b/src/modules/packages.c @@ -6,6 +6,58 @@ #define FF_PACKAGES_MODULE_NAME "Packages" #define FF_PACKAGES_NUM_FORMAT_ARGS 9 +#ifdef FF_HAVE_RPM +#include +#include +#include +#include + +static uint32_t getRpmFromLibrpm(const FFinstance* instance) +{ + FF_LIBRARY_LOAD(rpm, instance->config.librpm, 0, "librpm.so", 12) + FF_LIBRARY_LOAD_SYMBOL(rpm, rpmReadConfigFiles, 0) + FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsCreate, 0) + FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsInitIterator, 0) + FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbGetIteratorCount, 0) + FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbFreeIterator, 0) + FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsFree, 0) + FF_LIBRARY_LOAD_SYMBOL(rpm, rpmlogSetMask, 0) + + // Don't print any error messages + ffrpmlogSetMask(RPMLOG_MASK(RPMLOG_EMERG)); + + if(ffrpmReadConfigFiles(NULL, NULL) != 0) + { + dlclose(rpm); + return 0; + } + + rpmts ts = ffrpmtsCreate(); + if(ts == NULL) + { + dlclose(rpm); + return 0; + } + + rpmdbMatchIterator mi = ffrpmtsInitIterator(ts, RPMDBI_LABEL, NULL, 0); + if(mi == NULL) + { + ffrpmtsFree(ts); + dlclose(rpm); + return 0; + } + + int count = ffrpmdbGetIteratorCount(mi); + + ffrpmdbFreeIterator(mi); + ffrpmtsFree(ts); + dlclose(rpm); + + return count > 0 ? (uint32_t) count : 0; +} + +#endif + static uint32_t getNumElements(const char* dirname, unsigned char type) { DIR* dirp = opendir(dirname); @@ -140,19 +192,33 @@ static uint32_t getNixPackagesUser(const FFinstance* instance) return result; } +static uint32_t getRpmPackageCount(const FFinstance* instance) +{ + // We do our own sql querys instead of using (lib)rpm, because: + // - simply faster + // - we don't need to regulary increase librpm version, which increases rapidly without providing a major version symlink + uint32_t rpm = (uint32_t) ffSettingsGetSQLite3Int(instance, FASTFETCH_TARGET_DIR_ROOT"/var/lib/rpm/rpmdb.sqlite", "SELECT count(blob) FROM Packages"); + if(rpm != 0) + return rpm; + + rpm = (uint32_t) ffSettingsGetSQLite3Int(instance, FASTFETCH_TARGET_DIR_ROOT"/var/cache/dnf/packages.db", "SELECT count(pkg) FROM installed"); + if(rpm != 0) + return rpm; + + // If SQL failed, we can still try with rpm. + // This is needed on openSUSE, which seems to use a proprietary database file + #ifdef FF_HAVE_RPM + return getRpmFromLibrpm(instance); + #endif + + return 0; +} + void ffPrintPackages(FFinstance* instance) { uint32_t pacman = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/var/lib/pacman/local", DT_DIR); uint32_t dpkg = getNumStrings(FASTFETCH_TARGET_DIR_ROOT"/var/lib/dpkg/status", "Status: "); - - // We do our own sql querys instead of using (lib)rpm, because: - // - simply faster - // - we get package count on SUSE platforms - // - we don't need to regulary increase librpm version, which increases rapidly without providing a major version symlink - uint32_t rpm = (uint32_t) ffSettingsGetSQLite3Int(instance, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(blob) FROM Packages"); - if(rpm == 0) - rpm = (uint32_t) ffSettingsGetSQLite3Int(instance, "/var/cache/dnf/packages.db", "SELECT count(pkg) FROM installed"); - + uint32_t rpm = getRpmPackageCount(instance); uint32_t emerge = countFilesIn(FASTFETCH_TARGET_DIR_ROOT"/var/db/pkg", "SIZE"); uint32_t xbps = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/var/db/xbps", DT_REG);