Hi,

Last week I discovered an issue with dpkg-query -S and the usrmerge
with the phpmyadmin docker container; I proposed a fix for the
phpmyadmin container and it turned out a lot of other containers have
the same pattern and were likewise affected by this (see
https://github.com/docker-library/official-images/pull/14960)

The rootcause of the issue is that dpkg-query -S only supports
searching on the paths that listed in the package; it does not
know/care about symlinks; so with the usrmerge /lib and /usr/lib are
now the same; but some libs install to /lib while others install to
/usr/lib. This causes issues with scripts that rely on dpkg-query -S
to find out the package an installed library belongs to. Especially if
you try to find the package of a dependency with ldd and dpkg-query -S
(as ldd will prefer the /lib entry it finds)

I proposed a workaround/fix for this in
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=848622#27 and I now
have a proof of concept implementation of this.

The idea is simple: if you specify you want to match on realpath (for
now by prefixing the path with "realpath:"); it will search for files
matching the basename of the given path and does an extra check to
only return matches where the realpath of the given path will match
the realpath of the partial match it found.
This way you minimize the number of realpath calls that need to be
done and don't need to hardcode any path mappings into dpkg-query.

I don't think this implementation is particularly pretty (especially
the "realpath:" prefix to trigger it); but this was the easiest way
for me to prototype this.
It is meant as a starting point for the conversation if this is
something you'd consider supporting in dpkg-query; I am happy to make
any changes based on your suggestions.

I have attached the patch; but also have a github repo available:
https://github.com/ederuiter/dpkg/tree/fix/bug-848622-realpath

-- 
Best regards,

Eric de Ruiter
From 224e5bf5345d6fdc2bb6d865c44a75ac92ae462e Mon Sep 17 00:00:00 2001
From: Eric de Ruiter <e...@thisisdevelopment.nl>
Date: Sat, 8 Jul 2023 13:06:49 +0200
Subject: [PATCH] [WIP] proof-of-concept implementatin for realpath support in
 dpkg-query -S (fixes #848622 & #858331)

---
 src/query/main.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/src/query/main.c b/src/query/main.c
index 24dccc8c4..c7ce60f4a 100644
--- a/src/query/main.c
+++ b/src/query/main.c
@@ -331,6 +331,43 @@ searchoutput(struct fsys_namenode *namenode)
   return found + (namenode->divert ? 1 : 0);
 }
 
+static int
+searchfile_realpath(const char *file)
+{
+  struct fsys_hash_iter *iter;
+  char *real, *resolved, *namenode_real;
+  struct varbuf path = VARBUF_INIT;
+  struct fsys_namenode *namenode;
+  int found = 0;
+
+  varbuf_reset(&path);
+  varbuf_add_str(&path, "*/");
+  varbuf_add_str(&path, path_basename(file));
+  varbuf_end_str(&path);
+
+  real = realpath(file, NULL);
+  if (real == NULL) {
+    notice(_("unable to get realpath of %s; results might not be complete"), file);
+    return found;
+  }
+  iter = fsys_hash_iter_new();
+  resolved = malloc(PATH_MAX);
+  while ((namenode = fsys_hash_iter_next(iter)) != NULL) {
+    if (fnmatch(path.buf,namenode->name,0)) continue;
+    namenode_real = realpath(namenode->name, resolved);
+    if (namenode_real == NULL) {
+      notice(_("unable to get realpath of %s; results might not be complete"), namenode->name);
+    }
+    if (strcmp(real, namenode_real) != 0) continue;
+    found+= searchoutput(namenode);
+  }
+  fsys_hash_iter_free(iter);
+  free(real);
+  free(resolved);
+  varbuf_destroy(&path);
+  return found;
+}
+
 static int
 searchfiles(const char *const *argv)
 {
@@ -350,6 +387,9 @@ searchfiles(const char *const *argv)
     struct fsys_namenode *namenode;
     int found = 0;
 
+    if (strncmp(thisarg, "realpath:", 9) == 0) {
+      found += searchfile_realpath(&thisarg[9]);
+    } else {
     if (!strchr("*[?/",*thisarg)) {
       varbuf_reset(&vb);
       varbuf_add_char(&vb, '*');
@@ -378,6 +418,7 @@ searchfiles(const char *const *argv)
       }
       fsys_hash_iter_free(iter);
     }
+    }
     if (!found) {
       notice(_("no path found matching pattern %s"), thisarg);
       failures++;
-- 
2.25.1

Reply via email to