Hi Frank,

LGTM, please go ahead and merge the patch with these changes.

Aaron

On Sat, Jun 1, 2024 at 11:26 AM Frank Ch. Eigler <f...@redhat.com> wrote:
>
> Hi -
>
> > Thanks for the patch, some suggestions below.
>
> Thanks, adding the following 'git diff -w' to the patch you reviewed:
>
> > [...]
> > I was experimenting with metadata queries to a local server that indexed
> > a single rpm (binutils-2.41-8.fc40.x86_64.rpm). The following commands
> > produced JSON with empty "results":
> >
> >     debuginfod-find metadata glob '*'
> >     debuginfod-find metadata glob '/usr*'
> >     debuginfod-find metadata glob '/usr/bin*'
> >
> > Using the glob '/usr/bin/*' did produce results with complete metadata.
> >
> > I haven't looked into the cause but this seems like a bug.  I'd expect
> > the first 3 globs to return at least as many results as the 4th. If this is
> > intentional behaviour then I think it should be documented.
>
> This is intentional.  When you use glob patterns like '*' or '/usr*'
> in the shell, you don't get recursive path name lists either.
> Addressed in the documentation via reference to shell /
> fnmatch(FNM_PATHNAME).
>
>
> diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c
> index c75abadf7dce..3d6f8d8c4bea 100644
> --- a/debuginfod/debuginfod-client.c
> +++ b/debuginfod/debuginfod-client.c
> @@ -72,7 +72,7 @@ int debuginfod_find_section (debuginfod_client *c, const 
> unsigned char *b,
>                              int s, const char *scn, char **p)
>                               { return -ENOSYS; }
>  int debuginfod_find_metadata (debuginfod_client *c,
> -                              const char *k, char *v, char **p) { return 
> -ENOSYS; }
> +                              const char *k, const char *v, char **p) { 
> return -ENOSYS; }
>  void debuginfod_set_progressfn(debuginfod_client *c,
>                                debuginfod_progressfn_t fn) { }
>  void debuginfod_set_verbose_fd(debuginfod_client *c, int fd) { }
> @@ -858,22 +858,12 @@ init_server_urls(char* url_subdir, const char* type,
>    char *server_url = strtok_r(server_urls, url_delim, &strtok_saveptr);
>    /* Count number of URLs.  */
>    int n = 0;
> -  assert (0 == strcmp(url_subdir, "buildid") || 0 == strcmp(url_subdir, 
> "metadata"));
>
>    while (server_url != NULL)
>      {
> -      int r;
> -      char *tmp_url;
> -      if (strlen(server_url) > 1 && server_url[strlen(server_url)-1] == '/')
> -        r = asprintf(&tmp_url, "%s%s", server_url, url_subdir);
> -      else
> -        r = asprintf(&tmp_url, "%s/%s", server_url, url_subdir);
> -
> -      if (r == -1)
> -        return -ENOMEM;
> -
> -      // When we encounted a (well-formed) token off the form ima:foo, we 
> update the policy
> -      // under which results from that server will be ima verified
> +      // When we encountered a (well-formed) token off the form
> +      // ima:foo, we update the policy under which results from that
> +      // server will be ima verified
>        if (startswith(server_url, "ima:"))
>          {
>  #ifdef ENABLE_IMA_VERIFICATION
> @@ -898,6 +888,17 @@ init_server_urls(char* url_subdir, const char* type,
>            goto continue_next_url;
>          }
>
> +      // Construct actual URL for libcurl
> +      int r;
> +      char *tmp_url;
> +      if (strlen(server_url) > 1 && server_url[strlen(server_url)-1] == '/')
> +        r = asprintf(&tmp_url, "%s%s", server_url, url_subdir);
> +      else
> +        r = asprintf(&tmp_url, "%s/%s", server_url, url_subdir);
> +
> +      if (r == -1)
> +        return -ENOMEM;
> +
>        /* PR 27983: If the url is duplicate, skip it */
>        int url_index;
>        for (url_index = 0; url_index < n; ++url_index)
> @@ -1025,7 +1026,7 @@ init_handle(debuginfod_client *client,
>
>  /*
>   * This function busy-waits on one or more curl queries to complete. This can
> - * be controled via only_one, which, if true, will find the first winner and 
> exit
> + * be controlled via only_one, which, if true, will find the first winner 
> and exit
>   * once found. If positive maxtime and maxsize dictate the maximum allowed 
> wait times
>   * and download sizes respectively. Returns 0 on success and -Posix error on 
> failure.
>   */
> @@ -1044,7 +1045,7 @@ perform_queries(CURLM *curlm, CURL **target_handle, 
> struct handle_data *data, de
>        c->winning_headers = NULL;
>      }
>    if (maxtime > 0 && clock_gettime(CLOCK_MONOTONIC_RAW, &start_time) == -1)
> -    return errno;
> +    return -errno;
>    long delta = 0;
>    do
>      {
> @@ -1052,7 +1053,7 @@ perform_queries(CURLM *curlm, CURL **target_handle, 
> struct handle_data *data, de
>        if (maxtime > 0)
>          {
>            if (clock_gettime(CLOCK_MONOTONIC_RAW, &cur_time) == -1)
> -            return errno;
> +            return -errno;
>            delta = cur_time.tv_sec - start_time.tv_sec;
>            if ( delta >  maxtime)
>              {
> @@ -1108,9 +1109,7 @@ perform_queries(CURLM *curlm, CURL **target_handle, 
> struct handle_data *data, de
>          }
>
>        long dl_size = -1;
> -      if (only_one && target_handle)
> -        { // Only bother with progress functions if we're retrieving exactly 
> 1 file
> -          if (*target_handle && (c->progressfn || maxsize > 0))
> +      if (target_handle && *target_handle && (c->progressfn || maxsize > 0))
>          {
>            /* Get size of file being downloaded. NB: If going through
>               deflate-compressing proxies, this number is likely to be
> @@ -1148,7 +1147,7 @@ perform_queries(CURLM *curlm, CURL **target_handle, 
> struct handle_data *data, de
>          {
>            loops ++;
>            long pa = loops; /* default param for progress callback */
> -              if (*target_handle) /* we've committed to a server; report its 
> download progress */
> +          if (target_handle && *target_handle) /* we've committed to a 
> server; report its download progress */
>              {
>                /* PR30809: Check actual size of cached file.  This same
>                   fd is shared by all the multi-curl handles (but only
> @@ -1186,7 +1185,6 @@ perform_queries(CURLM *curlm, CURL **target_handle, 
> struct handle_data *data, de
>                  break;
>              }
>          }
> -        }
>        /* Check to see if we are downloading something which exceeds maxsize, 
> if set.*/
>        if (target_handle && *target_handle && dl_size > maxsize && maxsize > 
> 0)
>          {
> @@ -2050,7 +2048,6 @@ debuginfod_query_server_by_buildid (debuginfod_client 
> *c,
>      retry_limit = atoi (retry_limit_envvar);
>
>    CURLM *curlm = c->server_mhandle;
> -  assert (curlm != NULL);
>
>    /* Tracks which handle should write to fd. Set to the first
>       handle that is ready to write the target file to the cache.  */
> @@ -2637,13 +2634,8 @@ debuginfod_find_section (debuginfod_client *client,
>
>
>  int debuginfod_find_metadata (debuginfod_client *client,
> -                              const char* key, char* value, char **path)
> +                              const char* key, const char* value, char 
> **path)
>  {
> -  (void) client;
> -  (void) key;
> -  (void) value;
> -  (void) path;
> -
>    char *server_urls = NULL;
>    char *urls_envvar = NULL;
>    char *cache_path = NULL;
> @@ -2718,7 +2710,10 @@ int debuginfod_find_metadata (debuginfod_client 
> *client,
>    /* Check if we have a recent result already in the cache. */
>    cache_path = make_cache_path();
>    if (! cache_path)
> +    {
> +      rc = -ENOMEM;
>        goto out;
> +    }
>    xalloc_str (target_cache_dir, "%s/metadata", cache_path);
>    (void) mkdir (target_cache_dir, 0700);
>    xalloc_str (target_cache_path, "%s/%s", target_cache_dir, 
> target_file_name);
> @@ -2823,7 +2818,6 @@ int debuginfod_find_metadata (debuginfod_client *client,
>      }
>
>    CURLM *curlm = client->server_mhandle;
> -  assert (curlm != NULL);
>
>    CURL *target_handle = NULL;
>    data = malloc(sizeof(struct handle_data) * num_urls);
> diff --git a/debuginfod/debuginfod-find.c b/debuginfod/debuginfod-find.c
> index b0a7c2360dd8..0ef80377a81b 100644
> --- a/debuginfod/debuginfod-find.c
> +++ b/debuginfod/debuginfod-find.c
> @@ -243,6 +243,8 @@ main(int argc, char** argv)
>
>        rc = debuginfod_find_metadata (client, argv[remaining+1], 
> argv[remaining+2],
>                                       &cache_name);
> +      if (rc >= 0)
> +        {
>            /* We output a pprinted JSON object, not the regular 
> debuginfod-find cached file path */
>            print_cached_file = false;
>            json_object *metadata = json_object_from_file(cache_name);
> @@ -262,6 +264,7 @@ main(int argc, char** argv)
>                return 1;
>              }
>          }
> +    }
>    else
>      {
>        argp_help (&argp, stderr, ARGP_HELP_USAGE, argv[0]);
> diff --git a/debuginfod/debuginfod.h.in b/debuginfod/debuginfod.h.in
> index 3936b17b97cf..0a6a4a22efd9 100644
> --- a/debuginfod/debuginfod.h.in
> +++ b/debuginfod/debuginfod.h.in
> @@ -97,17 +97,12 @@ int debuginfod_find_section (debuginfod_client *client,
>     successful, set *path to a strdup'd copy of the name of the same
>     file in the cache.  Caller must free() it later.
>
> -   key can be one of 'glob' or 'file' corresponding to querying for value
> -   by exact name or using a pattern matching approach.
> -
> -   The JSON document will be of the form {results: [{...}, ...], complete: 
> <bool>},
> -   where the results are JSON objects containing metadata and complete is 
> true iff
> -   all of the federation of servers responded with complete results (as 
> opposed to 1+
> -   failing to return or having an issue)
> +   See the debuginfod-find(1) man page for examples of the supported types
> +   of key/value queries and their JSON results.
>     */
>  int debuginfod_find_metadata (debuginfod_client *client,
>                                const char *key,
> -                              char* value,
> +                              const char* value,
>                                char **path);
>
>  typedef int (*debuginfod_progressfn_t)(debuginfod_client *c, long a, long b);
> diff --git a/doc/Makefile.am b/doc/Makefile.am
> index 87de4f0beb7f..0c094af2289b 100644
> --- a/doc/Makefile.am
> +++ b/doc/Makefile.am
> @@ -39,6 +39,7 @@ notrans_dist_man3_MANS += debuginfod_find_debuginfo.3
>  notrans_dist_man3_MANS += debuginfod_find_executable.3
>  notrans_dist_man3_MANS += debuginfod_find_source.3
>  notrans_dist_man3_MANS += debuginfod_find_section.3
> +notrans_dist_man3_MANS += debuginfod_find_metadata.3
>  notrans_dist_man3_MANS += debuginfod_get_user_data.3
>  notrans_dist_man3_MANS += debuginfod_get_url.3
>  notrans_dist_man3_MANS += debuginfod_set_progressfn.3
> diff --git a/doc/debuginfod-find.1 b/doc/debuginfod-find.1
> index 8c63b2c5a5e0..38b5b0184dfe 100644
> --- a/doc/debuginfod-find.1
> +++ b/doc/debuginfod-find.1
> @@ -123,16 +123,17 @@ l l.
>
>  .SS metadata \fIKEY\fP \fIVALUE\fP
>
> -All designated debuginfod servers are queried for metadata about files
> -in their index.  Different search keys may be supported by different
> -servers.
> +All designated debuginfod servers are queried for metadata about all
> +files that match a given key/value query in their index.  The results
> +include names and buildids, which may be used in future queries to
> +fetch actual files.
>
>  .TS
>  l l l .
>  KEY    VALUE   DESCRIPTION
>
> -\fBfile\fP     path    exact match \fIpath\fP, including in archives
> -\fBglob\fP     pattern glob match \fIpattern\fP, including in archives
> +\fBfile\fP     \fIpath\fP      exact match \fIpath\fP, including in archives
> +\fBglob\fP     \fIpattern\fP   shell-style glob match \fIpattern\fP, 
> including in archives, as in fnmatch(FNM_PATHNAME)
>  .TE
>
>  The resulting output will look something like the following
> diff --git a/doc/debuginfod_find_debuginfo.3 b/doc/debuginfod_find_debuginfo.3
> index 4e359c8c4bd4..589a2c2b63b4 100644
> --- a/doc/debuginfod_find_debuginfo.3
> +++ b/doc/debuginfod_find_debuginfo.3
> @@ -48,6 +48,10 @@ LOOKUP FUNCTIONS
>  .BI "                           int " build_id_len ","
>  .BI "                           const char * " section ","
>  .BI "                           char ** " path ");"
> +.BI "int debuginfod_find_metadata(debuginfod_client *" client ","
> +.BI "                            const char *" key ","
> +.BI "                            const char *" value ","
> +.BI "                            char ** " path ");"
>
>
>  OPTIONAL FUNCTIONS
> @@ -114,6 +118,14 @@ section queries, debuginfod_find_section may query the 
> server for the
>  debuginfo and/or executable with \fIbuild_id\fP in order to retrieve
>  and extract the section.
>
> +.BR debuginfod_find_metadata ()
> +queries all debuginfod server URLs contained in
> +.BR $DEBUGINFOD_URLS
> +for metadata for all matches of a given key/value query against files
> +in their indexes.  The resulting file is a JSON document.  See the
> +\fIdebuginfod-find(1)\fP man page for examples of the supported types
> +of key/value queries and their JSON results.
> +
>  If \fIpath\fP is not NULL and the query is successful, \fIpath\fP is set
>  to the path of the file in the cache. The caller must \fBfree\fP() this 
> value.
>
> diff --git a/doc/debuginfod_find_metadata.3 b/doc/debuginfod_find_metadata.3
> new file mode 100644
> index 000000000000..16279936e2ea
> --- /dev/null
> +++ b/doc/debuginfod_find_metadata.3
> @@ -0,0 +1 @@
> +.so man3/debuginfod_find_debuginfo.3
> diff --git a/tests/run-debuginfod-find-metadata.sh 
> b/tests/run-debuginfod-find-metadata.sh
> index f19c5a6e6942..78a34f09490f 100755
> --- a/tests/run-debuginfod-find-metadata.sh
> +++ b/tests/run-debuginfod-find-metadata.sh
> @@ -1,6 +1,6 @@
>  #!/usr/bin/env bash
>  #
> -# Copyright (C) 2022 Red Hat, Inc.
> +# Copyright (C) 2022-2024 Red Hat, Inc.
>  # This file is part of elfutils.
>  #
>  # This file is free software; you can redistribute it and/or modify
>
>
>
>
> - FChE
>

Reply via email to