diff options
Diffstat (limited to '')
-rw-r--r-- | src/journal/journald-server.c | 354 |
1 files changed, 266 insertions, 88 deletions
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 1c3a2a0..717c8e4 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -18,7 +18,9 @@ #include "audit-util.h" #include "cgroup-util.h" #include "conf-parser.h" +#include "creds-util.h" #include "dirent-util.h" +#include "event-util.h" #include "extract-word.h" #include "fd-util.h" #include "fileio.h" @@ -39,9 +41,11 @@ #include "journald-native.h" #include "journald-rate-limit.h" #include "journald-server.h" +#include "journald-socket.h" #include "journald-stream.h" #include "journald-syslog.h" #include "log.h" +#include "memory-util.h" #include "missing_audit.h" #include "mkdir.h" #include "parse-util.h" @@ -51,12 +55,13 @@ #include "rm-rf.h" #include "selinux-util.h" #include "signal-util.h" +#include "socket-netlink.h" #include "socket-util.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "syslog-util.h" -#include "uid-alloc-range.h" +#include "uid-classification.h" #include "user-util.h" #include "varlink-io.systemd.Journal.h" @@ -87,6 +92,9 @@ #define FAILED_TO_WRITE_ENTRY_RATELIMIT ((const RateLimit) { .interval = 1 * USEC_PER_SEC, .burst = 1 }) +static int server_schedule_sync(Server *s, int priority); +static int server_refresh_idle_timer(Server *s); + static int server_determine_path_usage( Server *s, const char *path, @@ -289,11 +297,10 @@ static int server_open_journal( s->compress.threshold_bytes, metrics, s->mmap, - /* template= */ NULL, &f); else r = journal_file_open( - /* fd= */ -1, + /* fd= */ -EBADF, fname, open_flags, file_flags, @@ -328,6 +335,20 @@ static bool server_flushed_flag_is_set(Server *s) { return access(fn, F_OK) >= 0; } +static void server_drop_flushed_flag(Server *s) { + const char *fn; + + assert(s); + + if (s->namespace) + return; + + fn = strjoina(s->runtime_directory, "/flushed"); + if (unlink(fn) < 0 && errno != ENOENT) + log_ratelimit_warning_errno(errno, JOURNAL_LOG_RATELIMIT, + "Failed to unlink %s, ignoring: %m", fn); +} + static int server_system_journal_open( Server *s, bool flush_requested, @@ -430,6 +451,7 @@ static int server_system_journal_open( server_add_acls(s->runtime_journal, 0); (void) cache_space_refresh(s, &s->runtime_storage); patch_min_use(&s->runtime_storage); + server_drop_flushed_flag(s); } } @@ -717,19 +739,46 @@ void server_rotate(Server *s) { server_process_deferred_closes(s); } -void server_sync(Server *s) { +static void server_rotate_journal(Server *s, JournalFile *f, uid_t uid) { + int r; + + assert(s); + assert(f); + + /* This is similar to server_rotate(), but rotates only specified journal file. + * + * 💣💣💣 This invalidate 'f', and the caller cannot reuse the passed JournalFile object. 💣💣💣 */ + + if (f == s->system_journal) + (void) server_do_rotate(s, &s->system_journal, "system", s->seal, /* uid= */ 0); + else if (f == s->runtime_journal) + (void) server_do_rotate(s, &s->runtime_journal, "runtime", /* seal= */ false, /* uid= */ 0); + else { + assert(ordered_hashmap_get(s->user_journals, UID_TO_PTR(uid)) == f); + r = server_do_rotate(s, &f, "user", s->seal, uid); + if (r >= 0) + ordered_hashmap_replace(s->user_journals, UID_TO_PTR(uid), f); + else if (!f) + /* Old file has been closed and deallocated */ + ordered_hashmap_remove(s->user_journals, UID_TO_PTR(uid)); + } + + server_process_deferred_closes(s); +} + +static void server_sync(Server *s, bool wait) { JournalFile *f; int r; if (s->system_journal) { - r = journal_file_set_offline(s->system_journal, false); + r = journal_file_set_offline(s->system_journal, wait); if (r < 0) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to sync system journal, ignoring: %m"); } ORDERED_HASHMAP_FOREACH(f, s->user_journals) { - r = journal_file_set_offline(f, false); + r = journal_file_set_offline(f, wait); if (r < 0) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to sync user journal, ignoring: %m"); @@ -899,47 +948,45 @@ static void server_write_to_journal( uid_t uid, const struct iovec *iovec, size_t n, + const dual_timestamp *ts, int priority) { - bool vacuumed = false, rotate = false; - struct dual_timestamp ts; + bool vacuumed = false; JournalFile *f; int r; assert(s); assert(iovec); assert(n > 0); + assert(ts); - /* Get the closest, linearized time we have for this log event from the event loop. (Note that we do not use - * the source time, and not even the time the event was originally seen, but instead simply the time we started - * processing it, as we want strictly linear ordering in what we write out.) */ - assert_se(sd_event_now(s->event, CLOCK_REALTIME, &ts.realtime) >= 0); - assert_se(sd_event_now(s->event, CLOCK_MONOTONIC, &ts.monotonic) >= 0); - - if (ts.realtime < s->last_realtime_clock) { + if (ts->realtime < s->last_realtime_clock) { /* When the time jumps backwards, let's immediately rotate. Of course, this should not happen during * regular operation. However, when it does happen, then we should make sure that we start fresh files * to ensure that the entries in the journal files are strictly ordered by time, in order to ensure * bisection works correctly. */ log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "Time jumped backwards, rotating."); - rotate = true; - } else { + server_rotate(s); + server_vacuum(s, /* verbose = */ false); + vacuumed = true; + } - f = server_find_journal(s, uid); - if (!f) - return; + f = server_find_journal(s, uid); + if (!f) + return; - if (journal_file_rotate_suggested(f, s->max_file_usec, LOG_DEBUG)) { - log_debug("%s: Journal header limits reached or header out-of-date, rotating.", - f->path); - rotate = true; + if (journal_file_rotate_suggested(f, s->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."); + return; } - } - if (rotate) { - server_rotate(s); - server_vacuum(s, false); + log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path); + + server_rotate_journal(s, TAKE_PTR(f), uid); + server_vacuum(s, /* verbose = */ false); vacuumed = true; f = server_find_journal(s, uid); @@ -947,11 +994,11 @@ static void server_write_to_journal( return; } - s->last_realtime_clock = ts.realtime; + s->last_realtime_clock = ts->realtime; r = journal_file_append_entry( f, - &ts, + ts, /* boot_id= */ NULL, iovec, n, &s->seqnum->seqnum, @@ -973,8 +1020,8 @@ static void server_write_to_journal( return; } - server_rotate(s); - server_vacuum(s, false); + server_rotate_journal(s, TAKE_PTR(f), uid); + server_vacuum(s, /* verbose = */ false); f = server_find_journal(s, uid); if (!f) @@ -983,7 +1030,7 @@ static void server_write_to_journal( log_debug_errno(r, "Retrying write."); r = journal_file_append_entry( f, - &ts, + ts, /* boot_id= */ NULL, iovec, n, &s->seqnum->seqnum, @@ -1037,7 +1084,7 @@ static void server_dispatch_message_real( int priority, pid_t object_pid) { - char source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)]; + char source_time[STRLEN("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)]; _unused_ _cleanup_free_ char *cmdline1 = NULL, *cmdline2 = NULL; uid_t journal_uid; ClientContext *o; @@ -1111,13 +1158,13 @@ static void server_dispatch_message_real( IOVEC_ADD_STRING_FIELD(iovec, n, o->slice, "OBJECT_SYSTEMD_SLICE"); IOVEC_ADD_STRING_FIELD(iovec, n, o->user_slice, "OBJECT_SYSTEMD_USER_SLICE"); - IOVEC_ADD_ID128_FIELD(iovec, n, o->invocation_id, "OBJECT_SYSTEMD_INVOCATION_ID="); + IOVEC_ADD_ID128_FIELD(iovec, n, o->invocation_id, "OBJECT_SYSTEMD_INVOCATION_ID"); } assert(n <= m); if (tv) { - sprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=" USEC_FMT, timeval_load(tv)); + xsprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=" USEC_FMT, timeval_load(tv)); iovec[n++] = IOVEC_MAKE_STRING(source_time); } @@ -1152,7 +1199,15 @@ static void server_dispatch_message_real( else journal_uid = 0; - server_write_to_journal(s, journal_uid, iovec, n, priority); + /* Get the closest, linearized time we have for this log event from the event loop. (Note that we do + * not use the source time, and not even the time the event was originally seen, but instead simply + * the time we started processing it, as we want strictly linear ordering in what we write out.) */ + struct dual_timestamp ts; + event_dual_timestamp_now(s->event, &ts); + + (void) server_forward_socket(s, iovec, n, &ts, priority); + + server_write_to_journal(s, journal_uid, iovec, n, &ts, priority); } void server_driver_message(Server *s, pid_t object_pid, const char *message_id, const char *format, ...) { @@ -1233,7 +1288,13 @@ void server_dispatch_message( if (c && c->unit) { (void) server_determine_space(s, &available, /* limit= */ NULL); - rl = journal_ratelimit_test(s->ratelimit, c->unit, c->log_ratelimit_interval, c->log_ratelimit_burst, priority & LOG_PRIMASK, available); + rl = journal_ratelimit_test( + &s->ratelimit_groups_by_id, + c->unit, + c->log_ratelimit_interval, + c->log_ratelimit_burst, + LOG_PRI(priority), + available); if (rl == 0) return; @@ -1275,11 +1336,19 @@ int server_flush_to_var(Server *s, bool require_flag_file) { if (!s->system_journal) return 0; + /* Offline and close the 'main' runtime journal file to allow the runtime journal to be opened with + * the SD_JOURNAL_ASSUME_IMMUTABLE flag in the below. */ + s->runtime_journal = journal_file_offline_close(s->runtime_journal); + + /* Reset current seqnum data to avoid unnecessary rotation when switching to system journal. + * See issue #30092. */ + zero(*s->seqnum); + log_debug("Flushing to %s...", s->system_storage.path); start = now(CLOCK_MONOTONIC); - r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY); + r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY | SD_JOURNAL_ASSUME_IMMUTABLE); if (r < 0) return log_ratelimit_error_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to read runtime journal: %m"); @@ -1318,8 +1387,8 @@ int server_flush_to_var(Server *s, bool require_flag_file) { log_ratelimit_info(JOURNAL_LOG_RATELIMIT, "Rotating system journal."); - server_rotate(s); - server_vacuum(s, false); + server_rotate_journal(s, s->system_journal, /* uid = */ 0); + server_vacuum(s, /* verbose = */ false); if (!s->system_journal) { log_ratelimit_notice(JOURNAL_LOG_RATELIMIT, @@ -1348,13 +1417,36 @@ finish: if (s->system_journal) journal_file_post_change(s->system_journal); - s->runtime_journal = journal_file_offline_close(s->runtime_journal); - - if (r >= 0) - (void) rm_rf(s->runtime_storage.path, REMOVE_ROOT); + /* Save parent directories of runtime journals before closing runtime journals. */ + _cleanup_strv_free_ char **dirs = NULL; + (void) journal_get_directories(j, &dirs); + /* First, close all runtime journals opened in the above. */ sd_journal_close(j); + /* Remove the runtime directory if the all entries are successfully flushed to /var/. */ + if (r >= 0) { + r = rm_rf(s->runtime_storage.path, REMOVE_ROOT); + if (r < 0) + log_debug_errno(r, "Failed to remove runtime journal directory %s, ignoring: %m", s->runtime_storage.path); + else + log_debug("Removed runtime journal directory %s.", s->runtime_storage.path); + + /* The initrd may have a different machine ID from the host's one. Typically, that happens + * when our tests running on qemu, as the host's initrd is picked as is without updating + * the machine ID in the initrd with the one used in the image. Even in such the case, the + * runtime journals in the subdirectory named with the initrd's machine ID are flushed to + * the persistent journal. To make not the runtime journal flushed multiple times, let's + * also remove the runtime directories. */ + STRV_FOREACH(p, dirs) { + r = rm_rf(*p, REMOVE_ROOT); + if (r < 0) + log_debug_errno(r, "Failed to remove additional runtime journal directory %s, ignoring: %m", *p); + else + log_debug("Removed additional runtime journal directory %s.", *p); + } + } + server_driver_message(s, 0, NULL, LOG_MESSAGE("Time spent on flushing to %s is %s for %u entries.", s->system_storage.path, @@ -1373,7 +1465,6 @@ finish: } static int server_relinquish_var(Server *s) { - const char *fn; assert(s); if (s->storage == STORAGE_NONE) @@ -1393,11 +1484,6 @@ static int server_relinquish_var(Server *s) { ordered_hashmap_clear_with_destructor(s->user_journals, journal_file_offline_close); set_clear_with_destructor(s->deferred_closes, journal_file_offline_close); - fn = strjoina(s->runtime_directory, "/flushed"); - if (unlink(fn) < 0 && errno != ENOENT) - log_ratelimit_warning_errno(errno, JOURNAL_LOG_RATELIMIT, - "Failed to unlink %s, ignoring: %m", fn); - server_refresh_idle_timer(s); return 0; } @@ -1512,7 +1598,7 @@ int server_process_datagram( if (n > 0 && n_fds == 0) server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len); else if (n == 0 && n_fds == 1) - server_process_native_file(s, fds[0], ucred, tv, label, label_len); + (void) server_process_native_file(s, fds[0], ucred, tv, label, label_len); else if (n_fds > 0) log_ratelimit_warning(JOURNAL_LOG_RATELIMIT, "Got too many file descriptors via native socket. Ignoring."); @@ -1537,7 +1623,7 @@ static void server_full_flush(Server *s) { assert(s); (void) server_flush_to_var(s, false); - server_sync(s); + server_sync(s, /* wait = */ false); server_vacuum(s, false); server_space_usage_message(s, NULL); @@ -1669,13 +1755,13 @@ fail: return 0; } -static void server_full_sync(Server *s) { +static void server_full_sync(Server *s, bool wait) { const char *fn; int r; assert(s); - server_sync(s); + server_sync(s, wait); /* Let clients know when the most recent sync happened. */ fn = strjoina(s->runtime_directory, "/synced"); @@ -1683,15 +1769,13 @@ static void server_full_sync(Server *s) { if (r < 0) log_ratelimit_warning_errno(r, JOURNAL_LOG_RATELIMIT, "Failed to write %s, ignoring: %m", fn); - - return; } static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { Server *s = ASSERT_PTR(userdata); log_debug("Received SIGRTMIN1 signal from PID %u, as request to sync.", si->ssi_pid); - server_full_sync(s); + server_full_sync(s, /* wait = */ false); return 0; } @@ -1701,7 +1785,7 @@ static int server_setup_signals(Server *s) { assert(s); - assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+18, -1) >= 0); + assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+18) >= 0); r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s); if (r < 0) @@ -1839,6 +1923,17 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat else s->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 + s->max_level_socket = r; + } else if (startswith(key, "systemd.journald")) log_warning("Unknown journald kernel command line option \"%s\". Ignoring.", key); @@ -1847,39 +1942,44 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat } static int server_parse_config_file(Server *s) { - const char *conf_file = "journald.conf"; + const char *conf_file; assert(s); if (s->namespace) - conf_file = strjoina("journald@", s->namespace, ".conf"); + conf_file = strjoina("systemd/journald@", s->namespace, ".conf"); + else + conf_file = "systemd/journald.conf"; - return config_parse_config_file(conf_file, "Journal\0", - config_item_perf_lookup, journald_gperf_lookup, - CONFIG_PARSE_WARN, s); + return config_parse_standard_file_with_dropins( + conf_file, + "Journal\0", + config_item_perf_lookup, journald_gperf_lookup, + CONFIG_PARSE_WARN, + /* userdata= */ s); } static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) { Server *s = ASSERT_PTR(userdata); - server_sync(s); + server_sync(s, /* wait = */ false); return 0; } -int server_schedule_sync(Server *s, int priority) { +static int server_schedule_sync(Server *s, int priority) { int r; assert(s); if (priority <= LOG_CRIT) { /* Immediately sync to disk when this is of priority CRIT, ALERT, EMERG */ - server_sync(s); + server_sync(s, /* wait = */ false); return 0; } if (!s->event || sd_event_get_state(s->event) == SD_EVENT_FINISHED) { /* Shutting down the server? Let's sync immediately. */ - server_sync(s); + server_sync(s, /* wait = */ false); return 0; } @@ -2098,7 +2198,7 @@ static int synchronize_second_half(sd_event_source *event_source, void *userdata /* This is the "second half" of the Synchronize() varlink method. This function is called as deferred * event source at a low priority to ensure the synchronization completes after all queued log * messages are processed. */ - server_full_sync(s); + server_full_sync(s, /* wait = */ true); /* Let's get rid of the event source now, by marking it as non-floating again. It then has no ref * anymore and is immediately destroyed after we return from this function, i.e. from this event @@ -2303,7 +2403,7 @@ int server_map_seqnum_file( return 0; } -void server_unmap_seqnum_file(void *p, size_t size) { +static void server_unmap_seqnum_file(void *p, size_t size) { assert(size > 0); if (!p) @@ -2373,7 +2473,7 @@ int server_start_or_stop_idle_timer(Server *s) { return 1; } -int server_refresh_idle_timer(Server *s) { +static int server_refresh_idle_timer(Server *s) { int r; assert(s); @@ -2444,14 +2544,44 @@ static int server_setup_memory_pressure(Server *s) { return 0; } -int server_init(Server *s, const char *namespace) { - const char *native_socket, *syslog_socket, *stdout_socket, *varlink_socket, *e; - _cleanup_fdset_free_ FDSet *fds = NULL; - int n, r, fd, varlink_fd = -EBADF; - bool no_sockets; +static void server_load_credentials(Server *s) { + _cleanup_free_ void *data = NULL; + int r; assert(s); + 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(&s->forward_to_socket, data); + if (r < 0) + log_debug_errno(r, "Failed to parse socket address '%s' from credential journal.forward_to_socket, ignoring: %m", (char *) data); + } + + data = mfree(data); + + r = read_credential("journal.storage", &data, NULL); + if (r < 0) + log_debug_errno(r, "Failed to read credential journal.storage, ignoring: %m"); + else { + r = storage_from_string(data); + if (r < 0) + log_debug_errno(r, "Failed to parse storage '%s' from credential journal.storage, ignoring: %m", (char *) data); + else + s->storage = r; + } +} + +int server_new(Server **ret) { + _cleanup_(server_freep) Server *s = NULL; + + assert(ret); + + s = new(Server, 1); + if (!s) + return -ENOMEM; + *s = (Server) { .syslog_fd = -EBADF, .native_fd = -EBADF, @@ -2460,6 +2590,7 @@ int server_init(Server *s, const char *namespace) { .audit_fd = -EBADF, .hostname_fd = -EBADF, .notify_fd = -EBADF, + .forward_socket_fd = -EBADF, .compress.enabled = true, .compress.threshold_bytes = UINT64_MAX, @@ -2476,6 +2607,7 @@ int server_init(Server *s, const char *namespace) { .ratelimit_burst = DEFAULT_RATE_LIMIT_BURST, .forward_to_wall = true, + .forward_to_socket = { .sockaddr.sa.sa_family = AF_UNSPEC }, .max_file_usec = DEFAULT_MAX_FILE_USEC, @@ -2484,6 +2616,7 @@ int server_init(Server *s, const char *namespace) { .max_level_kmsg = LOG_NOTICE, .max_level_console = LOG_INFO, .max_level_wall = LOG_EMERG, + .max_level_socket = LOG_DEBUG, .line_max = DEFAULT_LINE_MAX, @@ -2499,6 +2632,18 @@ int server_init(Server *s, const char *namespace) { .sigrtmin18_info.memory_pressure_userdata = s, }; + *ret = TAKE_PTR(s); + return 0; +} + +int server_init(Server *s, const char *namespace) { + const char *native_socket, *syslog_socket, *stdout_socket, *varlink_socket, *e; + _cleanup_fdset_free_ FDSet *fds = NULL; + int n, r, varlink_fd = -EBADF; + bool no_sockets; + + assert(s); + r = server_set_namespace(s, namespace); if (r < 0) return r; @@ -2510,6 +2655,7 @@ int server_init(Server *s, const char *namespace) { journal_reset_metrics(&s->system_storage.metrics); journal_reset_metrics(&s->runtime_storage.metrics); + server_load_credentials(s); server_parse_config_file(s); if (!s->namespace) { @@ -2562,7 +2708,7 @@ int server_init(Server *s, const char *namespace) { syslog_socket = strjoina(s->runtime_directory, "/dev-log"); varlink_socket = strjoina(s->runtime_directory, "/io.systemd.journal"); - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { + for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, native_socket, 0) > 0) { @@ -2615,12 +2761,11 @@ int server_init(Server *s, const char *namespace) { if (r < 0) return log_oom(); } - } /* Try to restore streams, but don't bother if this fails */ (void) server_restore_streams(s, fds); - if (fdset_size(fds) > 0) { + if (!fdset_isempty(fds)) { log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds)); fds = fdset_free(fds); } @@ -2683,10 +2828,6 @@ int server_init(Server *s, const char *namespace) { if (r < 0) return r; - s->ratelimit = journal_ratelimit_new(); - if (!s->ratelimit) - return log_oom(); - r = cg_get_root_path(&s->cgroup_root); if (r < 0) return log_error_errno(r, "Failed to acquire cgroup root path: %m"); @@ -2721,6 +2862,7 @@ int server_init(Server *s, const char *namespace) { return r; server_start_or_stop_idle_timer(s); + return 0; } @@ -2739,8 +2881,9 @@ void server_maybe_append_tags(Server *s) { #endif } -void server_done(Server *s) { - assert(s); +Server* server_free(Server *s) { + if (!s) + return NULL; free(s->namespace); free(s->namespace_field); @@ -2783,9 +2926,9 @@ void server_done(Server *s) { safe_close(s->audit_fd); safe_close(s->hostname_fd); safe_close(s->notify_fd); + safe_close(s->forward_socket_fd); - if (s->ratelimit) - journal_ratelimit_free(s->ratelimit); + ordered_hashmap_free(s->ratelimit_groups_by_id); server_unmap_seqnum_file(s->seqnum, sizeof(*s->seqnum)); server_unmap_seqnum_file(s->kernel_seqnum, sizeof(*s->kernel_seqnum)); @@ -2799,6 +2942,8 @@ void server_done(Server *s) { free(s->runtime_directory); mmap_cache_unref(s->mmap); + + return mfree(s); } static const char* const storage_table[_STORAGE_MAX] = { @@ -2883,9 +3028,12 @@ int config_parse_compress( void *data, void *userdata) { - JournalCompressOptions* compress = data; + JournalCompressOptions* compress = ASSERT_PTR(data); int r; + assert(filename); + assert(rvalue); + if (isempty(rvalue)) { compress->enabled = true; compress->threshold_bytes = UINT64_MAX; @@ -2912,3 +3060,33 @@ int config_parse_compress( 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; +} |