Hi -
Thanks for the review!
> On my machine memcheck reports leaks due to target_cachehdr_path
> missing a free. [...]
Sorry! I must have sent an immediately prior version of the patch;
the following one has the missing free().
> [...]
> There is some stray white space at the end of this line and elsewhere.
Hehehe, okay, nuked that.
> [...]
> It doesn't have to be done in this patch but we could add a read_retry
> function to elfutils lib/system.h to handle reading all bytes. There
> are some read calls in debuginfod.cxx where read_retry could also be used.
Just switched to using pread_retry() already there, and pwrite_retry()
for the corresponding other case.
v2 patch:
PR31862: debuginfod: client to cache x-debuginfod-* headers
This feature allows the extra http headers from debuginfod to be saved
into the client cache, and also thus replayed to clients. This way
they can perform IMA verification again, if they like, or a federating
caching intermediate debuginfod server can replay the headers it
received previously from upstream to future downstream. The headers
are placed adjacent to the payload files .cache/debuginfod/BUILDID/PAYLOAD
as .cache/debuginfod/BUILDID/hdr-PAYLOAD. They are aged the same
atime-based way.
Testing via an extension of a previous small test, and hand-running both
client & server code under valgrind. No memcheck errors reported.
Signed-off-by: Frank Ch. Eigler
diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c
index d89beae93ea1..585855b92c68 100644
--- a/debuginfod/debuginfod-client.c
+++ b/debuginfod/debuginfod-client.c
@@ -569,7 +569,7 @@ debuginfod_clean_cache(debuginfod_client *c,
return -errno;
regex_t re;
- const char * pattern =
".*/(metadata.*|[a-f0-9]+(/debuginfo|/executable|/source.*|))$"; /* include
dirs */
+ const char * pattern =
".*/(metadata.*|[a-f0-9]+(/hdr.*|/debuginfo|/executable|/source.*|))$"; /*
include dirs */
/* NB: also matches .../section/ subdirs, so extracted section files also
get cleaned. */
if (regcomp (&re, pattern, REG_EXTENDED | REG_NOSUB) != 0)
return -ENOMEM;
@@ -1777,7 +1777,9 @@ debuginfod_query_server_by_buildid (debuginfod_client *c,
char *cache_miss_path = NULL;
char *target_cache_dir = NULL;
char *target_cache_path = NULL;
+ char *target_cachehdr_path = NULL;
char *target_cache_tmppath = NULL;
+ char *target_cachehdr_tmppath = NULL;
char suffix[NAME_MAX];
char build_id_bytes[MAX_BUILD_ID_BYTES * 2 + 1];
int vfd = c->verbose_fd;
@@ -1912,6 +1914,8 @@ debuginfod_query_server_by_buildid (debuginfod_client *c,
target_cache_path: $HOME/.cache/0123abcd/debuginfo
target_cache_path: $HOME/.cache/0123abcd/executable-.debug_info
target_cache_path: $HOME/.cache/0123abcd/source-HASH-#PATH#TO#SOURCE
+ target_cachehdr_path: $HOME/.cache/0123abcd/hdr-debuginfo
+ target_cachehdr_path: $HOME/.cache/0123abcd/hdr-executable...
*/
cache_path = make_cache_path();
@@ -1923,11 +1927,15 @@ debuginfod_query_server_by_buildid (debuginfod_client
*c,
xalloc_str (target_cache_dir, "%s/%s", cache_path, build_id_bytes);
(void) mkdir (target_cache_dir, 0700); // failures with this mkdir would be
caught later too
- if (suffix[0] != '\0') /* section, source queries */
+ if (suffix[0] != '\0') { /* section, source queries */
xalloc_str (target_cache_path, "%s/%s-%s", target_cache_dir, type, suffix);
- else
+xalloc_str (target_cachehdr_path, "%s/hdr-%s-%s", target_cache_dir, type,
suffix);
+ } else {
xalloc_str (target_cache_path, "%s/%s", target_cache_dir, type);
+xalloc_str (target_cachehdr_path, "%s/hdr-%s", target_cache_dir, type);
+ }
xalloc_str (target_cache_tmppath, "%s.XX", target_cache_path);
+ xalloc_str (target_cachehdr_tmppath, "%s.XX", target_cachehdr_path);
/* XXX combine these */
xalloc_str (interval_path, "%s/%s", cache_path,
cache_clean_interval_filename);
@@ -1978,6 +1986,32 @@ debuginfod_query_server_by_buildid (debuginfod_client *c,
/* Success */
update_atime(fd);
rc = fd;
+
+ /* Attempt to transcribe saved headers. */
+ int fdh = open (target_cachehdr_path, O_RDONLY);
+ if (fdh >= 0)
+{
+ if (fstat (fdh, &st) == 0 && st.st_size > 0)
+{
+ c->winning_headers = malloc(st.st_size);
+ if (NULL != c->winning_headers)
+{
+ ssize_t bytes_read = pread_retry(fdh,
c->winning_headers, st.st_size, 0);
+ if (bytes_read <= 0)
+{
+ free (c->winning_headers);
+ c->winning_headers = NULL;
+ (void) unlink (target_cachehdr_path);
+}
+ if (vfd >= 0)
+dprintf (vfd, "