]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
coredump: add zstandard support for coredumps
authorNorbert Lange <nolange79@gmail.com>
Sat, 11 Apr 2020 23:09:05 +0000 (01:09 +0200)
committerNorbert Lange <nolange79@gmail.com>
Mon, 4 May 2020 08:59:43 +0000 (10:59 +0200)
this will hook libzstd into coredump,
using this format as default.

README
meson.build
meson_options.txt
src/basic/build.h
src/coredump/coredump.c
src/coredump/coredumpctl.c
src/journal/compress.c
src/journal/compress.h
src/journal/test-compress.c
src/shared/meson.build
src/test/meson.build

diff --git a/README b/README
index b2c8d28411f623ea4cdb5fa5416add16db8eeb43..4f4a21eeca7ea1e824542b3eda148d54ee88cfa8 100644 (file)
--- a/README
+++ b/README
@@ -150,6 +150,7 @@ REQUIREMENTS:
         libselinux (optional)
         liblzma (optional)
         liblz4 >= 1.3.0 / 130 (optional)
+        libzstd >= 1.4.0 (optional)
         libgcrypt (optional)
         libqrencode (optional)
         libmicrohttpd (optional)
index 6c9299e27b5b73b99ec84627ee6a496152283c95..fef3c27cf4d907fb6d9e2c7ab21ac323d3e74d97 100644 (file)
@@ -1195,6 +1195,18 @@ else
 endif
 conf.set10('HAVE_LZ4', have)
 
+want_zstd = get_option('zstd')
+if want_zstd != 'false' and not skip_deps
+        libzstd = dependency('libzstd',
+                             required : want_zstd == 'true',
+                             version : '>= 1.4.0')
+        have = libzstd.found()
+else
+        have = false
+        libzstd = []
+endif
+conf.set10('HAVE_ZSTD', have)
+
 want_xkbcommon = get_option('xkbcommon')
 if want_xkbcommon != 'false' and not skip_deps
         libxkbcommon = dependency('xkbcommon',
@@ -1543,6 +1555,7 @@ libsystemd = shared_library(
         dependencies : [threads,
                         librt,
                         libxz,
+                        libzstd,
                         liblz4],
         link_depends : libsystemd_sym,
         install : true,
@@ -1566,6 +1579,7 @@ install_libsystemd_static = static_library(
         dependencies : [threads,
                         librt,
                         libxz,
+                        libzstd,
                         liblz4,
                         libcap,
                         libblkid,
@@ -1727,7 +1741,8 @@ executable(
         dependencies : [threads,
                         libxz,
                         liblz4,
-                        libselinux],
+                        libselinux,
+                        libzstd],
         install_rpath : rootlibexecdir,
         install : true,
         install_dir : rootlibexecdir)
@@ -1751,7 +1766,8 @@ public_programs += executable(
                         libqrencode,
                         libxz,
                         liblz4,
-                        libpcre2],
+                        libpcre2,
+                        libzstd],
         install_rpath : rootlibexecdir,
         install : true,
         install_dir : rootbindir)
@@ -1906,7 +1922,8 @@ if conf.get('ENABLE_LOGIND') == 1
                 link_with : [libshared],
                 dependencies : [threads,
                                 liblz4,
-                                libxz],
+                                libxz,
+                                libzstd],
                 install_rpath : rootlibexecdir,
                 install : true,
                 install_dir : rootbindir)
@@ -2036,7 +2053,8 @@ public_programs += executable(
                         libcap,
                         libselinux,
                         libxz,
-                        liblz4],
+                        liblz4,
+                        libzstd],
         install_rpath : rootlibexecdir,
         install : true,
         install_dir : rootbindir)
@@ -2386,7 +2404,8 @@ if conf.get('ENABLE_MACHINED') == 1
                 link_with : [libshared],
                 dependencies : [threads,
                                 libxz,
-                                liblz4],
+                                liblz4,
+                                libzstd],
                 install_rpath : rootlibexecdir,
                 install : true,
                 install_dir : rootbindir)
@@ -2467,7 +2486,8 @@ if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_LIBCURL') == 1
                                 libcurl,
                                 libgnutls,
                                 libxz,
-                                liblz4],
+                                liblz4,
+                                libzstd],
                 install_rpath : rootlibexecdir,
                 install : true,
                 install_dir : rootlibexecdir)
@@ -2484,7 +2504,8 @@ if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1
                                 libmicrohttpd,
                                 libgnutls,
                                 libxz,
