diff --git a/man/journalctl.xml b/man/journalctl.xml
index 933d56a38e9..ff89fc50f8f 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -395,6 +395,10 @@
This parameter can be specified multiple times.
+ If the argument contains a shell-style glob, it is matched against the syslog identifiers
+ actually present in the journal, as for . If no glob matches anything, and
+ no exact identifier was given either, an error is returned.
+
@@ -407,6 +411,10 @@
This parameter can be specified multiple times.
+ If the argument contains a shell-style glob, it is matched against the syslog identifiers
+ actually present in the journal, as for . Patterns which do not match
+ anything are silently skipped.
+
diff --git a/src/journal/journalctl-filter.c b/src/journal/journalctl-filter.c
index 01c82ca4059..87922d98e0f 100644
--- a/src/journal/journalctl-filter.c
+++ b/src/journal/journalctl-filter.c
@@ -133,7 +133,7 @@ int journal_add_unit_matches(
if (!strv_isempty(patterns)) {
_cleanup_set_free_ Set *units = NULL;
- r = get_possible_units(j, SYSTEM_UNITS_FULL, patterns, &units);
+ r = get_possible_field_values(j, SYSTEM_UNITS_FULL, patterns, &units);
if (r < 0)
return r;
@@ -176,7 +176,7 @@ int journal_add_unit_matches(
if (!strv_isempty(patterns)) {
_cleanup_set_free_ Set *units = NULL;
- r = get_possible_units(j, USER_UNITS_FULL, patterns, &units);
+ r = get_possible_field_values(j, USER_UNITS_FULL, patterns, &units);
if (r < 0)
return r;
@@ -217,6 +217,8 @@ static int add_units(sd_journal *j) {
}
static int add_syslog_identifier(sd_journal *j) {
+ _cleanup_strv_free_ char **patterns = NULL;
+ bool added = false;
int r;
assert(j);
@@ -225,26 +227,83 @@ static int add_syslog_identifier(sd_journal *j) {
return 0;
STRV_FOREACH(i, arg_syslog_identifier) {
+ if (string_is_glob(*i)) {
+ r = strv_extend(&patterns, *i);
+ if (r < 0)
+ return r;
+ continue;
+ }
+
r = journal_add_match_pair(j, "SYSLOG_IDENTIFIER", *i);
if (r < 0)
return r;
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
+ added = true;
}
+ if (!strv_isempty(patterns)) {
+ _cleanup_set_free_ Set *identifiers = NULL;
+
+ r = get_possible_field_values(j, "SYSLOG_IDENTIFIER\0", patterns, &identifiers);
+ if (r < 0)
+ return r;
+
+ const char *id;
+ SET_FOREACH(id, identifiers) {
+ r = journal_add_match_pair(j, "SYSLOG_IDENTIFIER", id);
+ if (r < 0)
+ return r;
+ r = sd_journal_add_disjunction(j);
+ if (r < 0)
+ return r;
+ added = true;
+ }
+ }
+
+ /* Complain if the user asked for identifiers but nothing whatsoever was found, since otherwise
+ * everything would be matched. Same as for --unit=. */
+ if (!added)
+ return -ENODATA;
+
return sd_journal_add_conjunction(j);
}
static int add_exclude_identifier(sd_journal *j) {
+ _cleanup_strv_free_ char **patterns = NULL;
_cleanup_set_free_ Set *excludes = NULL;
int r;
assert(j);
- r = set_put_strdupv(&excludes, arg_exclude_identifier);
- if (r < 0)
- return r;
+ STRV_FOREACH(i, arg_exclude_identifier) {
+ if (string_is_glob(*i)) {
+ r = strv_extend(&patterns, *i);
+ if (r < 0)
+ return r;
+ continue;
+ }
+
+ r = set_put_strdup(&excludes, *i);
+ if (r < 0)
+ return r;
+ }
+
+ if (!strv_isempty(patterns)) {
+ _cleanup_set_free_ Set *found = NULL;
+
+ r = get_possible_field_values(j, "SYSLOG_IDENTIFIER\0", patterns, &found);
+ if (r < 0)
+ return r;
+
+ const char *id;
+ SET_FOREACH(id, found) {
+ r = set_put_strdup(&excludes, id);
+ if (r < 0)
+ return r;
+ }
+ }
return set_free_and_replace(j->exclude_syslog_identifiers, excludes);
}
diff --git a/src/journal/journalctl-util.c b/src/journal/journalctl-util.c
index aedb2da20dc..18d250a868e 100644
--- a/src/journal/journalctl-util.c
+++ b/src/journal/journalctl-util.c
@@ -128,7 +128,7 @@ int journal_acquire_boot(sd_journal *j) {
return 1;
}
-int get_possible_units(
+int get_possible_field_values(
sd_journal *j,
const char *fields,
char * const *patterns,
@@ -163,10 +163,12 @@ int get_possible_units(
return -ENOMEM;
size_t i;
- if (!strv_fnmatch_full(patterns, u, FNM_NOESCAPE, &i))
+ /* Unlike unit names, values such as SYSLOG_IDENTIFIER= may legitimately contain
+ * '*', '?' or '[', so an exact match must count too. */
+ if (!strv_fnmatch_full(patterns, u, FNM_NOESCAPE, &i) && !strv_contains(patterns, u))
continue;
- log_debug("Matched %s with pattern %s=%s", u, field, patterns[i]);
+ log_debug("Matched %s with pattern %s=%s", u, field, i == SIZE_MAX ? u : patterns[i]);
r = set_ensure_consume(&found, &string_hash_ops_free, TAKE_PTR(u));
if (r < 0)
return r;
@@ -215,7 +217,7 @@ int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit,
if (string_is_glob(u)) {
_cleanup_set_free_ Set *s = NULL;
- r = get_possible_units(j, type == LOG_SYSTEM_UNIT_INVOCATION_ID ? SYSTEM_UNITS : USER_UNITS,
+ r = get_possible_field_values(j, type == LOG_SYSTEM_UNIT_INVOCATION_ID ? SYSTEM_UNITS : USER_UNITS,
STRV_MAKE(u), &s);
if (r < 0)
return log_error_errno(r, "Failed to get matching unit '%s' from journal: %m", u);
diff --git a/src/journal/journalctl-util.h b/src/journal/journalctl-util.h
index 4571c285408..07c7c17102b 100644
--- a/src/journal/journalctl-util.h
+++ b/src/journal/journalctl-util.h
@@ -30,6 +30,6 @@ char* format_timestamp_maybe_utc(char *buf, size_t l, usec_t t);
int acquire_journal(sd_journal **ret);
bool journal_boot_has_effect(sd_journal *j);
int journal_acquire_boot(sd_journal *j);
-int get_possible_units(sd_journal *j, const char *fields, char * const *patterns, Set **ret);
+int get_possible_field_values(sd_journal *j, const char *fields, char * const *patterns, Set **ret);
int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type);
int journal_acquire_invocation(sd_journal *j);