]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tools: add a function to load a file into a tar archive
authorWilly Tarreau <w@1wt.eu>
Wed, 18 Mar 2026 09:28:16 +0000 (10:28 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 18 Mar 2026 14:30:39 +0000 (15:30 +0100)
New function load_file_into_tar() concatenates a file into an in-memory
tar archive and grows its size. Only the base name and a provided prefix
are used to name the faile. If the file cannot be loaded, it's added as
size zero and permissions 0 to show that it failed to load. This will
be used to load post-mortem information so it needs to remain simple.

include/haproxy/tools.h
src/tools.c

index e311512119ecfd2b610bf802b4d3c14cb84fc16c..cb3155a0285dede8ace1a3945a682ad855957e26 100644 (file)
@@ -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);
index 5ad0c95aec239fabbd316335f2418097eb7f9fa8..f6e493e9ec3ebc3b8dc00b377ce1c815ef1f8523 100644 (file)
@@ -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 <input> into the tar file at location <storage> and size
+ * <size>. The file's location in the archive will appear at <pfx>/<fname>. If
+ * <pfx> is NULL, no prefix is inserted. Note that <pfx> must not end with a
+ * slash. If <fname> is NULL, then the basename of <input> is used. If <input>
+ * is NULL, then <fname> is used. The two may not be NULL simultaneously. An
+ * optional <link> 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