[pacman-dev] [PATCH] Allow -Qo to perform a functional 'which'
Dan McGee
dpmcgee at gmail.com
Thu May 6 03:03:19 CEST 2010
On Sat, Mar 6, 2010 at 10:02 PM, Allan McRae <allan at archlinux.org> wrote:
> 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.
>
> Original-patch-by: Shankar <jatheendra at gmail.com>
> Signed-off-by: Allan McRae <allan at archlinux.org>
> ---
>
> This should address all comments I had when this was submitted a
> few months back.
Until I'm about to merge it tonight! I have a few small ideas/tweaks. :P
> src/pacman/query.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++----
> 1 files changed, 52 insertions(+), 5 deletions(-)
>
> diff --git a/src/pacman/query.c b/src/pacman/query.c
> index 6b6a25d..038072f 100644
> --- a/src/pacman/query.c
> +++ b/src/pacman/query.c
> @@ -56,10 +56,44 @@ static char *resolve_path(const char* file)
> return(str);
> }
>
> +/* check if filename exists in PATH */
> +static int search_path(char *filename, size_t size, struct stat * bufptr)
no space needed between * and bufptr
> +{
> + char *envpath, *envpathsplit, *path, fullname[PATH_MAX+1];
Perhaps I am being a bit overkill, but I'd prefer:
char *envpath, *envpathsplit, *path;
char fullname[PATH_MAX+1];
just to separate the ptrs from the real thing.
> + int len;
> +
> + if ((envpath = getenv("PATH")) == NULL) {
> + return(-1);
> + }
Not that you'd see this regularly, but sudo can sometimes play weird
games with envvars among other things. This will cause a rather
nonsensical error:
$ PATH= ./src/pacman/.libs/lt-pacman -Qo pacman
error: failed to read file 'pacman': No such file or directory
$ ./src/pacman/.libs/lt-pacman -Qo pacman
/usr/bin/pacman is owned by pacman-git 20100404-1
> + if ((envpath = envpathsplit = strdup(envpath)) == NULL) {
> + return(-1);
> + }
Same kind of deal. I think we need better wording to indicate we
attempted to search the $PATH and failed, as opposed to couldn't
locate a file in the current directory and/or looked for an absolute
file path.
$ ./src/pacman/.libs/lt-pacman -Qo foobar
error: failed to read file 'foobar': No such file or directory
> +
> + while ((path = strsep(&envpathsplit, ":")) != NULL) {
> + len = strlen(path);
> +
> + /* strip the trailing slash if one exists */
> + while(path[len - 1] == '/') {
> + path[--len] = '\0';
> + }
> +
> + snprintf(fullname, sizeof(fullname), "%s/%s", path, filename);
> +
> + if(stat(fullname, bufptr) == 0) {
Shouldn't we be using lstat just like the query_fileowner() code?
Otherwise broken symlink from package X will be unqueryable?
> + strncpy(filename, fullname, size);
> + free(envpath);
> + return(0);
> + }
> + }
> + free(envpath);
> + return(-1);
> +}
> +
> static int query_fileowner(alpm_list_t *targets)
> {
> int ret = 0;
> alpm_list_t *t;
> + size_t len=PATH_MAX+1;
We use spaces between operators everywhere else; should use them here
too please.
>
> /* This code is here for safety only */
> if(targets == NULL) {
> @@ -67,19 +101,31 @@ static int query_fileowner(alpm_list_t *targets)
> return(1);
> }
>
> + char *filename = calloc(len, sizeof(char));
Why do we go through the "trouble" of allocating this one on the heap
when every single call to search_path() just allocates something the
same size on the stack?
> +
> for(t = targets; t; t = alpm_list_next(t)) {
> int found = 0;
> - char *filename = alpm_list_getdata(t);
> + strncpy(filename, alpm_list_getdata(t), len);
> 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, len, &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 +186,7 @@ static int query_fileowner(alpm_list_t *targets)
> free(rpath);
> }
>
> + free(filename);
> return ret;
> }
Oh, and more weirdness (my working directory was ~/projects/pacman/
with no etc in sight):
$ ./src/pacman/.libs/lt-pacman -Qo etc
error: cannot determine ownership of a directory
$ pacman -Qo etc
error: cannot determine ownership of a directory
So this is not new, but worth looking at perhaps?
-Dan
More information about the pacman-dev
mailing list