diff --git a/README b/README index b2c8d28411..4f4a21eeca 100644 --- 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) diff --git a/meson.build b/meson.build index 6c9299e27b..fef3c27cf4 100644 --- a/meson.build +++ b/meson.build @@ -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'], diff --git a/meson_options.txt b/meson_options.txt index 104a7ea043..0229179c99 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -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'], diff --git a/src/basic/build.h b/src/basic/build.h index c47e912eb0..d160af5bc7 100644 --- a/src/basic/build.h +++ b/src/basic/build.h @@ -87,6 +87,12 @@ #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 @@ -146,6 +152,7 @@ _ACL_FEATURE_ " " \ _XZ_FEATURE_ " " \ _LZ4_FEATURE_ " " \ + _ZSTD_FEATURE_ " " \ _SECCOMP_FEATURE_ " " \ _BLKID_FEATURE_ " " \ _ELFUTILS_FEATURE_ " " \ diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index b88b284584..ff4238c91d 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -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)) { diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index a848268177..60a02b770b 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -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); diff --git a/src/journal/compress.c b/src/journal/compress.c index 4e00e4fc5e..2bbfc7644a 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -16,6 +16,11 @@ #include #endif +#if HAVE_ZSTD +#include +#include +#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; } diff --git a/src/journal/compress.h b/src/journal/compress.h index 56411484ce..74ef592f43 100644 --- a/src/journal/compress.h +++ b/src/journal/compress.h @@ -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 diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c index 0b2898e109..c9d295b3c1 100644 --- a/src/journal/test-compress.c +++ b/src/journal/test-compress.c @@ -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 } diff --git a/src/shared/meson.build b/src/shared/meson.build index e608ea8a1d..41d214890c 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -329,6 +329,7 @@ libshared_deps = [threads, librt, libseccomp, libselinux, + libzstd, libxz] libshared_sym_path = '@0@/libshared.sym'.format(meson.current_source_dir()) diff --git a/src/test/meson.build b/src/test/meson.build index 7f96be8f55..b133980e45 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -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'],