mirror of
https://github.com/systemd/systemd.git
synced 2025-01-25 10:04:04 +03:00
journalctl: also mangle unit name when --invocation= or --list-invocations is specified (#35542)
Fixes #35538.
This commit is contained in:
commit
c9011f170b
@ -12,7 +12,6 @@
|
|||||||
#include "journalctl-util.h"
|
#include "journalctl-util.h"
|
||||||
#include "logs-show.h"
|
#include "logs-show.h"
|
||||||
#include "missing_sched.h"
|
#include "missing_sched.h"
|
||||||
#include "nulstr-util.h"
|
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "unit-name.h"
|
#include "unit-name.h"
|
||||||
|
|
||||||
@ -65,73 +64,6 @@ static int add_dmesg(sd_journal *j) {
|
|||||||
return sd_journal_add_conjunction(j);
|
return sd_journal_add_conjunction(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_possible_units(
|
|
||||||
sd_journal *j,
|
|
||||||
const char *fields,
|
|
||||||
char **patterns,
|
|
||||||
Set **ret) {
|
|
||||||
|
|
||||||
_cleanup_set_free_ Set *found = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(j);
|
|
||||||
assert(fields);
|
|
||||||
assert(ret);
|
|
||||||
|
|
||||||
NULSTR_FOREACH(field, fields) {
|
|
||||||
const void *data;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
r = sd_journal_query_unique(j, field);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
|
|
||||||
_cleanup_free_ char *u = NULL;
|
|
||||||
char *eq;
|
|
||||||
|
|
||||||
eq = memchr(data, '=', size);
|
|
||||||
if (eq) {
|
|
||||||
size -= eq - (char*) data + 1;
|
|
||||||
data = ++eq;
|
|
||||||
}
|
|
||||||
|
|
||||||
u = strndup(data, size);
|
|
||||||
if (!u)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
if (!strv_fnmatch_full(patterns, u, FNM_NOESCAPE, &i))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
log_debug("Matched %s with pattern %s=%s", u, field, patterns[i]);
|
|
||||||
r = set_ensure_consume(&found, &string_hash_ops_free, TAKE_PTR(u));
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*ret = TAKE_PTR(found);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This list is supposed to return the superset of unit names
|
|
||||||
* possibly matched by rules added with add_matches_for_unit... */
|
|
||||||
#define SYSTEM_UNITS \
|
|
||||||
"_SYSTEMD_UNIT\0" \
|
|
||||||
"COREDUMP_UNIT\0" \
|
|
||||||
"UNIT\0" \
|
|
||||||
"OBJECT_SYSTEMD_UNIT\0" \
|
|
||||||
"_SYSTEMD_SLICE\0"
|
|
||||||
|
|
||||||
/* ... and add_matches_for_user_unit */
|
|
||||||
#define USER_UNITS \
|
|
||||||
"_SYSTEMD_USER_UNIT\0" \
|
|
||||||
"USER_UNIT\0" \
|
|
||||||
"COREDUMP_USER_UNIT\0" \
|
|
||||||
"OBJECT_SYSTEMD_USER_UNIT\0" \
|
|
||||||
"_SYSTEMD_USER_SLICE\0"
|
|
||||||
|
|
||||||
static int add_units(sd_journal *j) {
|
static int add_units(sd_journal *j) {
|
||||||
_cleanup_strv_free_ char **patterns = NULL;
|
_cleanup_strv_free_ char **patterns = NULL;
|
||||||
bool added = false;
|
bool added = false;
|
||||||
@ -175,7 +107,7 @@ static int add_units(sd_journal *j) {
|
|||||||
_cleanup_set_free_ Set *units = NULL;
|
_cleanup_set_free_ Set *units = NULL;
|
||||||
char *u;
|
char *u;
|
||||||
|
|
||||||
r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
|
r = get_possible_units(j, SYSTEM_UNITS_FULL, patterns, &units);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -218,7 +150,7 @@ static int add_units(sd_journal *j) {
|
|||||||
_cleanup_set_free_ Set *units = NULL;
|
_cleanup_set_free_ Set *units = NULL;
|
||||||
char *u;
|
char *u;
|
||||||
|
|
||||||
r = get_possible_units(j, USER_UNITS, patterns, &units);
|
r = get_possible_units(j, USER_UNITS_FULL, patterns, &units);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -246,11 +246,11 @@ int action_list_invocations(void) {
|
|||||||
|
|
||||||
assert(arg_action == ACTION_LIST_INVOCATIONS);
|
assert(arg_action == ACTION_LIST_INVOCATIONS);
|
||||||
|
|
||||||
r = acquire_unit("--list-invocations", &unit, &type);
|
r = acquire_journal(&j);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = acquire_journal(&j);
|
r = acquire_unit(j, "--list-invocations", &unit, &type);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -2,14 +2,17 @@
|
|||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "glob-util.h"
|
||||||
#include "id128-util.h"
|
#include "id128-util.h"
|
||||||
#include "journal-util.h"
|
#include "journal-util.h"
|
||||||
#include "journalctl.h"
|
#include "journalctl.h"
|
||||||
#include "journalctl-util.h"
|
#include "journalctl-util.h"
|
||||||
#include "logs-show.h"
|
#include "logs-show.h"
|
||||||
|
#include "nulstr-util.h"
|
||||||
#include "rlimit-util.h"
|
#include "rlimit-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
|
#include "unit-name.h"
|
||||||
|
|
||||||
char* format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
|
char* format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
|
||||||
assert(buf);
|
assert(buf);
|
||||||
@ -111,9 +114,61 @@ int journal_acquire_boot(sd_journal *j) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int acquire_unit(const char *option_name, const char **ret_unit, LogIdType *ret_type) {
|
int get_possible_units(
|
||||||
size_t n;
|
sd_journal *j,
|
||||||
|
const char *fields,
|
||||||
|
char * const *patterns,
|
||||||
|
Set **ret) {
|
||||||
|
|
||||||
|
_cleanup_set_free_ Set *found = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(j);
|
||||||
|
assert(fields);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
NULSTR_FOREACH(field, fields) {
|
||||||
|
const void *data;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
r = sd_journal_query_unique(j, field);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
|
||||||
|
_cleanup_free_ char *u = NULL;
|
||||||
|
char *eq;
|
||||||
|
|
||||||
|
eq = memchr(data, '=', size);
|
||||||
|
if (eq) {
|
||||||
|
size -= eq - (char*) data + 1;
|
||||||
|
data = ++eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
u = strndup(data, size);
|
||||||
|
if (!u)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
if (!strv_fnmatch_full(patterns, u, FNM_NOESCAPE, &i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
log_debug("Matched %s with pattern %s=%s", u, field, patterns[i]);
|
||||||
|
r = set_ensure_consume(&found, &string_hash_ops_free, TAKE_PTR(u));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(found);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(option_name);
|
||||||
assert(ret_unit);
|
assert(ret_unit);
|
||||||
assert(ret_type);
|
assert(ret_type);
|
||||||
@ -128,15 +183,44 @@ int acquire_unit(const char *option_name, const char **ret_unit, LogIdType *ret_
|
|||||||
"Using %s with multiple units is not supported.",
|
"Using %s with multiple units is not supported.",
|
||||||
option_name);
|
option_name);
|
||||||
|
|
||||||
|
LogIdType type;
|
||||||
|
char **units;
|
||||||
if (!strv_isempty(arg_system_units)) {
|
if (!strv_isempty(arg_system_units)) {
|
||||||
*ret_type = LOG_SYSTEM_UNIT_INVOCATION_ID;
|
type = LOG_SYSTEM_UNIT_INVOCATION_ID;
|
||||||
*ret_unit = arg_system_units[0];
|
units = arg_system_units;
|
||||||
} else {
|
} else {
|
||||||
assert(!strv_isempty(arg_user_units));
|
assert(!strv_isempty(arg_user_units));
|
||||||
*ret_type = LOG_USER_UNIT_INVOCATION_ID;
|
type = LOG_USER_UNIT_INVOCATION_ID;
|
||||||
*ret_unit = arg_user_units[0];
|
units = arg_user_units;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cleanup_free_ char *u = NULL;
|
||||||
|
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]);
|
||||||
|
|
||||||
|
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];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,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
|
* system unit or user unit, and calling without unit name is allowed. Otherwise, a unit name must
|
||||||
* be specified. */
|
* be specified. */
|
||||||
if (arg_invocation_offset != 0 || sd_id128_is_null(arg_invocation_id)) {
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,35 @@
|
|||||||
#include "sd-journal.h"
|
#include "sd-journal.h"
|
||||||
|
|
||||||
#include "logs-show.h"
|
#include "logs-show.h"
|
||||||
|
#include "set.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
|
/* The lists below are supposed to return the superset of unit names possibly matched by rules added with
|
||||||
|
* add_matches_for_unit() and add_matches_for_user_unit(). */
|
||||||
|
#define SYSTEM_UNITS \
|
||||||
|
"_SYSTEMD_UNIT\0" \
|
||||||
|
"UNIT\0" \
|
||||||
|
"OBJECT_SYSTEMD_UNIT\0"
|
||||||
|
|
||||||
|
#define SYSTEM_UNITS_FULL \
|
||||||
|
SYSTEM_UNITS \
|
||||||
|
"COREDUMP_UNIT\0" \
|
||||||
|
"_SYSTEMD_SLICE\0"
|
||||||
|
|
||||||
|
#define USER_UNITS \
|
||||||
|
"_SYSTEMD_USER_UNIT\0" \
|
||||||
|
"USER_UNIT\0" \
|
||||||
|
"OBJECT_SYSTEMD_USER_UNIT\0"
|
||||||
|
|
||||||
|
#define USER_UNITS_FULL \
|
||||||
|
USER_UNITS \
|
||||||
|
"COREDUMP_USER_UNIT\0" \
|
||||||
|
"_SYSTEMD_USER_SLICE\0"
|
||||||
|
|
||||||
char* format_timestamp_maybe_utc(char *buf, size_t l, usec_t t);
|
char* format_timestamp_maybe_utc(char *buf, size_t l, usec_t t);
|
||||||
int acquire_journal(sd_journal **ret);
|
int acquire_journal(sd_journal **ret);
|
||||||
bool journal_boot_has_effect(sd_journal *j);
|
bool journal_boot_has_effect(sd_journal *j);
|
||||||
int journal_acquire_boot(sd_journal *j);
|
int journal_acquire_boot(sd_journal *j);
|
||||||
int acquire_unit(const char *option_name, const char **ret_unit, LogIdType *ret_type);
|
int get_possible_units(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);
|
int journal_acquire_invocation(sd_journal *j);
|
||||||
|
@ -7,7 +7,10 @@ set -o pipefail
|
|||||||
# shellcheck source=test/units/util.sh
|
# shellcheck source=test/units/util.sh
|
||||||
. "$(dirname "$0")"/util.sh
|
. "$(dirname "$0")"/util.sh
|
||||||
|
|
||||||
SERVICE_NAME=invocation-id-test-"$RANDOM".service
|
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)
|
TMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
@ -26,6 +29,8 @@ done
|
|||||||
# systemd[1]: invocation-id-test-26448.service: Deactivated successfully.
|
# systemd[1]: invocation-id-test-26448.service: Deactivated successfully.
|
||||||
journalctl --sync
|
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" | tee "$TMP_DIR"/10
|
||||||
journalctl --list-invocation -u "$SERVICE_NAME" --reverse | tee "$TMP_DIR"/10-r
|
journalctl --list-invocation -u "$SERVICE_NAME" --reverse | tee "$TMP_DIR"/10-r
|
||||||
journalctl --list-invocation -u "$SERVICE_NAME" -n +10 | tee "$TMP_DIR"/p10
|
journalctl --list-invocation -u "$SERVICE_NAME" -n +10 | tee "$TMP_DIR"/p10
|
||||||
@ -44,6 +49,8 @@ journalctl --list-invocation -u "$SERVICE_NAME" -n +5 --reverse | tee "$TMP_DIR"
|
|||||||
[[ $(cat "$TMP_DIR"/p5 | wc -l) == 6 ]]
|
[[ $(cat "$TMP_DIR"/p5 | wc -l) == 6 ]]
|
||||||
[[ $(cat "$TMP_DIR"/p5-r | wc -l) == 6 ]]
|
[[ $(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 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) <(tail -n 5 "$TMP_DIR"/5)
|
||||||
diff <(tail -n 5 "$TMP_DIR"/10 | tac) <(tail -n 5 "$TMP_DIR"/5-r)
|
diff <(tail -n 5 "$TMP_DIR"/10 | tac) <(tail -n 5 "$TMP_DIR"/5-r)
|
||||||
@ -54,6 +61,10 @@ diff <(tail -n 10 "$TMP_DIR"/p10 | head -n 5 | tac) <(tail -n 5 "$TMP_DIR"/p5-r)
|
|||||||
tail -n 10 "$TMP_DIR"/10 |
|
tail -n 10 "$TMP_DIR"/10 |
|
||||||
while read -r idx invocation _; do
|
while read -r idx invocation _; do
|
||||||
i="$(( idx + 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="${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="${idx}" -u "$SERVICE_NAME")"
|
||||||
assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${invocation}")"
|
assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${invocation}")"
|
||||||
@ -62,6 +73,10 @@ tail -n 10 "$TMP_DIR"/10 |
|
|||||||
tail -n 10 "$TMP_DIR"/p10 |
|
tail -n 10 "$TMP_DIR"/p10 |
|
||||||
while read -r i invocation _; do
|
while read -r i invocation _; do
|
||||||
idx="$(( i - 10 ))"
|
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="${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="${idx}" -u "$SERVICE_NAME")"
|
||||||
assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${invocation}")"
|
assert_in "invocation ${i} ${invocation}" "$(journalctl --no-hostname -n 1 -t bash --invocation="${invocation}")"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user