Several follow-ups for JournalAccess varlink interface (#40794)
This commit is contained in:
@@ -967,7 +967,6 @@ Features:
|
||||
|
||||
* Varlinkification of the following command line tools, to open them up to
|
||||
other programs via IPC:
|
||||
- bootctl
|
||||
- coredumpcl
|
||||
- systemd-bless-boot
|
||||
- systemd-measure
|
||||
|
||||
@@ -895,7 +895,6 @@ foreach option : ['adm-gid',
|
||||
'video-gid',
|
||||
'wheel-gid',
|
||||
'systemd-journal-gid',
|
||||
'systemd-journal-uid',
|
||||
'systemd-network-uid',
|
||||
'systemd-resolve-uid',
|
||||
'systemd-timesync-uid']
|
||||
|
||||
@@ -328,8 +328,6 @@ option('wheel-gid', type : 'integer', value : 0,
|
||||
description : 'soft-static allocation for the "wheel" group')
|
||||
option('systemd-journal-gid', type : 'integer', value : 0,
|
||||
description : 'soft-static allocation for the systemd-journal group')
|
||||
option('systemd-journal-uid', type : 'integer', value : 0,
|
||||
description : 'soft-static allocation for the systemd-journal user')
|
||||
option('systemd-network-uid', type : 'integer', value : 0,
|
||||
description : 'soft-static allocation for the systemd-network user')
|
||||
option('systemd-resolve-uid', type : 'integer', value : 0,
|
||||
|
||||
@@ -97,6 +97,7 @@ typedef enum RuntimeScope RuntimeScope;
|
||||
typedef enum TimestampStyle TimestampStyle;
|
||||
typedef enum UnitActiveState UnitActiveState;
|
||||
typedef enum UnitDependency UnitDependency;
|
||||
typedef enum UnitNameMangle UnitNameMangle;
|
||||
typedef enum UnitType UnitType;
|
||||
typedef enum WaitFlags WaitFlags;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "chase.h"
|
||||
#include "devnum-util.h"
|
||||
#include "fileio.h"
|
||||
#include "glob-util.h"
|
||||
#include "journal-internal.h"
|
||||
#include "journalctl.h"
|
||||
#include "journalctl-filter.h"
|
||||
@@ -71,6 +72,116 @@ static int add_dmesg(sd_journal *j) {
|
||||
return sd_journal_add_conjunction(j);
|
||||
}
|
||||
|
||||
int journal_add_unit_matches(
|
||||
sd_journal *j,
|
||||
MatchUnitFlag flags,
|
||||
UnitNameMangle mangle_flags,
|
||||
char * const *system_units,
|
||||
uid_t uid,
|
||||
char * const *user_units) {
|
||||
|
||||
_cleanup_strv_free_ char **patterns = NULL;
|
||||
bool added = false;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
if (strv_isempty(system_units) && strv_isempty(user_units))
|
||||
return 0;
|
||||
|
||||
STRV_FOREACH(i, system_units) {
|
||||
_cleanup_free_ char *u = NULL;
|
||||
|
||||
r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | mangle_flags, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (string_is_glob(u)) {
|
||||
r = strv_consume(&patterns, TAKE_PTR(u));
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
r = add_matches_for_unit_full(j, flags, u);
|
||||
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 *units = NULL;
|
||||
|
||||
r = get_possible_units(j, SYSTEM_UNITS_FULL, patterns, &units);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
char *u;
|
||||
SET_FOREACH(u, units) {
|
||||
r = add_matches_for_unit_full(j, flags, u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_journal_add_disjunction(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
patterns = strv_free(patterns);
|
||||
|
||||
STRV_FOREACH(i, user_units) {
|
||||
_cleanup_free_ char *u = NULL;
|
||||
|
||||
r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | mangle_flags, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (string_is_glob(u)) {
|
||||
r = strv_consume(&patterns, TAKE_PTR(u));
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
r = add_matches_for_user_unit_full(j, flags, uid, u);
|
||||
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 *units = NULL;
|
||||
|
||||
r = get_possible_units(j, USER_UNITS_FULL, patterns, &units);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
char *u;
|
||||
SET_FOREACH(u, units) {
|
||||
r = add_matches_for_user_unit_full(j, flags, uid, u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_journal_add_disjunction(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Complain if the user request matches but nothing whatsoever was found, since otherwise everything
|
||||
* would be matched. */
|
||||
if (!added)
|
||||
return -ENODATA;
|
||||
|
||||
return sd_journal_add_conjunction(j);
|
||||
}
|
||||
|
||||
static int add_units(sd_journal *j) {
|
||||
MatchUnitFlag flags = MATCH_UNIT_ALL;
|
||||
|
||||
@@ -82,7 +193,9 @@ static int add_units(sd_journal *j) {
|
||||
if (arg_directory || arg_root || arg_file_stdin || arg_file || arg_machine)
|
||||
flags &= ~MATCH_UNIT_COREDUMP_UID;
|
||||
|
||||
return journal_add_unit_matches(j, flags, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, arg_system_units, arg_user_units);
|
||||
return journal_add_unit_matches(j, flags, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
||||
arg_system_units,
|
||||
UID_INVALID, arg_user_units);
|
||||
}
|
||||
|
||||
static int add_syslog_identifier(sd_journal *j) {
|
||||
|
||||
@@ -3,4 +3,12 @@
|
||||
|
||||
#include "shared-forward.h"
|
||||
|
||||
int journal_add_unit_matches(
|
||||
sd_journal *j,
|
||||
MatchUnitFlag flags,
|
||||
UnitNameMangle mangle_flags,
|
||||
char * const *system_units,
|
||||
uid_t uid,
|
||||
char * const *user_units);
|
||||
|
||||
int add_filters(sd_journal *j, char **matches);
|
||||
|
||||
@@ -177,108 +177,6 @@ int get_possible_units(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int journal_add_unit_matches(sd_journal *j, MatchUnitFlag flags, UnitNameMangle mangle_flags, char **system_units, char **user_units) {
|
||||
_cleanup_strv_free_ char **patterns = NULL;
|
||||
bool added = false;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
if (strv_isempty(system_units) && strv_isempty(user_units))
|
||||
return 0;
|
||||
|
||||
STRV_FOREACH(i, system_units) {
|
||||
_cleanup_free_ char *u = NULL;
|
||||
|
||||
r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | mangle_flags, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (string_is_glob(u)) {
|
||||
r = strv_consume(&patterns, TAKE_PTR(u));
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
r = add_matches_for_unit_full(j, flags, u);
|
||||
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 *units = NULL;
|
||||
|
||||
r = get_possible_units(j, SYSTEM_UNITS_FULL, patterns, &units);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
char *u;
|
||||
SET_FOREACH(u, units) {
|
||||
r = add_matches_for_unit_full(j, flags, u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_journal_add_disjunction(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
patterns = strv_free(patterns);
|
||||
|
||||
STRV_FOREACH(i, user_units) {
|
||||
_cleanup_free_ char *u = NULL;
|
||||
|
||||
r = unit_name_mangle(*i, UNIT_NAME_MANGLE_GLOB | mangle_flags, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (string_is_glob(u)) {
|
||||
r = strv_consume(&patterns, TAKE_PTR(u));
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
r = add_matches_for_user_unit_full(j, flags, u);
|
||||
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 *units = NULL;
|
||||
|
||||
r = get_possible_units(j, USER_UNITS_FULL, patterns, &units);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
char *u;
|
||||
SET_FOREACH(u, units) {
|
||||
r = add_matches_for_user_unit_full(j, flags, u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_journal_add_disjunction(j);
|
||||
if (r < 0)
|
||||
return r;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Complain if the user request matches but nothing whatsoever was found, since otherwise everything
|
||||
* would be matched. */
|
||||
if (!added)
|
||||
return -ENODATA;
|
||||
|
||||
return sd_journal_add_conjunction(j);
|
||||
}
|
||||
|
||||
int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type) {
|
||||
size_t n;
|
||||
int r;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "shared-forward.h"
|
||||
#include "logs-show.h"
|
||||
#include "unit-name.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(). */
|
||||
@@ -32,6 +31,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 journal_add_unit_matches(sd_journal *j, MatchUnitFlag flags, UnitNameMangle mangle_flags, char **system_units, char **user_units);
|
||||
int acquire_unit(sd_journal *j, const char *option_name, const char **ret_unit, LogIdType *ret_type);
|
||||
int journal_acquire_invocation(sd_journal *j);
|
||||
|
||||
@@ -4,25 +4,30 @@
|
||||
#include "sd-varlink.h"
|
||||
|
||||
#include "journal-internal.h"
|
||||
#include "journalctl-util.h"
|
||||
#include "journalctl.h"
|
||||
#include "journalctl-filter.h"
|
||||
#include "journalctl-varlink-server.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
#include "logs-show.h"
|
||||
#include "output-mode.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "strv.h"
|
||||
#include "unit-name.h" /* IWYU pragma: keep */
|
||||
#include "user-util.h"
|
||||
#include "varlink-util.h"
|
||||
|
||||
typedef struct GetEntriesParameters {
|
||||
char **units;
|
||||
char **user_units;
|
||||
const char *namespace;
|
||||
uid_t uid;
|
||||
int priority;
|
||||
uint64_t limit;
|
||||
} GetEntriesParameters;
|
||||
|
||||
static void get_entries_parameters_done(GetEntriesParameters *p) {
|
||||
assert(p);
|
||||
|
||||
p->units = strv_free(p->units);
|
||||
p->user_units = strv_free(p->user_units);
|
||||
}
|
||||
@@ -31,6 +36,7 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "units", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(GetEntriesParameters, units), 0 },
|
||||
{ "uid", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid, offsetof(GetEntriesParameters, uid), 0 },
|
||||
{ "userUnits", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(GetEntriesParameters, user_units), 0 },
|
||||
{ "namespace", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetEntriesParameters, namespace), 0 },
|
||||
{ "priority", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_log_level, offsetof(GetEntriesParameters, priority), 0 },
|
||||
@@ -39,6 +45,7 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||
};
|
||||
|
||||
_cleanup_(get_entries_parameters_done) GetEntriesParameters p = {
|
||||
.uid = UID_INVALID,
|
||||
.priority = -1,
|
||||
};
|
||||
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
||||
@@ -51,23 +58,26 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (arg_varlink_runtime_scope == RUNTIME_SCOPE_SYSTEM && p.user_units && !uid_is_valid(p.uid))
|
||||
return sd_varlink_error_invalid_parameter_name(link, "uid");
|
||||
|
||||
/* systemd ships with sensible defaults for the system/user services and the socket permissions so we
|
||||
* do not need to do extra sd_varlink_get_peer_uid() or policykit checks here */
|
||||
r = sd_journal_open_namespace(&j, p.namespace, SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_ASSUME_IMMUTABLE);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open journal: %m");
|
||||
return r;
|
||||
|
||||
r = journal_add_unit_matches(j, MATCH_UNIT_ALL, /* mangle_flags= */ 0, p.units, p.user_units);
|
||||
r = journal_add_unit_matches(j, MATCH_UNIT_ALL, /* mangle_flags= */ 0, p.units, p.uid, p.user_units);
|
||||
if (r == -ENODATA)
|
||||
return sd_varlink_error(link, SD_VARLINK_ERROR_INVALID_PARAMETER, NULL);
|
||||
return sd_varlink_error(link, "io.systemd.JournalAccess.NoMatches", NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add unit matches: %m");
|
||||
return r;
|
||||
|
||||
if (p.priority >= 0) {
|
||||
for (int i = 0; i <= p.priority; i++) {
|
||||
r = journal_add_matchf(j, "PRIORITY=%d", i);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add priority match: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_journal_add_conjunction(j);
|
||||
@@ -78,7 +88,7 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||
/* this simulates "journalctl -n $p.limit" */
|
||||
r = sd_journal_seek_tail(j);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to seek to tail: %m");
|
||||
return r;
|
||||
|
||||
/* FIXME: this restriction should be removed eventually */
|
||||
if (p.limit > 10000)
|
||||
@@ -86,6 +96,10 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||
|
||||
uint64_t n = p.limit == 0 ? 100 : p.limit;
|
||||
|
||||
r = sd_journal_previous_skip(j, n + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = varlink_set_sentinel(link, "io.systemd.JournalAccess.NoEntries");
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -93,9 +107,9 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *entry = NULL;
|
||||
|
||||
r = sd_journal_previous(j);
|
||||
r = sd_journal_next(j);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to iterate journal: %m");
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
@@ -105,7 +119,7 @@ int vl_method_get_entries(sd_varlink *link, sd_json_variant *parameters, sd_varl
|
||||
if (r == 0)
|
||||
continue; /* skip corrupted entry */
|
||||
|
||||
r = sd_varlink_replybo(link, SD_JSON_BUILD_PAIR("entry", SD_JSON_BUILD_VARIANT(entry)));
|
||||
r = sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_VARIANT("entry", entry));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "parse-util.h"
|
||||
#include "pcre2-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "set.h"
|
||||
#include "static-destruct.h"
|
||||
#include "string-table.h"
|
||||
@@ -111,7 +112,9 @@ pcre2_code *arg_compiled_pattern = NULL;
|
||||
PatternCompileCase arg_case = PATTERN_COMPILE_CASE_AUTO;
|
||||
ImagePolicy *arg_image_policy = NULL;
|
||||
bool arg_synchronize_on_exit = false;
|
||||
|
||||
static bool arg_varlink = false;
|
||||
RuntimeScope arg_varlink_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_cursor, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_cursor_file, freep);
|
||||
@@ -486,7 +489,35 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
|
||||
if (r > 0) {
|
||||
arg_varlink = true;
|
||||
arg_pager_flags |= PAGER_DISABLE;
|
||||
|
||||
static const struct option varlink_options[] = {
|
||||
{ "system", no_argument, NULL, ARG_SYSTEM },
|
||||
{ "user", no_argument, NULL, ARG_USER },
|
||||
{}
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, "", varlink_options, NULL)) >= 0)
|
||||
|
||||
switch (c) {
|
||||
|
||||
case ARG_SYSTEM:
|
||||
arg_varlink_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
||||
break;
|
||||
|
||||
case ARG_USER:
|
||||
arg_varlink_runtime_scope = RUNTIME_SCOPE_USER;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (arg_varlink_runtime_scope < 0)
|
||||
return log_error_errno(arg_varlink_runtime_scope, "Cannot run in Varlink mode with no runtime scope specified.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,3 +94,6 @@ extern bool arg_synchronize_on_exit;
|
||||
static inline bool arg_lines_needs_seek_end(void) {
|
||||
return arg_lines >= 0 && !arg_lines_oldest;
|
||||
}
|
||||
|
||||
/* Only used for varlink server invocation */
|
||||
extern RuntimeScope arg_varlink_runtime_scope;
|
||||
|
||||
+35
-27
@@ -1193,17 +1193,20 @@ static int update_json_data_split(
|
||||
return update_json_data(h, flags, name, eq + 1, size - fieldlen - 1);
|
||||
}
|
||||
|
||||
int journal_entry_to_json(sd_journal *j, OutputFlags flags, const Set *output_fields, sd_json_variant **ret) {
|
||||
int journal_entry_to_json(
|
||||
sd_journal *j,
|
||||
OutputFlags flags,
|
||||
const Set *output_fields,
|
||||
sd_json_variant **ret) {
|
||||
|
||||
char usecbuf[CONST_MAX(DECIMAL_STR_MAX(usec_t), DECIMAL_STR_MAX(uint64_t))];
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *object = NULL;
|
||||
_cleanup_hashmap_free_ Hashmap *h = NULL;
|
||||
sd_id128_t journal_boot_id, seqnum_id;
|
||||
_cleanup_free_ char *cursor = NULL;
|
||||
usec_t realtime, monotonic;
|
||||
sd_json_variant **array = NULL;
|
||||
JsonData *d;
|
||||
uint64_t seqnum;
|
||||
const char *corrupted_what = NULL;
|
||||
_cleanup_hashmap_free_ Hashmap *h = NULL;
|
||||
_cleanup_free_ sd_json_variant **array = NULL;
|
||||
size_t n = 0;
|
||||
int r;
|
||||
|
||||
@@ -1214,32 +1217,32 @@ int journal_entry_to_json(sd_journal *j, OutputFlags flags, const Set *output_fi
|
||||
|
||||
r = sd_journal_get_cursor(j, &cursor);
|
||||
if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) {
|
||||
log_debug_errno(r, "Unable to determine cursor of entry, assuming bad or partially written entry: %m");
|
||||
return 0;
|
||||
corrupted_what = "cursor";
|
||||
goto corrupted_skip;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get cursor: %m");
|
||||
|
||||
r = sd_journal_get_realtime_usec(j, &realtime);
|
||||
if (r == -EBADMSG) {
|
||||
log_debug_errno(r, "Unable to read realtime timestamp of entry, assuming bad or partially written entry: %m");
|
||||
return 0;
|
||||
corrupted_what = "realtime timestamp";
|
||||
goto corrupted_skip;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get realtime timestamp: %m");
|
||||
|
||||
r = sd_journal_get_monotonic_usec(j, &monotonic, &journal_boot_id);
|
||||
if (r == -EBADMSG) {
|
||||
log_debug_errno(r, "Unable to read monotonic timestamp of entry, assuming bad or partially written entry: %m");
|
||||
return 0;
|
||||
corrupted_what = "monotonic timestamp";
|
||||
goto corrupted_skip;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get monotonic timestamp: %m");
|
||||
|
||||
r = sd_journal_get_seqnum(j, &seqnum, &seqnum_id);
|
||||
if (r == -EBADMSG) {
|
||||
log_debug_errno(r, "Unable to read sequence number of entry, assuming bad or partially written entry: %m");
|
||||
return 0;
|
||||
corrupted_what = "sequence number";
|
||||
goto corrupted_skip;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get seqnum: %m");
|
||||
@@ -1294,29 +1297,32 @@ int journal_entry_to_json(sd_journal *j, OutputFlags flags, const Set *output_fi
|
||||
return r;
|
||||
}
|
||||
|
||||
array = new(sd_json_variant*, hashmap_size(h)*2);
|
||||
array = new(sd_json_variant*, hashmap_size(h) * 2);
|
||||
if (!array)
|
||||
return log_oom();
|
||||
|
||||
CLEANUP_ARRAY(array, n, sd_json_variant_unref_many);
|
||||
|
||||
JsonData *d;
|
||||
HASHMAP_FOREACH(d, h) {
|
||||
assert(sd_json_variant_elements(d->values) > 0);
|
||||
|
||||
array[n++] = sd_json_variant_ref(d->name);
|
||||
array[n++] = d->name;
|
||||
|
||||
if (sd_json_variant_elements(d->values) == 1)
|
||||
array[n++] = sd_json_variant_ref(sd_json_variant_by_index(d->values, 0));
|
||||
array[n++] = sd_json_variant_by_index(d->values, 0);
|
||||
else
|
||||
array[n++] = sd_json_variant_ref(d->values);
|
||||
array[n++] = d->values;
|
||||
}
|
||||
|
||||
r = sd_json_variant_new_object(&object, array, n);
|
||||
r = sd_json_variant_new_object(ret, array, n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate JSON object: %m");
|
||||
|
||||
*ret = TAKE_PTR(object);
|
||||
return 1;
|
||||
|
||||
corrupted_skip:
|
||||
log_debug_errno(r, "Unable to determine %s of entry, assuming bad or partially written entry: %m", ASSERT_PTR(corrupted_what));
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_json(
|
||||
@@ -1338,9 +1344,9 @@ static int output_json(
|
||||
return r;
|
||||
|
||||
return sd_json_variant_dump(object,
|
||||
output_mode_to_json_format_flags(mode) |
|
||||
(FLAGS_SET(flags, OUTPUT_COLOR) ? SD_JSON_FORMAT_COLOR : 0),
|
||||
f, NULL);
|
||||
output_mode_to_json_format_flags(mode) |
|
||||
(FLAGS_SET(flags, OUTPUT_COLOR) ? SD_JSON_FORMAT_COLOR : 0),
|
||||
f, NULL);
|
||||
}
|
||||
|
||||
static int output_cat_field(
|
||||
@@ -1761,13 +1767,15 @@ int add_matches_for_unit_full(sd_journal *j, MatchUnitFlag flags, const char *un
|
||||
return r;
|
||||
}
|
||||
|
||||
int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, const char *unit) {
|
||||
uid_t uid = getuid();
|
||||
int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, uid_t uid, const char *unit) {
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
assert(unit);
|
||||
|
||||
if (uid == UID_INVALID)
|
||||
uid = getuid();
|
||||
|
||||
(void) (
|
||||
/* Look for messages from the user service itself */
|
||||
(r = journal_add_match_pair(j, "_SYSTEMD_USER_UNIT", unit)) ||
|
||||
@@ -2004,7 +2012,7 @@ static int set_matches_for_discover_id(
|
||||
return add_matches_for_unit_full(j, /* flags= */ 0, unit);
|
||||
|
||||
if (type == LOG_USER_UNIT_INVOCATION_ID)
|
||||
return add_matches_for_user_unit_full(j, /* flags= */ 0, unit);
|
||||
return add_matches_for_user_unit_full(j, /* flags= */ 0, UID_INVALID, unit);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -57,9 +57,9 @@ int add_matches_for_unit_full(sd_journal *j, MatchUnitFlag flags, const char *un
|
||||
static inline int add_matches_for_unit(sd_journal *j, const char *unit) {
|
||||
return add_matches_for_unit_full(j, MATCH_UNIT_ALL, unit);
|
||||
}
|
||||
int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, const char *unit);
|
||||
int add_matches_for_user_unit_full(sd_journal *j, MatchUnitFlag flags, uid_t uid, const char *unit);
|
||||
static inline int add_matches_for_user_unit(sd_journal *j, const char *unit) {
|
||||
return add_matches_for_user_unit_full(j, MATCH_UNIT_ALL, unit);
|
||||
return add_matches_for_user_unit_full(j, MATCH_UNIT_ALL, UID_INVALID, unit);
|
||||
}
|
||||
|
||||
int show_journal_by_unit(
|
||||
|
||||
@@ -26,6 +26,7 @@ typedef enum DnssecMode DnssecMode;
|
||||
typedef enum Fido2EnrollFlags Fido2EnrollFlags;
|
||||
typedef enum KeySourceType KeySourceType;
|
||||
typedef enum LabelFixFlags LabelFixFlags;
|
||||
typedef enum MatchUnitFlag MatchUnitFlag;
|
||||
typedef enum MountInNamespaceFlags MountInNamespaceFlags;
|
||||
typedef enum NamePolicy NamePolicy;
|
||||
typedef enum OutputFlags OutputFlags;
|
||||
|
||||
@@ -7,6 +7,8 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
|
||||
SD_VARLINK_REQUIRES_MORE,
|
||||
SD_VARLINK_FIELD_COMMENT("Show messages for the specified systemd units (e.g. ['foo.service'])."),
|
||||
SD_VARLINK_DEFINE_INPUT(units, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
|
||||
SD_VARLINK_FIELD_COMMENT("UID to match user units for"),
|
||||
SD_VARLINK_DEFINE_INPUT(uid, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Show messages for the specified user units (e.g. ['foo.service'])."),
|
||||
SD_VARLINK_DEFINE_INPUT(userUnits, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
|
||||
SD_VARLINK_FIELD_COMMENT("If specified, shows the log data of the specified namespace, otherwise the default namespace."),
|
||||
@@ -16,8 +18,9 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
|
||||
SD_VARLINK_FIELD_COMMENT("Maximum number of entries to return. Defaults to 100, capped at 10000."),
|
||||
SD_VARLINK_DEFINE_INPUT(limit, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The journal entry in flat JSON format, matching journalctl --output=json."),
|
||||
SD_VARLINK_DEFINE_OUTPUT(entry, SD_VARLINK_OBJECT, SD_VARLINK_NULLABLE));
|
||||
SD_VARLINK_DEFINE_OUTPUT(entry, SD_VARLINK_OBJECT, 0));
|
||||
|
||||
static SD_VARLINK_DEFINE_ERROR(NoMatches);
|
||||
static SD_VARLINK_DEFINE_ERROR(NoEntries);
|
||||
|
||||
SD_VARLINK_DEFINE_INTERFACE(
|
||||
@@ -26,5 +29,7 @@ SD_VARLINK_DEFINE_INTERFACE(
|
||||
SD_VARLINK_INTERFACE_COMMENT("Journal log read APIs"),
|
||||
SD_VARLINK_SYMBOL_COMMENT("Retrieve journal log entries, optionally filtered by unit, priority, etc."),
|
||||
&vl_method_GetEntries,
|
||||
SD_VARLINK_SYMBOL_COMMENT("No matches found for specified unit patterns"),
|
||||
&vl_error_NoMatches,
|
||||
SD_VARLINK_SYMBOL_COMMENT("No journal entries matched the specified filters."),
|
||||
&vl_error_NoEntries);
|
||||
|
||||
@@ -5,5 +5,4 @@
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
g systemd-journal {{SYSTEMD_JOURNAL_GID}} -
|
||||
u! systemd-journal {{SYSTEMD_JOURNAL_UID}} "systemd Journal"
|
||||
g systemd-journal {{SYSTEMD_JOURNAL_GID}} -
|
||||
|
||||
@@ -13,7 +13,10 @@ Documentation=man:journalctl(1)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
Before=shutdown.target
|
||||
RequiresMountsFor=/var/log/journal
|
||||
|
||||
[Service]
|
||||
ExecStart=journalctl
|
||||
User=systemd-journal
|
||||
ExecStart=journalctl --system
|
||||
DynamicUser=yes
|
||||
User=systemd-journal-access
|
||||
SupplementaryGroups=systemd-journal
|
||||
|
||||
@@ -22,6 +22,3 @@ FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
MaxConnectionsPerSource=16
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
|
||||
@@ -17,4 +17,3 @@ Symlinks=%t/varlink/registry/io.systemd.JournalAccess
|
||||
FileDescriptorName=varlink
|
||||
SocketMode=0600
|
||||
Accept=yes
|
||||
MaxConnectionsPerSource=16
|
||||
|
||||
@@ -12,4 +12,4 @@ Description=Journal Log Access Service
|
||||
Documentation=man:journalctl(1)
|
||||
|
||||
[Service]
|
||||
ExecStart=journalctl
|
||||
ExecStart=journalctl --user
|
||||
|
||||
Reference in New Issue
Block a user