1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "dlfcn-util.h"
5 #include "pcre2-util.h"
8 static void *pcre2_dl
= NULL
;
10 pcre2_match_data
* (*sym_pcre2_match_data_create
)(uint32_t, pcre2_general_context
*);
11 void (*sym_pcre2_match_data_free
)(pcre2_match_data
*);
12 void (*sym_pcre2_code_free
)(pcre2_code
*);
13 pcre2_code
* (*sym_pcre2_compile
)(PCRE2_SPTR
, PCRE2_SIZE
, uint32_t, int *, PCRE2_SIZE
*, pcre2_compile_context
*);
14 int (*sym_pcre2_get_error_message
)(int, PCRE2_UCHAR
*, PCRE2_SIZE
);
15 int (*sym_pcre2_match
)(const pcre2_code
*, PCRE2_SPTR
, PCRE2_SIZE
, PCRE2_SIZE
, uint32_t, pcre2_match_data
*, pcre2_match_context
*);
16 PCRE2_SIZE
* (*sym_pcre2_get_ovector_pointer
)(pcre2_match_data
*);
18 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
19 pcre2_code_hash_ops_free
,
21 (void (*)(const pcre2_code
*, struct siphash
*))trivial_hash_func
,
22 (int (*)(const pcre2_code
*, const pcre2_code
*))trivial_compare_func
,
25 const struct hash_ops pcre2_code_hash_ops_free
= {};
28 int dlopen_pcre2(void) {
30 /* So here's something weird: PCRE2 actually renames the symbols exported by the library via C
31 * macros, so that the exported symbols carry a suffix "_8" but when used from C the suffix is
32 * gone. In the argument list below we ignore this mangling. Surprisingly (at least to me), we
33 * actually get away with that. That's because DLSYM_ARG() useses STRINGIFY() to generate a string
34 * version of the symbol name, and that resolves the macro mapping implicitly already, so that the
35 * string actually contains the "_8" suffix already due to that and we don't have to append it
36 * manually anymore. C is weird. 🤯 */
38 return dlopen_many_sym_or_warn(
39 &pcre2_dl
, "libpcre2-8.so.0", LOG_ERR
,
40 DLSYM_ARG(pcre2_match_data_create
),
41 DLSYM_ARG(pcre2_match_data_free
),
42 DLSYM_ARG(pcre2_code_free
),
43 DLSYM_ARG(pcre2_compile
),
44 DLSYM_ARG(pcre2_get_error_message
),
45 DLSYM_ARG(pcre2_match
),
46 DLSYM_ARG(pcre2_get_ovector_pointer
));
48 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "PCRE2 support is not compiled in.");
52 int pattern_compile_and_log(const char *pattern
, PatternCompileCase case_
, pcre2_code
**ret
) {
54 PCRE2_SIZE erroroffset
;
55 _cleanup_(sym_pcre2_code_freep
) pcre2_code
*p
= NULL
;
65 if (case_
== PATTERN_COMPILE_CASE_INSENSITIVE
)
66 flags
= PCRE2_CASELESS
;
67 else if (case_
== PATTERN_COMPILE_CASE_AUTO
) {
68 _cleanup_(sym_pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
70 _cleanup_(sym_pcre2_code_freep
) pcre2_code
*cs
= NULL
;
72 md
= sym_pcre2_match_data_create(1, NULL
);
76 r
= pattern_compile_and_log("[[:upper:]]", PATTERN_COMPILE_CASE_SENSITIVE
, &cs
);
80 r
= sym_pcre2_match(cs
, (PCRE2_SPTR8
) pattern
, PCRE2_ZERO_TERMINATED
, 0, 0, md
, NULL
);
83 flags
= !has_case
* PCRE2_CASELESS
;
86 log_debug("Doing case %s matching based on %s",
87 flags
& PCRE2_CASELESS
? "insensitive" : "sensitive",
88 case_
!= PATTERN_COMPILE_CASE_AUTO
? "request" : "pattern casing");
90 p
= sym_pcre2_compile((PCRE2_SPTR8
) pattern
,
91 PCRE2_ZERO_TERMINATED
, flags
, &errorcode
, &erroroffset
, NULL
);
93 unsigned char buf
[LINE_MAX
];
95 r
= sym_pcre2_get_error_message(errorcode
, buf
, sizeof buf
);
97 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
98 "Bad pattern \"%s\": %s", pattern
,
99 r
< 0 ? "unknown error" : (char *)buf
);
107 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "PCRE2 support is not compiled in.");
111 int pattern_matches_and_log(pcre2_code
*compiled_pattern
, const char *message
, size_t size
, size_t *ret_ovec
) {
113 _cleanup_(sym_pcre2_match_data_freep
) pcre2_match_data
*md
= NULL
;
116 assert(compiled_pattern
);
118 /* pattern_compile_and_log() must be called before this function is called and that function already
119 * dlopens pcre2 so we can assert on it being available here. */
122 md
= sym_pcre2_match_data_create(1, NULL
);
126 r
= sym_pcre2_match(compiled_pattern
,
127 (const unsigned char *)message
,
129 0, /* start at offset 0 in the subject */
130 0, /* default options */
133 if (r
== PCRE2_ERROR_NOMATCH
)
136 unsigned char buf
[LINE_MAX
];
138 r
= sym_pcre2_get_error_message(r
, buf
, sizeof(buf
));
139 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Pattern matching failed: %s",
140 r
< 0 ? "unknown error" : (char*) buf
);
144 ret_ovec
[0] = sym_pcre2_get_ovector_pointer(md
)[0];
145 ret_ovec
[1] = sym_pcre2_get_ovector_pointer(md
)[1];
150 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "PCRE2 support is not compiled in.");
154 void *pattern_free(pcre2_code
*p
) {
160 sym_pcre2_code_free(p
);