diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-10-23 00:28:17 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-10-23 00:39:42 +0200 |
commit | 74055aa76278232ff05574fc47c4e6b3560554a7 (patch) | |
tree | cebf74b2f97108dc325ce4522962863b2b4c2f35 | |
parent | 0e2f14014c65b4d8b30146e414579154cfa932da (diff) |
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.
-rw-r--r-- | man/journalctl.xml | 14 | ||||
-rw-r--r-- | src/journal/journalctl.c | 92 | ||||
-rw-r--r-- | src/journal/journald-server.c | 3 | ||||
-rw-r--r-- | 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.</para></listitem> </varlistentry> + <varlistentry> + <term><option>--flush</option></term> + + <listitem><para>Asks the Journal + daemon to flush any log data stored in + <filename>/run/systemd/log</filename> + into + <filename>/var/systemd/log</filename>, + if persistent storage is enabled. This + call does not return until the + operation is + complete.</para></listitem> + </varlistentry> + <xi:include href="standard-options.xml" xpointer="help" /> <xi:include href="standard-options.xml" xpointer="version" /> <xi:include href="standard-options.xml" xpointer="no-pager" /> 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 <time.h> #include <getopt.h> #include <signal.h> +#include <poll.h> #include <sys/stat.h> #include <sys/ioctl.h> +#include <sys/inotify.h> #include <linux/fs.h> #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 |