aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Groffen <grobian@gentoo.org>2018-04-15 14:03:14 +0200
committerFabian Groffen <grobian@gentoo.org>2018-04-15 14:03:14 +0200
commit23c09a20dfcc044343b16bfe4b5873f663a46286 (patch)
treecaf079cf0032865376b17208b342fc4fe0acf2dc
parentqlop: accept "today" and "yesterday" for parse_date (diff)
downloadportage-utils-23c09a20dfcc044343b16bfe4b5873f663a46286.tar.gz
portage-utils-23c09a20dfcc044343b16bfe4b5873f663a46286.tar.bz2
portage-utils-23c09a20dfcc044343b16bfe4b5873f663a46286.zip
qfile: fix matching of files
A bit overenthusiastic check for files in the current directory caused weird directory prefixes to be ignored. Bug: https://bugs.gentoo.org/652720
-rw-r--r--man/include/qfile-01-owners.include9
-rw-r--r--qfile.c94
2 files changed, 60 insertions, 43 deletions
diff --git a/man/include/qfile-01-owners.include b/man/include/qfile-01-owners.include
index c9ce378..a4bdc76 100644
--- a/man/include/qfile-01-owners.include
+++ b/man/include/qfile-01-owners.include
@@ -1,13 +1,14 @@
-.SH "FINDING FILES OWNERS"
+.SH "FINDING FILE OWNERS"
.PP
This is the default behavior of \fBqfile\fP. It will list the packages which
own the files (or directories, or symlinks, or anything else Portage can
-install) you are querying. Query items may be file paths or simple file names.
+install) you are querying. Query items may be file paths or simple file
+names when the \fB\-b\fP option is used.
By default, output includes packages names and the complete paths to
the matching files. If using \fB\-\-exact\fP, versions of the packages will
also be shown. At the contrary, when using \fB\-\-quiet\fP, only package
names are listed, without files paths. Finally, \fB\-\-verbose\fP is similar
-to \fB\-\-exact\fP, but may adds a few warnings. The return status of
+to \fB\-\-exact\fP, but may add a few warnings. The return status of
\fBqfile\fP will be \fI0\fP as soon as an owning package has been found for
one of the query items.
.PP
@@ -19,7 +20,7 @@ Find names of package(s) owning "/bin/bash":
.PP
Find package(s) owning any file named "bash", and show paths of this files:
.nf\fI
- $ qfile bash
+ $ qfile -b bash
app-shells/bash (/bin/bash)
app-shells/bash (/etc/bash)
.fi
diff --git a/qfile.c b/qfile.c
index 08ba642..285277b 100644
--- a/qfile.c
+++ b/qfile.c
@@ -118,66 +118,73 @@ static int qfile_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv)
goto qlist_done;
while (getline(&state->buf, &state->buflen, fp) != -1) {
+ size_t dirname_len;
contents_entry *e;
+
e = contents_parse_line(state->buf);
if (!e)
continue;
- /* assume sane basename() -- doesnt modify argument */
- if ((base = basename(e->name)) == NULL)
+ /* basename(3) possibly modifies e->name (if it has trailing
+ * slashes) but this is not likely since it comes from VDB which
+ * has normalised everything, so effectively e->name isn't
+ * touched, however, it /can/ return a pointer to a private
+ * allocation */
+ base = basename(e->name);
+ if (base < e->name || base > (e->name + strlen(e->name)))
continue;
+ /* basename(/usr) = usr, dirname(/usr) = /
+ * basename(/usr/bin) = bin, dirname(/usr/bin) = /usr */
+ if ((dirname_len = (base - e->name - 1)) == 0)
+ dirname_len = 1;
+
for (i = 0; i < args->length; i++) {
if (base_names[i] == NULL)
continue;
if (non_orphans && non_orphans[i])
continue;
- /* For optimization of qfile(), we also give it an array of the first char
- * of each basename. This way we avoid numerous strcmp() calls.
- */
- if (base[0] != base_names[i][0] || strcmp(base, base_names[i]))
+ /* For optimization of qfile(), we also give it an array of
+ * the first char of each basename. This way we avoid
+ * numerous strcmp() calls. */
+ if (base[0] != base_names[i][0] || strcmp(base, base_names[i]) != 0)
continue;
path_ok = false;
- /* check the full filepath ... */
- size_t dirname_len = (base - e->name - 1);
- /* basename(/usr) = usr, dirname(/usr) = /
- * basename(/usr/bin) = bin, dirname(/usr/bin) = /usr
- */
- if (dirname_len == 0)
- dirname_len = 1;
-
if (dir_names[i] &&
strncmp(e->name, dir_names[i], dirname_len) == 0 &&
- dir_names[i][dirname_len] == '\0') {
+ dir_names[i][dirname_len] == '\0')
+ {
/* dir_name == dirname(CONTENTS) */
path_ok = true;
-
} else if (real_dir_names[i] &&
- strncmp(e->name, real_dir_names[i], dirname_len) == 0 &&
- real_dir_names[i][dirname_len] == '\0') {
+ strncmp(e->name, real_dir_names[i], dirname_len) == 0 &&
+ real_dir_names[i][dirname_len] == '\0')
+ {
/* real_dir_name == dirname(CONTENTS) */
path_ok = true;
-
} else if (real_root[0]) {
- char rpath[_Q_PATH_MAX + 1], *_rpath;
- char *fullpath;
+ char rpath[_Q_PATH_MAX + 1];
+ char *_rpath;
+ char fullpath[_Q_PATH_MAX + 1];
size_t real_root_len = state->real_root_len;
- xasprintf(&fullpath, "%s%s", real_root, e->name);
- fullpath[real_root_len + dirname_len] = '\0';
+ snprintf(fullpath, sizeof(fullpath), "%s%s",
+ real_root, e->name);
_rpath = rpath + real_root_len;
if (realpath(fullpath, rpath) == NULL) {
if (verbose) {
- warnp("Could not read real path of \"%s\" (from %s)", fullpath, pkg);
- warn("We'll never know whether \"%s\" was a result for your query...",
- e->name);
+ warnp("Could not read real path of \"%s\" (from %s)",
+ fullpath, pkg);
+ 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)) {
if (verbose)
- warn("Real path of \"%s\" is not under ROOT: %s", fullpath, rpath);
+ warn("Real path of \"%s\" is not under ROOT: %s",
+ fullpath, rpath);
} else if (dir_names[i] &&
strcmp(_rpath, dir_names[i]) == 0) {
/* dir_name == realpath(dirname(CONTENTS)) */
@@ -187,11 +194,12 @@ static int qfile_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv)
/* real_dir_name == realpath(dirname(CONTENTS)) */
path_ok = true;
}
- free(fullpath);
} else if (state->basename) {
path_ok = true;
- } else if (state->pwd) {
- if (!strncmp(e->name, state->pwd, dirname_len))
+ } else if (state->pwd && dir_names[i] == NULL) {
+ /* try to match file in current directory */
+ if (strncmp(e->name, state->pwd, dirname_len) == 0 &&
+ state->pwd[dirname_len] == '\0')
path_ok = true;
}
if (!path_ok)
@@ -222,7 +230,6 @@ static int qfile_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv)
puts("");
else
printf(" (%s%s)\n", state->root ? : "", e->name);
-
} else {
non_orphans[i] = 1;
}
@@ -285,7 +292,8 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st
for (i = 0; i < argc; ++i) {
/* Record basename, but if it is ".", ".." or "/" */
- strncpy(abspath, argv[i], _Q_PATH_MAX); /* strncopy so that "argv" can be "const" */
+ /* strncopy so that "argv" can be "const" */
+ strncpy(abspath, argv[i], _Q_PATH_MAX);
strncpy(tmppath, basename(abspath), _Q_PATH_MAX);
if ((strlen(tmppath) > 2) ||
(strncmp(tmppath, "..", strlen(tmppath))
@@ -299,7 +307,8 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st
continue;
}
- /* Make sure we have an absolute path available (with "realpath(ROOT)" prefix) */
+ /* Make sure we have an absolute path available (with
+ * "realpath(ROOT)" prefix) */
if (argv[i][0] == '/') {
if (state->assume_root_prefix)
strncpy(abspath, argv[i], _Q_PATH_MAX);
@@ -309,9 +318,11 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st
if (state->assume_root_prefix)
snprintf(abspath, _Q_PATH_MAX, "%s/%s", pwd, argv[i]);
else
- snprintf(abspath, _Q_PATH_MAX, "%s%s/%s", real_root, pwd, argv[i]);
+ snprintf(abspath, _Q_PATH_MAX, "%s%s/%s",
+ real_root, pwd, argv[i]);
} else {
- warn("$PWD was not found in environment, or is not an absolute path");
+ warn("$PWD was not found in environment, "
+ "or is not an absolute path");
goto skip_query_item;
}
@@ -328,12 +339,14 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st
if (realpath(abspath, tmppath) == NULL) {
if (verbose) {
warnp("Could not read real path of \"%s\"", abspath);
- warn("Results for query item \"%s\" may be inaccurate.", argv[i]);
+ warn("Results for query item \"%s\" may be inaccurate.",
+ argv[i]);
}
continue;
}
if (!qfile_is_prefix(tmppath, real_root, real_root_len)) {
- warn("Real path of \"%s\" is not under ROOT: %s", abspath, tmppath);
+ warn("Real path of \"%s\" is not under ROOT: %s",
+ abspath, tmppath);
goto skip_query_item;
}
if (tmppath[real_root_len] == '\0')
@@ -350,7 +363,8 @@ prepare_qfile_args(const int argc, const char **argv, struct qfile_opt_state *st
goto skip_query_item;
}
if (!qfile_is_prefix(tmppath, real_root, real_root_len)) {
- warn("Real path of \"%s\" is not under ROOT: %s", abspath, tmppath);
+ warn("Real path of \"%s\" is not under ROOT: %s",
+ abspath, tmppath);
goto skip_query_item;
}
strncpy(abspath, tmppath, _Q_PATH_MAX);
@@ -470,7 +484,9 @@ int qfile_main(int argc, char **argv)
if (state.args.non_orphans[i])
continue;
if (state.args.basenames[i]) {
- found = 0; /* ~inverse return code (as soon as an orphan is found, return non-zero) */
+ /* inverse return code (as soon as an orphan is found,
+ * return non-zero) */
+ found = 0;
if (!quiet)
puts(argv[i]);
else