No functional change, just refactoring and preparation for later changes.
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "sd-event.h"
+
+#include "conf-parser.h"
+#include "creds-util.h"
+#include "daemon-util.h"
+#include "journald-config.h"
+#include "journald-kmsg.h"
+#include "journald-manager.h"
+#include "log.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "socket-netlink.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "syslog-util.h"
+#include "time-util.h"
+
+#define DEFAULT_SYNC_INTERVAL_USEC (5*USEC_PER_MINUTE)
+#define DEFAULT_RATE_LIMIT_INTERVAL (30*USEC_PER_SEC)
+#define DEFAULT_RATE_LIMIT_BURST 10000
+#define DEFAULT_MAX_FILE_USEC USEC_PER_MONTH
+
+/* Pick a good default that is likely to fit into AF_UNIX and AF_INET SOCK_DGRAM datagrams, and even leaves some room
+ * for a bit of additional metadata. */
+#define DEFAULT_LINE_MAX (48*1024)
+
+#define JOURNAL_CONFIG_INIT \
+ (JournalConfig) { \
+ .forward_to_socket = (SocketAddress) { .sockaddr.sa.sa_family = AF_UNSPEC }, \
+ .storage = _STORAGE_INVALID, \
+ .max_level_store = -1, \
+ .max_level_syslog = -1, \
+ .max_level_kmsg = -1, \
+ .max_level_console = -1, \
+ .max_level_wall = -1, \
+ .max_level_socket = -1, \
+ }
+
+static void manager_set_defaults(Manager *m) {
+ assert(m);
+
+ m->compress.enabled = true;
+ m->compress.threshold_bytes = UINT64_MAX;
+
+ m->seal = true;
+
+ /* By default, only read from /dev/kmsg if are the main namespace */
+ m->read_kmsg = !m->namespace;
+
+ m->set_audit = true;
+
+ m->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC;
+
+ m->ratelimit_interval = DEFAULT_RATE_LIMIT_INTERVAL;
+ m->ratelimit_burst = DEFAULT_RATE_LIMIT_BURST;
+
+ m->system_storage.name = "System Journal";
+ journal_reset_metrics(&m->system_storage.metrics);
+
+ m->runtime_storage.name = "Runtime Journal";
+ journal_reset_metrics(&m->runtime_storage.metrics);
+
+ m->max_file_usec = DEFAULT_MAX_FILE_USEC;
+
+ m->config.forward_to_wall = true;
+
+ m->config.max_level_store = LOG_DEBUG;
+ m->config.max_level_syslog = LOG_DEBUG;
+ m->config.max_level_kmsg = LOG_NOTICE;
+ m->config.max_level_console = LOG_INFO;
+ m->config.max_level_wall = LOG_EMERG;
+ m->config.max_level_socket = LOG_DEBUG;
+
+ m->line_max = DEFAULT_LINE_MAX;
+}
+
+static void manager_reset_configs(Manager *m) {
+ assert(m);
+
+ m->config_by_cmdline = JOURNAL_CONFIG_INIT;
+ m->config_by_conf = JOURNAL_CONFIG_INIT;
+ m->config_by_cred = JOURNAL_CONFIG_INIT;
+}
+
+static void manager_merge_forward_to_socket(Manager *m) {
+ assert(m);
+
+ /* Conf file takes precedence over credentials. */
+ if (m->config_by_conf.forward_to_socket.sockaddr.sa.sa_family != AF_UNSPEC)
+ m->config.forward_to_socket = m->config_by_conf.forward_to_socket;
+ else if (m->config_by_cred.forward_to_socket.sockaddr.sa.sa_family != AF_UNSPEC)
+ m->config.forward_to_socket = m->config_by_cred.forward_to_socket;
+ else
+ m->config.forward_to_socket = (SocketAddress) { .sockaddr.sa.sa_family = AF_UNSPEC };
+}
+
+static void manager_merge_storage(Manager *m) {
+ assert(m);
+
+ /* Conf file takes precedence over credentials. */
+ if (m->config_by_conf.storage != _STORAGE_INVALID)
+ m->config.storage = m->config_by_conf.storage;
+ else if (m->config_by_cred.storage != _STORAGE_INVALID)
+ m->config.storage = m->config_by_cred.storage;
+ else
+ m->config.storage = m->namespace ? STORAGE_PERSISTENT : STORAGE_AUTO;
+}
+
+#define MERGE_BOOL(name, default_value) \
+ (m->config.name = (m->config_by_cmdline.name ? m->config_by_cmdline.name : \
+ m->config_by_conf.name ? m->config_by_conf.name : \
+ m->config_by_cred.name ? m->config_by_cred.name : \
+ default_value))
+
+#define MERGE_NON_NEGATIVE(name, default_value) \
+ (m->config.name = (m->config_by_cmdline.name >= 0 ? m->config_by_cmdline.name : \
+ m->config_by_conf.name >= 0 ? m->config_by_conf.name : \
+ m->config_by_cred.name >= 0 ? m->config_by_cred.name : \
+ default_value))
+
+static void manager_merge_configs(Manager *m) {
+ assert(m);
+
+ /*
+ * From highest to lowest priority: cmdline, conf, cred
+ */
+ manager_merge_storage(m);
+ manager_merge_forward_to_socket(m);
+
+ MERGE_BOOL(forward_to_syslog, false);
+ MERGE_BOOL(forward_to_kmsg, false);
+ MERGE_BOOL(forward_to_console, false);
+ MERGE_BOOL(forward_to_wall, true);
+
+ MERGE_NON_NEGATIVE(max_level_store, LOG_DEBUG);
+ MERGE_NON_NEGATIVE(max_level_syslog, LOG_DEBUG);
+ MERGE_NON_NEGATIVE(max_level_kmsg, LOG_NOTICE);
+ MERGE_NON_NEGATIVE(max_level_console, LOG_INFO);
+ MERGE_NON_NEGATIVE(max_level_wall, LOG_EMERG);
+ MERGE_NON_NEGATIVE(max_level_socket, LOG_DEBUG);
+}
+
+static void manager_adjust_configs(Manager *m) {
+ assert(m);
+
+ if (!!m->ratelimit_interval != !!m->ratelimit_burst) { /* One set to 0 and the other not? */
+ log_debug("Setting both rate limit interval and burst from %s/%u to 0/0",
+ FORMAT_TIMESPAN(m->ratelimit_interval, USEC_PER_SEC),
+ m->ratelimit_burst);
+ m->ratelimit_interval = m->ratelimit_burst = 0;
+ }
+}
+
+static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
+ Manager *m = ASSERT_PTR(data);
+ int r;
+
+ if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_syslog")) {
+
+ r = value ? parse_boolean(value) : true;
+ if (r < 0)
+ log_warning("Failed to parse forward to syslog switch \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.forward_to_syslog = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_kmsg")) {
+
+ r = value ? parse_boolean(value) : true;
+ if (r < 0)
+ log_warning("Failed to parse forward to kmsg switch \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.forward_to_kmsg = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_console")) {
+
+ r = value ? parse_boolean(value) : true;
+ if (r < 0)
+ log_warning("Failed to parse forward to console switch \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.forward_to_console = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_wall")) {
+
+ r = value ? parse_boolean(value) : true;
+ if (r < 0)
+ log_warning("Failed to parse forward to wall switch \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.forward_to_wall = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_console")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = log_level_from_string(value);
+ if (r < 0)
+ log_warning("Failed to parse max level console value \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.max_level_console = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_store")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = log_level_from_string(value);
+ if (r < 0)
+ log_warning("Failed to parse max level store value \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.max_level_store = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_syslog")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = log_level_from_string(value);
+ if (r < 0)
+ log_warning("Failed to parse max level syslog value \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.max_level_syslog = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_kmsg")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = log_level_from_string(value);
+ if (r < 0)
+ log_warning("Failed to parse max level kmsg value \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.max_level_kmsg = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_wall")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = log_level_from_string(value);
+ if (r < 0)
+ log_warning("Failed to parse max level wall value \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.max_level_wall = r;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_socket")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = log_level_from_string(value);
+ if (r < 0)
+ log_warning("Failed to parse max level socket value \"%s\". Ignoring.", value);
+ else
+ m->config_by_cmdline.max_level_socket = r;
+
+ } else if (startswith(key, "systemd.journald"))
+ log_warning("Unknown journald kernel command line option \"%s\". Ignoring.", key);
+
+ /* do not warn about state here, since probably systemd already did */
+ return 0;
+}
+
+static void manager_parse_config_file(Manager *m) {
+ const char *conf_file;
+
+ assert(m);
+
+ if (m->namespace)
+ conf_file = strjoina("systemd/journald@", m->namespace, ".conf");
+ else
+ conf_file = "systemd/journald.conf";
+
+ (void) config_parse_standard_file_with_dropins(
+ conf_file,
+ "Journal\0",
+ config_item_perf_lookup,
+ journald_gperf_lookup,
+ CONFIG_PARSE_WARN,
+ m);
+}
+
+static void manager_load_credentials(Manager *m) {
+ _cleanup_free_ void *data = NULL;
+ int r;
+
+ assert(m);
+
+ r = read_credential("journal.forward_to_socket", &data, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential journal.forward_to_socket, ignoring: %m");
+ else {
+ r = socket_address_parse(&m->config_by_cred.forward_to_socket, data);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse socket address '%s' from credential journal.forward_to_socket, ignoring: %m", (char *) data);
+ }
+
+ data = mfree(data);
+
+ r = read_credential("journal.storage", &data, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential journal.storage, ignoring: %m");
+ else {
+ r = storage_from_string(data);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse storage '%s' from credential journal.storage, ignoring: %m", (char *) data);
+ else
+ m->config_by_cred.storage = r;
+ }
+}
+
+void manager_load_config(Manager *m) {
+ int r;
+
+ assert(m);
+
+ manager_set_defaults(m);
+ manager_reset_configs(m);
+
+ manager_load_credentials(m);
+ manager_parse_config_file(m);
+
+ if (!m->namespace) {
+ /* Parse kernel command line, but only if we are not a namespace instance */
+ r = proc_cmdline_parse(parse_proc_cmdline_item, m, PROC_CMDLINE_STRIP_RD_PREFIX);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
+ }
+
+ manager_merge_configs(m);
+
+ manager_adjust_configs(m);
+}
+
+static void manager_reload_config(Manager *m) {
+ assert(m);
+
+ manager_set_defaults(m);
+
+ m->config_by_conf = JOURNAL_CONFIG_INIT;
+ manager_parse_config_file(m);
+
+ manager_merge_configs(m);
+ manager_adjust_configs(m);
+}
+
+int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = ASSERT_PTR(userdata);
+ int r;
+
+ (void) notify_reloading();
+
+ manager_reload_config(m);
+
+ r = manager_reload_dev_kmsg(m);
+ if (r < 0)
+ return r;
+
+ r = manager_reload_journals(m);
+ if (r < 0)
+ return r;
+
+ log_info("Config file reloaded.");
+ (void) sd_notify(/* unset_environment */ false, NOTIFY_READY_MESSAGE);
+
+ return 0;
+}
+
+static const char* const storage_table[_STORAGE_MAX] = {
+ [STORAGE_AUTO] = "auto",
+ [STORAGE_VOLATILE] = "volatile",
+ [STORAGE_PERSISTENT] = "persistent",
+ [STORAGE_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage);
+
+static const char* const split_mode_table[_SPLIT_MAX] = {
+ [SPLIT_LOGIN] = "login",
+ [SPLIT_UID] = "uid",
+ [SPLIT_NONE] = "none",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode);
+
+int config_parse_line_max(
+ 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) {
+
+ size_t *sz = ASSERT_PTR(data);
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue))
+ /* Empty assignment means default */
+ *sz = DEFAULT_LINE_MAX;
+ else {
+ uint64_t v;
+
+ r = parse_size(rvalue, 1024, &v);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse LineMax= value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (v < 79) {
+ /* Why specify 79 here as minimum line length? Simply, because the most common traditional
+ * terminal size is 80ch, and it might make sense to break one character before the natural
+ * line break would occur on that. */
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too small, clamping to 79: %s", rvalue);
+ *sz = 79;
+ } else if (v > (uint64_t) (SSIZE_MAX-1)) {
+ /* So, why specify SSIZE_MAX-1 here? Because that's one below the largest size value read()
+ * can return, and we need one extra byte for the trailing NUL byte. Of course IRL such large
+ * memory allocations will fail anyway, hence this limit is mostly theoretical anyway, as we'll
+ * fail much earlier anyway. */
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too large, clamping to %" PRIu64 ": %s", (uint64_t) (SSIZE_MAX-1), rvalue);
+ *sz = SSIZE_MAX-1;
+ } else
+ *sz = (size_t) v;
+ }
+
+ return 0;
+}
+
+int config_parse_compress(
+ 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) {
+
+ JournalCompressOptions* compress = ASSERT_PTR(data);
+ int r;
+
+ assert(filename);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ compress->enabled = true;
+ compress->threshold_bytes = UINT64_MAX;
+ } else if (streq(rvalue, "1")) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Compress= ambiguously specified as 1, enabling compression with default threshold");
+ compress->enabled = true;
+ } else if (streq(rvalue, "0")) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Compress= ambiguously specified as 0, disabling compression");
+ compress->enabled = false;
+ } else {
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ r = parse_size(rvalue, 1024, &compress->threshold_bytes);
+ if (r < 0)
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse Compress= value, ignoring: %s", rvalue);
+ else
+ compress->enabled = true;
+ } else
+ compress->enabled = r;
+ }
+
+ return 0;
+}
+
+int config_parse_forward_to_socket(
+ 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) {
+
+ SocketAddress* addr = ASSERT_PTR(data);
+ int r;
+
+ assert(filename);
+ assert(rvalue);
+
+ if (isempty(rvalue))
+ *addr = (SocketAddress) { .sockaddr.sa.sa_family = AF_UNSPEC };
+ else {
+ r = socket_address_parse(addr, rvalue);
+ if (r < 0)
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse ForwardToSocket= value, ignoring: %s", rvalue);
+ }
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "journald-forward.h"
+#include "socket-util.h"
+
+typedef enum Storage {
+ STORAGE_AUTO,
+ STORAGE_VOLATILE,
+ STORAGE_PERSISTENT,
+ STORAGE_NONE,
+ _STORAGE_MAX,
+ _STORAGE_INVALID = -EINVAL,
+} Storage;
+
+typedef enum SplitMode {
+ SPLIT_UID,
+ SPLIT_LOGIN, /* deprecated */
+ SPLIT_NONE,
+ _SPLIT_MAX,
+ _SPLIT_INVALID = -EINVAL,
+} SplitMode;
+
+typedef struct JournalCompressOptions {
+ bool enabled;
+ uint64_t threshold_bytes;
+} JournalCompressOptions;
+
+typedef struct JournalConfig {
+ Storage storage;
+
+ bool forward_to_kmsg;
+ bool forward_to_syslog;
+ bool forward_to_console;
+ bool forward_to_wall;
+
+ SocketAddress forward_to_socket;
+
+ int max_level_store;
+ int max_level_syslog;
+ int max_level_kmsg;
+ int max_level_console;
+ int max_level_wall;
+ int max_level_socket;
+} JournalConfig;
+
+void manager_load_config(Manager *m);
+int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
+
+/* Defined in generated journald-gperf.c */
+const struct ConfigPerfItem* journald_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
+
+const char* storage_to_string(Storage s) _const_;
+Storage storage_from_string(const char *s) _pure_;
+
+const char* split_mode_to_string(SplitMode s) _const_;
+SplitMode split_mode_from_string(const char *s) _pure_;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_storage);
+CONFIG_PARSER_PROTOTYPE(config_parse_line_max);
+CONFIG_PARSER_PROTOTYPE(config_parse_compress);
+CONFIG_PARSER_PROTOTYPE(config_parse_forward_to_socket);
+CONFIG_PARSER_PROTOTYPE(config_parse_split_mode);
#include "conf-parser-forward.h" /* IWYU pragma: export */
#include "forward.h" /* IWYU pragma: export */
+typedef enum Storage Storage;
+typedef enum SplitMode SplitMode;
+typedef struct JournalCompressOptions JournalCompressOptions;
+typedef struct JournalConfig JournalConfig;
+
typedef struct Manager Manager;
typedef struct StreamSyncReq StreamSyncReq;
typedef struct SyncReq SyncReq;
#include "journal-internal.h"
#include "journal-vacuum.h"
#include "journald-audit.h"
+#include "journald-config.h"
#include "journald-context.h"
#include "journald-kmsg.h"
#include "journald-manager.h"
#include "parse-util.h"
#include "path-util.h"
#include "prioq.h"
-#include "proc-cmdline.h"
#include "process-util.h"
#include "rm-rf.h"
#include "set.h"
#include "socket-netlink.h"
#include "socket-util.h"
#include "stdio-util.h"
-#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
#define USER_JOURNALS_MAX 1024
-#define DEFAULT_SYNC_INTERVAL_USEC (5*USEC_PER_MINUTE)
-#define DEFAULT_RATE_LIMIT_INTERVAL (30*USEC_PER_SEC)
-#define DEFAULT_RATE_LIMIT_BURST 10000
-#define DEFAULT_MAX_FILE_USEC USEC_PER_MONTH
-
#define DEFAULT_KMSG_OWN_INTERVAL (5 * USEC_PER_SEC)
#define DEFAULT_KMSG_OWN_BURST 50
/* The period to insert between posting changes for coalescing */
#define POST_CHANGE_TIMER_INTERVAL_USEC (250*USEC_PER_MSEC)
-/* Pick a good default that is likely to fit into AF_UNIX and AF_INET SOCK_DGRAM datagrams, and even leaves some room
- * for a bit of additional metadata. */
-#define DEFAULT_LINE_MAX (48*1024)
-
#define DEFERRED_CLOSES_MAX (4096)
#define IDLE_TIMEOUT_USEC (30*USEC_PER_SEC)
static int manager_schedule_sync(Manager *m, int priority);
static int manager_refresh_idle_timer(Manager *m);
-static int dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
static int manager_determine_path_usage(
Manager *m,
if (r < 0)
return r;
- r = sd_event_add_signal(m->event, NULL, SIGHUP|SD_EVENT_SIGNAL_PROCMASK, dispatch_reload_signal, m);
+ r = sd_event_add_signal(m->event, NULL, SIGHUP|SD_EVENT_SIGNAL_PROCMASK, manager_dispatch_reload_signal, m);
if (r < 0)
return r;
return 0;
}
-static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
- Manager *m = ASSERT_PTR(data);
- int r;
-
- if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_syslog")) {
-
- r = value ? parse_boolean(value) : true;
- if (r < 0)
- log_warning("Failed to parse forward to syslog switch \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.forward_to_syslog = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_kmsg")) {
-
- r = value ? parse_boolean(value) : true;
- if (r < 0)
- log_warning("Failed to parse forward to kmsg switch \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.forward_to_kmsg = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_console")) {
-
- r = value ? parse_boolean(value) : true;
- if (r < 0)
- log_warning("Failed to parse forward to console switch \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.forward_to_console = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_wall")) {
-
- r = value ? parse_boolean(value) : true;
- if (r < 0)
- log_warning("Failed to parse forward to wall switch \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.forward_to_wall = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_console")) {
-
- if (proc_cmdline_value_missing(key, value))
- return 0;
-
- r = log_level_from_string(value);
- if (r < 0)
- log_warning("Failed to parse max level console value \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.max_level_console = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_store")) {
-
- if (proc_cmdline_value_missing(key, value))
- return 0;
-
- r = log_level_from_string(value);
- if (r < 0)
- log_warning("Failed to parse max level store value \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.max_level_store = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_syslog")) {
-
- if (proc_cmdline_value_missing(key, value))
- return 0;
-
- r = log_level_from_string(value);
- if (r < 0)
- log_warning("Failed to parse max level syslog value \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.max_level_syslog = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_kmsg")) {
-
- if (proc_cmdline_value_missing(key, value))
- return 0;
-
- r = log_level_from_string(value);
- if (r < 0)
- log_warning("Failed to parse max level kmsg value \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.max_level_kmsg = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_wall")) {
-
- if (proc_cmdline_value_missing(key, value))
- return 0;
-
- r = log_level_from_string(value);
- if (r < 0)
- log_warning("Failed to parse max level wall value \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.max_level_wall = r;
-
- } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_socket")) {
-
- if (proc_cmdline_value_missing(key, value))
- return 0;
-
- r = log_level_from_string(value);
- if (r < 0)
- log_warning("Failed to parse max level socket value \"%s\". Ignoring.", value);
- else
- m->config_by_cmdline.max_level_socket = r;
-
- } else if (startswith(key, "systemd.journald"))
- log_warning("Unknown journald kernel command line option \"%s\". Ignoring.", key);
-
- /* do not warn about state here, since probably systemd already did */
- return 0;
-}
-
-static int manager_parse_config_file(Manager *m) {
- const char *conf_file;
-
- assert(m);
-
- if (m->namespace)
- conf_file = strjoina("systemd/journald@", m->namespace, ".conf");
- else
- conf_file = "systemd/journald.conf";
-
- return config_parse_standard_file_with_dropins(
- conf_file,
- "Journal\0",
- config_item_perf_lookup, journald_gperf_lookup,
- CONFIG_PARSE_WARN,
- /* userdata= */ m);
-}
-
static int manager_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
return 0;
}
-static void manager_load_credentials(Manager *m) {
- _cleanup_free_ void *data = NULL;
- int r;
-
- assert(m);
-
- r = read_credential("journal.forward_to_socket", &data, NULL);
- if (r < 0)
- log_debug_errno(r, "Failed to read credential journal.forward_to_socket, ignoring: %m");
- else {
- r = socket_address_parse(&m->config_by_cred.forward_to_socket, data);
- if (r < 0)
- log_debug_errno(r, "Failed to parse socket address '%s' from credential journal.forward_to_socket, ignoring: %m", (char *) data);
- }
-
- data = mfree(data);
-
- r = read_credential("journal.storage", &data, NULL);
- if (r < 0)
- log_debug_errno(r, "Failed to read credential journal.storage, ignoring: %m");
- else {
- r = storage_from_string(data);
- if (r < 0)
- log_debug_errno(r, "Failed to parse storage '%s' from credential journal.storage, ignoring: %m", (char *) data);
- else
- m->config_by_cred.storage = r;
- }
-}
-
-static void manager_set_defaults(Manager *m) {
- assert(m);
-
- m->compress.enabled = true;
- m->compress.threshold_bytes = UINT64_MAX;
-
- m->seal = true;
-
- /* By default, only read from /dev/kmsg if are the main namespace */
- m->read_kmsg = !m->namespace;
-
- m->set_audit = true;
-
- m->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC;
-
- m->ratelimit_interval = DEFAULT_RATE_LIMIT_INTERVAL;
- m->ratelimit_burst = DEFAULT_RATE_LIMIT_BURST;
-
- m->system_storage.name = "System Journal";
- journal_reset_metrics(&m->system_storage.metrics);
-
- m->runtime_storage.name = "Runtime Journal";
- journal_reset_metrics(&m->runtime_storage.metrics);
-
- m->max_file_usec = DEFAULT_MAX_FILE_USEC;
-
- m->config.forward_to_wall = true;
-
- m->config.max_level_store = LOG_DEBUG;
- m->config.max_level_syslog = LOG_DEBUG;
- m->config.max_level_kmsg = LOG_NOTICE;
- m->config.max_level_console = LOG_INFO;
- m->config.max_level_wall = LOG_EMERG;
- m->config.max_level_socket = LOG_DEBUG;
-
- m->line_max = DEFAULT_LINE_MAX;
-}
-
-static void manager_reset_configs(Manager *m) {
- assert(m);
-
- m->config_by_cmdline = JOURNAL_CONFIG_INIT;
- m->config_by_conf = JOURNAL_CONFIG_INIT;
- m->config_by_cred = JOURNAL_CONFIG_INIT;
-}
-
-static void manager_adjust_configs(Manager *m) {
- assert(m);
-
- if (!!m->ratelimit_interval != !!m->ratelimit_burst) { /* One set to 0 and the other not? */
- log_debug(
- "Setting both rate limit interval and burst from %s/%u to 0/0",
- FORMAT_TIMESPAN(m->ratelimit_interval, USEC_PER_SEC),
- m->ratelimit_burst);
- m->ratelimit_interval = m->ratelimit_burst = 0;
- }
-}
-
-static void manager_merge_forward_to_socket(Manager *m) {
- assert(m);
-
- /* Conf file takes precedence over credentials. */
- if (m->config_by_conf.forward_to_socket.sockaddr.sa.sa_family != AF_UNSPEC)
- m->config.forward_to_socket = m->config_by_conf.forward_to_socket;
- else if (m->config_by_cred.forward_to_socket.sockaddr.sa.sa_family != AF_UNSPEC)
- m->config.forward_to_socket = m->config_by_cred.forward_to_socket;
- else
- m->config.forward_to_socket = (SocketAddress) { .sockaddr.sa.sa_family = AF_UNSPEC };
-}
-
-static void manager_merge_storage(Manager *m) {
- assert(m);
-
- /* Conf file takes precedence over credentials. */
- if (m->config_by_conf.storage != _STORAGE_INVALID)
- m->config.storage = m->config_by_conf.storage;
- else if (m->config_by_cred.storage != _STORAGE_INVALID)
- m->config.storage = m->config_by_cred.storage;
- else
- m->config.storage = m->namespace ? STORAGE_PERSISTENT : STORAGE_AUTO;
-}
-
-#define MERGE_BOOL(name, default_value) \
- (m->config.name = (m->config_by_cmdline.name ? m->config_by_cmdline.name : \
- m->config_by_conf.name ? m->config_by_conf.name : \
- m->config_by_cred.name ? m->config_by_cred.name : \
- default_value))
-
-#define MERGE_NON_NEGATIVE(name, default_value) \
- (m->config.name = (m->config_by_cmdline.name >= 0 ? m->config_by_cmdline.name : \
- m->config_by_conf.name >= 0 ? m->config_by_conf.name : \
- m->config_by_cred.name >= 0 ? m->config_by_cred.name : \
- default_value))
-
-static void manager_merge_configs(Manager *m) {
- assert(m);
-
- /*
- * From highest to lowest priority: cmdline, conf, cred
- */
- manager_merge_storage(m);
- manager_merge_forward_to_socket(m);
-
- MERGE_BOOL(forward_to_syslog, false);
- MERGE_BOOL(forward_to_kmsg, false);
- MERGE_BOOL(forward_to_console, false);
- MERGE_BOOL(forward_to_wall, true);
-
- MERGE_NON_NEGATIVE(max_level_store, LOG_DEBUG);
- MERGE_NON_NEGATIVE(max_level_syslog, LOG_DEBUG);
- MERGE_NON_NEGATIVE(max_level_kmsg, LOG_NOTICE);
- MERGE_NON_NEGATIVE(max_level_console, LOG_INFO);
- MERGE_NON_NEGATIVE(max_level_wall, LOG_EMERG);
- MERGE_NON_NEGATIVE(max_level_socket, LOG_DEBUG);
-}
-
-static void manager_load_config(Manager *m) {
- assert(m);
-
- int r;
-
- manager_set_defaults(m);
- manager_reset_configs(m);
-
- manager_load_credentials(m);
- manager_parse_config_file(m);
-
- if (!m->namespace) {
- /* Parse kernel command line, but only if we are not a namespace instance */
- r = proc_cmdline_parse(parse_proc_cmdline_item, m, PROC_CMDLINE_STRIP_RD_PREFIX);
- if (r < 0)
- log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
- }
-
- manager_merge_configs(m);
-
- manager_adjust_configs(m);
-}
-
-static void manager_reload_config(Manager *m) {
- assert(m);
-
- manager_set_defaults(m);
-
- m->config_by_conf = JOURNAL_CONFIG_INIT;
- manager_parse_config_file(m);
-
- manager_merge_configs(m);
- manager_adjust_configs(m);
-}
-
-static int manager_reload_journals(Manager *m) {
+int manager_reload_journals(Manager *m) {
assert(m);
int r;
return 0;
}
-static int dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
- Manager *m = ASSERT_PTR(userdata);
- int r;
-
- (void) notify_reloading();
-
- manager_reload_config(m);
-
- r = manager_reload_dev_kmsg(m);
- if (r < 0)
- return r;
-
- r = manager_reload_journals(m);
- if (r < 0)
- return r;
-
- log_info("Config file reloaded.");
- (void) sd_notify(/* unset_environment */ false, NOTIFY_READY_MESSAGE);
-
- return 0;
-}
-
int manager_new(Manager **ret, const char *namespace) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
return mfree(m);
}
-
-static const char* const storage_table[_STORAGE_MAX] = {
- [STORAGE_AUTO] = "auto",
- [STORAGE_VOLATILE] = "volatile",
- [STORAGE_PERSISTENT] = "persistent",
- [STORAGE_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage);
-
-static const char* const split_mode_table[_SPLIT_MAX] = {
- [SPLIT_LOGIN] = "login",
- [SPLIT_UID] = "uid",
- [SPLIT_NONE] = "none",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode);
-
-int config_parse_line_max(
- 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) {
-
- size_t *sz = ASSERT_PTR(data);
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue))
- /* Empty assignment means default */
- *sz = DEFAULT_LINE_MAX;
- else {
- uint64_t v;
-
- r = parse_size(rvalue, 1024, &v);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse LineMax= value, ignoring: %s", rvalue);
- return 0;
- }
-
- if (v < 79) {
- /* Why specify 79 here as minimum line length? Simply, because the most common traditional
- * terminal size is 80ch, and it might make sense to break one character before the natural
- * line break would occur on that. */
- log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too small, clamping to 79: %s", rvalue);
- *sz = 79;
- } else if (v > (uint64_t) (SSIZE_MAX-1)) {
- /* So, why specify SSIZE_MAX-1 here? Because that's one below the largest size value read()
- * can return, and we need one extra byte for the trailing NUL byte. Of course IRL such large
- * memory allocations will fail anyway, hence this limit is mostly theoretical anyway, as we'll
- * fail much earlier anyway. */
- log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too large, clamping to %" PRIu64 ": %s", (uint64_t) (SSIZE_MAX-1), rvalue);
- *sz = SSIZE_MAX-1;
- } else
- *sz = (size_t) v;
- }
-
- return 0;
-}
-
-int config_parse_compress(
- 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) {
-
- JournalCompressOptions* compress = ASSERT_PTR(data);
- int r;
-
- assert(filename);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- compress->enabled = true;
- compress->threshold_bytes = UINT64_MAX;
- } else if (streq(rvalue, "1")) {
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Compress= ambiguously specified as 1, enabling compression with default threshold");
- compress->enabled = true;
- } else if (streq(rvalue, "0")) {
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Compress= ambiguously specified as 0, disabling compression");
- compress->enabled = false;
- } else {
- r = parse_boolean(rvalue);
- if (r < 0) {
- r = parse_size(rvalue, 1024, &compress->threshold_bytes);
- if (r < 0)
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Failed to parse Compress= value, ignoring: %s", rvalue);
- else
- compress->enabled = true;
- } else
- compress->enabled = r;
- }
-
- return 0;
-}
-
-int config_parse_forward_to_socket(
- 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) {
-
- SocketAddress* addr = ASSERT_PTR(data);
- int r;
-
- assert(filename);
- assert(rvalue);
-
- if (isempty(rvalue))
- *addr = (SocketAddress) { .sockaddr.sa.sa_family = AF_UNSPEC };
- else {
- r = socket_address_parse(addr, rvalue);
- if (r < 0)
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Failed to parse ForwardToSocket= value, ignoring: %s", rvalue);
- }
-
- return 0;
-}
#include "common-signal.h"
#include "journal-file.h"
+#include "journald-config.h"
#include "journald-forward.h"
#include "list.h"
#include "ratelimit.h"
#include "socket-util.h"
-typedef enum Storage {
- STORAGE_AUTO,
- STORAGE_VOLATILE,
- STORAGE_PERSISTENT,
- STORAGE_NONE,
- _STORAGE_MAX,
- _STORAGE_INVALID = -EINVAL,
-} Storage;
-
-typedef enum SplitMode {
- SPLIT_UID,
- SPLIT_LOGIN, /* deprecated */
- SPLIT_NONE,
- _SPLIT_MAX,
- _SPLIT_INVALID = -EINVAL,
-} SplitMode;
-
-typedef struct JournalCompressOptions {
- bool enabled;
- uint64_t threshold_bytes;
-} JournalCompressOptions;
-
typedef struct JournalStorageSpace {
usec_t timestamp;
uint64_t seqnum;
} SeqnumData;
-typedef struct JournalConfig {
- SocketAddress forward_to_socket;
- Storage storage;
-
- bool forward_to_kmsg;
- bool forward_to_syslog;
- bool forward_to_console;
- bool forward_to_wall;
-
- int max_level_store;
- int max_level_syslog;
- int max_level_kmsg;
- int max_level_console;
- int max_level_wall;
- int max_level_socket;
-} JournalConfig;
-
typedef struct Manager {
char *namespace;
LIST_HEAD(SyncReq, sync_req_pending_rqlen);
/* These structs are used to preserve configurations set by credentials and command line.
- config - main configuration used by journald manager,
- config_by_cred - configuration set by credentials,
- config_by_conf - configuration set by configuration file,
- config_by_cmdline - configuration set by command line.
- The priority order of the sub-configurations is:
- config_by_cmdline > config_by_conf > config_by_cred
- where A > B means that if the two have the same setting,
- A's value overrides B's value for that setting.
- */
+ * - config - main configuration used by journald manager,
+ * - config_by_cred - configuration set by credentials,
+ * - config_by_conf - configuration set by configuration file,
+ * - config_by_cmdline - configuration set by command line.
+ * The priority order of the sub-configurations is:
+ * config_by_cmdline > config_by_conf > config_by_cred
+ * where A > B means that if the two have the same setting, A's value overrides B's value for that
+ * setting. */
JournalConfig config;
JournalConfig config_by_cred;
JournalConfig config_by_conf;
void manager_driver_message_internal(Manager *m, pid_t object_pid, const char *format, ...) _sentinel_;
#define manager_driver_message(...) manager_driver_message_internal(__VA_ARGS__, NULL)
-#define JOURNAL_CONFIG_INIT \
- (JournalConfig) { \
- .forward_to_socket = (SocketAddress) { .sockaddr.sa.sa_family = AF_UNSPEC }, \
- .storage = _STORAGE_INVALID, \
- .max_level_store = -1, \
- .max_level_syslog = -1, \
- .max_level_kmsg = -1, \
- .max_level_console = -1, \
- .max_level_wall = -1, \
- .max_level_socket = -1, \
- }
-
-/* gperf lookup function */
-const struct ConfigPerfItem* journald_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
-
-CONFIG_PARSER_PROTOTYPE(config_parse_storage);
-CONFIG_PARSER_PROTOTYPE(config_parse_line_max);
-CONFIG_PARSER_PROTOTYPE(config_parse_compress);
-CONFIG_PARSER_PROTOTYPE(config_parse_forward_to_socket);
-
-const char* storage_to_string(Storage s) _const_;
-Storage storage_from_string(const char *s) _pure_;
-
-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 manager_new(Manager **ret, const char *namespace);
int manager_init(Manager *m);
Manager* manager_free(Manager *m);
void manager_space_usage_message(Manager *m, JournalStorage *storage);
int manager_start_or_stop_idle_timer(Manager *m);
+int manager_reload_journals(Manager *m);
int manager_map_seqnum_file(Manager *m, const char *fname, size_t size, void **ret);
systemd_journald_extract_sources = files(
'journald-audit.c',
'journald-client.c',
+ 'journald-config.c',
'journald-console.c',
'journald-context.c',
'journald-kmsg.c',