From 3c4d3b0b2f29dd65c4a01128f56babe552986800 Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthalion6@gmail.com> Date: Sat, 25 Jan 2025 20:32:59 +0100 Subject: [PATCH v3 4/4] Add pg_system_libraries view Introduce a way to report shared objects linked with PostgreSQL. Such information is useful for troubleshooting, and could enhance bug reports. The reporting is done via pg_system_libraries view, which contains a file path to the shared object. It's implemented via standard C library dl_iterate_phdr, which should be portable enough. select * from pg_system_libraries; name ----------------------------- /lib64/libkrb5.so.3 /lib64/libz.so.1 linux-vdso.so.1 /lib64/libxml2.so.2 [...] --- doc/src/sgml/system-views.sgml | 46 +++++++++++++++ src/backend/catalog/system_views.sql | 3 + src/backend/tcop/postgres.c | 1 + src/backend/utils/misc/system_version.c | 76 +++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 6 ++ src/include/utils/system_version.h | 10 ++++ src/test/regress/expected/rules.out | 2 + src/test/regress/expected/sysviews.out | 7 +++ src/test/regress/sql/sysviews.sql | 2 + src/tools/pgindent/typedefs.list | 1 + 10 files changed, 154 insertions(+) diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml index fa27f8cf52c..e86b1f61bbc 100644 --- a/doc/src/sgml/system-views.sgml +++ b/doc/src/sgml/system-views.sgml @@ -231,6 +231,11 @@ system versions + + pg_system_libraries + linked libraries + + @@ -5133,4 +5138,45 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx + + <structname>pg_system_libraries</structname> + + + pg_system_libraries + + + + The view pg_system_libraries provides description + about shared objects PostgreSQL is linked with. + + + + <structname>pg_system_libraries</structname> Columns + + + + + Column Type + + + Description + + + + + + + + name text + + + Shared object file path + + + + + +
+
+ diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 0704567bf8c..46b8711be7e 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1396,3 +1396,6 @@ CREATE VIEW pg_system_versions AS WHEN 1 THEN 'Run Time' END AS "type" FROM pg_get_system_versions(); + +CREATE VIEW pg_system_libraries AS + SELECT * FROM pg_get_system_libraries() as f(name text); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 3d815bfa1d2..602d0a51f2a 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -4271,6 +4271,7 @@ PostgresMain(const char *dbname, const char *username) /* Prepare information for reporting versions and libraries. */ register_system_versions(); + register_libraries(); /* * Also set up handler to log session end; we have to wait till now to be diff --git a/src/backend/utils/misc/system_version.c b/src/backend/utils/misc/system_version.c index d217c7e8cdb..0851da966f2 100644 --- a/src/backend/utils/misc/system_version.c +++ b/src/backend/utils/misc/system_version.c @@ -14,6 +14,10 @@ * a version string directly allows for more flexibility about how and when the * information could be reported. * + * Libraries reporting is implemented similarly via a hash table containing + * only the library file path. This information is populated directly during + * the initialization. + * * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * @@ -32,6 +36,7 @@ #include "utils/system_version.h" static HTAB *versions = NULL; +static HTAB *libraries = NULL; void add_system_version(const char* name, SystemVersionCB cb, VersionType type) @@ -163,3 +168,74 @@ pg_get_system_versions(PG_FUNCTION_ARGS) return (Datum) 0; } + +/* + * Walk through list of shared objects and populate the libraries hash table. + */ +void +register_libraries() +{ + HASHCTL ctl; + + ctl.keysize = NAMEDATALEN; + ctl.entrysize = sizeof(SystemLibrary); + ctl.hcxt = CurrentMemoryContext; + + libraries = hash_create("Libraries table", + MAX_SYSTEM_LIBRARIES, + &ctl, + HASH_ELEM | HASH_STRINGS); + + dl_iterate_phdr(add_library, NULL); +} + +int add_library(struct dl_phdr_info *info, size_t size, void *data) +{ + const char *key; + bool found; + + if (strcmp(info->dlpi_name, "") == 0) + { + /* The first visited object is the main program with the empty name, + * which is not so interesting. */ + return 0; + } + + key = pstrdup(info->dlpi_name); + hash_search(libraries, key, HASH_ENTER, &found); + + return 0; +} + +/* + * pg_get_libraries + * + * List information about shared objects. + */ +Datum +pg_get_system_libraries(PG_FUNCTION_ARGS) +{ +#define PG_GET_SYS_LIBRARIES_COLS 1 + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + HASH_SEQ_STATUS status; + SystemLibrary *hentry; + + /* Build tuplestore to hold the result rows */ + InitMaterializedSRF(fcinfo, 0); + + if (!versions) + return (Datum) 0; + + hash_seq_init(&status, libraries); + while ((hentry = (SystemLibrary *) hash_seq_search(&status)) != NULL) + { + Datum values[PG_GET_SYS_LIBRARIES_COLS] = {0}; + bool nulls[PG_GET_SYS_LIBRARIES_COLS] = {0}; + + values[0] = CStringGetTextDatum(hentry->filepath); + + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); + } + + return (Datum) 0; +} diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 563c2bc1437..3584be8bf77 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12444,4 +12444,10 @@ proargtypes => '', proallargtypes => '{text,text,int8}', proargmodes => '{o,o,o}', proargnames => '{name,version,type}', prosrc => 'pg_get_system_versions' }, +{ oid => '9433', descr => 'describe system libraries', + proname => 'pg_get_system_libraries', procost => '10', prorows => '30', + proretset => 't', provolatile => 'v', prorettype => 'record', + proargtypes => '', proallargtypes => '{text}', + proargmodes => '{o}', proargnames => '{name}', + prosrc => 'pg_get_system_libraries' }, ] diff --git a/src/include/utils/system_version.h b/src/include/utils/system_version.h index 28ebfb30807..4c65e7288b2 100644 --- a/src/include/utils/system_version.h +++ b/src/include/utils/system_version.h @@ -13,9 +13,11 @@ #ifdef __GLIBC__ #include +#include #endif #define MAX_SYSTEM_VERSIONS 100 +#define MAX_SYSTEM_LIBRARIES 100 typedef enum VersionType { @@ -37,8 +39,14 @@ typedef struct SystemVersion SystemVersionCB callback; /* Callback to fetch the version string */ } SystemVersion; +typedef struct SystemLibrary +{ + char filepath[NAMEDATALEN]; +} SystemLibrary; + void add_system_version(const char* name, SystemVersionCB cb, VersionType type); extern void register_core_versions(void); +extern void register_libraries(void); const char* core_get_version(bool *available); const char* core_get_arch(bool *available); @@ -47,4 +55,6 @@ const char* core_get_compiler(bool *available); const char* icu_get_version(bool *available); const char* glibc_get_version(bool *available); +int add_library(struct dl_phdr_info *info, size_t size, void *data); + #endif /* SYSTEM_VERSION_H */ diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 047441f9ebb..3949bebab3f 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2617,6 +2617,8 @@ pg_stats_ext_exprs| SELECT cn.nspname AS schemaname, JOIN LATERAL ( SELECT unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr, unnest(sd.stxdexpr) AS a) stat ON ((stat.expr IS NOT NULL))) WHERE (pg_has_role(c.relowner, 'USAGE'::text) AND ((c.relrowsecurity = false) OR (NOT row_security_active(c.oid)))); +pg_system_libraries| SELECT name + FROM pg_get_system_libraries() f(name text); pg_system_versions| SELECT name, version, CASE type diff --git a/src/test/regress/expected/sysviews.out b/src/test/regress/expected/sysviews.out index e9af9a72df6..af5b0c2ba5c 100644 --- a/src/test/regress/expected/sysviews.out +++ b/src/test/regress/expected/sysviews.out @@ -239,3 +239,10 @@ select count(*) >= 4 as ok FROM pg_system_versions; t (1 row) +-- There is always some number of shared objects +select count(*) > 0 as ok FROM pg_system_libraries; + ok +---- + t +(1 row) + diff --git a/src/test/regress/sql/sysviews.sql b/src/test/regress/sql/sysviews.sql index 4ac0dacbb3e..30000c3f770 100644 --- a/src/test/regress/sql/sysviews.sql +++ b/src/test/regress/sql/sysviews.sql @@ -105,3 +105,5 @@ select * from pg_timezone_abbrevs where abbrev = 'LMT'; -- At least 4 core versions should be present, architecture, ICU, core and -- compiler select count(*) >= 4 as ok FROM pg_system_versions; +-- There is always some number of shared objects +select count(*) > 0 as ok FROM pg_system_libraries; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index ccad37e0e2c..ae12644286a 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2820,6 +2820,7 @@ SysFKRelationship SysScanDesc SyscacheCallbackFunction SysloggerStartupData +SystemLibrary SystemRowsSamplerData SystemSamplerData SystemTimeSamplerData -- 2.45.1