From 7bb1c8f2a30bf41c968059fab92c6296904910e2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 11 Dec 2024 09:35:32 +0900 Subject: [PATCH] journalctl: make --invocation and --list-invocations accept unit name with glob Previously, journalctl -I -u GLOB was not supported, while journalctl -u GLOB works fine. Let's make them consistent. --- src/journal/journalctl-misc.c | 4 ++-- src/journal/journalctl-util.c | 28 ++++++++++++++++++++---- src/journal/journalctl-util.h | 2 +- test/units/TEST-04-JOURNAL.invocation.sh | 10 ++++++++- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/journal/journalctl-misc.c b/src/journal/journalctl-misc.c index 3dea69d9fb3..46a70ae1ac5 100644 --- a/src/journal/journalctl-misc.c +++ b/src/journal/journalctl-misc.c @@ -246,11 +246,11 @@ int action_list_invocations(void) { assert(arg_action == ACTION_LIST_INVOCATIONS); - r = acquire_unit("--list-invocations", &unit, &type); + r = acquire_journal(&j); if (r < 0) return r; - r = acquire_journal(&j); + r = acquire_unit(j, "--list-invocations", &unit, &type); if (r < 0) return r; diff --git a/src/journal/journalctl-util.c b/src/journal/journalctl-util.c index 82ddb64f2b3..918e5713f6d 100644 --- a/src/journal/journalctl-util.c +++ b/src/journal/journalctl-util.c @@ -2,6 +2,7 @@ #include +#include "glob-util.h" #include "id128-util.h" #include "journal-util.h" #include "journalctl.h" @@ -163,10 +164,11 @@ int get_possible_units( return 0; } -int acquire_unit(const char *option_name, const char **ret_unit, LogIdType *ret_type) { +int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type) { size_t n; int r; + assert(j); assert(option_name); assert(ret_unit); assert(ret_type); @@ -193,11 +195,29 @@ int acquire_unit(const char *option_name, const char **ret_unit, LogIdType *ret_ } _cleanup_free_ char *u = NULL; - r = unit_name_mangle(units[0], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, &u); + r = unit_name_mangle(units[0], UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN), &u); if (r < 0) return log_error_errno(r, "Failed to mangle unit name '%s': %m", units[0]); - free_and_replace(units[0], u); + 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, + STRV_MAKE(u), &s); + if (r < 0) + return log_error_errno(r, "Failed to get matching unit '%s' from journal: %m", u); + if (set_isempty(s)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No matching unit found for '%s' in journal.", u); + if (set_size(s) > 1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple matching units found for '%s' in journal.", u); + + char *found = set_steal_first(s); + log_debug("Found matching unit '%s' for '%s'.", found, u); + + free_and_replace(units[0], found); + assert(set_isempty(s)); + } else + free_and_replace(units[0], u); *ret_type = type; *ret_unit = units[0]; @@ -225,7 +245,7 @@ int journal_acquire_invocation(sd_journal *j) { * system unit or user unit, and calling without unit name is allowed. Otherwise, a unit name must * be specified. */ if (arg_invocation_offset != 0 || sd_id128_is_null(arg_invocation_id)) { - r = acquire_unit("-I/--invocation= with an offset", &unit, &type); + r = acquire_unit(j, "-I/--invocation= with an offset", &unit, &type); if (r < 0) return r; } diff --git a/src/journal/journalctl-util.h b/src/journal/journalctl-util.h index 49a4d3e08b0..14cdfb51361 100644 --- a/src/journal/journalctl-util.h +++ b/src/journal/journalctl-util.h @@ -34,5 +34,5 @@ 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 acquire_unit(const char *option_name, const char **ret_unit, LogIdType *ret_type); +int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type); int journal_acquire_invocation(sd_journal *j); diff --git a/test/units/TEST-04-JOURNAL.invocation.sh b/test/units/TEST-04-JOURNAL.invocation.sh index 3ac931e2633..74db1040fdf 100755 --- a/test/units/TEST-04-JOURNAL.invocation.sh +++ b/test/units/TEST-04-JOURNAL.invocation.sh @@ -7,8 +7,10 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh -SERVICE_NAME_SHORT=invocation-id-test-"$RANDOM" +BASE=test-"$RANDOM" +SERVICE_NAME_SHORT=invocation-id-"$BASE" SERVICE_NAME="$SERVICE_NAME_SHORT".service +SERVICE_NAME_GLOB="invocation-*-${BASE}.service" TMP_DIR=$(mktemp -d) @@ -28,6 +30,7 @@ done journalctl --sync journalctl --list-invocation -u "$SERVICE_NAME_SHORT" | tee "$TMP_DIR"/short +journalctl --list-invocation -u "$SERVICE_NAME_GLOB" | tee "$TMP_DIR"/glob journalctl --list-invocation -u "$SERVICE_NAME" | tee "$TMP_DIR"/10 journalctl --list-invocation -u "$SERVICE_NAME" --reverse | tee "$TMP_DIR"/10-r journalctl --list-invocation -u "$SERVICE_NAME" -n +10 | tee "$TMP_DIR"/p10 @@ -47,6 +50,7 @@ journalctl --list-invocation -u "$SERVICE_NAME" -n +5 --reverse | tee "$TMP_DIR" [[ $(cat "$TMP_DIR"/p5-r | wc -l) == 6 ]] diff "$TMP_DIR"/10 "$TMP_DIR"/short +diff "$TMP_DIR"/10 "$TMP_DIR"/glob diff <(tail -n 10 "$TMP_DIR"/10 | tac) <(tail -n 10 "$TMP_DIR"/10-r) diff <(tail -n 5 "$TMP_DIR"/10) <(tail -n 5 "$TMP_DIR"/5) diff <(tail -n 5 "$TMP_DIR"/10 | tac) <(tail -n 5 "$TMP_DIR"/5-r) @@ -59,6 +63,8 @@ tail -n 10 "$TMP_DIR"/10 | i="$(( idx + 10 ))" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${i}" -u "$SERVICE_NAME_SHORT")" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${idx}" -u "$SERVICE_NAME_SHORT")" + assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${i}" -u "$SERVICE_NAME_GLOB")" + assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${idx}" -u "$SERVICE_NAME_GLOB")" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${i}" -u "$SERVICE_NAME")" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${idx}" -u "$SERVICE_NAME")" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${invocation}")" @@ -69,6 +75,8 @@ tail -n 10 "$TMP_DIR"/p10 | idx="$(( i - 10 ))" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${i}" -u "$SERVICE_NAME_SHORT")" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${idx}" -u "$SERVICE_NAME_SHORT")" + assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${i}" -u "$SERVICE_NAME_GLOB")" + assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${idx}" -u "$SERVICE_NAME_GLOB")" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${i}" -u "$SERVICE_NAME")" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${idx}" -u "$SERVICE_NAME")" assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${invocation}")"