diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h
index e31151211..cb3155a02 100644
--- a/include/haproxy/tools.h
+++ b/include/haproxy/tools.h
@@ -1148,6 +1148,7 @@ int may_access(const void *ptr);
const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *addr);
const void *resolve_dso_name(struct buffer *buf, const char *pfx, const void *addr);
void make_tar_header(char *output, const char *pfx, const char *fname, const char *link, size_t size, mode_t mode);
+int load_file_into_tar(char **storage, size_t *size, const char *pfx, const char *fname, const char *input, const char *link);
const char *get_exec_path(void);
void *get_sym_curr_addr(const char *name);
void *get_sym_next_addr(const char *name);
diff --git a/src/tools.c b/src/tools.c
index 5ad0c95ae..f6e493e9e 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -5874,6 +5874,86 @@ void make_tar_header(char *output, const char *pfx, const char *fname, const cha
memcpy(output, &blk, sizeof(blk));
}
+/* appends file into the tar file at location and size
+ * . The file's location in the archive will appear at /. If
+ * is NULL, no prefix is inserted. Note that must not end with a
+ * slash. If is NULL, then the basename of is used. If
+ * is NULL, then is used. The two may not be NULL simultaneously. An
+ * optional tag (100 chars max) may be added if not NULL. The file's
+ * mode is set with just r/x depending on what was present, or zero in case of
+ * open error (so as to keep trace of the attempt to load the file). Returns 0
+ * on success, non-zero with errno set on error.
+ */
+int load_file_into_tar(char **storage, size_t *size, const char *pfx, const char *fname, const char *input, const char *link)
+{
+ size_t alloc_size;
+ ssize_t fsize = 0;
+ struct stat buf;
+ ssize_t ret = -1;
+ mode_t mode;
+ int fd = -1;
+ char *ptr;
+
+ if (!input)
+ input = fname;
+ else if (!fname) {
+ fname = strrchr(input, '/');
+ if (!fname++)
+ fname = input;
+ }
+
+ /* do not concatenate slashes */
+ if (*fname == '/')
+ fname++;
+
+ if (stat(input, &buf) != 0)
+ goto leave;
+
+ fsize = buf.st_size;
+
+ /* only keep read and exec */
+ mode = buf.st_mode;
+ if (mode & 0111)
+ mode |= 0111;
+ if (mode & 0444)
+ mode |= 0444;
+ mode &= 0555;
+
+ /* Open the file. In case of failure, we'll still create an entry of
+ * size zero to indicate that we tried to read this file.
+ */
+ fd = open(input, O_RDONLY);
+ if (fd < 0) {
+ fsize = 0;
+ mode = 0;
+ }
+
+ /* we need one 512B block for the header + as many 512B blocks as
+ * needed for the file.
+ */
+ alloc_size = (fsize + 512 + 511) & -512;
+ ptr = realloc(*storage, *size + alloc_size);
+ if (!ptr)
+ goto leave;
+
+ *storage = ptr;
+ ptr += *size; // previous end
+ *size += alloc_size; // new end
+
+ make_tar_header(ptr, pfx, fname, link, fsize, mode);
+
+ ret = fsize ? read(fd, ptr + 512, fsize) : 0;
+ /* always pad with zeroes (complete of partial reads) */
+ if (ret < 0)
+ ret = 0;
+ memset(ptr + 512 + ret, 0, alloc_size - 512 - ret);
+
+ leave:
+ if (fd >= 0)
+ close(fd);
+ return ret == fsize ? 0 : 1;
+}
+
/* On systems where this is supported, let's provide a possibility to enumerate
* the list of object files. The output is appended to a buffer initialized by
* the caller, with one name per line. A trailing zero is always emitted if data