[pacman-dev] [PATCH] Allow -Qo to perform a functional 'which'

Allan McRae allan at archlinux.org
Mon Dec 21 04:55:53 EST 2009


When pacman queries the ownership of an object that is not a path,
it will check in the users PATH for a match. Implements FS#8798.

Patch-by: Shankar <jatheendra at gmail.com>
[Allan: rework for master, tidy-up]
Signed-off-by: Allan McRae <allan at archlinux.org>
---

This was original posted a year ago...
http://mailman.archlinux.org/pipermail/pacman-dev/2008-November/007659.html

The comments then were that we should maybe refactor out stuff dealing with
file paths, specifically removing trailing backslashes. That appears to only
occur in two other places and is very simple so I do not thing it needs
refactored and can be done in a spearate patch if necessary.

The only other part I do not like is the "failed to read file" error block is
repeated, but I can not see a nice way to fix that.

 src/pacman/query.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/src/pacman/query.c b/src/pacman/query.c
index 6b6a25d..6f579fd 100644
--- a/src/pacman/query.c
+++ b/src/pacman/query.c
@@ -56,6 +56,41 @@ static char *resolve_path(const char* file)
 	return(str);
 }
 
+/* check if filename exists in PATH */
+static int search_path(char *filename, struct stat * bufptr)
+{
+	char *envpath, *path, *fullname;
+	int len;
+
+	if ((envpath = getenv("PATH")) == NULL) {
+		return(-1);
+	}
+	if ((envpath = strdup(envpath)) == NULL) {
+		return(-1);
+	}
+
+	fullname = calloc(PATH_MAX+1, sizeof(char));
+
+	while ((path = strsep(&envpath, ":")) != NULL) {
+		len = strlen(path);
+
+		/* strip the trailing slash if one exists */
+		if(path[len - 1] == '/') {
+				path[len - 1] = '\0';
+		}
+
+		snprintf(fullname, PATH_MAX+1, "%s/%s", path, filename);
+
+		if(stat(fullname, bufptr) == 0) {
+			strncpy(filename, fullname, PATH_MAX+1);
+			free(fullname);
+			return(0);
+		}
+	}
+	free(fullname);
+	return(-1);
+}
+
 static int query_fileowner(alpm_list_t *targets)
 {
 	int ret = 0;
@@ -67,19 +102,31 @@ static int query_fileowner(alpm_list_t *targets)
 		return(1);
 	}
 
+	char *filename = calloc(PATH_MAX+1, sizeof(char));
+
 	for(t = targets; t; t = alpm_list_next(t)) {
 		int found = 0;
-		char *filename = alpm_list_getdata(t);
+		strncpy(filename, alpm_list_getdata(t), PATH_MAX+1);
 		char *bname, *dname, *rpath;
 		const char *root;
 		struct stat buf;
 		alpm_list_t *i, *j;
 
 		if(lstat(filename, &buf) == -1) {
-			pm_fprintf(stderr, PM_LOG_ERROR, _("failed to read file '%s': %s\n"),
-					filename, strerror(errno));
-			ret++;
-			continue;
+			/*  if it is not a path but a program name, then check in PATH */
+			if(strchr(filename, '/') == NULL) {
+				if(search_path(filename, &buf) == -1) {
+					pm_fprintf(stderr, PM_LOG_ERROR, _("failed to read file '%s': %s\n"),
+						filename, strerror(errno));
+					ret++;
+					continue;
+				}
+			} else {
+				pm_fprintf(stderr, PM_LOG_ERROR, _("failed to read file '%s': %s\n"),
+						filename, strerror(errno));
+				ret++;
+				continue;
+			}
 		}
 
 		if(S_ISDIR(buf.st_mode)) {
@@ -140,6 +187,7 @@ static int query_fileowner(alpm_list_t *targets)
 		free(rpath);
 	}
 
+	free(filename);
 	return ret;
 }
 
-- 
1.6.5.6



More information about the pacman-dev mailing list