Introduce a new function debuginfod_set_verbose_fd which will produce verbose output on a given file descriptor (STDERR_FILENO if the environment variable DEBUGINFOD_VERBOSE is set) showing how the search for a particular client query is going.
Example output: debuginfod_find_debuginfo 1234567890 server urls "https://debuginfod.elfutils.org/ http://debuginfod.usersys.redhat.com:3632/" checking build-id checking cache dir /root/.cache/debuginfod_client using timeout 90 init server 0 https://debuginfod.elfutils.org/ url 0 https://debuginfod.elfutils.org/buildid/1234567890/debuginfo init server 1 http://debuginfod.usersys.redhat.com:3632/ url 1 http://debuginfod.usersys.redhat.com:3632/buildid/1234567890/debuginfo query 2 urls in parallel server response HTTP response code said error url 0 The requested URL returned error: 404 Not Found server response HTTP response code said error url 1 The requested URL returned error: 404 Not Found not found No such file or directory (err=-2) Signed-off-by: Mark Wielaard <m...@klomp.org> --- debuginfod/ChangeLog | 16 ++++ debuginfod/debuginfod-client.c | 134 +++++++++++++++++++++++++++++--- debuginfod/debuginfod-find.c | 4 +- debuginfod/debuginfod.h | 3 + debuginfod/libdebuginfod.map | 5 +- doc/ChangeLog | 7 ++ doc/debuginfod_find_debuginfo.3 | 17 ++++ 7 files changed, 174 insertions(+), 12 deletions(-) diff --git a/debuginfod/ChangeLog b/debuginfod/ChangeLog index d4face2d..5e507f0f 100644 --- a/debuginfod/ChangeLog +++ b/debuginfod/ChangeLog @@ -1,3 +1,19 @@ +2020-11-11 Mark Wielaard <m...@klomp.org> + + * debuginfod-client.c (debuginfod_set_verbose_fd): New function. + (struct debuginfod_client): Add verbose_fd. + (struct handle_data): Add errbuf. + (debuginfod_query_server): Produce verbose output when + debuginfod_client verbose_fd is set. Only clear old data and set + default_headers when any work is done. Always goto out when setting + rc to an error value. Use CURLOPT_ERRORBUFFER to get more error + output when verbose output is requested. + * debuginfod.h (DEBUGINFOD_VERBOSE_ENV_VAR): New. + (debuginfod_set_verbose_fd): Added. + * debuginfod-find.c (parse_opt): Set debuginfod_set_verbose_fd on -v. + * bdebuginfod.map (ELFUTILS_0.183): New section, add + debuginfod_set_verbose_fd. + 2020-11-11 Mark Wielaard <m...@klomp.org> * debuginfod-find.c (progressfn): Use clock_gettime to print Progress diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c index ce1d819b..2bf1543a 100644 --- a/debuginfod/debuginfod-client.c +++ b/debuginfod/debuginfod-client.c @@ -56,6 +56,7 @@ int debuginfod_find_source (debuginfod_client *c, const unsigned char *b, int s, const char *f, 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) { } void debuginfod_set_user_data (debuginfod_client *c, void *d) { } void* debuginfod_get_user_data (debuginfod_client *c) { return NULL; } const char* debuginfod_get_url (debuginfod_client *c) { return NULL; } @@ -115,6 +116,9 @@ struct debuginfod_client debuginfod_end needs to terminate. */ int default_progressfn_printed_p; + /* File descriptor to output any verbose messages if > 0. */ + int verbose_fd; + /* Can contain all other context, like cache_path, server_urls, timeout or other info gotten from environment variables, the handle data, etc. So those don't have to be reparsed and @@ -158,6 +162,9 @@ struct handle_data /* URL queried by this handle. */ char url[PATH_MAX]; + /* error buffer for this handle. */ + char errbuf[CURL_ERROR_SIZE]; + /* This handle. */ CURL *handle; @@ -498,28 +505,51 @@ debuginfod_query_server (debuginfod_client *c, char *target_cache_tmppath = NULL; char suffix[PATH_MAX + 1]; /* +1 for zero terminator. */ char build_id_bytes[MAX_BUILD_ID_BYTES * 2 + 1]; + int vfd = c->verbose_fd; int rc; - /* Clear the obsolete URL from a previous _find operation. */ - free (c->url); - c->url = NULL; - - add_default_headers(c); + if (vfd >= 0) + { + dprintf (vfd, "debuginfod_find_%s ", type); + if (build_id_len == 0) /* expect clean hexadecimal */ + dprintf (vfd, "%s", (const char *) build_id); + else + for (int i = 0; i < build_id_len; i++) + dprintf (vfd, "%02x", build_id[i]); + if (filename != NULL) + dprintf (vfd, " %s\n", filename); + dprintf (vfd, "\n"); + } /* Is there any server we can query? If not, don't do any work, just return with ENOSYS. Don't even access the cache. */ urls_envvar = getenv(server_urls_envvar); + if (vfd >= 0) + dprintf (vfd, "server urls \"%s\"\n", + urls_envvar != NULL ? urls_envvar : ""); if (urls_envvar == NULL || urls_envvar[0] == '\0') { rc = -ENOSYS; goto out; } + /* Clear the obsolete URL from a previous _find operation. */ + free (c->url); + c->url = NULL; + + add_default_headers(c); + /* Copy lowercase hex representation of build_id into buf. */ + if (vfd >= 0) + dprintf (vfd, "checking build-id\n"); if ((build_id_len >= MAX_BUILD_ID_BYTES) || (build_id_len == 0 && strlen ((const char *) build_id) > MAX_BUILD_ID_BYTES*2)) - return -EINVAL; + { + rc = -EINVAL; + goto out; + } + if (build_id_len == 0) /* expect clean hexadecimal */ strcpy (build_id_bytes, (const char *) build_id); else @@ -528,8 +558,13 @@ debuginfod_query_server (debuginfod_client *c, if (filename != NULL) { + if (vfd >= 0) + dprintf (vfd, "checking filename\n"); if (filename[0] != '/') // must start with / - return -EINVAL; + { + rc = -EINVAL; + goto out; + } /* copy the filename to suffix, s,/,#,g */ unsigned q = 0; @@ -559,6 +594,9 @@ debuginfod_query_server (debuginfod_client *c, else suffix[0] = '\0'; + if (suffix[0] != '\0' && vfd >= 0) + dprintf (vfd, "suffix %s\n", suffix); + /* set paths needed to perform the query example format @@ -630,6 +668,10 @@ debuginfod_query_server (debuginfod_client *c, /* XXX combine these */ xalloc_str (interval_path, "%s/%s", cache_path, cache_clean_interval_filename); xalloc_str (maxage_path, "%s/%s", cache_path, cache_max_unused_age_filename); + + if (vfd >= 0) + dprintf (vfd, "checking cache dir %s\n", cache_path); + rc = debuginfod_init_cache(cache_path, interval_path, maxage_path); if (rc != 0) goto out; @@ -653,6 +695,9 @@ debuginfod_query_server (debuginfod_client *c, if (timeout_envvar != NULL) timeout = atoi (timeout_envvar); + if (vfd >= 0) + dprintf (vfd, "using timeout %ld\n", timeout); + /* make a copy of the envvar so it can be safely modified. */ server_urls = strdup(urls_envvar); if (server_urls == NULL) @@ -719,6 +764,9 @@ debuginfod_query_server (debuginfod_client *c, /* Initialize each handle. */ for (int i = 0; i < num_urls && server_url != NULL; i++) { + if (vfd >= 0) + dprintf (vfd, "init server %d %s\n", i, server_url); + data[i].fd = fd; data[i].target_handle = &target_handle; data[i].handle = curl_easy_init(); @@ -745,7 +793,12 @@ debuginfod_query_server (debuginfod_client *c, snprintf(data[i].url, PATH_MAX, "%s%s/%s/%s", server_url, slashbuildid, build_id_bytes, type); + if (vfd >= 0) + dprintf (vfd, "url %d %s\n", i, data[i].url); + curl_easy_setopt(data[i].handle, CURLOPT_URL, data[i].url); + if (vfd >= 0) + curl_easy_setopt(data[i].handle, CURLOPT_ERRORBUFFER, data[i].errbuf); curl_easy_setopt(data[i].handle, CURLOPT_WRITEFUNCTION, debuginfod_write_callback); @@ -778,8 +831,12 @@ debuginfod_query_server (debuginfod_client *c, } /* Query servers in parallel. */ + if (vfd >= 0) + dprintf (vfd, "query %d urls in parallel\n", num_urls); int still_running; long loops = 0; + int committed_to = -1; + bool verbose_reported = false; do { /* Wait 1 second, the minimum DEBUGINFOD_TIMEOUT. */ @@ -787,9 +844,23 @@ debuginfod_query_server (debuginfod_client *c, /* If the target file has been found, abort the other queries. */ if (target_handle != NULL) - for (int i = 0; i < num_urls; i++) - if (data[i].handle != target_handle) - curl_multi_remove_handle(curlm, data[i].handle); + { + for (int i = 0; i < num_urls; i++) + if (data[i].handle != target_handle) + curl_multi_remove_handle(curlm, data[i].handle); + else + committed_to = i; + } + + if (vfd >= 0 && !verbose_reported && committed_to >= 0) + { + bool pnl = (c->default_progressfn_printed_p && vfd == STDERR_FILENO); + dprintf (vfd, "%scommitted to url %d\n", pnl ? "\n" : "", + committed_to); + if (pnl) + c->default_progressfn_printed_p = 0; + verbose_reported = true; + } CURLMcode curlm_res = curl_multi_perform(curlm, &still_running); if (curlm_res != CURLM_OK) @@ -863,6 +934,23 @@ debuginfod_query_server (debuginfod_client *c, msg = curl_multi_info_read(curlm, &num_msg); if (msg != NULL && msg->msg == CURLMSG_DONE) { + if (vfd >= 0) + { + bool pnl = (c->default_progressfn_printed_p + && vfd == STDERR_FILENO); + dprintf (vfd, "%sserver response %s\n", pnl ? "\n" : "", + curl_easy_strerror (msg->data.result)); + if (pnl) + c->default_progressfn_printed_p = 0; + for (int i = 0; i < num_urls; i++) + if (msg->easy_handle == data[i].handle) + { + if (strlen (data[i].errbuf) > 0) + dprintf (vfd, "url %d %s\n", i, data[i].errbuf); + break; + } + } + if (msg->data.result != CURLE_OK) { /* Unsucessful query, determine error code. */ @@ -946,6 +1034,14 @@ debuginfod_query_server (debuginfod_client *c, if (verified_handle == NULL) goto out1; + if (vfd >= 0) + { + bool pnl = c->default_progressfn_printed_p && vfd == STDERR_FILENO; + dprintf (vfd, "%sgot file from server\n", pnl ? "\n" : ""); + if (pnl) + c->default_progressfn_printed_p = 0; + } + /* we've got one!!!! */ time_t mtime; CURLcode curl_res = curl_easy_getinfo(verified_handle, CURLINFO_FILETIME, (void*) &mtime); @@ -1005,6 +1101,14 @@ debuginfod_query_server (debuginfod_client *c, if (c->default_progressfn_printed_p) dprintf(STDERR_FILENO, "\n"); + if (vfd >= 0) + { + if (rc < 0) + dprintf (vfd, "not found %s (err=%d)\n", strerror (-rc), rc); + else + dprintf (vfd, "found %s (fd=%d)\n", target_cache_path, rc); + } + free (cache_path); free (maxage_path); free (interval_path); @@ -1027,6 +1131,10 @@ debuginfod_begin (void) { if (getenv(DEBUGINFOD_PROGRESS_ENV_VAR)) client->progressfn = default_progressfn; + if (getenv(DEBUGINFOD_VERBOSE_ENV_VAR)) + client->verbose_fd = STDERR_FILENO; + else + client->verbose_fd = -1; } return client; } @@ -1125,6 +1233,12 @@ debuginfod_set_progressfn(debuginfod_client *client, client->progressfn = fn; } +void +debuginfod_set_verbose_fd(debuginfod_client *client, int fd) +{ + client->verbose_fd = fd; +} + /* NB: these are thread-unsafe. */ __attribute__((constructor)) attribute_hidden void libdebuginfod_ctor(void) diff --git a/debuginfod/debuginfod-find.c b/debuginfod/debuginfod-find.c index 5f9bccc3..3e8ab203 100644 --- a/debuginfod/debuginfod-find.c +++ b/debuginfod/debuginfod-find.c @@ -98,7 +98,9 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) switch (key) { case 'v': verbose++; - debuginfod_set_progressfn (client, & progressfn); break; + debuginfod_set_progressfn (client, & progressfn); + debuginfod_set_verbose_fd (client, STDERR_FILENO); + break; default: return ARGP_ERR_UNKNOWN; } return 0; diff --git a/debuginfod/debuginfod.h b/debuginfod/debuginfod.h index 8d90838b..4ee86ce9 100644 --- a/debuginfod/debuginfod.h +++ b/debuginfod/debuginfod.h @@ -34,6 +34,7 @@ #define DEBUGINFOD_CACHE_PATH_ENV_VAR "DEBUGINFOD_CACHE_PATH" #define DEBUGINFOD_TIMEOUT_ENV_VAR "DEBUGINFOD_TIMEOUT" #define DEBUGINFOD_PROGRESS_ENV_VAR "DEBUGINFOD_PROGRESS" +#define DEBUGINFOD_VERBOSE_ENV_VAR "DEBUGINFOD_VERBOSE" /* Handle for debuginfod-client connection. */ typedef struct debuginfod_client debuginfod_client; @@ -75,6 +76,8 @@ typedef int (*debuginfod_progressfn_t)(debuginfod_client *c, long a, long b); void debuginfod_set_progressfn(debuginfod_client *c, debuginfod_progressfn_t fn); +void debuginfod_set_verbose_fd(debuginfod_client *c, int fd); + /* Set the user parameter. */ void debuginfod_set_user_data (debuginfod_client *client, void *value); diff --git a/debuginfod/libdebuginfod.map b/debuginfod/libdebuginfod.map index b8edfb01..7d2f5882 100644 --- a/debuginfod/libdebuginfod.map +++ b/debuginfod/libdebuginfod.map @@ -14,4 +14,7 @@ ELFUTILS_0.179 { debuginfod_get_user_data; debuginfod_get_url; debuginfod_add_http_header; -}; +} ELFUTILS_0.178; +ELFUTILS_0.183 { + debuginfod_set_verbose_fd; +} ELFUTILS_0.179; diff --git a/doc/ChangeLog b/doc/ChangeLog index 8c33f174..fdf352e7 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,10 @@ +2020-11-11 Mark Wielaard <m...@klomp.org> + + * debuginfod_find_debuginfo.3: Document debuginfod_set_verbose_fd + and DEBUGINFOD_VERBOSE. + * debuginfod_set_verbose_fd.3: New redirect to + debuginfod_find_debuginfo.3 + 2020-10-29 Frank Ch. Eigler <f...@redhat.com> PR26775 diff --git a/doc/debuginfod_find_debuginfo.3 b/doc/debuginfod_find_debuginfo.3 index eec04e5e..3c6d52f5 100644 --- a/doc/debuginfod_find_debuginfo.3 +++ b/doc/debuginfod_find_debuginfo.3 @@ -50,6 +50,8 @@ OPTIONAL FUNCTIONS .BI " long a, long b);" .BI "void debuginfod_set_progressfn(debuginfod_client *" client "," .BI " debuginfod_progressfn_t " progressfn ");" +.BI "void debuginfod_set_verbose_fd(debuginfod_client *" client "," +.BI " int " fd ");" .BI "void debuginfod_set_user_data(debuginfod_client *" client "," .BI " void *" data ");" .BI "void* debuginfod_get_user_data(debuginfod_client *" client ");" @@ -143,6 +145,15 @@ continue the work, or any other value to stop work as soon as possible. Consequently, the \fBdebuginfod_find_*\fP() function will likely return with an error, but might still succeed. +.SS "VERBOSE OUTPUT" + +The \fBdebuginfod_find_*\fP() functions may use several techniques +to retrieve the requested files, through the cache or through one +or multiple servers or file URLs. To show how a query is handled hte +.BR debuginfod_set_verbose_fd () +can be used to set a particular file descriptor on which verbose +output is given about the query steps and eventual errors encountered. + .SS "USER DATA POINTER" A single \fIvoid *\fP pointer associated with the connection handle @@ -235,6 +246,12 @@ configure a default progressfn. This function will append a simple progress message periodically to stderr. The default is no progress function output. +.TP 21 +.B DEBUGINFOD_VERBOSE +This environment variable governs the default file descriptor for +verbose output. If set, and if a verbose fd is not explicitly set, +then the verbose output will be produced on STDERR_FILENO. + .TP 21 .B DEBUGINFOD_CACHE_PATH This environment variable governs the location of the cache where -- 2.18.4