diff options
Diffstat (limited to 'src/journal')
-rw-r--r-- | src/journal/journalctl.c | 123 | ||||
-rw-r--r-- | src/journal/journald-server.c | 38 | ||||
-rw-r--r-- | src/journal/journald-server.h | 1 |
3 files changed, 135 insertions, 27 deletions
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 277adba904..521360b11b 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -135,6 +135,7 @@ static enum { ACTION_FLUSH, ACTION_ROTATE, ACTION_VACUUM, + ACTION_SYNC, } arg_action = ACTION_SHOW; typedef struct BootId { @@ -201,7 +202,7 @@ static void help(void) { printf("%s [OPTIONS...] [MATCHES...]\n\n" "Query the journal.\n\n" - "Flags:\n" + "Options:\n" " --system Show the system journal\n" " --user Show the user journal for the current user\n" " -M --machine=CONTAINER Operate on local container\n" @@ -234,7 +235,7 @@ static void help(void) { " -m --merge Show entries from all available journals\n" " -D --directory=PATH Show journal files from directory\n" " --file=PATH Show journal file\n" - " --root=ROOT Operate on catalog files underneath the root ROOT\n" + " --root=ROOT Operate on catalog files below a root directory\n" #ifdef HAVE_GCRYPT " --interval=TIME Time interval for changing the FSS sealing key\n" " --verify-key=KEY Specify FSS verification key\n" @@ -244,20 +245,21 @@ static void help(void) { " -h --help Show this help text\n" " --version Show package version\n" " -F --field=FIELD List all values that a specified field takes\n" - " --new-id128 Generate a new 128-bit ID\n" " --disk-usage Show total disk usage of all journal files\n" " --vacuum-size=BYTES Reduce disk usage below specified size\n" " --vacuum-files=INT Leave only the specified number of journal files\n" " --vacuum-time=TIME Remove journal files older than specified time\n" + " --verify Verify journal file consistency\n" + " --sync Synchronize unwritten journal messages to disk\n" " --flush Flush all journal data from /run into /var\n" " --rotate Request immediate rotation of the journal files\n" " --header Show journal header information\n" " --list-catalog Show all message IDs in the catalog\n" " --dump-catalog Show entries in the message catalog\n" " --update-catalog Update the message catalog database\n" + " --new-id128 Generate a new 128-bit ID\n" #ifdef HAVE_GCRYPT " --setup-keys Generate a new FSS key pair\n" - " --verify Verify journal file consistency\n" #endif , program_invocation_short_name); } @@ -289,6 +291,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_UPDATE_CATALOG, ARG_FORCE, ARG_UTC, + ARG_SYNC, ARG_FLUSH, ARG_ROTATE, ARG_VACUUM_SIZE, @@ -345,6 +348,7 @@ static int parse_argv(int argc, char *argv[]) { { "machine", required_argument, NULL, 'M' }, { "utc", no_argument, NULL, ARG_UTC }, { "flush", no_argument, NULL, ARG_FLUSH }, + { "sync", no_argument, NULL, ARG_SYNC }, { "rotate", no_argument, NULL, ARG_ROTATE }, { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE }, { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES }, @@ -729,6 +733,10 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_ROTATE; break; + case ARG_SYNC: + arg_action = ACTION_SYNC; + break; + case '?': return -EINVAL; @@ -1782,10 +1790,8 @@ static int flush_to_var(void) { &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; - } + if (r < 0) + return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); mkdir_p("/run/systemd/journal", 0755); @@ -1816,30 +1822,94 @@ static int flush_to_var(void) { return 0; } -static int rotate(void) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +static int send_signal_and_wait(int sig, const char *watch_path) { _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_close_ int watch_fd = -1; + usec_t start; int r; - r = bus_connect_system_systemd(&bus); - if (r < 0) - return log_error_errno(r, "Failed to get D-Bus connection: %m"); + start = now(CLOCK_REALTIME); - r = sd_bus_call_method( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "KillUnit", - &error, - NULL, - "ssi", "systemd-journald.service", "main", SIGUSR2); - if (r < 0) - return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); + /* This call sends the specified signal to journald, and waits + * for acknowledgment by watching the mtime of the specified + * flag file. This is used to trigger syncing or rotation and + * then wait for the operation to complete. */ + + for (;;) { + struct stat st; + + /* See if a sync happened by now. */ + if (stat(watch_path, &st) < 0) { + if (errno != ENOENT) + return log_error_errno(errno, "Failed to stat %s: %m", watch_path); + } else { + if (timespec_load(&st.st_mtim) >= start) + return 0; + } + + /* Let's ask for a sync, but only once. */ + if (!bus) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + + r = bus_connect_system_systemd(&bus); + if (r < 0) + return log_error_errno(r, "Failed to get D-Bus connection: %m"); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + &error, + NULL, + "ssi", "systemd-journald.service", "main", sig); + if (r < 0) + return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); + + continue; + } + + /* Let's install the inotify watch, if we didn't do that yet. */ + if (watch_fd < 0) { + + mkdir_p("/run/systemd/journal", 0755); + + watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (watch_fd < 0) + return log_error_errno(errno, "Failed to create inotify watch: %m"); + + r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_ATTRIB|IN_DONT_FOLLOW|IN_ONLYDIR); + if (r < 0) + return log_error_errno(errno, "Failed to watch journal directory: %m"); + + /* Recheck the flag file immediately, so that we don't miss any event since the last check. */ + continue; + } + + /* OK, all preparatory steps done, let's wait until + * inotify reports an event. */ + + r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY); + if (r < 0) + return log_error_errno(r, "Failed to wait for event: %m"); + + r = flush_fd(watch_fd); + if (r < 0) + return log_error_errno(r, "Failed to flush inotify events: %m"); + } return 0; } +static int rotate(void) { + return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated"); +} + +static int sync_journal(void) { + return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced"); +} + int main(int argc, char *argv[]) { int r; _cleanup_journal_close_ sd_journal *j = NULL; @@ -1875,6 +1945,11 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_action == ACTION_SYNC) { + r = sync_journal(); + goto finish; + } + if (arg_action == ACTION_ROTATE) { r = rotate(); goto finish; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index a6e5e4a20f..70ff101d5f 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1243,7 +1243,7 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo * assert(s); - log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid); + log_info("Received request to flush runtime journal from PID " PID_FMT, si->ssi_pid); server_flush_to_var(s); server_sync(s); @@ -1259,10 +1259,13 @@ static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo * assert(s); - log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid); + log_info("Received request to rotate journal from PID " PID_FMT, si->ssi_pid); server_rotate(s); server_vacuum(s, true, true); + /* Let clients know when the most recent rotation happened. */ + (void) touch("/run/systemd/journal/rotated"); + return 0; } @@ -1277,12 +1280,27 @@ static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo * return 0; } +static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; + + assert(s); + + log_debug("Received request to sync from PID " PID_FMT, si->ssi_pid); + + server_sync(s); + + /* Let clients know when the most recent sync happened. */ + (void) touch("/run/systemd/journal/synced"); + + return 0; +} + static int setup_signals(Server *s) { int r; assert(s); - assert(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1) >= 0); + assert(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0); r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s); if (r < 0) @@ -1312,6 +1330,19 @@ static int setup_signals(Server *s) { if (r < 0) return r; + /* SIGRTMIN+1 causes an immediate sync. We process this very + * late, so that everything else queued at this point is + * really written to disk. Clients can watch + * /run/systemd/journal/synced with inotify until its mtime + * changes to see when a sync happened. */ + r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s); + if (r < 0) + return r; + + r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15); + if (r < 0) + return r; + return 0; } @@ -1869,6 +1900,7 @@ void server_done(Server *s) { sd_event_source_unref(s->sigusr2_event_source); sd_event_source_unref(s->sigterm_event_source); sd_event_source_unref(s->sigint_event_source); + sd_event_source_unref(s->sigrtmin1_event_source); sd_event_source_unref(s->hostname_event_source); sd_event_source_unref(s->notify_event_source); sd_event_source_unref(s->watchdog_event_source); diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 03a61bd2ed..dcc21bb7c3 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -72,6 +72,7 @@ struct Server { sd_event_source *sigusr2_event_source; sd_event_source *sigterm_event_source; sd_event_source *sigint_event_source; + sd_event_source *sigrtmin1_event_source; sd_event_source *hostname_event_source; sd_event_source *notify_event_source; sd_event_source *watchdog_event_source; |