typedef enum TimestampStyle TimestampStyle;
typedef enum UnitActiveState UnitActiveState;
typedef enum UnitDependency UnitDependency;
+typedef enum UnitNameMangle UnitNameMangle;
typedef enum UnitType UnitType;
typedef enum WaitFlags WaitFlags;
#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"
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;
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) {
#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);
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;
#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(). */
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);
#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);
}
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 },
};
_cleanup_(get_entries_parameters_done) GetEntriesParameters p = {
+ .uid = UID_INVALID,
.priority = -1,
};
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
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 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, "io.systemd.JournalAccess.NoMatches", NULL);
if (r < 0)
#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"
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);
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;
}
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;
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)) ||
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;
}
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(
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;
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."),
RequiresMountsFor=/var/log/journal
[Service]
-ExecStart=journalctl
+ExecStart=journalctl --system
DynamicUser=yes
User=systemd-journal-access
SupplementaryGroups=systemd-journal
Documentation=man:journalctl(1)
[Service]
-ExecStart=journalctl
+ExecStart=journalctl --user