diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml index 3a9d8049725..eb84a311338 100644 --- a/man/systemd-journald.service.xml +++ b/man/systemd-journald.service.xml @@ -218,6 +218,22 @@ systemd-tmpfiles --create --prefix /var/log/journal + + + SIGHUP + + Upon reception of the SIGHUP process signal + systemd-journald will reload its configuration values + and update the kernel log buffer and journals to reflect the new configuration. + If ReadKmsg= has changed, the kernel log buffer will be flushed + and updated as part of the reload. The active journal (e.g., persistent, volatile) + will continue to be used with the updated configuration. + However, if the storage mode has changed from persistent to volatile + and the current journal in use is the persistent journal, then the active journal will + be switched to the volatile journal. + + + diff --git a/src/journal/fuzz-journald-audit.c b/src/journal/fuzz-journald-audit.c index 059becc04fe..7558900ff51 100644 --- a/src/journal/fuzz-journald-audit.c +++ b/src/journal/fuzz-journald-audit.c @@ -9,7 +9,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { fuzz_setup_logging(); - assert_se(manager_new(&m) >= 0); + assert_se(manager_new(&m, /* namespace= */ NULL) >= 0); dummy_manager_init(m, data, size); process_audit_string(m, 0, m->buffer, size); diff --git a/src/journal/fuzz-journald-kmsg.c b/src/journal/fuzz-journald-kmsg.c index 9c65bcf1776..2ef36172887 100644 --- a/src/journal/fuzz-journald-kmsg.c +++ b/src/journal/fuzz-journald-kmsg.c @@ -12,7 +12,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { fuzz_setup_logging(); - assert_se(manager_new(&m) >= 0); + assert_se(manager_new(&m, /* namespace= */ NULL) >= 0); dummy_manager_init(m, data, size); dev_kmsg_record(m, m->buffer, size); diff --git a/src/journal/fuzz-journald-native-fd.c b/src/journal/fuzz-journald-native-fd.c index ea07c5a354c..356e59046fb 100644 --- a/src/journal/fuzz-journald-native-fd.c +++ b/src/journal/fuzz-journald-native-fd.c @@ -21,7 +21,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { fuzz_setup_logging(); - assert_se(manager_new(&m) >= 0); + assert_se(manager_new(&m, /* namespace= */ NULL) >= 0); dummy_manager_init(m, NULL, 0); sealed_fd = memfd_new_and_seal(NULL, data, size); diff --git a/src/journal/fuzz-journald-stream.c b/src/journal/fuzz-journald-stream.c index cc3298f0dde..602bd59c45f 100644 --- a/src/journal/fuzz-journald-stream.c +++ b/src/journal/fuzz-journald-stream.c @@ -23,7 +23,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { fuzz_setup_logging(); assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0, stream_fds) >= 0); - assert_se(manager_new(&m) >= 0); + assert_se(manager_new(&m, /* namespace= */ NULL) >= 0); dummy_manager_init(m, NULL, 0); assert_se(stdout_stream_install(m, stream_fds[0], &stream) >= 0); diff --git a/src/journal/fuzz-journald.c b/src/journal/fuzz-journald.c index 5c2953dbdc2..0bb4d5d5650 100644 --- a/src/journal/fuzz-journald.c +++ b/src/journal/fuzz-journald.c @@ -9,7 +9,7 @@ void dummy_manager_init(Manager *m, const uint8_t *buffer, size_t size) { assert(m); - m->storage = STORAGE_NONE; + m->config.storage = STORAGE_NONE; assert_se(sd_event_default(&m->event) >= 0); if (buffer) { @@ -33,7 +33,7 @@ void fuzz_journald_processing_function( if (size == 0) return; - assert_se(manager_new(&m) >= 0); + assert_se(manager_new(&m, /* namespace= */ NULL) >= 0); dummy_manager_init(m, data, size); (*f)(m, m->buffer, size, ucred, tv, label, label_len); } diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c index 887b59b2690..73cccb4da98 100644 --- a/src/journal/journald-console.c +++ b/src/journal/journald-console.c @@ -52,7 +52,7 @@ void manager_forward_console( assert(m); assert(message); - if (LOG_PRI(priority) > m->max_level_console) + if (LOG_PRI(priority) > m->config.max_level_console) return; /* First: timestamp */ diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf index b2cfde3ade6..26cd08b3845 100644 --- a/src/journal/journald-gperf.gperf +++ b/src/journal/journald-gperf.gperf @@ -19,7 +19,7 @@ struct ConfigPerfItem; %struct-type %includes %% -Journal.Storage, config_parse_storage, 0, offsetof(Manager, storage) +Journal.Storage, config_parse_storage, 0, offsetof(Manager, config_by_conf.storage) Journal.Compress, config_parse_compress, 0, offsetof(Manager, compress) Journal.Seal, config_parse_bool, 0, offsetof(Manager, seal) Journal.ReadKMsg, config_parse_bool, 0, offsetof(Manager, read_kmsg) @@ -39,17 +39,17 @@ Journal.RuntimeKeepFree, config_parse_iec_uint64, 0, offsetof(Manager, Journal.RuntimeMaxFiles, config_parse_uint64, 0, offsetof(Manager, runtime_storage.metrics.n_max_files) Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(Manager, max_retention_usec) Journal.MaxFileSec, config_parse_sec, 0, offsetof(Manager, max_file_usec) -Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Manager, forward_to_syslog) -Journal.ForwardToKMsg, config_parse_bool, 0, offsetof(Manager, forward_to_kmsg) -Journal.ForwardToConsole, config_parse_bool, 0, offsetof(Manager, forward_to_console) -Journal.ForwardToWall, config_parse_bool, 0, offsetof(Manager, forward_to_wall) -Journal.ForwardToSocket, config_parse_forward_to_socket, 0, offsetof(Manager, forward_to_socket) +Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Manager, config_by_conf.forward_to_syslog) +Journal.ForwardToKMsg, config_parse_bool, 0, offsetof(Manager, config_by_conf.forward_to_kmsg) +Journal.ForwardToConsole, config_parse_bool, 0, offsetof(Manager, config_by_conf.forward_to_console) +Journal.ForwardToWall, config_parse_bool, 0, offsetof(Manager, config_by_conf.forward_to_wall) +Journal.ForwardToSocket, config_parse_forward_to_socket, 0, offsetof(Manager, config_by_conf.forward_to_socket) Journal.TTYPath, config_parse_path, 0, offsetof(Manager, tty_path) -Journal.MaxLevelStore, config_parse_log_level, 0, offsetof(Manager, max_level_store) -Journal.MaxLevelSyslog, config_parse_log_level, 0, offsetof(Manager, max_level_syslog) -Journal.MaxLevelKMsg, config_parse_log_level, 0, offsetof(Manager, max_level_kmsg) -Journal.MaxLevelConsole, config_parse_log_level, 0, offsetof(Manager, max_level_console) -Journal.MaxLevelWall, config_parse_log_level, 0, offsetof(Manager, max_level_wall) -Journal.MaxLevelSocket, config_parse_log_level, 0, offsetof(Manager, max_level_socket) +Journal.MaxLevelStore, config_parse_log_level, 0, offsetof(Manager, config_by_conf.max_level_store) +Journal.MaxLevelSyslog, config_parse_log_level, 0, offsetof(Manager, config_by_conf.max_level_syslog) +Journal.MaxLevelKMsg, config_parse_log_level, 0, offsetof(Manager, config_by_conf.max_level_kmsg) +Journal.MaxLevelConsole, config_parse_log_level, 0, offsetof(Manager, config_by_conf.max_level_console) +Journal.MaxLevelWall, config_parse_log_level, 0, offsetof(Manager, config_by_conf.max_level_wall) +Journal.MaxLevelSocket, config_parse_log_level, 0, offsetof(Manager, config_by_conf.max_level_socket) Journal.SplitMode, config_parse_split_mode, 0, offsetof(Manager, split_mode) Journal.LineMax, config_parse_line_max, 0, offsetof(Manager, line_max) diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index f8185baefc1..926cc823db5 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -46,7 +46,7 @@ void manager_forward_kmsg( assert(priority <= 999); assert(message); - if (_unlikely_(LOG_PRI(priority) > m->max_level_kmsg)) + if (_unlikely_(LOG_PRI(priority) > m->config.max_level_kmsg)) return; if (_unlikely_(m->dev_kmsg_fd < 0)) @@ -128,7 +128,7 @@ void dev_kmsg_record(Manager *m, char *p, size_t l) { if (r < 0 || priority < 0 || priority > 999) return; - if (m->forward_to_kmsg && LOG_FAC(priority) != LOG_KERN) + if (m->config.forward_to_kmsg && LOG_FAC(priority) != LOG_KERN) return; /* seqnum */ @@ -389,6 +389,10 @@ static int dispatch_dev_kmsg(sd_event_source *es, int fd, uint32_t revents, void return manager_read_dev_kmsg(m); } +static mode_t manager_kmsg_mode(bool read_kmsg) { + return O_CLOEXEC|O_NONBLOCK|O_NOCTTY|(read_kmsg ? O_RDWR : O_WRONLY); +} + int manager_open_dev_kmsg(Manager *m) { int r; @@ -396,7 +400,7 @@ int manager_open_dev_kmsg(Manager *m) { assert(m->dev_kmsg_fd < 0); assert(!m->dev_kmsg_event_source); - mode_t mode = O_CLOEXEC|O_NONBLOCK|O_NOCTTY|(m->read_kmsg ? O_RDWR : O_WRONLY); + mode_t mode = manager_kmsg_mode(m->read_kmsg); _cleanup_close_ int fd = open("/dev/kmsg", mode); if (fd < 0) { @@ -441,3 +445,33 @@ int manager_open_kernel_seqnum(Manager *m) { return 0; } + +int manager_reload_dev_kmsg(Manager *m) { + int r; + + assert(m); + + /* Check if the fd has not yet been initialized. If so, open /dev/kmsg. */ + if (m->dev_kmsg_fd < 0) + return manager_open_dev_kmsg(m); + + mode_t mode = manager_kmsg_mode(m->read_kmsg); + int flags = fcntl(m->dev_kmsg_fd, F_GETFL); + if (flags < 0) + /* Proceed with reload in case the flags have changed. */ + log_warning_errno(errno, "Failed to get flags for /dev/kmsg, ignoring: %m"); + else if ((flags & O_ACCMODE_STRICT) == mode) + /* Mode is the same. No-op. */ + return 0; + + /* Flush kmsg. */ + r = manager_flush_dev_kmsg(m); + if (r < 0) + log_warning_errno(r, "Failed to flush /dev/kmsg on reload, ignoring: %m"); + + /* Set kmsg values to default. */ + m->dev_kmsg_event_source = sd_event_source_disable_unref(m->dev_kmsg_event_source); + m->dev_kmsg_fd = safe_close(m->dev_kmsg_fd); + + return manager_open_dev_kmsg(m); +} diff --git a/src/journal/journald-kmsg.h b/src/journal/journald-kmsg.h index e1f2114a8ad..51e5f34492d 100644 --- a/src/journal/journald-kmsg.h +++ b/src/journal/journald-kmsg.h @@ -5,6 +5,7 @@ int manager_open_dev_kmsg(Manager *m); int manager_flush_dev_kmsg(Manager *m); +int manager_reload_dev_kmsg(Manager *m); void manager_forward_kmsg(Manager *m, int priority, const char *identifier, const char *message, const struct ucred *ucred); diff --git a/src/journal/journald-manager.c b/src/journal/journald-manager.c index 6aa732e0eec..9f44fb80b40 100644 --- a/src/journal/journald-manager.c +++ b/src/journal/journald-manager.c @@ -100,6 +100,7 @@ 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, @@ -269,6 +270,12 @@ static void manager_add_acls(JournalFile *f, uid_t uid) { #endif } +static int manager_get_file_flags(Manager *m, bool seal) { + return (m->compress.enabled ? JOURNAL_COMPRESS : 0) | + (seal ? JOURNAL_SEAL : 0) | + JOURNAL_STRICT_ORDER; +} + static int manager_open_journal( Manager *m, bool reliably, @@ -286,10 +293,7 @@ static int manager_open_journal( assert(fname); assert(ret); - file_flags = - (m->compress.enabled ? JOURNAL_COMPRESS : 0) | - (seal ? JOURNAL_SEAL : 0) | - JOURNAL_STRICT_ORDER; + file_flags = manager_get_file_flags(m, seal); set_clear(m->deferred_closes); @@ -363,7 +367,7 @@ static int manager_system_journal_open( int r = 0; if (!m->system_journal && - IN_SET(m->storage, STORAGE_PERSISTENT, STORAGE_AUTO) && + IN_SET(m->config.storage, STORAGE_PERSISTENT, STORAGE_AUTO) && (flush_requested || manager_flushed_flag_is_set(m)) && !relinquish_requested) { @@ -371,7 +375,7 @@ static int manager_system_journal_open( * * If in persistent mode: create /var/log/journal and the machine path */ - if (m->storage == STORAGE_PERSISTENT) + if (m->config.storage == STORAGE_PERSISTENT) (void) mkdir_parents(m->system_storage.path, 0755); (void) mkdir(m->system_storage.path, 0755); @@ -408,7 +412,7 @@ static int manager_system_journal_open( } if (!m->runtime_journal && - (m->storage != STORAGE_NONE)) { + (m->config.storage != STORAGE_NONE)) { fn = strjoina(m->runtime_storage.path, "/system.journal"); @@ -532,7 +536,7 @@ static JournalFile* manager_find_journal(Manager *m, uid_t uid) { * persistent journal of any sort. * * Fixes https://github.com/systemd/systemd/issues/20390 */ - if (!IN_SET(m->storage, STORAGE_AUTO, STORAGE_PERSISTENT)) + if (!IN_SET(m->config.storage, STORAGE_AUTO, STORAGE_PERSISTENT)) return NULL; if (!uid_for_system_journal(uid)) { @@ -1279,12 +1283,12 @@ void manager_dispatch_message( if (n == 0) return; - if (LOG_PRI(priority) > m->max_level_store) + if (LOG_PRI(priority) > m->config.max_level_store) return; /* Stop early in case the information will not be stored * in a journal. */ - if (m->storage == STORAGE_NONE) + if (m->config.storage == STORAGE_NONE) return; if (c && c->unit) { @@ -1320,7 +1324,7 @@ int manager_flush_to_var(Manager *m, bool require_flag_file) { assert(m); - if (!IN_SET(m->storage, STORAGE_AUTO, STORAGE_PERSISTENT)) + if (!IN_SET(m->config.storage, STORAGE_AUTO, STORAGE_PERSISTENT)) return 0; if (m->namespace) /* Flushing concept does not exist for namespace instances */ @@ -1468,7 +1472,7 @@ finish: int manager_relinquish_var(Manager *m) { assert(m); - if (m->storage == STORAGE_NONE) + if (m->config.storage == STORAGE_NONE) return 0; if (m->namespace) /* Concept does not exist for namespaced instances */ @@ -1859,6 +1863,10 @@ 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); + if (r < 0) + return r; + return 0; } @@ -1872,7 +1880,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse forward to syslog switch \"%s\". Ignoring.", value); else - m->forward_to_syslog = r; + m->config_by_cmdline.forward_to_syslog = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_kmsg")) { @@ -1880,7 +1888,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse forward to kmsg switch \"%s\". Ignoring.", value); else - m->forward_to_kmsg = r; + m->config_by_cmdline.forward_to_kmsg = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_console")) { @@ -1888,7 +1896,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse forward to console switch \"%s\". Ignoring.", value); else - m->forward_to_console = r; + m->config_by_cmdline.forward_to_console = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_wall")) { @@ -1896,7 +1904,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse forward to wall switch \"%s\". Ignoring.", value); else - m->forward_to_wall = r; + m->config_by_cmdline.forward_to_wall = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_console")) { @@ -1907,7 +1915,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse max level console value \"%s\". Ignoring.", value); else - m->max_level_console = r; + m->config_by_cmdline.max_level_console = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_store")) { @@ -1918,7 +1926,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse max level store value \"%s\". Ignoring.", value); else - m->max_level_store = r; + m->config_by_cmdline.max_level_store = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_syslog")) { @@ -1929,7 +1937,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse max level syslog value \"%s\". Ignoring.", value); else - m->max_level_syslog = r; + m->config_by_cmdline.max_level_syslog = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_kmsg")) { @@ -1940,7 +1948,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse max level kmsg value \"%s\". Ignoring.", value); else - m->max_level_kmsg = r; + m->config_by_cmdline.max_level_kmsg = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_wall")) { @@ -1951,7 +1959,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse max level wall value \"%s\". Ignoring.", value); else - m->max_level_wall = r; + m->config_by_cmdline.max_level_wall = r; } else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_socket")) { @@ -1962,7 +1970,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (r < 0) log_warning("Failed to parse max level socket value \"%s\". Ignoring.", value); else - m->max_level_socket = r; + 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); @@ -2394,7 +2402,7 @@ static void manager_load_credentials(Manager *m) { if (r < 0) log_debug_errno(r, "Failed to read credential journal.forward_to_socket, ignoring: %m"); else { - r = socket_address_parse(&m->forward_to_socket, data); + 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); } @@ -2409,12 +2417,225 @@ static void manager_load_credentials(Manager *m) { if (r < 0) log_debug_errno(r, "Failed to parse storage '%s' from credential journal.storage, ignoring: %m", (char *) data); else - m->storage = r; + m->config_by_cred.storage = r; } } -int manager_new(Manager **ret) { +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 precendence 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 precendence 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) { + assert(m); + + int r; + + if (m->system_journal && IN_SET(m->config.storage, STORAGE_PERSISTENT, STORAGE_AUTO)) { + /* Current journal can continue being used. Update config values as needed. */ + r = journal_file_reload( + m->system_journal, + manager_get_file_flags(m, m->seal), + m->compress.threshold_bytes, + &m->system_storage.metrics); + if (r < 0) + return log_warning_errno(r, "Failed to reload system journal on reload, ignoring: %m"); + } else if (m->system_journal && m->config.storage == STORAGE_VOLATILE) { + /* Journal needs to be switched from system to runtime. */ + r = manager_relinquish_var(m); + if (r < 0) + return log_warning_errno(r, "Failed to relinquish to runtime journal on reload, ignoring: %m"); + } else if (m->runtime_journal && IN_SET(m->config.storage, STORAGE_PERSISTENT, STORAGE_AUTO, STORAGE_VOLATILE)) { + /* Current journal can continue being used. Update config values as needed.*/ + r = journal_file_reload( + m->runtime_journal, + manager_get_file_flags(m, /* seal */ false), + m->compress.threshold_bytes, + &m->runtime_storage.metrics); + if (r < 0) + return log_warning_errno(r, "Failed to reload runtime journal on reload, ignoring: %m"); + } + + /* If journal-related configuration, such as SystemMaxUse, SystemMaxFileSize, RuntimeMaxUse, RuntimeMaxFileSize, + * were to change, then we can vacuum for the change to take effect. For example, if pre-reload SystemMaxUse=2M, + * current usage=1.5M, and the post-reload SystemMaxUse=1M, the vacuum can shrink it to 1M. + */ + manager_vacuum(m, /* verbose */ false); + + 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; assert(ret); @@ -2432,37 +2653,10 @@ int manager_new(Manager **ret) { .notify_fd = -EBADF, .forward_socket_fd = -EBADF, - .compress.enabled = true, - .compress.threshold_bytes = UINT64_MAX, - .seal = true, - - .set_audit = true, - .watchdog_usec = USEC_INFINITY, - .sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC, .sync_scheduled = false, - .ratelimit_interval = DEFAULT_RATE_LIMIT_INTERVAL, - .ratelimit_burst = DEFAULT_RATE_LIMIT_BURST, - - .forward_to_wall = true, - .forward_to_socket = { .sockaddr.sa.sa_family = AF_UNSPEC }, - - .max_file_usec = DEFAULT_MAX_FILE_USEC, - - .max_level_store = LOG_DEBUG, - .max_level_syslog = LOG_DEBUG, - .max_level_kmsg = LOG_NOTICE, - .max_level_console = LOG_INFO, - .max_level_wall = LOG_EMERG, - .max_level_socket = LOG_DEBUG, - - .line_max = DEFAULT_LINE_MAX, - - .runtime_storage.name = "Runtime Journal", - .system_storage.name = "System Journal", - .kmsg_own_ratelimit = { .interval = DEFAULT_KMSG_OWN_INTERVAL, .burst = DEFAULT_KMSG_OWN_BURST, @@ -2472,11 +2666,17 @@ int manager_new(Manager **ret) { .sigrtmin18_info.memory_pressure_userdata = m, }; + r = manager_set_namespace(m, namespace); + if (r < 0) + return r; + + manager_load_config(m); + *ret = TAKE_PTR(m); return 0; } -int manager_init(Manager *m, const char *namespace) { +int manager_init(Manager *m) { const char *native_socket, *syslog_socket, *stdout_socket, *varlink_socket, *e; _cleanup_fdset_free_ FDSet *fds = NULL; int n, r, varlink_fd = -EBADF; @@ -2484,33 +2684,6 @@ int manager_init(Manager *m, const char *namespace) { assert(m); - r = manager_set_namespace(m, namespace); - if (r < 0) - return r; - - /* By default, only read from /dev/kmsg if are the main namespace */ - m->read_kmsg = !m->namespace; - m->storage = m->namespace ? STORAGE_PERSISTENT : STORAGE_AUTO; - - journal_reset_metrics(&m->system_storage.metrics); - journal_reset_metrics(&m->runtime_storage.metrics); - - 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"); - } - - 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 "USEC_FMT",%u to 0,0", - m->ratelimit_interval, m->ratelimit_burst); - m->ratelimit_interval = m->ratelimit_burst = 0; - } - e = getenv("RUNTIME_DIRECTORY"); if (e) m->runtime_directory = strdup(e); diff --git a/src/journal/journald-manager.h b/src/journal/journald-manager.h index dda1184e25b..f1958f79bfe 100644 --- a/src/journal/journald-manager.h +++ b/src/journal/journald-manager.h @@ -55,6 +55,23 @@ 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; @@ -111,12 +128,6 @@ typedef struct Manager { bool sent_notify_ready; bool sync_scheduled; - bool forward_to_kmsg; - bool forward_to_syslog; - bool forward_to_console; - bool forward_to_wall; - SocketAddress forward_to_socket; - unsigned n_forward_syslog_missed; usec_t last_warn_forward_syslog_missed; @@ -130,14 +141,6 @@ typedef struct Manager { char *tty_path; - int max_level_store; - int max_level_syslog; - int max_level_kmsg; - int max_level_console; - int max_level_wall; - int max_level_socket; - - Storage storage; SplitMode split_mode; MMapCache *mmap; @@ -183,6 +186,21 @@ typedef struct Manager { /* Pending synchronization requests with non-zero rqlen counter */ 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. + */ + JournalConfig config; + JournalConfig config_by_cred; + JournalConfig config_by_conf; + JournalConfig config_by_cmdline; } Manager; #define MANAGER_MACHINE_ID(s) ((s)->machine_id_field + STRLEN("_MACHINE_ID=")) @@ -209,6 +227,17 @@ 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, \ + } + /* gperf lookup function */ const struct ConfigPerfItem* journald_gperf_lookup(const char *key, GPERF_LEN_TYPE length); @@ -225,8 +254,8 @@ 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); -int manager_init(Manager *m, const char *namespace); +int manager_new(Manager **ret, const char *namespace); +int manager_init(Manager *m); Manager* manager_free(Manager *m); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); void manager_full_sync(Manager *m, bool wait); diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 4288bd4f3f5..d9c6fad4f63 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -267,16 +267,16 @@ static int manager_process_entry( if (r <= 0) goto finish; - if (m->forward_to_syslog) + if (m->config.forward_to_syslog) manager_forward_syslog(m, syslog_fixup_facility(priority), identifier, message, ucred, tv); - if (m->forward_to_kmsg) + if (m->config.forward_to_kmsg) manager_forward_kmsg(m, priority, identifier, message, ucred); - if (m->forward_to_console) + if (m->config.forward_to_console) manager_forward_console(m, priority, identifier, message, ucred); - if (m->forward_to_wall) + if (m->config.forward_to_wall) manager_forward_wall(m, priority, identifier, message, ucred); } diff --git a/src/journal/journald-socket.c b/src/journal/journald-socket.c index ba3c37e45b7..533fa664ced 100644 --- a/src/journal/journald-socket.c +++ b/src/journal/journald-socket.c @@ -23,13 +23,13 @@ static int manager_open_forward_socket(Manager *m) { assert(m); /* Noop if there is nothing to do. */ - if (m->forward_to_socket.sockaddr.sa.sa_family == AF_UNSPEC || m->namespace) + if (m->config.forward_to_socket.sockaddr.sa.sa_family == AF_UNSPEC || m->namespace) return 0; /* All ready, nothing to do. */ if (m->forward_socket_fd >= 0) return 1; - addr = &m->forward_to_socket; + addr = &m->config.forward_to_socket; family = socket_address_family(addr); @@ -86,7 +86,7 @@ int manager_forward_socket( assert(n_iovec > 0); assert(ts); - if (LOG_PRI(priority) > m->max_level_socket) + if (LOG_PRI(priority) > m->config.max_level_socket) return 0; r = manager_open_forward_socket(m); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 45fc3257fff..cfd17fcd83d 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -251,16 +251,16 @@ static int stdout_stream_log( if (r <= 0) return r; - if (s->forward_to_syslog || s->manager->forward_to_syslog) + if (s->forward_to_syslog || s->manager->config.forward_to_syslog) manager_forward_syslog(s->manager, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL); - if (s->forward_to_kmsg || s->manager->forward_to_kmsg) + if (s->forward_to_kmsg || s->manager->config.forward_to_kmsg) manager_forward_kmsg(s->manager, priority, s->identifier, p, &s->ucred); - if (s->forward_to_console || s->manager->forward_to_console) + if (s->forward_to_console || s->manager->config.forward_to_console) manager_forward_console(s->manager, priority, s->identifier, p, &s->ucred); - if (s->manager->forward_to_wall) + if (s->manager->config.forward_to_wall) manager_forward_wall(s->manager, priority, s->identifier, p, &s->ucred); m = N_IOVEC_META_FIELDS + 7 + client_context_extra_fields_n_iovec(s->context); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index ca204f25f5e..8e9c0e2b402 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -127,7 +127,7 @@ static void forward_syslog_raw( assert(m); assert(buffer); - if (LOG_PRI(priority) > m->max_level_syslog) + if (LOG_PRI(priority) > m->config.max_level_syslog) return; iovec = IOVEC_MAKE((char *) buffer, buffer_len); @@ -154,7 +154,7 @@ void manager_forward_syslog( assert(priority <= 999); assert(message); - if (LOG_PRI(priority) > m->max_level_syslog) + if (LOG_PRI(priority) > m->config.max_level_syslog) return; /* First: priority field */ @@ -403,16 +403,16 @@ void manager_process_syslog_message( syslog_parse_identifier(&msg, &identifier, &pid); - if (m->forward_to_syslog) + if (m->config.forward_to_syslog) forward_syslog_raw(m, priority, buf, raw_len, ucred, tv); - if (m->forward_to_kmsg) + if (m->config.forward_to_kmsg) manager_forward_kmsg(m, priority, identifier, msg, ucred); - if (m->forward_to_console) + if (m->config.forward_to_console) manager_forward_console(m, priority, identifier, msg, ucred); - if (m->forward_to_wall) + if (m->config.forward_to_wall) manager_forward_wall(m, priority, identifier, msg, ucred); mm = N_IOVEC_META_FIELDS + 8 + client_context_extra_fields_n_iovec(context); diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c index 375b03a6549..5c862821660 100644 --- a/src/journal/journald-wall.c +++ b/src/journal/journald-wall.c @@ -23,7 +23,7 @@ void manager_forward_wall( assert(m); assert(message); - if (LOG_PRI(priority) > m->max_level_wall) + if (LOG_PRI(priority) > m->config.max_level_wall) return; if (ucred) { diff --git a/src/journal/journald.c b/src/journal/journald.c index 1fcae98f70b..95787418d22 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -52,11 +52,11 @@ static int run(int argc, char *argv[]) { sigbus_install(); - r = manager_new(&m); + r = manager_new(&m, namespace); if (r < 0) return log_oom(); - r = manager_init(m, namespace); + r = manager_init(m); if (r < 0) return r; diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 11e251748a2..5b988e1f95d 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -4082,6 +4082,54 @@ static void journal_default_metrics(JournalMetrics *m, int fd, bool compact) { m->n_max_files); } +static uint64_t get_compress_threshold_bytes(uint64_t compress_threshold_bytes) { + return compress_threshold_bytes == UINT64_MAX ? + DEFAULT_COMPRESS_THRESHOLD : + MAX(MIN_COMPRESS_THRESHOLD, compress_threshold_bytes); +} + +static int set_metrics(JournalFile *f, JournalMetrics *metrics, JournalFile *template) { + assert(f); + int r; + + if (!journal_file_writable(f)) + return 0; + + if (metrics) { + journal_default_metrics(metrics, f->fd, JOURNAL_HEADER_COMPACT(f->header)); + f->metrics = *metrics; + } else if (template) + f->metrics = template->metrics; + + r = journal_file_refresh_header(f); + if (r < 0) + return log_error_errno(r, "Failed to refresh journal file header. Error to be handled by caller."); + + return 0; +} + +int journal_file_reload( + JournalFile *f, + JournalFileFlags file_flags, + uint64_t compress_threshold_bytes, + JournalMetrics *metrics) { + + assert(f); + assert((file_flags & ~_JOURNAL_FILE_FLAGS_ALL) == 0); + assert(metrics); + + int r; + + f->compress_threshold_bytes = get_compress_threshold_bytes(compress_threshold_bytes); + + r = set_metrics(f, metrics, /* template */ NULL); + if (r < 0) + /* Journal file header failed to be rotated. The changes may not have taken effect in this case. */ + return r; + + return 0; +} + int journal_file_open( int fd, const char *fname, @@ -4121,9 +4169,7 @@ int journal_file_open( .fd = fd, .mode = mode, .open_flags = open_flags, - .compress_threshold_bytes = compress_threshold_bytes == UINT64_MAX ? - DEFAULT_COMPRESS_THRESHOLD : - MAX(MIN_COMPRESS_THRESHOLD, compress_threshold_bytes), + .compress_threshold_bytes = get_compress_threshold_bytes(compress_threshold_bytes), .strict_order = FLAGS_SET(file_flags, JOURNAL_STRICT_ORDER), .newest_boot_id_prioq_idx = PRIOQ_IDX_NULL, .last_direction = _DIRECTION_INVALID, @@ -4232,17 +4278,9 @@ int journal_file_open( } #endif - if (journal_file_writable(f)) { - if (metrics) { - journal_default_metrics(metrics, f->fd, JOURNAL_HEADER_COMPACT(f->header)); - f->metrics = *metrics; - } else if (template) - f->metrics = template->metrics; - - r = journal_file_refresh_header(f); - if (r < 0) - goto fail; - } + r = set_metrics(f, metrics, template); + if (r < 0) + goto fail; #if HAVE_GCRYPT r = journal_file_hmac_setup(f); diff --git a/src/libsystemd/sd-journal/journal-file.h b/src/libsystemd/sd-journal/journal-file.h index 1fcfafbb16e..d00e5f8c535 100644 --- a/src/libsystemd/sd-journal/journal-file.h +++ b/src/libsystemd/sd-journal/journal-file.h @@ -149,6 +149,12 @@ int journal_file_open( JournalFile *template, JournalFile **ret); +int journal_file_reload( + JournalFile *f, + JournalFileFlags file_flags, + uint64_t compress_threshold_bytes, + JournalMetrics *metrics); + int journal_file_set_offline_thread_join(JournalFile *f); JournalFile* journal_file_close(JournalFile *j); int journal_file_fstat(JournalFile *f); diff --git a/test/units/TEST-04-JOURNAL.journal-reload.sh b/test/units/TEST-04-JOURNAL.journal-reload.sh new file mode 100755 index 00000000000..53314a59864 --- /dev/null +++ b/test/units/TEST-04-JOURNAL.journal-reload.sh @@ -0,0 +1,316 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +MACHINE_ID="$(/run/systemd/journald.conf.d/reload.conf +[Journal] +Storage=persistent +EOF + +systemctl daemon-reload +systemctl restart systemd-journald.service + +# Add entries in system. +journalctl --flush +rand_val1=$(write_to_journal) +verify_journals "$rand_val1" false true "Confirming test setup after flush." + +# Reload journald (persistent->persistent) +systemctl reload systemd-journald.service + +# Reload should persist persistent journal. +verify_journals "$rand_val1" false true "Persistent->Persistent System Reload: " + +rand_val1=$(write_to_journal) +verify_journals "$rand_val1" false true "Persistent->Persistent System Post-Reload: " + +# Add entries in runtime +journalctl --relinquish +rand_val2=$(write_to_journal) +verify_journals "$rand_val2" true false "Confirming test setup after relinquish." + +# Reload journald (persistent->persistent) +systemctl reload systemd-journald.service + +# System journal entries should stay in system journal, runtime in runtime. +verify_journals "$rand_val1" false true "Persistent->Persistent Runtime Reload 1: " +verify_journals "$rand_val2" true false "Persistent->Persistent Runtime Reload 2: " + +# Write new message and confirm it's written to runtime. +rand_val=$(write_to_journal) +verify_journals "$rand_val" true false "Persistent->Persistent New Message After Reload: " + +# Flush and confirm that messages are written to system. +journalctl --flush +rand_val=$(write_to_journal) +verify_journals "$rand_val" false true "Persistent->Volatile New Message Before Reload: " + +# Test persistent->volatile +cat </run/systemd/journald.conf.d/reload.conf +[Journal] +Storage=volatile +EOF + +# Confirm old message exists where it was written to (storage->storage). +systemctl reload systemd-journald.service +verify_journals "$rand_val" false true "Persistent->Volatile Reload: " + +# Confirm that messages are written to only runtime journal. +rand_val=$(write_to_journal) +verify_journals "$rand_val" true false "Persistent->Volatile New Message After Reload: " + +# Test volatile works and logs are NOT getting written to system journal despite flush. +journalctl --flush +rand_val=$(write_to_journal) +verify_journals "$rand_val" true false "Persistent->Volatile New Message After Flush: " + +# Test that the new limits (e.g., RuntimeMaxUse) take effect on reload. +# Write 1M of data to runtime journal +max_size=1048656 # (1 * 1024 * 1024) = 1048576, but centos has a different minimum value for some reason. +set +x +dd if=/dev/urandom bs=1M count=5 | base64 | systemd-cat -t "$SYSLOG_ID" +set -x +journalctl --vacuum-size=2M + +total_size=$(du -sb "/run/log/journal/$MACHINE_ID" | cut -f1) +if [ "$total_size" -lt "$max_size" ]; then + echo "ERROR: Journal size does not exceed RuntimeMaxUse limit" + cleanup + exit 1 +fi + +# Reload with RuntimeMaxUse=1M. +cat </run/systemd/journald.conf.d/reload.conf +[Journal] +Storage=volatile +RuntimeMaxUse=1M +EOF + +# systemctl daemon-reload +systemctl reload systemd-journald.service + +sleep 15 # Wait for RuntimeMaxUse change to take effect. + +# Confirm that runtime journal size shrunk to <=1M. +total_size=$(du -sb "/run/log/journal/$MACHINE_ID" | cut -f1) +if [ "$total_size" -gt "$max_size" ]; then + echo "ERROR: Journal size exceeds RuntimeMaxUse limit" + cleanup + exit 1 +fi + +# Prepare for volatile->persistent by getting rid of runtime limit. Otherwise, it will not write. +cat </run/systemd/journald.conf.d/reload.conf +[Journal] +Storage=volatile +EOF +systemctl daemon-reload +systemctl reload systemd-journald.service +sleep 15 # Wait for RuntimeMaxUse change to take effect. + +journalctl --vacuum-size=1M +sleep 5 + +rand_val=$(write_to_journal) +verify_journals "$rand_val" true false "Volatile->Persistent New Message Before Reload: " + +# Reload volatile->persistent +cat </run/systemd/journald.conf.d/reload.conf +[Journal] +Storage=persistent +EOF + +systemctl reload systemd-journald.service + +# Confirm that previous message is still in runtime journal. +verify_journals "$rand_val" true false "Volatile->Persistent Reload: " + +# Confirm that new messages are written to runtime journal. +rand_val=$(write_to_journal) +verify_journals "$rand_val" true false "Volatile->Persistent New Message After Reload: " + +# Confirm that flushing writes to system journal. +journalctl --flush +verify_journals "$rand_val" false true "Volatile->Persistent New Message After Flush: " + +set +x +dd if=/dev/urandom bs=1M count=5 | base64 | systemd-cat -t "$SYSLOG_ID" +set -x + +max_size=$((2 * 1024 * 1024)) +total_size=$(du -sb "/var/log/journal/$MACHINE_ID" | cut -f1) +if [ "$total_size" -lt "$max_size" ]; then + echo "ERROR: Journal size does not exceed SystemMaxUse limit" + cleanup + exit 1 +fi + +# Ensure reloading without limit does not interfere with SystemMaxUse test. +systemctl reload systemd-journald.service +total_size=$(du -sb "/var/log/journal/$MACHINE_ID" | cut -f1) +if [ "$total_size" -lt "$max_size" ]; then + echo "ERROR: Journal size does not exceed SystemMaxUse limit" + cleanup + exit 1 +fi + +# Write to storage to prepare for SystemMaxFiles test. +journalctl --flush + +num_var_journals=$(get_num_archived_journals "var") +limit_var_journals=3 +if [ "$num_var_journals" -lt "$limit_var_journals" ]; then + echo "Creating archive files." + for (( i=0; i<=num_var_journals; i++ )) + do + echo "$TEST_MSG_PREFIX" | systemd-cat -t "$SYSLOG_ID" + journalctl --rotate + done + + num_var_journals=$(get_num_archived_journals "var") + if [ "$num_var_journals" -lt "$limit_var_journals" ]; then + echo "ERROR: Number of journal files in /var/log/journal/$MACHINE_ID/ is less than $limit_var_journals" + cleanup + exit 1 + fi +fi + +# Reload with less SystemMaxUse and SystemMaxFiles. +cat </run/systemd/journald.conf.d/reload.conf +[Journal] +Storage=persistent +RuntimeMaxUse=2M +SystemMaxUse=2M +SystemMaxFiles=3 +EOF + +systemctl daemon-reload +systemctl reload systemd-journald.service + +# New system journal needs to be created with the new configuration for change to take effect. +journalctl --flush + +# Check SystemMaxFiles +num_var_journals=$(get_num_archived_journals "var") +if [ "$num_var_journals" -gt "$limit_var_journals" ]; then + echo "ERROR: Number of journal files in /var/log/journal/$MACHINE_ID/ is greater than $limit_var_journals" + cleanup + exit 1 +fi + +sleep 15 + +# Check SystemMaxUse +total_size=$(du -sb "/var/log/journal/$MACHINE_ID" | cut -f1) +if [ "$total_size" -gt "$max_size" ]; then + echo "ERROR: Journal size exceeds SystemMaxUse limit" + cleanup + exit 1 +fi + +rm /run/systemd/journald.conf.d/reload.conf +journalctl --vacuum-size=1M +systemctl daemon-reload +systemctl reload systemd-journald.service diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in index 45fd746526a..1fb080d2685 100644 --- a/units/systemd-journald.service.in +++ b/units/systemd-journald.service.in @@ -57,7 +57,7 @@ StandardOutput=null SystemCallArchitectures=native SystemCallErrorNumber=EPERM SystemCallFilter=@system-service -Type=notify +Type=notify-reload PassEnvironment=TERM {{SERVICE_WATCHDOG}}