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]>
---
 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

Reply via email to