-                                liblz4],
+                                liblz4,
+                                libzstd],
                 install_rpath : rootlibexecdir,
                 install : true,
                 install_dir : rootlibexecdir)
@@ -2498,7 +2519,8 @@ if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1
                                 libmicrohttpd,
                                 libgnutls,
                                 libxz,
-                                liblz4],
+                                liblz4,
+                                libzstd],
                 install_rpath : rootlibexecdir,
                 install : true,
                 install_dir : rootlibexecdir)
@@ -2514,7 +2536,8 @@ if conf.get('ENABLE_COREDUMP') == 1
                                 libacl,
                                 libdw,
                                 libxz,
-                                liblz4],
+                                liblz4,
+                                libzstd],
                 install_rpath : rootlibexecdir,
                 install : true,
                 install_dir : rootlibexecdir)
@@ -2526,7 +2549,8 @@ if conf.get('ENABLE_COREDUMP') == 1
                 link_with : [libshared],
                 dependencies : [threads,
                                 libxz,
-                                liblz4],
+                                liblz4,
+                                libzstd],
                 install_rpath : rootlibexecdir,
                 install : true)
 endif
@@ -2541,7 +2565,8 @@ if conf.get('ENABLE_PSTORE') == 1
                                 libacl,
                                 libdw,
                                 libxz,
-                                liblz4],
+                                liblz4,
+                                libzstd],
                 install_rpath : rootlibexecdir,
                 install : true,
                 install_dir : rootlibexecdir)
@@ -3496,6 +3521,7 @@ foreach tuple : [
         ['SMACK'],
         ['zlib'],
         ['xz'],
+        ['zstd'],
         ['lz4'],
         ['bzip2'],
         ['ACL'],
index 104a7ea04308dd5e8e79f7ca318d0db83185fc37..0229179c99cd8de5a75d292713a1d8b554859c21 100644 (file)
@@ -316,6 +316,8 @@ option('xz', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'xz compression support')
 option('lz4', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'lz4 compression support')
+option('zstd', type : 'combo', choices : ['auto', 'true', 'false'],
+       description : 'zstd compression support')
 option('xkbcommon', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'xkbcommon keymap support')
 option('pcre2', type : 'combo', choices : ['auto', 'true', 'false'],
index c47e912eb0ac4617de7bc2b03c148cfcda143224..d160af5bc7e6d7e6101c73d54853eb3c37270877 100644 (file)
 #define _LZ4_FEATURE_ "-LZ4"
 #endif
 
+#if HAVE_ZSTD
+#define _ZSTD_FEATURE_ "+ZSTD"
+#else
+#define _ZSTD_FEATURE_ "-ZSTD"
+#endif
+
 #if HAVE_SECCOMP
 #define _SECCOMP_FEATURE_ "+SECCOMP"
 #else
         _ACL_FEATURE_ " "                                               \
         _XZ_FEATURE_ " "                                                \
         _LZ4_FEATURE_ " "                                               \
+        _ZSTD_FEATURE_ " "                                              \
         _SECCOMP_FEATURE_ " "                                           \
         _BLKID_FEATURE_ " "                                             \
         _ELFUTILS_FEATURE_ " "                                          \
index b88b2845840c8b99511ac1b057538fb734959be7..ff4238c91d7e86b1530ade5679e7f8cf82f49451 100644 (file)
@@ -420,7 +420,7 @@ static int save_external_coredump(
                 goto fail;
         }
 
-#if HAVE_XZ || HAVE_LZ4
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
         /* If we will remove the coredump anyway, do not compress. */
         if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
 
index a848268177ae5558ce5ab7974c4c274a894de24f..60a02b770bee060810b4fdf1a20e23eca343a82d 100644 (file)
@@ -765,7 +765,7 @@ static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp)
                 if (access(filename, R_OK) < 0)
                         return log_error_errno(errno, "File \"%s\" is not readable: %m", filename);
 
-                if (path && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) {
+                if (path && !ENDSWITH_SET(filename, ".xz", ".lz4", ".zst")) {
                         *path = TAKE_PTR(filename);
 
                         return 0;
@@ -824,7 +824,7 @@ static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp)
         }
 
         if (filename) {
-#if HAVE_XZ || HAVE_LZ4
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
                 _cleanup_close_ int fdf;
 
                 fdf = open(filename, O_RDONLY | O_CLOEXEC);
index 4e00e4fc5e721c07f922905abd03dce6b62abc02..2bbfc7644aed53c58d8d57bda085de47f5b03c33 100644 (file)
 #include <lz4frame.h>
 #endif
 
+#if HAVE_ZSTD
+#include <zstd.h>
+#include <zstd_errors.h>
+#endif
+
 #include "alloc-util.h"
 #include "compress.h"
 #include "fd-util.h"
@@ -33,6 +38,22 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionConte
 DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext);
 #endif
 
+#if HAVE_ZSTD
+DEFINE_TRIVIAL_CLEANUP_FUNC(ZSTD_CCtx *, ZSTD_freeCCtx);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ZSTD_DCtx *, ZSTD_freeDCtx);
+
+static int zstd_ret_to_errno(size_t ret) {
+        switch (ZSTD_getErrorCode(ret)) {
+        case ZSTD_error_dstSize_tooSmall:
+                return -ENOBUFS;
+        case ZSTD_error_memory_allocation:
+                return -ENOMEM;
+        default:
+                return -EBADMSG;
+        }
+}
+#endif
+
 #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
 
 static const char* const object_compressed_table[_OBJECT_COMPRESSED_MAX] = {
@@ -668,12 +689,230 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) {
 #endif
 }
 
