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

Dan McGee dan at archlinux.org
Mon May 10 20:02:10 CEST 2010


From: Allan McRae <allan at archlinux.org>

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.

Dan: did some small refactoring and error message changes when PATH is
searched and nothing is found.

Original-patch-by: Shankar <jatheendra at gmail.com>
Signed-off-by: Allan McRae <allan at archlinux.org>
Signed-off-by: Dan McGee <dan at archlinux.org>
---

I think I just had some NIH and did a bit more refactoring than strictly
necessary, but I thought I'd at least send this along. I think it gets all the
error messaging tweaked up to be a bit more useful.


-Dan

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

diff --git a/src/pacman/query.c b/src/pacman/query.c
index 6010fd0..a882328 100644
--- a/src/pacman/query.c
+++ b/src/pacman/query.c
@@ -56,9 +56,49 @@ 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, *envpathsplit, *path;
+	char *fullname;
+	size_t flen;
+
+	if ((envpath = getenv("PATH")) == NULL) {
+		return(-1);
+	}
+	if ((envpath = envpathsplit = strdup(envpath)) == NULL) {
+		return(-1);
+	}
+
+	flen = strlen(*filename);
+
+	while ((path = strsep(&envpathsplit, ":")) != NULL) {
+		size_t plen = strlen(path);
+
+		/* strip the trailing slash if one exists */
+		while(path[plen - 1] == '/') {
+				path[--plen] = '\0';
+		}
+
+		fullname = malloc(plen + flen + 2);
+		sprintf(fullname, "%s/%s", path, *filename);
+
+		if(lstat(fullname, bufptr) == 0) {
+			free(*filename);
+			*filename = fullname;
+			free(envpath);
+			return(0);
+		}
+		free(fullname);
+	}
+	free(envpath);
+	return(-1);
+}
+
 static int query_fileowner(alpm_list_t *targets)
 {
 	int ret = 0;
+	char *filename;
 	alpm_list_t *t;
 
 	/* This code is here for safety only */
@@ -69,23 +109,36 @@ static int query_fileowner(alpm_list_t *targets)
 
 	for(t = targets; t; t = alpm_list_next(t)) {
 		int found = 0;
-		char *filename = alpm_list_getdata(t);
+		filename = strdup(alpm_list_getdata(t));
 		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 find '%s' on PATH: %s\n"),
+							filename, strerror(errno));
+					ret++;
+					free(filename);
+					continue;
+				}
+			} else {
+				pm_fprintf(stderr, PM_LOG_ERROR, _("failed to read file '%s': %s\n"),
+						filename, strerror(errno));
+				ret++;
+				free(filename);
+				continue;
+			}
 		}
 
 		if(S_ISDIR(buf.st_mode)) {
 			pm_fprintf(stderr, PM_LOG_ERROR,
 				_("cannot determine ownership of a directory\n"));
 			ret++;
+			free(filename);
 			continue;
 		}
 
@@ -97,6 +150,7 @@ static int query_fileowner(alpm_list_t *targets)
 		if(!rpath) {
 			pm_fprintf(stderr, PM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"),
 					filename, strerror(errno));
+			free(filename);
 			free(rpath);
 			ret++;
 			continue;
@@ -137,6 +191,7 @@ static int query_fileowner(alpm_list_t *targets)
 			pm_fprintf(stderr, PM_LOG_ERROR, _("No package owns %s\n"), filename);
 			ret++;
 		}
+		free(filename);
 		free(rpath);
 	}
 
-- 
1.7.1



More information about the pacman-dev mailing list