mirror of
https://github.com/systemd/systemd.git
synced 2026-08-09 09:32:04 +00:00
journald: several follow-ups for reloading journald.conf (#38199)
Follow-ups for df5b3426f6 (#36742).
This commit is contained in:
@@ -482,7 +482,7 @@
|
||||
kernel auditing on start-up. If disabled it will turn it off. If unset it will neither enable nor
|
||||
disable it, leaving the previous state unchanged. This means if another tool turns on auditing even
|
||||
if <command>systemd-journald</command> left it off, it will still collect the generated
|
||||
messages. Defaults to on.</para>
|
||||
messages. Defaults to on in the default journal namespace, and unset otherwise.</para>
|
||||
|
||||
<para>Note that this option does not control whether <command>systemd-journald</command> collects
|
||||
generated audit records, it just controls whether it tells the kernel to generate them. If you need
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "fuzz.h"
|
||||
#include "fuzz-journald.h"
|
||||
#include "fuzz-journald-util.h"
|
||||
#include "journald-audit.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
@@ -9,8 +9,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
||||
fuzz_setup_logging();
|
||||
|
||||
assert_se(manager_new(&m, /* namespace= */ NULL) >= 0);
|
||||
dummy_manager_init(m, data, size);
|
||||
dummy_manager_new(&m, data, size);
|
||||
process_audit_string(m, 0, m->buffer, size);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "fuzz.h"
|
||||
#include "fuzz-journald.h"
|
||||
#include "fuzz-journald-util.h"
|
||||
#include "journald-kmsg.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
@@ -12,8 +12,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
||||
fuzz_setup_logging();
|
||||
|
||||
assert_se(manager_new(&m, /* namespace= */ NULL) >= 0);
|
||||
dummy_manager_init(m, data, size);
|
||||
dummy_manager_new(&m, data, size);
|
||||
dev_kmsg_record(m, m->buffer, size);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "fuzz.h"
|
||||
#include "fuzz-journald.h"
|
||||
#include "fuzz-journald-util.h"
|
||||
#include "journald-native.h"
|
||||
#include "memfd-util.h"
|
||||
#include "process-util.h"
|
||||
@@ -21,8 +21,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
||||
fuzz_setup_logging();
|
||||
|
||||
assert_se(manager_new(&m, /* namespace= */ NULL) >= 0);
|
||||
dummy_manager_init(m, NULL, 0);
|
||||
dummy_manager_new(&m, NULL, 0);
|
||||
|
||||
sealed_fd = memfd_new_and_seal(NULL, data, size);
|
||||
assert_se(sealed_fd >= 0);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "fuzz.h"
|
||||
#include "fuzz-journald.h"
|
||||
#include "fuzz-journald-util.h"
|
||||
#include "journald-native.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "fuzz.h"
|
||||
#include "fuzz-journald.h"
|
||||
#include "fuzz-journald-util.h"
|
||||
#include "journald-stream.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
@@ -23,8 +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, /* namespace= */ NULL) >= 0);
|
||||
dummy_manager_init(m, NULL, 0);
|
||||
dummy_manager_new(&m, NULL, 0);
|
||||
|
||||
assert_se(stdout_stream_install(m, stream_fds[0], &stream) >= 0);
|
||||
fd0 = TAKE_FD(stream_fds[0]); /* avoid double close */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "fuzz.h"
|
||||
#include "fuzz-journald.h"
|
||||
#include "fuzz-journald-util.h"
|
||||
#include "journald-syslog.h"
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
||||
37
src/journal/fuzz-journald-util.c
Normal file
37
src/journal/fuzz-journald-util.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fuzz-journald-util.h"
|
||||
#include "journald-manager.h"
|
||||
#include "tests.h"
|
||||
|
||||
void dummy_manager_new(Manager **ret, const uint8_t *buffer, size_t size) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
|
||||
assert(ret);
|
||||
|
||||
ASSERT_OK(manager_new(&m));
|
||||
manager_merge_configs(m);
|
||||
m->config.storage = STORAGE_NONE;
|
||||
ASSERT_OK(sd_event_default(&m->event));
|
||||
|
||||
if (buffer)
|
||||
ASSERT_NOT_NULL(m->buffer = memdup_suffix0(buffer, size));
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
}
|
||||
|
||||
void fuzz_journald_processing_function(
|
||||
const uint8_t *data,
|
||||
size_t size,
|
||||
journal_process_t f) {
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
dummy_manager_new(&m, data, size);
|
||||
f(m, m->buffer, size, /* ucred = */ NULL, /* tv = */ NULL, /* label = */ NULL, /* label_len = */ 0);
|
||||
}
|
||||
20
src/journal/fuzz-journald-util.h
Normal file
20
src/journal/fuzz-journald-util.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "journald-manager.h"
|
||||
|
||||
typedef void (*journal_process_t)(
|
||||
Manager *m,
|
||||
const char *buf,
|
||||
size_t raw_len,
|
||||
const struct ucred *ucred,
|
||||
const struct timeval *tv,
|
||||
const char *label,
|
||||
size_t label_len);
|
||||
|
||||
void dummy_manager_new(Manager **ret, const uint8_t *buffer, size_t size);
|
||||
|
||||
void fuzz_journald_processing_function(
|
||||
const uint8_t *data,
|
||||
size_t size,
|
||||
journal_process_t f);
|
||||
@@ -1,39 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fuzz-journald.h"
|
||||
#include "journald-manager.h"
|
||||
|
||||
void dummy_manager_init(Manager *m, const uint8_t *buffer, size_t size) {
|
||||
assert(m);
|
||||
|
||||
m->config.storage = STORAGE_NONE;
|
||||
assert_se(sd_event_default(&m->event) >= 0);
|
||||
|
||||
if (buffer) {
|
||||
m->buffer = memdup_suffix0(buffer, size);
|
||||
assert_se(m->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void fuzz_journald_processing_function(
|
||||
const uint8_t *data,
|
||||
size_t size,
|
||||
void (*f)(Manager *m, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len)
|
||||
) {
|
||||
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
char *label = NULL;
|
||||
size_t label_len = 0;
|
||||
struct ucred *ucred = NULL;
|
||||
struct timeval *tv = NULL;
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
assert_se(manager_new(&m, /* namespace= */ NULL) >= 0);
|
||||
dummy_manager_init(m, data, size);
|
||||
(*f)(m, m->buffer, size, ucred, tv, label, label_len);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "journald-manager.h"
|
||||
|
||||
void dummy_manager_init(Manager *m, const uint8_t *buffer, size_t size);
|
||||
|
||||
void fuzz_journald_processing_function(
|
||||
const uint8_t *data,
|
||||
size_t size,
|
||||
void (*f)(Manager *m, const char *buf, size_t raw_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len)
|
||||
);
|
||||
@@ -460,7 +460,15 @@ void manager_process_audit_message(
|
||||
process_audit_string(m, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)));
|
||||
}
|
||||
|
||||
static int enable_audit(int fd, bool b) {
|
||||
static int manager_set_kernel_audit(Manager *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->audit_fd >= 0);
|
||||
|
||||
if (m->config.set_audit < 0)
|
||||
return 0;
|
||||
|
||||
struct {
|
||||
union {
|
||||
struct nlmsghdr header;
|
||||
@@ -474,7 +482,7 @@ static int enable_audit(int fd, bool b) {
|
||||
.header.nlmsg_seq = 1,
|
||||
.header.nlmsg_pid = 0,
|
||||
.body.mask = AUDIT_STATUS_ENABLED,
|
||||
.body.enabled = b,
|
||||
.body.enabled = m->config.set_audit,
|
||||
};
|
||||
union sockaddr_union sa = {
|
||||
.nl.nl_family = AF_NETLINK,
|
||||
@@ -491,17 +499,18 @@ static int enable_audit(int fd, bool b) {
|
||||
.msg_namelen = sizeof(sa.nl),
|
||||
};
|
||||
|
||||
ssize_t n;
|
||||
|
||||
n = sendmsg(fd, &mh, MSG_NOSIGNAL);
|
||||
r = 0;
|
||||
ssize_t n = sendmsg(m->audit_fd, &mh, MSG_NOSIGNAL);
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
r = -errno;
|
||||
if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
|
||||
return -EIO;
|
||||
r = SYNTHETIC_ERRNO(EIO);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to %s kernel auditing: %m", enable_disable(m->config.set_audit));
|
||||
|
||||
/* We don't wait for the result here, we can't do anything
|
||||
* about it anyway */
|
||||
/* We don't wait for the result here, we can't do anything about it anyway. */
|
||||
|
||||
log_debug("Auditing in kernel is %s.", enabled_disabled(m->config.set_audit));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -544,16 +553,18 @@ int manager_open_audit(Manager *m) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add audit fd to event loop: %m");
|
||||
|
||||
if (m->set_audit >= 0) {
|
||||
/* We are listening now, try to enable audit if configured so */
|
||||
r = enable_audit(m->audit_fd, m->set_audit);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to issue audit enable call: %m");
|
||||
else if (m->set_audit > 0)
|
||||
log_debug("Auditing in kernel turned on.");
|
||||
else
|
||||
log_debug("Auditing in kernel turned off.");
|
||||
}
|
||||
|
||||
(void) manager_set_kernel_audit(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void manager_reset_kernel_audit(Manager *m, int old_set_audit) {
|
||||
assert(m);
|
||||
|
||||
if (m->audit_fd < 0)
|
||||
return;
|
||||
|
||||
if (m->config.set_audit == old_set_audit)
|
||||
return;
|
||||
|
||||
(void) manager_set_kernel_audit(m);
|
||||
}
|
||||
|
||||
@@ -10,3 +10,4 @@ void manager_process_audit_message(Manager *m, const void *buffer, size_t buffer
|
||||
void process_audit_string(Manager *m, int type, const char *data, size_t size);
|
||||
|
||||
int manager_open_audit(Manager *m);
|
||||
void manager_reset_kernel_audit(Manager *m, int old_set_audit);
|
||||
|
||||
526
src/journal/journald-config.c
Normal file
526
src/journal/journald-config.c
Normal file
@@ -0,0 +1,526 @@
|
||||
/* 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-audit.h"
|
||||
#include "journald-config.h"
|
||||
#include "journald-context.h"
|
||||
#include "journald-kmsg.h"
|
||||
#include "journald-manager.h"
|
||||
#include "journald-socket.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)
|
||||
|
||||
void journal_config_done(JournalConfig *c) {
|
||||
assert(c);
|
||||
|
||||
free(c->tty_path);
|
||||
}
|
||||
|
||||
void journal_config_set_defaults(JournalConfig *c) {
|
||||
assert(c);
|
||||
|
||||
journal_config_done(c);
|
||||
|
||||
*c = (JournalConfig) {
|
||||
.storage = _STORAGE_INVALID,
|
||||
.compress.enabled = -1,
|
||||
.compress.threshold_bytes = UINT64_MAX,
|
||||
.seal = -1,
|
||||
.read_kmsg = -1,
|
||||
.set_audit = -1,
|
||||
.ratelimit_interval = DEFAULT_RATE_LIMIT_INTERVAL,
|
||||
.ratelimit_burst = DEFAULT_RATE_LIMIT_BURST,
|
||||
.forward_to_syslog = -1,
|
||||
.forward_to_kmsg = -1,
|
||||
.forward_to_console = -1,
|
||||
.forward_to_wall = -1,
|
||||
.max_level_store = -1,
|
||||
.max_level_syslog = -1,
|
||||
.max_level_kmsg = -1,
|
||||
.max_level_console = -1,
|
||||
.max_level_wall = -1,
|
||||
.max_level_socket = -1,
|
||||
};
|
||||
|
||||
journal_reset_metrics(&c->system_storage_metrics);
|
||||
journal_reset_metrics(&c->runtime_storage_metrics);
|
||||
}
|
||||
|
||||
static void manager_merge_journal_compress_options(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
if (m->config_by_cmdline.compress.enabled >= 0)
|
||||
m->config.compress = m->config_by_cmdline.compress;
|
||||
else if (m->config_by_conf.compress.enabled >= 0)
|
||||
m->config.compress = m->config_by_conf.compress;
|
||||
else if (m->config_by_cred.compress.enabled >= 0)
|
||||
m->config.compress = m->config_by_cred.compress;
|
||||
else
|
||||
m->config.compress = (JournalCompressOptions) {
|
||||
.enabled = true,
|
||||
.threshold_bytes = UINT64_MAX,
|
||||
};
|
||||
}
|
||||
|
||||
static void manager_merge_forward_to_socket(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
if (m->config_by_cmdline.forward_to_socket.sockaddr.sa.sa_family != AF_UNSPEC)
|
||||
m->config.forward_to_socket = m->config_by_cmdline.forward_to_socket;
|
||||
else 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) {};
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#define MERGE_NON_ZERO(name, default_value) \
|
||||
m->config.name = \
|
||||
m->config_by_cmdline.name ?: \
|
||||
m->config_by_conf.name ?: \
|
||||
m->config_by_cred.name ?: \
|
||||
default_value
|
||||
|
||||
void manager_merge_configs(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
/* From highest to lowest priority: cmdline, conf, cred */
|
||||
|
||||
journal_config_done(&m->config);
|
||||
|
||||
MERGE_NON_NEGATIVE(storage, STORAGE_AUTO);
|
||||
manager_merge_journal_compress_options(m);
|
||||
MERGE_NON_NEGATIVE(seal, true);
|
||||
/* By default, /dev/kmsg is read only by the main namespace instance. */
|
||||
MERGE_NON_NEGATIVE(read_kmsg, !m->namespace);
|
||||
/* By default, kernel auditing is enabled by the main namespace instance, and not controlled by
|
||||
* non-default namespace instances. */
|
||||
MERGE_NON_NEGATIVE(set_audit, m->namespace ? -1 : true);
|
||||
MERGE_NON_ZERO(sync_interval_usec, DEFAULT_SYNC_INTERVAL_USEC);
|
||||
|
||||
/* TODO: also merge them when comdline or credentials support to configure them. */
|
||||
m->config.ratelimit_interval = m->config_by_conf.ratelimit_interval;
|
||||
m->config.ratelimit_burst = m->config_by_conf.ratelimit_burst;
|
||||
m->config.system_storage_metrics = m->config_by_conf.system_storage_metrics;
|
||||
m->config.runtime_storage_metrics = m->config_by_conf.runtime_storage_metrics;
|
||||
|
||||
MERGE_NON_ZERO(max_retention_usec, 0);
|
||||
MERGE_NON_ZERO(max_file_usec, DEFAULT_MAX_FILE_USEC);
|
||||
MERGE_NON_NEGATIVE(forward_to_syslog, false);
|
||||
MERGE_NON_NEGATIVE(forward_to_kmsg, false);
|
||||
MERGE_NON_NEGATIVE(forward_to_console, false);
|
||||
MERGE_NON_NEGATIVE(forward_to_wall, true);
|
||||
manager_merge_forward_to_socket(m);
|
||||
|
||||
if (strdup_to(&m->config.tty_path,
|
||||
m->config_by_cmdline.tty_path ?:
|
||||
m->config_by_conf.tty_path ?:
|
||||
m->config_by_cred.tty_path) < 0)
|
||||
log_oom_debug();
|
||||
|
||||
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);
|
||||
MERGE_NON_NEGATIVE(split_mode, SPLIT_UID);
|
||||
MERGE_NON_ZERO(line_max, DEFAULT_LINE_MAX);
|
||||
}
|
||||
|
||||
static void manager_adjust_configs(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
if ((m->config.ratelimit_interval == 0) != (m->config.ratelimit_burst == 0)) { /* 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->config.ratelimit_interval, USEC_PER_SEC),
|
||||
m->config.ratelimit_burst);
|
||||
m->config.ratelimit_interval = 0;
|
||||
m->config.ratelimit_burst = 0;
|
||||
}
|
||||
|
||||
/* copy metrics to manager */
|
||||
m->system_storage.metrics = m->config.system_storage_metrics;
|
||||
m->runtime_storage.metrics = m->config.runtime_storage_metrics;
|
||||
|
||||
if (m->config.forward_to_socket.sockaddr.sa.sa_family != AF_UNSPEC && m->namespace) {
|
||||
log_debug("ForwardToSocket= is not supported in non-default namespace instance.");
|
||||
m->config.forward_to_socket = (SocketAddress) {};
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
JournalConfig *c = 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
|
||||
c->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
|
||||
c->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
|
||||
c->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
|
||||
c->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
|
||||
c->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
|
||||
c->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
|
||||
c->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
|
||||
c->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
|
||||
c->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
|
||||
c->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->config_by_conf);
|
||||
}
|
||||
|
||||
static void manager_load_credentials(JournalConfig *c) {
|
||||
_cleanup_free_ char *data = NULL;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
r = read_credential("journal.forward_to_socket", (void**) &data, /* ret_size = */ NULL);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to read credential 'journal.forward_to_socket', ignoring: %m");
|
||||
else {
|
||||
r = socket_address_parse(&c->forward_to_socket, data);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse journal.forward_to_socket credential, ignoring: %s", data);
|
||||
}
|
||||
|
||||
data = mfree(data);
|
||||
|
||||
r = read_credential("journal.storage", (void**) &data, /* ret_size = */ 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 journal.storage credential, ignoring: %s", data);
|
||||
else
|
||||
c->storage = r;
|
||||
}
|
||||
}
|
||||
|
||||
void manager_load_config(Manager *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
manager_load_credentials(&m->config_by_cred);
|
||||
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->config_by_cmdline, 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);
|
||||
|
||||
journal_config_set_defaults(&m->config_by_conf);
|
||||
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);
|
||||
|
||||
(void) notify_reloading();
|
||||
|
||||
_cleanup_(journal_config_done) JournalConfig old = TAKE_STRUCT(m->config);
|
||||
|
||||
manager_reload_config(m);
|
||||
|
||||
(void) manager_reopen_dev_kmsg(m, old.read_kmsg);
|
||||
manager_reset_kernel_audit(m, old.set_audit);
|
||||
manager_reload_forward_socket(m, &old.forward_to_socket);
|
||||
manager_refresh_client_contexts_on_reload(m, old.ratelimit_interval, old.ratelimit_burst);
|
||||
manager_reopen_journals(m, &old);
|
||||
|
||||
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;
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
/* Empty assignment means default */
|
||||
*sz = DEFAULT_LINE_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t v;
|
||||
r = parse_size(rvalue, 1024, &v);
|
||||
if (r < 0)
|
||||
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
|
||||
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;
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
compress->enabled = -1;
|
||||
compress->threshold_bytes = UINT64_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
compress->threshold_bytes = UINT64_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq(rvalue, "0")) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||
"Compress= ambiguously specified as 0, disabling compression.");
|
||||
compress->enabled = false;
|
||||
compress->threshold_bytes = UINT64_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_boolean(rvalue);
|
||||
if (r >= 0) {
|
||||
compress->enabled = r;
|
||||
compress->threshold_bytes = UINT64_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_size(rvalue, 1024, &compress->threshold_bytes);
|
||||
if (r < 0)
|
||||
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
|
||||
compress->enabled = true;
|
||||
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;
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*addr = (SocketAddress) {};
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = socket_address_parse(addr, rvalue);
|
||||
if (r < 0)
|
||||
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
104
src/journal/journald-config.h
Normal file
104
src/journal/journald-config.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "journal-file.h"
|
||||
#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 {
|
||||
int enabled;
|
||||
uint64_t threshold_bytes;
|
||||
} JournalCompressOptions;
|
||||
|
||||
typedef struct JournalConfig {
|
||||
/* Storage=, cred: journal.storage */
|
||||
Storage storage;
|
||||
/* Compress= */
|
||||
JournalCompressOptions compress;
|
||||
/* Seal= */
|
||||
int seal;
|
||||
/* ReadKMsg= */
|
||||
int read_kmsg;
|
||||
/* Audit= */
|
||||
int set_audit;
|
||||
/* SyncIntervalSec= */
|
||||
usec_t sync_interval_usec;
|
||||
/* RateLimitIntervalSec= */
|
||||
usec_t ratelimit_interval;
|
||||
/* RateLimitBurst= */
|
||||
unsigned ratelimit_burst;
|
||||
/* SystemMaxUse=, SystemMaxFileSize=, SystemKeepFree=, SystemMaxFiles= */
|
||||
JournalMetrics system_storage_metrics;
|
||||
/* RuntimeMaxUse=, RuntimeMaxFileSize=, RuntimeKeepFree=, RuntimeMaxFiles= */
|
||||
JournalMetrics runtime_storage_metrics;
|
||||
/* MaxRetentionSec= */
|
||||
usec_t max_retention_usec;
|
||||
/* MaxFileSec= */
|
||||
usec_t max_file_usec;
|
||||
/* ForwardToSyslog=, proc: systemd.journald.forward_to_syslog */
|
||||
int forward_to_syslog;
|
||||
/* ForwardToKMsg=, proc: systemd.journald.forward_to_kmsg */
|
||||
int forward_to_kmsg;
|
||||
/* ForwardToConsole=, proc: systemd.journald.forward_to_console */
|
||||
int forward_to_console;
|
||||
/* ForwardToWall=, proc: systemd.journald.forward_to_wall */
|
||||
int forward_to_wall;
|
||||
/* ForwardToSocket=, cred: journal.forward_to_socket */
|
||||
SocketAddress forward_to_socket;
|
||||
/* TTYPath= */
|
||||
char *tty_path;
|
||||
/* MaxLevelStore=, proc: systemd.journald.max_level_store */
|
||||
int max_level_store;
|
||||
/* MaxLevelSyslog=, proc: systemd.journald.max_level_syslog */
|
||||
int max_level_syslog;
|
||||
/* MaxLevelKMsg=, proc: systemd.journald.max_level_kmsg */
|
||||
int max_level_kmsg;
|
||||
/* MaxLevelConsole=, proc: systemd.journald.max_level_console */
|
||||
int max_level_console;
|
||||
/* MaxLevelWall=, systemd.journald.max_level_wall */
|
||||
int max_level_wall;
|
||||
/* MaxLevelSocket=, systemd.journald.max_level_socket */
|
||||
int max_level_socket;
|
||||
/* SplitMode= */
|
||||
SplitMode split_mode;
|
||||
/* LineMax= */
|
||||
size_t line_max;
|
||||
} JournalConfig;
|
||||
|
||||
void journal_config_done(JournalConfig *c);
|
||||
void journal_config_set_defaults(JournalConfig *c);
|
||||
void manager_merge_configs(Manager *m);
|
||||
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);
|
||||
@@ -91,7 +91,7 @@ void manager_forward_console(
|
||||
iovec[n++] = IOVEC_MAKE_STRING(color_off);
|
||||
iovec[n++] = IOVEC_MAKE_STRING("\n");
|
||||
|
||||
tty = m->tty_path ?: "/dev/console";
|
||||
tty = m->config.tty_path ?: "/dev/console";
|
||||
|
||||
/* Before you ask: yes, on purpose we open/close the console for each log line we write individually. This is a
|
||||
* good strategy to avoid journald getting killed by the kernel's SAK concept (it doesn't fix this entirely,
|
||||
|
||||
@@ -139,8 +139,8 @@ static int client_context_new(Manager *m, pid_t pid, ClientContext **ret) {
|
||||
.timestamp = USEC_INFINITY,
|
||||
.extra_fields_mtime = NSEC_INFINITY,
|
||||
.log_level_max = -1,
|
||||
.log_ratelimit_interval = m->ratelimit_interval,
|
||||
.log_ratelimit_burst = m->ratelimit_burst,
|
||||
.log_ratelimit_interval = m->config.ratelimit_interval,
|
||||
.log_ratelimit_burst = m->config.ratelimit_burst,
|
||||
.capability_quintet = CAPABILITY_QUINTET_NULL,
|
||||
};
|
||||
|
||||
@@ -188,8 +188,10 @@ static void client_context_reset(Manager *m, ClientContext *c) {
|
||||
|
||||
c->log_level_max = -1;
|
||||
|
||||
c->log_ratelimit_interval = m->ratelimit_interval;
|
||||
c->log_ratelimit_burst = m->ratelimit_burst;
|
||||
c->log_ratelimit_interval = m->config.ratelimit_interval;
|
||||
c->log_ratelimit_burst = m->config.ratelimit_burst;
|
||||
c->log_ratelimit_interval_from_unit = false;
|
||||
c->log_ratelimit_burst_from_unit = false;
|
||||
|
||||
c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns);
|
||||
c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns);
|
||||
@@ -496,7 +498,12 @@ static int client_context_read_log_ratelimit_interval(ClientContext *c) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return safe_atou64(value, &c->log_ratelimit_interval);
|
||||
r = safe_atou64(value, &c->log_ratelimit_interval);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c->log_ratelimit_interval_from_unit = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_context_read_log_ratelimit_burst(ClientContext *c) {
|
||||
@@ -514,7 +521,12 @@ static int client_context_read_log_ratelimit_burst(ClientContext *c) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return safe_atou(value, &c->log_ratelimit_burst);
|
||||
r = safe_atou(value, &c->log_ratelimit_burst);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c->log_ratelimit_burst_from_unit = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void client_context_really_refresh(
|
||||
@@ -599,6 +611,33 @@ refresh:
|
||||
client_context_really_refresh(m, c, ucred, label, label_size, unit_id, timestamp);
|
||||
}
|
||||
|
||||
static void client_context_refresh_on_reload(Manager *m, ClientContext *c) {
|
||||
assert(m);
|
||||
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
if (!c->log_ratelimit_interval_from_unit)
|
||||
c->log_ratelimit_interval = m->config.ratelimit_interval;
|
||||
|
||||
if (!c->log_ratelimit_burst_from_unit)
|
||||
c->log_ratelimit_burst = m->config.ratelimit_burst;
|
||||
}
|
||||
|
||||
void manager_refresh_client_contexts_on_reload(Manager *m, usec_t old_interval, unsigned old_burst) {
|
||||
assert(m);
|
||||
|
||||
if (m->config.ratelimit_interval == old_interval && m->config.ratelimit_burst == old_burst)
|
||||
return;
|
||||
|
||||
client_context_refresh_on_reload(m, m->my_context);
|
||||
client_context_refresh_on_reload(m, m->pid1_context);
|
||||
|
||||
ClientContext *c;
|
||||
HASHMAP_FOREACH(c, m->client_contexts)
|
||||
client_context_refresh_on_reload(m, c);
|
||||
}
|
||||
|
||||
static void client_context_try_shrink_to(Manager *m, size_t limit) {
|
||||
ClientContext *c;
|
||||
usec_t t;
|
||||
|
||||
@@ -50,6 +50,8 @@ typedef struct ClientContext {
|
||||
|
||||
usec_t log_ratelimit_interval;
|
||||
unsigned log_ratelimit_burst;
|
||||
bool log_ratelimit_interval_from_unit;
|
||||
bool log_ratelimit_burst_from_unit;
|
||||
|
||||
Set *log_filter_allowed_patterns;
|
||||
Set *log_filter_denied_patterns;
|
||||
@@ -81,6 +83,7 @@ void client_context_maybe_refresh(
|
||||
const char *unit_id,
|
||||
usec_t tstamp);
|
||||
|
||||
void manager_refresh_client_contexts_on_reload(Manager *m, usec_t old_interval, unsigned old_burst);
|
||||
void client_context_acquire_default(Manager *m);
|
||||
void client_context_flush_all(Manager *m);
|
||||
void client_context_flush_regular(Manager *m);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -6,7 +6,7 @@ _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
#include "conf-parser.h"
|
||||
#include "journald-manager.h"
|
||||
#include "journald-config.h"
|
||||
%}
|
||||
struct ConfigPerfItem;
|
||||
%null_strings
|
||||
@@ -19,37 +19,37 @@ struct ConfigPerfItem;
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
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)
|
||||
Journal.Audit, config_parse_tristate, 0, offsetof(Manager, set_audit)
|
||||
Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Manager, sync_interval_usec)
|
||||
Journal.Storage, config_parse_storage, 0, offsetof(JournalConfig, storage)
|
||||
Journal.Compress, config_parse_compress, 0, offsetof(JournalConfig, compress)
|
||||
Journal.Seal, config_parse_tristate, 0, offsetof(JournalConfig, seal)
|
||||
Journal.ReadKMsg, config_parse_tristate, 0, offsetof(JournalConfig, read_kmsg)
|
||||
Journal.Audit, config_parse_tristate, 0, offsetof(JournalConfig, set_audit)
|
||||
Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(JournalConfig, sync_interval_usec)
|
||||
# The following is a legacy name for compatibility
|
||||
Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Manager, ratelimit_interval)
|
||||
Journal.RateLimitIntervalSec,config_parse_sec, 0, offsetof(Manager, ratelimit_interval)
|
||||
Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Manager, ratelimit_burst)
|
||||
Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Manager, system_storage.metrics.max_use)
|
||||
Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Manager, system_storage.metrics.max_size)
|
||||
Journal.SystemKeepFree, config_parse_iec_uint64, 0, offsetof(Manager, system_storage.metrics.keep_free)
|
||||
Journal.SystemMaxFiles, config_parse_uint64, 0, offsetof(Manager, system_storage.metrics.n_max_files)
|
||||
Journal.RuntimeMaxUse, config_parse_iec_uint64, 0, offsetof(Manager, runtime_storage.metrics.max_use)
|
||||
Journal.RuntimeMaxFileSize, config_parse_iec_uint64, 0, offsetof(Manager, runtime_storage.metrics.max_size)
|
||||
Journal.RuntimeKeepFree, config_parse_iec_uint64, 0, offsetof(Manager, runtime_storage.metrics.keep_free)
|
||||
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, 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, 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)
|
||||
Journal.RateLimitInterval, config_parse_sec, 0, offsetof(JournalConfig, ratelimit_interval)
|
||||
Journal.RateLimitIntervalSec, config_parse_sec, 0, offsetof(JournalConfig, ratelimit_interval)
|
||||
Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(JournalConfig, ratelimit_burst)
|
||||
Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(JournalConfig, system_storage_metrics.max_use)
|
||||
Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(JournalConfig, system_storage_metrics.max_size)
|
||||
Journal.SystemKeepFree, config_parse_iec_uint64, 0, offsetof(JournalConfig, system_storage_metrics.keep_free)
|
||||
Journal.SystemMaxFiles, config_parse_uint64, 0, offsetof(JournalConfig, system_storage_metrics.n_max_files)
|
||||
Journal.RuntimeMaxUse, config_parse_iec_uint64, 0, offsetof(JournalConfig, runtime_storage_metrics.max_use)
|
||||
Journal.RuntimeMaxFileSize, config_parse_iec_uint64, 0, offsetof(JournalConfig, runtime_storage_metrics.max_size)
|
||||
Journal.RuntimeKeepFree, config_parse_iec_uint64, 0, offsetof(JournalConfig, runtime_storage_metrics.keep_free)
|
||||
Journal.RuntimeMaxFiles, config_parse_uint64, 0, offsetof(JournalConfig, runtime_storage_metrics.n_max_files)
|
||||
Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(JournalConfig, max_retention_usec)
|
||||
Journal.MaxFileSec, config_parse_sec, 0, offsetof(JournalConfig, max_file_usec)
|
||||
Journal.ForwardToSyslog, config_parse_tristate, 0, offsetof(JournalConfig, forward_to_syslog)
|
||||
Journal.ForwardToKMsg, config_parse_tristate, 0, offsetof(JournalConfig, forward_to_kmsg)
|
||||
Journal.ForwardToConsole, config_parse_tristate, 0, offsetof(JournalConfig, forward_to_console)
|
||||
Journal.ForwardToWall, config_parse_tristate, 0, offsetof(JournalConfig, forward_to_wall)
|
||||
Journal.ForwardToSocket, config_parse_forward_to_socket, 0, offsetof(JournalConfig, forward_to_socket)
|
||||
Journal.TTYPath, config_parse_path, 0, offsetof(JournalConfig, tty_path)
|
||||
Journal.MaxLevelStore, config_parse_log_level, 0, offsetof(JournalConfig, max_level_store)
|
||||
Journal.MaxLevelSyslog, config_parse_log_level, 0, offsetof(JournalConfig, max_level_syslog)
|
||||
Journal.MaxLevelKMsg, config_parse_log_level, 0, offsetof(JournalConfig, max_level_kmsg)
|
||||
Journal.MaxLevelConsole, config_parse_log_level, 0, offsetof(JournalConfig, max_level_console)
|
||||
Journal.MaxLevelWall, config_parse_log_level, 0, offsetof(JournalConfig, max_level_wall)
|
||||
Journal.MaxLevelSocket, config_parse_log_level, 0, offsetof(JournalConfig, max_level_socket)
|
||||
Journal.SplitMode, config_parse_split_mode, 0, offsetof(JournalConfig, split_mode)
|
||||
Journal.LineMax, config_parse_line_max, 0, offsetof(JournalConfig, line_max)
|
||||
|
||||
@@ -332,7 +332,7 @@ static int manager_read_dev_kmsg(Manager *m) {
|
||||
|
||||
assert(m);
|
||||
assert(m->dev_kmsg_fd >= 0);
|
||||
assert(m->read_kmsg);
|
||||
assert(m->config.read_kmsg);
|
||||
|
||||
l = read(m->dev_kmsg_fd, buffer, sizeof(buffer) - 1);
|
||||
if (l == 0)
|
||||
@@ -356,18 +356,15 @@ int manager_flush_dev_kmsg(Manager *m) {
|
||||
if (m->dev_kmsg_fd < 0)
|
||||
return 0;
|
||||
|
||||
if (!m->read_kmsg)
|
||||
if (!m->config.read_kmsg)
|
||||
return 0;
|
||||
|
||||
log_debug("Flushing /dev/kmsg...");
|
||||
|
||||
for (;;) {
|
||||
r = manager_read_dev_kmsg(m);
|
||||
if (r < 0)
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -389,10 +386,6 @@ 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;
|
||||
|
||||
@@ -400,7 +393,7 @@ int manager_open_dev_kmsg(Manager *m) {
|
||||
assert(m->dev_kmsg_fd < 0);
|
||||
assert(!m->dev_kmsg_event_source);
|
||||
|
||||
mode_t mode = manager_kmsg_mode(m->read_kmsg);
|
||||
mode_t mode = O_CLOEXEC|O_NONBLOCK|O_NOCTTY|(m->config.read_kmsg ? O_RDWR : O_WRONLY);
|
||||
|
||||
_cleanup_close_ int fd = open("/dev/kmsg", mode);
|
||||
if (fd < 0) {
|
||||
@@ -409,7 +402,7 @@ int manager_open_dev_kmsg(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!m->read_kmsg) {
|
||||
if (!m->config.read_kmsg) {
|
||||
m->dev_kmsg_fd = TAKE_FD(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -432,11 +425,12 @@ int manager_open_kernel_seqnum(Manager *m) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(!m->kernel_seqnum);
|
||||
|
||||
/* We store the seqnum we last read in an mmapped file. That way we can just use it like a variable,
|
||||
* but it is persistent and automatically flushed at reboot. */
|
||||
|
||||
if (!m->read_kmsg)
|
||||
if (!m->config.read_kmsg)
|
||||
return 0;
|
||||
|
||||
r = manager_map_seqnum_file(m, "kernel-seqnum", sizeof(uint64_t), (void**) &m->kernel_seqnum);
|
||||
@@ -446,32 +440,53 @@ int manager_open_kernel_seqnum(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_reload_dev_kmsg(Manager *m) {
|
||||
void manager_close_kernel_seqnum(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
manager_unmap_seqnum_file(m->kernel_seqnum, sizeof(*m->kernel_seqnum));
|
||||
m->kernel_seqnum = NULL;
|
||||
}
|
||||
|
||||
static int manager_unlink_kernel_seqnum(Manager *m) {
|
||||
assert(m);
|
||||
assert(!m->kernel_seqnum); /* The file must not be mmap()ed. */
|
||||
|
||||
return manager_unlink_seqnum_file(m, "kernel-seqnum");
|
||||
}
|
||||
|
||||
int manager_reopen_dev_kmsg(Manager *m, bool old_read_kmsg) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
/* Check if the fd has not yet been initialized. If so, open /dev/kmsg. */
|
||||
/* If the fd has not yet been initialized, let's shortcut and simply 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;
|
||||
if (m->config.read_kmsg == old_read_kmsg)
|
||||
return 0; /* Setting is unchanged. */
|
||||
|
||||
/* Flush kmsg. */
|
||||
r = manager_flush_dev_kmsg(m);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to flush /dev/kmsg on reload, ignoring: %m");
|
||||
if (!m->config.read_kmsg) {
|
||||
/* If reading kmsg was enabled but now disable, let's flush the buffer before disabling it. */
|
||||
m->config.read_kmsg = true;
|
||||
(void) manager_flush_dev_kmsg(m);
|
||||
m->config.read_kmsg = false;
|
||||
|
||||
/* Set kmsg values to default. */
|
||||
/* seqnum file is not necessary anymore. Let's close it. */
|
||||
manager_close_kernel_seqnum(m);
|
||||
|
||||
/* Also, unlink the file name as we will not warn some kmsg are lost when reading kmsg is
|
||||
* re-enabled later. */
|
||||
manager_unlink_kernel_seqnum(m);
|
||||
}
|
||||
|
||||
/* Close previously configured event source and opened file descriptor. */
|
||||
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);
|
||||
r = manager_open_dev_kmsg(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return manager_open_kernel_seqnum(m);
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
|
||||
int manager_open_dev_kmsg(Manager *m);
|
||||
int manager_flush_dev_kmsg(Manager *m);
|
||||
int manager_reload_dev_kmsg(Manager *m);
|
||||
int manager_reopen_dev_kmsg(Manager *m, bool old_read_kmsg);
|
||||
|
||||
void manager_forward_kmsg(Manager *m, int priority, const char *identifier, const char *message, const struct ucred *ucred);
|
||||
|
||||
int manager_open_kernel_seqnum(Manager *m);
|
||||
void manager_close_kernel_seqnum(Manager *m);
|
||||
|
||||
void dev_kmsg_record(Manager *m, char *p, size_t l);
|
||||
|
||||
@@ -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"
|
||||
@@ -73,11 +72,6 @@
|
||||
|
||||
#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
|
||||
|
||||
@@ -88,10 +82,6 @@
|
||||
/* 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)
|
||||
@@ -100,7 +90,6 @@
|
||||
|
||||
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,
|
||||
@@ -160,6 +149,7 @@ static int cache_space_refresh(Manager *m, JournalStorage *storage) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(storage);
|
||||
|
||||
metrics = &storage->metrics;
|
||||
space = &storage->space;
|
||||
@@ -270,10 +260,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 JournalFileFlags manager_get_file_flags(Manager *m, bool seal) {
|
||||
assert(m);
|
||||
|
||||
return (m->config.compress.enabled ? JOURNAL_COMPRESS : 0) |
|
||||
(seal ? JOURNAL_SEAL : 0) |
|
||||
JOURNAL_STRICT_ORDER;
|
||||
}
|
||||
|
||||
static int manager_open_journal(
|
||||
@@ -303,7 +295,7 @@ static int manager_open_journal(
|
||||
open_flags,
|
||||
file_flags,
|
||||
0640,
|
||||
m->compress.threshold_bytes,
|
||||
m->config.compress.threshold_bytes,
|
||||
metrics,
|
||||
m->mmap,
|
||||
&f);
|
||||
@@ -314,7 +306,7 @@ static int manager_open_journal(
|
||||
open_flags,
|
||||
file_flags,
|
||||
0640,
|
||||
m->compress.threshold_bytes,
|
||||
m->config.compress.threshold_bytes,
|
||||
metrics,
|
||||
m->mmap,
|
||||
/* template= */ NULL,
|
||||
@@ -386,7 +378,7 @@ static int manager_system_journal_open(
|
||||
/* reliably= */ true,
|
||||
fn,
|
||||
O_RDWR|O_CREAT,
|
||||
m->seal,
|
||||
m->config.seal,
|
||||
&m->system_storage.metrics,
|
||||
&m->system_journal);
|
||||
if (r >= 0) {
|
||||
@@ -494,7 +486,7 @@ static int manager_find_user_journal(Manager *m, uid_t uid, JournalFile **ret) {
|
||||
/* reliably= */ true,
|
||||
p,
|
||||
O_RDWR|O_CREAT,
|
||||
m->seal,
|
||||
m->config.seal,
|
||||
&m->system_storage.metrics,
|
||||
&f);
|
||||
if (r < 0)
|
||||
@@ -559,7 +551,6 @@ static int manager_do_rotate(
|
||||
bool seal,
|
||||
uint32_t uid) {
|
||||
|
||||
JournalFileFlags file_flags;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@@ -567,12 +558,7 @@ static int manager_do_rotate(
|
||||
if (!*f)
|
||||
return -EINVAL;
|
||||
|
||||
file_flags =
|
||||
(m->compress.enabled ? JOURNAL_COMPRESS : 0)|
|
||||
(seal ? JOURNAL_SEAL : 0) |
|
||||
JOURNAL_STRICT_ORDER;
|
||||
|
||||
r = journal_file_rotate(f, m->mmap, file_flags, m->compress.threshold_bytes, m->deferred_closes);
|
||||
r = journal_file_rotate(f, m->mmap, manager_get_file_flags(m, seal), m->config.compress.threshold_bytes, m->deferred_closes);
|
||||
if (r < 0) {
|
||||
if (*f)
|
||||
return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT,
|
||||
@@ -682,10 +668,9 @@ static int manager_archive_offline_user_journals(Manager *m) {
|
||||
fd,
|
||||
full,
|
||||
O_RDWR,
|
||||
(m->compress.enabled ? JOURNAL_COMPRESS : 0) |
|
||||
(m->seal ? JOURNAL_SEAL : 0), /* strict order does not matter here */
|
||||
manager_get_file_flags(m, m->config.seal) & ~JOURNAL_STRICT_ORDER, /* strict order does not matter here */
|
||||
0640,
|
||||
m->compress.threshold_bytes,
|
||||
m->config.compress.threshold_bytes,
|
||||
&m->system_storage.metrics,
|
||||
m->mmap,
|
||||
/* template= */ NULL,
|
||||
@@ -728,11 +713,11 @@ void manager_rotate(Manager *m) {
|
||||
|
||||
/* First, rotate the system journal (either in its runtime flavour or in its runtime flavour) */
|
||||
(void) manager_do_rotate(m, &m->runtime_journal, "runtime", /* seal= */ false, /* uid= */ 0);
|
||||
(void) manager_do_rotate(m, &m->system_journal, "system", m->seal, /* uid= */ 0);
|
||||
(void) manager_do_rotate(m, &m->system_journal, "system", m->config.seal, /* uid= */ 0);
|
||||
|
||||
/* Then, rotate all user journals we have open (keeping them open) */
|
||||
ORDERED_HASHMAP_FOREACH_KEY(f, k, m->user_journals) {
|
||||
r = manager_do_rotate(m, &f, "user", m->seal, PTR_TO_UID(k));
|
||||
r = manager_do_rotate(m, &f, "user", m->config.seal, PTR_TO_UID(k));
|
||||
if (r >= 0)
|
||||
ordered_hashmap_replace(m->user_journals, k, f);
|
||||
else if (!f)
|
||||
@@ -759,12 +744,12 @@ static void manager_rotate_journal(Manager *m, JournalFile *f, uid_t uid) {
|
||||
* 💣💣💣 This invalidate 'f', and the caller cannot reuse the passed JournalFile object. 💣💣💣 */
|
||||
|
||||
if (f == m->system_journal)
|
||||
(void) manager_do_rotate(m, &m->system_journal, "system", m->seal, /* uid= */ 0);
|
||||
(void) manager_do_rotate(m, &m->system_journal, "system", m->config.seal, /* uid= */ 0);
|
||||
else if (f == m->runtime_journal)
|
||||
(void) manager_do_rotate(m, &m->runtime_journal, "runtime", /* seal= */ false, /* uid= */ 0);
|
||||
else {
|
||||
assert(ordered_hashmap_get(m->user_journals, UID_TO_PTR(uid)) == f);
|
||||
r = manager_do_rotate(m, &f, "user", m->seal, uid);
|
||||
r = manager_do_rotate(m, &f, "user", m->config.seal, uid);
|
||||
if (r >= 0)
|
||||
ordered_hashmap_replace(m->user_journals, UID_TO_PTR(uid), f);
|
||||
else if (!f)
|
||||
@@ -802,7 +787,6 @@ static void manager_sync(Manager *m, bool wait) {
|
||||
}
|
||||
|
||||
static void manager_do_vacuum(Manager *m, JournalStorage *storage, bool verbose) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@@ -814,7 +798,7 @@ static void manager_do_vacuum(Manager *m, JournalStorage *storage, bool verbose)
|
||||
manager_space_usage_message(m, storage);
|
||||
|
||||
r = journal_directory_vacuum(storage->path, storage->space.limit,
|
||||
storage->metrics.n_max_files, m->max_retention_usec,
|
||||
storage->metrics.n_max_files, m->config.max_retention_usec,
|
||||
&m->oldest_file_usec, verbose);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT,
|
||||
@@ -983,7 +967,7 @@ static void manager_write_to_journal(
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
if (journal_file_rotate_suggested(f, m->max_file_usec, LOG_DEBUG)) {
|
||||
if (journal_file_rotate_suggested(f, m->config.max_file_usec, LOG_DEBUG)) {
|
||||
if (vacuumed) {
|
||||
log_ratelimit_warning(JOURNAL_LOG_RATELIMIT,
|
||||
"Suppressing rotation, as we already rotated immediately before write attempt. Giving up.");
|
||||
@@ -1193,10 +1177,10 @@ static void manager_dispatch_message_real(
|
||||
iovec[n++] = in_initrd() ? IOVEC_MAKE_STRING("_RUNTIME_SCOPE=initrd") : IOVEC_MAKE_STRING("_RUNTIME_SCOPE=system");
|
||||
assert(n <= mm);
|
||||
|
||||
if (m->split_mode == SPLIT_UID && c && uid_is_valid(c->uid))
|
||||
if (m->config.split_mode == SPLIT_UID && c && uid_is_valid(c->uid))
|
||||
/* Split up strictly by (non-root) UID */
|
||||
journal_uid = c->uid;
|
||||
else if (m->split_mode == SPLIT_LOGIN && c && c->uid > 0 && uid_is_valid(c->owner_uid))
|
||||
else if (m->config.split_mode == SPLIT_LOGIN && c && c->uid > 0 && uid_is_valid(c->owner_uid))
|
||||
/* Split up by login UIDs. We do this only if the
|
||||
* realuid is not root, in order not to accidentally
|
||||
* leak privileged information to the user that is
|
||||
@@ -1863,140 +1847,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);
|
||||
|
||||
@@ -2024,21 +1881,21 @@ static int manager_schedule_sync(Manager *m, int priority) {
|
||||
if (m->sync_scheduled)
|
||||
return 0;
|
||||
|
||||
if (m->sync_interval_usec > 0) {
|
||||
if (m->config.sync_interval_usec > 0) {
|
||||
|
||||
if (!m->sync_event_source) {
|
||||
r = sd_event_add_time_relative(
|
||||
m->event,
|
||||
&m->sync_event_source,
|
||||
CLOCK_MONOTONIC,
|
||||
m->sync_interval_usec, 0,
|
||||
m->config.sync_interval_usec, 0,
|
||||
manager_dispatch_sync, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_priority(m->sync_event_source, SD_EVENT_PRIORITY_IMPORTANT);
|
||||
} else {
|
||||
r = sd_event_source_set_time_relative(m->sync_event_source, m->sync_interval_usec);
|
||||
r = sd_event_source_set_time_relative(m->sync_event_source, m->config.sync_interval_usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -2250,7 +2107,7 @@ int manager_map_seqnum_file(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void manager_unmap_seqnum_file(void *p, size_t size) {
|
||||
void manager_unmap_seqnum_file(void *p, size_t size) {
|
||||
assert(size > 0);
|
||||
|
||||
if (!p)
|
||||
@@ -2259,6 +2116,20 @@ static void manager_unmap_seqnum_file(void *p, size_t size) {
|
||||
assert_se(munmap(p, size) >= 0);
|
||||
}
|
||||
|
||||
int manager_unlink_seqnum_file(Manager *m, const char *fname) {
|
||||
assert(m);
|
||||
assert(fname);
|
||||
|
||||
_cleanup_free_ char *fn = path_join(m->runtime_directory, fname);
|
||||
if (!fn)
|
||||
return log_oom();
|
||||
|
||||
if (unlink(fn) < 0 && errno != ENOENT)
|
||||
return log_warning_errno(errno, "Failed to remove '%s': %m", fname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool manager_is_idle(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
@@ -2268,7 +2139,7 @@ static bool manager_is_idle(Manager *m) {
|
||||
|
||||
/* If a retention maximum is set larger than the idle time we need to be running to enforce it, hence
|
||||
* turn off the idle logic. */
|
||||
if (m->max_retention_usec > IDLE_TIMEOUT_USEC)
|
||||
if (m->config.max_retention_usec > IDLE_TIMEOUT_USEC)
|
||||
return false;
|
||||
|
||||
/* We aren't idle if we have a varlink client */
|
||||
@@ -2336,7 +2207,7 @@ static int manager_refresh_idle_timer(Manager *m) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int manager_set_namespace(Manager *m, const char *namespace) {
|
||||
int manager_set_namespace(Manager *m, const char *namespace) {
|
||||
assert(m);
|
||||
|
||||
if (!namespace)
|
||||
@@ -2392,250 +2263,38 @@ static int manager_setup_memory_pressure(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void manager_load_credentials(Manager *m) {
|
||||
_cleanup_free_ void *data = NULL;
|
||||
int r;
|
||||
|
||||
void manager_reopen_journals(Manager *m, const JournalConfig *old) {
|
||||
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);
|
||||
}
|
||||
if (m->config.storage == old->storage &&
|
||||
m->config.compress.enabled == old->compress.enabled &&
|
||||
m->config.compress.threshold_bytes == old->compress.threshold_bytes &&
|
||||
m->config.seal == old->seal &&
|
||||
m->config.sync_interval_usec == old->sync_interval_usec &&
|
||||
journal_metrics_equal(&m->config.system_storage_metrics, &old->system_storage_metrics) &&
|
||||
journal_metrics_equal(&m->config.runtime_storage_metrics, &old->runtime_storage_metrics))
|
||||
return; /* no-op */
|
||||
|
||||
data = mfree(data);
|
||||
/* Explicitly close the runtime journal to make it reopened later by manager_system_journal_open().
|
||||
* But only when volatile (or no) storage is requested. If auto or persistent storage is requested,
|
||||
* we may need to flush the runtime journal to the persistent storage, it will done through
|
||||
* manager_system_journal_open(). Hence, we should not touch the runtime journal here in that case. */
|
||||
if (IN_SET(m->config.storage, STORAGE_VOLATILE, STORAGE_NONE))
|
||||
m->runtime_journal = journal_file_offline_close(m->runtime_journal);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* Close other journals unconditionally to make the new settings applied. */
|
||||
m->system_journal = journal_file_offline_close(m->system_journal);
|
||||
ordered_hashmap_clear(m->user_journals);
|
||||
set_clear(m->deferred_closes);
|
||||
|
||||
static void manager_set_defaults(Manager *m) {
|
||||
assert(m);
|
||||
(void) manager_system_journal_open(m, /* flush_requested = */ false, /* relinquish_requested = */ false);
|
||||
|
||||
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) {
|
||||
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.
|
||||
*/
|
||||
/* To make the storage related settings applied, vacuum the storage. */
|
||||
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) {
|
||||
int manager_new(Manager **ret) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
@@ -2653,6 +2312,9 @@ int manager_new(Manager **ret, const char *namespace) {
|
||||
.notify_fd = -EBADF,
|
||||
.forward_socket_fd = -EBADF,
|
||||
|
||||
.system_storage.name = "System Journal",
|
||||
.runtime_storage.name = "Runtime Journal",
|
||||
|
||||
.watchdog_usec = USEC_INFINITY,
|
||||
|
||||
.sync_scheduled = false,
|
||||
@@ -2666,11 +2328,9 @@ int manager_new(Manager **ret, const char *namespace) {
|
||||
.sigrtmin18_info.memory_pressure_userdata = m,
|
||||
};
|
||||
|
||||
r = manager_set_namespace(m, namespace);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
manager_load_config(m);
|
||||
journal_config_set_defaults(&m->config_by_conf);
|
||||
journal_config_set_defaults(&m->config_by_cred);
|
||||
journal_config_set_defaults(&m->config_by_cmdline);
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
@@ -2944,10 +2604,9 @@ Manager* manager_free(Manager *m) {
|
||||
ordered_hashmap_free(m->ratelimit_groups_by_id);
|
||||
|
||||
manager_unmap_seqnum_file(m->seqnum, sizeof(*m->seqnum));
|
||||
manager_unmap_seqnum_file(m->kernel_seqnum, sizeof(*m->kernel_seqnum));
|
||||
manager_close_kernel_seqnum(m);
|
||||
|
||||
free(m->buffer);
|
||||
free(m->tty_path);
|
||||
free(m->cgroup_root);
|
||||
free(m->hostname_field);
|
||||
free(m->runtime_storage.path);
|
||||
@@ -2965,150 +2624,10 @@ Manager* manager_free(Manager *m) {
|
||||
sync_req_free(req);
|
||||
prioq_free(m->sync_req_boottime_prioq);
|
||||
|
||||
journal_config_done(&m->config);
|
||||
journal_config_done(&m->config_by_cred);
|
||||
journal_config_done(&m->config_by_conf);
|
||||
journal_config_done(&m->config_by_cmdline);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -112,18 +74,10 @@ typedef struct Manager {
|
||||
char *buffer;
|
||||
|
||||
OrderedHashmap *ratelimit_groups_by_id;
|
||||
usec_t sync_interval_usec;
|
||||
usec_t ratelimit_interval;
|
||||
unsigned ratelimit_burst;
|
||||
|
||||
JournalStorage runtime_storage;
|
||||
JournalStorage system_storage;
|
||||
|
||||
JournalCompressOptions compress;
|
||||
int set_audit;
|
||||
bool seal;
|
||||
bool read_kmsg;
|
||||
|
||||
bool send_watchdog;
|
||||
bool sent_notify_ready;
|
||||
bool sync_scheduled;
|
||||
@@ -131,18 +85,12 @@ typedef struct Manager {
|
||||
unsigned n_forward_syslog_missed;
|
||||
usec_t last_warn_forward_syslog_missed;
|
||||
|
||||
usec_t max_retention_usec;
|
||||
usec_t max_file_usec;
|
||||
usec_t oldest_file_usec;
|
||||
|
||||
LIST_HEAD(StdoutStream, stdout_streams);
|
||||
LIST_HEAD(StdoutStream, stdout_streams_notify_queue);
|
||||
unsigned n_stdout_streams;
|
||||
|
||||
char *tty_path;
|
||||
|
||||
SplitMode split_mode;
|
||||
|
||||
MMapCache *mmap;
|
||||
|
||||
Set *deferred_closes;
|
||||
@@ -163,8 +111,6 @@ typedef struct Manager {
|
||||
|
||||
usec_t last_realtime_clock;
|
||||
|
||||
size_t line_max;
|
||||
|
||||
/* Caching of client metadata */
|
||||
Hashmap *client_contexts;
|
||||
Prioq *client_contexts_lru;
|
||||
@@ -188,15 +134,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,35 +172,8 @@ 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_new(Manager **ret);
|
||||
int manager_set_namespace(Manager *m, const char *namespace);
|
||||
int manager_init(Manager *m);
|
||||
Manager* manager_free(Manager *m);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
||||
@@ -271,5 +189,8 @@ 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);
|
||||
void manager_reopen_journals(Manager *m, const JournalConfig *old);
|
||||
|
||||
int manager_map_seqnum_file(Manager *m, const char *fname, size_t size, void **ret);
|
||||
void manager_unmap_seqnum_file(void *p, size_t size);
|
||||
int manager_unlink_seqnum_file(Manager *m, const char *fname);
|
||||
|
||||
@@ -163,3 +163,20 @@ int manager_forward_socket(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void manager_reload_forward_socket(Manager *m, const SocketAddress *old) {
|
||||
assert(m);
|
||||
assert(old);
|
||||
|
||||
/* The socket is not opened yet or already closed. There is nothing we need to do now. The socket
|
||||
* will be opened when necessary. */
|
||||
if (m->forward_socket_fd < 0)
|
||||
return;
|
||||
|
||||
if (socket_address_equal(&m->config.forward_to_socket, old))
|
||||
return;
|
||||
|
||||
/* A different socket address is specified. Let's close the old socket. New socket will be opened
|
||||
* when necessary. */
|
||||
m->forward_socket_fd = safe_close(m->forward_socket_fd);
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
#include "journald-forward.h"
|
||||
|
||||
int manager_forward_socket(Manager *m, const struct iovec *iovec, size_t n, const dual_timestamp *ts, int priority);
|
||||
void manager_reload_forward_socket(Manager *m, const SocketAddress *old);
|
||||
|
||||
@@ -454,7 +454,7 @@ static size_t stdout_stream_line_max(StdoutStream *s) {
|
||||
return STDOUT_STREAM_SETUP_PROTOCOL_LINE_MAX;
|
||||
|
||||
/* After the protocol's "setup" phase is complete, let's use whatever the user configured */
|
||||
return s->manager->line_max;
|
||||
return s->manager->config.line_max;
|
||||
}
|
||||
|
||||
static int stdout_stream_scan(
|
||||
@@ -557,7 +557,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
|
||||
|
||||
/* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also,
|
||||
* always leave room for a terminating NUL we might need to add. */
|
||||
limit = MIN(allocated - 1, MAX(s->manager->line_max, STDOUT_STREAM_SETUP_PROTOCOL_LINE_MAX));
|
||||
limit = MIN(allocated - 1, MAX(s->manager->config.line_max, STDOUT_STREAM_SETUP_PROTOCOL_LINE_MAX));
|
||||
assert(s->length <= limit);
|
||||
iovec = IOVEC_MAKE(s->buffer + s->length, limit - s->length);
|
||||
|
||||
|
||||
@@ -52,10 +52,16 @@ static int run(int argc, char *argv[]) {
|
||||
|
||||
sigbus_install();
|
||||
|
||||
r = manager_new(&m, namespace);
|
||||
r = manager_new(&m);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = manager_set_namespace(m, namespace);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
manager_load_config(m);
|
||||
|
||||
r = manager_init(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -91,9 +97,9 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get the current time: %m");
|
||||
|
||||
if (m->max_retention_usec > 0 && m->oldest_file_usec > 0) {
|
||||
if (m->config.max_retention_usec > 0 && m->oldest_file_usec > 0) {
|
||||
/* Calculate when to rotate the next time */
|
||||
t = usec_sub_unsigned(usec_add(m->oldest_file_usec, m->max_retention_usec), n);
|
||||
t = usec_sub_unsigned(usec_add(m->oldest_file_usec, m->config.max_retention_usec), n);
|
||||
|
||||
/* The retention time is reached, so let's vacuum! */
|
||||
if (t <= 0) {
|
||||
|
||||
@@ -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',
|
||||
@@ -20,7 +21,7 @@ systemd_journald_extract_sources = files(
|
||||
'journald-wall.c',
|
||||
# Build fuzz-journald.c as part of systemd-journald so we only compile it once instead of once per
|
||||
# fuzz test.
|
||||
'fuzz-journald.c',
|
||||
'fuzz-journald-util.c',
|
||||
)
|
||||
|
||||
journald_gperf_c = custom_target(
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#define _COMPRESS_PARSE_CHECK(str, enab, thresh, varname) \
|
||||
do { \
|
||||
JournalCompressOptions varname = {true, 111}; \
|
||||
JournalCompressOptions varname = {-222, 111}; \
|
||||
config_parse_compress("", "", 0, "", 0, "", 0, str, \
|
||||
&varname, NULL); \
|
||||
assert_se((enab) == varname.enabled); \
|
||||
@@ -25,21 +25,21 @@
|
||||
_COMPRESS_PARSE_CHECK(str, enabled, threshold, conf##__COUNTER__)
|
||||
|
||||
TEST(config_compress) {
|
||||
COMPRESS_PARSE_CHECK("yes", true, 111);
|
||||
COMPRESS_PARSE_CHECK("no", false, 111);
|
||||
COMPRESS_PARSE_CHECK("y", true, 111);
|
||||
COMPRESS_PARSE_CHECK("n", false, 111);
|
||||
COMPRESS_PARSE_CHECK("true", true, 111);
|
||||
COMPRESS_PARSE_CHECK("false", false, 111);
|
||||
COMPRESS_PARSE_CHECK("t", true, 111);
|
||||
COMPRESS_PARSE_CHECK("f", false, 111);
|
||||
COMPRESS_PARSE_CHECK("on", true, 111);
|
||||
COMPRESS_PARSE_CHECK("off", false, 111);
|
||||
COMPRESS_PARSE_CHECK("yes", true, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("no", false, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("y", true, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("n", false, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("true", true, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("false", false, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("t", true, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("f", false, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("on", true, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("off", false, UINT64_MAX);
|
||||
|
||||
/* Weird size/bool overlapping case. We preserve backward compatibility instead of assuming these are byte
|
||||
* counts. */
|
||||
COMPRESS_PARSE_CHECK("1", true, 111);
|
||||
COMPRESS_PARSE_CHECK("0", false, 111);
|
||||
COMPRESS_PARSE_CHECK("1", true, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("0", false, UINT64_MAX);
|
||||
|
||||
/* IEC sizing */
|
||||
COMPRESS_PARSE_CHECK("1B", true, 1);
|
||||
@@ -48,9 +48,9 @@ TEST(config_compress) {
|
||||
COMPRESS_PARSE_CHECK("1G", true, 1024 * 1024 * 1024);
|
||||
|
||||
/* Invalid Case */
|
||||
COMPRESS_PARSE_CHECK("-1", true, 111);
|
||||
COMPRESS_PARSE_CHECK("blah blah", true, 111);
|
||||
COMPRESS_PARSE_CHECK("", true, UINT64_MAX);
|
||||
COMPRESS_PARSE_CHECK("-1", -222, 111);
|
||||
COMPRESS_PARSE_CHECK("blah blah", -222, 111);
|
||||
COMPRESS_PARSE_CHECK("", -1, UINT64_MAX);
|
||||
}
|
||||
|
||||
#define _FORWARD_TO_SOCKET_PARSE_CHECK_FAILS(str, addr, varname) \
|
||||
|
||||
@@ -4082,54 +4082,6 @@ 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,
|
||||
@@ -4169,7 +4121,9 @@ int journal_file_open(
|
||||
.fd = fd,
|
||||
.mode = mode,
|
||||
.open_flags = open_flags,
|
||||
.compress_threshold_bytes = get_compress_threshold_bytes(compress_threshold_bytes),
|
||||
.compress_threshold_bytes = compress_threshold_bytes == UINT64_MAX ?
|
||||
DEFAULT_COMPRESS_THRESHOLD :
|
||||
MAX(MIN_COMPRESS_THRESHOLD, compress_threshold_bytes),
|
||||
.strict_order = FLAGS_SET(file_flags, JOURNAL_STRICT_ORDER),
|
||||
.newest_boot_id_prioq_idx = PRIOQ_IDX_NULL,
|
||||
.last_direction = _DIRECTION_INVALID,
|
||||
@@ -4278,9 +4232,17 @@ int journal_file_open(
|
||||
}
|
||||
#endif
|
||||
|
||||
r = set_metrics(f, metrics, template);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
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;
|
||||
}
|
||||
|
||||
#if HAVE_GCRYPT
|
||||
r = journal_file_hmac_setup(f);
|
||||
@@ -4578,6 +4540,19 @@ void journal_reset_metrics(JournalMetrics *m) {
|
||||
};
|
||||
}
|
||||
|
||||
bool journal_metrics_equal(const JournalMetrics *x, const JournalMetrics *y) {
|
||||
assert(x);
|
||||
assert(y);
|
||||
|
||||
return
|
||||
x->max_size == y->max_size &&
|
||||
x->min_size == y->min_size &&
|
||||
x->max_use == y->max_use &&
|
||||
x->min_use == y->min_use &&
|
||||
x->keep_free == y->keep_free &&
|
||||
x->n_max_files == y->n_max_files;
|
||||
}
|
||||
|
||||
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *ret_from, usec_t *ret_to) {
|
||||
assert(f);
|
||||
assert(f->header);
|
||||
|
||||
@@ -149,12 +149,6 @@ 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);
|
||||
@@ -315,6 +309,7 @@ void journal_file_post_change(JournalFile *f);
|
||||
int journal_file_enable_post_change_timer(JournalFile *f, sd_event *e, usec_t t);
|
||||
|
||||
void journal_reset_metrics(JournalMetrics *m);
|
||||
bool journal_metrics_equal(const JournalMetrics *x, const JournalMetrics *y);
|
||||
|
||||
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *ret_from, usec_t *ret_to);
|
||||
int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *ret_from, usec_t *ret_to);
|
||||
|
||||
Reference in New Issue
Block a user