+int compress_stream_zstd(int fdf, int fdt, uint64_t max_bytes) {
+#if HAVE_ZSTD
+        _cleanup_(ZSTD_freeCCtxp) ZSTD_CCtx *cctx = NULL;
+        _cleanup_free_ void *in_buff = NULL, *out_buff = NULL;
+        size_t in_allocsize, out_allocsize;
+        size_t z;
+        uint64_t left = max_bytes, in_bytes = 0;
+        /* This can be used in the future to add uncompressed size to the header */
+        uint64_t in_totalsize = 0;
+
+        assert(fdf >= 0);
+        assert(fdt >= 0);
+
+        /* Create the context and buffers */
+        in_allocsize = ZSTD_CStreamInSize();
+        out_allocsize = ZSTD_CStreamOutSize();
+        in_buff = malloc(in_allocsize);
+        out_buff = malloc(out_allocsize);
+        cctx = ZSTD_createCCtx();
+        if (!cctx || !out_buff || !in_buff)
+                return -ENOMEM;
+
+        if (in_totalsize) {
+                z = ZSTD_CCtx_setPledgedSrcSize(cctx, in_totalsize);
+                if (z)
+                        log_debug("Failed to enable ZSTD input size, ignoring: %s", ZSTD_getErrorName(z));
+        }
+        z = ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1);
+        if (ZSTD_isError(z))
+                log_debug("Failed to enable ZSTD checksum, ignoring: %s", ZSTD_getErrorName(z));
+
+        /* This loop read from the input file, compresses that entire chunk,
+         * and writes all output produced to the output file.
+         */
+        for (;;) {
+                bool is_last_chunk;
+                ZSTD_inBuffer input = {
+                        .src = in_buff,
+                        .size = 0,
+                        .pos = 0
+                };
+                ssize_t red;
+
+                red = loop_read(fdf, in_buff, in_allocsize, true);
+                if (red < 0)
+                        return red;
+                is_last_chunk = red == 0;
+
+                in_bytes += (size_t) red;
+                input.size = (size_t) red;
+
+                for (bool finished = false; !finished;) {
+                        ZSTD_outBuffer output = {
+                                .dst = out_buff,
+                                .size = out_allocsize,
+                                .pos = 0
+                        };
+                        size_t remaining;
+                        ssize_t wrote;
+
+                        /* Compress into the output buffer and write all of the
+                         * output to the file so we can reuse the buffer next
+                         * iteration.
+                         */
+                        remaining = ZSTD_compressStream2(
+                                cctx, &output, &input,
+                                is_last_chunk ? ZSTD_e_end : ZSTD_e_continue);
+
+                        if (ZSTD_isError(remaining)) {
+                                log_debug("ZSTD encoder failed: %s", ZSTD_getErrorName(remaining));
+                                return zstd_ret_to_errno(remaining);
+                        }
+
+                        if (left < output.pos)
+                                return -EFBIG;
+
+                        wrote = loop_write(fdt, output.dst, output.pos, 1);
+                        if (wrote < 0)
+                                return wrote;
+
+                        left -= output.pos;
+
+                        /* If we're on the last chunk we're finished when zstd
+                         * returns 0, which means its consumed all the input AND
+                         * finished the frame. Otherwise, we're finished when
+                         * we've consumed all the input.
+                         */
+                        finished = is_last_chunk ? (remaining == 0) : (input.pos == input.size);
+                }
+
+                /* zstd only returns 0 when the input is completely consumed */
+                assert(input.pos == input.size);
+                if (is_last_chunk)
+                        break;
+        }
+
+        log_debug(
+                "ZSTD compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
+                in_bytes,
+                max_bytes - left,
+                (double) (max_bytes - left) / in_bytes * 100);
+
+        return 0;
+#else
+        return -EPROTONOSUPPORT;
+#endif
+}
+
+int decompress_stream_zstd(int fdf, int fdt, uint64_t max_bytes) {
+#if HAVE_ZSTD
+        _cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = NULL;
+        _cleanup_free_ void *in_buff = NULL, *out_buff = NULL;
+        size_t in_allocsize, out_allocsize;
+        size_t last_result = 0;
+        uint64_t left = max_bytes, in_bytes = 0;
+
+        assert(fdf >= 0);
+        assert(fdt >= 0);
+
+        /* Create the context and buffers */
+        in_allocsize = ZSTD_DStreamInSize();
+        out_allocsize = ZSTD_DStreamOutSize();
+        in_buff = malloc(in_allocsize);
+        out_buff = malloc(out_allocsize);
+        dctx = ZSTD_createDCtx();
+        if (!dctx || !out_buff || !in_buff)
+                return -ENOMEM;
+
+        /* This loop assumes that the input file is one or more concatenated
+         * zstd streams. This example won't work if there is trailing non-zstd
+         * data at the end, but streaming decompression in general handles this
+         * case. ZSTD_decompressStream() returns 0 exactly when the frame is
+         * completed, and doesn't consume input after the frame.
+         */
+        for (;;) {
+                bool has_error = false;
+                ZSTD_inBuffer input = {
+                        .src = in_buff,
+                        .size = 0,
+                        .pos = 0
+                };
+                ssize_t red;
+
+                red = loop_read(fdf, in_buff, in_allocsize, true);
+                if (red < 0)
+                        return red;
+                if (red == 0)
+                        break;
+
+                in_bytes += (size_t) red;
+                input.size = (size_t) red;
+                input.pos = 0;
+
+                /* Given a valid frame, zstd won't consume the last byte of the
+                 * frame until it has flushed all of the decompressed data of
+                 * the frame. So input.pos < input.size means frame is not done
+                 * or there is still output available.
+                 */
+                while (input.pos < input.size) {
+                        ZSTD_outBuffer output = {
+                                .dst = out_buff,
+                                .size = out_allocsize,
+                                .pos = 0
+                        };
+                        ssize_t wrote;
+                        /* The return code is zero if the frame is complete, but
+                         * there may be multiple frames concatenated together.
+                         * Zstd will automatically reset the context when a
+                         * frame is complete. Still, calling ZSTD_DCtx_reset()
+                         * can be useful to reset the context to a clean state,
+                         * for instance if the last decompression call returned
+                         * an error.
+                         */
+                        last_result = ZSTD_decompressStream(dctx, &output, &input);
+                        if (ZSTD_isError(last_result)) {
+                                has_error = true;
+                                break;
+                        }
+
+                        if (left < output.pos)
+                                return -EFBIG;
+
+                        wrote = loop_write(fdt, output.dst, output.pos, 1);
+                        if (wrote < 0)
+                                return wrote;
+
+                        left -= output.pos;
+                }
+                if (has_error)
+                        break;
+        }
+
+        if (in_bytes == 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "ZSTD decoder failed: no data read");
+
+        if (last_result != 0) {
+                /* The last return value from ZSTD_decompressStream did not end
+                 * on a frame, but we reached the end of the file! We assume
+                 * this is an error, and the input was truncated.
+                 */
+                log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(last_result));
+                return zstd_ret_to_errno(last_result);
+        }
+
+        log_debug(
+                "ZSTD decompression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
+                in_bytes,
+                max_bytes - left,
+                (double) (max_bytes - left) / in_bytes * 100);
+        return 0;
+#else
+        log_debug("Cannot decompress file. Compiled without ZSTD support.");
+        return -EPROTONOSUPPORT;
+#endif
+}
+
 int decompress_stream(const char *filename, int fdf, int fdt, uint64_t max_bytes) {
 
         if (endswith(filename, ".lz4"))
                 return decompress_stream_lz4(fdf, fdt, max_bytes);
         else if (endswith(filename, ".xz"))
                 return decompress_stream_xz(fdf, fdt, max_bytes);
+        else if (endswith(filename, ".zst"))
+                return decompress_stream_zstd(fdf, fdt, max_bytes);
         else
                 return -EPROTONOSUPPORT;
 }
