Merge pull request #14178 from poettering/journal-namespace

journal: add concept of "journal namespaces"
This commit is contained in:
Lennart Poettering
2020-02-01 11:25:48 +01:00
committed by GitHub
59 changed files with 1385 additions and 470 deletions
+2
View File
@@ -1054,6 +1054,8 @@ bool string_is_safe(const char *p) {
if (!p)
return false;
/* Checks if the specified string contains no quotes or control characters */
for (t = p; *t; t++) {
if (*t > 0 && *t < ' ') /* no control characters */
return false;
+33
View File
@@ -2,10 +2,15 @@
#include <syslog.h>
#include "sd-id128.h"
#include "glob-util.h"
#include "hexdecoct.h"
#include "macro.h"
#include "path-util.h"
#include "string-table.h"
#include "syslog-util.h"
#include "unit-name.h"
int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
int a = 0, b = 0, c = 0;
@@ -96,3 +101,31 @@ DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
bool log_level_is_valid(int level) {
return level >= 0 && level <= LOG_DEBUG;
}
/* The maximum size for a log namespace length. This is the file name size limit 255 minus the size of a
* formatted machine ID minus a separator char */
#define LOG_NAMESPACE_MAX (NAME_MAX - (SD_ID128_STRING_MAX - 1) - 1)
bool log_namespace_name_valid(const char *s) {
/* Let's make sure the namespace fits in a filename that is prefixed with the machine ID and a dot
* (so that /var/log/journal/<machine-id>.<namespace> can be created based on it). Also make sure it
* is suitable as unit instance name, and does not contain fishy characters. */
if (!filename_is_valid(s))
return false;
if (strlen(s) > LOG_NAMESPACE_MAX)
return false;
if (!unit_instance_is_valid(s))
return false;
if (!string_is_safe(s))
return false;
/* Let's avoid globbing for now */
if (string_is_glob(s))
return false;
return true;
}
+2
View File
@@ -12,3 +12,5 @@ int log_level_from_string(const char *s);
bool log_level_is_valid(int level);
int syslog_parse_priority(const char **p, int *priority, bool with_facility);
bool log_namespace_name_valid(const char *s);
+27
View File
@@ -766,6 +766,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("LogRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(ExecContext, log_ratelimit_interval_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogRateLimitBurst", "u", bus_property_get_unsigned, offsetof(ExecContext, log_ratelimit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogExtraFields", "aay", property_get_log_extra_fields, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LogNamespace", "s", NULL, offsetof(ExecContext, log_namespace), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CapabilityBoundingSet", "t", NULL, offsetof(ExecContext, capability_bounding_set), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("AmbientCapabilities", "t", NULL, offsetof(ExecContext, capability_ambient_set), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1436,6 +1437,32 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (streq(name, "LogNamespace")) {
const char *n;
r = sd_bus_message_read(message, "s", &n);
if (r < 0)
return r;
if (!isempty(n) && !log_namespace_name_valid(n))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log namespace name not valid");
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
if (isempty(n)) {
c->log_namespace = mfree(c->log_namespace);
unit_write_settingf(u, flags, name, "%s=", name);
} else {
r = free_and_strdup(&c->log_namespace, n);
if (r < 0)
return r;
unit_write_settingf(u, flags, name, "%s=%s", name, n);
}
}
return 1;
} else if (streq(name, "LogExtraFields")) {
size_t n = 0;
+37 -5
View File
@@ -265,15 +265,27 @@ static int open_null_as(int flags, int nfd) {
return move_fd(fd, nfd, false);
}
static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
static const union sockaddr_union sa = {
static int connect_journal_socket(
int fd,
const char *log_namespace,
uid_t uid,
gid_t gid) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
uid_t olduid = UID_INVALID;
gid_t oldgid = GID_INVALID;
const char *j;
int r;
j = log_namespace ?
strjoina("/run/systemd/journal.", log_namespace, "/stdout") :
"/run/systemd/journal/stdout";
r = sockaddr_un_set_path(&sa.un, j);
if (r < 0)
return r;
if (gid_is_valid(gid)) {
oldgid = getgid();
@@ -328,7 +340,7 @@ static int connect_logger_as(
if (fd < 0)
return -errno;
r = connect_journal_socket(fd, uid, gid);
r = connect_journal_socket(fd, context->log_namespace, uid, gid);
if (r < 0)
return r;
@@ -1686,7 +1698,7 @@ static int build_environment(
assert(p);
assert(ret);
our_env = new0(char*, 14 + _EXEC_DIRECTORY_TYPE_MAX);
our_env = new0(char*, 15 + _EXEC_DIRECTORY_TYPE_MAX);
if (!our_env)
return -ENOMEM;
@@ -1795,6 +1807,14 @@ static int build_environment(
our_env[n_env++] = x;
}
if (c->log_namespace) {
x = strjoin("LOG_NAMESPACE=", c->log_namespace);
if (!x)
return -ENOMEM;
our_env[n_env++] = x;
}
for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
_cleanup_free_ char *pre = NULL, *joined = NULL;
const char *n;
@@ -1919,6 +1939,9 @@ static bool exec_needs_mount_namespace(
!strv_isempty(context->directories[EXEC_DIRECTORY_LOGS].paths)))
return true;
if (context->log_namespace)
return true;
return false;
}
@@ -2517,6 +2540,9 @@ static bool insist_on_sandboxing(
if (!path_equal(bind_mounts[i].source, bind_mounts[i].destination))
return true;
if (context->log_namespace)
return true;
return false;
}
@@ -2600,6 +2626,7 @@ static int apply_mount_namespace(
context->n_temporary_filesystems,
tmp,
var,
context->log_namespace,
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags,
@@ -4140,6 +4167,8 @@ void exec_context_done(ExecContext *c) {
c->stdin_data_size = 0;
c->network_namespace_path = mfree(c->network_namespace_path);
c->log_namespace = mfree(c->log_namespace);
}
int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
@@ -4675,6 +4704,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
}
}
if (c->log_namespace)
fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace);
if (c->secure_bits) {
_cleanup_free_ char *str = NULL;
+2
View File
@@ -250,6 +250,8 @@ struct ExecContext {
int log_level_max;
char *log_namespace;
bool private_tmp;
bool private_network;
bool private_devices;
+1
View File
@@ -119,6 +119,7 @@ $1.ProtectKernelLogs, config_parse_bool, 0,
$1.ProtectClock, config_parse_bool, 0, offsetof($1, exec_context.protect_clock)
$1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups)
$1.NetworkNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.network_namespace_path)
$1.LogNamespace, config_parse_log_namespace, 0, offsetof($1, exec_context)
$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
$1.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users)
$1.PrivateMounts, config_parse_bool, 0, offsetof($1, exec_context.private_mounts)
+44 -1
View File
@@ -52,10 +52,11 @@
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
#include "time-util.h"
#include "unit-name.h"
#include "unit-printf.h"
#include "user-util.h"
#include "time-util.h"
#include "web-util.h"
static int parse_socket_protocol(const char *s) {
@@ -2519,6 +2520,48 @@ int config_parse_log_extra_fields(
}
}
int config_parse_log_namespace(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ char *k = NULL;
ExecContext *c = data;
const Unit *u = userdata;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(c);
if (isempty(rvalue)) {
c->log_namespace = mfree(c->log_namespace);
return 0;
}
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", rvalue);
return 0;
}
if (!log_namespace_name_valid(k)) {
log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Specified log namespace name is not valid: %s", k);
return 0;
}
free_and_replace(c->log_namespace, k);
return 0;
}
int config_parse_unit_condition_path(
const char *unit,
const char *filename,
+1
View File
@@ -107,6 +107,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_keyring_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_job_timeout_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_job_running_timeout_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_log_extra_fields);
CONFIG_PARSER_PROTOTYPE(config_parse_log_namespace);
CONFIG_PARSER_PROTOTYPE(config_parse_collect_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_pid_file);
CONFIG_PARSER_PROTOTYPE(config_parse_exit_status);
+22 -1
View File
@@ -1132,6 +1132,7 @@ static size_t namespace_calculate_mounts(
size_t n_temporary_filesystems,
const char* tmp_dir,
const char* var_tmp_dir,
const char* log_namespace,
ProtectHome protect_home,
ProtectSystem protect_system) {
@@ -1166,7 +1167,8 @@ static size_t namespace_calculate_mounts(
(ns_info->protect_control_groups ? 1 : 0) +
protect_home_cnt + protect_system_cnt +
(ns_info->protect_hostname ? 2 : 0) +
(namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0);
(namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0) +
!!log_namespace;
}
static void normalize_mounts(const char *root_directory, MountEntry *mounts, size_t *n_mounts) {
@@ -1247,6 +1249,7 @@ int setup_namespace(
size_t n_temporary_filesystems,
const char* tmp_dir,
const char* var_tmp_dir,
const char *log_namespace,
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags,
@@ -1323,6 +1326,7 @@ int setup_namespace(
n_bind_mounts,
n_temporary_filesystems,
tmp_dir, var_tmp_dir,
log_namespace,
protect_home, protect_system);
if (n_mounts > 0) {
@@ -1428,6 +1432,23 @@ int setup_namespace(
};
}
if (log_namespace) {
_cleanup_free_ char *q;
q = strjoin("/run/systemd/journal.", log_namespace);
if (!q) {
r = -ENOMEM;
goto finish;
}
*(m++) = (MountEntry) {
.path_const = "/run/systemd/journal",
.mode = BIND_MOUNT_RECURSIVE,
.read_only = true,
.source_malloc = TAKE_PTR(q),
};
}
assert(mounts + n_mounts == m);
/* Prepend the root directory where that's necessary */
+1
View File
@@ -84,6 +84,7 @@ int setup_namespace(
size_t n_temporary_filesystems,
const char *tmp_dir,
const char *var_tmp_dir,
const char *log_namespace,
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags,
+24 -4
View File
@@ -1059,13 +1059,33 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
!IN_SET(c->std_error,
EXEC_OUTPUT_JOURNAL, EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
EXEC_OUTPUT_KMSG, EXEC_OUTPUT_KMSG_AND_CONSOLE,
EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE))
EXEC_OUTPUT_SYSLOG, EXEC_OUTPUT_SYSLOG_AND_CONSOLE) &&
!c->log_namespace)
return 0;
/* If syslog or kernel logging is requested, make sure our own
* logging daemon is run first. */
/* If syslog or kernel logging is requested (or log namespacing is), make sure our own logging daemon
* is run first. */
r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE);
if (c->log_namespace) {
_cleanup_free_ char *socket_unit = NULL, *varlink_socket_unit = NULL;
r = unit_name_build_from_type("systemd-journald", c->log_namespace, UNIT_SOCKET, &socket_unit);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, socket_unit, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
r = unit_name_build_from_type("systemd-journald-varlink", c->log_namespace, UNIT_SOCKET, &varlink_socket_unit);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, varlink_socket_unit, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
} else
r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
+6 -2
View File
@@ -754,9 +754,13 @@ static int open_journal(sd_journal **j) {
r = sd_journal_open_directory(j, arg_directory, arg_journal_type);
else if (arg_file)
r = sd_journal_open_files(j, (const char**) arg_file, 0);
else if (arg_machine)
else if (arg_machine) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* FIXME: replace with D-Bus call OpenMachineRootDirectory() so that things also work with raw disk images */
r = sd_journal_open_container(j, arg_machine, 0);
else
#pragma GCC diagnostic pop
} else
r = sd_journal_open(j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
if (r < 0)
log_error_errno(r, "Failed to open %s: %m",
+1
View File
@@ -69,6 +69,7 @@ struct sd_journal {
char *path;
char *prefix;
char *namespace;
OrderedHashmap *files;
IteratedCache *files_cache;
+101 -91
View File
@@ -70,36 +70,8 @@
#include "varlink.h"
#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
#define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */
#if HAVE_PCRE2
DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, pcre2_match_data_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, pcre2_code_free);
static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out) {
int errorcode, r;
PCRE2_SIZE erroroffset;
pcre2_code *p;
p = pcre2_compile((PCRE2_SPTR8) pattern,
PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
if (!p) {
unsigned char buf[LINE_MAX];
r = pcre2_get_error_message(errorcode, buf, sizeof buf);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Bad pattern \"%s\": %s", pattern,
r < 0 ? "unknown error" : (char *)buf);
}
*out = p;
return 0;
}
#endif
enum {
/* Special values for arg_lines */
ARG_LINES_DEFAULT = -2,
@@ -143,13 +115,14 @@ static const char *arg_field = NULL;
static bool arg_catalog = false;
static bool arg_reverse = false;
static int arg_journal_type = 0;
static int arg_namespace_flags = 0;
static char *arg_root = NULL;
static const char *arg_machine = NULL;
static const char *arg_namespace = NULL;
static uint64_t arg_vacuum_size = 0;
static uint64_t arg_vacuum_n_files = 0;
static usec_t arg_vacuum_time = 0;
static char **arg_output_fields = NULL;
#if HAVE_PCRE2
static const char *arg_pattern = NULL;
static pcre2_code *arg_compiled_pattern = NULL;
@@ -184,6 +157,33 @@ typedef struct BootId {
LIST_FIELDS(struct BootId, boot_list);
} BootId;
#if HAVE_PCRE2
DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, pcre2_match_data_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, pcre2_code_free);
static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out) {
int errorcode, r;
PCRE2_SIZE erroroffset;
pcre2_code *p;
p = pcre2_compile((PCRE2_SPTR8) pattern,
PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
if (!p) {
unsigned char buf[LINE_MAX];
r = pcre2_get_error_message(errorcode, buf, sizeof buf);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Bad pattern \"%s\": %s", pattern,
r < 0 ? "unknown error" : (char *)buf);
}
*out = p;
return 0;
}
#endif
static int add_matches_for_device(sd_journal *j, const char *devpath) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
sd_device *d = NULL;
@@ -313,9 +313,9 @@ static int help(void) {
if (r < 0)
return log_oom();
printf("%s [OPTIONS...] [MATCHES...]\n\n"
"%sQuery the journal.%s\n\n"
"Options:\n"
printf("%1$s [OPTIONS...] [MATCHES...]\n\n"
"%5$sQuery the journal.%6$s\n\n"
"%3$sOptions:%4$s\n"
" --system Show the system journal\n"
" --user Show the user journal for the current user\n"
" -M --machine=CONTAINER Operate on local container\n"
@@ -356,10 +356,11 @@ static int help(void) {
" -D --directory=PATH Show journal files from directory\n"
" --file=PATH Show journal file\n"
" --root=ROOT Operate on files below a root directory\n"
" --namespace=NAMESPACE Show journal data from specified namespace\n"
" --interval=TIME Time interval for changing the FSS sealing key\n"
" --verify-key=KEY Specify FSS verification key\n"
" --force Override of the FSS key pair with --setup-keys\n"
"\nCommands:\n"
"\n%3$sCommands:%4$s\n"
" -h --help Show this help text\n"
" --version Show package version\n"
" -N --fields List all field names currently used\n"
@@ -379,10 +380,11 @@ static int help(void) {
" --dump-catalog Show entries in the message catalog\n"
" --update-catalog Update the message catalog database\n"
" --setup-keys Generate a new FSS key pair\n"
"\nSee the %s for details.\n"
"\nSee the %2$s for details.\n"
, program_invocation_short_name
, ansi_highlight(), ansi_normal()
, link
, ansi_underline(), ansi_normal()
, ansi_highlight(), ansi_normal()
);
return 0;
@@ -428,6 +430,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VACUUM_TIME,
ARG_NO_HOSTNAME,
ARG_OUTPUT_FIELDS,
ARG_NAMESPACE,
};
static const struct option options[] = {
@@ -492,6 +495,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
{ "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
{ "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS },
{ "namespace", required_argument, NULL, ARG_NAMESPACE },
{}
};
@@ -533,10 +537,8 @@ static int parse_argv(int argc, char *argv[]) {
}
arg_output = output_mode_from_string(optarg);
if (arg_output < 0) {
log_error("Unknown output format '%s'.", optarg);
return -EINVAL;
}
if (arg_output < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown output format '%s'.", optarg);
if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT))
arg_quiet = true;
@@ -561,10 +563,8 @@ static int parse_argv(int argc, char *argv[]) {
arg_lines = ARG_LINES_ALL;
else {
r = safe_atoi(optarg, &arg_lines);
if (r < 0 || arg_lines < 0) {
log_error("Failed to parse lines '%s'", optarg);
return -EINVAL;
}
if (r < 0 || arg_lines < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse lines '%s'", optarg);
}
} else {
arg_lines = 10;
@@ -656,6 +656,23 @@ static int parse_argv(int argc, char *argv[]) {
arg_machine = optarg;
break;
case ARG_NAMESPACE:
if (streq(optarg, "*")) {
arg_namespace_flags = SD_JOURNAL_ALL_NAMESPACES;
arg_namespace = NULL;
} else if (startswith(optarg, "+")) {
arg_namespace_flags = SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE;
arg_namespace = optarg + 1;
} else if (isempty(optarg)) {
arg_namespace_flags = 0;
arg_namespace = NULL;
} else {
arg_namespace_flags = 0;
arg_namespace = optarg;
}
break;
case 'D':
arg_directory = optarg;
break;
@@ -710,30 +727,24 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VACUUM_SIZE:
r = parse_size(optarg, 1024, &arg_vacuum_size);
if (r < 0) {
log_error("Failed to parse vacuum size: %s", optarg);
return r;
}
if (r < 0)
return log_error_errno(r, "Failed to parse vacuum size: %s", optarg);
arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
break;
case ARG_VACUUM_FILES:
r = safe_atou64(optarg, &arg_vacuum_n_files);
if (r < 0) {
log_error("Failed to parse vacuum files: %s", optarg);
return r;
}
if (r < 0)
return log_error_errno(r, "Failed to parse vacuum files: %s", optarg);
arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
break;
case ARG_VACUUM_TIME:
r = parse_sec(optarg, &arg_vacuum_time);
if (r < 0) {
log_error("Failed to parse vacuum time: %s", optarg);
return r;
}
if (r < 0)
return log_error_errno(r, "Failed to parse vacuum time: %s", optarg);
arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM;
break;
@@ -748,7 +759,6 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_VERIFY_KEY:
arg_action = ACTION_VERIFY;
r = free_and_strdup(&arg_verify_key, optarg);
if (r < 0)
return r;
@@ -756,23 +766,23 @@ static int parse_argv(int argc, char *argv[]) {
* in ps or htop output. */
memset(optarg, 'x', strlen(optarg));
arg_action = ACTION_VERIFY;
arg_merge = false;
break;
case ARG_INTERVAL:
r = parse_sec(optarg, &arg_interval);
if (r < 0 || arg_interval <= 0) {
log_error("Failed to parse sealing key change interval: %s", optarg);
return -EINVAL;
}
if (r < 0 || arg_interval <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse sealing key change interval: %s", optarg);
break;
#else
case ARG_SETUP_KEYS:
case ARG_VERIFY_KEY:
case ARG_INTERVAL:
case ARG_FORCE:
log_error("Compiled without forward-secure sealing support.");
return -EOPNOTSUPP;
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Compiled without forward-secure sealing support.");
#endif
case 'p': {
@@ -780,7 +790,7 @@ static int parse_argv(int argc, char *argv[]) {
dots = strstr(optarg, "..");
if (dots) {
char *a;
_cleanup_free_ char *a = NULL;
int from, to, i;
/* a range */
@@ -790,12 +800,10 @@ static int parse_argv(int argc, char *argv[]) {
from = log_level_from_string(a);
to = log_level_from_string(dots + 2);
free(a);
if (from < 0 || to < 0) {
log_error("Failed to parse log level range %s", optarg);
return -EINVAL;
}
if (from < 0 || to < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse log level range %s", optarg);
arg_priorities = 0;
@@ -811,10 +819,9 @@ static int parse_argv(int argc, char *argv[]) {
int p, i;
p = log_level_from_string(optarg);
if (p < 0) {
log_error("Unknown log level %s", optarg);
return -EINVAL;
}
if (p < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown log level %s", optarg);
arg_priorities = 0;
@@ -848,19 +855,17 @@ static int parse_argv(int argc, char *argv[]) {
case 'S':
r = parse_timestamp(optarg, &arg_since);
if (r < 0) {
log_error("Failed to parse timestamp: %s", optarg);
return -EINVAL;
}
if (r < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse timestamp: %s", optarg);
arg_since_set = true;
break;
case 'U':
r = parse_timestamp(optarg, &arg_until);
if (r < 0) {
log_error("Failed to parse timestamp: %s", optarg);
return -EINVAL;
}
if (r < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse timestamp: %s", optarg);
arg_until_set = true;
break;
@@ -1417,7 +1422,6 @@ static int add_boot(sd_journal *j) {
* so take the slow path if log location is specified. */
if (arg_boot_offset == 0 && sd_id128_is_null(arg_boot_id) &&
!arg_directory && !arg_file && !arg_root)
return add_match_this_boot(j, arg_machine);
boot_id = arg_boot_id;
@@ -1944,15 +1948,19 @@ static int verify(sd_journal *j) {
static int simple_varlink_call(const char *option, const char *method) {
_cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
const char *error;
const char *error, *fn;
int r;
if (arg_machine)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "%s is not supported in conjunction with --machine=.", option);
r = varlink_connect_address(&link, "/run/systemd/journal/io.systemd.journal");
fn = arg_namespace ?
strjoina("/run/systemd/journal.", arg_namespace, "/io.systemd.journal") :
"/run/systemd/journal/io.systemd.journal";
r = varlink_connect_address(&link, fn);
if (r < 0)
return log_error_errno(r, "Failed to connect to /run/systemd/journal/io.systemd.journal: %m");
return log_error_errno(r, "Failed to connect to %s: %m", fn);
(void) varlink_set_description(link, "journal");
(void) varlink_set_relative_timeout(link, USEC_INFINITY);
@@ -2122,10 +2130,9 @@ int main(int argc, char *argv[]) {
r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
else if (arg_root)
r = sd_journal_open_directory(&j, arg_root, arg_journal_type | SD_JOURNAL_OS_ROOT);
else if (arg_file_stdin) {
int ifd = STDIN_FILENO;
r = sd_journal_open_files_fd(&j, &ifd, 1, 0);
} else if (arg_file)
else if (arg_file_stdin)
r = sd_journal_open_files_fd(&j, (int[]) { STDIN_FILENO }, 1, 0);
else if (arg_file)
r = sd_journal_open_files(&j, (const char**) arg_file, 0);
else if (arg_machine) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -2136,8 +2143,7 @@ int main(int argc, char *argv[]) {
if (geteuid() != 0) {
/* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
* the container, thus we need root privileges to override them. */
log_error("Using the --machine= switch requires root privileges.");
r = -EPERM;
r = log_error_errno(SYNTHETIC_ERRNO(EPERM), "Using the --machine= switch requires root privileges.");
goto finish;
}
@@ -2177,7 +2183,11 @@ int main(int argc, char *argv[]) {
if (r < 0)
safe_close(fd);
} else
r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
r = sd_journal_open_namespace(
&j,
arg_namespace,
(arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY) |
arg_namespace_flags | arg_journal_type);
if (r < 0) {
log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
goto finish;
+18 -15
View File
@@ -117,23 +117,24 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) {
if (r < 0)
return r;
c = new0(ClientContext, 1);
c = new(ClientContext, 1);
if (!c)
return -ENOMEM;
c->pid = pid;
c->uid = UID_INVALID;
c->gid = GID_INVALID;
c->auditid = AUDIT_SESSION_INVALID;
c->loginuid = UID_INVALID;
c->owner_uid = UID_INVALID;
c->lru_index = PRIOQ_IDX_NULL;
c->timestamp = USEC_INFINITY;
c->extra_fields_mtime = NSEC_INFINITY;
c->log_level_max = -1;
c->log_ratelimit_interval = s->ratelimit_interval;
c->log_ratelimit_burst = s->ratelimit_burst;
*c = (ClientContext) {
.pid = pid,
.uid = UID_INVALID,
.gid = GID_INVALID,
.auditid = AUDIT_SESSION_INVALID,
.loginuid = UID_INVALID,
.owner_uid = UID_INVALID,
.lru_index = PRIOQ_IDX_NULL,
.timestamp = USEC_INFINITY,
.extra_fields_mtime = NSEC_INFINITY,
.log_level_max = -1,
.log_ratelimit_interval = s->ratelimit_interval,
.log_ratelimit_burst = s->ratelimit_burst,
};
r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c);
if (r < 0) {
@@ -779,7 +780,9 @@ void client_context_acquire_default(Server *s) {
log_warning_errno(r, "Failed to acquire our own context, ignoring: %m");
}
if (!s->pid1_context) {
if (!s->namespace && !s->pid1_context) {
/* Acquire PID1's context, but only if we are in non-namespaced mode, since PID 1 is only
* going to log to the non-namespaced journal instance. */
r = client_context_acquire(s, 1, NULL, NULL, 0, NULL, &s->pid1_context);
if (r < 0)
+15 -11
View File
@@ -24,11 +24,11 @@
#include "string-util.h"
void server_forward_kmsg(
Server *s,
int priority,
const char *identifier,
const char *message,
const struct ucred *ucred) {
Server *s,
int priority,
const char *identifier,
const char *message,
const struct ucred *ucred) {
_cleanup_free_ char *ident_buf = NULL;
struct iovec iovec[5];
@@ -416,19 +416,23 @@ fail:
}
int server_open_kernel_seqnum(Server *s) {
_cleanup_close_ int fd;
_cleanup_close_ int fd = -1;
const char *fn;
uint64_t *p;
int r;
assert(s);
/* We store the seqnum we last read in an mmaped file. That
* way we can just use it like a variable, but it is
* persistent and automatically flushed at reboot. */
/* We store the seqnum we last read in an mmaped file. That way we can just use it like a variable,
* but it is persistent and automatically flushed at reboot. */
fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
if (!s->read_kmsg)
return 0;
fn = strjoina(s->runtime_directory, "/kernel-seqnum");
fd = open(fn, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
if (fd < 0) {
log_error_errno(errno, "Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m");
log_error_errno(errno, "Failed to open %s, ignoring: %m", fn);
return 0;
}
+10 -6
View File
@@ -450,17 +450,21 @@ void server_process_native_file(
}
}
int server_open_native_socket(Server *s) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/socket",
};
int server_open_native_socket(Server *s, const char *native_socket) {
int r;
assert(s);
assert(native_socket);
if (s->native_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
r = sockaddr_un_set_path(&sa.un, native_socket);
if (r < 0)
return log_error_errno(r, "Unable to use namespace path %s for AF_UNIX socket: %m", native_socket);
s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->native_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
+1 -1
View File
@@ -20,4 +20,4 @@ void server_process_native_file(
const char *label,
size_t label_len);
int server_open_native_socket(Server *s);
int server_open_native_socket(Server *s, const char *native_socket);
+1 -1
View File
@@ -99,7 +99,7 @@ void journal_ratelimit_free(JournalRateLimit *r) {
free(r);
}
_pure_ static bool journal_ratelimit_group_expired(JournalRateLimitGroup *g, usec_t ts) {
static bool journal_ratelimit_group_expired(JournalRateLimitGroup *g, usec_t ts) {
unsigned i;
assert(g);
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -60,6 +60,8 @@ typedef struct JournalStorage {
} JournalStorage;
struct Server {
char *namespace;
int syslog_fd;
int native_fd;
int stdout_fd;
@@ -84,6 +86,7 @@ struct Server {
sd_event_source *hostname_event_source;
sd_event_source *notify_event_source;
sd_event_source *watchdog_event_source;
sd_event_source *idle_event_source;
JournalFile *runtime_journal;
JournalFile *system_journal;
@@ -147,6 +150,8 @@ struct Server {
char machine_id_field[sizeof("_MACHINE_ID=") + 32];
char boot_id_field[sizeof("_BOOT_ID=") + 32];
char *hostname_field;
char *namespace_field;
char *runtime_directory;
/* Cached cgroup root, so that we don't have to query that all the time */
char *cgroup_root;
@@ -172,7 +177,7 @@ struct Server {
#define SERVER_MACHINE_ID(s) ((s)->machine_id_field + STRLEN("_MACHINE_ID="))
/* Extra fields for any log messages */
#define N_IOVEC_META_FIELDS 22
#define N_IOVEC_META_FIELDS 23
/* Extra fields for log messages that contain OBJECT_PID= (i.e. log about another process) */
#define N_IOVEC_OBJECT_FIELDS 18
@@ -204,7 +209,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_split_mode);
const char *split_mode_to_string(SplitMode s) _const_;
SplitMode split_mode_from_string(const char *s) _pure_;
int server_init(Server *s);
int server_init(Server *s, const char *namespace);
void server_done(Server *s);
void server_sync(Server *s);
int server_vacuum(Server *s, bool verbose);
@@ -214,3 +219,6 @@ int server_flush_to_var(Server *s, bool require_flag_file);
void server_maybe_append_tags(Server *s);
int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata);
void server_space_usage_message(Server *s, JournalStorage *storage);
int server_start_or_stop_idle_timer(Server *s);
int server_refresh_idle_timer(Server *s);
+34 -23
View File
@@ -17,6 +17,7 @@
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "io-util.h"
#include "journald-console.h"
#include "journald-context.h"
@@ -109,6 +110,8 @@ void stdout_stream_free(StdoutStream *s) {
if (s->in_notify_queue)
LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
(void) server_start_or_stop_idle_timer(s->server); /* Maybe we are idle now? */
}
if (s->event_source) {
@@ -139,7 +142,7 @@ void stdout_stream_destroy(StdoutStream *s) {
}
static int stdout_stream_save(StdoutStream *s) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
@@ -156,11 +159,12 @@ static int stdout_stream_save(StdoutStream *s) {
return log_warning_errno(errno, "Failed to stat connected stream: %m");
/* We use device and inode numbers as identifier for the stream */
if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
r = asprintf(&s->state_file, "%s/streams/%lu:%lu", s->server->runtime_directory, (unsigned long) st.st_dev, (unsigned long) st.st_ino);
if (r < 0)
return log_oom();
}
(void) mkdir_p("/run/systemd/journal/streams", 0755);
(void) mkdir_parents(s->state_file, 0755);
r = fopen_temporary(s->state_file, &f, &temp_path);
if (r < 0)
@@ -214,6 +218,8 @@ static int stdout_stream_save(StdoutStream *s) {
goto fail;
}
temp_path = mfree(temp_path);
if (!s->fdstore && !s->in_notify_queue) {
LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
s->in_notify_queue = true;
@@ -229,10 +235,6 @@ static int stdout_stream_save(StdoutStream *s) {
fail:
(void) unlink(s->state_file);
if (temp_path)
(void) unlink(temp_path);
return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
}
@@ -590,12 +592,14 @@ int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
if (r < 0)
return log_error_errno(r, "Failed to generate stream ID: %m");
stream = new0(StdoutStream, 1);
stream = new(StdoutStream, 1);
if (!stream)
return log_oom();
stream->fd = -1;
stream->priority = LOG_INFO;
*stream = (StdoutStream) {
.fd = -1,
.priority = LOG_INFO,
};
xsprintf(stream->id_field, "_STREAM_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
@@ -629,11 +633,12 @@ int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
s->n_stdout_streams++;
(void) server_start_or_stop_idle_timer(s); /* Maybe no longer idle? */
if (ret)
*ret = stream;
stream = NULL;
TAKE_PTR(stream);
return 0;
}
@@ -676,7 +681,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
if (r < 0)
return r;
fd = -1;
TAKE_FD(fd);
return 0;
}
@@ -694,7 +699,7 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) {
assert(fname);
if (!stream->state_file) {
stream->state_file = path_join("/run/systemd/journal/streams", fname);
stream->state_file = path_join(stream->server->runtime_directory, "streams", fname);
if (!stream->state_file)
return log_oom();
}
@@ -783,14 +788,16 @@ static int stdout_stream_restore(Server *s, const char *fname, int fd) {
int server_restore_streams(Server *s, FDSet *fds) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
const char *path;
int r;
d = opendir("/run/systemd/journal/streams");
path = strjoina(s->runtime_directory, "/streams");
d = opendir(path);
if (!d) {
if (errno == ENOENT)
return 0;
return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m");
return log_warning_errno(errno, "Failed to enumerate %s: %m", path);
}
FOREACH_DIRENT(de, d, goto fail) {
@@ -818,8 +825,7 @@ int server_restore_streams(Server *s, FDSet *fds) {
/* No file descriptor? Then let's delete the state file */
log_debug("Cannot restore stream file %s", de->d_name);
if (unlinkat(dirfd(d), de->d_name, 0) < 0)
log_warning_errno(errno, "Failed to remove /run/systemd/journal/streams/%s: %m",
de->d_name);
log_warning_errno(errno, "Failed to remove %s%s: %m", path, de->d_name);
continue;
}
@@ -836,16 +842,21 @@ fail:
return log_error_errno(errno, "Failed to read streams directory: %m");
}
int server_open_stdout_socket(Server *s) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
int server_open_stdout_socket(Server *s, const char *stdout_socket) {
int r;
assert(s);
assert(stdout_socket);
if (s->stdout_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
r = sockaddr_un_set_path(&sa.un, stdout_socket);
if (r < 0)
return log_error_errno(r, "Unable to use namespace path %s for AF_UNIX socket: %m", stdout_socket);
s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->stdout_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
+1 -1
View File
@@ -6,7 +6,7 @@ typedef struct StdoutStream StdoutStream;
#include "fdset.h"
#include "journald-server.h"
int server_open_stdout_socket(Server *s);
int server_open_stdout_socket(Server *s, const char *stdout_socket);
int server_restore_streams(Server *s, FDSet *fds);
void stdout_stream_free(StdoutStream *s);
+26 -9
View File
@@ -25,11 +25,15 @@
/* Warn once every 30s if we missed syslog message */
#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, const struct ucred *ucred, const struct timeval *tv) {
static void forward_syslog_iovec(
Server *s,
const struct iovec *iovec,
unsigned n_iovec,
const struct ucred *ucred,
const struct timeval *tv) {
static const union sockaddr_union sa = {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/syslog",
};
struct msghdr msghdr = {
.msg_iov = (struct iovec *) iovec,
@@ -42,11 +46,20 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
} control;
const char *j;
int r;
assert(s);
assert(iovec);
assert(n_iovec > 0);
j = strjoina(s->runtime_directory, "/syslog");
r = sockaddr_un_set_path(&sa.un, j);
if (r < 0) {
log_debug_errno(r, "Forwarding socket path %s too long for AF_UNIX, not forwarding: %m", j);
return;
}
if (ucred) {
zero(control);
msghdr.msg_control = &control;
@@ -441,17 +454,21 @@ void server_process_syslog_message(
server_dispatch_message(s, iovec, n, m, context, tv, priority, 0);
}
int server_open_syslog_socket(Server *s) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/dev-log",
};
int server_open_syslog_socket(Server *s, const char *syslog_socket) {
int r;
assert(s);
assert(syslog_socket);
if (s->syslog_fd < 0) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
r = sockaddr_un_set_path(&sa.un, syslog_socket);
if (r < 0)
return log_error_errno(r, "Unable to use namespace path %s for AF_UNIX socket: %m", syslog_socket);
s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->syslog_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
+1 -1
View File
@@ -10,6 +10,6 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid);
void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv);
void server_process_syslog_message(Server *s, const char *buf, size_t buf_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len);
int server_open_syslog_socket(Server *s);
int server_open_syslog_socket(Server *s, const char *syslog_socket);
void server_maybe_warn_forward_syslog_missed(Server *s);
+19 -6
View File
@@ -14,14 +14,17 @@
#include "sigbus.h"
int main(int argc, char *argv[]) {
const char *namespace;
Server server;
int r;
if (argc > 1) {
log_error("This program does not take arguments.");
if (argc > 2) {
log_error("This program takes one or no arguments.");
return EXIT_FAILURE;
}
namespace = argc > 1 ? empty_to_null(argv[1]) : NULL;
log_set_prohibit_ipc(true);
log_set_target(LOG_TARGET_AUTO);
log_set_facility(LOG_SYSLOG);
@@ -32,7 +35,7 @@ int main(int argc, char *argv[]) {
sigbus_install();
r = server_init(&server);
r = server_init(&server, namespace);
if (r < 0)
goto finish;
@@ -40,7 +43,11 @@ int main(int argc, char *argv[]) {
server_flush_to_var(&server, true);
server_flush_dev_kmsg(&server);
log_debug("systemd-journald running as pid "PID_FMT, getpid_cached());
if (server.namespace)
log_debug("systemd-journald running as PID "PID_FMT" for namespace '%s'.", getpid_cached(), server.namespace ?: "<system>");
else
log_debug("systemd-journald running as PID "PID_FMT" for the system.", getpid_cached());
server_driver_message(&server, 0,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_START_STR,
LOG_MESSAGE("Journal started"),
@@ -55,8 +62,10 @@ int main(int argc, char *argv[]) {
usec_t t = USEC_INFINITY, n;
r = sd_event_get_state(server.event);
if (r < 0)
if (r < 0) {
log_error_errno(r, "Failed to get event loop state: %m");
goto finish;
}
if (r == SD_EVENT_FINISHED)
break;
@@ -99,7 +108,11 @@ int main(int argc, char *argv[]) {
server_maybe_warn_forward_syslog_missed(&server);
}
log_debug("systemd-journald stopped as pid "PID_FMT, getpid_cached());
if (server.namespace)
log_debug("systemd-journald stopped as PID "PID_FMT" for namespace '%s'.", getpid_cached(), server.namespace ?: "<system>");
else
log_debug("systemd-journald stopped as PID "PID_FMT" for the system.", getpid_cached());
server_driver_message(&server, 0,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_STOP_STR,
LOG_MESSAGE("Journal stopped"),
+105 -24
View File
@@ -39,6 +39,7 @@
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
#define JOURNAL_FILES_MAX 7168
@@ -204,16 +205,17 @@ static bool same_field(const void *_a, size_t s, const void *_b, size_t t) {
static Match *match_new(Match *p, MatchType t) {
Match *m;
m = new0(Match, 1);
m = new(Match, 1);
if (!m)
return NULL;
m->type = t;
*m = (Match) {
.type = t,
.parent = p,
};
if (p) {
m->parent = p;
if (p)
LIST_PREPEND(matches, p->matches, m);
}
return m;
}
@@ -1434,22 +1436,63 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
static int dirname_is_machine_id(const char *fn) {
sd_id128_t id, machine;
const char *e;
int r;
/* Returns true if the specified directory name matches the local machine ID */
r = sd_id128_get_machine(&machine);
if (r < 0)
return r;
r = sd_id128_from_string(fn, &id);
e = strchr(fn, '.');
if (e) {
const char *k;
/* Looks like it has a namespace suffix. Verify that. */
if (!log_namespace_name_valid(e + 1))
return false;
k = strndupa(fn, e - fn);
r = sd_id128_from_string(k, &id);
} else
r = sd_id128_from_string(fn, &id);
if (r < 0)
return r;
return sd_id128_equal(id, machine);
}
static int dirname_has_namespace(const char *fn, const char *namespace) {
const char *e;
/* Returns true if the specified directory name matches the specified namespace */
e = strchr(fn, '.');
if (e) {
const char *k;
if (!namespace)
return false;
if (!streq(e + 1, namespace))
return false;
k = strndupa(fn, e - fn);
return id128_is_valid(k);
}
if (namespace)
return false;
return id128_is_valid(fn);
}
static bool dirent_is_journal_file(const struct dirent *de) {
assert(de);
/* Returns true if the specified directory entry looks like a journal file we might be interested in */
if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN))
return false;
@@ -1457,13 +1500,26 @@ static bool dirent_is_journal_file(const struct dirent *de) {
endswith(de->d_name, ".journal~");
}
static bool dirent_is_id128_subdir(const struct dirent *de) {
static bool dirent_is_journal_subdir(const struct dirent *de) {
const char *e, *n;
assert(de);
/* returns true if the specified directory entry looks like a directory that might contain journal
* files we might be interested in, i.e. is either a 128bit ID or a 128bit ID suffixed by a
* namespace. */
if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN))
return false;
return id128_is_valid(de->d_name);
e = strchr(de->d_name, '.');
if (!e)
return id128_is_valid(de->d_name); /* No namespace */
n = strndupa(de->d_name, e - de->d_name);
if (!id128_is_valid(n))
return false;
return log_namespace_name_valid(e + 1);
}
static int directory_open(sd_journal *j, const char *path, DIR **ret) {
@@ -1500,7 +1556,7 @@ static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) {
if (dirent_is_journal_file(de))
(void) add_file_by_name(j, m->path, de->d_name);
if (m->is_root && dirent_is_id128_subdir(de))
if (m->is_root && dirent_is_journal_subdir(de))
(void) add_directory(j, m->path, de->d_name);
}
@@ -1540,7 +1596,11 @@ static void directory_watch(sd_journal *j, Directory *m, int fd, uint32_t mask)
}
}
static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
static int add_directory(
sd_journal *j,
const char *prefix,
const char *dirname) {
_cleanup_free_ char *path = NULL;
_cleanup_closedir_ DIR *d = NULL;
Directory *m;
@@ -1565,6 +1625,11 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
!((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
return 0;
if (!(FLAGS_SET(j->flags, SD_JOURNAL_ALL_NAMESPACES) ||
dirname_has_namespace(dirname, j->namespace) > 0 ||
(FLAGS_SET(j->flags, SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE) && dirname_has_namespace(dirname, NULL) > 0)))
return 0;
r = directory_open(j, path, &d);
if (r < 0) {
log_debug_errno(r, "Failed to open directory '%s': %m", path);
@@ -1573,14 +1638,16 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
m = hashmap_get(j->directories_by_path, path);
if (!m) {
m = new0(Directory, 1);
m = new(Directory, 1);
if (!m) {
r = -ENOMEM;
goto fail;
}
m->is_root = false;
m->path = path;
*m = (Directory) {
.is_root = false,
.path = path,
};
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
free(m);
@@ -1803,7 +1870,7 @@ static int allocate_inotify(sd_journal *j) {
return hashmap_ensure_allocated(&j->directories_by_wd, NULL);
}
static sd_journal *journal_new(int flags, const char *path) {
static sd_journal *journal_new(int flags, const char *path, const char *namespace) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
j = new0(sd_journal, 1);
@@ -1829,6 +1896,12 @@ static sd_journal *journal_new(int flags, const char *path) {
j->path = t;
}
if (namespace) {
j->namespace = strdup(namespace);
if (!j->namespace)
return NULL;
}
j->files = ordered_hashmap_new(&path_hash_ops);
if (!j->files)
return NULL;
@@ -1845,16 +1918,19 @@ static sd_journal *journal_new(int flags, const char *path) {
#define OPEN_ALLOWED_FLAGS \
(SD_JOURNAL_LOCAL_ONLY | \
SD_JOURNAL_RUNTIME_ONLY | \
SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER)
SD_JOURNAL_SYSTEM | \
SD_JOURNAL_CURRENT_USER | \
SD_JOURNAL_ALL_NAMESPACES | \
SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE)
_public_ int sd_journal_open(sd_journal **ret, int flags) {
_public_ int sd_journal_open_namespace(sd_journal **ret, const char *namespace, int flags) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
int r;
assert_return(ret, -EINVAL);
assert_return((flags & ~OPEN_ALLOWED_FLAGS) == 0, -EINVAL);
j = journal_new(flags, NULL);
j = journal_new(flags, NULL, namespace);
if (!j)
return -ENOMEM;
@@ -1866,6 +1942,10 @@ _public_ int sd_journal_open(sd_journal **ret, int flags) {
return 0;
}
_public_ int sd_journal_open(sd_journal **ret, int flags) {
return sd_journal_open_namespace(ret, NULL, flags);
}
#define OPEN_CONTAINER_ALLOWED_FLAGS \
(SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
@@ -1875,7 +1955,7 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
char *p;
int r;
/* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
/* This is deprecated, people should use machined's OpenMachineRootDirectory() call instead in
* combination with sd_journal_open_directory_fd(). */
assert_return(machine, -EINVAL);
@@ -1897,7 +1977,7 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
if (!streq_ptr(class, "container"))
return -EIO;
j = journal_new(flags, root);
j = journal_new(flags, root, NULL);
if (!j)
return -ENOMEM;
@@ -1921,7 +2001,7 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
assert_return(path, -EINVAL);
assert_return((flags & ~OPEN_DIRECTORY_ALLOWED_FLAGS) == 0, -EINVAL);
j = journal_new(flags, path);
j = journal_new(flags, path, NULL);
if (!j)
return -ENOMEM;
@@ -1944,7 +2024,7 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
assert_return(ret, -EINVAL);
assert_return(flags == 0, -EINVAL);
j = journal_new(flags, NULL);
j = journal_new(flags, NULL, NULL);
if (!j)
return -ENOMEM;
@@ -1979,7 +2059,7 @@ _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
if (!S_ISDIR(st.st_mode))
return -EBADFD;
j = journal_new(flags, NULL);
j = journal_new(flags, NULL, NULL);
if (!j)
return -ENOMEM;
@@ -2007,7 +2087,7 @@ _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fd
assert_return(n_fds > 0, -EBADF);
assert_return(flags == 0, -EINVAL);
j = journal_new(flags, NULL);
j = journal_new(flags, NULL, NULL);
if (!j)
return -ENOMEM;
@@ -2079,6 +2159,7 @@ _public_ void sd_journal_close(sd_journal *j) {
free(j->path);
free(j->prefix);
free(j->namespace);
free(j->unique_field);
free(j->fields_buffer);
free(j);
@@ -2480,7 +2561,7 @@ static void process_q_overflow(sd_journal *j) {
log_debug("Reiteration complete.");
}
static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
static void process_inotify_event(sd_journal *j, const struct inotify_event *e) {
Directory *d;
assert(j);
+1
View File
@@ -693,4 +693,5 @@ global:
sd_event_source_get_child_process_own;
sd_event_source_set_child_process_own;
sd_event_source_send_child_signal;
sd_journal_open_namespace;
} LIBSYSTEMD_243;
+2
View File
@@ -576,6 +576,7 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
show_journal_by_unit(
stdout,
i.scope,
NULL,
arg_output,
0,
i.timestamp.monotonic,
@@ -660,6 +661,7 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
show_journal_by_unit(
stdout,
i.slice,
NULL,
arg_output,
0,
i.timestamp.monotonic,
+1
View File
@@ -626,6 +626,7 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
show_journal_by_unit(
stdout,
i->unit,
NULL,
arg_output,
0,
i->timestamp.monotonic,
+2 -1
View File
@@ -833,7 +833,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"RuntimeDirectoryPreserve",
"Personality",
"KeyringMode",
"NetworkNamespacePath"))
"NetworkNamespacePath",
"LogNamespace"))
return bus_append_string(m, field, eq);
if (STR_IN_SET(field, "IgnoreSIGPIPE",
+2 -1
View File
@@ -1453,6 +1453,7 @@ int add_match_this_boot(sd_journal *j, const char *machine) {
int show_journal_by_unit(
FILE *f,
const char *unit,
const char *log_namespace,
OutputMode mode,
unsigned n_columns,
usec_t not_before,
@@ -1473,7 +1474,7 @@ int show_journal_by_unit(
if (how_many <= 0)
return 0;
r = sd_journal_open(&j, journal_open_flags);
r = sd_journal_open_namespace(&j, log_namespace, journal_open_flags | SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE);
if (r < 0)
return log_error_errno(r, "Failed to open journal: %m");
+1
View File
@@ -46,6 +46,7 @@ int add_matches_for_user_unit(
int show_journal_by_unit(
FILE *f,
const char *unit,
const char *namespace,
OutputMode mode,
unsigned n_columns,
usec_t not_before,
+27 -2
View File
@@ -168,6 +168,7 @@ struct VarlinkServer {
Hashmap *methods;
VarlinkConnect connect_callback;
VarlinkDisconnect disconnect_callback;
sd_event *event;
int64_t event_priority;
@@ -1146,6 +1147,7 @@ int varlink_flush(Varlink *v) {
}
static void varlink_detach_server(Varlink *v) {
VarlinkServer *saved_server;
assert(v);
if (!v->server)
@@ -1169,8 +1171,15 @@ static void varlink_detach_server(Varlink *v) {
v->server->n_connections--;
/* If this is a connection associated to a server, then let's disconnect the server and the
* connection from each other. This drops the dangling reference that connect_callback() set up. */
v->server = varlink_server_unref(v->server);
* connection from each other. This drops the dangling reference that connect_callback() set up. But
* before we release the references, let's call the disconnection callback if it is defined. */
saved_server = TAKE_PTR(v->server);
if (saved_server->disconnect_callback)
saved_server->disconnect_callback(saved_server, v, saved_server->userdata);
varlink_server_unref(saved_server);
varlink_unref(v);
}
@@ -2413,6 +2422,16 @@ int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect callback) {
return 0;
}
int varlink_server_bind_disconnect(VarlinkServer *s, VarlinkDisconnect callback) {
assert_return(s, -EINVAL);
if (callback && s->disconnect_callback && callback != s->disconnect_callback)
return -EBUSY;
s->disconnect_callback = callback;
return 0;
}
unsigned varlink_server_connections_max(VarlinkServer *s) {
int dts;
@@ -2460,6 +2479,12 @@ int varlink_server_set_connections_max(VarlinkServer *s, unsigned m) {
return 0;
}
unsigned varlink_server_current_connections(VarlinkServer *s) {
assert_return(s, UINT_MAX);
return s->n_connections;
}
int varlink_server_set_description(VarlinkServer *s, const char *description) {
assert_return(s, -EINVAL);
+4
View File
@@ -51,6 +51,7 @@ typedef enum VarlinkServerFlags {
typedef int (*VarlinkMethod)(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata);
typedef int (*VarlinkReply)(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata);
typedef int (*VarlinkConnect)(VarlinkServer *server, Varlink *link, void *userdata);
typedef void (*VarlinkDisconnect)(VarlinkServer *server, Varlink *link, void *userdata);
int varlink_connect_address(Varlink **ret, const char *address);
int varlink_connect_fd(Varlink **ret, int fd);
@@ -134,6 +135,7 @@ int varlink_server_bind_method(VarlinkServer *s, const char *method, VarlinkMeth
int varlink_server_bind_method_many_internal(VarlinkServer *s, ...);
#define varlink_server_bind_method_many(s, ...) varlink_server_bind_method_many_internal(s, __VA_ARGS__, NULL)
int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect connect);
int varlink_server_bind_disconnect(VarlinkServer *s, VarlinkDisconnect disconnect);
void* varlink_server_set_userdata(VarlinkServer *s, void *userdata);
void* varlink_server_get_userdata(VarlinkServer *s);
@@ -150,6 +152,8 @@ unsigned varlink_server_connections_per_uid_max(VarlinkServer *s);
int varlink_server_set_connections_per_uid_max(VarlinkServer *s, unsigned m);
int varlink_server_set_connections_max(VarlinkServer *s, unsigned m);
unsigned varlink_server_current_connections(VarlinkServer *s);
int varlink_server_set_description(VarlinkServer *s, const char *description);
DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_unref);
+4
View File
@@ -4007,6 +4007,8 @@ typedef struct UnitStatusInfo {
int exit_code, exit_status;
const char *log_namespace;
usec_t condition_timestamp;
bool condition_result;
LIST_HEAD(UnitCondition, conditions);
@@ -4545,6 +4547,7 @@ static void print_status_info(
show_journal_by_unit(
stdout,
i->id,
i->log_namespace,
arg_output,
0,
i->inactive_exit_timestamp_monotonic,
@@ -5491,6 +5494,7 @@ static int show_one(
{ "ExecMainExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, exit_timestamp) },
{ "ExecMainCode", "i", NULL, offsetof(UnitStatusInfo, exit_code) },
{ "ExecMainStatus", "i", NULL, offsetof(UnitStatusInfo, exit_status) },
{ "LogNamespace", "s", NULL, offsetof(UnitStatusInfo, log_namespace) },
{ "ConditionTimestamp", "t", NULL, offsetof(UnitStatusInfo, condition_timestamp) },
{ "ConditionResult", "b", NULL, offsetof(UnitStatusInfo, condition_result) },
{ "Conditions", "a(sbbsi)", map_conditions, 0 },
+12
View File
@@ -45,6 +45,18 @@ typedef void (*_sd_destroy_t)(void *userdata);
# define _sd_pure_ __attribute__((__pure__))
#endif
/* Note that strictly speaking __deprecated__ has been available before GCC 6. However, starting with GCC 6
* it also works on enum values, which we are interested in. Since this is a developer-facing feature anyway
* (as opposed to build engineer-facing), let's hence conditionalize this to gcc 6, given that the developers
* are probably going to use something newer anyway. */
#ifndef _sd_deprecated_
# if __GNUC__ >= 6
# define _sd_deprecated_ __attribute__((__deprecated__))
# else
# define _sd_deprecated_
# endif
#endif
#ifndef _SD_STRINGIFY
# define _SD_XSTRINGIFY(x) #x
# define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x)
+10 -7
View File
@@ -64,13 +64,15 @@ typedef struct sd_journal sd_journal;
/* Open flags */
enum {
SD_JOURNAL_LOCAL_ONLY = 1 << 0,
SD_JOURNAL_RUNTIME_ONLY = 1 << 1,
SD_JOURNAL_SYSTEM = 1 << 2,
SD_JOURNAL_CURRENT_USER = 1 << 3,
SD_JOURNAL_OS_ROOT = 1 << 4,
SD_JOURNAL_LOCAL_ONLY = 1 << 0,
SD_JOURNAL_RUNTIME_ONLY = 1 << 1,
SD_JOURNAL_SYSTEM = 1 << 2,
SD_JOURNAL_CURRENT_USER = 1 << 3,
SD_JOURNAL_OS_ROOT = 1 << 4,
SD_JOURNAL_ALL_NAMESPACES = 1 << 5, /* Show all namespaces, not just the default or specified one */
SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE = 1 << 6, /* Show default namespace in addition to specified one */
SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM /* deprecated name */
SD_JOURNAL_SYSTEM_ONLY _sd_deprecated_ = SD_JOURNAL_SYSTEM /* deprecated name */
};
/* Wakeup event types */
@@ -81,11 +83,12 @@ enum {
};
int sd_journal_open(sd_journal **ret, int flags);
int sd_journal_open_namespace(sd_journal **ret, const char *name_space, int flags);
int sd_journal_open_directory(sd_journal **ret, const char *path, int flags);
int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags);
int sd_journal_open_files(sd_journal **ret, const char **paths, int flags);
int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags);
int sd_journal_open_container(sd_journal **ret, const char *machine, int flags); /* deprecated */
int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) _sd_deprecated_; /* deprecated */
void sd_journal_close(sd_journal *j);
int sd_journal_previous(sd_journal *j);
+3
View File
@@ -6,6 +6,9 @@ for header in sys.argv[2:]:
print('#include "{}"'.format(header.split('/')[-1]))
print('''
/* We want to check deprecated symbols too, without complaining */
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
const void* symbols[] = {''')
for line in open(sys.argv[1]):
+1
View File
@@ -148,6 +148,7 @@ static void test_protect_kernel_logs(void) {
NULL, 0,
NULL,
NULL,
NULL,
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,
+1
View File
@@ -72,6 +72,7 @@ int main(int argc, char *argv[]) {
&(TemporaryFileSystem) { .path = (char*) "/var", .options = (char*) "ro" }, 1,
tmp_dir,
var_tmp_dir,
NULL,
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
0,