From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 9CD2E1584AD for ; Fri, 18 Apr 2025 20:47:30 +0000 (UTC) Received: from lists.gentoo.org (bobolink.gentoo.org [140.211.166.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: relay-lists.gentoo.org@gentoo.org) by smtp.gentoo.org (Postfix) with ESMTPSA id 805BF342F9D for ; Fri, 18 Apr 2025 20:47:30 +0000 (UTC) Received: from bobolink.gentoo.org (localhost [127.0.0.1]) by bobolink.gentoo.org (Postfix) with ESMTP id 700B4110105; Fri, 18 Apr 2025 20:47:29 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bobolink.gentoo.org (Postfix) with ESMTPS id 6309F110105 for ; Fri, 18 Apr 2025 20:47:29 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 0CB9A342F94 for ; Fri, 18 Apr 2025 20:47:29 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 5C87E19F6 for ; Fri, 18 Apr 2025 20:47:27 +0000 (UTC) From: "Fabian Groffen" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Fabian Groffen" Message-ID: <1745009107.b7fe0ef1f162c7076c7e04afa706e16d4c6ff8e0.grobian@gentoo> Subject: [gentoo-commits] proj/portage-utils:master commit in: /, man/, man/include/ X-VCS-Repository: proj/portage-utils X-VCS-Files: man/include/qfile.optdesc.yaml man/qfile.1 qfile.c X-VCS-Directories: / man/ man/include/ X-VCS-Committer: grobian X-VCS-Committer-Name: Fabian Groffen X-VCS-Revision: b7fe0ef1f162c7076c7e04afa706e16d4c6ff8e0 X-VCS-Branch: master Date: Fri, 18 Apr 2025 20:47:27 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: b6363b2a-5550-4e42-8254-ea993eb06066 X-Archives-Hash: e8eb804aa1a3e7486e318381f7346266 commit: b7fe0ef1f162c7076c7e04afa706e16d4c6ff8e0 Author: Fabian Groffen gentoo org> AuthorDate: Fri Apr 18 20:45:07 2025 +0000 Commit: Fabian Groffen gentoo org> CommitDate: Fri Apr 18 20:45:07 2025 +0000 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=b7fe0ef1 qfile: add -L option to resolve symlinks in VDB entries This is mostly useful in usr-merge situations where e.g. /bin is a symlink to usr/bin, and app-shells/bash installs into /bin/bash. This records /bin/bash in the VDB, but the actual on-disk location is /usr/bin/bash. Closes: https://github.com/gentoo/portage-utils/pull/22 Closes: https://github.com/gentoo/portage-utils/pull/32 Signed-off-by: Fabian Groffen gentoo.org> man/include/qfile.optdesc.yaml | 6 ++++ man/qfile.1 | 9 +++++- qfile.c | 68 +++++++++++++++++++++++------------------- 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/man/include/qfile.optdesc.yaml b/man/include/qfile.optdesc.yaml index 9e1d24b..249da71 100644 --- a/man/include/qfile.optdesc.yaml +++ b/man/include/qfile.optdesc.yaml @@ -9,3 +9,9 @@ dir: | Only consider basename of argument and also match directories, this option makes qlist ignore any path component given in the arguments if present. +follow: | + Follow symlinks in both input as well as VDB stored entries. This + is useful in situations such as usr-merge where files are stored in + locations which contain a symlink traversal, e.g. /bin/bash. By + default only the input arguments are resolved to make an exact match + with the VDB. Turning this option on may affect performance. diff --git a/man/qfile.1 b/man/qfile.1 index 21aa77d..204f55d 100644 --- a/man/qfile.1 +++ b/man/qfile.1 @@ -1,5 +1,5 @@ .\" generated by mkman.py, please do NOT edit! -.TH qfile "1" "Jan 2024" "Gentoo Foundation" "qfile" +.TH qfile "1" "Apr 2025" "Gentoo Foundation" "qfile" .SH NAME qfile \- list all pkgs owning files .SH SYNOPSIS @@ -38,6 +38,13 @@ renamed to \fB-d\fR. \fB\-F\fR \fI\fR, \fB\-\-format\fR \fI\fR Print matched atom using given format string. .TP +\fB\-L\fR, \fB\-\-follow\fR +Follow symlinks in both input as well as VDB stored entries. This +is useful in situations such as usr-merge where files are stored in +locations which contain a symlink traversal, e.g. /bin/bash. By +default only the input arguments are resolved to make an exact match +with the VDB. Turning this option on may affect performance. +.TP \fB\-S\fR, \fB\-\-slots\fR Display installed packages with slots. .TP diff --git a/qfile.c b/qfile.c index 084ead0..af931d8 100644 --- a/qfile.c +++ b/qfile.c @@ -21,9 +21,10 @@ #include "rmspace.h" #include "tree.h" -#define QFILE_FLAGS "F:doRx:SP" COMMON_FLAGS +#define QFILE_FLAGS "F:LdoRx:SP" COMMON_FLAGS static struct option const qfile_long_opts[] = { {"format", a_argument, NULL, 'F'}, + {"follow", no_argument, NULL, 'L'}, {"slots", no_argument, NULL, 'S'}, {"root-prefix", no_argument, NULL, 'R'}, {"dir", no_argument, NULL, 'd'}, @@ -34,6 +35,7 @@ static struct option const qfile_long_opts[] = { }; static const char * const qfile_opts_help[] = { "Print matched atom using given format string", + "Follow symlinks in CONTENTS entries (slower)", "Display installed packages with slots", "Assume arguments are already prefixed by $ROOT", "Also match directories for single component arguments", @@ -77,6 +79,7 @@ struct qfile_opt_state { char *exclude_slot; depend_atom *exclude_atom; bool basename; + bool followlinks; bool orphans; bool assume_root_prefix; bool skip_plibreg; @@ -172,6 +175,9 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) qfile_str_len_t *real_dir_names = args->realdirnames; short *non_orphans = args->non_orphans; int *results = args->results; + const char *_rpath; + char rpath[_Q_PATH_MAX + 1]; + char fullpath[_Q_PATH_MAX + 1]; char *line; char *savep; const char *base; @@ -238,27 +244,9 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) path_ok = false; - if (dir_names[i].len == dirname_len && - memcmp(e->name, dir_names[i].str, dir_names[i].len) == 0) - { - /* dir_name == dirname(CONTENTS) */ - path_ok = true; - } else if (real_dir_names[i].len == dirname_len && - memcmp(e->name, real_dir_names[i].str, - real_dir_names[i].len) == 0) - { - /* real_dir_name == dirname(CONTENTS) */ - path_ok = true; - } else if (state->real_root_len > 0) { - char rpath[_Q_PATH_MAX + 1]; - char *_rpath; - char fullpath[_Q_PATH_MAX + 1]; - char *real_root = state->real_root; - size_t real_root_len = state->real_root_len; - + if (state->followlinks) { snprintf(fullpath, sizeof(fullpath), "%s%s", - real_root, e->name); - _rpath = rpath + real_root_len; + state->real_root, e->name); if (realpath(fullpath, rpath) == NULL) { if (verbose) { atom = tree_get_atom(pkg_ctx, false); @@ -268,20 +256,37 @@ static int qfile_cb(tree_pkg_ctx *pkg_ctx, void *priv) warn("We'll never know whether \"%s\" was a result " "for your query...", e->name); } - } else if (!qfile_is_prefix(rpath, real_root, real_root_len)) { + break; + } + if (state->real_root_len > 0 && + !qfile_is_prefix(rpath, + state->real_root, state->real_root_len)) + { if (verbose) warn("Real path of \"%s\" is not under ROOT: %s", fullpath, rpath); - } else if (dir_names[i].len > 0 && - real_dir_names[i].len == 0 && - strcmp(_rpath, dir_names[i].str) == 0) { - /* dir_name == realpath(dirname(CONTENTS)) */ - path_ok = true; - } else if (real_dir_names[i].len > 0 && - strcmp(_rpath, real_dir_names[i].str) == 0) { - /* real_dir_name == realpath(dirname(CONTENTS)) */ - path_ok = true; + break; } + _rpath = rpath + state->real_root_len; + dirname_len = strlen(_rpath) - 1 - base_names[i].len; + } else { + _rpath = e->name; + } + + if (real_dir_names[i].len == dirname_len && + memcmp(_rpath, real_dir_names[i].str, + real_dir_names[i].len) == 0) + { + /* real_dir_name == dirname(CONTENTS) */ + path_ok = true; + } + else if ((!state->followlinks || + real_dir_names[i].len == 0) && + dir_names[i].len == dirname_len && + memcmp(_rpath, dir_names[i].str, dir_names[i].len) == 0) + { + /* dir_name == dirname(CONTENTS) */ + path_ok = true; } if (!path_ok && state->basename) @@ -513,6 +518,7 @@ int qfile_main(int argc, char **argv) COMMON_GETOPTS_CASES(qfile) case 'F': state.format = optarg; /* fall through */ case 'S': state.need_full_atom = true; break; + case 'L': state.followlinks = true; break; case 'd': state.basename = true; break; case 'o': state.orphans = true; break; case 'R': state.assume_root_prefix = true; break;