journalctl: Accept globs in --{exclude-,}identifier=

--unit= has accepted globs for a long time, let's bring --identifier= up
to parity.

Closes: #20457
This commit is contained in:
Chris Down committed 2026-10-26 21:18:31 +08:00
1 parent 80f70d2af6
commit 8a125ff7b3
4 files changed
+79 -10

No files matched your search

+8
View File
@@ -395,6 +395,10 @@
<para>This parameter can be specified multiple times.</para>
<para>If the argument contains a shell-style glob, it is matched against the syslog identifiers
actually present in the journal, as for <option>--unit=</option>. If no glob matches anything, and
no exact identifier was given either, an error is returned.</para>
<xi:include href="version-info.xml" xpointer="v217"/></listitem>
</varlistentry>
@@ -407,6 +411,10 @@
<para>This parameter can be specified multiple times.</para>
<para>If the argument contains a shell-style glob, it is matched against the syslog identifiers
actually present in the journal, as for <option>--identifier=</option>. Patterns which do not match
anything are silently skipped.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
+64 -5
View File
@@ -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);
}
+6 -4
View File
@@ -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);
+1 -1
View File
@@ -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);