summaryrefslogtreecommitdiff
path: root/src/shared/pcre2-util.c
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2022-07-22 14:49:42 +0200
committerDaan De Meyer <daan.j.demeyer@gmail.com>2022-07-25 14:16:17 +0200
commit75db32dcd810cb6f4bc0148c3e280c5c04203491 (patch)
treed200b732eeae976392e8c64ac87782ecaa0f022e /src/shared/pcre2-util.c
parent05abe850330fdef145d8d45d5a2e33d76a0a8d21 (diff)
downloadsystemd-75db32dcd810cb6f4bc0148c3e280c5c04203491.tar.gz
journal: Move more pattern matching logic into pcre2-util
To avoid having "#if HAVE_PCRE2" all throughout the code, let's confine the pcre2 header specific stuff to pcre2-util.c. Instead of exposing all the individual symbols from pcre2, let's only expose three high level functions that do all we need: - pcre2_pattern_compile(): Compile the regex - pcre2_pattern_matches(): Check if the compiled regex matches a message - pcre2_pattern_free(): Free the compiled regex We expose the compiled pcre2 pattern (which is of type pcre2_code *) as a void pointer to avoid having to include pcre2.h in all code where we work with compiled pcre2 patterns. For readability, we typedef void to pcre2_pattern and use that as the type specifier for compiled pcre2 patterns.
Diffstat (limited to 'src/shared/pcre2-util.c')
-rw-r--r--src/shared/pcre2-util.c119
1 files changed, 116 insertions, 3 deletions
diff --git a/src/shared/pcre2-util.c b/src/shared/pcre2-util.c
index 80f6cec342..998dab0491 100644
--- a/src/shared/pcre2-util.c
+++ b/src/shared/pcre2-util.c
@@ -14,8 +14,10 @@ pcre2_code* (*sym_pcre2_compile)(PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_
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 *);
+#endif
int dlopen_pcre2(void) {
+#if HAVE_PCRE2
/* 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
@@ -33,12 +35,123 @@ int dlopen_pcre2(void) {
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;
+ pcre2_code *p;
+ 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 = p;
+
+ return 0;
#else
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "PCRE2 support is not compiled in.");
+#endif
+}
-int dlopen_pcre2(void) {
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
- "PCRE2 support is not compiled in.");
+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
+}