]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journald: move several configuration related definitions to journald-config.[ch]
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 13 Jul 2025 02:46:46 +0000 (11:46 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 18 Jul 2025 06:25:35 +0000 (15:25 +0900)
No functional change, just refactoring and preparation for later changes.

src/journal/journald-config.c [new file with mode: 0644]
src/journal/journald-config.h [new file with mode: 0644]
src/journal/journald-forward.h
src/journal/journald-manager.c
src/journal/journald-manager.h
src/journal/meson.build

diff --git a/src/journal/journald-config.c b/src/journal/journald-config.c
new file mode 100644 (file)
index 0000000..58d86b5
--- /dev/null
@@ -0,0 +1,513 @@
+/* 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;
+}
diff --git a/src/journal/journald-config.h b/src/journal/journald-config.h
new file mode 100644 (file)
index 0000000..ffa6c5f
--- /dev/null
@@ -0,0 +1,63 @@
+/* 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);
index 41214b87f69ec527822eea45c685f68a71921708..65458f46ab0a72b93a8c9e49dfd2a32845c611e3 100644 (file)
@@ -4,6 +4,11 @@
 #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;
index 8b10ce97106f30edf97a00d51c07b5b0d4b4a990..ea8ca4365302da97da98ae1e27115e913b81d1cd 100644 (file)
@@ -38,6 +38,7 @@
 #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"
@@ -55,7 +56,6 @@
 #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"
@@ -63,7 +63,6 @@
 #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,
@@ -1863,140 +1852,13 @@ static int manager_setup_signals(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);
 
@@ -2392,187 +2254,7 @@ static int manager_setup_memory_pressure(Manager *m) {
         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;
@@ -2611,28 +2293,6 @@ static int manager_reload_journals(Manager *m) {
         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;
@@ -2967,148 +2627,3 @@ Manager* manager_free(Manager *m) {
 
         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;
-}
index 4bcb75aa8fdf0be1d98ae6e83c297e2f676e0356..ac538a12e753e3ad3848a47d738be272f99755a9 100644 (file)
@@ -3,33 +3,12 @@
 
 #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;
 
@@ -55,23 +34,6 @@ typedef struct SeqnumData {
         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;
 
@@ -188,15 +150,14 @@ typedef struct Manager {
         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;
@@ -227,34 +188,6 @@ void manager_dispatch_message(Manager *m, struct iovec *iovec, size_t n, size_t
 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);
@@ -271,5 +204,6 @@ int manager_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
 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);
index e5da683b3800a5ecba6b0cd39458c1bc6bf0b9d7..5f34cd6866c5b07a51bd9d2d3397494d70aa66f1 100644 (file)
@@ -6,6 +6,7 @@ systemd_journald_sources = files(
 systemd_journald_extract_sources = files(
         'journald-audit.c',
         'journald-client.c',
+        'journald-config.c',
         'journald-console.c',
         'journald-context.c',
         'journald-kmsg.c',