Hi Josef,
On Wed, Mar 18, 2026 at 7:02 AM Josef Cejka <[email protected]> wrote:
>
> This patch extends current metadata by search by buildid.
> It allows clients to query for all packages (with exact versions)
> and files associated with a specific buildid.
>
> I'd like to use the exact package versions during core dump
> analysis to match them with already known issues/bugs,
> to check that involved packages are reasonable up-to-date
> and to identify other invalid setup, such as mixing packages
> from different Linux distros.
>
> Search by buildid prepares alternative db query, handling
> of results incl. gathering results from federated servers
> remains the same.
> It does not search for source files or source file archives.
>
> Signed-off-by: Josef Cejka <[email protected]>
Thanks for this patch. I've pushed this with one line added to
doc/debuginfod-find.1 mentioning the new buildid key.
Aaron
> ---
> debuginfod/debuginfod-find.c | 2 +-
> debuginfod/debuginfod.cxx | 77 ++++++++++++++++++++-------
> tests/run-debuginfod-find-metadata.sh | 6 +++
> 3 files changed, 66 insertions(+), 19 deletions(-)
>
> diff --git a/debuginfod/debuginfod-find.c b/debuginfod/debuginfod-find.c
> index 39de65c3..2f90a567 100644
> --- a/debuginfod/debuginfod-find.c
> +++ b/debuginfod/debuginfod-find.c
> @@ -54,7 +54,7 @@ static const char args_doc[] = N_("debuginfo BUILDID\n"
> "source PATH /FILENAME\n"
> "section BUILDID SECTION-NAME\n"
> "section PATH SECTION-NAME\n"
> - "metadata (glob|file|KEY)
> (GLOB|FILENAME|VALUE)\n"
> + "metadata (glob|file|buildid|KEY)
> (GLOB|FILENAME|BUILDID|VALUE)\n"
> );
>
> /* Definitions of arguments for argp functions. */
> diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
> index 049570ae..2cf77bcc 100644
> --- a/debuginfod/debuginfod.cxx
> +++ b/debuginfod/debuginfod.cxx
> @@ -3578,25 +3578,9 @@ handle_metrics (off_t* size)
> return r;
> }
>
> -
> -static struct MHD_Response*
> -handle_metadata (MHD_Connection* conn,
> - string key, string value, off_t* size)
> +static sqlite_ps*
> +handle_metadata_glob(sqlite3* thisdb, const string& key, const string& value)
> {
> - MHD_Response* r;
> - // Because this query can take on the order of many seconds, we need
> - // to prevent DoS against the other normal quick queries, so we use
> - // a dedicated database connection.
> - sqlite3 *thisdb = 0;
> - int rc = sqlite3_open_v2 (db_path.c_str(), &thisdb, (SQLITE_OPEN_READONLY
> - |SQLITE_OPEN_URI
> -
> |SQLITE_OPEN_PRIVATECACHE
> -
> |SQLITE_OPEN_NOMUTEX), /* private to us */
> - NULL);
> - if (rc)
> - throw sqlite_exception(rc, "cannot open database for metadata query");
> - defer_dtor<sqlite3*,int> sqlite_db_closer (thisdb, sqlite3_close_v2);
> -
> // Query locally for matching e, d files
> string op;
> if (key == "glob")
> @@ -3670,6 +3654,63 @@ handle_metadata (MHD_Connection* conn,
> pp->bind(2, bname);
> pp->bind(3, dirname);
> pp->bind(4, bname);
> + return pp;
> +}
> +
> +static sqlite_ps*
> +handle_metadata_buildid(sqlite3* thisdb, const string& value)
> +{
> + string sql = string(
> + "select d1.executable_p, d1.debuginfo_p, 0 as
> source_p, "
> + " b1.hex, f1d.name || '/' || f1b.name as file,
> a1.name as archive "
> + "from " BUILDIDS "_r_de d1, " BUILDIDS "_files f1, "
> BUILDIDS "_fileparts f1b, " BUILDIDS "_fileparts f1d, "
> + BUILDIDS "_buildids b1, " BUILDIDS "_files_v a1 "
> + "where f1.id = d1.content and a1.id = d1.file and
> d1.buildid = b1.id "
> + " and b1.hex = ? and f1.dirname = f1d.id and
> f1.basename = f1b.id "
> + "union all \n"
> + "select d2.executable_p, d2.debuginfo_p, 0, "
> + " b2.hex, f2d.name || '/' || f2b.name, NULL "
> + "from " BUILDIDS "_f_de d2, " BUILDIDS "_files f2, "
> BUILDIDS "_fileparts f2b, " BUILDIDS "_fileparts f2d, "
> + BUILDIDS "_buildids b2 "
> + "where f2.id = d2.file and d2.buildid = b2.id "
> + " and b2.hex = ? "
> + " and f2.dirname = f2d.id and f2.basename =
> f2b.id");
> +
> + sqlite_ps *pp = new sqlite_ps (thisdb, "mhd-query-meta-buildid", sql);
> + pp->reset();
> + pp->bind(1, value); // Bind buildid for the first select (_r_de)
> + pp->bind(2, value); // Bind buildid for the second select (_f_de)
> + return pp;
> +}
> +
> +static struct MHD_Response*
> +handle_metadata (MHD_Connection* conn,
> + string key, string value, off_t* size)
> +{
> + MHD_Response* r;
> + // Because this query can take on the order of many seconds, we need
> + // to prevent DoS against the other normal quick queries, so we use
> + // a dedicated database connection.
> + sqlite3 *thisdb = 0;
> + int rc = sqlite3_open_v2 (db_path.c_str(), &thisdb, (SQLITE_OPEN_READONLY
> + |SQLITE_OPEN_URI
> +
> |SQLITE_OPEN_PRIVATECACHE
> +
> |SQLITE_OPEN_NOMUTEX), /* private to us */
> + NULL);
> + if (rc)
> + throw sqlite_exception(rc, "cannot open database for metadata query");
> + defer_dtor<sqlite3*,int> sqlite_db_closer (thisdb, sqlite3_close_v2);
> +
> + sqlite_ps *pp = nullptr;
> +
> + if (key == "glob" || key == "file") {
> + pp = handle_metadata_glob(thisdb, key, value);
> + } else if (key == "buildid") {
> + pp = handle_metadata_buildid(thisdb, value);
> + } else {
> + throw reportable_exception("/metadata webapi error, unsupported key");
> + }
> +
> unique_ptr<sqlite_ps> ps_closer(pp); // release pp if exception or return
> pp->reset_timeout(metadata_maxtime_s);
>
> diff --git a/tests/run-debuginfod-find-metadata.sh
> b/tests/run-debuginfod-find-metadata.sh
> index 99759cff..fd42fb8e 100755
> --- a/tests/run-debuginfod-find-metadata.sh
> +++ b/tests/run-debuginfod-find-metadata.sh
> @@ -75,6 +75,10 @@ RESULTJ=`env LD_LIBRARY_PATH=$ldpath ${VALGRIND_CMD}
> ${abs_builddir}/../debuginf
> echo $RESULTJ
> N_FOUND=`echo $RESULTJ | jq '.results | length'`
> test $N_FOUND -eq 2
> +RESULTJ=`env LD_LIBRARY_PATH=$ldpath ${VALGRIND_CMD}
> ${abs_builddir}/../debuginfod/debuginfod-find metadata buildid
> "f17a29b5a25bd4960531d82aa6b07c8abe84fa66"`
> +echo $RESULTJ
> +N_FOUND=`echo $RESULTJ | jq '.results | length'`
> +test $N_FOUND -eq 2
>
>
> # Query via the webapi as well
> @@ -85,6 +89,8 @@ curl -s -i
> http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | gre
> test `curl -s
> http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq
> '.results[0].buildid == "f17a29b5a25bd4960531d82aa6b07c8abe84fa66"'` = 'true'
> test `curl -s
> http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq
> '.results[0].file == "/usr/bin/hithere"'` = 'true'
> test `curl -s
> http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq
> '.results[0].archive | test(".*hithere.*deb")'` = 'true'
> +test `curl -s
> http://127.0.0.1:$PORT1'/metadata?key=buildid&value=bc1febfd03ca05e030f0d205f7659db29f8a4b30'
> | jq '.results[0].archive | test(".*hello2.*rpm")'` = 'true'
> +test `curl -s
> http://127.0.0.1:$PORT2'/metadata?key=buildid&value=bc1febfd03ca05e030f0d205f7659db29f8a4b30'
> | jq '.results[0].archive | test(".*hello2.*rpm")'` = 'true'
> # Note we query the upstream server too, since the downstream will have an
> incomplete result due to the badurl
> test `curl -s
> http://127.0.0.1:$PORT1'/metadata?key=glob&value=/usr/bin/*hi*' | jq
> '.complete == true'` = 'true'
> test `curl -s
> http://127.0.0.1:$PORT2'/metadata?key=glob&value=/usr/bin/*hi*' | jq
> '.complete == false'` = 'true'
> --
> 2.51.0
>