diff --git a/TODO b/TODO index c5abddc8a5..220caec35f 100644 --- a/TODO +++ b/TODO @@ -83,8 +83,6 @@ Features: * make us use dynamically fewer deps for containers in general purpose distros: o turn into dlopen() deps: - - pcre2 (always) — irrelevant on Fedora, since dep by - libselinux, but should benefit Debian - libpwquality (always) - only relevant for homed, and maybe soon firstboot - elfutils (always) diff --git a/meson.build b/meson.build index e4c95c9c32..134e95d475 100644 --- a/meson.build +++ b/meson.build @@ -1802,8 +1802,8 @@ public_programs += executable( libdl, libxz, liblz4, - libpcre2, - libzstd], + libzstd, + libdl], install_rpath : rootlibexecdir, install : true, install_dir : rootbindir) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 5a56a990f9..79daa43494 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -56,6 +56,7 @@ #include "pager.h" #include "parse-util.h" #include "path-util.h" +#include "pcre2-dlopen.h" #include "pretty-print.h" #include "random-util.h" #include "rlimit-util.h" @@ -161,20 +162,20 @@ typedef struct BootId { } BootId; #if HAVE_PCRE2 -DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, pcre2_match_data_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, pcre2_code_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, sym_pcre2_match_data_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, sym_pcre2_code_free); static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out) { int errorcode, r; PCRE2_SIZE erroroffset; pcre2_code *p; - p = pcre2_compile((PCRE2_SPTR8) pattern, - PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL); + p = sym_pcre2_compile((PCRE2_SPTR8) pattern, + PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL); if (!p) { unsigned char buf[LINE_MAX]; - r = pcre2_get_error_message(errorcode, buf, sizeof buf); + r = sym_pcre2_get_error_message(errorcode, buf, sizeof buf); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad pattern \"%s\": %s", pattern, @@ -184,7 +185,6 @@ static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out *out = p; return 0; } - #endif static int add_matches_for_device(sd_journal *j, const char *devpath) { @@ -1088,14 +1088,18 @@ static int parse_argv(int argc, char *argv[]) { if (arg_pattern) { unsigned flags; + r = dlopen_pcre2(); + if (r < 0) + return r; + if (arg_case_sensitive >= 0) flags = !arg_case_sensitive * PCRE2_CASELESS; else { - _cleanup_(pcre2_match_data_freep) pcre2_match_data *md = NULL; + _cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL; bool has_case; - _cleanup_(pcre2_code_freep) pcre2_code *cs = NULL; + _cleanup_(sym_pcre2_code_freep) pcre2_code *cs = NULL; - md = pcre2_match_data_create(1, NULL); + md = sym_pcre2_match_data_create(1, NULL); if (!md) return log_oom(); @@ -1103,7 +1107,7 @@ static int parse_argv(int argc, char *argv[]) { if (r < 0) return r; - r = pcre2_match(cs, (PCRE2_SPTR8) arg_pattern, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL); + r = sym_pcre2_match(cs, (PCRE2_SPTR8) arg_pattern, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL); has_case = r >= 0; flags = !has_case * PCRE2_CASELESS; @@ -2607,12 +2611,12 @@ int main(int argc, char *argv[]) { #if HAVE_PCRE2 if (arg_compiled_pattern) { - _cleanup_(pcre2_match_data_freep) pcre2_match_data *md = NULL; + _cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL; const void *message; size_t len; PCRE2_SIZE *ovec; - md = pcre2_match_data_create(1, NULL); + md = sym_pcre2_match_data_create(1, NULL); if (!md) return log_oom(); @@ -2629,13 +2633,13 @@ int main(int argc, char *argv[]) { assert_se(message = startswith(message, "MESSAGE=")); - r = pcre2_match(arg_compiled_pattern, - message, - len - strlen("MESSAGE="), - 0, /* start at offset 0 in the subject */ - 0, /* default options */ - md, - NULL); + r = sym_pcre2_match(arg_compiled_pattern, + message, + len - strlen("MESSAGE="), + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + md, + NULL); if (r == PCRE2_ERROR_NOMATCH) { need_seek = true; continue; @@ -2644,14 +2648,14 @@ int main(int argc, char *argv[]) { unsigned char buf[LINE_MAX]; int r2; - r2 = pcre2_get_error_message(r, buf, sizeof buf); + r2 = sym_pcre2_get_error_message(r, buf, sizeof buf); log_error("Pattern matching failed: %s", r2 < 0 ? "unknown error" : (char*) buf); r = -EINVAL; goto finish; } - ovec = pcre2_get_ovector_pointer(md); + ovec = sym_pcre2_get_ovector_pointer(md); highlight[0] = ovec[0]; highlight[1] = ovec[1]; } @@ -2743,7 +2747,7 @@ finish: #if HAVE_PCRE2 if (arg_compiled_pattern) { - pcre2_code_free(arg_compiled_pattern); + sym_pcre2_code_free(arg_compiled_pattern); /* --grep was used, no error was thrown, but the pattern didn't * match anything. Let's mimic grep's behavior here and return diff --git a/src/journal/meson.build b/src/journal/meson.build index 5796f77cac..3a590bdc6c 100644 --- a/src/journal/meson.build +++ b/src/journal/meson.build @@ -101,7 +101,11 @@ journald_gperf_c = custom_target( systemd_cat_sources = files('cat.c') -journalctl_sources = files('journalctl.c') +journalctl_sources = files(''' + journalctl.c + pcre2-dlopen.c + pcre2-dlopen.h +'''.split()) if conf.get('HAVE_QRENCODE') == 1 journalctl_sources += files('journal-qrcode.c', diff --git a/src/journal/pcre2-dlopen.c b/src/journal/pcre2-dlopen.c new file mode 100644 index 0000000000..1e1108c657 --- /dev/null +++ b/src/journal/pcre2-dlopen.c @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "alloc-util.h" +#include "dlfcn-util.h" +#include "pcre2-dlopen.h" + +#if HAVE_PCRE2 +static void *pcre2_dl = NULL; + +pcre2_match_data* (*sym_pcre2_match_data_create)(uint32_t, pcre2_general_context *); +void (*sym_pcre2_match_data_free)(pcre2_match_data *); +void (*sym_pcre2_code_free)(pcre2_code *); +pcre2_code* (*sym_pcre2_compile)(PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_SIZE *, pcre2_compile_context *); +int (*sym_pcre2_get_error_message)(int, PCRE2_UCHAR *, PCRE2_SIZE); +int (*sym_pcre2_match)(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, pcre2_match_data *, pcre2_match_context *); +PCRE2_SIZE* (*sym_pcre2_get_ovector_pointer)(pcre2_match_data *); + +int dlopen_pcre2(void) { + _cleanup_(dlclosep) void *dl = NULL; + int r; + + if (pcre2_dl) + return 0; /* Already loaded */ + + dl = dlopen("libpcre2-8.so.0", RTLD_LAZY); + if (!dl) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "PCRE2 support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_ERR, + &sym_pcre2_match_data_create, "pcre2_match_data_create_8", + &sym_pcre2_match_data_free, "pcre2_match_data_free_8", + &sym_pcre2_code_free, "pcre2_code_free_8", + &sym_pcre2_compile, "pcre2_compile_8", + &sym_pcre2_get_error_message, "pcre2_get_error_message_8", + &sym_pcre2_match, "pcre2_match_8", + &sym_pcre2_get_ovector_pointer, "pcre2_get_ovector_pointer_8", + NULL); + if (r < 0) + return r; + + /* Note that we never release the reference here, because there's no real reason to, after all this + * was traditionally a regular shared library dependency which lives forever too. */ + pcre2_dl = TAKE_PTR(dl); + + return 1; +} + +#else + +int dlopen_pcre2(void) { + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "PCRE2 support is not compiled in."); +} +#endif diff --git a/src/journal/pcre2-dlopen.h b/src/journal/pcre2-dlopen.h new file mode 100644 index 0000000000..e7cb0a5907 --- /dev/null +++ b/src/journal/pcre2-dlopen.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#if HAVE_PCRE2 + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include + +extern pcre2_match_data* (*sym_pcre2_match_data_create)(uint32_t, pcre2_general_context *); +extern void (*sym_pcre2_match_data_free)(pcre2_match_data *); +extern void (*sym_pcre2_code_free)(pcre2_code *); +extern pcre2_code* (*sym_pcre2_compile)(PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_SIZE *, pcre2_compile_context *); +extern int (*sym_pcre2_get_error_message)(int, PCRE2_UCHAR *, PCRE2_SIZE); +extern int (*sym_pcre2_match)(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, pcre2_match_data *, pcre2_match_context *); +extern PCRE2_SIZE* (*sym_pcre2_get_ovector_pointer)(pcre2_match_data *); +#endif + +int dlopen_pcre2(void);