From 74055aa76278232ff05574fc47c4e6b3560554a7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Oct 2014 00:28:17 +0200 Subject: journalctl: add new --flush command and make use of it in systemd-journal-flush.service This new command will ask the journal daemon to flush all log data stored in /run to /var, and wait for it to complete. This is useful, so that in case of Storage=persistent we can order systemd-tmpfiles-setup afterwards, to ensure any possibly newly created directory in /var/log gets proper access mode and owners. --- man/journalctl.xml | 14 ++++++ src/journal/journalctl.c | 92 +++++++++++++++++++++++++++++++++- src/journal/journald-server.c | 3 +- units/systemd-journal-flush.service.in | 5 +- 4 files changed, 110 insertions(+), 4 deletions(-) diff --git a/man/journalctl.xml b/man/journalctl.xml index 7fb6afc8f6..db2a1e142b 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -878,6 +878,20 @@ operation. + + + + Asks the Journal + daemon to flush any log data stored in + /run/systemd/log + into + /var/systemd/log, + if persistent storage is enabled. This + call does not return until the + operation is + complete. + + diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index ee4e1659b0..c32028268a 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -31,8 +31,10 @@ #include #include #include +#include #include #include +#include #include #ifdef HAVE_ACL @@ -40,7 +42,8 @@ #include "acl-util.h" #endif -#include "systemd/sd-journal.h" +#include "sd-journal.h" +#include "sd-bus.h" #include "log.h" #include "logs-show.h" @@ -59,6 +62,9 @@ #include "fsprg.h" #include "unit-name.h" #include "catalog.h" +#include "mkdir.h" +#include "bus-util.h" +#include "bus-error.h" #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) @@ -117,6 +123,7 @@ static enum { ACTION_DUMP_CATALOG, ACTION_UPDATE_CATALOG, ACTION_LIST_BOOTS, + ACTION_FLUSH, } arg_action = ACTION_SHOW; typedef struct boot_id_t { @@ -231,6 +238,7 @@ static void help(void) { " --list-catalog Show message IDs of all entries in the message catalog\n" " --dump-catalog Show entries in the message catalog\n" " --update-catalog Update the message catalog database\n" + " --flush Flush all journal data from /run into /var\n" #ifdef HAVE_GCRYPT " --setup-keys Generate a new FSS key pair\n" " --verify Verify journal file consistency\n" @@ -267,6 +275,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_UPDATE_CATALOG, ARG_FORCE, ARG_UTC, + ARG_FLUSH, }; static const struct option options[] = { @@ -317,6 +326,7 @@ static int parse_argv(int argc, char *argv[]) { { "reverse", no_argument, NULL, 'r' }, { "machine", required_argument, NULL, 'M' }, { "utc", no_argument, NULL, ARG_UTC }, + { "flush", no_argument, NULL, ARG_FLUSH }, {} }; @@ -661,6 +671,10 @@ static int parse_argv(int argc, char *argv[]) { arg_utc = true; break; + case ARG_FLUSH: + arg_action = ACTION_FLUSH; + break; + case '?': return -EINVAL; @@ -1641,6 +1655,77 @@ static int access_check(sd_journal *j) { return r; } +static int flush_to_var(void) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_close_ int watch_fd = -1; + int r; + + /* Quick exit */ + if (access("/run/systemd/journal/flushed", F_OK) >= 0) + return 0; + + /* OK, let's actually do the full logic, send SIGUSR1 to the + * daemon and set up inotify to wait for the flushed file to appear */ + r = bus_open_system_systemd(&bus); + if (r < 0) { + log_error("Failed to get D-Bus connection: %s", strerror(-r)); + return r; + } + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + &error, + NULL, + "ssi", "systemd-journald.service", "main", SIGUSR1); + if (r < 0) { + log_error("Failed to kill journal service: %s", bus_error_message(&error, r)); + return r; + } + + mkdir_p("/run/systemd/journal", 0755); + + watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (watch_fd < 0) { + log_error("Failed to create inotify watch: %m"); + return -errno; + } + + r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR); + if (r < 0) { + log_error("Failed to watch journal directory: %m"); + return -errno; + } + + for (;;) { + if (access("/run/systemd/journal/flushed", F_OK) >= 0) + break; + + if (errno != ENOENT) { + log_error("Failed to check for existance of /run/systemd/journal/flushed: %m"); + return -errno; + } + + r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY); + if (r < 0) { + log_error("Failed to wait for event: %s", strerror(-r)); + return r; + } + + r = flush_fd(watch_fd); + if (r < 0) { + log_error("Failed to flush inotify events: %s", strerror(-r)); + return r; + } + } + + return 0; +} + int main(int argc, char *argv[]) { int r; _cleanup_journal_close_ sd_journal *j = NULL; @@ -1665,6 +1750,11 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_action == ACTION_FLUSH) { + r = flush_to_var(); + goto finish; + } + if (arg_action == ACTION_SETUP_KEYS) { r = setup_keys(); goto finish; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index bf9cfcccc9..991f4f2a38 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1221,11 +1221,12 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo * log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid); - touch("/run/systemd/journal/flushed"); server_flush_to_var(s); server_sync(s); server_vacuum(s); + touch("/run/systemd/journal/flushed"); + return 0; } diff --git a/units/systemd-journal-flush.service.in b/units/systemd-journal-flush.service.in index 503e8a63b8..699670bb4e 100644 --- a/units/systemd-journal-flush.service.in +++ b/units/systemd-journal-flush.service.in @@ -11,8 +11,9 @@ Documentation=man:systemd-journald.service(8) man:journald.conf(5) DefaultDependencies=no Requires=systemd-journald.service After=systemd-journald.service local-fs.target remote-fs.target -Before=systemd-user-sessions.service +Before=systemd-user-sessions.service systemd-tmpfiles-setup.service [Service] -ExecStart=@rootbindir@/systemctl kill --kill-who=main --signal=SIGUSR1 systemd-journald.service +ExecStart=@rootbindir@/journalctl --flush Type=oneshot +RemainAfterExit=yes -- cgit v1.2.3-54-g00ecf