index 56411484cee71acc7e448e274ea0d91488c1f395..74ef592f4374d8e74385af34d119f3fa657e0eba 100644 (file)
@@ -52,11 +52,16 @@ int decompress_startswith(int compression,
 
 int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes);
 int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes);
+int compress_stream_zstd(int fdf, int fdt, uint64_t max_bytes);
 
 int decompress_stream_xz(int fdf, int fdt, uint64_t max_size);
 int decompress_stream_lz4(int fdf, int fdt, uint64_t max_size);
+int decompress_stream_zstd(int fdf, int fdt, uint64_t max_size);
 
-#if HAVE_LZ4
+#if HAVE_ZSTD
+#  define compress_stream compress_stream_zstd
+#  define COMPRESSED_EXT ".zst"
+#elif HAVE_LZ4
 #  define compress_stream compress_stream_lz4
 #  define COMPRESSED_EXT ".lz4"
 #else
index 0b2898e10995ac265f79e2ee6db654e7b8a9ab64..c9d295b3c1cfa5e08ac0d768488fe9dd0a36b36b 100644 (file)
@@ -44,20 +44,20 @@ typedef int (decompress_sw_t)(const void *src, uint64_t src_size,
 typedef int (compress_stream_t)(int fdf, int fdt, uint64_t max_bytes);
 typedef int (decompress_stream_t)(int fdf, int fdt, uint64_t max_size);
 
-#if HAVE_XZ || HAVE_LZ4
-static void test_compress_decompress(int compression,
-                                     compress_blob_t compress,
-                                     decompress_blob_t decompress,
-                                     const char *data,
-                                     size_t data_len,
-                                     bool may_fail) {
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
+_unused_ static void test_compress_decompress(const char *compression,
+                                              compress_blob_t compress,
+                                              decompress_blob_t decompress,
+                                              const char *data,
+                                              size_t data_len,
+                                              bool may_fail) {
         char compressed[512];
         size_t csize, usize = 0;
         _cleanup_free_ char *decompressed = NULL;
         int r;
 
         log_info("/* testing %s %s blob compression/decompression */",
-                 object_compressed_to_string(compression), data);
+                 compression, data);
 
         r = compress(data, data_len, compressed, sizeof(compressed), &csize);
         if (r == -ENOBUFS) {
@@ -88,12 +88,12 @@ static void test_compress_decompress(int compression,
         memzero(decompressed, usize);
 }
 
-static void test_decompress_startswith(int compression,
-                                       compress_blob_t compress,
-                                       decompress_sw_t decompress_sw,
-                                       const char *data,
-                                       size_t data_len,
-                                       bool may_fail) {
+_unused_ static void test_decompress_startswith(const char *compression,
+                                                compress_blob_t compress,
+                                                decompress_sw_t decompress_sw,
+                                                const char *data,
+                                                size_t data_len,
+                                                bool may_fail) {
 
         char *compressed;
         _cleanup_free_ char *compressed1 = NULL, *compressed2 = NULL, *decompressed = NULL;
@@ -101,7 +101,7 @@ static void test_decompress_startswith(int compression,
         int r;
 
         log_info("/* testing decompress_startswith with %s on %.20s text */",
-                 object_compressed_to_string(compression), data);
+                 compression, data);
 
 #define BUFSIZE_1 512
 #define BUFSIZE_2 20000
@@ -136,9 +136,9 @@ static void test_decompress_startswith(int compression,
         assert_se(r > 0);
 }
 
-static void test_decompress_startswith_short(int compression,
-                                             compress_blob_t compress,
-                                             decompress_sw_t decompress_sw) {
+_unused_ static void test_decompress_startswith_short(const char *compression,
+                                                      compress_blob_t compress,
+                                                      decompress_sw_t decompress_sw) {
 
 #define TEXT "HUGE=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
 
@@ -146,7 +146,7 @@ static void test_decompress_startswith_short(int compression,
         size_t i, csize;
         int r;
 
-        log_info("/* %s with %s */", __func__, object_compressed_to_string(compression));
+        log_info("/* %s with %s */", __func__, compression);
 
         r = compress(TEXT, sizeof TEXT, buf, sizeof buf, &csize);
         assert_se(r == 0);
@@ -162,11 +162,11 @@ static void test_decompress_startswith_short(int compression,
         }
 }
 
-static void test_compress_stream(int compression,
-                                 const char* cat,
-                                 compress_stream_t compress,
-                                 decompress_stream_t decompress,
-                                 const char *srcfile) {
+_unused_ static void test_compress_stream(const char *compression,
+                                          const char *cat,
+                                          compress_stream_t compress,
+                                          decompress_stream_t decompress,
+                                          const char *srcfile) {
 
         _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
         _cleanup_(unlink_tempfilep) char
@@ -182,8 +182,7 @@ static void test_compress_stream(int compression,
                 return;
         }
 
-        log_debug("/* testing %s compression */",
-                  object_compressed_to_string(compression));
+        log_debug("/* testing %s compression */", compression);
 
         log_debug("/* create source from %s */", srcfile);
 
@@ -266,8 +265,8 @@ static void test_lz4_decompress_partial(void) {
 #endif
 
 int main(int argc, char *argv[]) {
-#if HAVE_XZ || HAVE_LZ4
-        const char text[] =
+#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD
+        _unused_ const char text[] =
                 "text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
                 "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
 
@@ -288,60 +287,67 @@ int main(int argc, char *argv[]) {
         random_bytes(data + 7, sizeof(data) - 7);
 
 #if HAVE_XZ
-        test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
+        test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
                                  text, sizeof(text), false);
-        test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
+        test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
                                  data, sizeof(data), true);
 
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
                                    text, sizeof(text), false);
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
                                    data, sizeof(data), true);
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
                                    huge, HUGE_SIZE, true);
 
-        test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat",
+        test_compress_stream("XZ", "xzcat",
                              compress_stream_xz, decompress_stream_xz, srcfile);
 
-        test_decompress_startswith_short(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_startswith_xz);
+        test_decompress_startswith_short("XZ", compress_blob_xz, decompress_startswith_xz);
 
 #else
         log_info("/* XZ test skipped */");
 #endif
 
 #if HAVE_LZ4
-        test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
+        test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
                                  text, sizeof(text), false);
-        test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
+        test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
                                  data, sizeof(data), true);
 
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    text, sizeof(text), false);
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    data, sizeof(data), true);
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    huge, HUGE_SIZE, true);
 
-        test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
+        test_compress_stream("LZ4", "lz4cat",
                              compress_stream_lz4, decompress_stream_lz4, srcfile);
 
         test_lz4_decompress_partial();
 
-        test_decompress_startswith_short(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_startswith_lz4);
+        test_decompress_startswith_short("LZ4", compress_blob_lz4, decompress_startswith_lz4);
 
 #else
         log_info("/* LZ4 test skipped */");
 #endif
 
+#if HAVE_ZSTD
+        test_compress_stream("ZSTD", "zstdcat",
+                             compress_stream_zstd, decompress_stream_zstd, srcfile);
+#else
+        log_info("/* ZSTD test skipped */");
+#endif
+
         return 0;
 #else
-        log_info("/* XZ and LZ4 tests skipped */");
+        log_info("/* XZ, LZ4 and ZSTD tests skipped */");
         return EXIT_TEST_SKIP;
 #endif
 }
index e608ea8a1da59a17485da72d58b20231a49b1682..41d214890c58bc5bbb82d8bc7d2905b7d59dcaa2 100644 (file)
@@ -329,6 +329,7 @@ libshared_deps = [threads,
                   librt,
                   libseccomp,
                   libselinux,
+                  libzstd,
                   libxz]
 
 libshared_sym_path = '@0@/libshared.sym'.format(meson.current_source_dir())
index 7f96be8f55afabe88f0f0e4093e57bf5321858d6..b133980e4592f3c47380dbfc227d67119c20ad72 100644 (file)
@@ -893,12 +893,14 @@ tests += [
          [libjournal_core,
           libshared],
          [liblz4,
+          libzstd,
           libxz]],
 
         [['src/journal/test-compress-benchmark.c'],
          [libjournal_core,
           libshared],
          [liblz4,
+          libzstd,
           libxz],
          '', 'timeout=90'],