1
0
mirror of https://github.com/systemd/systemd synced 2025-10-06 00:13:24 +02:00

journald: support reloading configuration at runtime

This commit is contained in:
Ubuntu
2025-06-11 23:32:27 +00:00
committed by Lennart Poettering
parent c35ceb84e3
commit df5b3426f6
22 changed files with 766 additions and 153 deletions

View File

@@ -218,6 +218,22 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
<xi:include href="version-info.xml" xpointer="v228"/></listitem>
</varlistentry>
<varlistentry>
<term>SIGHUP</term>
<listitem><para>Upon reception of the <constant>SIGHUP</constant> process signal
<command>systemd-journald</command> will reload its configuration values
and update the kernel log buffer and journals to reflect the new configuration.
If <varname>ReadKmsg=</varname> 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.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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="$(</etc/machine-id)"
TEST_MSG_PREFIX="JOURNAL-RELOAD TEST"
SYSLOG_ID="$(systemd-id128 new)"
write_to_journal() {
local rand_val
rand_val=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 14)
echo "$TEST_MSG_PREFIX $rand_val" | systemd-cat -t "$SYSLOG_ID"
journalctl --sync
echo "$rand_val"
}
verify_archived_journals() {
local msg="$1"
local journal_path_prefix="$2"
local journal_dir="/$journal_path_prefix/log/journal/$MACHINE_ID"
for journal_file in "$journal_dir"/*; do
filename=$(basename -- "$journal_file")
if [[ "$filename" != "system.journal" ]]; then
if journalctl --file="$journal_file" | grep -q "$msg"; then
echo "Message present in archived journal: $filename"
exit 0
fi
fi
done
exit 1
}
# shellcheck disable=SC2317
verify_journal() {
local msg="$1"
local entry_expected="$2"
local test_name="$3"
local journal_path_prefix="$4"
local path="/$journal_path_prefix/log/journal/$MACHINE_ID/system.journal"
if [ ! -e "$path" ] || ! grep -Fxq "MESSAGE=$TEST_MSG_PREFIX $msg" "$path"; then
if [ "$entry_expected" == true ]; then
echo "$test_name ERROR: Message not present in $journal_path_prefix journal. Checking archived journals..."
if ! verify_archived_journals "$msg" "$journal_path_prefix"; then
echo "$test_name ERROR: Message also not present in archived journals"
cleanup
exit 1
fi
fi
else
if [ "$entry_expected" == false ]; then
echo "$test_name ERROR: Message present in $journal_path_prefix journal"
cleanup
exit 1
fi
fi
}
verify_journals() {
local msg="$1"
local runtime_expected="$2"
local system_expected="$3"
local test_name="$4"
local failed=false
if ! verify_journal "$msg" "$runtime_expected" "$test_name" "run"; then
failed=true
fi
if ! verify_journal "$msg" "$system_expected" "$test_name" "var"; then
failed=true
fi
if [ "$failed" == true ]; then
cleanup
exit 1
fi
}
get_num_archived_journals() {
local journal_path_prefix="$1"
local journal_dir="/$journal_path_prefix/log/journal/$MACHINE_ID/"
num_journal_files=$(find "$journal_dir" -type f -name "*.journal" ! -name "system.journal" | wc -l)
echo "$num_journal_files"
}
cleanup() {
rm /run/systemd/journald.conf.d/reload.conf
journalctl --vacuum-size=1M
systemctl daemon-reload
systemctl reload systemd-journald.service
}
# Start clean slate.
mkdir -p /run/systemd/journald.conf.d
cat <<EOF >/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 <<EOF >/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 <<EOF >/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 <<EOF >/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 <<EOF >/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 <<EOF >/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

View File

@@ -57,7 +57,7 @@ StandardOutput=null
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
Type=notify
Type=notify-reload
PassEnvironment=TERM
{{SERVICE_WATCHDOG}}