mirror of
https://github.com/systemd/systemd.git
synced 2025-05-29 01:05:59 +03:00
Use 'recommended' priority for the default compression library, to indicate that it should be prioritized over the other ones, as it will be used to compress journals/core files. Also use 'recommended' for kmod, as systems will likely fail to boot if it's missing from the initrd. Use 'suggested' for everything else. There is one dlopen'ed TPM library that has the name generated at runtime (depending on the driver), so that cannot be added, as it needs to be known at build time. Also when we support multiple ABI versions list them all, as for the same reason we cannot know which one will be used at build time. $ dlopen-notes.py build/libsystemd.so.0.39.0 build/src/shared/libsystemd-shared-256.so libarchive.so.13 suggested libbpf.so.0 suggested libbpf.so.1 suggested libcryptsetup.so.12 suggested libdw.so.1 suggested libelf.so.1 suggested libfido2.so.1 suggested libgcrypt.so.20 suggested libidn2.so.0 suggested libip4tc.so.2 suggested libkmod.so.2 recommended liblz4.so.1 suggested liblzma.so.5 suggested libp11-kit.so.0 suggested libpcre2-8.so.0 suggested libpwquality.so.1 suggested libqrencode.so.3 suggested libqrencode.so.4 suggested libtss2-esys.so.0 suggested libtss2-mu.so.0 suggested libtss2-rc.so.0 suggested libzstd.so.1 recommended Co-authored-by: Luca Boccassi <bluca@debian.org>
172 lines
6.1 KiB
C
172 lines
6.1 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
#include "dlfcn-util.h"
|
|
#include "log.h"
|
|
#include "pcre2-util.h"
|
|
|
|
#if HAVE_PCRE2
|
|
static void *pcre2_dl = NULL;
|
|
|
|
DLSYM_FUNCTION(pcre2_match_data_create);
|
|
DLSYM_FUNCTION(pcre2_match_data_free);
|
|
DLSYM_FUNCTION(pcre2_code_free);
|
|
DLSYM_FUNCTION(pcre2_compile);
|
|
DLSYM_FUNCTION(pcre2_get_error_message);
|
|
DLSYM_FUNCTION(pcre2_match);
|
|
DLSYM_FUNCTION(pcre2_get_ovector_pointer);
|
|
|
|
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
|
pcre2_code_hash_ops_free,
|
|
pcre2_code,
|
|
(void (*)(const pcre2_code *, struct siphash*))trivial_hash_func,
|
|
(int (*)(const pcre2_code *, const pcre2_code*))trivial_compare_func,
|
|
sym_pcre2_code_free);
|
|
#else
|
|
const struct hash_ops pcre2_code_hash_ops_free = {};
|
|
#endif
|
|
|
|
int dlopen_pcre2(void) {
|
|
#if HAVE_PCRE2
|
|
ELF_NOTE_DLOPEN("pcre2",
|
|
"Support for regular expressions",
|
|
ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
|
|
"libpcre2-8.so.0");
|
|
|
|
/* So here's something weird: PCRE2 actually renames the symbols exported by the library via C
|
|
* macros, so that the exported symbols carry a suffix "_8" but when used from C the suffix is
|
|
* gone. In the argument list below we ignore this mangling. Surprisingly (at least to me), we
|
|
* actually get away with that. That's because DLSYM_ARG() useses STRINGIFY() to generate a string
|
|
* version of the symbol name, and that resolves the macro mapping implicitly already, so that the
|
|
* string actually contains the "_8" suffix already due to that and we don't have to append it
|
|
* manually anymore. C is weird. 🤯 */
|
|
|
|
return dlopen_many_sym_or_warn(
|
|
&pcre2_dl, "libpcre2-8.so.0", LOG_ERR,
|
|
DLSYM_ARG(pcre2_match_data_create),
|
|
DLSYM_ARG(pcre2_match_data_free),
|
|
DLSYM_ARG(pcre2_code_free),
|
|
DLSYM_ARG(pcre2_compile),
|
|
DLSYM_ARG(pcre2_get_error_message),
|
|
DLSYM_ARG(pcre2_match),
|
|
DLSYM_ARG(pcre2_get_ovector_pointer));
|
|
#else
|
|
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "PCRE2 support is not compiled in.");
|
|
#endif
|
|
}
|
|
|
|
int pattern_compile_and_log(const char *pattern, PatternCompileCase case_, pcre2_code **ret) {
|
|
#if HAVE_PCRE2
|
|
PCRE2_SIZE erroroffset;
|
|
_cleanup_(sym_pcre2_code_freep) pcre2_code *p = NULL;
|
|
unsigned flags = 0;
|
|
int errorcode, r;
|
|
|
|
assert(pattern);
|
|
|
|
r = dlopen_pcre2();
|
|
if (r < 0)
|
|
return r;
|
|
|
|
if (case_ == PATTERN_COMPILE_CASE_INSENSITIVE)
|
|
flags = PCRE2_CASELESS;
|
|
else if (case_ == PATTERN_COMPILE_CASE_AUTO) {
|
|
_cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL;
|
|
bool has_case;
|
|
_cleanup_(sym_pcre2_code_freep) pcre2_code *cs = NULL;
|
|
|
|
md = sym_pcre2_match_data_create(1, NULL);
|
|
if (!md)
|
|
return log_oom();
|
|
|
|
r = pattern_compile_and_log("[[:upper:]]", PATTERN_COMPILE_CASE_SENSITIVE, &cs);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = sym_pcre2_match(cs, (PCRE2_SPTR8) pattern, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL);
|
|
has_case = r >= 0;
|
|
|
|
flags = !has_case * PCRE2_CASELESS;
|
|
}
|
|
|
|
log_debug("Doing case %s matching based on %s",
|
|
flags & PCRE2_CASELESS ? "insensitive" : "sensitive",
|
|
case_ != PATTERN_COMPILE_CASE_AUTO ? "request" : "pattern casing");
|
|
|
|
p = sym_pcre2_compile((PCRE2_SPTR8) pattern,
|
|
PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
|
|
if (!p) {
|
|
unsigned char buf[LINE_MAX];
|
|
|
|
r = sym_pcre2_get_error_message(errorcode, buf, sizeof buf);
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
"Bad pattern \"%s\": %s", pattern,
|
|
r < 0 ? "unknown error" : (char *)buf);
|
|
}
|
|
|
|
if (ret)
|
|
*ret = TAKE_PTR(p);
|
|
|
|
return 0;
|
|
#else
|
|
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "PCRE2 support is not compiled in.");
|
|
#endif
|
|
}
|
|
|
|
int pattern_matches_and_log(pcre2_code *compiled_pattern, const char *message, size_t size, size_t *ret_ovec) {
|
|
#if HAVE_PCRE2
|
|
_cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL;
|
|
int r;
|
|
|
|
assert(compiled_pattern);
|
|
assert(message);
|
|
/* pattern_compile_and_log() must be called before this function is called and that function already
|
|
* dlopens pcre2 so we can assert on it being available here. */
|
|
assert(pcre2_dl);
|
|
|
|
md = sym_pcre2_match_data_create(1, NULL);
|
|
if (!md)
|
|
return log_oom();
|
|
|
|
r = sym_pcre2_match(compiled_pattern,
|
|
(const unsigned char *)message,
|
|
size,
|
|
0, /* start at offset 0 in the subject */
|
|
0, /* default options */
|
|
md,
|
|
NULL);
|
|
if (r == PCRE2_ERROR_NOMATCH)
|
|
return false;
|
|
if (r < 0) {
|
|
unsigned char buf[LINE_MAX];
|
|
|
|
r = sym_pcre2_get_error_message(r, buf, sizeof(buf));
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Pattern matching failed: %s",
|
|
r < 0 ? "unknown error" : (char*) buf);
|
|
}
|
|
|
|
if (ret_ovec) {
|
|
ret_ovec[0] = sym_pcre2_get_ovector_pointer(md)[0];
|
|
ret_ovec[1] = sym_pcre2_get_ovector_pointer(md)[1];
|
|
}
|
|
|
|
return true;
|
|
#else
|
|
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "PCRE2 support is not compiled in.");
|
|
#endif
|
|
}
|
|
|
|
void *pattern_free(pcre2_code *p) {
|
|
#if HAVE_PCRE2
|
|
if (!p)
|
|
return NULL;
|
|
|
|
assert(pcre2_dl);
|
|
sym_pcre2_code_free(p);
|
|
return NULL;
|
|
#else
|
|
assert(p == NULL);
|
|
return NULL;
|
|
#endif
|
|
}
|